Documentation

Install it, run a task, read the evidence. Everything on this page is what the CLI actually does — no layer between you and the commands.

Quickstart

Six steps from setup to a reviewed task. Any git repo, macOS or Linux.

1

Install

Homebrew, or direct downloads for macOS and Linux.

$ brew install runselvage/selvage/selvage
2

Set up the repo

init opens a guided setup in the dashboard — detect Claude, Kiro, and Codex, choose an implementer and an independent reviewer, and pick the checks that gate the work. Each agent has a Test connection button that validates it live: installed → authenticated → responds to a real prompt, reporting the first thing that’s wrong. Saving writes .selvage/config.yaml. Prefer the terminal? selvage init --cli.

$ cd your-repo
$ selvage init
3

Trust the config

Config is untrusted input. You approve its digest once; if the config changes later, you’re asked to re-trust before it takes effect.

$ selvage trust
4

Start the pipeline

start validates each configured adapter with a live prompt and connects it to the daemon. Do this before your first run — a task submitted with no connected adapters waits at ready until one comes online. Check anytime with selvage nodes; if it’s empty, run start.

$ selvage start
$ selvage nodes # confirm implementer + reviewer are connected
5

Run your first task

A description, or issue numbers — batches work in order. --local skips GitHub entirely. The command returns; follow with selvage watch. If a task sits at ready, your adapters aren’t connected — run selvage start.

$ selvage run "add retries to the fetch path"
$ selvage run 115
$ selvage run 115 130 136 --local
6

Read the evidence, then decide

Open selvage ui to inspect the diff, verification results, and review findings, then approve, request a revision, or reject the task. The same decisions are available in the terminal:

$ selvage report 44
$ selvage approve 44
$ selvage revise 44 --reason "handle the 504 path"

What happens to a task

From the moment you queue it to the moment it’s yours to merge:

  1. Queued

    Submitted to selvaged, the daemon that schedules work across models. Your terminal is free the second the command returns.

  2. Isolated

    A selvage/<task-id> worktree and branch exist before implementation — a failed run is still inspectable. Your working tree is never touched.

  3. Implemented

    An adapter drives the configured model — Claude, Kiro, or Codex — inside your repo, against your code and its conventions.

  4. Verified

    The checks from .selvage/config.yaml run from the orchestrator, not the agent. Go tests run with -count=1, so a green run is fresh execution, not a cached replay.

  5. Reviewed

    A separate session — never the implementer — reads the diff and files findings. Findings go back to the implementer for revision.

  6. Reported

    Diff, build, tests, review, approval state — all on the evidence chain. selvage report <task> reads the ledger.

  7. Gated by you

    selvage approve publishes per your config — or the branch simply stays local. There is no auto-push path.

Commands

Grouped the way the CLI groups itself. selvage with no arguments prints this same map; global flag --socket PATH (or SELVAGE_SOCKET) points at a non-default daemon.

START
initGuided dashboard setup: detect adapters, Test connection, write .selvage/config.yaml. --force re-opens it to replace an existing config; --cli uses the terminal flow
registerRegister a repository with the daemon
start / stopBring the daemon and configured adapters up (with live validation) / shut them down. Run start before your first task
nodesList connected adapters. Empty means no implementer/reviewer is live — run start
DO
run<issue|description> [more…] [--local] [--foreground] — queue one or more tasks; follow with watch
askOne prompt as a bounded task — "prompt" [--repo] [--base] [--effort]
implementRun a spec autonomously — --spec path.md
status / watchTerminal snapshot / live progress — watch [task-id] [--latest] [--dashboard]
inbox / uiPending, landed, failed / web dashboard on localhost
logsTask logs
reportThe evidence — <task-id> [--output DIR]: diff, build, tests, review
planPlan and scope an issue batch before running it
usageUsage and cost provenance
adapters<add|update|remove|list> — manage the models it drives (adapters doctor checks health)
modelsModel catalog
indexbuild / query <provides|depends-on|exports|callers|callees|call-tree> — the structural code index the implementer is oriented with; opt in via SELVAGE_CODEINDEX=1
metricsThroughput, phase timings, and lease outcomes
ab-costMeasured A/B of cost-to-done and revision counts across two sets of already-run task ids — --off IDS --on IDS [--feature TEXT]
epicRun a multi-issue epic as one dependency-ordered batch
DECIDE
approveThe human gate — TASK_ID; publishes per config
acceptAccept a task — <task-id> [--dry-run]
reviseSend it back with a reason — TASK_ID --reason TEXT
rejectClose it out with a reason — TASK_ID --reason TEXT
re-reviewRe-run the independent review
resolveRecord an operator decision on a blocking finding
signoffAcknowledge a major finding you have judged acceptable
overrideOverride a routing or policy decision, with the reason recorded
TIDY
taskcancel | retry | recover | overage — task-level operations
trustApprove the config digest — [--repo PATH]
cleanGC stale runtime state (alias gc)
daemonserve | status | stop — the daemon directly, when you are not using start/stop
mcp-serverExpose selvage (or just its code index, with --index-only) over MCP to another agent

