Skip to content
commission

Your first task

You will be able to create a project, plan a small graph, claim a task, be refused when you try to close it, satisfy the refusal, and close it for real — in about five minutes, on a repository you already have.

Assumes: Commission is installed and COMMISSION_ACTOR is set.

The refusal in the middle is the point of this page. A tour that only shows the happy path teaches the wrong model of commission: it hides that completion is a checked fact rather than an assertion.

1. Create the project

From the root of the repository you want to track:

commission init myapp --name "My App"
created project myapp (My App)
this repo is bound to it — bare commission commands target 'myapp' here

next:
  commission apply -f plan.json    create a whole task graph at once
  commission add "..."             or one task to start with
  commission next --claim          what to work on, claimed atomically

That wrote a .commission.json at the repository root:

{
  "$schema": "https://commission.sh/schema/commission-config.schema.json",
  "version": 1,
  "project": "myapp"
}

Three keys, and only one of them is about you. Every Commission command run anywhere inside this repository now resolves the project by walking up to that file, so agents never have to be told which project they are in. Commit it.

2. Define a gate

A gate names the evidence a task must carry before Commission will let it close. Gates are data, not process documentation:

commission gates --set shipped=pr,test
shipped: pr, test

A task tagged gate: shipped cannot reach done without a pr and a test evidence record attached. Nothing enforces what those references mean — commission checks that you attached them, and the event log records who did.

3. Plan a small graph

One task is not interesting; the shape of the work is. Write a plan document:

cat > plan.json <<'PLAN'
{
  "project": "myapp",
  "tasks": [
    { "key": "schema", "title": "Design the events table",
      "criteria": ["migration reviewed", "indexes justified"],
      "touches": ["src/db"] },
    { "key": "ingest", "title": "Webhook ingest endpoint",
      "deps": ["schema"], "gate": "shipped", "touches": ["src/http"],
      "criteria": ["signature verified", "replays rejected"] },
    { "key": "feed", "title": "Event feed in the web view",
      "deps": ["schema"], "touches": ["src/web"] }
  ]
}
PLAN
commission apply -f plan.json
applied to 'myapp': 3 created, 0 updated
  + myapp-1  (schema)
  + myapp-2  (ingest)
  + myapp-3  (feed)

apply is atomic: the local keys resolve to real ids inside one transaction, so a plan that names an undefined gate or a missing dependency creates nothing and tells you which line was wrong. Re-applying the same document upserts by key rather than duplicating — the plan file can live in the repo and grow. Every field is in the apply reference.

touches is a free-text label for the area of the codebase a task will edit. Commission never interprets it; it only uses it to work out which ready tasks can be dispatched to different agents at the same time without colliding.

4. See the frontier, not the backlog

commission ready
ready frontier (dispatch independent tasks in parallel):
  myapp-1 · Design the events table  [open · p2]

Two of the three tasks exist and are not shown, because they depend on the first. Blocked is derived, never set — there is no blocked status to forget to update, and no way for the board to disagree with the graph.

5. Claim it

commission next --claim
claimed myapp-1
routing: blaze is holding it; autonomy autonomous (default); no actors are declared, so nothing is restricted

myapp-1 · Design the events table  [open · p2]
project: My App

criteria:
  [ ] 0. migration reviewed
  [ ] 1. indexes justified
blocks: myapp-2, myapp-3

next:
  commission start myapp-1
  commission note myapp-1 -m "<progress>"

One command selected the task, claimed it atomically under a lease, and printed the whole context bundle — body, criteria, dependency state, linked documents, recent notes, and the commands that come next. A fresh session resumes from this and nothing else. Run it from two shells with different COMMISSION_ACTOR values and each gets a different task; see parallel work.

Move it into flight and leave a breadcrumb:

commission start myapp-1
commission note myapp-1 -m "partial index on (project_id, ts) — full index was 4x the size"

Notes are for the next session, which is often you on Monday. Decisions, dead ends, and discoveries; not a progress bar.

6. Be refused

commission done myapp-1
cannot complete myapp-1: 2 unchecked criteria
  missing: criterion 0: migration reviewed
  missing: criterion 1: indexes justified
hint: tick each with 'commission check myapp-1 0', 'commission check myapp-1 1' — only once it is actually true; or --force to override (logged)

Exit code 2. That is not a crash and not a failure — it is commission declining an action it understood, naming what is missing and the exact command that fixes it. An agent reads that hint and acts on it without a human. See exit codes for the full contract, including the --json shape of the same refusal.

7. Satisfy it, and close

commission check myapp-1 0
commission check myapp-1 1
commission done myapp-1
myapp-1 criterion 0 ticked; 1 remaining
myapp-1 criterion 1 ticked; 0 remaining
myapp-1: in_progress → done
next task: commission next --claim

Tick a criterion when it is actually met. Nothing checks that you were honest — but the event log records when you ticked it and what you had attached at the time, which is a far more useful artifact than a status field nobody trusts.

myapp-2 carries gate: shipped, so it will refuse a second time, for a different reason, until evidence is attached:

commission evidence myapp-2 pr=https://github.com/acme/myapp/pull/14 test=ci-2211

8. Look at where you are

commission board
commission log --last 5
My App (myapp) — 1/3 done, 2 open

ready:
  myapp-2 · Webhook ingest endpoint  [open · p2 · gate:shipped]
  myapp-3 · Event feed in the web view  [open · p2]

recently done:
  myapp-1 · Design the events table  (2026-07-27 14:52)

The board is a query, not a record. So are ready, standup, export, and blocked state. There is nothing to keep in sync, which is why drift is structurally impossible rather than merely discouraged.

The whole sequence

commission init myapp --name "My App"
commission gates --set shipped=pr,test
commission apply -f plan.json
commission ready
commission next --claim
commission start myapp-1
commission note myapp-1 -m "partial index on (project_id, ts) — full index was 4x the size"
commission done myapp-1              # refused: 2 unchecked criteria
commission check myapp-1 0
commission check myapp-1 1
commission done myapp-1              # closes
commission board

Every command on this page is executed by tests/docs.test.ts against a scratch database.

Next


Part of Start here.

This page is docs/start/first-task.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.