Observed since 21 Oct, 11:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Reference SDK and verifier for the .aim document format — AI proposals and human accept/reject as file primitives
.aim: an open document format for human + AI co-authoringSpecification · Getting started · Examples
A .aim file is a single HTML document that is, at the same time:
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, handing work from one agent
to the next. .aim makes those primitives part of the file format itself:
open, editor-agnostic, MIT. And because proposals, reasoning, and
rejections stay in the file, an agent in another tool or harness picks up
the collaboration where the last one left off instead of starting from a
bare document.
┌──────────────────────────── 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 │
└────────────────────────────────────────────────────────────────────────┘
The spec is a v0.5 draft; breaking changes are possible until 1.0. What each revision added: status and roadmap.
pip install aimformat # zero runtime dependencies (stdlib only)
pip install 'aimformat[docx]' # + DOCX import (styling-preserving) and export
pip install 'aimformat[mcp]' # + MCP server: aim mcp
pip install 'aimformat[convert]' # + md import-export, DOCX both ways, 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).
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":
verify() replays the log backwards over a copy, byte-compares
every payload (which catches out-of-band edits), and checks every
checkpoint hash.human / agent + exact model id / external), timestamp, batch, and
a one-line explanation.DOCX imports natively, styling preserved — from_docx walks the OOXML
itself (the docx extra, no docling), so fonts, sizes, colours, highlights,
alignment, and the document's own theme survive into the .aim:
import aimformat as aim
doc = aim.from_docx("contract.docx") # styling carried, not just structure
doc.save("contract.aim") # ingestion itself is history
For everything else — PDF, PPTX, images, HTML — ingest whatever docling can read, without adding docling as a dependency of this package (PDF is structure-only: the model carries no fonts or colours):
from docling.document_converter import DocumentConverter
result = DocumentConverter().convert("contract.pdf")
doc = aim.from_docling(result.document) # chunks, lists, tables, figures
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")
| Area | API |
|---|---|
| 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, amend_proposal (replace a pending payload/explanation in place, unrecorded), 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) |
| compare versions | diff_documents (unit-level: added/deleted/modified/moved), classify_divergence (did the log grow, was it rewritten, does it explain the body) |
| caches | set_summary, generate_toc, set_embedding, stale_embeddings |
| assets | pack_assets (data-URIs into the content-addressed registry), gc_assets |
| convert | from_path, from_text, from_markdown, from_docx, from_pdf, from_docling; to_markdown, to_html, to_pdf, to_print_html (the HTML to_pdf prints, for your own Chromium), to_docx |
| verifier | lint, lint_text, lint_path, each returning 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").
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: for 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.
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/) ships ok_* files that must lint
clean plus nok_<CODE>_* files that must trip exactly their rule,
covering a growing subset of the rulebook (every rule's firing behavior
is additionally pinned in the test suite), for third-party
implementations to reuse.
Design pillars (details and rationale in the spec):
style, on a
closed property list with a closed grammar per property. An editing agent
usually sees part of a document; the literal is the only tier that cannot
repaint something it was never shown.applied vs proposed), and
deterministic supersede/chain semantics.aim lint is the gate). Executable
content was never part of the vocabulary, so a conforming file has nothing
to run; lint anything you did not write before you render it.The spec and the reference tooling are published; breaking changes stay possible until 1.0.
num-1 … num-9) and the stylesheet draws the
number, so inserting a clause renumbers everything below it instead of
leaving stale text that still reads as authoritative.font-size and
font-family, a display type scale, and justified alignment.color,
background-color and border-color, so one element can be given one
exact colour without touching a document-wide theme slot.aim:doc) and hard page breaks.Planned next, tracked in the spec's Future Extensions: reference viewer and PPTX import/export.
| Path | What it is |
|---|---|
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 the linter, stylesheet, and spec appendix |
tests/ | 598+ tests; tests/fixtures/ is the conformance suite |
examples/ | worked documents, generated by the SDK (readme) |
ts/ | @aimformat/reader: the official TypeScript read library (readme), pinned to the Python SDK by a parity suite (tests/parity/) |
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) |
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.
See CONTRIBUTING.md, which covers how the
registry, generated appendix, fixtures, and executable spec snippets fit
together. AI agents: start at AGENTS.md.
MIT © Luca Campanella
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.5.3 | 14 Oct 2026 | 11 |
This describes our collected data; it is not a security assessment.
Observed since 21 Oct, 11:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:63285cc0d616931d8f3671a9c98c0d55f735a8ba3bcdaf5bd01b7613fff2f334