livedocs
Notes that know when the code moved on.
livedocs binds Markdown notes (an Obsidian vault, or any folder of .md files inside a repo) to the
code they mention, and makes the git commit the place where notes and code are reconciled. It is a
thin layer over Fiberplane drift (which fingerprints symbols)
that adds what an agent-written vault needs:
- Anchors derived from the note's own backtick mentions — nothing to declare by hand.
- A note hash and member-level hashes in append-only stamps, so "this note was verified against this code" is a recorded fact, and only changes to what the note actually mentions count.
- A git pre-commit gate: a commit that changes code a note mentions is blocked until the note is
updated or acked with a reason. Provably benign changes (comment-only edits, pure moves, changes to
members the note doesn't mention) are acked mechanically.
unknownnever blocks. - A read-time report for agents:
CHANGEDwith was / now pinned to the note lines that mention the symbol — a fact, not a verdict. The agent that made the change decides what the note should say. - Coverage: which of a note's code claims are anchored, and which names it uses that no longer exist.
The guarantee is a mechanism of the development framework (git), not a capability of any agent: it holds for Claude Code, Codex, a human at a terminal, or anything else that commits.
New project? One command
livedocs new-vault docs/vault --scaffold-modules
creates an Obsidian vault (Home.md, Modules/ Concepts/ Reference/ Sessions/ Templates/, a minimal
.obsidian/), one empty note per source module, the livedocs config (sessions, reviews and templates
are snapshots), the git gate, the Claude Code adapter, and an AGENTS.md block — then commit. Open the
folder in Obsidian as a vault. From there: write notes, commit, reconcile when the gate says so.
Install
brew install fiberplane/tap/drift # or: curl -fsSL https://drift.fp.dev/install.sh | sh
Then livedocs itself, from PyPI (stdlib only, no Python dependencies):
uv tool install livedocs # or: pipx install livedocs
To hack on it: uv tool install --editable /path/to/vault-drift.
Then, in the repository that holds the vault:
livedocs init --vault docs/vault # git gate (.githooks + core.hooksPath), .livedocs/config.json,
# Claude Code Stop heads-up (settings.local.json), AGENTS.md block
That is the whole setup. Notes are stamped by the commit that adds or edits them: write a note, commit
it, and the gate binds its code mentions and records the stamp in the same commit. For an existing vault,
git add the notes and commit once (or run livedocs stamp <note> per note to see what each binds).
Each clone activates the versioned hook with git config core.hooksPath .githooks (init does it).
--repo defaults to the current git repository and --vault to the configured one, so inside the repo
the commands need no arguments.
The commit flow
edit code ──► git commit
│ gate: notes that mention the changed code, not yet reconciled?
├─ none / benign ────────────────────────────────► commit passes (benign ones auto-acked;
│ new or edited notes stamped)
└─ some ──► "CHANGED: <note> … was: … now: … note lines 13, 30"
edit the note and commit again (the commit stamps it)
or, still correct: livedocs stamp <note> --ack --reason "…"; git add -A; commit
livedocs affected lists the notes your uncommitted changes touch before you get there.
Commands
| Command | Does |
|---|---|
livedocs new-vault <path> [--scaffold-modules] |
scaffold an Obsidian vault and wire everything in |
livedocs init --vault <path> [--read-gate] [--shared] |
install the gate, config and harness adapter for an existing vault |
livedocs stamp <note> [--ack --reason R] |
bind a note's mentions with drift and record a stamp |
livedocs check <note> [--json] |
one note's state: fresh, changed, broken, unknown, snapshot |
livedocs affected [--cached] |
notes bound to files changed in the working tree (or the index) |
livedocs verify |
CI: every stamped note against the checked-out tree; exit 1 on changed/broken |
livedocs coverage |
per-note anchored / dangling mentions |
livedocs survey |
resolution statistics over a vault (diagnostics) |
Snapshot notes
Dated records — reviews, session logs, reports — describe the code as it was. Mark them with
livedocs: snapshot in the frontmatter, or list globs in .livedocs/config.json:
{ "vault": "docs/vault", "snapshot_globs": ["Reference/Review *", "Sessions/*"] }
They bind nothing, report snapshot, and never block.
CI
Pre-commit is skipped by --no-verify, merges and rebases. Run the same check in CI:
# .github/workflows/livedocs.yml
name: livedocs
on: [push, pull_request]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: curl -fsSL https://drift.fp.dev/install.sh | sh && echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- uses: astral-sh/setup-uv@v5
- run: uv tool install livedocs
- run: livedocs verify --repo . --vault docs/vault
Or with the pre-commit framework, add to .pre-commit-config.yaml:
- repo: https://github.com/GusEllerm/vault-drift
rev: v0.1.0
hooks: [{ id: livedocs-gate }]
What it can and cannot guarantee
- It guarantees that a committed note has been vouched for against the code it mentions, at that
commit. A read-time
changedmeans the working tree has moved since. - It sees code the note names in backticks. A prose claim with nothing to anchor ("tokens rotate every
15 minutes") is reported
unknown, neverfresh.livedocs coverageshows how much of each note that is. - It does not follow the call graph: a note's claim about what a function does can go stale when a callee changes. That is the residual miss class, measured at about 1 in 20 real changes on the reference history.
- Python only, for now (symbol resolution uses
ast; drift fingerprints six languages).
Background
Design, decisions and the measurements behind every choice live in the vault at live-docs-vault/
(start at Start Here.md). The short version: on a real 141-commit history, the hash flagged 22 of the
23 note-invalidating changes an anchor covered; only ~5% of flags marked a change that made a note wrong
— which is why the signal is delivered as a fact at commit time, to the agent that has the context, and
never as a verdict.
Release files for livedocs 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| livedocs-0.1.1.tar.gz | 46.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| livedocs-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 100.3 kB
Release files / livedocs-0.1.1.tar.gz
| Download URL | livedocs-0.1.1.tar.gz |
|---|---|
| Size | 46.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
450aa6415e87a4c66cf1b54db05c590e1faa73d204653cb192e733529e7ea07b
|
|
BLAKE2b-256 checksum How to use checksums |
188c50fd66494a7e4f8a449cb2c09149f71301f1fb003498ada1980fc91387b9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / livedocs-0.1.1-py3-none-any.whl
| Download URL | livedocs-0.1.1-py3-none-any.whl |
|---|---|
| Size | 53.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2b7861a84211065c5dfea973d1512801496b4ae32c93bb156d34fe85adc836cf
|
|
BLAKE2b-256 checksum How to use checksums |
5434a906c0c22c5b1309b05e0fe04e483f85754d61229e107ce9d4908adf2681
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|