Adapters — the CLIs it drives

Selvage does not call model APIs. It drives coding CLIs you have already installed and authenticated, one process per role, so your existing subscription and auth are the ones being used. selvage init detects what is on your PATH; selvage adapters list shows what the current config resolves to, and selvage adapters doctor checks each one is runnable and authenticated.

SUPPORTED CLIs
claudeprovider anthropic — reports real per-run cost and token totals through --output-format stream-json
kiro-cliprovider kiro — reports credits; token and dollar fields are marked unsupported rather than guessed
opencodeprovider opencode — any provider you have authenticated inside OpenCode, including local and Cloudflare Workers AI models
codexprovider openai

OpenCode

OpenCode is a useful adapter when you want a model that is not behind one of the first-party CLIs — a local model, or a hosted one such as Cloudflare Workers AI — without Selvage needing its own provider integration.

1. Authenticate a provider inside OpenCode first. This is the step people miss: opencode --version succeeding only proves the binary runs. Selvage checks opencode providers list and refuses setup unless at least one provider is authenticated, because an unauthenticated OpenCode fails at the first lease instead of at setup.

opencode providers login  # pick e.g. Cloudflare Workers AI
opencode providers list   # must show at least one authenticated provider
opencode models         # the model ids you can use below

2. Add the adapter. Interactive, which reads the model list from opencode models for you:

selvage adapters add  # choose OpenCode, then a model and a role

3. Or write it directly in .selvage/config.yaml. Model ids are the fully qualified ones OpenCode prints, provider prefix included:

adapters:
  - kind: exec
    node-id: opencode-impl
    role: implementer
    provider: opencode
    model: cloudflare-workers-ai/@cf/zai-org/glm-5.3
    profile-id: opencode/cloudflare-workers-ai/@cf/zai-org/glm-5.3
    max_concurrent_leases: 1
    command: ["opencode", "run", "--pure", "-m", "{model}"]
    extra_flags: ["--completion", "commit", "--timeout", "30m"]

Three details matter. --pure keeps the run non-interactive and free of your local OpenCode session state. {model} is substituted from the model field, so the two never drift apart. And --completion commit tells Selvage this role finishes by committing, which is what an implementer must do — a reviewer omits it.

Then selvage trust to approve the changed config, and selvage start, which validates every adapter with a live prompt before accepting work. A model that cannot answer a one-line prompt is caught there rather than three minutes into a task.

What you get back is provider-dependent. Cost and token reporting is only as good as what the CLI prints. Claude emits machine-readable totals; Kiro reports credits; OpenCode's footer varies by provider, and Selvage records what is reported and marks the rest unavailable rather than inferring numbers. selvage usage shows the provenance for each figure, so an A/B measurement can tell a real zero from an unreported one.

Independence still applies: the reviewer must differ from every implementer that touched a task by node, profile, and provider, subject to minimum_independence. Running OpenCode as the implementer and Claude or Kiro as the reviewer satisfies it; the same OpenCode model on both sides does not.

