> built 2026-10-08 12:17 UTC from 0d69851 (main) · acquaint 0.0.14. Details: build_info.json

# index.html.md

<!-- generated by epythet -->

# acquaint

People, and what they are involved in, for AI agents: who someone is, how to reach them, how to read them, how to write to them.

```bash
pip install acquaint

acquaint new person "Ada Lovelace"
acquaint remember ada-lovelace "prefers email for anything with attachments" --source "https://example.org/thread/1"
acquaint who ada -f aka                      # → Ada, Lovelace
acquaint brief ada-lovelace --purpose ask    # everything to know before writing to her
```

Tell an agent “write to Ada about the export” and it can find out, without being told again, who that is, where to reach her for this, what register to use, what to avoid, and where to record what it learns. The “how” is written down once, per person, and every agent, skill and tool reads it through the same verbs.

Records are hand-editable Markdown, one folder per person (or project, org, group), kept **outside any code repository**. Every preference carries its source, and `acquaint lint` fails when one does not.

## What it records, and what it never does

A profile holds observable behaviour with evidence: “replies in one or two lines”, “wants the decision first”, quoted and linked. It never holds personality labels, moods, or special-category data (health, religion, politics, ethnicity, sexuality, union membership), stated or inferred, nor credentials, identifiers, or whole message bodies. Every store gets a `POLICY.md` stating this, and `lint` warns on tripwires.

The test for every line: would it survive being handed to the person it is about?

## Where the data lives

The data root is the first of: the `data_dir` argument, `$ACQUAINT_DATA_DIR`, `data_dir` in `~/.config/acquaint/config.toml`, `~/.local/share/acquaint`.

```default
POLICY.md                       what may be recorded
people/ada-lovelace/
  PROFILE.md                    entry file: identity frontmatter + Who · Reach · Write to them · Read them · Don't · Now · More
  identities.yaml               handles and addresses, with evidence
  rules.yaml                    channel rules: when → do (channel, and the address
                                when the channel is addressed by conversation), who set it, source
  links.yaml                    affiliations: project, org, group; role; period
  style.md                      the writing card: AI tolerance, register, do, don't, blocklist, exemplars
  views.md                      positions and standing objections, sourced
  sources.md                    where their writing lives, how authorship was verified
  log/2026-09.md                append-only observations
projects/<id>/PROFILE.md        What & status · Where things live · Who · Agents & skills · Norms · Now
orgs/<id>/  groups/<id>/  …     any other kind
```

Only `PROFILE.md` is required. A malformed file is reported and skipped; it never breaks lookups of anyone else.

## The verbs

The same eighteen functions are the Python API (`acquaint.tools`), the CLI, and the MCP tools. Each returns a JSON-ready dict.

| Verb                                                                               | Does                                                                                                                                                                                                                                                                                                                                                         |
|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `who NAME [-f FIELD] [-b]`                                                         | one field (`email`, `aka`, `label`, `tier`, any frontmatter key), the identity block, or the whole entry file; lists candidates instead of guessing                                                                                                                                                                                                          |
| `resolve HANDLE`                                                                   | `github:octocat`, `email:…` → the person, with the evidence; a handle without its platform, a match by name only, or an inactive identity is reported, never acted on                                                                                                                                                                                        |
| `check TEXT`                                                                       | before publishing: one person written as two (“Ada or Lovelace”), shared names, unknown names                                                                                                                                                                                                                                                                |
| `reach PERSON [--purpose --urgency --project --message-type --topic]`              | ordered channels: the person’s own rules > the operator’s rules > project norms > observed habits > defaults                                                                                                                                                                                                                                                 |
| `brief PERSON [--purpose --project --ref CONVERSATION | --audience-json - | FILE]` | card, writing style, views, reach, project norms, recent observations, reminders, and what is **not** known; with `--ref` (correspond is asked who can read it; unknown is public) or an audience record, it opens with the ceiling, the records and terms not to identify, how many lines were withheld (never their text), and what they were already told |
| `remember ENTITY TEXT [--source --kind --disclosed --reactivate]`                  | append a dated, sourced observation (or identity, preference, view, rule); an `interaction` may list the records a message identified (`--disclosed project:heron`); an identity equal to an inactive one is refused, naming that entry, unless `--reactivate`                                                                                               |
| `disclosure ID... [--project SLUG] [--audience-json - | FILE]`                     | who may be told what: the tier and clearance in force for each reader, the least clearance, the seals, the terms a gate must scan for, what each was already told, and the gaps                                                                                                                                                                              |
| `review PERSON`                                                                    | everything that names someone’s disclosure standing, with sources and dates: tier entries, links, default tiers and clearances reached through links, seals, rules; exits 1 when an affiliation ended while a permissive tier is still in force. Run it when a collaboration ends, when someone changes role, or before changing a tier                      |
| `todo-preflight PROJECT PEOPLE`                                                    | before filing a meeting’s todos as issues: the project is unambiguous, every participant (comma-separated) is registered and linked to it, and its meta repository (`meta_repo: owner/name`, or `github_org: <org>` meaning `<org>/meta`, in the record’s frontmatter) is private now; returns each person’s GitHub login and a fix for every problem        |
| `lint [ENTITY]`                                                                    | sources on every preference; tiers, labels and seals set by the operator, with known values and review dates; parseable files; entry-file budget; policy tripwires                                                                                                                                                                                           |
| `style-lint TEXT [--recipient --tolerance]`                                        | machine-writing tells, enforced by the reader’s tolerance of AI-sounding text                                                                                                                                                                                                                                                                                |
| `new KIND NAME [--qualifier --description]`                                        | scaffold from a template; readable slug ids (`ada-lovelace`, `john-smith--example-org`)                                                                                                                                                                                                                                                                      |
| `rename ID TO`                                                                     | new id or name; links elsewhere rewritten (never inside URLs or logs); old forms kept as aliases                                                                                                                                                                                                                                                             |
| `forget ID [--confirm]`                                                            | remove the whole folder, leaving a salted tombstone so the person is not silently re-created                                                                                                                                                                                                                                                                 |
| `sync init --repo OWNER/NAME` · `sync push` · `sync pull` · `sync status`          | private-repository sync, below                                                                                                                                                                                                                                                                                                                               |

`--json` prints the result dict; `-` as the text of `check` or `style-lint` reads stdin.

Exit status: 0 on success; 1 when the result is not ok (the reason is on stderr); 2 for a usage error; 3 when `reach` matched a rule but no usable address is recorded for its channel (the rule is still listed, and the reason says what to add).

Nothing acts on a guess: a name, alias, handle or email counts only when exactly one record has it exactly, and a partial match comes back as a suggestion. `rename` and `forget` need the exact id.

## Sources

End every preference, view or rule with a source tag:

```markdown
## Write to them
- Lead with the decision, then the options. [source: self: "give me the recommendation first"]
- Short replies on chat, fuller ones by email. [source: log/2026-09.md#e03]
- No attachments over chat. [source: https://example.org/thread/1]
```

A source is a permalink, a log or research anchor, the person’s own words, `operator`, or `none located`. **A date alone is not a source**, and neither is a placeholder such as `unknown` or `TODO`: an unsourced claim with a date attached reads as observed when it was not. A nested bullet is its own line and needs its own source.

## Agent skills

Six skills ship inside the package (`acquaint/data/skills/`) and install with `gh skill`:

| Skill                    | For                                                                                                                               |
|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `acquaint`               | the router: lookups at the right cost, `check` before publishing, `remember` with sources                                         |
| `acquaint-profile`       | building a profile from someone’s own writing, with parallel `profile-reader` agents                                              |
| `acquaint-write`         | writing for a known reader, and sparring with a simulated one (`recipient-reader` agent)                                          |
| `acquaint-read`          | interpreting a message from a known person; AI-processing as a likelihood with evidence                                           |
| `deslop`                 | prose without machine-writing tells, calibrated to the reader                                                                     |
| `acquaint-sync`          | private sync, and what it does not protect                                                                                        |
| `acquaint-meeting-todos` | a meeting’s todos as one assigned `manual-task` issue per person in the project’s private meta repository, after `todo-preflight` |
```bash
gh skill install thorwhalen/acquaint acquaint --agent claude-code
```

`gh skill` needs a recent `gh`; otherwise symlink the folders from the installed package’s `acquaint/data/skills/` into `~/.claude/skills/`. If you already have a user-level skill named `deslop`, skip acquaint’s or install it under another name: two skills with the same name at the same scope replace each other.

## MCP

```bash
pip install "acquaint[mcp]"
```

```json
{"mcpServers": {"acquaint": {"command": "acquaint-mcp"}}}
```

The server exposes the tools that read locally, append or create (`who`, `resolve`, `check`, `reach`, `brief`, `remember`, `lint`, `new`, `style_lint`, `disclosure`). Renaming, forgetting and syncing stay at the terminal. `data_dir` is not exposed: the data root is the server’s (set `ACQUAINT_DATA_DIR` in the client configuration), never the model’s. Neither is `remember`’s `reactivate`: making an inactive identity active again is the operator’s call. Nor is `disclosure`’s `today`, which could revive a lapsed tier.

## Private sync

```bash
acquaint sync init --repo <owner>/<name> --dry-run
acquaint sync init --repo <owner>/<name>
```

`sync init` creates the repository through `gh` as private, refuses to continue unless `gh` reports it `PRIVATE`, and installs a pre-push hook, active in every worktree, that allows a push only through `origin`, only when `origin` has exactly the one URL recorded at init (no `pushurl` or `pushInsteadOf` redirect), only when that URL names the checked repository on github.com, and only while `gh` still reports it private. `push`, `pull` and `status` check again. `sync init` takes over only an empty folder or a clone of that same repository.

`sync status` also reports `auto_commit`: true only while the repository is private, owned by a person rather than an organisation, has that person as its only collaborator and no pending invitation. The `acquaint-profile` skill then commits and pushes profile edits straight away; otherwise it leaves them uncommitted for the operator to review. `auto_commit_reason` says which condition decided.

