Devplane

CLI reference

Every Devplane command and flag. Reading works with nothing running; a command that needs the host says so.

Commands are nouns with verbs: devplane run show, devplane inbox answer. Plain devplane runs devplane status. A verb typed without its noun (devplane connect) is refused, naming the right command.

  • --json works on every command, before or after its name. A failure is {"error": "…"} on stdout with a non-zero exit. It changes nothing for run watch, run attach, gate install, completions and up.
  • Colour follows NO_COLOR and is off when output is not a terminal; CLICOLOR_FORCE=1 forces it.
  • Reading needs no host. status, run list, run show, inbox, audit, search, change list, change show and agent list read the store when no host answers, and say what only a host sees. Starting, steering or stopping an agent needs the host. inbox answer works without one.
  • Exit codes: 0 success, 1 failure, 2 a usage error, 3 a refusal by change draft or change offer. devplane verify and devplane gate have their own.

Naming a run, a change or an ask

Every id takes the full id or any unique prefix; a run also takes its session name.

$ devplane status
core-lib
  ● a1         vscode     88%   $0.41   2s  Bash: cargo test --workspace

$ devplane run show a1

An ambiguous prefix is an error listing the matches; a live session wins over one that never reported. change prompt, change stop and inbox snooze take a change or a run.

The groups

devplane --help lists the commands under five groups:

GroupCommands
See what is happeningstatus run search
What needs you, and what happened without youinbox audit pr issue
Start and steer workchange gate verify
Set up a projectproject config agent auth doctor completions
The hostup down

Hidden, for machines: devplane mcp (below), and devplane hook and devplane statusline, which devplane agent connect installs.

See what is happening

devplane status

Sessions in play, and anything asking for you.

FlagWhat
-a, --allinclude sessions that never reported anything (idle editor tabs)
-p, --project <name>one project; matches any part of the name (mat finds matter-kit)
--needs-youonly sessions waiting on a person
--modeseach live session’s permission mode, least supervised first, with when it was first seen in that mode and any question auto-continue timer (askUserQuestionTimeout, CLAUDE_AFK_TIMEOUT_MS) and who set it

devplane run

SubcommandWhat
run listsessions in play, grouped by project. Alias ls. Takes -a, -p and --needs-you as status does
run show <run>state, agent, model, surface, cost, tool calls, blocker, plan, recent tools, tasks sent, and a driven run’s last lines
run watch [run]without a run, follow events; with a driven run, print its conversation like tail -f. Needs the host
run attach <run>hand this terminal to the agent: claude --resume <id>, or claude attach <id> for a background session. Replaces this process. Needs the host

run watch flags: --thinking includes the agent’s reasoning where streamed; --history <n> is how much conversation to print first (default 40).

devplane search <query>

Full-text search over tool calls, questions and errors in every session. The query is a phrase.

What needs you, and what happened without you

devplane inbox

What needs a person, by band, then oldest first. Derived from state, so correct after a restart.

BandWhat is in it
stops without youa question or permission an agent is waiting on
already stoppedan abandoned question, a run that is gone
broke after the facta gate red after the agent finished; a failed run
ready to decidea verified change waiting for review; never offered from the inbox
owed by youa review requested, an issue assigned, an open question in a spec
worth knowingdrift, overlap, a cost anomaly, the machine’s health
FlagWhat
-p, --project <name>one project, matched like status --project
--needs-youonly what can be answered from here (a question, not a red gate)
--allevery question and permission an agent asked, settled ones too
$ devplane inbox
since you last looked · 16h

 ! Keep the legacy /v1/login route? [question] saas 3m new
   Gate failed after the agent claimed completion [gate_failed] core-lib 5h
  • new marks what arrived since you last read the inbox. An empty inbox counts the decisions taken in your name and by whom.
  • A narrowed list counts what it hides. Filters are not remembered.
  • Above twelve rows, issues and stalled sessions fold into a counted row. Questions, permissions and drift never fold.
  • A permission item names the narrowest rule that would stop the ask. Nothing is written for you.
  • gate_down: the permission gate is not answering. config_broken: a devplane.toml will not load.

