Reference SDK and verifier for the .aim document format — AI proposals and human accept/reject as file primitives
Project description
.aim — an open document format for human + AI co-authoring
Status: v0.2 draft — spec and reference tooling published, breaking changes
possible until 1.0. v0.2 adds pagination: page setup (aim:doc) and hard
page breaks. Specification ·
Getting started ·
Examples
A .aim file is a single HTML document that is, at the same time:
- the rendered artifact — open it in any browser, styled, no tooling;
- the accepted current version — every block covered by a stable, uniquely-identified chunk that AI and tools can address;
- the pending-change lane — AI/human proposals carried in the file, visible to any reader, applied only on explicit accept;
- the full edit history — an append-only, invertible event log; any past version is reconstructible and verifiable against checkpoint hashes;
- derived caches — summary, TOC, embeddings, packed assets — that help agents but are never load-bearing.
Documents are increasingly written with AI, in formats designed for a
single human at a single cursor. Everyone building document workflows with
AI reinvents the same primitives: addressing a region of a document,
tracking which edits came from the model, letting a human accept or reject
them, proving what the document said before. .aim makes those primitives
part of the file format — open, editor-agnostic, MIT.
┌──────────────────────────── one .aim file ────────────────────────────┐
│ <head> summary + TOC cache · versioned stylesheet · theme │
│ <body> the accepted document (chunks + containers, renderable) │
│ <aim-proposals> pending AI/human changes + explanations │
│ <aim-assets> content-addressed packed images │
│ history append-only invertible event log (JSONL) │
│ embeddings per-chunk vectors w/ staleness hashes │
└────────────────────────────────────────────────────────────────────────┘
Install
pip install aimformat # zero runtime dependencies (stdlib only)
pip install 'aimformat[docx]' # + DOCX export (python-docx)
pip install 'aimformat[mcp]' # + MCP server: aim mcp
pip install 'aimformat[convert]' # + md/docx import-export, pdf import
pip install 'aimformat[pdf]' # + PDF export (playwright + chromium)
The CLI installs as aim and as aimformat (same tool; the alias avoids
the console-script collision with AimStack's aim experiment tracker and
makes uvx aimformat work).
Sixty seconds
import aimformat as aim
doc = aim.new_document(title="Q3 Proposal")
me, bot = aim.human("ada"), aim.agent("model-id")
# direct edits append invertible history events
intro = doc.add_chunk("<p>We propose a three-year engagement.</p>", author=bot)
# the pending lane: propose → human decides
p = doc.propose_modify(intro.id,
f'<p data-aim="{intro.id}">Acme saves €2.1M over three years.</p>',
author=bot, explanation="Lead with the outcome.")
doc.accept(p.id, decided_by=me) # or .reject(...), or accept with tweaks
doc.checkpoint("sent-to-client") # pins a verifiable doc_hash
assert doc.verify() == [] # replay the log, check every hash
doc.save("proposal.aim") # canonical bytes; renders in a browser
aim lint proposal.aim # structure + vocabulary + security + history chain
aim show proposal.aim # chunks, pending lane, history at a glance
aim hash proposal.aim # current doc_hash
aim normalize other.aim # re-spell to canonical form (lossless, idempotent)
What makes this different from "HTML with extra attributes":
- Identity is part of the format. Chunk ids live in the file, edits target ids (never character offsets), and identity survives any tool.
- Byte-canonical serialization. Attribute order, class order, escaping, line structure — all specified. Equality is byte equality; diffs are string compares; no editor's parser is the arbiter of truth.
- The history verifies. Every state-changing event carries enough to
undo it;
verify()replays the log backwards and byte-compares every payload, catching out-of-band edits, and checks every checkpoint hash. - Provenance is first-class. Every event and proposal records its actor
(
human/agent+ exact model id /external), timestamp, batch, and a one-line explanation.
Interop: anything → .aim → DOCX
Ingest whatever docling can read (PDF, DOCX, PPTX, images, HTML) — without adding docling as a dependency of this package:
from docling.document_converter import DocumentConverter
import aimformat as aim
result = DocumentConverter().convert("contract.pdf")
doc = aim.from_docling(result.document) # chunks, lists, tables, figures
doc.save("contract.aim") # ingestion itself is history
Export back to Word — with the pending lane as real tracked changes
(w:ins/w:del, attributed to the proposing human or model), or resolved
with a caller-chosen default:
aim.to_docx(doc, "out.docx", pending="tracked") # reviewable in Word
aim.to_docx(doc, "out.docx", pending="accept-all") # resolved on a copy
aim.to_docx(doc, "out.docx", pending="reject-all")
The API in one table
| load / create | load, loads, new_document, doc.save, doc.dumps |
| read | doc.chunks, doc.chunk(id), doc.containers, doc.proposals, doc.history, doc.meta, doc.theme, doc.doc_hash, doc.seq |
| direct edits | add_chunk, modify_chunk, delete_chunk, move_chunk, set_theme, doc.batch() |
| pending lane | propose_modify/add/delete/move/theme, accept (with optional applied= tweaks), reject; supersede and chain rebinding are automatic |
| history | verify, state_at(seq), checkpoint, undo, redo, flatten, prune, reconcile (repair out-of-band edits / adopt hand-written files) |
| caches | set_summary, generate_toc, set_embedding, stale_embeddings |
| assets | pack_assets (data-URIs → content-addressed registry), gc_assets |
| interop | from_docling, to_docx |
| verifier | lint, lint_text, lint_path → Finding(code, level, message, where) |
| agent note | doc.note, doc.set_note(), doc.remove_note(), doc.has_canonical_note() (spec §2.5) |
Actors: aim.human("ada"), aim.agent("model-id"), aim.external("tool"),
parsed from strings with aim.parse_actor("agent:model-id").
For agents & LLMs
Every .aim file opens with a short agent note (spec §2.5) — a
declarative head comment that tells whichever LLM opens the file what it
is, where the docs live, and which invariants to keep. It is informative
only, by spec: nothing installs or executes because of it. The note points
to https://aimformat.com/llms.txt, which condenses
docs/for-agents.md
— the canonical guide for agents.
The tooling on-ramps, in order of preference:
# CLI — coding agents with a shell need nothing else
aim show FILE --format json
aim propose modify FILE CHUNK_ID --html '…' --author agent:MODEL_ID
aim accept FILE PID --author human:ada
aim note FILE --check # CI gate for the agent note
# Agent Skill — any harness supporting the open Agent Skills standard
npx skills add tndmhq/aimformat
# Claude Code: /plugin marketplace add tndmhq/aimformat
# MCP server — shell-less clients (six tools, local stdio)
pip install 'aimformat[mcp]'
{ "mcpServers": { "aimformat": { "command": "aimformat", "args": ["mcp"] } } }
An id-preservation eval harness under
evals/ measures
how well naked LLMs respect the format's invariants with and without the
agent note.
Format at a glance
The specification is one file, and it is executable: every
```aim snippet in it is linted in CI, the construct reference appendix
is generated from the same registry that
drives the linter and the stylesheet, and the conformance suite
(tests/fixtures/) pins every rule with an ok_* /
nok_<CODE>_* file pair that third-party implementations can reuse.
Design pillars (details and rationale in the spec):
- HTML + a closed Tailwind-vocabulary subset — models read and write it accurately; a finite vocabulary plus one versioned stylesheet kills cross-model drift; every browser renders it for free.
- Semantic chunking — chunk boundaries are authorial; the chunk is the unit of meaning, retrieval, edit targeting, and explanation.
- Propose/accept as file primitives — with persisted attribution,
explanations, accept-with-tweaks (
appliedvsproposed), and deterministic supersede/chain semantics. - Docs and slides in one format — slides are fixed-canvas containers of positioned chunks; same proposals, same history.
- Security as conformance — no script, no event handlers, no dangerous
URL schemes, enforced by the linter (
aim lintis the gate).
Repository map
spec.md |
the normative specification (single file, executable snippets) |
src/aimformat/ |
reference SDK: document ops, verifier, canonical form, CSS generator, ingest/export |
src/aimformat/registry.json |
the machine-readable vocabulary — single source for linter, stylesheet, spec appendix |
tests/ |
310+ tests; tests/fixtures/ is the conformance suite |
examples/ |
worked documents, generated by the SDK (readme) |
src/aimformat/mcp.py |
the MCP server (aim mcp, stdio, six workflow tools) |
skills/aimformat/ |
the Agent Skill (npx skills add tndmhq/aimformat) |
docs/for-agents.md |
the canonical LLM-facing guide (served as aimformat.com/llms.txt) |
evals/ |
id-preservation eval harness (agent-note A/B) |
scripts/ |
appendix/fixture/example generators |
docs/ |
contributor + agent memory (knowledge base and decision log) |
Planned next (tracked in the spec's Future Extensions): reference viewer, PPTX export, pagination.
Relationship to Tndm
The format is maintained by Tndm, which builds a commercial editor on top of it — the same model as ProseMirror/Tiptap or Git/GitHub. The format itself is neutral ground: open, MIT-licensed, and designed to be adopted (and extended) by anyone, including other editors.
Contributing
See CONTRIBUTING.md — including how the registry,
generated appendix, fixtures, and executable spec snippets fit together.
AI agents: start at AGENTS.md.
License
MIT © Luca Campanella
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aimformat-0.2.0.tar.gz.
File metadata
- Download URL: aimformat-0.2.0.tar.gz
- Upload date:
- Size: 243.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cdf29d4980faf7138e1f4a74b404ea7a2991b5180fefffd1e90a74caa1155dde
|
|
| MD5 |
6767a17a2e3ed689ddb75195daa4679a
|
|
| BLAKE2b-256 |
19fe775c981213811b2a96db2298001dd9f344783e437fd76618a34e6eeabc01
|
Provenance
The following attestation bundles were made for aimformat-0.2.0.tar.gz:
Publisher:
publish.yml on tndmhq/aimformat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aimformat-0.2.0.tar.gz -
Subject digest:
cdf29d4980faf7138e1f4a74b404ea7a2991b5180fefffd1e90a74caa1155dde - Sigstore transparency entry: 2137666070
- Sigstore integration time:
-
Permalink:
tndmhq/aimformat@463b74ad54a8c6d8a4e1ca1018a39db048bad13f -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/tndmhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@463b74ad54a8c6d8a4e1ca1018a39db048bad13f -
Trigger Event:
release
-
Statement type:
File details
Details for the file aimformat-0.2.0-py3-none-any.whl.
File metadata
- Download URL: aimformat-0.2.0-py3-none-any.whl
- Upload date:
- Size: 111.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3e508b4c86d884e3c3bd0160cd6e539c98256b6b6c219d559715165a9873935
|
|
| MD5 |
ef7427eda6a6d804303ab212d99ff5bf
|
|
| BLAKE2b-256 |
8ba95fbcb6d7e2e5e1f45b4b9d8764b73ad5b5fe39c742ba793e98b330d4b78e
|
Provenance
The following attestation bundles were made for aimformat-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on tndmhq/aimformat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aimformat-0.2.0-py3-none-any.whl -
Subject digest:
f3e508b4c86d884e3c3bd0160cd6e539c98256b6b6c219d559715165a9873935 - Sigstore transparency entry: 2137666455
- Sigstore integration time:
-
Permalink:
tndmhq/aimformat@463b74ad54a8c6d8a4e1ca1018a39db048bad13f -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/tndmhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@463b74ad54a8c6d8a4e1ca1018a39db048bad13f -
Trigger Event:
release
-
Statement type: