Skip to content
commission

Enterprise adoption — incremental, and reversible at every stage

You will be able to introduce commission into an organization that already has a system of record, without migrating anything, without asking anyone to stop using Jira, and without a stage you cannot back out of — and answer procurement’s questions about where the data lives, who may write to what, and what the licence permits.

Audience: the person who has to sign off on commission being used at all. Assumes: install, and that Jira (or Linear, or Azure DevOps) is staying.

The premise is narrow and worth stating first: Commission is not replacing your tracker. Your tracker answers “what is the organization committed to, and who is accountable” — a reporting and planning question, asked by people who are not in the repository. Commission answers “what may this agent work on right now, and how do we know it was verified” — an execution question, asked hundreds of times a day by processes. Those are different jobs, and the second one is currently not being done by anything. See positioning.md §2.

Why “reversible” is the first section and not the last

A rollout nobody can back out of is a rollout nobody starts. Every stage below states its exit before it states its benefit, and the exits are real because of how Commission stores things:

  • The data is one SQLite file. Deleting it removes commission from the machine. There is no server holding state, no account to close, no tenant to decommission.
  • commission dump is unconditional and complete. Full JSON, every project, at any stage, free forever — see business model §2 docs/business-model.md.
  • Bindings are opt-in and individually removable. No binding means no interop machinery runs at all.
  • Commission never writes to an external system unattended. Pushes are explicit. Undoing a stage is therefore a matter of stopping, not of repairing.

Stage 0 — one engineer, one repository, nothing bound

What changes. One person installs commission and runs it against a repository they already work in. No Jira credentials, no bindings, no server. Commission is a private execution surface for that person’s agents.

Who has to agree. Nobody. This is the same permission surface as installing any developer tool that writes files under $HOME.

What proves it worked. They stop hand-writing task lists for their agents, and an agent that finishes work cannot close it without attaching the test and commit references. Ask them for commission standup at the end of the week.

The exit. rm -rf ~/.commission. Nothing outside that directory was touched.

Start here even if you are certain you want stage 3. The whole model — refusals, gates, claims, derived views — is legible in an afternoon on one repository, and every later stage assumes people already understand it. The solo founder guide is the walkthrough; it is written for one person, which is what stage 0 is.

Stage 1 — one team, committed configuration, still nothing bound

What changes. The team commits .commission.json at the repository root and declares who is who. Commission now knows which humans exist, which agents exist, and what each may do. Jira is untouched and does not know commission exists.

commission init payments --name "Payments platform"
cat > .commission.json <<'CONFIG'
{
  "$schema": "https://commission.sh/schema/commission-config.schema.json",
  "version": 1,
  "project": "payments",
  "actors": [
    { "name": "priya", "kind": "human", "roles": ["tech-lead", "approver"] },
    { "name": "sam", "kind": "human", "roles": ["security"] },
    { "name": "claude:impl", "kind": "agent", "capabilities": ["implement", "test"] }
  ],
  "execution": {
    "defaultAutonomy": "supervised",
    "requireApproval": [
      { "role": "approver", "kind": "approval", "reason": "the team's existing PR review, recorded as data" }
    ],
    "reviewPolicy": {
      "released": [{ "role": "security", "kind": "verification", "reason": "change control: a named human confirms the rollback was exercised" }]
    }
  },
  "gates": { "shipped": ["pr", "test"], "released": ["pr", "test", "changelog"] },
  "integrations": {
    "jira": { "baseUrl": "https://acme.atlassian.net", "projects": ["PAY"] },
    "github": { "repos": ["acme/payments"], "autoCloseOnMerge": false }
  }
}
CONFIG
commission actors
commission gates
claude:impl          agent  autonomous  may: claim
  can: implement, test
priya                human  autonomous  may: claim, approve, verify
  roles: tech-lead, approver
sam                  human  autonomous  may: claim, approve, verify
  roles: security

Note what the integrations block does at this stage: nothing. It declares what this project is allowed to bind to later. Writing it now, in the same review as everything else, is how the allowlist gets read by the people who care about it rather than added under time pressure in stage 2.

Who has to agree. Whoever reviews changes to the repository. .commission.json is code and goes through code review.

What proves it worked. commission inbox is short and the team stops asking each other what state something is in.

The exit. Delete the file, delete the database. The repository is byte- identical to before.

Who owns the configuration

Three layers, and the split is a rule rather than a habit:

