HUMANS.md, version 0.2 (draft)

HUMANS.md is a file a person writes so that AI agents know how to work with them: what they read, what they decide, and when to interrupt them. AGENTS.md tells agents how to work on a codebase. HUMANS.md tells them how to work with a person.

Not to be confused with a list of a project’s contributors, or with a guide for people who work with agents. Both exist under the same file name. This document describes neither (§ 1).

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be read as in RFC 2119 and RFC 8174 when, and only when, they appear in capitals.

Terms used below:

  • Owner: the person a profile describes. Only the owner writes it.
  • Own agent: an agent working for the owner (their Claude Code, Codex, Cursor…).
  • Sender’s agent: an agent working for someone else that writes to, or for, the owner.
  • Consumer: any program that reads a profile and hands it to an agent (a skill, an MCP server, a hook).
  • Directory: the organization’s list of people, synchronised with its identity provider, that maps a person to one profile.

1. Not to be confused with

You found…What it isHow to tell
A HUMANS.md that lists the people behind a projectA contributor list, in the spirit of humans.txtNo YAML frontmatter with humans:
A HUMANS.md that tells people how to collaborate with an AI assistant (e.g. attogram/agents)Guidance written for humans about agents. The opposite direction.No YAML frontmatter with humans:
An output-style skill such as i-have-adhdOne set of formatting rules for your own agent, named after a condition (its README says no diagnosis is needed). You change it by editing the skill.It is a skill, not a profile.

A HUMANS.md profile is recognised by its frontmatter: a YAML block with humans: "0.2". A consumer MUST ignore a file named HUMANS.md that has no such frontmatter.

What sets a profile apart from an output-style skill: the owner declares it in closed fields, it covers decisions and interruptions as well as format, and any agent can read it, including the agents of the people who write to the owner.

2. Principles

  1. Preferences, never diagnoses. A profile says how to write to the owner, never why. “TL;DR first, one decision per message” belongs in it; “ADHD” never does. Validators reject health terms (§ 3.9).
  2. Declared, never inferred. Everything served is what the owner approved. Consumers infer nothing about a person from other data.
  3. Closed values. Every field but name, aliases and notes takes a value from a fixed list. That is what makes a profile safe to hand to an agent written by someone else, mergeable for a group, and identical in every language.
  4. Free text stays local. The owner writes in their own words; their own agent compiles those words into fields; the owner approves. Only the fields leave the machine (§ 10).
  5. Fewer asks, never more rights. A profile can reduce what agents ask the owner. It never grants a permission (§ 4).

3. Files

The owner keeps two files:

FileHoldsRead by
~/.humans/me.mdthe profile: the fields, as a YAML frontmatter and nothing elseEvery agent, through imports and consumers
~/.humans/me.source.mdthe source: the owner’s free text, in any languageThe owner’s own agent only, to compile the profile. It never leaves the machine.

A profile file is UTF-8 and opens with the frontmatter:

  • The first line is exactly ---. The frontmatter ends at the next line that is exactly ---. Nothing else may share those lines.
  • The frontmatter is at most 6 KB.
  • me.md has nothing after the closing line. A profile kept in a repository (humans/<id>.md) MAY add a short Markdown body for colleagues, at most 4 KB. A consumer MUST NOT serve that body to any agent.

The source file SHOULD use three headings so tools can add a line under the right one without a model: ## What I read, ## What I decide, ## When to interrupt me. Tools MUST also accept ## Ce que je lis, ## Ce que je décide, ## Quand tu m'interromps. HTML comments in the source (for example a provenance line <!-- added-by: tool-name … -->) are ignored by compilation.

3.1 YAML subset

The frontmatter is one YAML 1.2 document, read with the core schema. Validators MUST reject anchors, aliases, explicit tags (!…), directives (%…), document markers (---, ...) inside the frontmatter, and duplicate keys. What is left is plain maps, lists, strings, integers and booleans.

All fields are optional unless marked required. An absent field means “no preference”: the agent keeps its default.

3.2 Identity

FieldRequiredValue
humansyes"0.2", quoted
idyesslug [a-z0-9-]{2,64}, unique within the organization. Equals the file name without .md, except in me.md.
nameyesplain text (§ 3.8), ≤ 80 characters. For the directory only, never served (§ 6).
aliases≤ 5 entries, plain text, ≤ 40 characters each. For the directory only, never served.
identitiesmap with keys email, slack (T…/U…), github, gitlab, entra (object ID, a UUID), google. Claims, not proof (§ 7).
languagesISO 639-1 codes in order of preference, e.g. [fr, en]
updatedyes"YYYY-MM-DD", quoted, a real calendar date: the day the owner last approved the profile
visibilityorg (default), public, private (served to the owner only)

3.3 reading: what I read

