A ticket standard for local-first coordination

Give the work a ledger.
Give the failure a reason.

fluxrecord is a ticket standard for local-first, evidence-driven coordination — built for people working across AI coding agents, CLIs, and terminal sessions.

The fluxrecord wordmark, rendered by flux art
The wordmark, rendered by flux art. One idea in five styles, with an optional ANSI gradient that honours NO_COLOR.

01 / Quick start

One ledger, one command, one source of truth.

Zero runtime dependencies. The ledger is a SQLite file you own.

# install
pip install fluxrecord

# create the ledger and the project layout
flux init

# add a ticket with its acceptance criteria
flux task-add M-0001 \
  --objective "Add intake validation" \
  --acceptance "Bad intake returns exit 2 with a named reason" \
  --scope src/intake.py

# claim it, then record what you actually did
flux start M-0001 --owner agent-alpha
flux checkpoint <session> \
  --summary "Added intake validation" \
  --evidence tests/test_intake.py \
  --next "wire it into the CLI" \
  --tokens 1200

02 / What it does

Bounded context, explicit ownership, visible failures.

The ledger separates a finished session from accepted work.

Leases

Ownership that expires.

A ticket is claimed with a lease. When the lease runs out the work is reconciled, not silently stolen.

Evidence

Checkpoints, not vibes.

Every checkpoint carries a summary, the evidence that backs it, the next step, and the tokens it cost.

Portable files

The ledger exports to files.

Markdown tickets with front matter, an index, and one evidence file per checkpoint — the layout the specification describes.

Adapters

GitHub as an outbox.

Durable observations and an idempotent outbox, so a public summary is never sent twice and never sent blind.

03 / See it work

The whole loop, in one ticket.

Every image is the real output of the real CLI, captured against a throwaway ledger. Nothing here is mocked.

The flux command line: task-add, start, checkpoint, finish and decide accept, showing one ticket moving from ready to done
One ticket, one gate. A ticket is created with an objective and an acceptance criterion, claimed with a lease, checked with evidence, and only an operator's decide accept moves it to done. Nothing else does.
flux benchmark compares the packet a worker is handed with the bytes re-reading the files would cost
The promise, measured. A promise nobody measures is a marketing claim, so flux benchmark compares the packet against the files the ticket names. Files that do not exist are not counted, so the comparison never flatters itself.
flux pack --since --delta-only returns only what changed since a packet was last sent
Only what changed. Every packet is addressed by its hash, so a worker resuming a ticket reads the delta rather than the whole thing again.
flux doctor reports on the ledger, the project, the adapters and the environment in one answer
One report about the whole system. The doctor asks every part what it knows and puts the answers together — and it will not create the ledger it is diagnosing.
flux verify checks the event chain and reports whether the log was rewritten
Proof the log is intact. With a chain key, every event carries a digest of the one before it, so a silent edit is detectable. It is evidence, not protection.

04 / The standard

A format other tools can check.

Versioned, frozen, and published as a schema somebody else can validate against.

Wire format

Version 1, and frozen.

From wire format 1 onwards, changing the name of a field is a breaking change. The published schema is generated from the code, so it cannot describe the previous release.

The JSON Schema ↗

Conformance

Check your own.

The conformance suite runs a fixed sequence of commands against an implementation and checks every report against the published schema. It knows nothing about fluxrecord's internals.

The suite ↗

Boundaries

What it will not do.

The core ledger opens no socket, runs no subprocess, and sends no telemetry. The adapters each declare their own. The threat model says what that does and does not protect against.

The threat model ↗