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:
>>> 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 is a MutableMapping of entities over any mapping of
files (a dol files store by default).
- exception acquaint.AcquaintError[source]
An expected failure with a message meant for the person or agent that asked.
- class acquaint.Entity(store: Store, key: str)[source]
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; they never raise.- property aka: list[str]
Other names this entity goes by, as strings (a scalar
akais one alias, not its letters).
- property body: str
The entry file’s Markdown body.
- property errors: list[str]
Everything about the entry file and the YAML files that did not parse.
- property identities: list[dict]
{platform, value, source, status, …}.- Type:
Handles and addresses from
identities.yaml
- property kind: str
person,project,org,group, or the singular of an open kind’s folder.
- property links: list[dict]
{to, relation, role, since, until, source}.- Type:
Affiliations from
links.yaml
- property meta: dict
The entry file’s frontmatter (empty when it did not parse).
- property name: str
The display name, falling back to the id.
- property ref: str
person:ada-lovelace.- Type:
The link form other records use
- property rules: list[dict]
{when, do, set_by, source}.- Type:
Channel and communication rules from
rules.yaml
- property sections: dict[str, str]
The entry file’s
## Sections, keyed by normalized title.
- property surface_forms: list[str]
id, name, aka, name parts, handles.
- Type:
Every string a document might use for this entity
- class acquaint.Store(data_dir: str | PathLike | None = None, *, files: MutableMapping[str, str] | None = None)[source]
MutableMapping[str, Entity]over one folder per entity, keyed"<kind dir>/<slug>".>>> store = Store(files={}) >>> store["projects/example"] = {"PROFILE.md": "---\nname: Example\n---\n"} >>> store.find("project:example"), store.find("example") ('projects/example', 'projects/example')
- append_text(key: str, name: str, text: str) None[source]
Append to one of an entity’s files (created if missing); a true append on disk, so concurrent writers do not erase each other.
- exists(key: str) bool[source]
Whether anything is stored under the entity’s folder, with or without an entry file.
- find(ref: str) str[source]
The store key for
people/ada-lovelace,person:ada-lovelaceor a bareada-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 raisesKeyError, so no reference reaches outside the data root.
- find_id(slug: str) list[str][source]
Every key whose id is
slug, in any kind (ids are lowercase, so the lookup is too).
- location_warning() str | None[source]
A warning when the data root is, or sits inside, a git repository that is not an acquaint store.
- misnamed() list[str][source]
Entry files on disk the store cannot address: a folder or file name not in lowercase
kind/id/PROFILE.mdform, or a linked folder.
- acquaint.brief(person: str, *, purpose: str | None = None, project: str | None = None, data_dir: str | None = None) dict[source]
Everything to know before writing to someone: card, writing style, reach, project norms, recent observations, gaps.
- acquaint.check(text: str, *, data_dir: str | None = None) dict[source]
Scan prose that names people before publishing it: conflations (one person written as two), ambiguous names, unknown names.
- acquaint.data_dir(data_dir: str | PathLike | None = None) Path[source]
The data root: the argument, else
$ACQUAINT_DATA_DIR, elsedata_dirin 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.
>>> data_dir("profiles").is_absolute() True
- acquaint.forget(entity: str, *, confirm: bool = False, data_dir: str | None = None) dict[source]
Remove an entity’s folder and leave a salted tombstone. Needs the exact id; without
confirm, only reports what would be removed.
- acquaint.lint(entity: str | None = None, *, data_dir: str | None = None) dict[source]
Check records: every preference, view and rule sourced; nothing POLICY.md forbids; files parse; entry files within budget.
- acquaint.new(kind: str, name: str, *, qualifier: str | None = None, description: str | None = None, force: bool = False, data_dir: str | None = None) dict[source]
Create a person, project, org or group from its template (a readable slug id;
qualifierseparates two of the same name).
- acquaint.reach(person: str, *, purpose: str | None = None, urgency: str | None = None, project: str | None = None, message_type: str | None = None, topic: str | None = None, data_dir: str | None = None) dict[source]
Ordered channels for reaching someone in a context. Only active addresses; returns them, sends nothing.
outcomeisreachable,no_address(a rule matched, but no usable address is recorded for its channels) orno_channel.
- acquaint.remember(entity: str, text: str, *, source: str | None = None, kind: str = 'observation', reactivate: bool = False, data_dir: str | None = None) dict[source]
Append a dated observation (
observation,interaction,identity,preference,view,rule) to an entity’s log, with its source. 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.
- acquaint.rename(entity: str, to: str, *, data_dir: str | None = None) dict[source]
Change an entity’s id (
tois a slug) or name and id (tois a name), rewriting links to it. Needs the exact id.
- acquaint.resolve(handle: str, *, data_dir: str | None = None) dict[source]
Map a channel handle (
github:octocat,email:ada@example.org) to the entity it belongs to, with the evidence.okis 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 returnok: falsewith what was found.
- acquaint.style_lint(text: str, *, recipient: str | None = None, tolerance: str | None = None, data_dir: str | None = None) dict[source]
The deterministic half of deslop: machine-writing tells in a draft, at the recipient’s tolerance and against their blocklist.
- acquaint.sync_init(*, repo: str, remote_url: str | None = None, existing_only: bool = False, dry_run: bool = False, data_dir: str | None = None) dict[source]
Make the data root a checkout of a PRIVATE GitHub repository (created private through
ghunlessexisting_only), with a pre-push guard.
- acquaint.sync_pull(*, dry_run: bool = False, data_dir: str | None = None) dict[source]
Pull the store from its private remote, rebasing local work on top.
- acquaint.sync_push(*, message: str | None = None, dry_run: bool = False, data_dir: str | None = None) dict[source]
Commit, rebase onto the remote and push the store, after re-checking the remote, the guard and the visibility.
- acquaint.sync_status(*, check_visibility: bool = True, data_dir: str | None = None) dict[source]
Whether the store is synced, to which repository, uncommitted changes, ahead/behind, the guard, and live visibility.
- acquaint.who(name: str, *, field: str | None = None, brief: bool = False, data_dir: str | None = None) dict[source]
Look up one person, project, org or group by exact id, name, alias, handle or email.
Costs scale with what you ask:
fieldreturns one value (aka,email,github, any frontmatter key),briefthe identity block, and the default the whole entry file. It never guesses: no exact match, or several, returns the candidates andok: false.