Open Agent Toolkit

CLI Reference

Use this page when you need a quick map of the OAT CLI rather than the full command-by-command docs. It is intentionally shallow: each section points to the owning page that documents the detailed behavior.

The CLI is also a standalone value path. You can use oat init, oat sync, oat tools, docs commands, repo archive sync, and repo-analysis commands without adopting the full project workflow.

Contents

Full CLI Reference Expansion Path

Keep this page as the command-family map. Fuller command coverage should live either in the owning section for a command family or in generated/semi-generated reference pages that link back here.

Each full command reference should include:

  • exact arguments, flags, defaults, aliases, and mutually exclusive options
  • output examples, including --json shapes where the CLI supports JSON
  • exit behavior for success, validation errors, missing state, and non-interactive blockers
  • side effects such as file writes, generated artifacts, config mutations, branch/commit behavior, and network calls
  • non-interactive usage guidance, including required flags and scripting-safe forms
  • source or test references for behavior that is easy to drift, marking unknown exit-code behavior as unknown instead of inventing a contract

The first practical expansion path is to keep improving the existing owners: Docs App Commands, Provider Interop Commands, Config and Local State, Tool Packs, Workflow & Projects, and Repository PR Comment Analysis.

Command Groups

Command groupWhat it coversGo deeper
oat initBootstrap canonical OAT directories, sync config, optional hooks, and guided setup.CLI Bootstrap
oat tools ...Install, inspect, update, remove, and migrate bundled OAT tool packs and assets across project and user scope.Tool Packs
oat pjm ...Adopt PJM for a repository and record it (init), run read-only adoption and reference diagnostics (doctor), and migrate legacy layouts to pjm/ + reference/ (migrate). Adoption is separate from pack placement.Install vs. initialize
oat pjm remote ...Intake, publish, refresh, reconcile, close out, inspect discussion, resolve anomalies, diagnose, migrate, and continue durable host actions for explicit remote bindings.Remote Project Management
oat decision ...Create, index, and migrate file-per-record repo decisions under reference/decisions/ (init, new, regenerate-index, migrate).Config and Local State
oat backlog ... / oat local ...File-backed backlog helpers, local path sync, and local-only operational support.Config and Local State
oat config ... / oat instructions ...Config discovery, source-aware config dumps, supported mutations, and instruction-integrity helpers.Config and Local State
oat gate ...Per-skill final gate config, review-specific gate execution, exec-target registry writes, and cross-runtime prompt dispatch.Workflow Gates
oat state ... / oat index ... / internalRepo dashboard refresh, repo indexing, validation helpers, and diagnostics.Config and Local State
oat docs ...Docs app bootstrap, migration, index generation, nav sync, and docs workflow entrypoints.Docs Tooling Commands
oat status / oat sync / oat providers ...Provider sync, drift inspection, provider configuration, and adoption behavior.Provider Sync
oat project ... / oat cleanup ...Project scaffolding, active-project status inspection, tracked-project listing, plan validation, archive creation, and project/artifact cleanup commands.Workflow & Projects
oat review ...Review artifact discovery helpers, including latest-review resolution for project and ad-hoc review flows.Reviews
oat repo ...Repository-level workflows such as archive sync and PR-comment analysis.Repository Analysis