--all lists open asks first, then settled ones with what ended them: you, a clock ([questions] deadline) or nobody, then questions an agent moved past.

devplane inbox answer <ask>

Answer a permission or a question by the id devplane inbox prints. The id outlives the asking process; a late answer reaches the agent through a resumed session.

FlagWhat
--allowallow a permission
--denyrefuse a permission
--option <text>one of the agent’s options, as written; the whole answer, so not with --allow/--deny
--custom <text>your own words, where the agent offered Other; wins over --option
--field <id>which question, when several were asked; not with --allow/--deny
  • One of --allow, --deny, --option or --custom is required.
  • --allow, and --option without --field, are refused inside an agent session (Security).
  • There is no dismiss. The first answer wins; a second is told who gave the first.

devplane inbox snooze <id>

Hide a run’s or a change’s current inbox items for a while; new kinds still show, and the run keeps running. A question or a permission is never snoozed. devplane inbox counts what is snoozed.

FlagWhat
--minutes <n>default 60, at most 30 days; 0 un-snoozes
--until-activityuntil the run next reports activity (a change: a run event, a check result or a moved tree); not with --minutes

devplane audit [about]

What Devplane decided, and on whose authority: person, rule, timer, nobody or devplane. about narrows to one run or change. How to read it: the decision log.

FlagWhat
--without-meonly what a rule, a clock or nobody decided, plus the calls nobody can be named for
--limit <n>rows (default 50)
--otelthe rows as OpenTelemetry GenAI gen_ai.tool.call.decision log records (OTLP/JSON on stdout). Nothing is sent

An MCP tool call’s row says where its server was defined (project, user, plugin, sdk), or that it was not reported.

devplane pr list and devplane issue list

Open pull requests and issues across registered projects, read with your GitHub sign-in, what needs you first. Alias ls. Nothing is written to GitHub.

  • The host refreshes them every five minutes and after a sign-in.
  • Each project shows its GitHub state (not signed in, expired, rate limited, unreachable, stale, not a GitHub repository) and how many are open past the page read.
  • In pr list, ◆ marks what waits on you: a review requested of you, or your own pull request that is red, has changes requested, or is approved and unmerged.
issue list flagWhat
--readyonly this repository’s issues with [github] ready_label: what change start --issue picks from
--cwd <path>which repository; implies --ready
--label <label>default [github] ready_label; implies --ready

Start and steer work

devplane change

A change is an isolated checkout, an agent in it, and [gates] check run when the agent finishes. Its states are drafted, isolated, in flight, verified, offered and archived (Verified done). Every <change> is an id or unique prefix as change list prints it.

Refused inside an agent session: change resume, login, claim-read, draft, draft-accept, draft-reject, offer, and review --seen.

devplane change start [title]...

devplane change start "add rate limiting to /login"
devplane change start --spec specs/001-password-reset --task REQ-3 "password reset"
devplane change start --project api --project web "bump tokio to 1.40"

The title is the first prompt and, slugged, the branch (change/add-rate-limiting-to-login-3f9a1c).

FlagWhat
--agent <id>default [agent] default: claude, codex, opencode, copilot, gemini, an agents.toml entry, or a command
--project <name|path>a registered project or a path; repeatable. Default: the current directory
--no-worktreework in the repository itself; marked in place, diffed against the working tree
--issue <n>start from a GitHub issue; its body is marked as an untrusted report
--spec <path>the spec file or folder this change answers, relative to the repository
--task <selector>repeatable, needs --spec: a requirement token (REQ-3) or file:line. A selector matching nothing refuses

Every project is checked first (trusted, clean, readable devplane.toml, matching --task); one refusal starts none. The preflight names [workspace] setup, or warns of a lockfile without one.

Reading a change

CommandWhat
change listevery change, its state and what it waits on (installing · pnpm install · 1m 12s, gates running, feedback round 2, needs you). Alias ls
change show <change>state; the agent’s open spec-and-tests claim, quoted; gate standing (verified, stale with both tree digests, failed, not run, no gates declared); runs; cost against budget; each check’s output; with a spec, task counts and drift
change review <change>the checks weakened or changed (kinds), the gate standing, then every file in [review] roles order with its role, covering test, decisions and task
change export <change>the done certificate
tasks      11 ticked · 9 seen by a passing check
REQ-3      3 tasks · 2 ticked · 0 seen by a passing check
drift      the specification changed 18m into run r-9f2 and the run never saw it
           devplane change drift c-01a0 --run r-9f2 --accept | --tell

change review flags:

FlagWhat
--by riskdeclared role order (default)
--by intentgrouped by the run that wrote each file and its tasks; unrequested files last
--seen <path>mark every weakened row at that path read, as yours (repeatable). An offer waits until every row is. Refused for a path with nothing in the change

change export flags and exits:

FlagWhat
--jsonthe in-toto statement: Statement v1, Test Result predicate
--out <file>write to <file> instead of printing; refused if it exists
--forcereplace <file> and <file>.sig
--sign sshneeds --out. Sign the statement with your global git user.signingkey by ssh-keygen -Y sign, write <file>.sig, and print the ssh-keygen -Y verify lines anyone can run. Devplane never makes a key

Exit 1, writing nothing, when the change has no statement (no check run, no tree recorded), when signing fails, or when --out exists. Exit 2 for --sign without --out.

devplane change export c-01a0 > cert.md
devplane change export c-01a0 --sign ssh --out c-01a0.intoto.json

Steering a change

CommandWhat
change verify <change>run [gates] check now and record it. --base-checks follows a pass with the base checks; the exit code stays check’s
change retry <change>one more feedback round past max_feedback_rounds, recorded as yours
change prompt <change|run> [text]...message the agent without stopping it (a change: its latest run); queued mid-turn
change stop <change|run>stop a run (a change: its latest). Says what survives (change, worktree, branch, record), then asks on a terminal; elsewhere it needs -y
change resume <change> [prompt]...reconnect to the same agent conversation after the host stopped; never automatic. --agent <id> continues with another agent in the same worktree, told only your words, never the earlier transcript. Refused while a run of the change is live
change login <change>for an agent that said it needs signing in. Without --method <id>, list its methods. A terminal method runs the agent’s login here, then starts the change again; an agent method asks the agent to sign itself in. Never asks for, reads or stores a credential
change claim-read <change>mark the agent’s open spec-and-tests claim read; it stays on the change under its run. No decision is recorded
change drift <change> --run <run> --accept|--tella spec moved under a run. --tell prompts the run with the changed files, resuming it if needed; --accept moves the change’s start to what the run saw. Recorded as yours. Needs the host
change adopt <branch>make a hand-made branch a change, in the checkout that has it or a new one under .claude/worktrees/. Refuses a missing branch and the base branch. --project <root>, --spec <path>, --title <text> (default: the first commit’s subject)

Drafting a specification

CommandWhat
change draft <name> -- <intent>...start a change whose agent is sent the project’s own spec command (Spec Kit’s /speckit-specify as that agent spells it, or OpenSpec’s installed propose workflow) followed by your words, and nothing else. Refused with exit 3 before anything is made
change draft-accept <change>the drafted folder becomes the spec the change answers
change draft-reject <change>the worktree goes back to where it was; the change, run and decisions stay on the record
change clarify <change> <path>:<line> -- <answer>...replace one bracketed open-question marker with your words, exactly. Prints the diff, writes on --yes or a y at the terminal. An unbracketed line is refused: use change prompt