What this does **not** protect: a private repository is access control, not encryption (the host can read everything); `git push --no-verify` skips the hook; whoever controls the repository’s git config or the `gh` on `PATH` controls what the guard sees; moving the data root disables the hook until `sync init --existing-only` runs again; file names and commit messages contain people’s names; deleting a folder does not remove it from history or other clones. `git-remote-gcrypt` would encrypt contents, names and history; it is the planned upgrade, but the guard does not support it yet, so `sync init` refuses `gcrypt::` URLs ([#13](https://github.com/thorwhalen/acquaint/issues/13)).

## Python

```python
from acquaint import Store, who, brief

who("ada", field="aka")["value"]  # ['Ada', 'Lovelace']
print(brief("ada-lovelace", purpose="ask")["text"])

store = Store()  # MutableMapping[str, Entity] over a dol files store
entity = store[
    "people/ada-lovelace"
]  # a mapping of that person's files, plus parsed views
entity.identities, entity.rules, entity.sections["Write to them"]
Store(files={})  # any MutableMapping[str, str] of files: a dict, a remote store
```

## Design

The seams, surfaces and deliberate non-seams are in [Discussion #1](https://github.com/thorwhalen/acquaint/discussions/1).

<p class="epythet-aggregates">This documentation as a single file: <a href="acquaint.md">acquaint.md</a> (Markdown, for agents).</p>


# _autosummary/acquaint.deslop.html.md

# acquaint.deslop

The deterministic half of deslop: find the patterns that make prose read as machine-written, scaled to the reader.

How strict the check is depends on the recipient’s tolerance of AI-sounding text,
recorded as `ai_tolerance` in their `style.md` (`tolerant`, `neutral`,
`averse`; anything else counts as unknown, which is neutral):

- **tolerant** enforces tier E only, with looser counts;
- **neutral** enforces E and W;
- **averse** enforces E, W and S, with the tightest counts.

Findings outside the enforced tiers are still reported, marked `enforced: False`.
The tells catalogue itself lives in `ductus` (the read-side package that gauges how
machine-written a text reads); this module reads it from there and layers the reader
calibration on top, so the two halves cannot drift apart. It is still a keyword
argument, so a list derived from the operator’s own writing replaces it without code
changes.

```pycon
>>> result = lint_text("Great question! This robust tool serves as a bridge.", tolerance="neutral")
>>> sorted({f["rule"] for f in result["findings"] if f["enforced"]})
['ai-vocabulary', 'chat-leftover', 'copula-avoidance']
>>> lint_text("Sending the export on Friday. Two sites, not five.")["ok"]
True
```

### Functions

| [`shipped_catalogue`](_autosummary/acquaint.deslop.html.md#acquaint.deslop.shipped_catalogue)()                              | The default catalogue: `ductus`'s tells and thresholds, this package's calibration.                               |
|---------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|
| [`lint_text`](_autosummary/acquaint.deslop.html.md#acquaint.deslop.lint_text)(text, \*[, tolerance, blocklist, ...]) | Check a draft against the tells catalogue at a reader's tolerance: `{"ok", "findings", "metrics", "relational"}`. |
| [`normalize_tolerance`](_autosummary/acquaint.deslop.html.md#acquaint.deslop.normalize_tolerance)(value)                       | A recorded `ai_tolerance` as one of `TOLERANCES`, with a warning when it was something else.                      |
| [`recipient_card`](_autosummary/acquaint.deslop.html.md#acquaint.deslop.recipient_card)(entity)                           | What the check needs from a recipient's writing card (`style.md`): tolerance, disclosure, blocklist, warnings.    |
| [`text_metrics`](_autosummary/acquaint.deslop.html.md#acquaint.deslop.text_metrics)(text)                               | Counts the checks use: words, sentences, sentence-length variation, em-dash rate, headers, bold.                  |

### acquaint.deslop.lint_text(text, , tolerance='neutral', blocklist=(), catalog=None)

Check a draft against the tells catalogue at a reader’s tolerance: `{"ok", "findings", "metrics", "relational"}`.

`blocklist` holds phrases this recipient’s card says never to use; each hit is
tier E. `catalog` replaces the shipped catalogue (same schema as `tells.yaml`).
An unrecognised `tolerance` is an error here; normalise recorded values first
with [`normalize_tolerance()`](_autosummary/acquaint.deslop.html.md#acquaint.deslop.normalize_tolerance).

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.deslop.normalize_tolerance(value)

A recorded `ai_tolerance` as one of `TOLERANCES`, with a warning when it was something else.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)]

```pycon
>>> normalize_tolerance("Averse"), normalize_tolerance(None)
(('averse', None), ('unknown', None))
>>> normalize_tolerance("low")[0]
'unknown'
```

### acquaint.deslop.recipient_card(entity)

What the check needs from a recipient’s writing card (`style.md`): tolerance, disclosure, blocklist, warnings.

`ai_tolerance` and `disclosure` come from the card’s frontmatter. Blocklist
phrases are the items of its `## Blocklist` section: the quoted phrase when an item
quotes one, else the item without its source tag.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.deslop.shipped_catalogue()

The default catalogue: `ductus`’s tells and thresholds, this package’s calibration.

`ductus` owns the patterns and the shared rhythm thresholds – it is the read
side, and a catalogue that disagreed with the one used to *find* machine writing
would be worse than useless. What this package adds is the part `ductus`
deliberately lacks: who tolerates what.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

```pycon
>>> catalogue = shipped_catalogue()
>>> sorted(catalogue)
['metrics', 'relational', 'rules', 'tolerance']
>>> len(catalogue["rules"]) > 10 and "averse" in catalogue["tolerance"]
True
```

### acquaint.deslop.text_metrics(text)

Counts the checks use: words, sentences, sentence-length variation, em-dash rate, headers, bold.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`float`](https://docs.python.org/3/builtins/functions.html#float)]

```pycon
>>> text_metrics("One two three. Four five!")["sentences"]
2
```


# _autosummary/acquaint.edit.html.md

# acquaint.edit

Changing the store: create an entity, append an observation, rename with relinking, forget with a tombstone.

The hot path is append-only. [`append_observation()`](_autosummary/acquaint.edit.html.md#acquaint.edit.append_observation) never edits an entry file, a
writing card or a rule: it appends a dated, sourced entry to `log/YYYY-MM.md` (or a
handle to `identities.yaml`). The one change it makes to an existing entry is making an
inactive handle active again, and only when asked (`reactivate`). `identities.yaml` is
rewritten whenever it changes, so comments in it are not kept. Turning observations into
profile lines is a separate, reviewed pass.

These functions take exact references (`ada-lovelace`, `person:ada-lovelace`,
`people/ada-lovelace`); matching names to ids is the caller’s job
([`acquaint.lookup.find_entity()`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.find_entity)), so nothing here acts on a guess.

### Module Attributes

| [`OBSERVATION_KINDS`](_autosummary/acquaint.edit.html.md#acquaint.edit.OBSERVATION_KINDS)   | What `remember` can record.   |
|----------------------------------------------------------------------|-------------------------------|

### Functions

| [`append_observation`](_autosummary/acquaint.edit.html.md#acquaint.edit.append_observation)(store, ref, text, \*[, ...])   | Append one dated, sourced entry to the entity's `log/YYYY-MM.md` (and, for `identity`, to `identities.yaml`).   |
|----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| [`forget_entity`](_autosummary/acquaint.edit.html.md#acquaint.edit.forget_entity)(store, ref, \*[, confirm, today])   | Remove an entity's whole folder, hidden files included, after writing a salted tombstone.                       |
| [`new_entity`](_autosummary/acquaint.edit.html.md#acquaint.edit.new_entity)(store, kind, name, \*[, ...])          | Scaffold `<kind dir>/<slug>/PROFILE.md` from the template for its kind, and seed `POLICY.md`.                   |
| [`rename_entity`](_autosummary/acquaint.edit.html.md#acquaint.edit.rename_entity)(store, ref, to, \*[, today])        | Give an entity a new id (`to` is a slug) or a new name and id (`to` is a name); links elsewhere follow.         |
| [`tombstone_problem`](_autosummary/acquaint.edit.html.md#acquaint.edit.tombstone_problem)(store)                          | Why `_tombstones.yaml` cannot be trusted, or `None`.                                                            |
| [`tombstoned`](_autosummary/acquaint.edit.html.md#acquaint.edit.tombstoned)(store, \*identifiers)                  | The tombstone matching any of these identifiers, if such an entity was forgotten.                               |

### acquaint.edit.OBSERVATION_KINDS *= ('observation', 'interaction', 'identity', 'preference', 'view', 'rule')*

What `remember` can record. The last three need a source at write time.

### acquaint.edit.append_observation(store, ref, text, , source=None, kind='observation', reactivate=False, disclosed=(), today=None)

Append one dated, sourced entry to the entity’s `log/YYYY-MM.md` (and, for `identity`, to `identities.yaml`).

An identity equal to an inactive one is refused, naming that entry, unless
`reactivate` is set (see `_append_identity()`). `disclosed` (`interaction`
only) lists the records the message identified, by exact id or reference, written as
references (`project:heron`); never the text. A refusal writes nothing.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.edit.forget_entity(store, ref, , confirm=False, today=None)

Remove an entity’s whole folder, hidden files included, after writing a salted tombstone.

Without `confirm` it only reports what it would remove, and which other records
still mention the entity (it does not edit them: other people’s logs are append-only).
The tombstone is written first, so a removal that fails half way still stops the
entity being re-created, and running `forget` again finishes the job.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.edit.new_entity(store, kind, name, , qualifier=None, description=None, force=False, today=None)

Scaffold `<kind dir>/<slug>/PROFILE.md` from the template for its kind, and seed `POLICY.md`.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.edit.rename_entity(store, ref, to, , today=None)

Give an entity a new id (`to` is a slug) or a new name and id (`to` is a name); links elsewhere follow.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.edit.tombstone_problem(store)

Why `_tombstones.yaml` cannot be trusted, or `None`. A broken file must never read as “nobody was forgotten”.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

### acquaint.edit.tombstoned(store, \*identifiers)

The tombstone matching any of these identifiers, if such an entity was forgotten. Raises if the tombstone file is broken.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict) | [`None`](https://docs.python.org/3/builtins/constants.html#None)


# _autosummary/acquaint.html.md

# acquaint

acquaint: people, and what they are involved in, for AI agents.

Who someone is, how to reach them, how to read them, how to write to them, kept as
hand-editable Markdown with a source on every preference, outside any code repository.

The verbs are the same in Python, on the command line (`acquaint who ada -f aka`) and
over MCP:

```default
>>> from acquaint import new, remember, who, brief
>>> new("person", "Ada Lovelace")
>>> remember("ada-lovelace", "prefers email for anything with attachments",
...          source="https://example.org/thread/1")
>>> who("ada", field="aka")["value"]
['Ada', 'Lovelace']
```

For library use, [`Store`](_autosummary/acquaint.html.md#acquaint.Store) is a `MutableMapping` of entities over any mapping of
files (a `dol` files store by default).

### Functions

| [`brief`](_autosummary/acquaint.html.md#acquaint.brief)(person, \*[, purpose, project, ref, ...])    | Everything to know before writing to someone: card, writing style, reach, project norms, recent observations, gaps.                                                                                                                                                                                                                      |
|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`check`](_autosummary/acquaint.html.md#acquaint.check)(text, \*[, data_dir])                        | Scan prose that names people before publishing it: conflations (one person written as two), ambiguous names, unknown names.                                                                                                                                                                                                              |
| [`data_dir`](_autosummary/acquaint.html.md#acquaint.data_dir)([data_dir])                               | The data root: the argument, else `$ACQUAINT_DATA_DIR`, else `data_dir` in config.toml, else `~/.local/share/acquaint`.                                                                                                                                                                                                                  |
| [`disclosure`](_autosummary/acquaint.html.md#acquaint.disclosure)(people, \*[, projects, audience, ...])  | Who may be told what, before writing to a set of readers (ids or channel identities, plus an optional correspond `audience` record as JSON): the tier and clearance in force for each, the least clearance, which records each is cleared for, the seals, the vocabulary a gate must scan for, what each was already told, and the gaps. |
| [`forget`](_autosummary/acquaint.html.md#acquaint.forget)(entity, \*[, confirm, data_dir])            | Remove an entity's folder and leave a salted tombstone.                                                                                                                                                                                                                                                                                  |
| [`lint`](_autosummary/acquaint.html.md#acquaint.lint)([entity, data_dir])                           | Check records: every preference, view and rule sourced; tiers, labels and seals set by the operator; nothing POLICY.md forbids; files parse; entry files within budget.                                                                                                                                                                  |
| [`new`](_autosummary/acquaint.html.md#acquaint.new)(kind, name, \*[, qualifier, description, ...]) | Create a person, project, org or group from its template (a readable slug id; `qualifier` separates two of the same name).                                                                                                                                                                                                               |
| [`reach`](_autosummary/acquaint.html.md#acquaint.reach)(person, \*[, purpose, urgency, ...])         | Ordered channels for reaching someone in a context.                                                                                                                                                                                                                                                                                      |
| [`remember`](_autosummary/acquaint.html.md#acquaint.remember)(entity, text, \*[, source, kind, ...])    | Append a dated observation (`observation`, `interaction`, `identity`, `preference`, `view`, `rule`) to an entity's log, with its source.                                                                                                                                                                                                 |
| [`rename`](_autosummary/acquaint.html.md#acquaint.rename)(entity, to, \*[, data_dir])                 | Change an entity's id (`to` is a slug) or name and id (`to` is a name), rewriting links to it.                                                                                                                                                                                                                                           |
| [`resolve`](_autosummary/acquaint.html.md#acquaint.resolve)(handle, \*[, data_dir])                    | Map a channel handle (`github:octocat`, `email:ada@example.org`) to the entity it belongs to, with the evidence.                                                                                                                                                                                                                         |
| [`review`](_autosummary/acquaint.html.md#acquaint.review)(person, \*[, today, data_dir])              | Everything the store says about one person's disclosure standing, with sources and dates, to confirm when a collaboration ends, when someone changes role, or before a tier changes: tier entries, links, the default tiers and clearances reached through links, seals on records and on fact lines, and the rules that name them.      |
| [`style_lint`](_autosummary/acquaint.html.md#acquaint.style_lint)(text, \*[, recipient, tolerance, ...])  | The deterministic half of deslop: machine-writing tells in a draft, at the recipient's tolerance and against their blocklist.                                                                                                                                                                                                            |
| [`sync_init`](_autosummary/acquaint.html.md#acquaint.sync_init)(\*, repo[, remote_url, ...])             | Make the data root a checkout of a PRIVATE GitHub repository (created private through `gh` unless `existing_only`), with a pre-push guard.                                                                                                                                                                                               |
| [`sync_pull`](_autosummary/acquaint.html.md#acquaint.sync_pull)(\*[, dry_run, data_dir])                 | Pull the store from its private remote, rebasing local work on top.                                                                                                                                                                                                                                                                      |
| [`sync_push`](_autosummary/acquaint.html.md#acquaint.sync_push)(\*[, message, dry_run, data_dir])        | Commit, rebase onto the remote and push the store, after re-checking the remote, the guard and the visibility.                                                                                                                                                                                                                           |
| [`sync_status`](_autosummary/acquaint.html.md#acquaint.sync_status)(\*[, check_visibility, data_dir])      | Whether the store is synced, to which repository, uncommitted changes, ahead/behind, the guard, and live visibility.                                                                                                                                                                                                                     |
| [`who`](_autosummary/acquaint.html.md#acquaint.who)(name, \*[, field, brief, data_dir])            | Look up one person, project, org or group by exact id, name, alias, handle or email.                                                                                                                                                                                                                                                     |

### Classes

| [`Entity`](_autosummary/acquaint.html.md#acquaint.Entity)(store, key)       | One person, project, org or group: a mapping of its files (relative names to text), plus parsed views of them.   |
|---------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
| [`Store`](_autosummary/acquaint.html.md#acquaint.Store)([data_dir, files]) | `MutableMapping[str, Entity]` over one folder per entity, keyed `"<kind dir>/<slug>"`.                           |

### Exceptions

| [`AcquaintError`](_autosummary/acquaint.html.md#acquaint.AcquaintError)   | An expected failure with a message meant for the person or agent that asked.   |
|------------------------------------------------------------------|--------------------------------------------------------------------------------|

### *exception* acquaint.AcquaintError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

An expected failure with a message meant for the person or agent that asked.

### *class* acquaint.Entity(store, key)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)

One person, project, org or group: a mapping of its files (relative names to text), plus parsed views of them.

Parsed views are recomputed on access (these are small text files), so an edit made
through the mapping is never hidden behind a stale cache. Parse problems are collected
in [`errors`](_autosummary/acquaint.html.md#acquaint.Entity.errors); they never raise.

#### *property* aka *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

Other names this entity goes by, as strings (a scalar `aka` is one alias, not its letters).

#### *property* body *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

The entry file’s Markdown body.

#### *property* errors *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

Everything about the entry file and the YAML files that did not parse.

#### *property* identities *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{platform, value, source, status, …}`.

* **Type:**
  Handles and addresses from `identities.yaml`

#### *property* kind *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

`person`, `project`, `org`, `group`, or the singular of an open kind’s folder.

#### *property* links *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{to, relation, role, since, until, source}`.

* **Type:**
  Affiliations from `links.yaml`

#### *property* meta *: [dict](https://docs.python.org/3/builtins/stdtypes.html#dict)*

The entry file’s frontmatter (empty when it did not parse).

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

The display name, falling back to the id.

#### *property* ref *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

`person:ada-lovelace`.

* **Type:**
  The link form other records use

#### *property* rules *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{when, do, set_by, source}`.

* **Type:**
  Channel and communication rules from `rules.yaml`

#### *property* sections *: [dict](https://docs.python.org/3/builtins/stdtypes.html#dict)[[str](https://docs.python.org/3/builtins/stdtypes.html#str), [str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

The entry file’s `## Sections`, keyed by normalized title.

#### summary()

The identity block: frontmatter plus identities, JSON-ready.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

#### *property* surface_forms *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

id, name, aka, name parts, handles.

* **Type:**
  Every string a document might use for this entity

#### text(name, default='')

A file’s text, or `default` when the file does not exist.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### *property* trust *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{tier, valid_from, valid_to, review_by, recorded, source, note}` (see [`acquaint.trust`](_autosummary/acquaint.trust.html.md#module-acquaint.trust)).

* **Type:**
  Disclosure tiers from `trust.yaml`

### *class* acquaint.Store(data_dir=None, , files=None)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)

`MutableMapping[str, Entity]` over one folder per entity, keyed `"<kind dir>/<slug>"`.

```pycon
>>> store = Store(files={})
>>> store["projects/example"] = {"PROFILE.md": "---\nname: Example\n---\n"}
>>> store.find("project:example"), store.find("example")
('projects/example', 'projects/example')
```

#### all_files(key)

Every file under the entity’s folder, hidden ones included.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### append_text(key, name, text)

Append to one of an entity’s files (created if missing); a true append on disk, so concurrent writers do not erase each other.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### exists(key)

Whether anything is stored under the entity’s folder, with or without an entry file.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### find(ref)

The store key for `people/ada-lovelace`, `person:ada-lovelace` or a bare `ada-lovelace`.

A bare id that names entities of two kinds is an error: say which, e.g.
`project:atlas`. Anything that is not a valid key raises `KeyError`, so no
reference reaches outside the data root.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### find_id(slug)

Every key whose id is `slug`, in any kind (ids are lowercase, so the lookup is too).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### location_warning()

A warning when the data root is, or sits inside, a git repository that is not an acquaint store.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### misnamed()

Entry files on disk the store cannot address: a folder or file name not in lowercase `kind/id/PROFILE.md` form, or a linked folder.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### move(src, dst)

Move an entity’s whole folder to a new key (hidden files included).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### path_of(key)

Where an entity lives, for a person to open: a real path when on disk, else the key.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### acquaint.brief(person, , purpose=None, project=None, ref=None, audience=None, data_dir=None)

Everything to know before writing to someone: card, writing style, reach, project norms, recent observations, gaps. With `ref` (the conversation the message goes to; correspond is asked who can read it, and an unknown audience is public) or `audience` (an audience record as JSON), it opens with the ceiling, the records not to identify, how many lines were withheld, and what they were already told.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.check(text, , data_dir=None)

Scan prose that names people before publishing it: conflations (one person written as two), ambiguous names, unknown names.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.data_dir(data_dir=None)

The data root: the argument, else `$ACQUAINT_DATA_DIR`, else `data_dir` in config.toml, else `~/.local/share/acquaint`.

An explicit argument may be relative (it is resolved now). The environment variable
and the config file must hold absolute paths: a relative one would put profiles
wherever the current directory happens to be.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

```pycon
>>> data_dir("profiles").is_absolute()
True
```

### acquaint.disclosure(people, , projects=None, audience=None, today=None, data_dir=None)

Who may be told what, before writing to a set of readers (ids or channel identities, plus an optional correspond `audience` record as JSON): the tier and clearance in force for each, the least clearance, which records each is cleared for, the seals, the vocabulary a gate must scan for, what each was already told, and the gaps. `projects` limits the records to those plus people. Reads only.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.forget(entity, , confirm=False, data_dir=None)

Remove an entity’s folder and leave a salted tombstone. Needs the exact id; without `confirm`, only reports what would be removed.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.lint(entity=None, , data_dir=None)

Check records: every preference, view and rule sourced; tiers, labels and seals set by the operator; nothing POLICY.md forbids; files parse; entry files within budget.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.new(kind, name, , qualifier=None, description=None, force=False, data_dir=None)

Create a person, project, org or group from its template (a readable slug id; `qualifier` separates two of the same name).

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.reach(person, , purpose=None, urgency=None, project=None, message_type=None, topic=None, data_dir=None)

Ordered channels for reaching someone in a context. Only active addresses; returns them, sends nothing. `outcome` is `reachable`, `no_address` (a rule matched, but neither states an address nor finds a usable one recorded for its channels) or `no_channel`. Each channel’s `address_kind` is `stated`, `identity` (the person’s handle, which a conversation-addressed channel does not take) or `None`.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.remember(entity, text, , source=None, kind='observation', disclosed=None, reactivate=False, data_dir=None)

Append a dated observation (`observation`, `interaction`, `identity`, `preference`, `view`, `rule`) to an entity’s log, with its source. An `interaction` may list the records the message identified (`disclosed`: exact ids, never the text). An identity equal to an inactive one (`stale`, `retracted`, …) is refused, naming that entry and the command with which the operator can make it active again.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.rename(entity, to, , data_dir=None)

Change an entity’s id (`to` is a slug) or name and id (`to` is a name), rewriting links to it. Needs the exact id.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.resolve(handle, , data_dir=None)

Map a channel handle (`github:octocat`, `email:ada@example.org`) to the entity it belongs to, with the evidence.

`ok` is true only when an active identity on the named platform belongs to exactly
one entity. A handle without a platform (`@octocat`), a match by name only, an
inactive identity, or several owners all return `ok: false` with what was found.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.review(person, , today=None, data_dir=None)

Everything the store says about one person’s disclosure standing, with sources and dates, to confirm when a collaboration ends, when someone changes role, or before a tier changes: tier entries, links, the default tiers and clearances reached through links, seals on records and on fact lines, and the rules that name them. Not ok when an affiliation has ended while a permissive tier is still in force. Reads only.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.style_lint(text, , recipient=None, tolerance=None, data_dir=None)

The deterministic half of deslop: machine-writing tells in a draft, at the recipient’s tolerance and against their blocklist.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.sync_init(, repo, remote_url=None, existing_only=False, dry_run=False, data_dir=None)

Make the data root a checkout of a PRIVATE GitHub repository (created private through `gh` unless `existing_only`), with a pre-push guard.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.sync_pull(, dry_run=False, data_dir=None)

Pull the store from its private remote, rebasing local work on top.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.sync_push(, message=None, dry_run=False, data_dir=None)

Commit, rebase onto the remote and push the store, after re-checking the remote, the guard and the visibility.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.sync_status(, check_visibility=True, data_dir=None)

Whether the store is synced, to which repository, uncommitted changes, ahead/behind, the guard, and live visibility.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.who(name, , field=None, brief=False, data_dir=None)

Look up one person, project, org or group by exact id, name, alias, handle or email.

Costs scale with what you ask: `field` returns one value (`aka`, `email`,
`github`, `label`, `tier`, any frontmatter key), `brief` the identity block, and the default the
whole entry file. It never guesses: no exact match, or several, returns the
candidates and `ok: false`.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### Modules

| [`deslop`](_autosummary/acquaint.deslop.html.md#module-acquaint.deslop)       | The deterministic half of deslop: find the patterns that make prose read as machine-written, scaled to the reader.                                                               |
|--------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`edit`](_autosummary/acquaint.edit.html.md#module-acquaint.edit)           | Changing the store: create an entity, append an observation, rename with relinking, forget with a tombstone.                                                                     |
| [`lookup`](_autosummary/acquaint.lookup.html.md#module-acquaint.lookup)       | Finding the right record: exact references, handle resolution, the conflation check, and channel choice.                                                                         |
| [`mcp`](_autosummary/acquaint.mcp.html.md#module-acquaint.mcp)             | MCP over stdio: the same tools, for Claude Desktop and other local MCP clients.                                                                                                  |
| [`meta`](_autosummary/acquaint.meta.html.md#module-acquaint.meta)           | Where a project's meeting todos may be filed: its declared private meta repository, and the people who belong to it.                                                             |
| [`records`](_autosummary/acquaint.records.html.md#module-acquaint.records)     | The text formats acquaint stores, as pure functions: frontmatter, sections, items, source tags, slugs, log entries.                                                              |
| [`render`](_autosummary/acquaint.render.html.md#module-acquaint.render)       | Turning a tool's result into terminal output: `(stdout, stderr, exit code)`.                                                                                                     |
| [`resources`](_autosummary/acquaint.resources.html.md#module-acquaint.resources) | Files shipped inside the package: record templates, the policy tripwires, purpose reminders, the tells catalogue, skills.                                                        |
| [`store`](_autosummary/acquaint.store.html.md#module-acquaint.store)         | Where records live and how code reaches them: the data root, [`Store`](_autosummary/acquaint.html.md#acquaint.Store) and [`Entity`](_autosummary/acquaint.html.md#acquaint.Entity). |
| [`sync`](_autosummary/acquaint.sync.html.md#module-acquaint.sync)           | Private-repository sync for the data root: create the repository private, refuse anything else, guard every push.                                                                |
| [`tools`](_autosummary/acquaint.tools.html.md#module-acquaint.tools)         | The single source of truth for every surface: plain functions, flat arguments in, JSON-ready dicts out.                                                                          |
| [`trust`](_autosummary/acquaint.trust.html.md#module-acquaint.trust)         | The disclosure vocabulary: tiers on people; labels, seals and clearances on records; and which tier is in force.                                                                 |


# _autosummary/acquaint.lookup.html.md

# acquaint.lookup

Finding the right record: exact references, handle resolution, the conflation check, and channel choice.

All functions take a [`Store`](_autosummary/acquaint.store.html.md#acquaint.store.Store) and return plain data. Matching is
deterministic normalisation (case, punctuation and accents ignored). Nothing here acts
on a partial match or picks between candidates: an id and another record’s exact alias
compete on equal terms, partials are offered as suggestions, and [`find_entity()`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.find_entity)
refuses when more than one record fits. One unreadable record is reported and skipped;
it never takes a lookup down.

### Module Attributes

| [`TIERS`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.TIERS)            | Who set a rule, most authoritative first.                                              |
|-------------------------------------------------------------------|----------------------------------------------------------------------------------------|
| [`USABLE_STATUSES`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.USABLE_STATUSES)  | An identity is usable only with one of these statuses (none recorded means active).    |
| [`INACTIVE_RULES`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.INACTIVE_RULES)   | A rule is out of use with one of these statuses.                                       |
| [`NO_CHANNEL_NAMED`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.NO_CHANNEL_NAMED) | What a channel entry is called when its rule named none, so no repr stands in for one. |

### Functions

| [`check_text`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.check_text)(store, text)                         | Scan prose for people errors before it is published.                                                                                    |
|--------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| [`find_entity`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.find_entity)(store, ref, \*[, names])            | The one store key a reference names, or an `AcquaintError` saying why not.                                                              |
| [`match`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.match)(store, query)                             | Store keys matching a name, alias, handle, email or id: `{"exact": [...], "partial": [...], "unreadable": [...]}`.                      |
| [`normalise_handle`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.normalise_handle)(platform, value)               | A handle's comparable form: an email lowercased, with Gmail dots and `+tags` folded; any other value lowercased, without a leading `@`. |
| [`normalize`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.normalize)(text)                                 | Lowercase ASCII letters and digits only, for comparing names and handles.                                                               |
| [`reach_channels`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.reach_channels)(store, key, \*[, defaults_text]) | Ordered channels for reaching one entity in a context (`purpose`, `urgency`, `project`, `message_type`, `topic`).                       |
| [`resolve_handle`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.resolve_handle)(store, handle)                   | Who a channel handle belongs to, with the evidence: `{"platform", "matches", "inactive", "by_name", "unreadable"}`.                     |

### acquaint.lookup.INACTIVE_RULES *= {'dead', 'draft', 'expired', 'retracted', 'superseded'}*

A rule is out of use with one of these statuses.

### acquaint.lookup.NO_CHANNEL_NAMED *= '(no channel named)'*

What a channel entry is called when its rule named none, so no repr stands in for one.

### acquaint.lookup.TIERS *= ('self', 'operator', 'affiliation', 'observed', 'default')*

Who set a rule, most authoritative first. The operator’s instruction for the message
at hand outranks all of these; it belongs to the caller, not the store.

### acquaint.lookup.USABLE_STATUSES *= {'active', 'relay'}*

An identity is usable only with one of these statuses (none recorded means active).
Anything else (stale, former, unverified, retracted, dead, …) is reported, never acted on.

### acquaint.lookup.check_text(store, text)

Scan prose for people errors before it is published.

Reports the entities mentioned; **conflations** (one entity written as if it were two:
two different names for it joined by “or”, “and”, “/”, “,” …, citation order such as
“Lovelace, Ada” excepted); **ambiguous** forms shared by several entities; and
**unknown** name-like phrases that match nobody.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.lookup.find_entity(store, ref, , names=True)

The one store key a reference names, or an `AcquaintError` saying why not.

`person:ada-lovelace` and `people/ada-lovelace` are exact and decide on their own.
A bare word is looked up as an id (in any kind, any case) and, with `names`, as an
exact name, alias, handle or email; it resolves only when exactly one record fits all
of these together. A partial match never counts; it is offered as a suggestion.
Operations that rewrite or remove records pass `names=False` and need the id.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### acquaint.lookup.match(store, query)

Store keys matching a name, alias, handle, email or id: `{"exact": [...], "partial": [...], "unreadable": [...]}`.

`partial` holds entities where the query is part of a longer form (three characters
or more): suggestions for a person, never something to act on.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)]

### acquaint.lookup.normalise_handle(platform, value)

A handle’s comparable form: an email lowercased, with Gmail dots and `+tags` folded; any other value lowercased, without a leading `@`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### acquaint.lookup.normalize(text)

Lowercase ASCII letters and digits only, for comparing names and handles.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> normalize("Zoë O'Example")
'zoeoexample'
```

### acquaint.lookup.reach_channels(store, key, , defaults_text='', \*\*context)

Ordered channels for reaching one entity in a context (`purpose`, `urgency`, `project`, `message_type`, `topic`).

Precedence: the person’s own stated rules > the operator’s rules about them > norms of
a project or affiliation > observed habits > global defaults. Within a tier the most
specific matching rule wins. Only usable addresses are offered; a rule value that is
not a channel name is skipped with a note. It returns addresses; it sends nothing.

Each channel carries `address_kind`: `stated` when a rule gave the address,
`identity` when it was built from one of the entity’s identities, `None` when
there is no address. The distinction matters because an identity-built address is a
*handle* (`github:ada`), and a channel addressed by conversation rather than by
person (GitHub, a web inbox, a chat channel) does not take one. Such a channel’s rule
states its address.

A channel’s **position** is decided by the best-placed rule that names it; its
**address** by the best-placed rule that states one, which may be a different rule. A
rule that names a channel without stating an address expresses no opinion about where
that channel goes, so it does not bury an address a lower-placed rule states; the note
says which rule file the address came from when the two differ.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.lookup.resolve_handle(store, handle)

Who a channel handle belongs to, with the evidence: `{"platform", "matches", "inactive", "by_name", "unreadable"}`.

`github:octocat`, `email:ada@example.org` and `ada@example.org` name a platform;
`@octocat` does not, so it matches that handle on any platform. Only identities with
a usable status (see [`USABLE_STATUSES`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.USABLE_STATUSES)) are matches; the rest are reported under
`inactive` with their status. A handle found in no identity file is matched against
names under `by_name`, which is never enough to act on.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]


# _autosummary/acquaint.mcp.html.md

# acquaint.mcp

MCP over stdio: the same tools, for Claude Desktop and other local MCP clients.

Run `acquaint-mcp` (install the extra first: `pip install "acquaint[mcp]"`). The
exposed tools are named by `acquaint.tools:<name>` reference, so the core never imports
an MCP library. By default only tools that read locally, append or create are exposed;
renaming, forgetting and syncing are operator actions and stay at the terminal.

The data root is the server’s, never the model’s: `data_dir` is removed from every
tool’s schema, so a model cannot write profiles into whatever directory it is working
in. `remember`’s `reactivate` is removed too: making an inactive identity active
again changes a recorded status, which is the operator’s call. `disclosure`’s `today` is
removed too: a model that could set the date could revive a lapsed tier. Point the server
elsewhere with `ACQUAINT_DATA_DIR` in the client configuration:

```default
{"mcpServers": {"acquaint": {"command": "acquaint-mcp"}}}
```

### Functions

| [`main`](_autosummary/acquaint.mcp.html.md#acquaint.mcp.main)()                   | Serve the default tools over stdio.                                                      |
|---------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
| [`mk_server`](_autosummary/acquaint.mcp.html.md#acquaint.mcp.mk_server)(\*[, effects]) | A FastMCP server over the selected tools, with `HIDDEN_PARAMETERS` hidden (not started). |
| [`refs`](_autosummary/acquaint.mcp.html.md#acquaint.mcp.refs)(\*[, effects])      | `acquaint.tools:<name>` references for the tools whose side effects are in `effects`.    |

### acquaint.mcp.main()

Serve the default tools over stdio.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

### acquaint.mcp.mk_server(, effects=('read', 'append', 'create'))

A FastMCP server over the selected tools, with `HIDDEN_PARAMETERS` hidden (not started).

### acquaint.mcp.refs(, effects=('read', 'append', 'create'))

`acquaint.tools:<name>` references for the tools whose side effects are in `effects`.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

```pycon
>>> "acquaint.tools:brief" in refs(), "acquaint.tools:forget" in refs(), "acquaint.tools:sync_status" in refs()
(True, False, False)
```


# _autosummary/acquaint.meta.html.md

# acquaint.meta

Where a project’s meeting todos may be filed: its declared private meta repository, and the people who belong to it.

Before agents file todos from a meeting as GitHub issues, three things must hold, and
[`todo_preflight()`](_autosummary/acquaint.meta.html.md#acquaint.meta.todo_preflight) checks them against the store and the live repository:

1. **the project is unambiguous**: exactly one `project` or `org` record matches;
2. **every participant is registered and belongs to it**: each resolves to exactly one
   person whose `links.yaml` links them to that project or org;
3. **the project declares a private meta repository**: `meta_repo: owner/name` in the
   record’s frontmatter, or `github_org: <org>`, which means `<org>/meta`; and `gh`
   reports that repository private now.

Every failed check comes back as a problem with a concrete fix, so the skill can tell the
user how to proceed instead of guessing. Each participant’s GitHub login (an active
`github` identity) is returned for assigning issues, with a warning when there is none.

```pycon
>>> meta_repo_of({"github_org": "example-org"})
'example-org/meta'
>>> meta_repo_of({"meta_repo": "ada-lovelace/notes", "github_org": "example-org"})
'ada-lovelace/notes'
>>> meta_repo_of({}) is None
True
```

### Module Attributes

| [`META_REPO_NAME`](_autosummary/acquaint.meta.html.md#acquaint.meta.META_REPO_NAME)   | The repository name a declared `github_org` implies.   |
|-------------------------------------------------------------------|--------------------------------------------------------|

### Functions

| [`meta_repo_of`](_autosummary/acquaint.meta.html.md#acquaint.meta.meta_repo_of)(meta)                                | The meta repository a record's frontmatter declares: `meta_repo`, else `<github_org>/meta`, else `None`.         |
|----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
| [`repo_privacy`](_autosummary/acquaint.meta.html.md#acquaint.meta.repo_privacy)(repo, \*[, run])                     | `(True, …)` if `gh` reports the repository private now, `(False, …)` if not, `(None, why)` if it could not tell. |
| [`todo_preflight`](_autosummary/acquaint.meta.html.md#acquaint.meta.todo_preflight)(store, project, people, \*[, run]) | Check that meeting todos for `project` and `people` may be filed, and where.                                     |

### acquaint.meta.META_REPO_NAME *= 'meta'*

The repository name a declared `github_org` implies.

### acquaint.meta.meta_repo_of(meta)

The meta repository a record’s frontmatter declares: `meta_repo`, else `<github_org>/meta`, else `None`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

### acquaint.meta.repo_privacy(repo, \*, run=<function run_command>)

`(True, …)` if `gh` reports the repository private now, `(False, …)` if not, `(None, why)` if it could not tell.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`bool`](https://docs.python.org/3/builtins/functions.html#bool) | [`None`](https://docs.python.org/3/builtins/constants.html#None), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### acquaint.meta.todo_preflight(store, project, people, \*, run=<function run_command>)

Check that meeting todos for `project` and `people` may be filed, and where.

Returns `ok`, the resolved `project` reference, the `meta_repo`, one row per
participant (`ref`, `github`), `problems` (each a `check`, a `message` and a
`fix`) and `warnings`. `ok` is false whenever any problem is found.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]


# _autosummary/acquaint.records.html.md

# acquaint.records

The text formats acquaint stores, as pure functions: frontmatter, sections, items, source tags, slugs, log entries.

Nothing here touches a filesystem. A record is text in and data out, so the same
rules hold whether the text came from disk, a `dict` or a remote store. Every parser
accepts `\r\n` line endings and a leading byte-order mark, because a store edited on
Windows will have them.

The formats are deliberately hand-editable Markdown: YAML frontmatter for what a
machine looks up, `## Sections` of items for what a person writes, and an inline
`[source: …]` tag on every item that states a preference, a view or a rule (beside it, a
fact may carry `[label: …]` and `[sealed-from: …]`, read by the same tag reader). Sections,
items and code blocks follow CommonMark’s rules closely enough that what a reader sees
as one line under a heading is what the lint checks.

```pycon
>>> slugify("Ada Lovelace")
'ada-lovelace'
>>> meta, body, errors = split_frontmatter("\ufeff---\r\nname: Ada\r\n---\r\n## Who\r\n- a mathematician\r\n")
>>> meta, list(sections(body)), errors
({'name': 'Ada'}, ['Who'], [])
>>> source_problem("- Prefers email. [source: https://example.org/thread/1]") is None
True
>>> source_problem("- Prefers email. [source: 11th September 2026]")
'a date alone is not a source'
```

### Module Attributes

| [`NONE_LOCATED`](_autosummary/acquaint.records.html.md#acquaint.records.NONE_LOCATED)   | The words that say "no primary source was found", out loud.   |
|-----------------------------------------------------------------|---------------------------------------------------------------|

### Functions

| [`blank_frontmatter`](_autosummary/acquaint.records.html.md#acquaint.records.blank_frontmatter)(text)                          | The text with its frontmatter lines emptied, so line numbers still match the file.                                           |
|---------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| [`disclosed_refs`](_autosummary/acquaint.records.html.md#acquaint.records.disclosed_refs)(value)                            | The record references a log entry's `disclosed:` field lists, lowercased: `project:heron, org:example` or `[project:heron]`. |
| [`dump_yaml`](_autosummary/acquaint.records.html.md#acquaint.records.dump_yaml)(data)                                  | Write YAML the way a person would: keys in order, short lists inline, unicode kept.                                          |
| [`fact_tags`](_autosummary/acquaint.records.html.md#acquaint.records.fact_tags)(text)                                  | The label and seals one fact carries, and what is wrong with how they are written.                                           |
| [`format_log_entry`](_autosummary/acquaint.records.html.md#acquaint.records.format_log_entry)(entry_id, date, kind, text, \*) | One log entry: a `## id · date · kind` heading, the observation on one line, then `- key: value` fields.                     |
| [`item_blocks`](_autosummary/acquaint.records.html.md#acquaint.records.item_blocks)(text)                                | `(section, first_line, last_line, item)` for every item of a Markdown document.                                              |
| [`items`](_autosummary/acquaint.records.html.md#acquaint.records.items)(text)                                      | `(line, item)` for every item: each bullet with its wrapped lines, or a paragraph.                                           |
| [`join_frontmatter`](_autosummary/acquaint.records.html.md#acquaint.records.join_frontmatter)(meta, body)                     | The inverse of [`split_frontmatter()`](_autosummary/acquaint.records.html.md#acquaint.records.split_frontmatter).                                         |
| [`load_yaml`](_autosummary/acquaint.records.html.md#acquaint.records.load_yaml)(text)                                  | Parse YAML into JSON-ready data, returning `(data, errors)` instead of raising: these files are hand-edited.                 |
| [`next_log_id`](_autosummary/acquaint.records.html.md#acquaint.records.next_log_id)(text)                                | The next free entry id in a log, counting every `## eNN` heading however it is written.                                      |
| [`normalize_newlines`](_autosummary/acquaint.records.html.md#acquaint.records.normalize_newlines)(text)                         | `\r\n` and lone `\r` as `\n`, without a leading byte-order mark.                                                             |
| [`normalize_title`](_autosummary/acquaint.records.html.md#acquaint.records.normalize_title)(title)                           |                                                                                                                              |
| [`parse_log`](_autosummary/acquaint.records.html.md#acquaint.records.parse_log)(text)                                  | Entries of an append-only `log/YYYY-MM.md` file, oldest first.                                                               |
| [`sectioned_items`](_autosummary/acquaint.records.html.md#acquaint.records.sectioned_items)(text)                            | `(section, line, item)` for every item: see [`item_blocks()`](_autosummary/acquaint.records.html.md#acquaint.records.item_blocks).                  |
| [`sections`](_autosummary/acquaint.records.html.md#acquaint.records.sections)(body)                                   | `## Title` blocks of a Markdown body, in order, as `{normalized title: text}`.                                               |
| [`slugify`](_autosummary/acquaint.records.html.md#acquaint.records.slugify)(name, \*[, qualifier])                   | A readable, ASCII-folded, lowercase id: `given-family`, plus `--qualifier` on a collision.                                   |
| [`source_kind`](_autosummary/acquaint.records.html.md#acquaint.records.source_kind)(ref)                                 | Classify one source reference.                                                                                               |
| [`source_problem`](_autosummary/acquaint.records.html.md#acquaint.records.source_problem)(text)                             | Why a preference-bearing item is not sourced, or `None` when it is.                                                          |
| [`source_refs`](_autosummary/acquaint.records.html.md#acquaint.records.source_refs)(line)                                | Every `[source: …]` reference in a piece of text, stripped.                                                                  |
| [`split_frontmatter`](_autosummary/acquaint.records.html.md#acquaint.records.split_frontmatter)(text)                          | Split `---` YAML frontmatter from a Markdown body: `(meta, body, errors)`.                                                   |
| [`tags`](_autosummary/acquaint.records.html.md#acquaint.records.tags)(text)                                       | Every `[source: …]`, `[label: …]` and `[sealed-from: …]` tag in a piece of text: `(name, value)`, in order.                  |

### acquaint.records.NONE_LOCATED *= ('none located', 'no primary source located', 'no source located')*

The words that say “no primary source was found”, out loud.

### acquaint.records.blank_frontmatter(text)

The text with its frontmatter lines emptied, so line numbers still match the file.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> blank_frontmatter("---\nname: Ada\n---\nbody\n")
'\n\n\nbody\n'
```

### acquaint.records.disclosed_refs(value)

The record references a log entry’s `disclosed:` field lists, lowercased: `project:heron, org:example` or `[project:heron]`.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

```pycon
>>> disclosed_refs("[project:heron, Org:Example-Client]"), disclosed_refs(""), disclosed_refs(["project:heron"])
(['project:heron', 'org:example-client'], [], ['project:heron'])
```

### acquaint.records.dump_yaml(data)

Write YAML the way a person would: keys in order, short lists inline, unicode kept.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> print(dump_yaml({"name": "Ada", "aka": ["Ada", "Lovelace"], "links": [{"to": "org:x"}]}), end="")
name: Ada
aka: [Ada, Lovelace]
links:
- to: org:x
```

### acquaint.records.fact_tags(text)

The label and seals one fact carries, and what is wrong with how they are written.

`{"label": str | None, "sealed_from": [ids], "problems": [messages]}`. The label is
returned lowercased and unchecked: which labels exist is [`acquaint.trust`](_autosummary/acquaint.trust.html.md#module-acquaint.trust)’s
business. A tag that starts like `[label` or `[sealed from` but is not written
`[label: <label>]` or `[sealed-from: <id>, <id>]` is a problem, never ignored.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

```pycon
>>> fact_tags("- Cy is changing jobs. [label: red] [sealed-from: bram, person:dee] [source: operator]")
{'label': 'red', 'sealed_from': ['bram', 'person:dee'], 'problems': []}
>>> for problem in fact_tags("- Heron slips. [label amber] [sealed_from: bram] [source: operator]")["problems"]:
...     print(problem)
'[label amber]' is not a tag acquaint reads; write [label: <label>]
'[sealed_from: bram]' is not a tag acquaint reads; write [sealed-from: <id>, <id>]
```

### acquaint.records.format_log_entry(entry_id, date, kind, text, , source=None, \*\*fields)

One log entry: a `## id · date · kind` heading, the observation on one line, then `- key: value` fields.

An observation that would read as a field, a heading or a list item is escaped with a
leading backslash, so captured text can never forge an entry or change its kind.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### acquaint.records.item_blocks(text)

`(section, first_line, last_line, item)` for every item of a Markdown document.

An item is one bullet (`-`, `*`, `+`, `1.`) at any depth, together with the
wrapped lines under it, or a paragraph. A nested bullet is an item of its own, so it
needs its own source. Blank lines, headings, thematic breaks, HTML comments and fenced
code are not items. `section` is the enclosing `##` title (normalized), `None`
before the first one or after a `#` heading. Blank the frontmatter first
([`blank_frontmatter()`](_autosummary/acquaint.records.html.md#acquaint.records.blank_frontmatter)) if the text has one.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None), [`int`](https://docs.python.org/3/builtins/functions.html#int), [`int`](https://docs.python.org/3/builtins/functions.html#int), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]

### acquaint.records.items(text)

`(line, item)` for every item: each bullet with its wrapped lines, or a paragraph.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`int`](https://docs.python.org/3/builtins/functions.html#int), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]

```pycon
>>> doc = "- one\n  continued\n  - nested\n\nA paragraph\nwrapped.\n```\n- code, not an item\n```\n+ two\n3. three\n"
>>> items(doc)
[(1, 'one continued'), (3, 'nested'), (5, 'A paragraph wrapped.'), (10, 'two'), (11, 'three')]
```

### acquaint.records.join_frontmatter(meta, body)

The inverse of [`split_frontmatter()`](_autosummary/acquaint.records.html.md#acquaint.records.split_frontmatter).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> join_frontmatter({"name": "Ada"}, "## Who\n")
'---\nname: Ada\n---\n\n## Who\n'
```

### acquaint.records.load_yaml(text)

Parse YAML into JSON-ready data, returning `(data, errors)` instead of raising: these files are hand-edited.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`Any`](https://docs.python.org/3/library/typing.html#typing.Any), [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]

```pycon
>>> load_yaml("a: [1, 2]\nb: !!set {x: null}")
({'a': [1, 2], 'b': ['x']}, [])
>>> data, errors = load_yaml("a: [1, 2")
>>> data, bool(errors)
(None, True)
```

### acquaint.records.next_log_id(text)

The next free entry id in a log, counting every `## eNN` heading however it is written.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> next_log_id("## e01 · 2026-09-01 · observation\nx\n## e07 - 2026-09-02 - note\ny\n")
'e08'
>>> next_log_id("")
'e01'
```

### acquaint.records.normalize_newlines(text)

`\r\n` and lone `\r` as `\n`, without a leading byte-order mark.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> normalize_newlines("\ufeffa\r\nb\rc")
'a\nb\nc'
```

### acquaint.records.normalize_title(title)

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

A heading as written, minus decoration: closing 

```
``
```

#\`\`s, a trailing colon, typographic apostrophes, extra space.

```pycon
>>> normalize_title("  Don’t:  ## ")
"Don't"
```

### acquaint.records.parse_log(text)

Entries of an append-only `log/YYYY-MM.md` file, oldest first.

Headings may use `·`, `-` or `|` between their parts; an escaped prose line
(a leading backslash, see [`format_log_entry()`](_autosummary/acquaint.records.html.md#acquaint.records.format_log_entry)) is unescaped.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)]

```pycon
>>> entry = format_log_entry("e01", "2026-09-11", "observation", "- kind: rule, they said",
...                          source="https://example.org/thread/1")
>>> parse_log(entry)
[{'id': 'e01', 'date': '2026-09-11', 'kind': 'observation', 'text': '- kind: rule, they said', 'source': 'https://example.org/thread/1'}]
```

### acquaint.records.sectioned_items(text)

`(section, line, item)` for every item: see [`item_blocks()`](_autosummary/acquaint.records.html.md#acquaint.records.item_blocks).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None), [`int`](https://docs.python.org/3/builtins/functions.html#int), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]

```pycon
>>> sectioned_items(blank_frontmatter("---\nname: Ada\n---\n# Ada\n## Write to them:\n- Short. [source: operator]\n### Detail\n- More.\n"))
[('Write to them', 6, 'Short. [source: operator]'), ('Write to them', 8, 'More.')]
```

### acquaint.records.sections(body)

`## Title` blocks of a Markdown body, in order, as `{normalized title: text}`.

A `#` heading ends the current section; deeper headings stay inside it; headings
inside fenced code and HTML comments are not headings (and comments are left out).

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

```pycon
>>> sections("intro\n## Who\nAda\n### Detail\nmore\n# Aside\nnot in Who\n## Now:\n- busy\n")
{'Who': 'Ada\n### Detail\nmore\n', 'Now': '- busy\n'}
```

### acquaint.records.slugify(name, , qualifier=None)

A readable, ASCII-folded, lowercase id: `given-family`, plus `--qualifier` on a collision.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> slugify("Zoë Ångström")
'zoe-angstrom'
>>> slugify("John Smith", qualifier="Example Org")
'john-smith--example-org'
```

### acquaint.records.source_kind(ref)

Classify one source reference.

One of `url`, `file`, `self`, `operator`, `none-located`, `other`
(free text: accepted, not checkable), or a defect: `self-unquoted`,
`placeholder`, `date-only`, `empty`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> [source_kind(r) for r in ["https://example.org/x", "log/2026-09.md#e01", "self: 'don't email me'",
...     "self, it's what they're like", 'self: " "', "operator", "none located", "2026-09-01T10:00Z",
...     "last Tuesday", "todo: find link", "", "email to Ada on 2026-09-01"]]
['url', 'file', 'self', 'self-unquoted', 'self-unquoted', 'operator', 'none-located', 'date-only', 'date-only', 'placeholder', 'empty', 'other']
```

### acquaint.records.source_problem(text)

Why a preference-bearing item is not sourced, or `None` when it is.

A source is a permalink, a file anchor (`log/2026-09.md#e03`), the person’s own
words (`self: "…"`), the operator’s statement (`operator`), or an explicit
`none located`. A date alone is not a source, and neither is a placeholder.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

```pycon
>>> source_problem("- Prefers calls.")
'no [source: …] tag'
>>> source_problem('- Prefers calls. [source: self: "call me, never email"]') is None
True
>>> source_problem("- Prefers calls. [source: self, 2026-09-01]")
'self-stated sources need the quoted words: [source: self: "…"]'
>>> source_problem("- Prefers calls. [source: TODO]")
"'TODO' is a placeholder, not a source: write none located if you looked and found nothing; an inference goes under Hypotheses with its evidence"
```

### acquaint.records.source_refs(line)

Every `[source: …]` reference in a piece of text, stripped.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

```pycon
>>> source_refs("- Short replies. [source: log/2026-09.md#e03] [source: operator]")
['log/2026-09.md#e03', 'operator']
```

### acquaint.records.split_frontmatter(text)

Split `---` YAML frontmatter from a Markdown body: `(meta, body, errors)`.

A malformed header degrades to empty metadata plus an error, never an exception,
so one bad hand edit cannot take down lookups of every other record.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]

```pycon
>>> split_frontmatter("no frontmatter here")
({}, 'no frontmatter here', ['no --- frontmatter block at the top of the file'])
```

### acquaint.records.tags(text)

Every `[source: …]`, `[label: …]` and `[sealed-from: …]` tag in a piece of text: `(name, value)`, in order.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]]

```pycon
>>> tags("- Heron ships in October [label: amber] [Sealed-From: bram] [source: operator 2026-09-15]")
[('label', 'amber'), ('sealed-from', 'bram'), ('source', 'operator 2026-09-15')]
```


# _autosummary/acquaint.render.html.md

# acquaint.render

Turning a tool’s result into terminal output: `(stdout, stderr, exit code)`.

Used by the CLI only. The rules, in order: a one-field lookup prints just the value
(one line per item, so it pipes); otherwise the long `text` if there is one; otherwise
the `summary`. A result with `ok: False` exits 1 and puts its summary on stderr.
A result whose `outcome` is in `EXIT_CODES` exits with that code instead, so a
script can tell it apart from both success and failure (2 stays the usage error). An
outcome name means the same thing in every tool that uses it.

```pycon
>>> render({"ok": True, "value": ["Ada", "Lovelace"], "summary": "…"})
('Ada\nLovelace', '', 0)
>>> render({"ok": False, "summary": "no match for 'x'"})
('', "no match for 'x'", 1)
>>> render({"ok": False, "outcome": "no_address", "text": "1. pager  [self]", "summary": "no pager address"})
('1. pager  [self]', 'no pager address', 3)
```

### Functions

| [`exit_code`](_autosummary/acquaint.render.html.md#acquaint.render.exit_code)(result)   | The exit code for one tool result: its `outcome`'s code if it has one, else 0 if `ok`, else 1.   |
|----------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| [`render`](_autosummary/acquaint.render.html.md#acquaint.render.render)(result)      | `(stdout, stderr, exit_code)` for one tool result.                                               |

### acquaint.render.exit_code(result)

The exit code for one tool result: its `outcome`’s code if it has one, else 0 if `ok`, else 1.

* **Return type:**
  [`int`](https://docs.python.org/3/builtins/functions.html#int)

### acquaint.render.render(result)

`(stdout, stderr, exit_code)` for one tool result.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`int`](https://docs.python.org/3/builtins/functions.html#int)]


# _autosummary/acquaint.resources.html.md

# acquaint.resources

Files shipped inside the package: record templates, the policy tripwires, purpose reminders, the tells catalogue, skills.

Read through `importlib.resources` so they work from a wheel, a zip or a checkout.
Shipped data is part of the code: if it does not parse, that is a bug, and it raises.

### Functions

| [`data_path`](_autosummary/acquaint.resources.html.md#acquaint.resources.data_path)(\*parts)   | A path inside `acquaint/data/`.                                           |
|-----------------------------------------------------------------------|---------------------------------------------------------------------------|
| [`data_text`](_autosummary/acquaint.resources.html.md#acquaint.resources.data_text)(name)      | The text of a shipped data file, e.g. `data_text("templates/POLICY.md")`. |
| [`data_yaml`](_autosummary/acquaint.resources.html.md#acquaint.resources.data_yaml)(name)      | A shipped YAML file, parsed.                                              |

### acquaint.resources.data_path(\*parts)

A path inside `acquaint/data/`.

* **Return type:**
  [`Traversable`](https://docs.python.org/3/library/importlib.resources.abc.html#importlib.resources.abc.Traversable)

### acquaint.resources.data_text(name)

The text of a shipped data file, e.g. `data_text("templates/POLICY.md")`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### acquaint.resources.data_yaml(name)

A shipped YAML file, parsed. Raises `ValueError` if it does not parse.

* **Return type:**
  [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)


# _autosummary/acquaint.store.html.md

# acquaint.store

Where records live and how code reaches them: the data root, [`Store`](_autosummary/acquaint.store.html.md#acquaint.store.Store) and [`Entity`](_autosummary/acquaint.store.html.md#acquaint.store.Entity).

Layout under the data root (one folder per entity, one entry file each):

```default
POLICY.md                    what may be recorded
_tombstones.yaml             salted hashes of forgotten entities' identifiers
people/<slug>/PROFILE.md     the entry file (required)
people/<slug>/identities.yaml, rules.yaml, links.yaml, trust.yaml, style.md, views.md,
              sources.md, log/YYYY-MM.md, research/…   (each optional)
projects/<slug>/PROFILE.md   (and orgs/, groups/, or any other kind)
```

[`Store`](_autosummary/acquaint.store.html.md#acquaint.store.Store) is a `MutableMapping[str, Entity]` keyed `"<kind dir>/<slug>"`, where
both parts are lowercase letters, digits and hyphens; nothing else is a key, so no
reference can reach outside the data root. Underneath it is any
`MutableMapping[str, str]` of relative paths to text: a `dol` files store by
default, a `dict` in tests. That mapping is the storage seam.

When the store is on disk, an entity is a real directory whose name matches its key
exactly (case included, even on case-insensitive filesystems) and is not a link.
Listing, moving and removing work on those directories, so hidden files move and go
with their entity. A file that is not valid UTF-8 reads with replacement characters and
is reported, instead of failing every lookup. Entry files the store cannot address (a
capitalised folder, a linked folder, `profile.md`) are listed by [`Store.misnamed()`](_autosummary/acquaint.store.html.md#acquaint.store.Store.misnamed).

```pycon
>>> store = Store(files={})
>>> store["people/ada-lovelace"] = {"PROFILE.md": "---\nname: Ada Lovelace\n---\n"}
>>> list(store), store["people/ada-lovelace"].name
(['people/ada-lovelace'], 'Ada Lovelace')
```

### Module Attributes

| [`KIND_DIRS`](_autosummary/acquaint.store.html.md#acquaint.store.KIND_DIRS)   | see [`kind_dir()`](_autosummary/acquaint.store.html.md#acquaint.store.kind_dir).   |
|--------------------------------------------------------------|--------------------------------------------------------------------|
| [`UNREADABLE`](_autosummary/acquaint.store.html.md#acquaint.store.UNREADABLE)  | What undecodable bytes read as.                                    |

### Functions

| [`config_path`](_autosummary/acquaint.store.html.md#acquaint.store.config_path)()        | `~/.config/acquaint/config.toml` (honouring `XDG_CONFIG_HOME`; `%APPDATA%` on Windows).                                 |
|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|
| [`data_dir`](_autosummary/acquaint.store.html.md#acquaint.store.data_dir)([data_dir]) | The data root: the argument, else `$ACQUAINT_DATA_DIR`, else `data_dir` in config.toml, else `~/.local/share/acquaint`. |
| [`kind_dir`](_autosummary/acquaint.store.html.md#acquaint.store.kind_dir)(kind)       | The folder for a kind: `person`/`people` -> `people`; an unknown kind is used as given, pluralised.                     |
| [`text_files`](_autosummary/acquaint.store.html.md#acquaint.store.text_files)(root)     | A `dol` files store under `root`, for text.                                                                             |
| [`validate_key`](_autosummary/acquaint.store.html.md#acquaint.store.validate_key)(key)    | Return `key` if it is `<kind dir>/<slug>` of lowercase letters, digits and hyphens; refuse anything else.               |

### Classes

| [`Entity`](_autosummary/acquaint.store.html.md#acquaint.store.Entity)(store, key)       | One person, project, org or group: a mapping of its files (relative names to text), plus parsed views of them.   |
|---------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
| [`Store`](_autosummary/acquaint.store.html.md#acquaint.store.Store)([data_dir, files]) | `MutableMapping[str, Entity]` over one folder per entity, keyed `"<kind dir>/<slug>"`.                           |

### Exceptions

| [`AcquaintError`](_autosummary/acquaint.store.html.md#acquaint.store.AcquaintError)   | An expected failure with a message meant for the person or agent that asked.   |
|------------------------------------------------------------------|--------------------------------------------------------------------------------|

### *exception* acquaint.store.AcquaintError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

An expected failure with a message meant for the person or agent that asked.

### *class* acquaint.store.Entity(store, key)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)

One person, project, org or group: a mapping of its files (relative names to text), plus parsed views of them.

Parsed views are recomputed on access (these are small text files), so an edit made
through the mapping is never hidden behind a stale cache. Parse problems are collected
in [`errors`](_autosummary/acquaint.store.html.md#acquaint.store.Entity.errors); they never raise.

#### *property* aka *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

Other names this entity goes by, as strings (a scalar `aka` is one alias, not its letters).

#### *property* body *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

The entry file’s Markdown body.

#### *property* errors *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

Everything about the entry file and the YAML files that did not parse.

#### *property* identities *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{platform, value, source, status, …}`.

* **Type:**
  Handles and addresses from `identities.yaml`

#### *property* kind *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

`person`, `project`, `org`, `group`, or the singular of an open kind’s folder.

#### *property* links *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{to, relation, role, since, until, source}`.

* **Type:**
  Affiliations from `links.yaml`

#### *property* meta *: [dict](https://docs.python.org/3/builtins/stdtypes.html#dict)*

The entry file’s frontmatter (empty when it did not parse).

#### *property* name *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

The display name, falling back to the id.

#### *property* ref *: [str](https://docs.python.org/3/builtins/stdtypes.html#str)*

`person:ada-lovelace`.

* **Type:**
  The link form other records use

#### *property* rules *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{when, do, set_by, source}`.

* **Type:**
  Channel and communication rules from `rules.yaml`

#### *property* sections *: [dict](https://docs.python.org/3/builtins/stdtypes.html#dict)[[str](https://docs.python.org/3/builtins/stdtypes.html#str), [str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

The entry file’s `## Sections`, keyed by normalized title.

#### summary()

The identity block: frontmatter plus identities, JSON-ready.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

#### *property* surface_forms *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[str](https://docs.python.org/3/builtins/stdtypes.html#str)]*

id, name, aka, name parts, handles.

* **Type:**
  Every string a document might use for this entity

#### text(name, default='')

A file’s text, or `default` when the file does not exist.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### *property* trust *: [list](https://docs.python.org/3/builtins/stdtypes.html#list)[[dict](https://docs.python.org/3/builtins/stdtypes.html#dict)]*

`{tier, valid_from, valid_to, review_by, recorded, source, note}` (see [`acquaint.trust`](_autosummary/acquaint.trust.html.md#module-acquaint.trust)).

* **Type:**
  Disclosure tiers from `trust.yaml`

### acquaint.store.KIND_DIRS *= {'group': 'groups', 'org': 'orgs', 'person': 'people', 'project': 'projects'}*

see [`kind_dir()`](_autosummary/acquaint.store.html.md#acquaint.store.kind_dir).

* **Type:**
  The kinds that ship, singular -> folder. The vocabulary is open

### *class* acquaint.store.Store(data_dir=None, , files=None)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)

`MutableMapping[str, Entity]` over one folder per entity, keyed `"<kind dir>/<slug>"`.

```pycon
>>> store = Store(files={})
>>> store["projects/example"] = {"PROFILE.md": "---\nname: Example\n---\n"}
>>> store.find("project:example"), store.find("example")
('projects/example', 'projects/example')
```

#### all_files(key)

Every file under the entity’s folder, hidden ones included.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### append_text(key, name, text)

Append to one of an entity’s files (created if missing); a true append on disk, so concurrent writers do not erase each other.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### exists(key)

Whether anything is stored under the entity’s folder, with or without an entry file.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

#### find(ref)

The store key for `people/ada-lovelace`, `person:ada-lovelace` or a bare `ada-lovelace`.

A bare id that names entities of two kinds is an error: say which, e.g.
`project:atlas`. Anything that is not a valid key raises `KeyError`, so no
reference reaches outside the data root.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

#### find_id(slug)

Every key whose id is `slug`, in any kind (ids are lowercase, so the lookup is too).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### location_warning()

A warning when the data root is, or sits inside, a git repository that is not an acquaint store.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### misnamed()

Entry files on disk the store cannot address: a folder or file name not in lowercase `kind/id/PROFILE.md` form, or a linked folder.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

#### move(src, dst)

Move an entity’s whole folder to a new key (hidden files included).

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### path_of(key)

Where an entity lives, for a person to open: a real path when on disk, else the key.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### acquaint.store.UNREADABLE *= '�'*

What undecodable bytes read as. A file containing it is reported as not valid UTF-8.

### acquaint.store.config_path()

`~/.config/acquaint/config.toml` (honouring `XDG_CONFIG_HOME`; `%APPDATA%` on Windows).

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

### acquaint.store.data_dir(data_dir=None)

The data root: the argument, else `$ACQUAINT_DATA_DIR`, else `data_dir` in config.toml, else `~/.local/share/acquaint`.

An explicit argument may be relative (it is resolved now). The environment variable
and the config file must hold absolute paths: a relative one would put profiles
wherever the current directory happens to be.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

```pycon
>>> data_dir("profiles").is_absolute()
True
```

### acquaint.store.kind_dir(kind)

The folder for a kind: `person`/`people` -> `people`; an unknown kind is used as given, pluralised.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> [kind_dir(k) for k in ("person", "people", "org", "community", "teams")]
['people', 'people', 'orgs', 'communities', 'teams']
```

### acquaint.store.text_files(root)

A `dol` files store under `root`, for text.

UTF-8 values (undecodable bytes read as U+FFFD instead of raising; a byte-order mark
dropped), `\n` line endings, `/`-separated keys on every platform, folders made on
write and never on read, and permanent deletes (never to a trash folder, where
“forgotten” data would linger).

* **Return type:**
  [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### acquaint.store.validate_key(key)

Return `key` if it is `<kind dir>/<slug>` of lowercase letters, digits and hyphens; refuse anything else.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> validate_key("people/ada-lovelace")
'people/ada-lovelace'
>>> try:
...     validate_key("../outside/people/someone")
... except AcquaintError as error:
...     print(error)
not a store key: '../outside/people/someone' (expected <kind>/<id>, e.g. people/ada-lovelace)
```


# _autosummary/acquaint.sync.html.md

# acquaint.sync

Private-repository sync for the data root: create the repository private, refuse anything else, guard every push.

`init` creates the GitHub repository through `gh` as **private**, refuses to
continue unless `gh repo view --json visibility` reports `PRIVATE`, makes the data
root its checkout, and installs a `pre-push` hook. The hook, and `push` and `pull`
in Python, re-check that:

- the push goes through `origin`, which has exactly one URL, the one recorded at init;
- no `pushurl` differs from it, and no `url.*.pushInsteadOf` rewrites it;
- that URL is one of the forms that name the recorded repository on github.com
  ([`github_urls()`](_autosummary/acquaint.sync.html.md#acquaint.sync.github_urls), the same list the hook spells out);
- `gh` reports the repository, on github.com whatever `GH_HOST` says, as private.

The hook is installed in the repository’s shared hooks folder, executable, and
`core.hooksPath` points at it by absolute path, so linked worktrees are guarded too and
a global `core.hooksPath` cannot silently disable it. `init` takes over only an empty
folder, or a clone of that same repository; it refuses any other existing repository.

What this does **not** protect, stated plainly:

- a private repository is access control, not encryption: the host can read it all;
- `git push --no-verify` skips the hook;
- whoever can change this repository’s git config, or which `gh` runs on `PATH`,
  controls what the guard sees;
- moving the data root breaks the absolute hook path until `sync init
  --existing-only` runs again (`sync push` refuses in that state; a raw `git push`
  does not);
- file names and commit messages carry people’s names;
- deleting a folder does not remove it from history, other clones, or backups.

`git-remote-gcrypt`, which would encrypt contents, names and history, is not supported
yet: the guard does not recognise its internal push, so `init` refuses `gcrypt::` URLs.

Every `git` and `gh` call goes through `run`, so tests can script `gh` while
`git` runs for real.

### Functions

| [`github_urls`](_autosummary/acquaint.sync.html.md#acquaint.sync.github_urls)(repo)                               | Every remote URL accepted for a GitHub repository.                                                                                                                        |
|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`init`](_autosummary/acquaint.sync.html.md#acquaint.sync.init)(root, repo, \*[, remote_url, create, ...]) | Make `root` a checkout of the private GitHub repository `repo`, creating it (private) if needed.                                                                          |
| [`pull`](_autosummary/acquaint.sync.html.md#acquaint.sync.pull)(root, \*[, dry_run, run])                  | Re-check the remote and its visibility, then rebase local work onto it (uncommitted edits are stashed and restored).                                                      |
| [`push`](_autosummary/acquaint.sync.html.md#acquaint.sync.push)(root, \*[, message, dry_run, run])         | Commit everything, rebase onto the remote, and push, after re-checking the remote, the guard and the visibility.                                                          |
| [`run_command`](_autosummary/acquaint.sync.html.md#acquaint.sync.run_command)(args, \*[, cwd])                    | Run `git` or `gh` (`gh` pinned to github.com), capturing text output.                                                                                                     |
| [`sole_access`](_autosummary/acquaint.sync.html.md#acquaint.sync.sole_access)(repo, \*[, run])                    | Whether only the repository's owner can read it, and why not: private, owned by a person (not an organisation), that person its only collaborator, no invitation pending. |
| [`status`](_autosummary/acquaint.sync.html.md#acquaint.sync.status)(root, \*[, check_visibility, run])       | Whether the store is synced, where to, uncommitted changes, ahead/behind, the guard, and live visibility.                                                                 |
| [`visibility`](_autosummary/acquaint.sync.html.md#acquaint.sync.visibility)(repo, \*[, run])                     | `PRIVATE`, `PUBLIC` or `INTERNAL`, as `gh` reports it now for the repository on github.com.                                                                               |

### acquaint.sync.github_urls(repo)

Every remote URL accepted for a GitHub repository. The pre-push hook spells out the same six forms.

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

```pycon
>>> github_urls("example/profiles")
['git@github.com:example/profiles.git', 'git@github.com:example/profiles', 'ssh://git@github.com/example/profiles.git', 'ssh://git@github.com/example/profiles', 'https://github.com/example/profiles.git', 'https://github.com/example/profiles']
```

### acquaint.sync.init(root, repo, \*, remote_url=None, create=True, dry_run=False, run=<function run_command>)

Make `root` a checkout of the private GitHub repository `repo`, creating it (private) if needed.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.sync.pull(root, \*, dry_run=False, run=<function run_command>)

Re-check the remote and its visibility, then rebase local work onto it (uncommitted edits are stashed and restored).

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.sync.push(root, \*, message=None, dry_run=False, run=<function run_command>)

Commit everything, rebase onto the remote, and push, after re-checking the remote, the guard and the visibility.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.sync.run_command(args, , cwd=None)

Run `git` or `gh` (`gh` pinned to github.com), capturing text output.

* **Return type:**
  [`CompletedProcess`](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)

### acquaint.sync.sole_access(repo, \*, run=<function run_command>)

Whether only the repository’s owner can read it, and why not: private, owned by a person (not an organisation), that person its only collaborator, no invitation pending.

This decides whether profile edits may be committed and pushed without the operator
reviewing the diff first: nobody else will see them.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`bool`](https://docs.python.org/3/builtins/functions.html#bool), [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### acquaint.sync.status(root, \*, check_visibility=True, run=<function run_command>)

Whether the store is synced, where to, uncommitted changes, ahead/behind, the guard, and live visibility.

With `check_visibility`, `auto_commit` says whether edits may be committed and pushed
without the operator reviewing them first ([`sole_access()`](_autosummary/acquaint.sync.html.md#acquaint.sync.sole_access)), and
`auto_commit_reason` says why or why not.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Any`](https://docs.python.org/3/library/typing.html#typing.Any)]

### acquaint.sync.visibility(repo, \*, run=<function run_command>)

`PRIVATE`, `PUBLIC` or `INTERNAL`, as `gh` reports it now for the repository on github.com.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)


# _autosummary/acquaint.tools.html.md

# acquaint.tools

The single source of truth for every surface: plain functions, flat arguments in, JSON-ready dicts out.

The CLI is `cw` over [`TOOLS`](_autosummary/acquaint.tools.html.md#acquaint.tools.TOOLS); the MCP server exposes the same functions (by
`acquaint.tools:<name>` reference); the shipped skills describe these verbs. Nothing
in this module knows about any of those surfaces.

Every tool takes `data_dir` (default: `$ACQUAINT_DATA_DIR`, else `data_dir` in
`~/.config/acquaint/config.toml`, else `~/.local/share/acquaint`). Every result carries
`ok` and a one-line `summary`; long human-readable content is in `text`.

Tools never act on a guess. A name, alias, handle or email counts only when exactly one
entity has it exactly; a partial match is returned as a suggestion. `rename` and
`forget` need the exact id. Library callers with their own store use the core
functions ([`acquaint.lookup.find_entity()`](_autosummary/acquaint.lookup.html.md#acquaint.lookup.find_entity), `acquaint.brief.compose_brief()`, …)
with a [`Store`](_autosummary/acquaint.store.html.md#acquaint.store.Store).

### Module Attributes

| [`TOOLS`](_autosummary/acquaint.tools.html.md#acquaint.tools.TOOLS)        | Every tool, in the order surfaces list them.                                     |
|---------------------------------------------------------------|----------------------------------------------------------------------------------|
| [`SIDE_EFFECTS`](_autosummary/acquaint.tools.html.md#acquaint.tools.SIDE_EFFECTS) | What each tool changes, for surfaces that must decide what to expose or confirm. |

### Functions

| [`brief`](_autosummary/acquaint.tools.html.md#acquaint.tools.brief)(person, \*[, purpose, project, ref, ...])    | Everything to know before writing to someone: card, writing style, reach, project norms, recent observations, gaps.                                                                                                                                                                                                                      |
|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`check`](_autosummary/acquaint.tools.html.md#acquaint.tools.check)(text, \*[, data_dir])                        | Scan prose that names people before publishing it: conflations (one person written as two), ambiguous names, unknown names.                                                                                                                                                                                                              |
| [`disclosure`](_autosummary/acquaint.tools.html.md#acquaint.tools.disclosure)(people, \*[, projects, audience, ...])  | Who may be told what, before writing to a set of readers (ids or channel identities, plus an optional correspond `audience` record as JSON): the tier and clearance in force for each, the least clearance, which records each is cleared for, the seals, the vocabulary a gate must scan for, what each was already told, and the gaps. |
| [`forget`](_autosummary/acquaint.tools.html.md#acquaint.tools.forget)(entity, \*[, confirm, data_dir])            | Remove an entity's folder and leave a salted tombstone.                                                                                                                                                                                                                                                                                  |
| [`lint`](_autosummary/acquaint.tools.html.md#acquaint.tools.lint)([entity, data_dir])                           | Check records: every preference, view and rule sourced; tiers, labels and seals set by the operator; nothing POLICY.md forbids; files parse; entry files within budget.                                                                                                                                                                  |
| [`new`](_autosummary/acquaint.tools.html.md#acquaint.tools.new)(kind, name, \*[, qualifier, description, ...]) | Create a person, project, org or group from its template (a readable slug id; `qualifier` separates two of the same name).                                                                                                                                                                                                               |
| [`reach`](_autosummary/acquaint.tools.html.md#acquaint.tools.reach)(person, \*[, purpose, urgency, ...])         | Ordered channels for reaching someone in a context.                                                                                                                                                                                                                                                                                      |
| [`remember`](_autosummary/acquaint.tools.html.md#acquaint.tools.remember)(entity, text, \*[, source, kind, ...])    | Append a dated observation (`observation`, `interaction`, `identity`, `preference`, `view`, `rule`) to an entity's log, with its source.                                                                                                                                                                                                 |
| [`rename`](_autosummary/acquaint.tools.html.md#acquaint.tools.rename)(entity, to, \*[, data_dir])                 | Change an entity's id (`to` is a slug) or name and id (`to` is a name), rewriting links to it.                                                                                                                                                                                                                                           |
| [`resolve`](_autosummary/acquaint.tools.html.md#acquaint.tools.resolve)(handle, \*[, data_dir])                    | Map a channel handle (`github:octocat`, `email:ada@example.org`) to the entity it belongs to, with the evidence.                                                                                                                                                                                                                         |
| [`review`](_autosummary/acquaint.tools.html.md#acquaint.tools.review)(person, \*[, today, data_dir])              | Everything the store says about one person's disclosure standing, with sources and dates, to confirm when a collaboration ends, when someone changes role, or before a tier changes: tier entries, links, the default tiers and clearances reached through links, seals on records and on fact lines, and the rules that name them.      |
| [`style_lint`](_autosummary/acquaint.tools.html.md#acquaint.tools.style_lint)(text, \*[, recipient, tolerance, ...])  | The deterministic half of deslop: machine-writing tells in a draft, at the recipient's tolerance and against their blocklist.                                                                                                                                                                                                            |
| [`sync_init`](_autosummary/acquaint.tools.html.md#acquaint.tools.sync_init)(\*, repo[, remote_url, ...])             | Make the data root a checkout of a PRIVATE GitHub repository (created private through `gh` unless `existing_only`), with a pre-push guard.                                                                                                                                                                                               |
| [`sync_pull`](_autosummary/acquaint.tools.html.md#acquaint.tools.sync_pull)(\*[, dry_run, data_dir])                 | Pull the store from its private remote, rebasing local work on top.                                                                                                                                                                                                                                                                      |
| [`sync_push`](_autosummary/acquaint.tools.html.md#acquaint.tools.sync_push)(\*[, message, dry_run, data_dir])        | Commit, rebase onto the remote and push the store, after re-checking the remote, the guard and the visibility.                                                                                                                                                                                                                           |
| [`sync_status`](_autosummary/acquaint.tools.html.md#acquaint.tools.sync_status)(\*[, check_visibility, data_dir])      | Whether the store is synced, to which repository, uncommitted changes, ahead/behind, the guard, and live visibility.                                                                                                                                                                                                                     |
| [`todo_preflight`](_autosummary/acquaint.tools.html.md#acquaint.tools.todo_preflight)(project, people, \*[, data_dir])    | Before filing a meeting's todos as GitHub issues: is the project unambiguous, is every participant (comma-separated) registered and linked to it, and does it declare a meta repository that is private now? Returns the repository, each person's GitHub login, and a fix for every problem.                                            |
| [`who`](_autosummary/acquaint.tools.html.md#acquaint.tools.who)(name, \*[, field, brief, data_dir])            | Look up one person, project, org or group by exact id, name, alias, handle or email.                                                                                                                                                                                                                                                     |

### Exceptions

| [`AcquaintError`](_autosummary/acquaint.tools.html.md#acquaint.tools.AcquaintError)   | An expected failure with a message meant for the person or agent that asked.   |
|------------------------------------------------------------------|--------------------------------------------------------------------------------|

### *exception* acquaint.tools.AcquaintError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

An expected failure with a message meant for the person or agent that asked.

### acquaint.tools.SIDE_EFFECTS *= {'brief': 'read', 'check': 'read', 'disclosure': 'read', 'forget': 'destructive', 'lint': 'read', 'new': 'create', 'reach': 'read', 'remember': 'append', 'rename': 'rewrite', 'resolve': 'read', 'review': 'read', 'style_lint': 'read', 'sync_init': 'external', 'sync_pull': 'rewrite', 'sync_push': 'external', 'sync_status': 'external-read', 'todo_preflight': 'external-read', 'who': 'read'}*

What each tool changes, for surfaces that must decide what to expose or confirm.
`read` changes nothing and stays local; `append` adds to a log; `create` adds a
record; `rewrite` changes existing records; `destructive` removes data;
`external-read` queries a remote service; `external` acts on one.

### acquaint.tools.TOOLS *= [<function who>, <function resolve>, <function check>, <function reach>, <function brief>, <function remember>, <function lint>, <function new>, <function rename>, <function forget>, <function sync_init>, <function sync_push>, <function sync_pull>, <function sync_status>, <function style_lint>, <function disclosure>, <function review>, <function todo_preflight>]*

Every tool, in the order surfaces list them.

### acquaint.tools.brief(person, , purpose=None, project=None, ref=None, audience=None, data_dir=None)

Everything to know before writing to someone: card, writing style, reach, project norms, recent observations, gaps. With `ref` (the conversation the message goes to; correspond is asked who can read it, and an unknown audience is public) or `audience` (an audience record as JSON), it opens with the ceiling, the records not to identify, how many lines were withheld, and what they were already told.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.check(text, , data_dir=None)

Scan prose that names people before publishing it: conflations (one person written as two), ambiguous names, unknown names.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.disclosure(people, , projects=None, audience=None, today=None, data_dir=None)

Who may be told what, before writing to a set of readers (ids or channel identities, plus an optional correspond `audience` record as JSON): the tier and clearance in force for each, the least clearance, which records each is cleared for, the seals, the vocabulary a gate must scan for, what each was already told, and the gaps. `projects` limits the records to those plus people. Reads only.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.forget(entity, , confirm=False, data_dir=None)

Remove an entity’s folder and leave a salted tombstone. Needs the exact id; without `confirm`, only reports what would be removed.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.lint(entity=None, , data_dir=None)

Check records: every preference, view and rule sourced; tiers, labels and seals set by the operator; nothing POLICY.md forbids; files parse; entry files within budget.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.new(kind, name, , qualifier=None, description=None, force=False, data_dir=None)

Create a person, project, org or group from its template (a readable slug id; `qualifier` separates two of the same name).

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.reach(person, , purpose=None, urgency=None, project=None, message_type=None, topic=None, data_dir=None)

Ordered channels for reaching someone in a context. Only active addresses; returns them, sends nothing. `outcome` is `reachable`, `no_address` (a rule matched, but neither states an address nor finds a usable one recorded for its channels) or `no_channel`. Each channel’s `address_kind` is `stated`, `identity` (the person’s handle, which a conversation-addressed channel does not take) or `None`.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.remember(entity, text, , source=None, kind='observation', disclosed=None, reactivate=False, data_dir=None)

Append a dated observation (`observation`, `interaction`, `identity`, `preference`, `view`, `rule`) to an entity’s log, with its source. An `interaction` may list the records the message identified (`disclosed`: exact ids, never the text). An identity equal to an inactive one (`stale`, `retracted`, …) is refused, naming that entry and the command with which the operator can make it active again.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.rename(entity, to, , data_dir=None)

Change an entity’s id (`to` is a slug) or name and id (`to` is a name), rewriting links to it. Needs the exact id.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.resolve(handle, , data_dir=None)

Map a channel handle (`github:octocat`, `email:ada@example.org`) to the entity it belongs to, with the evidence.

`ok` is true only when an active identity on the named platform belongs to exactly
one entity. A handle without a platform (`@octocat`), a match by name only, an
inactive identity, or several owners all return `ok: false` with what was found.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.review(person, , today=None, data_dir=None)

Everything the store says about one person’s disclosure standing, with sources and dates, to confirm when a collaboration ends, when someone changes role, or before a tier changes: tier entries, links, the default tiers and clearances reached through links, seals on records and on fact lines, and the rules that name them. Not ok when an affiliation has ended while a permissive tier is still in force. Reads only.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.style_lint(text, , recipient=None, tolerance=None, data_dir=None)

The deterministic half of deslop: machine-writing tells in a draft, at the recipient’s tolerance and against their blocklist.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.sync_init(, repo, remote_url=None, existing_only=False, dry_run=False, data_dir=None)

Make the data root a checkout of a PRIVATE GitHub repository (created private through `gh` unless `existing_only`), with a pre-push guard.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.sync_pull(, dry_run=False, data_dir=None)

Pull the store from its private remote, rebasing local work on top.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.sync_push(, message=None, dry_run=False, data_dir=None)

Commit, rebase onto the remote and push the store, after re-checking the remote, the guard and the visibility.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.sync_status(, check_visibility=True, data_dir=None)

Whether the store is synced, to which repository, uncommitted changes, ahead/behind, the guard, and live visibility.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.todo_preflight(project, people, , data_dir=None)

Before filing a meeting’s todos as GitHub issues: is the project unambiguous, is every participant (comma-separated) registered and linked to it, and does it declare a meta repository that is private now? Returns the repository, each person’s GitHub login, and a fix for every problem.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

### acquaint.tools.who(name, , field=None, brief=False, data_dir=None)

Look up one person, project, org or group by exact id, name, alias, handle or email.

Costs scale with what you ask: `field` returns one value (`aka`, `email`,
`github`, `label`, `tier`, any frontmatter key), `brief` the identity block, and the default the
whole entry file. It never guesses: no exact match, or several, returns the
candidates and `ok: false`.

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)


# _autosummary/acquaint.trust.html.md

# acquaint.trust

The disclosure vocabulary: tiers on people; labels, seals and clearances on records; and which tier is in force.

What a reader may be told is decided by the operator and evaluated by code, so its words
are fixed here and nowhere else. Where they are written:

- `trust.yaml` beside a person’s entry file:
  `{tiers: [{tier, valid_from, valid_to, review_by, recorded, source, note}]}`;
- any record’s frontmatter: `label`, `sealed_from`, `vocabulary`, `clearance` (orgs
  and groups), `default_tier` (orgs and projects), and `label_source`;
- one fact line: `[label: …]` and `[sealed-from: …]` beside its `[source: …]`.

A tier records a disclosure consequence, never a judgement of the person. Only the
operator grants one. Nothing here reads a store: these are pure functions over parsed
records, and [`acquaint.lint`](_autosummary/acquaint.html.md#acquaint.lint) says what is wrong with them.

```pycon
>>> tiers = [
...     {"tier": "reviewed", "valid_from": "2026-01-01", "valid_to": "2026-09-01", "source": "operator"},
...     {"tier": "open", "valid_from": "2026-09-01", "review_by": "2026-11-01", "source": "operator"},
... ]
>>> tier_in_force(tiers, today="2026-09-15")["tier"], effective_tier(tiers, today="2026-09-15")
('open', ('open', False))
>>> effective_tier(tiers, today="2026-11-02")
('need-to-know', True)
>>> entity_label({}, "project"), entity_label({}, "person"), entity_label({"label": "red"}, "person")
('amber', 'green', 'red')
```

### Module Attributes

| [`TIERS`](_autosummary/acquaint.trust.html.md#acquaint.trust.TIERS)               | One ordinal scale, most permissive first.                                                                                    |
|----------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| [`PERMISSIVE_TIERS`](_autosummary/acquaint.trust.html.md#acquaint.trust.PERMISSIVE_TIERS)    | The tiers that need a `review_by` and lapse to [`DEFAULT_TIER`](_autosummary/acquaint.trust.html.md#acquaint.trust.DEFAULT_TIER) once it passes. |
| [`DEFAULT_TIER`](_autosummary/acquaint.trust.html.md#acquaint.trust.DEFAULT_TIER)        | The tier of anyone without one in force.                                                                                     |
| [`LABELS`](_autosummary/acquaint.trust.html.md#acquaint.trust.LABELS)              | Traffic Light Protocol names, most restrictive first.                                                                        |
| [`TRUST_SOURCES`](_autosummary/acquaint.trust.html.md#acquaint.trust.TRUST_SOURCES)       | the operator, or the person's own quoted words.                                                                              |
| [`OPERATOR_SET_FIELDS`](_autosummary/acquaint.trust.html.md#acquaint.trust.OPERATOR_SET_FIELDS) | Frontmatter fields that need `label_source: operator`.                                                                       |

### Functions

| [`effective_tier`](_autosummary/acquaint.trust.html.md#acquaint.trust.effective_tier)(tiers, \*, today)            | `(tier, lapsed)` for today: the tier in force, [`DEFAULT_TIER`](_autosummary/acquaint.trust.html.md#acquaint.trust.DEFAULT_TIER) in place of a lapsed one.                                    |
|----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`ended_affiliations`](_autosummary/acquaint.trust.html.md#acquaint.trust.ended_affiliations)(tiers, links, \*, today) | Links that ended while a permissive tier recorded before their end is still in force: `{to, until, tier, tier_recorded}`.                                                 |
| [`entity_label`](_autosummary/acquaint.trust.html.md#acquaint.trust.entity_label)(meta, kind)                    | A record's label: its frontmatter `label`, else `green` for a person and `amber` for anything else.                                                                       |
| [`fact_label`](_autosummary/acquaint.trust.html.md#acquaint.trust.fact_label)(text, record_label)              | One fact's label: its own `[label: …]` tag, else the label of the record it sits in.                                                                                      |
| [`is_iso_date`](_autosummary/acquaint.trust.html.md#acquaint.trust.is_iso_date)(value)                          | Whether a value is a date written `YYYY-MM-DD`.                                                                                                                           |
| [`is_lapsed`](_autosummary/acquaint.trust.html.md#acquaint.trust.is_lapsed)(entry, \*, today)                 | Whether a permissive tier's review is overdue, or was never scheduled.                                                                                                    |
| [`link_state`](_autosummary/acquaint.trust.html.md#acquaint.trust.link_state)(link, \*, today)                 | Where a `links.yaml` link stands today: `current`, `ended` (`until` today or earlier), `future` (`since` after today), or `unreadable` (a date not written `YYYY-MM-DD`). |
| [`tier_in_force`](_autosummary/acquaint.trust.html.md#acquaint.trust.tier_in_force)(tiers, \*, today)             | The entry whose validity covers `today` (from `valid_from`, up to but not including `valid_to`).                                                                          |

### acquaint.trust.DEFAULT_TIER *= 'need-to-know'*

The tier of anyone without one in force.

### acquaint.trust.LABELS *= ('red', 'amber', 'green', 'clear')*

Traffic Light Protocol names, most restrictive first. Also the clearance values.

### acquaint.trust.OPERATOR_SET_FIELDS *= ('label', 'sealed_from', 'clearance', 'default_tier')*

Frontmatter fields that need `label_source: operator`.

### acquaint.trust.PERMISSIVE_TIERS *= ('open', 'involved')*

The tiers that need a `review_by` and lapse to [`DEFAULT_TIER`](_autosummary/acquaint.trust.html.md#acquaint.trust.DEFAULT_TIER) once it passes.

### acquaint.trust.TIERS *= ('open', 'involved', 'need-to-know', 'reviewed')*

One ordinal scale, most permissive first.

### acquaint.trust.TRUST_SOURCES *= ('operator', 'self')*

the operator, or the person’s own quoted words.

* **Type:**
  The only sources a tier may have

### acquaint.trust.effective_tier(tiers, , today)

`(tier, lapsed)` for today: the tier in force, [`DEFAULT_TIER`](_autosummary/acquaint.trust.html.md#acquaint.trust.DEFAULT_TIER) in place of a lapsed one.

`None` when no entry covers today (what applies then, a linked org’s
`default_tier` or the default, is the disclosure computation’s question). An
unknown tier value reads as `reviewed`.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None), [`bool`](https://docs.python.org/3/builtins/functions.html#bool)]

```pycon
>>> effective_tier([{"tier": "trusted"}], today="2026-09-15"), effective_tier([], today="2026-09-15")
(('reviewed', False), (None, False))
```

### acquaint.trust.ended_affiliations(tiers, links, , today)

Links that ended while a permissive tier recorded before their end is still in force: `{to, until, tier, tier_recorded}`.

A tier recorded (or starting) after the link ended was set with the end in view, so it
is not reported; a lapsed tier already counts as [`DEFAULT_TIER`](_autosummary/acquaint.trust.html.md#acquaint.trust.DEFAULT_TIER).

* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)]

```pycon
>>> tiers = [{"tier": "open", "valid_from": "2026-09-01", "recorded": "2026-09-01", "review_by": "2026-11-01"}]
>>> ended_affiliations(tiers, [{"to": "project:heron", "until": "2026-09-10"}], today="2026-09-15")
[{'to': 'project:heron', 'until': '2026-09-10', 'tier': 'open', 'tier_recorded': '2026-09-01'}]
```

### acquaint.trust.entity_label(meta, kind)

A record’s label: its frontmatter `label`, else `green` for a person and `amber` for anything else.

A label that is not one of [`LABELS`](_autosummary/acquaint.trust.html.md#acquaint.trust.LABELS) reads as `red`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### acquaint.trust.fact_label(text, record_label)

One fact’s label: its own `[label: …]` tag, else the label of the record it sits in.

A malformed or unknown tag reads as `red`.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> fact_label("- Heron ships in October. [label: amber] [source: operator]", "green")
'amber'
>>> fact_label("- Prefers email. [source: operator]", "green"), fact_label("- x [label: purple]", "green")
('green', 'red')
```

### acquaint.trust.is_iso_date(value)

Whether a value is a date written `YYYY-MM-DD`.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

```pycon
>>> is_iso_date("2026-09-15"), is_iso_date("2026-9-1"), is_iso_date(None)
(True, False, False)
```

### acquaint.trust.is_lapsed(entry, , today)

Whether a permissive tier’s review is overdue, or was never scheduled. Restrictive tiers never lapse.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

```pycon
>>> is_lapsed({"tier": "involved"}, today="2026-09-15"), is_lapsed({"tier": "reviewed"}, today="2026-09-15")
(True, False)
```

### acquaint.trust.link_state(link, , today)

Where a `links.yaml` link stands today: `current`, `ended` (`until` today or earlier), `future` (`since` after today), or `unreadable` (a date not written `YYYY-MM-DD`).

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> [link_state(l, today="2026-09-15") for l in ({}, {"until": "2026-09-15"}, {"since": "2026-10-01"}, {"until": "soon"})]
['current', 'ended', 'future', 'unreadable']
```

### acquaint.trust.tier_in_force(tiers, , today)

The entry whose validity covers `today` (from `valid_from`, up to but not including `valid_to`).

Superseded entries stay in the file with their `valid_to`; when two still overlap,
the later `valid_from` wins, then the later entry.

* **Return type:**
  [`Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping) | [`None`](https://docs.python.org/3/builtins/constants.html#None)

```pycon
>>> tier_in_force([{"tier": "open", "valid_from": "2026-10-01"}], today="2026-09-15") is None
True
```


# about-this-build.html.md

<!-- generated by epythet -->

# About this build

This documentation was built on **2026-10-08 12:17 UTC** from commit <a href="https://github.com/thorwhalen/acquaint/commit/0d69851b720ab6a4ec56b84099b77449cd4ddc8d"><code>0d69851</code></a> on branch <code>main</code>, for **acquaint 0.0.14** (from <code>pyproject.toml</code>).

#### WARNING
The documentation and the package may be misaligned:

- The documented version (0.0.14) is behind the latest release on PyPI (0.0.15): `pip install acquaint` gives newer code than these docs describe.

## Source

|                     |                                                                                                                                                            |
|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Commit              | <a href="https://github.com/thorwhalen/acquaint/commit/0d69851b720ab6a4ec56b84099b77449cd4ddc8d"><code>0d69851b720ab6a4ec56b84099b77449cd4ddc8d</code></a> |
| Branch              | <code>main</code>                                                                                                                                          |
| Tags at this commit | none                                                                                                                                                       |
| Working tree        | clean                                                                                                                                                      |
| Remote              | <code>https://github.com/thorwhalen/acquaint</code>                                                                                                        |

## Continuous integration

|              |                                                                                            |
|--------------|--------------------------------------------------------------------------------------------|
| Repository   | <code>thorwhalen/acquaint</code>                                                           |
| Run          | <a href="https://github.com/thorwhalen/acquaint/actions/runs/37775567770">37775567770</a>  |
| Ref          | <code>refs/heads/main</code>                                                               |
| Event commit | <code>0d69851b720ab6a4ec56b84099b77449cd4ddc8d</code> (in the history of the built commit) |

## Tools

|          |         |
|----------|---------|
| epythet  | 0.2.12  |
| Sphinx   | 9.1.0   |
| docutils | 0.22.4  |
| Python   | 3.12.15 |

## Configuration as resolved

|               |                                                                  |
|---------------|------------------------------------------------------------------|
| theme         | <code>auto</code> (Sphinx theme <code>shibuya</code>)            |
| accent        | <code>#803878</code>                                             |
| api_generator | <code>autosummary</code>                                         |
| ignore        | <code>tests/</code>, <code>scrap/</code>, <code>examples/</code> |
| agent_outputs | <code>true</code>                                                |
| aggregates    | <code>md</code>                                                  |
| ai_artifacts  | <code>true</code>                                                |

## Package on PyPI

Latest release: <a href="https://pypi.org/project/acquaint/0.0.15/">0.0.15</a>, newer than the documented version (0.0.14).

## Reproduce

```bash
git clone https://github.com/thorwhalen/acquaint && cd acquaint
git checkout 0d69851b720ab6a4ec56b84099b77449cd4ddc8d
pip install "epythet==0.2.12"
epythet quickstart . --ignore tests/ scrap/ examples/
```

The same data, for machines: <a href="build_info.json"><code>build_info.json</code></a> (schema version 1).


# ai-agents.html.md

<!-- generated by epythet -->

# For AI agents

`acquaint` ships artifacts for coding agents alongside its code. This page lists
them, says where each lives in the repository, and points at the
machine-readable copies of this documentation.

## Skills

Skills are folders holding a `SKILL.md` (the [Agent Skills](https://agentskills.io) format): a description that tells an agent when to use it and a body with the procedure. Install one into your agent with `gh skill` (any host: `--agent claude-code`, `copilot`, `cursor`, `codex`, `gemini`), or use the copy bundled in the wheel.

### `acquaint`

Who someone is, how to reach them, and how to write to them, from the operator’s local people records (acquaint). Use whenever a person, project, org or group is named in a task — to get a handle, email or alias; to check whether two names are the same person before writing them as two; before drafting anything a specific person will read; and to record something learned about someone, with its source. Triggers on “who is X”, “what’s X’s email/handle/GitHub”, “is X the same person as Y”, “how do I reach X”, “remember that X…”, “add X to my profiles”, “brief me on X”, and on any name in prose about to be published. Routes heavier work to acquaint-write, acquaint-read, acquaint-profile, acquaint-sync, acquaint-meeting-todos and deslop. Query one record; never read the whole store.

```bash
gh skill install thorwhalen/acquaint acquaint --agent claude-code
```

Source: [`acquaint/data/skills/acquaint`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/skills/acquaint) (bundled with the pip package).

### `acquaint-meeting-todos`

Turn the todos from a meeting into GitHub issues for a company or project the operator works on — one manual-task issue per participant in the project’s private meta repository, items copied verbatim, each linked to the notes and to the issue or page it concerns. Use when given meeting notes, minutes, a transcript, a Slack thread or an email with “next steps”, “action items” or “todos” and asked to “put these in issues”, “file the meeting todos”, “make issues from the next steps”, “assign the action items”, or “track what everyone said they’d do”. Checks first, through acquaint, that the project is unambiguous, that every participant is registered and belongs to it, and that its declared meta repository is private; when any of these fails, it tells the user what is missing and how to fix it, and files nothing.

```bash
gh skill install thorwhalen/acquaint acquaint-meeting-todos --agent claude-code
```

Source: [`acquaint/data/skills/acquaint-meeting-todos`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/skills/acquaint-meeting-todos) (bundled with the pip package).

### `acquaint-profile`

Build, research, update or consolidate a profile in acquaint — gather a person’s own writing, extract observable communication habits with evidence, and write sourced lines into their entry file, writing card and views. Use when asked to “make a profile of X”, “research how X writes”, “update X’s profile”, “what do we know about how X communicates”, “consolidate X’s observations”, “turn these notes into a profile”, or before a high-stakes message to someone whose record is thin. Runs parallel profile-reader agents on one extraction brief. Records behaviour with sources, never personality labels or sensitive categories.

```bash
gh skill install thorwhalen/acquaint acquaint-profile --agent claude-code
```

Source: [`acquaint/data/skills/acquaint-profile`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/skills/acquaint-profile) (bundled with the pip package).

### `acquaint-read`

Interpret a message from a specific person using their acquaint record — what they are saying and asking, what they likely mean and how strongly, how it differs from their usual, and what to do next — and judge, with evidence and never as an accusation, whether it was AI-processed. Use when asked “what does X mean by this”, “read this message from X”, “how should I take X’s reply”, “is X unhappy with this”, “did X write this with AI”, or when a reply from a known person arrives during a task. Records anything newly learned with acquaint remember, sourced.

```bash
gh skill install thorwhalen/acquaint acquaint-read --agent claude-code
```

Source: [`acquaint/data/skills/acquaint-read`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/skills/acquaint-read) (bundled with the pip package).

### `acquaint-sync`

Set up, use and check private sync of the acquaint profile store through a private GitHub repository. Use when asked to “sync my profiles”, “back up my acquaint store”, “set up profiles on the server”, “use my profiles on another machine”, “is my profile store private”, “push/pull profiles”, or when acquaint sync status reports a problem. Covers what the visibility guard does and, plainly, what it does not protect, plus the git-remote-gcrypt upgrade.

```bash
gh skill install thorwhalen/acquaint acquaint-sync --agent claude-code
```

Source: [`acquaint/data/skills/acquaint-sync`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/skills/acquaint-sync) (bundled with the pip package).

### `acquaint-write`

Write, edit or review anything a specific person will read — an email, a reply, a chat message, an issue or PR comment, a pitch, a document — using that person’s acquaint record; and spar with a simulated version of them to stress-test a draft or an idea. Use when asked to “write to X”, “reply to X”, “draft this for X”, “how should I put this to X”, “would X like this”, “red-team this against X”, “argue with me as X”, or whenever the reader of a draft is a known person. Runs acquaint brief, check and style-lint, applies deslop, and keeps the operator’s voice and positions.

```bash
gh skill install thorwhalen/acquaint acquaint-write --agent claude-code
```

Source: [`acquaint/data/skills/acquaint-write`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/skills/acquaint-write) (bundled with the pip package).

### `deslop`

Write and edit prose that carries no machine-writing tells and sounds like its author, calibrated to the reader. Use whenever drafting or editing text a person will read — emails, messages, READMEs, docs, posts, pitches, reports — and whenever the user mentions AI slop, AI tells, “sounds like AI”, “make it sound human”, “my voice”, or asks to de-AI a draft; also whenever another skill asks for it (acquaint-write does). Runs the deterministic acquaint style-lint check at the reader’s tolerance of AI-sounding text, then judgment passes for rhythm, specificity and ownership. Never fakes humanity and never invents specifics.

```bash
gh skill install thorwhalen/acquaint deslop --agent claude-code
```

Source: [`acquaint/data/skills/deslop`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/skills/deslop) (bundled with the pip package).

The bundled skills are also on disk after `pip install acquaint`, under the package’s `data/skills/` directory; link them into an agent without network access with `skill link-skills <that directory>`.

## Subagents

Subagents are Markdown files with a frontmatter (`name`, `description`, `tools`) and a system prompt as the body. Copy one into your project’s `.claude/agents/` (or your agent host’s equivalent) to delegate the task it describes.

### `profile-reader`

Parallel extraction worker for the acquaint-profile skill. Reads one batch of a person’s own writing and returns evidence rows (dimension, observation, short quote, anchor, date) exactly as the skill’s extraction brief specifies — never a summary, never personality labels or sensitive categories. Spawn several at once, one batch each.

Source: [`acquaint/data/agents/profile-reader.md`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/agents/profile-reader.md); tools: `Read, Grep, Glob, WebFetch`.

### `recipient-reader`

Simulates how a specific, known person is likely to read a draft or answer an idea, grounded only in the acquaint brief it is handed. Used by the acquaint-write skill for its red-team check (a report on a draft, without rewriting it) and for sparring (arguing from the person’s documented positions). Always presented as a simulation; every point cites the brief line it rests on.

Source: [`acquaint/data/agents/recipient-reader.md`](https://github.com/thorwhalen/acquaint/tree/HEAD/acquaint/data/agents/recipient-reader.md); tools: `Read`.

## Instruction files

Files agents read before working in this repository.

- [`.claude/CLAUDE.md`](https://github.com/thorwhalen/acquaint/tree/HEAD/.claude/CLAUDE.md): read by Claude Code

## Machine-readable documentation

This site publishes the same documentation in forms that fit an agent’s context window:

- [`llms.txt`](https://thorwhalen.github.io/acquaint/llms.txt): an index of every page with a one-line description ([llms.txt](https://llmstxt.org) format)
- [`acquaint.md`](https://thorwhalen.github.io/acquaint/acquaint.md): the whole documentation as one Markdown file
- `<page>.html.md`: a rendered Markdown twin of every page, advertised from each page’s `<head>` with `<link rel="alternate" type="text/markdown">`
- [`objects.inv`](https://thorwhalen.github.io/acquaint/objects.inv): the Sphinx inventory: a symbol-to-URL index (`sphobjinv convert plain objects.inv -`)


# api.html.md

# API reference

| [`acquaint`](_autosummary/acquaint.html.md#module-acquaint)   | acquaint: people, and what they are involved in, for AI agents.   |
|-----------------------------------------------------------------------------|-------------------------------------------------------------------|