layerfileownscommitted
file.commission.jsonanything that constrains other people: actors, roles, autonomy, approval routing, gates, integration allowlistsyes
local.commission.local.jsonone machine’s preferences: lease length, workspace strategy, context budgetnever
envCOMMISSION_*one session: COMMISSION_ACTOR, COMMISSION_DB, credentialsn/a

Higher layers win, and .commission.local.json cannot declare project — a laptop cannot quietly re-point a repository at a different graph. When someone asks why a setting is what it is, the answer is a command rather than an investigation:

commission config explain execution.defaultAutonomy
execution.defaultAutonomy = "supervised"
  set by: file (.commission.json)
  overrode: defaults = "autonomous"
  precedence: defaults < db < file < local < env < flags

Two practical rules. Put .commission.json under CODEOWNERS alongside the CI configuration — it is the same class of file, and for the same reason. And put .commission.local.json in .gitignore on day one, because the first time it is committed it will be committed with someone’s lease preference and stay there for a year.

The full key list is Reference → config; worked examples are config examples.

How approvals map to the review process you already have

This is the question that decides whether an organization adopts commission, so it gets its own section rather than a bullet in a stage.

Commission does not replace code review. The pull request still happens, in GitHub, reviewed by people, under whatever rules you already enforce. What commission adds is that the outcome of that review becomes a fact the system can check, rather than a state of mind that someone remembers to act on.

Three mechanisms, mapping onto three things you probably already do:

you already havecommission mechanismwhat it does
“a PR must be merged, CI must be green”gate + evidencedone is refused until the required evidence kinds are attached
“a senior engineer signs off”approval (requireApproval by role)a named human accepts the work; no agent can satisfy it and --force cannot override it
“security/QA confirms something is actually true”verificationthe sibling of approval: a human confirming a fact, not expressing a preference

The distinction between approval and verification is not decoration. “I am happy with this” and “I ran the rollback and it worked” are different claims, they are made by different people, and an audit that cannot tell them apart is not an audit.

In practice an agent finishes the work, attaches its evidence, and is refused:

commission add "Rotate the card-vault signing key" -c "old key revoked" --gate released
COMMISSION_ACTOR=claude:impl commission start payments-1
COMMISSION_ACTOR=claude:impl commission check payments-1 0
COMMISSION_ACTOR=claude:impl commission evidence payments-1 pr=https://github.com/acme/payments/pull/812 test=ci-4471 changelog=CHANGELOG.md
COMMISSION_ACTOR=claude:impl commission done payments-1
cannot complete payments-1: 3 outstanding approval(s)
  missing: approval from a human — autonomy is supervised, so a human must accept the work
  missing: approval from anyone with the 'approver' role — the team's existing PR review, recorded as data
  missing: verification from anyone with the 'security' role — change control: a named human confirms the rollback was exercised
hint: a person has to accept this — priya or sam: COMMISSION_ACTOR=priya commission approve payments-1 -m "<why it is acceptable>"

Each missing item carries the reason from the configuration, so the requirement explains itself to the person who meets it. The agent puts the work up for review, and the humans see it in the one place they look:

COMMISSION_ACTOR=claude:impl commission review payments-1
commission inbox --all
1. [approve] payments-1 · Rotate the card-vault signing key
   what       an agent finished it and put it up for review; 3 outstanding approvals
   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 payments-1 -m "<why it is acceptable>"

commission review is what puts an item in the inbox, and nothing tells the agent to run it — the refusal names commission approve, which the agent cannot run, and commission prime does not connect review to approvals. An agent that meets the refusal and simply stops therefore leaves work that is finished, unaccepted, and invisible. Put the rule in your agent runbooks explicitly, and have whoever owns the queue read commission inbox --all rather than only their own.

COMMISSION_ACTOR=priya commission approve payments-1 -m "Reviewed PR 812; key rotation is behind a feature flag."
COMMISSION_ACTOR=sam commission verify payments-1 -m "Ran the rollback in staging against a production snapshot."
COMMISSION_ACTOR=claude:impl commission done payments-1

Three properties worth taking to whoever owns your change process:

  • An agent cannot approve. Commission treats any actor with COMMISSION_ACTOR set as a process, and refuses human judgement from it. The conservative direction is deliberate — a wrongly-declared human dissolves the boundary the whole mechanism exists to hold.
  • --force cannot override an approval. It overrides commission’s own checks — unchecked criteria, missing evidence — with a mandatory reason that is logged. It has never overridden a person’s sign-off.
  • An approval is bound to the work it accepted. Edit the task afterwards and the approval goes stale, rather than silently carrying forward onto changed work.