change draft flags: --agent <id>, --methodology speckit|openspec (needed only where the project has both), --project <name|path>, --change <change> (draft again into a change whose draft was rejected), --dry-run (print what would be sent). Accept and reject are refused while the agent is mid-turn. Full rules: Specifications.

Ending a change

CommandWhat
change offer <change>commit exactly the verified tree (the certificate’s gitTree) on the change’s branch, then push and open a draft pull request when [github] pull_request = true, else print the git push line and GitHub’s compare address
change finish <change>accept the change as finished, recording the basis (verified, stale, no gates declared, or by hand). Removes nothing
change archive <change>remove the worktree, keep the record. Refuses uncommitted or unmerged work unless told; a refusal changes nothing

change offer is refused with exit 3 while a weakened row is unseen (--json: refused, rows, seen_with), and when the tree moved since the last pass (rules).

change archive flagWhat
--delete-branchalso delete the branch; refused while it has commits its base lacks, unless its pull request merged
--discard-uncommittedremove the worktree despite uncommitted or untracked files
--forcewith --delete-branch: delete despite unmerged commits

devplane gate

Run this repository’s gates and report the exit codes. No host, no record, no spec. A Spec Kit hook or a verify skill calls it.

FlagWhat
--cwd <path>which repository; default the working directory
--name <gate>run [gates.<gate>] instead of check. A named gate never makes a change verified
state (--json)ExitMeans
passed0every command passed
failed1one did not, and it is named
no_gates1no checks declared
config_unreadable1devplane.toml did not parse; nothing ran
unknown_gate1--name names no declared gate; the declared names are printed

--json also prints passed, summary and commands.

devplane gate install

Put the gate where a workflow runs it. One of --speckit or --skill is required. Refused while the repository declares no gate. Setup: Specifications and Driving agents.

FlagWhat
--speckitinstall the Devplane extension into this repository’s Spec Kit, through specify extension add when specify is on PATH, else the hand-written hook in .specify/extensions.yml
--skilloffer the gate as the Claude Code skill verify in .claude/skills/, shown as a diff and written when you confirm
--userwith --skill: in ~/.claude/skills/, for every repository
-y, --yeswith --skill: write without asking
--event <hook>with --speckit: the hook point; default after_implement
--dry-runprint, write and run nothing
--anywayinstall with no gate declared, no reachable skill for the hand-written hook, or over a verify skill Devplane did not write

devplane verify

Run the base’s check on this change, leading with the checks it weakened. For CI (CI verify) or before you push. Needs only git: no host, store or network unless --approvals is passed.

  • The change is the diff from the merge base with --base to the working tree, untracked files included.
  • check, its timeout and review roles come from devplane.toml at the merge base. A change that edits check is judged by the base’s, and the edit is the summary’s first row.
FlagWhat
--base <ref>any commit-ish, tried as origin/<ref> then <ref>. Default: origin/HEAD’s branch, else main
--summary <path>write the Markdown summary there; otherwise appended to $GITHUB_STEP_SUMMARY if set
--statement <path>write the in-toto statement (never signed) when check ran
--no-base-checksskip the base checks that run after a pass
--sarif <path>write the weakened rows and failing named tests as SARIF 2.1.0; nothing is uploaded
--approvalsread who approved the pull request the run’s event names, with $GITHUB_TOKEN from $GITHUB_API_URL: two to twelve GET requests, nothing written (details)
ExitMeans
0verified: every command exited 0 and the tree stayed put
1failed: a command failed, timed out or never started, or the tree moved
2could not run: no base, no shared history, no check at the base, an unreadable diff, or evidence that could not be written

Weakened checks never change the exit code. --json prints one document: verdict, exit, base, tree, weakened rows and each command’s outcome. Under GitHub Actions, weakened rows and failing named tests are also annotations.

Set up a project

devplane project trust [path]

Allow agents in a repository (default: here), after printing the hooks and MCP servers an agent would load there:

$ devplane project trust .
  starting an agent here loads this repository's own:

  hook    ./scripts/guard.sh
          runs on every PreToolUse in this repository
  mcp     notes
          `notes-mcp` has no version pin, so starting an agent fetches and
          runs whatever is published at that name today

  Trust this repository? [y/N]
FlagWhat
--dry-runprint, trust nothing
-y, --yestrust without asking; required when stdin is not a terminal

Refused inside an agent session. It writes ~/.devplane/trusted.toml and has a running host re-read it.

devplane config

Read devplane.toml, ask what its rules decide, and manage your grants. Offline.

SubcommandWhat
config check [path]does the file parse, does everything it names exist, is anything unsafe. Also names a rule that covers nothing, one that grants more than it reads, a read-denied path that is still writable, and a removed key with its replacement. Exits non-zero on an error (Configuration)
config explain [call]...what the permission gate would decide about one call, and which rule says so
config grantsthe grants in ~/.devplane/policy.toml, with what each decided
config revoke <rule>remove a grant, exactly as the file has it, and list every decision it made. --dir <path>: a directory in the project the grant is for (default .)
$ devplane config explain 'git push --force origin main'
ask  Bash
        by Bash(git push *)

$ devplane config explain 'rm$IFS-rf node_modules'
ask — unreadable  Bash
        because the program is named by a variable the shell expands; …

$ devplane config explain 'cargo test'
undecided  Bash
        its rules loaded and none answers this one, so the provider's own dialog decides and it reaches your inbox

explain verdicts are deny, ask, ask — unreadable (unresolved in --json), undecided, or allow only for your own grant. See Permissions.

explain flagWhat
--tool <name>default Bash. Read, Edit and WebFetch take the specifier directly: --tool Read .env
--input <json>the whole tool input: --tool Agent --input '{"isolation":"worktree"}'
--dir <path>the agent’s working directory, which decides whose rules apply (default .)
--replayreplay every observed call against the current rules, grouping undecided calls by the allow rule that would cover them; a rule is offered after three interruptions
--limit <n>how many recent calls --replay reads (default 5000)

devplane agent

SubcommandWhat
agent listthe agents Devplane can drive and, once started, what each advertised (resume, load, list, modes, sign-in), with the date. Alias ls. See Driving agents
agent connect <vendor>install Devplane’s hooks: claude (hooks and telemetry in user settings, with a backup), codex (merged into ~/.codex/hooks.json) or copilot (one file in ~/.copilot/hooks/). Starts nothing
agent disconnect <vendor>remove exactly what connect installed; your own hooks stay
  • Both show the diff and ask on a terminal. Elsewhere, and under --json, they write only with -y.
  • Hooks run the binary by full path, so a temporary binary is refused (npx’s cache, macOS App Translocation, /Volumes, an AppImage mount). Run connect again after moving or reinstalling.
  • Codex runs a hook only after you approve it in its own dialog. For Copilot, connect prints three environment lines to export. See Watching sessions.
connect flagWhat
--statuslinealso wrap your status line, the only source of subscription rate limits
-y, --yeswrite without asking
--bin <path>the binary the hooks run; default this one

devplane auth

SubcommandWhat
auth loginGitHub’s device flow: prints a code and an address, then waits. The token goes only into the OS credential store (service devplane, account github:<host>); with no store, sign-in refuses
auth logoutdelete the token everywhere Devplane holds it, and name https://<host>/settings/applications to revoke the grant at GitHub
FlagWhat
--host <host>a GitHub Enterprise server instead of [github] host in ~/.devplane/app.toml (default github.com)
--with-tokenlogin only: read a token from stdin, never an argument; for a host with no registered app, and CI
gh auth token | devplane auth login --with-token  # GitHub CLI's token
devplane auth login --with-token < pat.txt        # a fine-grained personal access token

login --json prints { "state": "pending", "user_code", "verification_uri", "expires_at" }, then { "host", "login", "scopes" }. A build’s own OAuth app covers github.com only; an Enterprise app is set per host in app.toml.

