agent-doc
Alpha Software — actively developed, APIs and frontmatter format may change between versions. Feedback welcome via GitHub issues.
Interactive document sessions with AI agents.
Edit a markdown document. Press a hotkey. The tool diffs your changes, sends them to an AI agent, and writes the response back into the document. The document is the UI.
Why
Terminal prompts are ephemeral. You type, the agent responds, the context scrolls away. Documents are persistent — you can reorganize, delete noise, annotate inline, and curate the conversation as a living artifact. The agent sees your edits as diffs, so every change carries intent.
Install
Quick Start
Document Format
agent_doc_session: 05304d74-90f1-46a1-8a79-55736341b193
agent: claude
Your question or instruction here.
(agent writes here)
Follow-up. You can also annotate inline:
Frontmatter fields
| Field | Required | Default | Description |
|---|---|---|---|
agent_doc_session |
no | (generated on first run) | Document UUID for tmux pane routing (legacy: session) |
agent_doc_format |
no | template |
Document format: inline (canonical) or template. append accepted as backward-compat alias for inline. |
agent_doc_write |
no | crdt |
Write strategy: merge or crdt |
agent_doc_mode |
no | — | Deprecated. Use agent_doc_format + agent_doc_write instead |
resume |
no | (none) | Claude conversation ID for --resume |
agent |
no | claude |
Agent backend to use |
model |
no | (agent default) | Model override |
branch |
no | (none) | Git branch for session commits |
claude_args |
no | (none) | Additional CLI args for claude process (space-separated) |
Two interaction modes
Append mode: Structured ## User / ## Assistant blocks.
Inline mode: Annotations anywhere — blockquotes, edits to previous
responses. The diff captures what changed; the agent addresses inline edits
alongside new ## User content.
Both work simultaneously because the run sends a diff, not a parsed structure.
Run Flow
┌──────────┐ hotkey ┌────────────┐ diff + prompt ┌───────┐
│ Editor │ ──────> │ agent-doc │ ──────────────> │ Agent │
│ │ │ │ <────────────── │ API │
│ reload │ <────── │ write+snap │ └───────┘
└──────────┘ │ git commit │
└────────────┘
- Read document, load snapshot (last-known state)
- Compute diff — if empty, exit (double-run guard)
- Send diff + full document to agent, resuming session
- Append response as
## Assistantblock - Save snapshot, git commit
Session continuity
- Empty
agent_doc_session:— forks from the most recent agent session in the directory (inherits context) agent_doc_session: <uuid>— resumes that specific session- Delete
agent_doc_session:value — next run starts fresh
History rewriting
Delete anything from the document. On next run, the diff shows deletions and the agent sees the cleaned-up doc as ground truth.
Components
Components are bounded, named regions in a document that can be updated independently:
Inline attributes on the tag override components.toml and built-in defaults. Precedence: inline attr > components.toml > built-in defaults.
Component marker detection uses pulldown-cmark for CommonMark-compliant parsing: tags inside inline code spans or fenced code blocks are ignored and never treated as component boundaries.
Standard component names
| Component | Default patch |
Description |
|---|---|---|
exchange |
append | Conversation history — each cycle appends |
findings |
append | Accumulated research data — grows over time |
status |
replace | Current state — updated at milestones |
pending |
replace | Task queue — auto-cleaned each cycle |
output |
replace | Latest agent response only |
input |
replace | User prompt area |
| (custom) | replace | All other components default to replace |
Update a component:
|
Component config
Configure modes and hooks in .agent-doc/components.toml:
[]
= "append" # append | replace (default) | prepend
= true # auto-prefix with ISO timestamp
= 100 # trim old entries
[]
= "scripts/validate.sh" # transform content (stdin → stdout)
= "scripts/notify.sh" # fire-and-forget after write
Dashboard-as-document
A dashboard is a markdown document with agent-maintained components. External scripts update components via agent-doc patch, and the watch daemon can auto-trigger agent responses:
# Start watching for changes
# Update from CI scripts
See Components guide and Dashboard tutorial for full documentation.
Git Integration
Each run auto-commits the document for inline diff highlighting in your editor.
| Flag | Behavior |
|---|---|
-b |
Auto-create branch agent-doc/<filename> on first run |
| (none) | Commit to current branch |
--no-git |
Skip git entirely |
Cleanup: agent-doc clean <file> squashes all session commits into one.
Configuration
claude_args
Pass additional CLI arguments to the claude process spawned by agent-doc start. Three sources, highest precedence first:
1. Document frontmatter (per-document):
---
agent_doc_session: 05304d74-...
claude_args: "--dangerously-skip-permissions"
---
2. Global config (~/.config/agent-doc/config.toml):
= "--dangerously-skip-permissions"
3. Environment variable:
Args are split on whitespace and prepended to the claude command before other flags.
Agent Backends
Agent-agnostic core. Only the "send prompt, get response" step varies.
# ~/.config/agent-doc/config.toml
[]
= "claude"
= ["-p", "--output-format", "json"]
= ".result"
= ".session_id"
[]
= "codex"
= ["--prompt"]
= ".output"
= ".id"
= "claude"
Override per-document via agent: in frontmatter, or per-invocation via --agent.
Tmux Session Routing
Route documents to persistent Claude sessions via tmux. Pane management is powered by tmux-router.
How it works:
- Each document gets an
agent_doc_sessionUUID in frontmatter (auto-generated if missing) - agent-doc maps UUIDs to file paths, then delegates to tmux-router for pane routing
routechecks if the pane is alive — if so, sends the command (with Enter retry verification) and focuses the pane- If the pane is dead (previously registered),
routelazy-claims to an active pane in theclaudetmux session, syncs the layout, then sends the command - New/unregistered files skip lazy-claim and go directly to auto-start, so each file gets its own Claude session
- If no active pane is available, auto-starts a new Claude session in tmux: first tries
split-windowin an existing window that has a registered agent-doc pane (avoids creating throwaway windows), falls back to creating a new window if no registered panes exist (30s startup timeout with❯prompt detection) syncauto-starts Claude sessions for files with session UUIDs but no alive panes before arranging the layout
Parallel — Fan-Out
Decompose a complex task into independent subtasks, each running in its own git worktree with a separate Claude session.
CLI
| Flag | Description |
|---|---|
--task "..." |
Subtask description (repeatable, at least 1) |
--model <model> |
Model override for subtask agents |
--timeout <secs> |
Per-task timeout (default: 600) |
--no-git |
Skip git commits in worktrees |
--dry-run |
Print plan without executing |
How it works
- Creates a git worktree per task (
.agent-doc/worktrees/<session>-<n>) - Writes task prompt to each worktree
- Spawns
claude -pin stashed tmux panes (one per worktree) - Polls for completion every 2 seconds
- Collects results: agent JSON output +
git diff HEADper worktree - Prints formatted markdown with collapsible diffs
From a document session
In a template-mode document, write a deep: directive in the exchange:
deep:
- --
The SKILL.md skill parses the deep: prefix, extracts bullet tasks, and calls agent-doc parallel --task "..." --task "...". Results are written back to the exchange.
Resync
Validate sessions.json against live tmux state and fix inconsistencies.
Dry-run (no --fix): Removes entries whose tmux panes no longer exist, purges idle stash windows (30s grace period), logs orphaned claude/stash windows, and reports wrong-session, wrong-process, or wrong-window panes without changing them.
With --fix:
- Wrong-session panes (pane is in a different tmux session than the document's
tmux_sessionfrontmatter) — kills the pane and deregisters it. The nextrouteauto-starts in the correct session. - Wrong-process panes (pane is running a non-agent-doc process, e.g.
corky watch) — deregisters the entry but leaves the foreign process alive. - Wrong-window panes (pane is in a separate non-stash window from the majority of panes in the same tmux session) — moves the pane into the stash window via
stash_pane. The nextsyncorlayoutwill rejoin it into the correct window.
Stash windows: When split-window fails during auto-start (e.g. minimum pane size constraint), the new pane is created in a fresh window and immediately moved to the stash window so no extra visible windows appear. Stash windows are named stash; if tmux auto-deduplicates the name they become stash-2, stash-3, etc. — all such names are recognized and eligible for purging.
Process allowlist: agent-doc, claude, node are valid agent processes. Idle shells (zsh, bash, sh, fish) are also allowed (a shell means the agent process hasn't started yet or has exited).
Automatic pruning: resync::prune() runs automatically before route, sync, and claim operations — you only need to run agent-doc resync explicitly for diagnostics or --fix.
IPC-First Writes
Since v0.17.5, all write paths (run, stream, write) try IPC to the IDE plugin when .agent-doc/patches/ exists (plugin installed) and --force-disk is not set. agent-doc writes a JSON patch to .agent-doc/patches/ instead of modifying the file directly. The plugin applies the change via Document API, preserving cursor position, undo history, and avoiding "externally modified" dialogs. On IPC timeout (2s), exits with code 75 (EX_TEMPFAIL) instead of falling back to disk write. Use agent-doc write --force-disk to bypass IPC and write directly to disk.
Editor Integration
JetBrains
External Tool: Program=agent-doc, Args=run $FilePath$,
Working dir=$ProjectFileDir$, Output paths=$FilePath$. Assign keyboard shortcut.
VS Code
Task: "command": "agent-doc run ${file}". Bind to keybinding.
Vim/Neovim
nnoremap <leader>as :!agent-doc run %<CR>:e<CR>
CLI Reference
agent-doc run <file> [-b] [--agent <name>] [--model <model>] [--dry-run] [--no-git]
agent-doc install [--editor jetbrains|vscode] [--skip-prereqs] [--skip-plugins]
agent-doc init # project init: .agent-doc/ dirs + SKILL.md
agent-doc init <file> [title] [--agent <name>] # scaffold session document
agent-doc diff <file>
agent-doc reset <file>
agent-doc clean <file>
agent-doc route <file> # route to existing tmux pane or auto-start
agent-doc start <file> # start Claude session in current tmux pane
agent-doc claim <file> [--window W] [--pane P] # claim file for a tmux pane
agent-doc focus <file> [--pane P] # focus tmux pane for a session
agent-doc layout <files> --split h [--window W] # arrange panes (window-scoped)
agent-doc outline <file> [--json] # section structure + token counts
agent-doc parallel <file> --task "..." [--model M] [--timeout S] [--dry-run] # parallel fan-out
agent-doc resync # validate sessions, prune dead panes, report issues
agent-doc resync --fix # also kill wrong-session panes, deregister wrong-process panes
agent-doc prompt <file> [--all] # detect permission prompts → JSON
agent-doc prompt --answer N <file> # answer prompt option N
agent-doc commit <file> # selective commit (snapshot only, user edits stay uncommitted)
agent-doc terminal <file> [--session S] # launch terminal with tmux for editor plugins
agent-doc skill install # install Claude Code skill definition
agent-doc skill check # check if installed skill is up to date
agent-doc patch <file> <component> [content] # update component (stdin if no content)
agent-doc watch [--stop] [--status] # watch daemon (debounce + reactive mode for stream docs)
agent-doc write <file> --force-disk # bypass IPC, write directly to disk
agent-doc history <file> # list exchange versions from git
agent-doc history <file> --restore <commit> # prepend old exchange content
agent-doc audit-docs # audit instruction files for staleness
agent-doc upgrade # upgrade to latest version
agent-doc plugin install <editor> # install editor plugin (jetbrains|vscode)
agent-doc plugin update <editor> # update editor plugin to latest
agent-doc plugin list # list available editor plugins
Domain Ontology
agent-doc extends the existence kernel vocabulary (defined in ~/.claude/philosophy/src/) with domain-specific terms for interactive document sessions.
| Term | Derives From | Description |
|---|---|---|
| Session | project + story | A bounded interaction with temporal arc; the unit of agent-doc work |
| Document | entity + context | A markdown file that holds conversational state between user and agent |
| Pane | focus + scope | A tmux viewport — finite attention applied to a single document |
| Claim | scope + entity | Binding a document to a pane; scoping focus to a specific file |
| Route | context + resolution | Resolving which pane handles a document; context-aware dispatch |
| Sync | pattern + system | Aligning tmux pane layout to editor split state; maintaining coherence |
| Watch | consciousness + evolution | Detecting file changes and triggering agent responses; event-driven |
| Dashboard | system + focus | A document used as a live system view with agent-maintained sections |
| Component | scope + abstraction | Bounded, named, re-renderable region in a document (<!-- agent:name -->...<!-- /agent:name -->). Configurable mode (replace/append/prepend) and shell hooks. |
| Registry | system + perspective | Persistent mapping of documents to panes; the routing state |
| Snapshot | entity + story | Point-in-time capture of document content for diff computation |
| Project | system + scope | The bounded working context; identified by .agent-doc/ at its root. Contains documents, registry, snapshots, daemon. tmux-router is project-agnostic. |
| Overlay | context + resolution | Domain-specific terms extending the base kernel vocabulary |
License
MIT