Skip to content
Docs Reference and contribute Mirrored upstream
cli.md
Docs source v0.164.2 13d15fec6a14 View this file at the pinned commit ↗

CLI Reference

Back to README

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, or local enables tint text logs.
  • ENV=prod or any other non-development value keeps JSON logs.
  • When no environment is configured, Detent defaults to prod.
  • LOG_LEVEL accepts debug, info, warn, warning, and error.
  • --env and --log-level override environment variables for one run.
  • DETENT_ENV and DETENT_LOG_LEVEL remain 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.log next to the runtime database. log_max_size_bytes defaults to 52428800 and log_max_backups defaults to 5.
  • detent logs reads 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, and provider_session_id. All supplied filters combine conjunctively. --since and --until are inclusive RFC3339 boundaries compared in UTC, and --level means 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 json writes { "records": [...], "summary": {...} }. --output jsonl writes 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 an output_truncated diagnostic 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: true only 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.