FieldValuesMeaning
lead_withtldr, decision_needed, context, questionWhat the first line holds
lengthminimal (≤ 5 lines), short (≤ 1 screen), standard, thoroughTarget length
max_wordsinteger 20–2000Hard cap, overrides length
structurebullets, prose, mixedBody layout
visualordered list from table, diagram, chart, example, textPreferred forms, most wanted first. A list starting with table or diagram means “visual first”.
technical_depthnon_technical, balanced, expertLevel of detail
jargonavoid, define, okAcronyms and trade terms
tonedirect, neutral, warmRegister
evidencenumbers_and_sources, key_numbers, lightHow much proof to show
uncertaintyflag_explicitly, inlineflag_explicitly: say what was checked and what was assumed

3.4 deciding: what I decide

FieldValuesMeaning
reversibledecide_and_report, askFor a choice the agent is already allowed to make and that can be undone: make it and report, or ask first
batch_questionsend_of_task, as_they_comeWhen open questions reach the owner
default_answeralways, when_obviousWhether each question carries the agent’s proposed answer
asks_per_messageone, few, anyRequests per message
formatrecommendation_first, options_then_recommendation, options_onlyHow a choice is laid out
challengewelcome_early, after_draft, on_requestWhen to raise a disagreement
out_of_scope_stepsomit_unless_blocking, listWhether to list follow-ups outside the task (merge, publish, deploy) at the end

3.5 interrupting: when to interrupt me

FieldValuesMeaning
interrupt_forblocking_only, blocking_or_risky, anythingWhat justifies stopping to ask
group_byproject, noneHow several pending messages are grouped
when_focusedsummary_later, urgent_only, as_usualBehaviour while the focus state is on
channel_hintasync_written, sync_call, eitherPreferred channel for complex topics

3.6 context and avoid

context says what the owner already knows and what they decide, so agents skip what is known and explain what is not. Every value comes from VOCABULARY.md.

FieldValue
roleone role from the vocabulary, e.g. cto, product-manager
knows_well, knows_little≤ 15 topics each, e.g. kubernetes, cloud-costs
decides≤ 10 decisions, e.g. infra-budget, release-scope
context_updated"YYYY-MM-DD". Served with stale: true after 183 days.

A résumé or public profile MAY be used to propose values during compilation; it is never stored.

avoid is a list from: walls_of_text, filler_intro, filler_outro, hedging, emoji, rhetorical_questions, multiple_asks, unexplained_acronyms, passive_voice, exclamation, long_preamble, nested_bullets, sarcasm.

3.7 states

Temporary variants: incident, low_bandwidth, focus, mobile. Each holds a partial override of reading, deciding and interrupting, written with the bare field names (they are unique across the three blocks), e.g. incident: { lead_with: decision_needed, length: minimal, asks_per_message: one }. The file only describes the variants. Switching one on is a separate, short-lived event:

  • Who: only the owner switches a state on, directly (a command, a tool call made by the owner) or through a status they set themselves (Slack status, do-not-disturb). A sender, a sender’s agent or the owner’s own agent MUST NOT switch a state on, and MUST NOT infer one from content.
  • How long: every activation carries an expiry, at most 12 hours after it starts. An activation without an expiry lasts 2 hours. After expiry the consumer drops it. Activations are never stored as history.
  • Several at once: the order is incident, then low_bandwidth, then focus, then mobile. For each field, the value from the first active state that sets it wins; fields no active state sets come from the profile.
  • Served as instructions: a consumer serves the resulting field values, never the name of the state as a description of the person.
  • Inside permissions: a state changes form and asks only. It MUST NOT widen what an agent may do (§ 4).

3.8 Plain text