Configuration

.selvage/config.yaml is created by selvage init: which adapters to drive, and which checks gate the work. Checks must defeat caches — the agent runs tests during implementation, so a verifier replaying cached results is just re-reading the agent’s own run:

checks:
  go-test:
    command: ["go", "test", "-count=1", "./..."]
    timeout: 60s
  go-vet:
    command: ["go", "vet", "./..."]
    timeout: 30s

The config is untrusted input: selvage trust approves its digest, and a changed config re-arms the prompt. Runtime state lives in XDG, never in the repo.

Local & hosted

Two ways to run it, one gate in both.

NO GITHUB NEEDED

Local mode

From any project directory — no remote, no gh, no config file:

$ selvage run "refactor the database layer"
  • Safe defaults in memory; kiro-cli used when available
  • Detected build/test checks for Go, Node, Rust, Python
  • Isolated selvage/<task-id> worktree and branch
  • No issue lookup, no push, no PR — inspect with git diff, merge manually
GITHUB REMOTE + TRUSTED CONFIG

Hosted mode

The full workflow, in a repo with a GitHub identity:

$ selvage init
$ selvage trust
$ selvage run 115
  • Issue numbers resolve to real issues
  • Adapters and publisher per .selvage/config.yaml
  • Approve publishes per config — branch / PR
  • Required before connecting an MCP client

MCP — connect your agent tools

One stdio server; the agent terminal you already use submits work, reads evidence, and files review verdicts inside the chat it’s in. The project must be trusted first:

$ selvage mcp-server --repo /path/to/repo
selvage_submit_taskSubmit a bounded task request
selvage_implement_specSubmit a spec for autonomous execution
selvage_statusRead task states and progress
selvage_get_evidenceRead diffs, verification results, review findings
selvage_record_reviewFile a review verdict — revise or reject, never approve

The hard rule: selvage_approve does not exist as a model-callable tool. An MCP client is an agent — if it could call approve, a model holds the human gate. Approval remains a human decision in the dashboard or terminal.

Claude Code — .mcp.json:

{"mcpServers": {"selvage": {
  "command": "selvage",
  "args": ["mcp-server", "--repo", "/absolute/path/to/repository"]
}}}

Codex and OpenCode take the same command in ~/.codex/config.toml / opencode.json — snippets on GitHub.

Guarantees

The invariants are architectural, not configurable — they survive every integration request and every “can we just…” conversation:

Human approval, always

Review the evidence and approve in the dashboard or with selvage approve. MCP clients cannot call the approval action.

No auto-push

There is no flag that turns it on. Work lands only after you approve.

Reviewer ≠ implementer

Independence guard: a different model, a different session, reads the diff.

Verifier ≠ agent

Build and tests run from the orchestrator, cache-defeating. The agent can’t replay its own green run.

Config is untrusted input

First use requires digest approval. Change the config and you re-trust.

State out of the repo

Runtime state lives in XDG only — the repo stays clean.

Evidence or it didn’t happen

Diff, tests, review, approval — all on the chain, readable with selvage report.

The gates being non-optional is the product.

Everything else is convenience. The gates are the point.

FAQ

Does it ever push without me?

No. There is no auto-push — not behind a flag, not by default. Approval is a human decision in the dashboard or terminal.

Can a model approve a task?

No. selvage_approve has never existed as a model-callable tool. MCP review records are limited to revise or reject.

Who runs the tests?

The orchestrator, not the implementing agent — and checks defeat caches (Go: -count=1), so a green run is fresh evidence, not a replay.

Does it work without GitHub?

Yes — local mode needs only a project directory. A git repo gives you worktree isolation; a plain directory still records artifacts. No issue lookup, no push, no PR.

Which languages?

Build/test checks are detected for Go, Node, Rust, and Python. Anything else goes in .selvage/config.yaml under checks.

What exactly is the evidence?

The diff, build and test results, the review findings, and the approval state — on the chain, readable with selvage report <task>. If it’s not in the chain, it didn’t happen.