Notable commands introduced in the current CLI surface:

  • oat project new <slug> [--mode spec-driven|quick|import|lite] --scope shared|local|synced [--force] - create a project in an explicit scope. --mode selects the workflow mode and therefore which artifacts are scaffolded; it defaults to spec-driven. Use quick for a bounded feature with clear requirements, import to normalize an externally authored plan, and lite for a single-sitting change that scaffolds only plan.md, state.md, and implementation.md. See Lifecycle for the per-lane flow. Without --scope, creation uses projects.defaultScope, which defaults to synced. Project slugs are unique across all scopes by default, including recorded or remotely published synced projects. --force deliberately permits a duplicate; use an explicit project path with project open or project pause whenever a slug is ambiguous across scopes.
  • oat project scope [project] --format value|json - resolve a project's storage scope without inspecting its path manually.
  • oat project push [project] [--message <message>] - commit pending synced artifacts, reconcile with the exact project ref on origin, publish it, and refresh an open PR's artifact-links block. Use --no-refresh-pr to skip the PR edit. With --json, success returns status (pushed or up-to-date), the full project-ref sha, the retained ref, and optional prRefresh; conflict and rejected outcomes return their corresponding status and exit nonzero.
  • oat project pull [project] [--no-commit] - fetch and materialize or update a synced checkout. Resolve a rebase conflict and run pull --continue, or use pull --abort to return to the pre-pull state. Coordination children are pulled by default; --no-children limits the operation to the selected project. When pull adopts a remote project with no local discovery record, --no-commit leaves the new record uncommitted for the caller to persist. With --json, the receipt includes status, sha, and ref, plus conflicts when applicable and per-child results when coordination children were requested. A project whose authoritative ref is refs/oat/completed/<project> is terminal and cannot be pulled or opened. A same-SHA refs/oat/projects/<project> ref is only an inert alias; differing active and completed SHAs are reported as a terminal mismatch that must be repaired before lifecycle work continues.
  • oat project links [project] --format markdown|json - render SHA-pinned links for the linkable artifacts on the project ref. On GitHub origins the artifacts become full-SHA blob links; other hosts degrade to the retained ref and short SHA without guessing a web URL. --durable-summary <path> accepts only a path contained in the repository, normalizes it repository-relative, and renders it as a code span rather than a guessed remote link. Completed projects resolve through refs/oat/completed/<project> while the rendered artifact URLs remain pinned to the verified full source SHA.
  • oat project pause [project] - persist the pause state and clear the active project pointer. If synced publication is declined or fails after the pause commit is created, that clean commit is retained; address the publication failure and rerun pause to publish it.
  • oat project prune [project] [--force] [--no-commit] - remove every checkout, the local and remote project refs, and the tracked record. When the project is omitted, the active project is used. This is the explicit destructive operation; --force may discard dirty or unpushed artifacts, while --no-commit leaves the parent-record deletion for a library caller to commit. If remote deletion succeeds but local checkout removal fails, the local ref, record, and checkouts are retained. Resolve the reported local obstruction and retry prune --force; do not run project push, which would republish the deleted remote ref. For a completed project, explicit prune deletes the completed ref and any same-SHA active alias but preserves durable local and S3 archive snapshots. A differing-SHA terminal mismatch blocks prune and retains both refs.
  • oat project migrate <path> --to synced [--no-commit] - migrate an existing shared project to synced storage while preserving its artifacts and retargeting the active project pointer. --no-commit leaves the parent record and source-tree transition uncommitted for a library caller.
  • oat project list --scope shared|local|synced - filter tracked projects by scope. Add --remote to discover project refs that do not yet have a local record or checkout, and --include-coordination to include coordination parents. A malformed discovery record with no materialized checkout appears as a recorded-invalid row. When the checkout is materialized, its existing row instead carries the restore hint and recordError parse diagnostic in --json output. Fully retired completed refs and same-SHA active aliases are omitted from active discovery. A differing-SHA active/completed pair appears as a terminal-invalid row with a recovery diagnosis. When reconciling a local synced record or checkout, only a verified missing refs/oat/completed/<project> result counts as absence. Transport, authentication, and other lookup failures fail the command closed; they are never converted into a recorded-absent row or pull guidance.
  • oat tools migrate --pack <pack> --from <scope> --to <scope> - move one installed pack between project and user scope. Always previews first, installs and re-inventories the destination before touching the source, and offers source removal only after the destination is verified complete. Declining or running non-interactively leaves the pack installed at both scopes rather than failing. --dry-run stops after the preview; there is no force flag. See Tool Packs.
  • oat pjm doctor --json - read-only repository PJM diagnostics whose result carries an additive adoption object (state of declared | inferred-legacy | partial-initialization | none, repoRoot, and recovery). This, not oat tools has project-management, is the check that answers whether this repository adopted PJM.
  • oat pjm remote ... --json - operate one explicit provider-neutral binding. The family includes intake, publish, refresh, reconcile, closeout, discussion, resolve, doctor, migrate, storage, and operation continue. An ok envelope exits 0, a system failed envelope exits 2, and every safely persisted nonterminal or blocked status exits 1. A pending envelope with externalAction is a durable host handoff, not remote success.
  • oat config dump --json - merged config with source attribution
  • oat project status --json - full parsed state for the active tracked project. Stable contract for skills: the JSON output is a typed read interface for OAT skills; the field set consumed by migrated skills is locked by MIGRATED_FIELDS in packages/cli/src/commands/project/status.test.ts. Removing or renaming any of project.{name, path, phase, phaseStatus, workflowMode, docsUpdated, lastCommit, prStatus, prUrl} is a breaking change and will fail the contract test.
  • oat project status --field <path> - print one arbitrary dot-path field from the same status payload, e.g. project.workflowMode or project.timestamps.stateUpdated. Missing/null fields print null; object and array fields print compact JSON.
  • oat project status --project-path <path> - read from a repo-relative or absolute project path instead of .oat/config.local.json's active project pointer. Combine it with --field or --shell when a skill has already resolved the target project path.
  • oat project status --shell NAME=path ... - print shell-safe assignments for one or more fields from one status read, e.g. WORKFLOW_MODE='quick'. This is the preferred multi-field read API for skills. See Writing Skills → Reading project state for examples and the npx-backed oat shim contract.
  • oat project promote <project-path> --to quick [--json] - promote an authored lite project to quick mode. The command derives discovery.md from the lite plan's Summary, Decisions, Assumptions, Out of Scope, and Validation Criteria; carries Product Behavior into Success Criteria and Technical Design into a carried-forward discovery section when those adaptive sections are present; preserves the original as references/lite-plan.md; and scaffolds a fresh quick plan.md. It refuses unsupported targets, non-lite or unreadable projects, an existing lite-plan reference, invalid authored sections, unresolved scope, unavailable templates, failed writes, or failed persistence. JSON output is { status: "promoted" | "refused", reason, files }; reason is the stable categorical contract and refused results exit non-zero.
  • oat review latest --json - find the newest review artifact by oat_generated_at, scanning the active or specified project's reviews/ and reviews/archived/ directories plus ad-hoc review locations. Same-time candidates use target priority, then lifecycle recency (final > higher phase/task > lower phase/task). The JSON contract returns path, scope, generatedAt, kind (project or adhoc), archived, and actionable, with null values when no review exists. Archived project reviews remain discoverable as history but return actionable: false.
  • oat project list --json - summary state for tracked projects under the configured projects root
  • oat project complete-state <project-path> - apply the canonical completed-state mutation to a project's state.md; used by oat-project-complete during lifecycle closeout
  • oat project archive [project-path] [--project-recap-run <project-relative-path>] [--no-commit] - archive a tracked project through the same local move, summary export, and configured S3 upload path used by completion. When omitted, the project path falls back to the active project. The optional recap path must identify a project-recap run inside the project's explainers/ directory. Archive stages the selected complete package into .oat/repo/reference/project-recaps/<YYYYMMDD-project-slug>/, verifies every manifest-declared immutable file byte, then atomically installs the export before deleting the active project. Existing destinations, incomplete legacy hash coverage, stale bytes, path escapes, and recipe mismatches fail without removing the active project. For synced projects, a configured S3 upload must succeed before terminal cleanup. Successful closeout makes refs/oat/completed/<project> authoritative, deletes the tracked JSON record and nested checkout, and leaves archive metadata sufficient for an idempotent recordless retry. Legacy complete records receive a cleanup diagnosis rather than pull/open guidance. With --json, the terminal receipt reports completedRef, verifiedSourceSha, whether activeAliasDisposition was retained or removed, whether recordRetired completed, and the parent lifecycleCommit. --no-commit is a manual/library-only option: for a synced project it still removes the checkout but deliberately leaves lifecycleCommit null. Never pass it through oat-project-complete, which requires that receipt.
  • oat repo archive sync [project-name] - hydrate archived project snapshots from the configured repo-scoped S3 archive into .oat/projects/archived/. The old oat project archive sync path remains as a deprecated shim.
  • oat project dispatch record --event-file <json-file-or-dash> [--project <project-path>] - validate one generic dispatch record plus its namespaced OAT evidence event, and persist it into the project's append-only dispatch/ journal (optional; no lifecycle skill requires it). Omit --project to validate without persisting. Revision 1 is dispatch/<request-id>.json and every later revision is dispatch/<request-id>@<NNNN>.json; superseded revisions are never replaced or removed. The command validates and records evidence only — it never launches a provider. A runtime-observation event may carry either a finished observation or the provider metadata envelope (provider, observedAt, entries) to normalize, but not both. entries may be raw provider output: they are projected through the owning parser's allowlist, are never persisted, and both forms have their match derived from the record's configured invocation rather than trusted from the caller, with the observation's provider bound to the record's. With --json, the result adds runtimeIdentity with separate configured and observed objects plus a match of matching, mismatching, not-comparable, or null; observation is corroboration only and never overrides configured invocation. Error output is redacted on a best-effort basis; absolute paths in identity fields are rejected outright, while some prose forms (colon-prefixed, URL routes) can survive. See Evidence Layers.
  • oat project validate-plan --project-path <path> - validates oat_plan_parallel_groups metadata in plan.md; exits non-zero on invalid. Lite plans must contain exactly one phase, declare no parallel groups, and give every Validation Criteria bullet either a backticked command or a manual: instruction. See Implementation Execution.
  • oat project log append|check|synthesize|rollup - manage the optional append-only project observation log: append validated judgment or structural entries, inspect grammar and synthesis status, complete end-of-run synthesis, and roll observations into summary.md plus the configured repository ledger. See Project Log.
  • oat project set-mode — deprecated no-op. Execution mode is no longer user-selectable; emits a deprecation warning and preserves the --json contract.
  • oat gate review <prompt...> - run a stateful, headless OAT review through the target registry, parse the produced review artifact, and exit nonzero for configured blocking findings. --timeout-ms <milliseconds> overrides target, workflow.gateTimeouts, environment, and scope defaults; accepted values are 1,000–14,400,000. Final/phase/range code reviews default to 30 minutes, while task code and artifact reviews default to 15 minutes. With --json, the result envelope on exit is the canonical completion signal: status is ok | blocked | review_failed | artifact_missing | artifact_validation_failed | targeting_correlation_failed, alongside runId, generatedAt, and artifactPath when available. artifact_missing means an accepted child exited cleanly without an artifact; fix synchronous review/artifact completion and start a new run, without review-receive or same-run remediation. For targeting_correlation_failed, correct the project declaration or artifact routing and start a new run; do not run review-receive even if an artifact path is present. For artifact_validation_failed, correct the artifact and rerun the gate until it revalidates as ok or blocked. Invoke oat-project-review-receive only when all three conditions hold: status is ok or blocked, receiveEligible is true, and handoff is non-null. review_failed may include structured refusal, noOutputProduced, and metadata-only activityEvidence; these diagnostic fields never make a run receive-eligible. After a timeout, a validated run-correlated artifact returns the ordinary ok or blocked envelope with additive lateCompletion: true. When post-selection work fails after the reviewer already committed a run-correlated artifact, the gate re-validates that selected snapshot through the same eligibility path rather than re-parsing whatever the path now holds, never re-dispatching, and returns the ordinary ok or blocked envelope with additive postSelectionRecovery: true; the artifact must still be present and unchanged for re-validation to succeed. When nothing recovers, review_failed names the failing sub-step in postSelection.step and its cause in postSelection.code. Duplicate run-ID matches or a changed artifact with a mismatched run ID retain targeting_correlation_failed and receiveEligible: false. Orchestrators should read the structured result rather than poll the filesystem. See Workflow Gates.
  • oat gate route --expect-runtime <runtime> --expect-model <model> --can-await <true|false> --json - return the headless child route (inline, delegate-sync, or refuse) from provider-marker and model evidence. Ambiguous or contradictory evidence never routes inline.
  • oat gate exec <prompt...> / oat gate cross-provider-exec <prompt...> - run a generic target prompt. --timeout-ms uses the same validated CLI override; untyped runs otherwise retain the legacy default path.
  • oat gate target set <id> --invocation-model <model|provider-default> --invocation-reasoning-effort <effort|provider-default> - persist optional configured invocation metadata alongside an exec target without inferring it from the target command.
  • oat gate target set <id> --timeout-ms <milliseconds> - persist a validated per-target gate budget.
  • oat gate target list --json - inspect resolved gate targets without selecting or executing a reviewer. Each entry reports its config origin, whether it is explicitly configured and enabled, current availability, and normalized configured invocation values (unknown when omitted).
  • oat gate cross-provider-exec <prompt...> - choose an available exec target while avoiding the current runtime by default, then run the prompt with the chosen target's configured base command and exit with the child status.

