CLI Reference
Commands
Use detent --help for the top-level commands and detent help --format json
for the full command catalog, including subcommands, flags and examples.
| Area | Commands |
|---|---|
| Hub and runner | hub, cloud, attach |
| Artifacts and installation | artifacts, update, version, skill |
| Configuration and diagnostics | config, doctor, fix, logs, help, completion |
| Project operations | pause, unpause, resume, promote, budget, capacity, exposure |
| Application reads and tools | audit, issue, mcp, state, report |
| Isolated browser fixtures | dev-runtime |
Enroll a runner with detent hub runner register --service to install and start
its background service. Run detent --config /path/to/global.yaml --headless
to start an enrolled runner in the foreground. Hub API keys are managed in
Settings > API & MCP.
config migrate and fix workflow-layout remain available for repository
workflow migrations. dev-runtime remains available for tests/visual and
Browser Visual CI fixtures.
CLI exit codes
Detent uses stable process exit codes so scripts and agents can branch on the failure class.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General or unexpected error |
| 2 | Auth or GitHub token problem |
| 3 | Input validation error |
| 4 | Not found or config conflict |
CLI JSON error envelopes
When the resolved output format is JSON, command failures write one RFC 9457-style problem object to stderr. Human-readable pretty-mode errors are unchanged.
{
"type": "https://detent.dev/errors/project_not_found",
"code": "project_not_found",
"title": "Project not found",
"detail": "project \"ap\" not found",
"exit_code": 4,
"suggested_fix": "available: api, web, infra\ndid you mean \"api\"? see `detent config path`, then retry",
"did_you_mean": ["api"],
"docs_url": "https://detent.dev/docs/cli#project-not-found"
}
Envelope fields:
| Field | Required | Meaning |
|---|---|---|
type |
Yes | Stable problem type URL, using the code slug. |
code |
Yes | Stable machine-readable slug. |
title |
Yes | Short human title for the error class. |
detail |
Yes | Specific failure detail. |
exit_code |
Yes | Process exit code for the failure. |
suggested_fix |
No | Actionable next step when Detent has a hint. |
did_you_mean |
No | Candidate correction list when Detent has suggestions. |
docs_url |
No | Documentation URL for the error class. |
Stable JSON error codes:
| Code | Type URL | Exit code | Source |
|---|---|---|---|
general |
https://detent.dev/errors/general |
1 | Unexpected error. |
validation |
https://detent.dev/errors/validation |
3 | Input validation, invalid config, or invalid output format. |
unknown_command |
https://detent.dev/errors/unknown_command |
3 | Unknown command. |
unknown_flag |
https://detent.dev/errors/unknown_flag |
3 | Unknown flag. |
github_auth |
https://detent.dev/errors/github_auth |
2 | GitHub token or authentication failure. |
config_exists |
https://detent.dev/errors/config_exists |
4 | ErrConfigExists. |
project_exists |
https://detent.dev/errors/project_exists |
4 | ErrProjectExists. |
project_not_found |
https://detent.dev/errors/project_not_found |
4 | ErrProjectNotFound. |
doctor_failed |
https://detent.dev/errors/doctor_failed |
1 | ErrDoctorFailed. |
shutdown_forced |
https://detent.dev/errors/shutdown_forced |
1 | ErrShutdownForced. |
shutdown_timeout |
https://detent.dev/errors/shutdown_timeout |
1 | ErrShutdownTimeout. |
dashboard_unreachable |
https://detent.dev/errors/dashboard_unreachable |
1 | The configured Detent service is stopped or unreachable. |
dashboard_timeout |
https://detent.dev/errors/dashboard_timeout |
1 | The bounded dashboard API request timed out. |
dashboard_unauthorized |
https://detent.dev/errors/dashboard_unauthorized |
2 | The dashboard API rejected the supplied credential. |
dashboard_forbidden |
https://detent.dev/errors/dashboard_forbidden |
2 | The credential does not allow the requested read. |
ambiguous_reference |
https://detent.dev/errors/ambiguous_reference |
3 | The selected project contains more than one matching identity. |
issue_not_found |
https://detent.dev/errors/issue_not_found |
4 | The selected project has no matching issue. |
unsupported_model_version |
https://detent.dev/errors/unsupported_model_version |
1 | The CLI and service do not share an issue explanation schema version. |
runtime_unavailable |
https://detent.dev/errors/runtime_unavailable |
1 | The running service cannot currently produce the issue explanation read model. |
dashboard_request_failed |
https://detent.dev/errors/dashboard_request_failed |
1 | The dashboard API returned another unsuccessful response. |
Logging
Detent logs with log/slog.
ENV=dev,development, orlocalenables tint text logs.ENV=prodor any other non-development value keeps JSON logs.- When no environment is configured, Detent defaults to
prod. LOG_LEVELacceptsdebug,info,warn,warning, anderror.--envand--log-leveloverride environment variables for one run.DETENT_ENVandDETENT_LOG_LEVELremain deprecated fallbacks for one release. The unprefixed names win when both are set.- Text logs are written to stdout; JSON logs are written to stderr.
- The terminal dashboard writes JSON logs to
detent.lognext to the runtime database.log_max_size_bytesdefaults to 52428800 andlog_max_backupsdefaults to 5. detent logsreads that resolved dashboard log and its numbered backups. Headless runs stream JSON or development text logs to stdout or stderr instead of a file, so the command reports the dashboard log as unavailable when no file exists. It never switches to an arbitrary path or parses text logs.- Log filters use the canonical fields
project_id,issue_id,issue_identifier,work_attempt_id,detent_session_id, andprovider_session_id. All supplied filters combine conjunctively.--sinceand--untilare inclusive RFC3339 boundaries compared in UTC, and--levelmeans the selected level or higher. - With no overrides, the command examines at most the most recent 8 MiB, keeps at most the latest 1,000 matching records in chronological order, and uses a 24-hour UTC window ending at invocation time. The JSON summary reports byte or record truncation explicitly.
--output jsonwrites{ "records": [...], "summary": {...} }.--output jsonlwrites one original JSON log record per line to stdout. Malformed and partial records are skipped and reported as bounded JSON diagnostics on stderr without echoing their contents. JSONL reports truncation with anoutput_truncateddiagnostic on stderr; the full counts are available in the JSON summary.- Per-request GitHub REST request/response debug logs are off by default. Set
tracker.github_rest_debug_logging: trueonly while diagnosing REST traffic.
CLI Output
Detent command output is selected by --format pretty|json. The explicit flag
wins, then DETENT_FORMAT, then the stdout terminal check. Interactive
terminals default to pretty; pipes, redirects, and agent subprocesses default
to json. JSON is written to stdout. Progress and logs that would corrupt a
JSON stdout stream are written to stderr in JSON mode.
This changes piped output for scripts that parsed the old prose output. Use
--format pretty for a single command or DETENT_FORMAT=pretty for a process
environment that must keep the old text shape.
Structured command objects:
| Command | JSON object |
|---|---|
detent version |
{"version":"v0.55.0","commit":"abc1234","build_date":"2026-08-01T00:00:00Z","go_version":"go1.26.4","os":"linux","arch":"amd64"} |
detent update |
The update status object, including current_version, latest_version, latest_tag, update_available, install_source, action, message, and command when present. |
detent pause api --reason "maintenance" / detent unpause api |
{"status":"ok","project":"api","paused":true,"paused_reason":"maintenance"} |
detent resume api --for 2h |
{"status":"ok","project":"api","active_hours_override_until":"2026-08-07T21:00:00Z"} |
detent promote api --priority 1 |
{"status":"ok","project":"api","priority":1} |
detent config path |
{"path":"/path/global.yaml","rule":"--config"} |
detent exposure [--project api] |
{"findings":[{"source_project":"api","source_repository":"private/api","destination_repository":"public/detent","issue_number":42,"issue_url":"https://github.com/public/detent/issues/42","matched_identifier":"private/api"}],"warnings":[]} |
detent issue '#1643' --explain --project detent |
The exact versioned issue explanation DTO returned by the running service, with no wrapper. |
detent state [--project detent] |
A bounded projection of the public state response, plus truncation; internal board_issues are excluded. |
detent skill install --target codex --dry-run |
The complete skill install result, including bundle/build stamps, target intent and status, every planned filesystem action, and any rollback actions. |
detent doctor |
{"checks":[{"name":"Config resolution","status":"OK","detail":"...","hint":"..."}],"summary":{"ok":8,"warn":0,"fail":0},"result":"PASS"} |
detent fix worker-processes --dry-run / --yes |
The orphaned process groups reported by the live service, including session identity, PID, PGID, RSS, and the reap outcome when applied. |
Doctor token diagnostics
detent doctor includes these read-only project checks:
| Check | Evidence and thresholds |
|---|---|
workflow_source_drift |
Warns when workdir is on a different branch from the GitHub tracker default branch with no workflow_ref, or when the pinned WORKFLOW.md differs from the working copy. Reports both byte sizes; missing refs or metadata warn. |
instruction_budget |
Estimates the repository AGENTS chain (root to workdir, override-file precedence, 32 KiB aggregate cap), effective WORKFLOW prompt, and literal file paths (filenames with extensions, Makefile, or backtick-quoted paths) on read/follow/consult/load/review directive lines in every loaded instruction file, including transitive references (deduplicated). Lists files and bytes; warns above 24 KiB, fails above 48 KiB. Missing evidence warns. |
gate_instruction_conflict |
Warns when gate.run is required in multiple instruction files or both required and forbidden/conditional. Uses the same instruction inventory and line-based requirement/prohibition heuristics. When configured for make check-fast, also audits conflicting full make check instructions. |
model_policy |
Prints each effective level's model, effort, and configuration sources. Warns when more than 10% of project codex_sessions started in the last 24 hours have issue.effort (including role-specific issue.<role>.effort sources) above the current level default, or provenance cannot be compared. |
token_accounting |
Compares project usage_events.total_tokens with work_attempts.metrics_json.total_tokens over the last 24 hours; warns when the absolute difference is more than 5% of usage_events. Zero usage with nonzero attempt totals also warns. |
ci_trigger_shape |
For GitHub trackers, reads default-branch workflow files in one GraphQL query. Warns when a configured required-check job runs on an explicit labeled activity without a workflow/job concurrency group containing github.event.pull_request.head.sha. Missing or unreadable required workflows warn. |
Instruction analysis is a static estimate, not a full natural-language or Codex
configuration interpreter. It excludes dynamic template expansions, dynamic file
paths, custom Codex fallback filenames, and instructions below the configured
workdir; isolated workers exclude user-home instructions. Referenced files are
read from the checkout, while the workflow prompt uses the configured source.
Model history is compared against today's effective policy, not historical config.
Accounting uses usage finish times and attempt completion times (start time for
unfinished attempts); window-crossing sessions can produce differences. Use
usage_events as the reconciled reporting source. Unavailable database evidence
warns; these diagnostics do not change policy, tracker lanes, or runtime state.
MCP stdio server
detent mcp serves the shared typed operator catalog to any MCP client. Modern
2026-07-28 requests carry protocol version and client capabilities in _meta,
without an initialization handshake. Clients can probe server/discover first.
Older clients use initialize and notifications/initialized with
2025-11-25, 2025-06-18, 2025-03-26, or 2024-11-05; an unsupported
initialization revision negotiates 2025-11-25, never a modern handshake.
The process reads newline-delimited JSON-RPC from stdin and reserves stdout for
protocol frames. Diagnostics use stderr. Successful results include serialized
JSON text; versions from 2025-06-18 also receive structuredContent, and modern
results include resultType: "complete". Arguments, results, frames and catalog
responses are bounded. tools/list returns the complete current authorized
catalog by default; each shared definition has _meta["detent/toolset"] for
grouping. Request smaller groups with params._meta["detent/toolsets"], an
array such as ["board", "connection"]. Discovery never authorizes a call.
The MCP process uses the already-running daemon's authenticated application
bridge, with the same config, host, port, wildcard-to-loopback mapping and
API-token precedence as detent issue --explain. Set DETENT_API_TOKEN to an
existing scoped credential when needed. Discovery and execution recheck current
authority in the daemon; a legacy loopback read bridge does not gain write access.
The bridge opens a default-confirmation application connection and forwards its
server-issued handle on fixed typed-tool endpoints. Client metadata cannot
select identity, organization or YOLO, and no arbitrary HTTP path is accepted.
The five existing reads remain board_state, fleet_health, telemetry_usage,
recent_activity, and explain_item. Available shared application commands and
connection/approval reads are permission-filtered by the daemon. Snapshot results
include generated_at, freshness, and expires_at for last-known results.
See generic MCP setup for authority,
organization selection, approval URLs, explicit YOLO and trusted remote access.
Operator skill installation
detent skill install installs the embedded read-only operator introspection
skill for explicitly selected local agent clients. --target is required and
repeatable; supported values are claude-code, codex, and antigravity.
| Target | Discovery scope | Deterministic installed entrypoint |
|---|---|---|
claude-code |
Claude Code personal skill | ~/.claude/skills/detent-operator-introspection/SKILL.md |
codex |
Codex user skill | ~/.agents/skills/detent-operator-introspection/SKILL.md |
antigravity |
Antigravity global skill | ~/.gemini/config/skills/detent-operator-introspection/SKILL.md |
The locations intentionally follow each client's own discovery contract. The
portable bundle body does not imply a shared client home layout, and the
installer never writes repository .detent/skills worker metadata.
Use --dry-run to validate all selected roots and print every directory,
managed file, backup path, and action without writing. JSON output returns the
same complete plan and result model. The command preflights every selected
target before applying any action, so a conflict or unsafe path prevents all
targets from changing.
An exact reinstall is a no-op. A changed skill, changed install manifest,
upgrade, downgrade, or partial prior install fails without --force; the
command does not prompt in JSON mode. --force first creates deterministic
content-addressed backups beside changed managed files, then atomically replaces
only SKILL.md and .detent-install.json. Other files in the skill directory
are preserved. If a later action fails, earlier managed-file and directory
changes are rolled back across all selected targets, and rollback results are
included in output.
Every existing path component from the user home through the destination must
be a real directory. Symlinked roots, directories, managed files, backup files,
and lexical escapes are rejected. New directories use mode 0700; managed and
backup files use mode 0600. The install manifest records the embedded bundle
version and SHA-256 plus the running binary's resolved build version, commit,
date, and dirty state. It contains no credentials, Detent config, or runtime
filesystem paths.
Issue explanation reads
detent issue <ref> --explain --project <project-id> reads the versioned issue
explanation model from the running Detent service. --project is always
required, including for #number, so issue numbers are never treated as
globally unique. Issue IDs, canonical identifiers, and full tracker URLs are
accepted as <ref>.
The command resolves the configured host and port, maps wildcard bind hosts to
loopback for dialing, and uses DETENT_API_TOKEN before the resolved
api_token. If either source supplies a credential, the client sends it; a
rejected credential is reported as dashboard_unauthorized and is not retried
without authentication. Requests have a ten-second client timeout and honor
caller cancellation.
JSON mode writes exactly one issue explanation DTO to stdout. Pretty mode is a human-readable projection of the same DTO. Diagnostics and JSON problem objects remain on stderr.
Fleet state reads
detent state reads the public /api/v1/state model from the running service
with projection=cli, bounding the response before the client reads it.
--project <project-id> selects the existing project-scoped state route. The
CLI projection does not expose the fuller internal snapshot's board_issues
array. It preserves generated_at, refresh freshness and source degradation,
and snapshot-unavailable degraded responses.
Every state data array is limited to its first 100 entries in service order. The
top-level truncation object always reports that limit and contains
truncated plus a collections array of JSON Pointer paths, original total,
returned, and omitted counts. The service limits compact JSON, including
metadata, to 768 KiB (max_bytes), and individual encoded scalar values to
16 KiB (value_max_bytes). The byte budget can return fewer than 100 entries.
Oversized fields or subtrees appear in omitted_fields with a JSON Pointer
path and reason: byte_limit; an omitted array also records its original
total. Counts and freshness come from the complete scoped snapshot.
The shared client's hard one-MiB transport limit remains unchanged. Older
services remain compatible for small states, but large states require updating
the service to support this projection.
JSON is written to stdout, pretty output is only a human-readable projection,
and diagnostics remain on stderr.
Operations report export
detent report --html <path> reads GET /api/v1/operations from the running
service and writes it as one self-contained HTML file: inline styles, no
scripts, no external assets, so it reads correctly from a synced folder or an
email attachment away from the tailnet. The page states the producing instance
and its data time and refreshes itself every five minutes when left open in a
browser. Service-relative evidence links are rewritten to the service origin.
The file is written to a temporary sibling and renamed into place, so readers
never see a partial page. Pretty output reports the path, instance, data time,
and size; --format json returns the same fields.
Provider capacity recovery
After restoring subscription usage, request full configured dispatch capacity:
detent capacity clear --scope codex --recovery immediate
Use --project detent to select one project. Scope accepts a backend ID, kind,
provider, or backend/provider; omitting it selects all backend scopes.
The default --recovery ramping and automatic recovery retain the gradual
progress-based ramp. Immediate recovery also removes a matching ramp left by an
earlier clear, making repeated clears safe.
Immediate recovery preserves unrelated backend outages and recovery ramps, GitHub and tracker holds, project breakers, human holds, configured global, project and provider concurrency, and budget limits. It does not reset provider usage. A renewed usage-limit response pauses dispatch normally.
The command queues work asynchronously. JSON output reports
recovery_requested (ramping or immediate) and recovery_applied: pending;
HTTP 202 means accepted, not yet applied. The orchestrator emits a structured
backend capacity clear applied log with scope, recovery_requested,
recovery_applied, and the number of outages cleared when it processes the
request. Other holds may still prevent dispatch after immediate recovery.
Immediate mode requires a server that supports this option. If an older server accepts the clear but ignores the mode, the CLI reports that immediate recovery was not acknowledged; that older server may still apply its default ramp.
Worker CI trigger labels
detent hub ci-trigger-label reapplies the configured pull-request CI label for
Hub project workers, preserving host-wide staggering. The retired top-level
ci-trigger-label command is no longer available.