Details and the full refusal catalogue: execution policies.

Stage 2 — bind a deliberate subset, pull only

What changes. A named set of Jira issues — one team, one epic, one sprint — is bound to commission tasks. Commission observes them; Jira remains the system of record and nothing is written back. Divergences are recorded and surfaced, not resolved.

commission bind payments-1 --jira PAY-4412
commission sync
commission serve --sync 5m

Credentials come from the environment (JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN) and are never written to the database or to .commission.json. The committed file holds the site URL, the custom-field ids, and the key-prefix allowlist — the things that are configuration, not secrets.

The allowlist is enforced, not advisory: a project that has not declared a Jira site, a repository, or a key prefix cannot bind to it, and a mismatch between JIRA_BASE_URL and the declared site is refused on observe, push, and import. One project can never write to another project’s systems.

Who has to agree. Whoever owns the Jira project, and whoever issues API tokens. Ask for a token scoped to the smallest possible set of projects; commission never needs more than read access at this stage.

What proves it worked. commission sync reports divergences that are real — a Jira status claiming “In Progress” for work whose PR merged last Tuesday. That list is the value of the stage: it is the drift you already had and could not see.

The exit. commission unbind <id> on each binding, or stop running commission sync. Jira has no record that any of it happened, because nothing was written.

Expect a per-instance configuration pass. “Works with Jira” is never generic — every instance is a snowflake of custom fields, workflows, and status names, and the adapter is configurable precisely because it has to be. See interop for the honest caveat and the field mapping.

Stage 3 — supervised outbound writes

What changes. Commission starts proposing changes to Jira. It still does not make them unattended.

commission sync --plan
commission sync --push

--plan emits the outbound plan as JSON for a human to read or an agent to execute through its own credentials. --push has commission make the transitions itself. Both are explicit invocations; the background poller (commission serve --sync 5m) is pull-only and logs plans it will never execute.

Two rules keep this from becoming a synchronization mess:

  • Signals beat claims. Observable pull-request reality sets commission’s status. A Jira status field is a claim, and auto-applies only where Commission has not been moved by an agent.
  • Plans compare meaning, not names. Same-category workflow states — Triaged, Groomed, Awaiting QA — are the external system’s business and are left alone.

Who has to agree. Whoever is accountable for Jira hygiene, since Commission is now a writer. Run stage 3 with --plan only for two weeks before enabling --push; the plans are readable and the disagreement surfaces early.

What proves it worked. The Jira board stops being wrong without anyone updating it by hand.

The exit. Stop passing --push. You are back at stage 2 with no cleanup, because everything commission wrote is an ordinary Jira transition attributed to the token’s user.

Stage 4 — the team’s default execution surface

What changes. New work for that team is planned in commission and reflected outward for the people who need it in Jira. Agents get their work from commission next --claim; humans get theirs from commission inbox. Jira stays the system of record for the organization’s commitments.

Who has to agree. The team, and whoever reads the reports. Nobody else’s workflow changed.

What proves it worked. Two numbers: how much of the team’s completed work has evidence attached, and how long the inbox is. If the second is growing, the autonomy settings are wrong — not the tool.

The exit. commission dump > payments.json and commission export > STATUS.md. Every bound issue’s state is already in Jira, which is the point of having kept it there. The team goes back to working the Jira board directly, with a JSON archive of the execution history nobody else was recording anyway.

Do not run stages 2–4 forever and call it done. Two systems that both believe they are authoritative is worse than either alone. Either Commission is the execution layer and Jira is the reporting surface, or you finish the migration and stop syncing. The bridge is a bridge.

Security posture

Written for the person who has to fill in a questionnaire.

Where the data is

One SQLite file, on the machine that runs commission: ~/.commission/commission.db by default, COMMISSION_DB to move it. WAL journaling, so readers never block the writer. There is no commission-operated service, no account, no telemetry, no licence check, and no phone-home — a machine with no network runs the entire product. Data residency is “wherever you put the file”, and backup is copying it.

Schema migrations ship inside the binary and run on open, each step in its own transaction. A database written by a newer Commission is refused rather than guessed at, and any database holding data is copied before the first migration with the restore command printed. See upgrades.

Who can talk to it