oat config surface flags

oat config set and oat config unset support the same mutually exclusive surface flags, which control the config file the write or removal lands in:

  • --shared — write to or remove from .oat/config.json (committed team repo settings)
  • --local — write to or remove from .oat/config.local.json (per-developer repo state, gitignored)
  • --user — write to or remove from ~/.oat/config.json (user-level fallback, applies across all repos)

When no flag is passed, the CLI picks a sensible default per key type: structural keys (projects.root, documentation.*, etc.) go to shared, state keys (activeProject, etc.) go to local, workflow preferences (workflow.*) go to local. Pass at most one flag — the command rejects multiple surface flags.

Per-key restrictions apply identically to set and unset: structural keys can only be written at shared scope, most state keys can only be written at local scope (activeIdea is the exception — it accepts both local and user), and workflow preference keys accept any non-auto surface. Legacy autoReviewAtCheckpoints remains shared-only; prefer workflow.autoReviewAtHillCheckpoints.

oat config unset <key> removes the key from the selected surface and prunes any parent object it empties, so the resolved value falls back through the remaining surfaces to the built-in default. Removing a key the surface does not hold is not an error: it reports an already-unset outcome and exits 0. With --json the envelope adds a removed boolean, which is the machine-readable way to tell a real removal from an already-unset no-op, since both exit 0. A stored value that fails validation is still removed, matching oat config set, which repairs the same file.