devplane doctor

Whether Devplane works on this machine. The probe is recorded nowhere.

SectionReports
hostrunning (port, version, binary) or not
appthe window, signing, update checks, notifications, shortcut and port
watchedper vendor and channel: read, unproved, not published or not checked, with the date last read
gatethe rule-syntax baseline, and a timed PreToolUse probe
only gateDevplane is the only gate on this machine when a provider variable (Bedrock, Vertex, Foundry, a gateway, an API key) turns Claude Code’s supervision off
claude codehooks, INSTALLED AND NOT ANSWERING, gate off (binary gone), out of date, telemetry
this projecta JUnit path git does not ignore
githubper host: login, scopes, last answer (never the token); projects that are not GitHub repositories, with why
channelswhich are arriving, how many, worst latency, last error
inboxper kind over a week: raised, acted on, dismissed, resolved elsewhere
auto modeClaude Code’s own auto-mode classifier rules, read, never written
unreadable configurationa devplane.toml or app.toml that will not load
unwrittenevents and decisions the store refused
leaked agentsan agent a killed host left running, with the kill -TERM -<pgid>
unreadable rowsrows this build cannot decode

devplane completions <shell>

bash, zsh or fish. Ids complete from a running host or the store, never starting one.

devplane completions zsh  > ~/.zsh/completions/_devplane
devplane completions bash > /etc/bash_completion.d/devplane
devplane completions fish > ~/.config/fish/completions/devplane.fish

See Install.

devplane mcp

Hidden. Devplane over MCP on stdio: four questions and one claim. The plugin registers it, and every agent Devplane drives is offered it. By hand:

{ "mcpServers": { "devplane": { "command": "devplane", "args": ["mcp"] } } }
ToolAnswers
inboxwhat needs a person, across every project
changea change’s state, gate verdicts and spec; without an id, the change Devplane started the agent for, or every open change for an agent it did not start
explainwhat the gate would decide about a call, and which rule; recorded in devplane audit
auditwhat Devplane decided, and on whose authority
spec_and_tests_conflictnot a question: the calling agent says its change’s specification and tests cannot both be satisfied. Records the claim and stops the run (what follows)

The questions ask a host, else read the store, and act on nothing.

spec_and_tests_conflict takes exactly reason (1 to 1024 bytes) and paths (at most 10, each at most 512 bytes, inside the project or the change’s worktree). The run, change and a per-session key come from the server’s environment, and the host checks them. Anything else (a session Devplane did not start, no host, another run’s server, a second open claim, an argument out of bounds) is refused with a sentence and nothing recorded. Devplane never allows the call itself.

The host

The one long-lived process (Architecture). Nothing starts it automatically.

devplane up

Start the host and open the workbench. With a host running, only open it; otherwise this process is the host until ctrl-c.

FlagWhat
--port <n>default 47831, or DEVPLANE_PORT; 0 picks a free port. With --window, [app] port in ~/.devplane/app.toml if set
--no-browserhost without opening a browser
--windowthe native window instead of a browser

A port held by another process is refused, naming the holder (Troubleshooting). A second host on the same home is refused with the running one’s port and uptime.

devplane up --window

The host with a native window: a tray item with the need you count, notifications, one global shortcut ([app] shortcut), and devplane:// links to a change, review, ask or run. Closing the window keeps hosting; quitting from the tray says what it stops. Nothing starts at login. Needs a build with the app feature (cargo install devplane --features app); otherwise the flag is hidden and refused.

devplane down

Stop the host, first saying what ends: driven agents stop; your own sessions and waiting questions stay.

Quitting stops 2 agents Devplane started:
  r-4f2a9c1e  claude  ~/code/api
  r-8b31d07a  gemini  ~/code/web
It leaves 3 sessions running in their own terminals untouched.
Stopped.

Stopped. prints once the port is quiet. With no host: Nothing is running.

Something wrong or out of date? Edit this page.