Solo founder — install to "here are this quarter's deliverables"
You will be able to take a repository you already have, turn a quarter’s worth of intent into a task graph, run several agents against it at once, answer only the questions that are genuinely yours, and end the week with a derived list of what actually shipped — without keeping any of it in your head.
Audience: one person, several agents, no process. Assumes: install and your first task. Skip: approvals-at-scale, roles, org policy — see enterprise adoption if that is your world.
Every command below was run, in this order, against a real git repository — a small double-entry ledger service — and the transcripts on this page are that run’s output, copied verbatim. Where something went wrong, it is on the page, because the wrong turns are the part you will actually hit.
The shape of the week
| you do | commission does |
|---|---|
| say what the product is | stores it once, and puts it in every agent’s context |
| write the graph | derives what is ready, what is blocked, what can run together |
| fan agents out | hands each one a distinct task, atomically |
| answer questions, approve what you asked to see | refuses completion until the evidence exists |
| read one command | derives the deliverables from what happened |
Nothing on the left is administration. There is no board to groom and no status to update, because status is not a thing you write.
1. Bind the repository to a project
Run this at the root of the repository the work happens in. commission init writes
.commission.json, and from then on every bare commission command in this tree targets
this project — you never pass --project again.
commission init ledger --name "Ledger"
commission vision --set "A double-entry ledger service that never loses a cent. Money is integer minor units; the journal is append-only; every balance is derived from it and none is stored."
commission gates --set shipped=test,commitThe vision is not decoration. It is stored on the project and injected into every context bundle, which means a fresh agent session six weeks from now argues from your principles instead of inventing its own. Write the three or four sentences that settle design arguments in advance.
The gate is the evidence class your work belongs to. shipped=test,commit
means a task carrying that gate cannot close until a test reference and a commit
reference are attached. Define it now: commission init seeds no gate profile, so the
first apply that names one is otherwise refused with “project has no gate
profiles”.
2. Write the quarter as a graph, not a list
An agent writes this better than you do. commission define ledger prints a brief —
interrogate the idea, write the vision, design the graph, dry-run it — that you
hand to a coding agent along with commission apply --schema. What comes back is one
JSON document:
cat > plan.json <<'PLAN'
{ "project": "ledger", "tasks": [
{ "key": "money", "title": "Exact money arithmetic in minor units", "gate": "shipped",
"touches": ["src/money.ts"],
"criteria": ["cents(1.005) returns 101", "no float arithmetic remains in src/money.ts"] },
{ "key": "journal", "title": "Append-only journal with balanced entries", "gate": "shipped",
"deps": ["money"], "touches": ["src/journal.ts"],
"criteria": ["an unbalanced entry is rejected", "posted entries are frozen"] },
{ "key": "api", "title": "HTTP API for posting and reading entries", "gate": "shipped",
"deps": ["journal"], "touches": ["src/api.ts"],
"criteria": ["POST /entries returns 422 when debits != credits"] },
{ "key": "reconcile", "title": "Reconciliation report by account", "gate": "shipped",
"deps": ["journal"], "touches": ["src/reconcile.ts"],
"criteria": ["balances are derived from the journal, never stored"] },
{ "key": "docs", "title": "Bookkeeper-facing README", "deps": ["api", "reconcile"],
"touches": ["README.md"],
"criteria": ["a bookkeeper can post and reconcile one entry from the README alone"] } ] }
PLAN
commission apply --dry-run -f plan.json
commission apply -f plan.json--dry-run writes nothing and prints exactly what landing it would do. The real
apply is one transaction: a plan naming an undefined gate or a missing dependency
creates nothing, so there is never a half-landed graph to clean up.
applied to 'ledger': 5 created, 0 updated
+ ledger-1 (money)
+ ledger-2 (journal)
+ ledger-3 (api)
+ ledger-4 (reconcile)
+ ledger-5 (docs)The full document format is Reference → apply; the design rules are planning.
3. Check the frontier before you dispatch — this is where it went wrong
commission readyready frontier (dispatch independent tasks in parallel):
ledger-1 · Exact money arithmetic in minor units [open · p2 · gate:shipped]One task. Five tasks planned, five agents available, and a frontier of one.
That plan is a pipeline: everything hangs off money, and docs waits on both
api and reconcile. Fanning agents out against it would have produced four
idle sessions and one working one.
Two moves fix it, and both are worth doing before any agent starts.
Cut the dependencies that were preference, not order. The README was made to wait on the API and the reconciler because it felt later. It is not: a bookkeeper-facing README can be written against the design, and the criterion — “a bookkeeper can post and reconcile one entry from the README alone” — is what catches it if the design changes underneath.
commission undep ledger-5 --on ledger-3
commission undep ledger-5 --on ledger-4Use undep rather than editing plan.json and re-applying. commission apply is
additive for dependencies: re-applying a document with a shorter deps list
updates every other field in place but leaves the dropped edge exactly where it
was, and the frontier does not widen. Discovered the hard way on this walk; the
upsert-by-key behaviour documented in planning is about fields,
not edges.
Add the work that was genuinely independent all along. The chart of accounts touches nothing else in the graph, so it never needed to be in the pipeline:
cat > accounts.json <<'PLAN'
{ "project": "ledger", "tasks": [
{ "key": "accounts", "title": "Chart of accounts loader", "gate": "shipped",
"touches": ["src/accounts.ts"],
"criteria": ["an unknown account code is rejected at load time"] } ] }
PLAN
commission apply -f accounts.json
commission readyready frontier (dispatch independent tasks in parallel):
ledger-1 · Exact money arithmetic in minor units [open · p2 · gate:shipped]
ledger-5 · Bookkeeper-facing README [open · p2]
ledger-6 · Chart of accounts loader [open · p2 · gate:shipped]
safe to fan out together (no touches overlap): ledger-1, ledger-5, ledger-6Three wide, and commission says which three are safe together because their touches
globs do not overlap. That last line is advisory, not a lock — see
parallel work for exactly how much it promises.
4. Declare yourself a human before you need to be one
This is the step that is easy to skip and expensive to skip.
Commission decides whether an actor is a person conservatively: anything with
COMMISSION_ACTOR set is treated as an agent, because a process that could name
itself into a human could approve its own work.
That has a consequence worth catching before it catches you. Run commission init
from an ordinary shell and it declares you on the way past — “declared you
(blaze) as the human who approves work here” — writing an actors block with
your OS username. Run it with COMMISSION_ACTOR exported, which is what
install tells you to do and what every agent session does,
and commission cannot tell a person from a process, so it declares nobody. The config
it writes is two keys, and the first time an agent escalates a decision to you,
you get this:
blaze cannot answer ledger-6: answering is a human judgement
missing: a human actor
hint: no humans are declared on this project — add one under "actors" in .commission.json, then: COMMISSION_ACTOR=<their-name> commission answer ledger-6 -m "<the decision, and why>"The refusal is correct and it names the fix, but there is no reason to meet it
mid-flow. Declare the whole cast up front — you, and the agent names you intend
to run. This replaces whatever commission init wrote, and it is the file you would
have ended up with anyway once a second agent existed:
cat > .commission.json <<'CONFIG'
{
"$schema": "https://commission.sh/schema/commission-config.schema.json",
"version": 1,
"project": "ledger",
"actors": [
{ "name": "blaze", "kind": "human", "roles": ["owner"], "default": true },
{ "name": "agent:a", "kind": "agent", "capabilities": ["implement", "test"] },
{ "name": "agent:b", "kind": "agent", "capabilities": ["implement", "test"] }
]
}
CONFIG
commission actorsagent:a agent autonomous may: claim
can: implement, test
agent:b agent autonomous may: claim
can: implement, test
blaze human autonomous may: claim, approve, verify
roles: ownermay: claim, approve, verify on your line is the thing you came for. This file
is committed, so the answer to “who may accept this work” travels with the
repository rather than living in one machine’s environment. Every key is in
Reference → config.
5. Fan the agents out
Each agent session exports its own COMMISSION_ACTOR and asks for work. The claim is
atomic, so it does not matter whether they run a second apart or the same
millisecond:
COMMISSION_ACTOR=agent:a commission next --claim
COMMISSION_ACTOR=agent:b commission next --claimRun genuinely concurrently — two shells, same instant — the loser of the race is told so and takes the next task instead of colliding:
claimed ledger-5
skipped: ledger-1 (claimed concurrently by another agent)What each agent gets back is not a task id. It is the whole context bundle: the body, the vision, the criteria, what this task blocks, the gate it must satisfy, prior notes, and the commands that finish it from here. That is the property that makes a fresh session cheap — one command, no re-briefing.
In practice you do not type these two lines; you start two coding-agent sessions
whose CLAUDE.md contains commission prime output, and they run this themselves.
See your first agent.
6. What an agent’s task looks like from the inside
The agent claims, starts, writes the code, runs the tests, commits — and then meets the gate:
COMMISSION_ACTOR=agent:a commission start ledger-1
COMMISSION_ACTOR=agent:a commission note ledger-1 -m "Math.round on a float was the bug: 1.005 * 100 is 100.49999999999999. Parsing the decimal string into thousandths and rounding half-up there keeps it exact."
COMMISSION_ACTOR=agent:a commission done ledger-1cannot complete ledger-1: 2 unchecked criteria; gate 'shipped' missing evidence [test, commit]
missing: criterion 0: cents(1.005) returns 101
missing: criterion 1: no float arithmetic remains in src/money.ts
missing: evidence.test
missing: evidence.commit
hint: tick each with 'commission check ledger-1 0', 'commission check ledger-1 1' — only once it is actually true; attach with 'commission evidence ledger-1 test=<ref> commit=<ref>'; or --force to override (logged)Exit code 2, and the message is a to-do list. The agent satisfies it and closes:
COMMISSION_ACTOR=agent:a commission check ledger-1 0
COMMISSION_ACTOR=agent:a commission check ledger-1 1
COMMISSION_ACTOR=agent:a commission evidence ledger-1 test="bun test — 1 pass, 0 fail" commit=6feaa66
COMMISSION_ACTOR=agent:a commission done ledger-1The note is the part you cannot buy back later. Six weeks on, “why is this parsing a string instead of multiplying” is answered by the task itself rather than by re-deriving the floating-point bug from scratch.
7. Answer only what is actually yours
An agent that hits a judgement call escalates instead of guessing:
COMMISSION_ACTOR=agent:b commission ask ledger-5 -m "The sample books use both Accounts Receivable and Trade Debtors. Should the README teach one name or both?" --options "one name,both names" --blocking--blocking parks the task: no agent may work it until it is answered, which is
better than an agent picking a house style you disagree with three files later.
--options is a single comma-separated list, so a choice whose text contains a
comma silently becomes two choices — keep them short.
Your side of it is one command, and it is the only queue you have:
commission inbox1 thing needs your judgment in ledger — 1 escalated decision
scoped to blaze (--all shows every actor's) · 0 in flight · 2 ready to pick up
1. [decide] ledger-5 · Bookkeeper-facing README
just now
what agent:b asked: "The sample books use both Accounts Receivable and Trade Debtors. Should the README teach one name or both?" (one name / both names)
needs you no agent may work ledger-5 until this is decided — and deciding it is not theirs to do
if ignored ledger-5 stays parked
→ commission answer ledger-5 -m "<the decision, and why>"Every item states what it is, why it needs you specifically, what happens if you ignore it, and the one command that clears it. Answer it and the agents move:
commission answer ledger-5 -m "One name: Accounts Receivable. Trade Debtors is the UK synonym and the loader aliases it, so the README teaches the canonical name only."The answer is recorded on the task and appears in every later context bundle as a decision. It is not a Slack message that scrolls away.
8. Watch the one thing you actually want to see
You do not want to review everything, and reviewing nothing is how something lands that you would have vetoed. Mark the tasks you want a look at, and only those:
commission edit ledger-6 --autonomy supervisedThe agent works it exactly as before, and is refused at the end:
COMMISSION_ACTOR=agent:a commission claim ledger-6
COMMISSION_ACTOR=agent:a commission start ledger-6
COMMISSION_ACTOR=agent:a commission check ledger-6 0
COMMISSION_ACTOR=agent:a commission evidence ledger-6 test="bun test — 3 pass, 0 fail" commit=1d0a4f2
COMMISSION_ACTOR=agent:a commission done ledger-6cannot complete ledger-6: 1 outstanding approval(s)
missing: approval from a human — autonomy is supervised, so a human must accept the work
hint: a person has to accept this — blaze: COMMISSION_ACTOR=blaze commission approve ledger-6 -m "<why it is acceptable>"The agent must put it up for review, or you will not see it. This walk found
the gap the hard way: at the moment of that refusal, commission inbox said nothing
needs you. The approval item is keyed on the task being in_review, so an agent
that meets the refusal and stops leaves the work invisible to the only person who
can release it.
Nothing currently closes that loop for you. The refusal names commission approve — a
command the agent cannot run — and commission prime, the operating manual agents are
handed, explains approvals without mentioning review in connection with them.
Until it does, put one line in your own agent instructions: if done is refused
for an approval, run commission review <id> and stop.
COMMISSION_ACTOR=agent:a commission review ledger-6
commission inbox1 thing needs your judgment in ledger — 1 approval
scoped to blaze (--all shows every actor's) · 0 in flight · 1 ready to pick up
1. [approve] ledger-6 · Chart of accounts loader
just now
what an agent finished it and put it up for review; 1 outstanding approval
needs you autonomy is supervised, so a human must accept the work; no agent can satisfy it
if ignored it stays finished but unaccepted, and cannot close
→ commission approve ledger-6 -m "<why it is acceptable>"commission approve ledger-6 -m "Read the diff: unknown codes throw at load, and the UK alias resolves to 1100. Ship it."
COMMISSION_ACTOR=agent:a commission done ledger-6An approval is a separate fact from technical completion, stored against the
version of the work you accepted, and --force cannot substitute for it. An
agent that could force past a human approval would make “human approval” a naming
convention. See execution policies.
9. Here are this quarter’s deliverables
Three reads, no reporting:
commission board
commission standup
commission export > DELIVERABLES.mdboard is your position — in flight, ready, blocked, recently done. standup is
the same truth as prose, for the call where someone asks how it is going:
what to say (covers since Friday 7:00 AM):
Since Friday 7:00 AM we shipped 2 things: Chart of accounts loader and Exact money arithmetic in minor units.
Blocked: HTTP API for posting and reading entries — waiting on Append-only journal with balanced entries (open).
Next up: Append-only journal with balanced entries.export writes a git-committable markdown snapshot — the artifact you send to an
investor, a customer, or your future self:
# Ledger — status
`2/6` done · 2 ready · 2 blocked · generated 2026-07-27T16:30Z
## Done (last 7 days)
- **ledger-6** Chart of accounts loader (just now)
- **ledger-1** Exact money arithmetic in minor units (just now)It opens with DO NOT EDIT, and it means it: the database is the truth and this
file is a derivation of it. Commit it if you like the diff; never edit it, and
never let it become the place you look.
To catch up on a morning you missed, read the log forward instead:
commission log --last 52026-07-27 16:30 agent:a ledger-6 evidence: test=bun test — 3 pass, 0 fail, commit=1d0a4f2
2026-07-27 16:30 blaze ledger-6 approval: {"kind":"approval","by":"blaze","note":"Read the diff: unknown codes throw at load, and the UK alias resolves to 1100. Ship it.","remaining":0}
2026-07-27 16:30 agent:a ledger-6 transition: in_review→done
next cursor: 28 (commission log --after 28)Append-only, with a cursor, so “what happened since I last looked” is a real question with an exact answer.
Habits that survive the first month
- Keep the frontier wide. Run
commission readyafter every plan change. If it shows one item, you have written a queue, and the agents will run one at a time no matter how many you start. - Mark supervised sparingly. Two or three tasks a quarter — the public surface, the migration, the thing customers see. Marking everything supervised rebuilds the review bottleneck you left a job to escape.
- Notes over memory. A note costs eight seconds and buys back the hour spent
re-deriving a decision. It is also what
commission searchfinds. - Never edit an exported file. The database is the truth; everything else is a view. See architecture.
- Let the refusals teach the agents. Exit code 2 always names the fixing command. An agent that reads them needs no process documentation from you.
The whole sequence
commission init ledger --name "Ledger"
commission gates --set shipped=test,commit
commission apply -f plan.json
commission ready
commission undep ledger-5 --on ledger-3
commission undep ledger-5 --on ledger-4
commission actors
COMMISSION_ACTOR=agent:a commission next --claim
COMMISSION_ACTOR=agent:a commission start ledger-1
COMMISSION_ACTOR=agent:a commission check ledger-1 0
COMMISSION_ACTOR=agent:a commission evidence ledger-1 test="bun test — 1 pass, 0 fail" commit=6feaa66
COMMISSION_ACTOR=agent:a commission done ledger-1
commission inbox
commission answer ledger-5 -m "One name: Accounts Receivable. Trade Debtors is the UK synonym and the loader aliases it, so the README teaches the canonical name only."
commission edit ledger-6 --autonomy supervised
COMMISSION_ACTOR=agent:a commission review ledger-6
commission approve ledger-6 -m "Read the diff: unknown codes throw at load, and the UK alias resolves to 1100. Ship it."
commission board
commission export > DELIVERABLES.mdEvery command on this page is executed by tests/docs.test.ts against a scratch
database in a real git repository, in this order.
Related
- Planning — designing the graph, and why the frontier stays wide.
- Parallel work —
touches, batches, and what “safe to fan out” promises. - Task lifecycle — every transition and every refusal.
- Workspaces — when two agents need two checkouts and two ports.
- Enterprise adoption — the same product where other people have opinions.
Part of Guides.
This page is docs/guides/solo-founder.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.