Working on commission, with commission
You will be able to take a piece of work on commission from “what should I do” to “closed, with evidence”, using the same loop the project uses on itself — and know which tests your change has to satisfy, which files you must never edit by hand, and what a release costs.
Before anything else: this repository is private and the software is
proprietary. LICENSE LICENSE grants no rights, and it is explicit
about contribution — the repository is not open to public contribution, every
contribution is assigned to the copyright holder, and contributors must have a
written agreement in place before contributing. Access to the repository is not
that agreement. If you do not have one, stop here; the rest of this page is
operational detail for people who do. Context and consequences:
licensing.
Commission tracks commission
There is no second place where work on Commission is tracked. No status document, no
markdown board, no issue tracker — the project’s own CLAUDE.md says it first
and it is meant literally: “Commission is the single source of truth for tasks in
this project. Never track status in markdown files; query commission instead.”
That is not dogfooding for its own sake. It is the only way the refusals stay honest: every rough edge in commission’s own loop is met by whoever is building it, that same day.
Get work
commission next --project commission --claimThe claim is atomic, so several agents can run this at once and each gets a distinct task. What comes back is the whole context bundle — the body, the acceptance criteria, the dependency state, the linked documents to read, the recent notes, and the commands that finish it from here. A fresh session needs that one command and nothing else.
If you want position rather than an assignment:
commission board --project commission
commission log --project commission --last 20board is where things stand; log is what happened since you last looked.
Neither is a report anyone writes.
Search before you plan
commission search "generated docs"Commission’s own history is full-text searchable, notes included. A decision that was already argued out six weeks ago is cheaper to find than to re-derive, and re-deriving it usually produces a different answer, which is worse.
Leave breadcrumbs as you go, not at the end
commission note commission-1 -m "the drift test regenerates every artifact in memory and diffs it, so a generator change with no doc change fails the suite — which is the point"Notes are written for the next session, not for a reader today. Decisions, dead
ends, discoveries. They are carried in every future context bundle and are what
commission search finds.
Finish with evidence
Commission’s documentation tasks carry the documented gate — test, commit,
docs — so closing one without them is refused:
commission done commission-1cannot complete commission-1: 1 unchecked criteria; gate 'documented' missing evidence [test, commit, docs]Satisfy it, then close:
commission check commission-1 0
commission evidence commission-1 test="bun test — 0 fail" commit=300e680 docs=docs/contributing/working-with-commission.md
commission done commission-1Never fabricate evidence. A benchmark number nobody ran is worse than an
unfinished task, because it closes the loop that was supposed to catch it. And do
not --force past a gate unless a human asked you to: the override is recorded,
requires a reason, and shows up in the log and the standup.
Plan new work as a graph
commission apply --schemaWhole task graphs land atomically from one JSON document (commission apply -f plan.json). Use deps so the ready frontier stays accurate, and keep it
narrow — every false dependency serialises work that could have run in parallel.
See planning.
Setting up
bun install
bun test
bun run typecheckBun 1.1 or newer. There is no build step for development: bun run src/cli/index.ts
is the CLI, and bun link puts commission on your PATH from the bin entry in
package.json. bun run build compiles the standalone binary when you want to
test what users actually get.
The layout, and why it is that shape, is architecture.
The short version: src/core/ is the only writer, src/cli/, src/server/, and
src/mcp/ are thin consumers, src/db/ owns storage and migrations,
src/workspace/ prepares where work happens, and src/adapters/ talks to
external systems.
Test conventions
bun test runs everything. The suite is the specification, and four of its
conventions are worth internalising before you write your first test.
Tests are written against the surface a caller meets. tests/version.test.ts
spawns the real CLI and performs a real MCP initialize handshake over stdio
rather than importing the version constant, and says why: “Unit-importing the
constant would prove nothing: the drift being guarded against lives at the call
sites, not in the module.” When the risk is a call site, test the call site.
Every test file opens with what it is defending. Not what it covers — what
would go wrong without it. tests/cli-contract.test.ts opens with “The CLI is
an API: agents parse its output, branch on its exit codes, and act on its
refusals unsupervised.” If you cannot write that sentence, the test is probably
asserting an implementation detail.
A skip states its reason, in the file. The pattern is everywhere: the docs
generator pushes { path, reason } onto a blocked list rather than throwing;
tests/docs.test.ts requires every skipped command and every page routed to
another suite to carry a reason longer than twenty characters. A silent skip lets
a page or an artifact rot invisibly, which is the failure these tests exist to
prevent.
Scratch worlds, never your real database. Tests build a temp directory with
its own COMMISSION_DB, and often a commission shim on PATH so a documented pipeline or
VAR=x commission … prefix runs exactly as written. Nothing in the suite may touch
~/.commission/commission.db.
Where the interesting suites live:
| suite | defends |
|---|---|
tests/core.test.ts | the library surface: transitions, claims, gates, apply, bundles |
tests/cli-contract.test.ts | the CLI as an API — output shape, exit codes, refusal wording |
tests/docs.test.ts | every documented command actually runs; generated pages are current |
tests/version.test.ts | one version, reported identically by CLI, MCP, HTTP, and manifest |
tests/migrations.test.ts | a v1 database walks to current, and the backup restores |
tests/config.test.ts | the config schema and its generated reference agree |
Generated versus written
The rule that matters most. Some pages under docs/ are produced from
src/. Hand-editing one looks like it worked, is reverted by the next generator
run, and in the meantime makes the documentation disagree with the binary. Every
generated page opens with a comment naming its generator; if you see that line,
close the file and edit the source.
bun run generate:docs
bun run generate:configBoth are idempotent, and both take --check so CI can assert the same thing at
the terminal. The drift tests regenerate every artifact in memory and diff it
against disk, which has one consequence worth stating plainly: you cannot
change the CLI, the apply schema, the MCP tool list, or the config schema without
the documentation change landing in the same commit.
Everything else under docs/ is prose. Its authoring conventions — the opening
sentence, the tested command blocks, one definition in one place — are
writing commission’s documentation, and a new page carrying a
```sh block must be registered in that suite or the build fails by
design.
Before you open a change
bun test
bun run typecheck
bun run generate:docs
bun run generate:configIf either generator produces a diff you did not expect, that diff is the documentation change your source change implied. Commit it.
Then close the loop in commission: tick the criteria that are actually met, attach the
evidence the gate asks for, and let commission done check you.
The release process
The full step-by-step is the release checklist, and it is written to be run top to bottom by a human or an agent with no step that says “verify things look right”. The shape of it:
- Preconditions — clean tree, on
main, nothing for this release still in flight incommission board. - Decide the number — from the changelog, under compatibility.md. A schema bump alone does not force a major.
- Green build —
bun test,tsc --noEmit,bun run build, and./dist/commission doctoron a scratch database. - Bump the version in exactly one place — the
versionfield inpackage.json.src/version.tsderives from it and every surface derives from that;tests/version.test.tsfails if a literal appears anywhere else. - Close the changelog section, adding the
Schema version N · config version Mline. - Upgrade rehearsal — this is the step the test suite cannot replace. Take a
database created by the previous release, run
commission migrate --checkagainst a copy, migrate it, confirm the printed backup restores it, and check that any new migration was appended rather than edited in place. - Documentation — regenerate, and reflect any surface change in
compatibility.md. - Tag it. Pushing the tag is what builds and publishes: the workflow builds
every platform binary on its own runner and refuses to continue if any of them
cannot run
initthroughdoneon that platform. See release engineering. - Verify against the published artifact, not your working tree.
- Close the release task with the tag as evidence, and note anything that went wrong. A checklist that never changes is one nobody is following.
Two rules that are not steps. Released migrations are immutable — append,
never edit; a released migration’s text changing is how somebody’s database
becomes unreadable. And the version lives in one place, for the same reason
LATEST_SCHEMA is the migration array’s length: a second copy of a number can
only drift.
The rules that are not negotiable
- Never track status in a markdown file. Query commission. A file that says what is done is a second truth, and the second truth is always the wrong one.
- Never hand-edit a generated page.
- Never fabricate evidence.
- Do not
--forcepast a gate unless a human asked you to. - Nothing points at a public repository. No “view on GitHub”, no “edit this page”, no issue-tracker URL. The repository is private, and a 404 reads as broken rather than deliberate (licensing).
- Nothing is described in the present tense unless it has shipped. Check
positioning.md§8 andcommission show <id>before you write a claim onto a page.
Related
- Writing commission’s documentation — the authoring conventions in full.
- Concepts → architecture — why the source is laid out this way.
- Compatibility — what commission promises not to break, per surface.
- Release checklist — every step, in order.
- Release engineering — what the workflow does and does not guarantee.
Part of Contributing.
This page is docs/contributing/working-with-commission.md in the Commission
repository, rendered in place — the site keeps no copy of it. The repository is private, so there is no edit link to follow.