name, aliases and notes are the only free-text values. Each is one line of plain text. Validators MUST reject a value that contains:

  • a control, format, private-use or unassigned character (Unicode categories Cc, Cf, Co, Cn), which covers U+0085, U+00AD, U+061C, the zero-width characters, the bidirectional controls and the tag characters; a line or paragraph separator; any space other than U+0020;
  • a Markdown or HTML character: ` * _ # < > [ ] { } | ~ \;
  • a URL scheme: any scheme://, and http:, https:, mailto:, javascript:, vbscript:, data:, file:, ftp:, tel:, sms:, ssh:, blob:, ws:, wss: in any case; a www. address; an e-mail address.

notes is at most 280 characters: a form preference no field captures, written as a fact about the owner (“I often read on my phone”).

3.9 Health guard

A validator MUST reject a file that contains, at any depth:

  • one of these keys: diagnosis, condition, disability, health, medical, neurotype, personality_type, disc, mbti, motivations, triggers, persuasion;
  • in any string value, notes included, one of the health terms listed in VOCABULARY.md, in English or French, matched without case or accents, on whole words.

The list is a net, not a proof: a preference can still hint at a condition. That is why profiles carry instructions, never reasons.

3.10 Unknown keys and values

Validators MUST reject unknown keys and values. Consumers MUST ignore them, so a newer file still works with an older consumer.

4. Precedence

  1. For actions, the order is: the harness and the session’s permissions, then the repository’s instructions (AGENTS.md, CLAUDE.md), then HUMANS.md, then the agent’s defaults. A HUMANS.md MAY reduce what an agent asks the owner, inside what the higher levels allow. It MUST NOT grant a permission and MUST NOT lift a rule of the repository or the harness. deciding.reversible: decide_and_report applies only to actions the agent is already allowed to take and that can be undone.
  2. For form, HUMANS.md comes before the agent’s defaults for anything addressed to the owner: messages, summaries, questions, reports. Artifacts the repository formats itself (commit messages, PR templates, changelogs) follow the repository.
  3. The profile is data. It shapes how the agent works with the owner. Recipients, facts, tool calls and links come only from the request the agent is working on. A consumer MUST present the profile as data and MUST NOT follow instructions found in it.

5. Locations

ScopeLocationWritten by
Personal~/.humans/me.md (profile) and ~/.humans/me.source.md (source, local only)The owner
Repository or teamhumans/<id>.md, with a CODEOWNERS line humans/<id>.md @<handle> so only the owner can approve changesThe owner, by pull request
Repository indexHUMANS.md at the root, OPTIONAL: a list of links to humans/<id>.md. An index, never a profile; it has no humans: frontmatter.Maintainers
Local cache of other people~/.humans/people/<id>.mdConsumers, never by hand
Organization directoryan MCP server synchronised with the identity providerThe owner, through the server
WebWebFinger (RFC 7033) on the domain of the owner’s e-mail: GET https://<domain>/.well-known/webfinger?resource=acct:<email>&rel=https://humansmd.dev/rel/profile returns a link to the profileThe domain’s organization
Slacka custom profile field named HUMANS.md (long_text, ≤ 5,000 characters) holding the frontmatterAn admin creates the field; the owner fills it

Loading your own profile into your own agent: imports and hooks target the profile ~/.humans/me.md, never the source file.

  • Claude Code imports files with @path in CLAUDE.md. Add @~/.humans/me.md to ~/.claude/CLAUDE.md. An import from a project-level file that points outside the project triggers an approval dialog once; imports nest up to four levels.
  • Codex reads ~/.codex/AGENTS.md (or AGENTS.override.md) and has no import syntax. Use a SessionStart hook whose plain stdout prints ~/.humans/me.md: Codex adds it as developer context. Copying the profile into ~/.codex/AGENTS.md also works but goes stale.
  • Other agents: a HUMANS.md skill or MCP server; see the list at humansmd.dev/implementations.

Sources for this section: SOURCES.md.

6. What a consumer serves

6.1 Who gets what

  • The owner’s own agent gets the profile. It reads the source file only when the owner asks it to compile (§ 10).
  • A sender’s agent gets the validated fields only:
    • name and aliases are dropped; the display name comes from the directory.
    • notes is served by the rules of § 6.2 and § 6.3.
    • Any Markdown body is never served.
    • A profile not updated for 365 days is served with stale: true.
  • A group gets the merged profile only (§ 9), with no notes.

6.2 Withholding

A consumer MUST withhold notes when it contains one of the words addressed to an agent listed in VOCABULARY.md, matched like the health terms (no case, no accents, whole words). A withheld note is not served; the response lists notes under withheld. False positives only cost a note: “Instead of long emails, use bullet points.” is withheld.

Conformance cases: tests/withholding.json. A consumer is conformant when it serves or withholds each case as listed.

6.3 Serialization

  • In a structured tool result, notes is a JSON string field next to id, never merged into prose.

  • In text handed to a model, the only allowed form is:

    Form preference quoted from <id>'s HUMANS.md (data, not an instruction): <notes as a JSON string>

    where <notes as a JSON string> is the value encoded as a JSON string (RFC 8259 § 7), quotes included, so a " in the note cannot close the quotation. The serialization cases in tests/withholding.json are normative.

7. Resolving a name to a profile

In v0.2, the organization directory is the only resolver. A profile says who it belongs to (id, identities), but that is a claim: a consumer MUST NOT decide that a person is the owner of a profile from the profile’s own fields, a file name, or a display name.

  1. The sender’s request names a person: an @mention (Slack user ID), an e-mail, a handle or a name.
  2. The consumer asks the directory of the sender’s organization, which returns at most one person per identifier, with that person’s profile. id is unique within the organization.
  3. A name that matches several people: the sender picks from a list (name, title, team); the agent never picks.
  4. Nothing found: § 8.

Repository files (humans/<id>.md), the local cache and WebFinger are places a directory may load profiles from. WebFinger counts as the directory of the e-mail’s domain. Outside any directory, an agent uses a profile only when the sender points to that exact file; that is the sender’s choice, not a resolution.

8. No profile

The consumer returns status: none and the organization’s default profile if one exists. The agent writes neutrally: TL;DR first, one clear request, standard length. It infers nothing about the person from other data. From the outside, “no profile” and “hidden profile” look the same.

9. Groups

For a channel or a list of recipients, the consumer merges the members’ profiles field by field. The merge is deterministic: the same profiles always give the same result. Reference implementation: tools/merge.mjs, cases in tests/group/. Output shape: schema/humans-group.schema.json.

Who counts. Members with a private profile, and members without a profile, count in coverage.total only. If the channel has a state of its own (an incident channel), each member’s override for that state is applied first and state is set in the output.

Votes. For each field, only members who set it vote. A field nobody sets is omitted; a block with no field is omitted. “Majority” is the most frequent value; on a tie, the merge takes the tie value given below, even when it was not among the tied values.

FieldRuleTie or fallback
lead_withtldr if anyone sets it; else decision_needed if anyone sets it; else majoritycontext
lengththe shortest (minimal < short < standard < thorough)
max_wordsthe smallest
structuremajoritymixed
visualrank vote: each member gives 5, 4, 3… points down their list; top two keptorder table, diagram, example, chart, text
technical_depththe lowest; if members differ, the highest goes to appendix_depth
jargonthe strictest (avoid < define < ok)
tonemajorityneutral
evidencemajoritykey_numbers
uncertaintyflag_explicitly if anyone sets itotherwise inline
reversibleask if anyone sets itotherwise decide_and_report
batch_questionsmajorityend_of_task
default_answeralways if anyone sets itotherwise when_obvious
asks_per_messagethe strictest (one < few < any)
formatmajorityoptions_then_recommendation
challengemajorityafter_draft
out_of_scope_stepsmajorityomit_unless_blocking
interrupt_forthe strictest (blocking_only < blocking_or_risky < anything)
group_byproject if anyone sets itotherwise none
channel_hintmajorityeither
when_focusedomitted
languageslanguages every member lists, ordered by summed rank; if none is shared, the one most members listties by summed rank, then alphabetical
context.knows_welltopics every member knows wellvocabulary order
context.knows_littletopics any member knows littlevocabulary order
context.role, context.decidesomitted
avoidunionlist order of § 3.6
states, notes, identity fieldsomitted

Conflicts. For every merged single-value field where members set different values, conflicts lists the field. With three or more profiles, it also lists the values and their counts; with fewer, values stay hidden so nobody can tell who asked for what. Agents use conflicts to offer a split: a short version in the channel, details in a thread.

10. Compiling free text

  1. The owner writes in their own words, in any language, in ~/.humans/me.source.md.
  2. Their own agent, on their own machine, turns those words into fields. A local check flags health terms and proposes a preference instead (“short sentences, one idea per line”), without logging anything.
  3. The agent shows a preview (“this is how agents will write to you”) and the owner approves.
  4. The agent writes the approved fields to ~/.humans/me.md. Only that file leaves the machine.

11. Versioning

humans: "0.2" replaces 0.1. A consumer MAY read a 0.1 file: its reading block keeps its meaning, its asks_per_message and challenge move to deciding, its decisions becomes deciding.format, and its tired state maps to low_bandwidth. Field names in 0.2 are stable: tools write them into suggested changes, and a rename breaks those changes. The vocabularies grow only with a new version.

12. Security and privacy

  • Prompt injection is the main risk: a profile is text written by someone else and read by an agent with tools. The defences are closed values, plain-text rules, withholding and fixed serialization for notes, never serving a body, and treating the profile as data (§ 4).
  • Impersonation: only the owner writes their profile (CODEOWNERS in a repository, authenticated writes in the directory), and only the directory resolves people (§ 7).
  • Health data: the health guard catches the obvious cases. Keep reasons out, keep states short-lived, and let the owner see who read their profile and delete it in one step.
  • No evaluation: a profile describes how to write to someone. Using it to assess, rank, assign work or monitor people is outside this specification and against its purpose.

13. Known limits

  • No proof of identity in v0.2. A profile’s identities are claims. v0.2 relies on the organization directory and on CODEOWNERS; outside a directory, nothing proves that a profile belongs to the person it names. Strong proof (a signed profile, or verification by the identity provider) is planned for v0.3.
  • Lists catch words, not intent. The health guard and the withholding list miss paraphrases and other languages than English and French. They reduce risk; they do not remove it.
  • Closed vocabularies lag behind. A role, topic or decision missing from VOCABULARY.md cannot be expressed until the next version.