Skip to main content

.aim: an open document format for human + AI co-authoring

PyPI Python CI License: MIT

Specification · Getting started · Examples

A .aim file is a single HTML document that is, at the same time:

  • The rendered artifact. Double-click the file and any browser shows the styled document. No tooling, no build step, no export.
  • The accepted current version. Every block is covered by a chunk with a stable, unique id that AI and tools use to say which part of the document they mean.
  • The pending-change lane. Proposals from AI or humans travel inside the file, visible to any reader, each with its author and a one-line explanation. They apply only on an explicit accept.
  • The full edit history. An append-only, invertible event log from which any past version can be reconstructed and verified against checkpoint hashes.
  • The derived caches. Summary, table of contents, embeddings and packed assets ride along to help agents; none is load-bearing, and all of them can be rebuilt.

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 itself: 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       │
└────────────────────────────────────────────────────────────────────────┘

The spec is a v0.5 draft; breaking changes are possible until 1.0. What each revision added: status and roadmap.

Install

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

Quickstart

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, not in an editor's database: 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, and 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 over a copy, byte-compares every payload (which catches 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: read almost anything, write Word

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

The API in one table

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

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

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/) 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):

  • HTML plus a closed Tailwind-vocabulary subset. Models read and write it accurately, a finite vocabulary with one versioned stylesheet kills cross-model drift, and every browser renders it for free.
  • Styling has three tiers. Which one you reach for is decided by the scope of the change, not by taste: reusable roles are classes, document-wide constants are theme slots, and one element's own exact value (a position, or since v0.3 a colour) is inline 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.
  • 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 (applied vs proposed), and deterministic supersede/chain semantics.
  • Docs and slides in one format. Slides are fixed-canvas containers of positioned chunks, with the same proposals and the same history.
  • Security as conformance. No script, no event handlers, no dangerous URL schemes, all enforced by the linter (aim lint is the gate).

Status and roadmap

The spec and the reference tooling are published; breaking changes stay possible until 1.0.

  • v0.5 (the current draft) added numbering that survives an edit: a block states its level (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.
  • v0.4 added literal per-element typography: inline font-size and font-family, a display type scale, and justified alignment.
  • v0.3 added literal per-element paint: validated inline color, background-color and border-color, so one element can be given one exact colour without touching a document-wide theme slot.
  • v0.2 added pagination: page setup (aim:doc) and hard page breaks.

Planned next, tracked in the spec's Future Extensions: reference viewer and PPTX import/export.

Repository map

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)

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, which covers how the registry, generated appendix, fixtures, and executable spec snippets fit together. AI agents: start at AGENTS.md.

License

MIT © Luca Campanella

Metadata

Release files for aimformat 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aimformat 0.5.0
File Size Uploaded Provenance
aimformat-0.5.0.tar.gz 907.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for aimformat 0.5.0
File Interpreter ABI Platform
aimformat-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.1 MB

Release files / aimformat-0.5.0.tar.gz

Download URL aimformat-0.5.0.tar.gz
Size 907.0 kB
Tags Source
SHA-256 checksum
How to use checksums
51e7f23de0c974788a583fc77f2c0d753512b840a8aaffb6ecbb6b75a1c2505e
BLAKE2b-256 checksum
How to use checksums
a3006c9f48f28d88cfa3c20dc509d674243631b8cffb3e4407d8bb820db34bb6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Release files / aimformat-0.5.0-py3-none-any.whl

Download URL aimformat-0.5.0-py3-none-any.whl
Size 206.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c28c6250af78dd2e4116f1606379c30068f496d9790ddae2fb4a549c3ebbd0e7
BLAKE2b-256 checksum
How to use checksums
7a8f72ab8f08a6247b758f7af9bd626413ecb8d36a670a168772ff4aeea8e755
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

Security for aimformat 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for aimformat-0.5.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page