surfaceauthenticationnotes
CLIthe OS userwhoever can read the file can read the graph
MCP (commission mcp)stdio, local processno network listener
HTTP (commission serve)COMMISSION_TOKEN bearer, mutations onlyreads are unauthenticated
web viewthe same COMMISSION_TOKEN rule, as an HttpOnly SameSite=Strict cookie holding a SHA-256 of the tokena browser form cannot send a bearer header; reads never need it

The honest limitation is in that table: COMMISSION_TOKEN gates writes, not reads. A commission serve exposed beyond localhost is a readable board for anyone who can reach the port. Treat the port as internal, put your own proxy in front of it if it must be shared, and do not put a secret in a task body on the assumption that the web view is private.

Human judgement over HTTP is safe for a narrower reason than it looks: approve resolves the actor from the server process, never from the request, so a caller cannot name itself into a person.

Secrets

Commission stores none. The workspace layer exists to put environment variables in front of a task’s work, and its provider contract deliberately has no field for a value: a provider that materializes secrets writes them to a file and reports the path and the key names. Values never enter a workspace descriptor, so they cannot reach --json, the event log, or the persisted record. Hook output is masked on the same principle.

External credentials — Jira, GitHub — are read from the environment at the moment of use. They are not stored in the database, and the committed configuration holds only URLs, field ids, and allowlists.

The residual risk is the one every tracker has: a task body is stored in plaintext, and someone will eventually paste a key into one. The database is a file with file permissions; treat it as you treat a .env.

What is attributable

Every claim, transition, note, evidence attachment, approval, question, and answer is an event with an actor and a timestamp, appended to a log that is never rewritten. --force requires a reason and is recorded as an override. Reopening a task destroys nothing. “Who did this, under what authority, and how do we know it was verified” is a query, not an investigation:

commission log --last 20
commission board

Licence and supply chain

Commission is proprietary. The repository is private, all rights reserved, and distribution is by compiled binary under a commercial agreement — see LICENSE LICENSE and licensing. It is not open source and not source-available, so a source-code review is a contractual conversation rather than a link.

What a security team can inspect without one: the binary and its behaviour, the SQLite file (an open, documented format — commission dump renders it as JSON), the HTTP surface, and the network traffic, of which there is none unless you configure an integration.

Being free to use is a separate claim from being open source. Commission makes the first and not the second: the local product is free and unlimited, with no account and no cap on agents or concurrency (business model §2 docs/business-model.md).

What to say to the four people who will ask

  • The engineering manager: nothing about your Jira process changes at any stage. What changes is that “done” becomes checkable and agent work becomes attributable.
  • The security reviewer: local file, no network by default, secrets never stored, every action attributed, append-only log. The read side of the HTTP surface is unauthenticated; keep the port internal.
  • Procurement: proprietary licence, binary distribution, no hosted component today, complete data export at any moment.
  • The engineer who thinks this is more process: it is less. There is no status to update, no board to groom, and no estimate to give. The only thing Commission makes you do that you were not doing is attach the evidence you already produced.

The whole sequence

commission init payments --name "Payments platform"
commission actors
commission gates
commission config explain execution.defaultAutonomy
commission add "Rotate the card-vault signing key" -c "old key revoked" --gate released
COMMISSION_ACTOR=claude:impl commission start payments-1
COMMISSION_ACTOR=claude:impl commission check payments-1 0
COMMISSION_ACTOR=claude:impl commission evidence payments-1 pr=https://github.com/acme/payments/pull/812 test=ci-4471 changelog=CHANGELOG.md
COMMISSION_ACTOR=claude:impl commission done payments-1
COMMISSION_ACTOR=claude:impl commission review payments-1
commission inbox --all
COMMISSION_ACTOR=priya commission approve payments-1 -m "Reviewed PR 812; key rotation is behind a feature flag."
COMMISSION_ACTOR=sam commission verify payments-1 -m "Ran the rollback in staging against a production snapshot."
COMMISSION_ACTOR=claude:impl commission done payments-1
commission log --last 20

The commands on this page that do not need a live Jira site, a GitHub token, or a long-running server are executed by tests/docs.test.ts against a scratch database. The ones that do are named in that test with the reason they are skipped, and are checked against the live command tree so a renamed flag still fails the suite.

  • Interop — bindings, divergences, and the per-instance Jira caveat.
  • Migration — if you are leaving the tracker rather than living beside it.
  • Execution policies — autonomy, eligibility, and approval as data.
  • Upgrades — migrating a database that holds real work.
  • Architecture — why the security posture is a consequence of the storage decisions rather than a feature.

Part of Guides.

This page is docs/guides/enterprise.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.