Remote settings under pjm.remote.* remain shared-only. Removing a mutable leaf preserves sibling settings and the required empty policy object, if necessary, so the remaining remote configuration stays readable. Explicit defaults are removed from disk rather than silently written back by normalization; effective values still use fail-closed defaults. Remote policy must pass strict validation before removal.

unset refuses six classes of key, each with exit code 1:

  • Unknown keys, including keys OAT reads but does not expose in the oat config catalog (documentation.index). These are not removable by any oat config command.
  • Lifecycle state (activeProject, lastPausedProject) — cleared with oat config set <key> '' instead.
  • Pack intent (tools.*) — removed with oat tools remove --pack <pack> --scope project, which also removes the installed pack files. Clearing the intent alone would leave them behind.
  • Aggregate read views (workflow.dispatchCeiling, workflow.dispatchCeiling.providers) — these are assembled for get from the leaf keys and are not stored as such. Unset workflow.dispatchCeiling.preset or workflow.dispatchCeiling.providers.<provider> instead.
  • Read-only remote-policy structure (pjm.remote, pjm.remote.policy, pjm.remote.schemaVersion) — unset a documented mutable child key instead; removing the complete policy or its schema discriminator is not supported.
  • Environment-shadowed keys with nothing stored on the target surface — when OAT_PROJECTS_ROOT, OAT_PROJECTS_DEFAULT_SCOPE, or OAT_WORKTREES_ROOT supplies the effective value and the surface holds nothing to remove, clear the environment variable in your shell. When the surface does hold a stored value, unset removes it (as set would rewrite it) and warns that the override still supplies the effective value.

