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).

Functions

brief(person, *[, purpose, project, ref, ...])

Everything to know before writing to someone: card, writing style, reach, project norms, recent observations, gaps.

check(text, *[, data_dir])

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

data_dir([data_dir])

The data root: the argument, else $ACQUAINT_DATA_DIR, else data_dir in config.toml, else ~/.local/share/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(entity, *[, confirm, data_dir])

Remove an entity's folder and leave a salted tombstone.

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(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(person, *[, purpose, urgency, ...])

Ordered channels for reaching someone in a context.

remember(entity, text, *[, source, kind, ...])

Append a dated observation (observation, interaction, identity, preference, view, rule) to an entity's log, with its source.

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(handle, *[, data_dir])

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

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(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(*, 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(*[, dry_run, data_dir])

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

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(*[, check_visibility, data_dir])

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

who(name, *[, field, brief, data_dir])

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

Classes

Entity(store, key)

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

Store([data_dir, files])

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

Exceptions

AcquaintError

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

exception acquaint.AcquaintError[source]#

Bases: Exception

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

class acquaint.Entity(store, key)[source]#

Bases: 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; they never raise.

property aka: list[str]#

Other names this entity goes by, as strings (a scalar aka is 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.

{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.

summary()[source]#

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

Return type:

dict[str, Any]

property surface_forms: list[str]#

id, name, aka, name parts, handles.

Type:

Every string a document might use for this entity

text(name, default='')[source]#

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

Return type:

str

property trust: list[dict]#

{tier, valid_from, valid_to, review_by, recorded, source, note} (see acquaint.trust).

Type:

Disclosure tiers from trust.yaml

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

Bases: MutableMapping

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')
all_files(key)[source]#

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

Return type:

list[str]

append_text(key, name, text)[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.

Return type:

None

exists(key)[source]#

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

Return type:

bool

find(ref)[source]#

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

find_id(slug)[source]#

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

Return type:

list[str]

location_warning()[source]#

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

Return type:

str | None

misnamed()[source]#

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[str]

move(src, dst)[source]#

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

Return type:

None

path_of(key)[source]#

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

Return type:

str

acquaint.brief(person, *, purpose=None, project=None, ref=None, audience=None, data_dir=None)[source]#

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

acquaint.check(text, *, data_dir=None)[source]#

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

Return type:

dict

acquaint.data_dir(data_dir=None)[source]#

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

>>> data_dir("profiles").is_absolute()
True
acquaint.disclosure(people, *, projects=None, audience=None, today=None, data_dir=None)[source]#

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

acquaint.forget(entity, *, confirm=False, data_dir=None)[source]#

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

acquaint.lint(entity=None, *, data_dir=None)[source]#

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

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

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

Return type:

dict

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

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

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

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

acquaint.rename(entity, to, *, data_dir=None)[source]#

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

acquaint.resolve(handle, *, data_dir=None)[source]#

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

acquaint.review(person, *, today=None, data_dir=None)[source]#

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

acquaint.style_lint(text, *, recipient=None, tolerance=None, data_dir=None)[source]#

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

Return type:

dict

acquaint.sync_init(*, repo, remote_url=None, existing_only=False, dry_run=False, data_dir=None)[source]#

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

acquaint.sync_pull(*, dry_run=False, data_dir=None)[source]#

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

Return type:

dict

acquaint.sync_push(*, message=None, dry_run=False, data_dir=None)[source]#

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

Return type:

dict

acquaint.sync_status(*, check_visibility=True, data_dir=None)[source]#

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

Return type:

dict

acquaint.who(name, *, field=None, brief=False, data_dir=None)[source]#

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

Modules

deslop

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

edit

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

lookup

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

mcp

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

meta

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

records

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

render

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

resources

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

store

Where records live and how code reaches them: the data root, Store and Entity.

sync

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

tools

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

trust

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