workflow.* preference keys

The workflow.* namespace holds user-facing workflow preferences that let you answer repetitive confirmation prompts once and have OAT skills respect the answer automatically. Common keys:

  • workflow.hillCheckpointDefault (every | final) — default HiLL checkpoint behavior in oat-project-implement
  • workflow.archiveOnComplete (boolean) — skip the archive prompt in oat-project-complete
  • workflow.createPrOnComplete (boolean) — skip the "Open a PR?" prompt in oat-project-complete
  • workflow.postImplementSequence (legacy wait | summary | pr | docs-pr, or structured {preApproval, postApproval} arrays) — approval-aware post-implementation chaining
  • workflow.reviewExecutionModel (subagent | inline | fresh-session) — default final-review execution model
  • workflow.autoReviewAtHillCheckpoints (boolean) — auto-run the extra lifecycle review at HiLL checkpoints
  • workflow.autoNarrowReReviewScope (boolean, default true) — automatically narrow re-reviews to the guarded range after the prior matching review's recorded head; set false to use the nominal full scope
  • workflow.autoArtifactReview.plan (boolean, default true) — auto-run the bounded plan.md artifact-review loop before implementation handoff
  • workflow.autoArtifactReview.analysis (boolean, default true) — auto-run the bounded accuracy-review loop for generated analysis artifacts before apply workflows consume them
  • workflow.gateTimeouts.code / workflow.gateTimeouts.artifact (integer milliseconds from 1,000–14,400,000) — review-type budget defaults below CLI and target overrides

These workflow keys resolve through config files and defaults (local > shared > user > default). Some config keys have explicit environment aliases, but workflow.autoArtifactReview.plan and workflow.autoArtifactReview.analysis do not. See Workflow preferences in the Configuration guide for full descriptions, surface guidance, and cross-repo foot-gun examples.

On this page