Skip to content

CLI Reference

The oacp CLI provides commands for workspace management, inbox messaging, monitor-friendly inbox watching, agent profiles, memory archiving and opt-in cross-machine memory git sync, and environment health checks.

Version: This reference reflects the latest published release. See the Changelog for what’s new in each version.

Create a new project workspace under $OACP_HOME/projects/.

Terminal window
oacp init <project-name> [--agents <list>]

Scaffolds a complete OACP workspace with agent directories, shared memory files, and packet storage. The project name must be a valid directory name (lowercase alphanumeric and hyphens). --agents is a comma-separated list of runtimes to create — it defaults to claude,codex,cursor (since v0.3.2). Gemini remains supported: pass --agents claude,codex,gemini or add it later with oacp setup gemini.

$OACP_HOME/projects/<project-name>/
├── agents/
│ ├── claude/
│ │ ├── inbox/
│ │ │ └── archive/
│ │ ├── outbox/
│ │ └── dead_letter/
│ ├── codex/
│ │ └── ...
│ └── cursor/
│ └── ...
├── memory/
│ ├── project_facts.md
│ ├── decision_log.md
│ ├── open_threads.md
│ ├── known_debt.md
│ └── archive/
├── packets/
│ ├── review/
│ └── findings/
├── merges/
└── workspace.json

oacp add-agent --runtime creates both status.yaml and agent_card.yaml for the new agent. oacp doctor --fix creates or refreshes status.yaml only.

VariableDescriptionDefault
OACP_HOMERoot directory for all OACP projects~/oacp

If OACP_HOME is not set, it defaults to ~/oacp. The directory is created automatically if it does not exist.

Terminal window
export OACP_HOME=~/oacp
oacp init billing-service
# Created workspace at ~/oacp/projects/billing-service/

Send a protocol-compliant inbox message to another agent.

Terminal window
oacp send <project> --to <recipient> --type <type> \
--subject <subject> --body <body> [--from <sender>]

Composes a YAML message file and writes it to the recipient’s inbox/ directory. A copy is saved in the sender’s outbox/. The message is assigned a unique ID and timestamp automatically.

FlagRequiredDescription
--fromNoSender agent name. Optional when sender can be inferred (see below)
--toYesRecipient agent name
--typeYesMessage type (see Message Types)
--subjectYesShort subject line
--bodyYes*Message body (inline). Required unless --body-file is used.
--body-fileNoRead message body from a file instead of --body
--priorityNoPriority level: P0, P1, P2, P3 (default: P2)
--parent-message-idNoID of the message being replied to, for threading
--conversation-idNoConversation thread ID
--related-prNoRelated pull request number
--dry-runNoPrint the YAML message without writing files
--jsonNoOutput result as JSON
--quietNoSuppress success output

When --from is omitted, OACP resolves the sender using this precedence chain:

  1. --from flag (explicit)
  2. OACP_AGENT environment variable
  3. AGENT_NAME environment variable
  4. Agent card runtime match — if exactly one agent in the project has an agent_card.yaml whose runtime field matches the detected runtime, that agent is used

If none of these resolve to a sender, the command exits with an error.

The --type flag accepts any of the 12 defined message types: task_request, question, notification, follow_up, handoff, handoff_complete, review_request, review_feedback, review_addressed, review_lgtm, brainstorm_request, brainstorm_followup.

See Message Types for details on each type.

Terminal window
# Explicit sender
oacp send my-project \
--from claude \
--to codex \
--type review_request \
--priority P1 \
--subject "Review auth middleware PR" \
--body "PR #42 adds JWT validation to the API gateway."
# Inferred sender (inside a configured agent runtime)
oacp send my-project \
--to codex \
--type notification \
--subject "Done" --body "Task completed."

This writes a YAML file to the recipient’s inbox and saves a copy to the sender’s outbox. The message gets a unique ID in the format msg-<YYYYMMDDHHmmss>-<sender>-<rand>.


Check environment and workspace health.

Terminal window
# Global health check
oacp doctor
# Project-specific check
oacp doctor --project <name>
# Auto-fix common issues
oacp doctor --project <name> --fix

Runs a series of diagnostic checks and reports pass/fail status for each, similar to flutter doctor. Use the global form to verify your environment is set up correctly. Use --project to validate a specific workspace’s structure and configuration.

FlagDescription
--projectCheck a specific project workspace
--fixAuto-fix missing inbox directories and regenerate missing or stale status files
--memoryRun advisory checks for $OACP_HOME memory git sync (since v0.3.0)
--jsonOutput a machine-readable JSON report
--outputSave the report to a file (in addition to stdout)
--oacp-dirOverride $OACP_HOME directory

Global checks (always run):

CheckWhat It Verifies
Python versionPython 3.9+ is installed and on PATH
Required packagespyyaml is importable
OACP_HOMEEnvironment variable is set and the directory exists

Project checks (with --project):

CheckWhat It Verifies
Workspace structureagents/, memory/, packets/ directories exist
Agent directoriesEach agent has inbox/ and outbox/ subdirectories
Memory filesproject_facts.md, decision_log.md, open_threads.md, known_debt.md are present
workspace.jsonFile exists and contains valid JSON
Trust root (since v0.4.0)Receiver pins and the project catalog load and pass integrity checks; pinned-but-not-cataloged identities warn; cataloged-but-unpinned identities surface as the catalog-not-pinned advisory, escalating to warn when the identity is live
Signing readiness (since v0.4.1)Trust-pin completeness per receiver — every catalog identity must carry an active pin before a receiver flips signing.verify_mode to enforce, with gaps broken down per receiver
Policy-file authorization (since v0.4.2)Per-receiver signature status of config.yaml and trust/allowed_signers.yaml, loaded through the authorized policy loader — signed, unsigned, or invalid (an enrolled target without a verifiable signature reports invalid, never unsigned)
$ oacp doctor
[ok] Python 3.12.4
[ok] pyyaml 6.0.2
[ok] OACP_HOME=/Users/you/oacp
[ok] 2 projects found
$ oacp doctor --project billing-service
[ok] workspace.json valid
[ok] agents/ — 3 agents configured (claude, codex, cursor)
[ok] memory/ — all required files present
[ok] packets/ — review/ and findings/ exist
$ oacp doctor --project billing-service --fix
[fix] Created missing inbox/ for agent cursor
[fix] Regenerated stale status.yaml for agent codex
$ oacp doctor --memory
[ok] memory marker present: ~/oacp/.oacp-memory-repo
[ok] allowlist matches canonical .gitignore
[ok] working tree clean, in sync with origin/main
[warn] last commit was 14 days ago — consider running `oacp memory push`

Validate an inbox or outbox YAML message against the protocol schema.

Terminal window
oacp validate <path-to-message.yaml>

Parses a YAML message file and checks it against the OACP message schema. Reports any missing required fields, invalid values, or format violations. Exits with code 0 on success, code 1 on validation failure.

ValidationDescription
Required fieldsid, from, to, type, priority, created_at_utc, subject, body are present
Type validitytype is one of the 12 defined message types
Timestamp formatcreated_at_utc is valid ISO 8601 UTC (e.g., 2026-03-13T14:30:00Z)
Priority valuespriority is P0, P1, P2, or P3
ID formatid follows msg-<timestamp>-<sender>-<rand> convention
Terminal window
$ oacp validate ~/oacp/projects/my-project/agents/codex/inbox/20260313T1430Z_claude_task_request.yaml
[ok] Message is valid.
$ oacp validate bad-message.yaml
[error] Missing required field: subject
[error] Invalid type: "request" (expected one of: task_request, question, ...)

List pending inbox messages for one or all agents in a project.

Terminal window
oacp inbox <project> --agent <name>
oacp inbox <project> --all
oacp inbox <project> --agent <name> --json

Scans an agent’s inbox directory for YAML message files and displays a summary table with sender, type, priority, subject, and age. Use --all to see inboxes for every agent in the project. Use --json for machine-readable output.

Since v0.4.2, the lister reads each message through the shared receive boundary — one verified bounded snapshot per file. Under signing.verify_mode: enforce, an unverified message surfaces as a held row built from filesystem metadata only (no message field is parsed or displayed); under warn, rows carry the verification status. See Message Signing.

FlagDescription
--agentList messages for a specific agent (mutually exclusive with --all)
--allList messages for all agents in the project
--jsonEmit JSON output instead of a table
--oacp-dirOverride $OACP_HOME directory
$ oacp inbox my-project --agent claude
INBOX: claude (my-project) — 2 messages
| # | From | Type | Priority | Subject | Age |
|---|-------|--------------|----------|-----------------------------|-----|
| 1 | iris | task_request | P1 | Update docs for v0.2.0 | 3h |
| 2 | codex | review_lgtm | P2 | Re: Review auth middleware | 1d |
$ oacp inbox my-project --all --json
{
"project": "my-project",
"mode": "all",
"agents": [
{ "agent": "claude", "message_count": 2, "messages": [...] },
{ "agent": "codex", "message_count": 0, "messages": [] }
]
}

Emit inbox delta events for one agent — designed for Claude Monitor or shell loops that re-run the command.

Terminal window
oacp watch --agent <name> --project <project> [--project <project> ...]
oacp watch --agent <name> --all-projects
oacp watch --agent <name> --project <project> --json

oacp watch scans an agent’s inbox(es), persists state between runs, and prints one structured line per new event since the last run. Each invocation is short-lived: emit, persist, exit. Run it under a process supervisor or a shell loop to keep watching.

By default — since v0.2.3 — the first run for a target uses --since=now, so existing inbox messages are not replayed as NEW_MESSAGE events. message_archived events are also suppressed unless --show-archived is passed.

For concurrent watchers of the same inbox — for example, several Claude sessions each running their own oacp watch — pass a stable per-subscriber --state-id (since v0.3.3). Each --state-id gets an independent cursor file, so every watcher receives every new-message event instead of sharing one cursor and swallowing each other’s events.

Since v0.4.2, the emitter reads each message through the shared receive boundary. Under signing.verify_mode: enforce, an unverified message emits a held event built from filesystem metadata only; under warn, events carry the verification status. See Message Signing.

FlagDescription
--agentRequired. Agent inbox name to watch
--projectProject to scan (repeatable for multi-project watch)
--all-projectsAuto-discover all projects that contain this agent’s inbox
--state-idPer-subscriber cursor file (state/watch/<agent>.<id>.json). Lets concurrent watchers of the same inbox each receive every event instead of sharing a cursor. Omit for the legacy shared cursor. Since v0.3.3
--sinceFirst-run baseline cutoff. now (default), epoch, relative (30s, 5m, 2h, 7d), or ISO 8601 (2026-04-26T00:00:00Z). Only applies on the first run for a target
--show-archivedEmit message_archived events when messages disappear from the inbox. Off by default — when the watching agent is the inbox owner, deletes are self-loops
--jsonEmit JSON Lines instead of plain NEW_MESSAGE lines
--oacp-dirOverride $OACP_HOME directory

--project and --all-projects are mutually exclusive — pass one or the other.

Plain mode (default) emits one line per event:

NEW_MESSAGE project=my-project type=task_request priority=P1 Update docs for v0.3.0
message_archived project=my-project id=msg-20260427T1430Z-claude-a8f3

JSON mode (--json) emits one JSON object per line with full message metadata.

Terminal window
# Continuous watch under a shell loop — replay existing messages first time
while true; do
oacp watch --agent claude --all-projects --since=epoch || true
sleep 120
done
# Notification-friendly default — no replay, no archive noise
oacp watch --agent claude --all-projects
# Observer agent watching another agent's deletes
oacp watch --agent claude --project audit --show-archived

Prune message history across a project (since v0.4.3).

Terminal window
oacp retention <project> [--oacp-dir <dir>] [--dry-run] [--json]

Prunes outbox/, dead_letter/, and processed inbox/archive/ files when a target exceeds either an age or a count bound — defaults 30 days and 1,000 files per target, with validated partial overrides in workspace.json. --dry-run reports the eligible files without deleting them (add --json for deterministic JSON output; both flags apply to real runs too). Before each removal, the pruner re-checks the file’s identity (inode, size, and modification time) and skips any file that changed or disappeared since the scan.

Inside dead_letter/, quarantine evidence is protected from automatic pruning by its durable filename format, and a manually managed dead-letter fixture can be kept with an adjacent .retain marker. Processed inbound messages have one cross-runtime archive destination, inbox/archive/, preserving the original filename and bytes — see Inbox / Outbox.


Manage global agent profiles. Subcommands: init, show, list.

Terminal window
oacp agent init <name> --runtime <runtime>

Scaffold a global agent profile at $OACP_HOME/agents/<name>/profile.yaml. Valid runtimes: claude, codex, cursor, gemini, human.

Terminal window
oacp agent show <name> [--project <project>]

Print the merged agent profile as YAML. Without --project, shows the global profile only. With --project, merges the global profile with the project-level agent_card.yaml — project fields override global fields (shallow dict merge, list replacement).

Terminal window
oacp agent list [--project <project>]

List known agents with their scope tags (global, project, or both).

$ oacp agent init alice --runtime claude
Created global profile: ~/oacp/agents/alice/profile.yaml
$ oacp agent list --project billing-service
alice (global, project)
codex (project)
$ oacp agent show alice --project billing-service
name: alice
runtime: claude
capabilities:
tools: [shell_access, git_ops, github_cli]
...

Archive, restore, and git-sync project and org memory files.

Subcommands fall into two groups:

  • Archive layer (since v0.1.9): archive, restore — manage the per-project active vs. archived memory split.
  • Git sync (since v0.3.0): init, clone, pull, push, disable — opt-in cross-machine sync of $OACP_HOME memory via a plain git repo.

For the protocol-level overview of how memory works across agents, projects, and machines, see Shared Memory.

Memory sync uses three states, gated by the presence of $OACP_HOME/.oacp-memory-repo:

StateTriggerBehavior
DisabledNo markerLifecycle hooks no-op silently. oacp doctor --memory reports not configured.
Local-onlyoacp memory init (no --remote)Wrap-up commits memory locally for audit history. No remote, no push.
Syncedoacp memory init --remote <URL> or oacp memory clone <URL>Session start pulls fast-forward updates. Wrap-up commits and pushes.

The git repo at $OACP_HOME tracks only:

  • $OACP_HOME/org-memory/**
  • $OACP_HOME/projects/*/memory/**

agents/ runtime state, inbox messages, and status.yaml are not synced — see the SPEC for the full rationale and .gitignore allowlist.

Terminal window
oacp memory archive <project> <memory-file> [--dry-run] [--json]

Move a memory file from the active working set (memory/) into memory/archive/. Useful for decluttering the active memory directory without deleting historical context.

Terminal window
oacp memory restore <project> <archived-file> [--dry-run] [--json]

Restore an archived memory file back to the active working set. The <archived-file> argument must be the timestamp-prefixed filename (e.g., 20260320T143000Z_research_notes.md), not the original basename.

Terminal window
oacp memory init [--remote <url>] [--oacp-dir <dir>]

Initialize the $OACP_HOME memory git repo: writes the canonical .gitignore allowlist, creates the .oacp-memory-repo marker, configures the optional remote, and makes the initial commit. Local-only without --remote; Synced with --remote <url>.

Terminal window
oacp memory clone <url> [--force] [--oacp-dir <dir>]

Clone an existing memory repo into $OACP_HOME. Refuses to clone into a non-empty target unless --force is passed, in which case the existing directory is moved aside (not deleted).

Terminal window
oacp memory pull [--oacp-dir <dir>]

Advisory fetch + fast-forward-only pull. Warns loudly — but exits successfully — on dirty, ahead, behind, diverged, or fetch-failed states. Never auto-merges. Designed to run as a session-init hook.

Terminal window
oacp memory push [--oacp-dir <dir>]

Stages only the memory allowlist (.gitignore, .oacp-memory-repo, org-memory/**, projects/*/memory/**), commits as memory: <agent>@<host> <date> (N files), and pushes when a remote is configured. Warns loudly — but exits successfully — on dirty, behind, diverged, or push-failed states. Designed to run as a wrap-up / session-end hook.

Terminal window
oacp memory disable [--oacp-dir <dir>]

Removes the .oacp-memory-repo marker locally while leaving .git/ intact. Lifecycle hooks become no-ops; the local commit history is preserved and can be re-activated later by re-creating the marker.

FlagDescription
--dry-runArchive/restore only — report what would happen without moving files
--jsonArchive/restore only — emit JSON output
--remoteinit only — git remote URL for cross-machine sync
--forceclone only — move a non-empty OACP_HOME aside before cloning
--oacp-dirAll subcommands — override $OACP_HOME directory
Terminal window
# Archive layer
$ oacp memory archive billing-service research_notes.md
Archived memory/research_notes.md -> memory/archive/20260320T143000Z_research_notes.md
$ oacp memory restore billing-service 20260320T143000Z_research_notes.md
Restored memory/archive/20260320T143000Z_research_notes.md -> memory/research_notes.md
# Git sync — local-only
$ oacp memory init
Initialized memory repo at /home/you/oacp (local-only)
# Git sync — with remote
$ oacp memory init --remote git@github.com:your-org/oacp-memory.git
Initialized memory repo at /home/you/oacp (synced)
# Pull at session start, push at wrap-up
$ oacp memory pull
$ oacp memory push

Add an agent to an existing project workspace.

Terminal window
oacp add-agent <project> <agent-name> [--runtime <runtime>]

Creates the agent’s directory structure (inbox/ with its archive/, outbox/, dead_letter/) within an existing project. When --runtime is provided, also generates status.yaml and agent_card.yaml with runtime-specific defaults. Use this to add agents after initial oacp init without re-initializing the workspace.

FlagRequiredDescription
--runtimeNoAgent runtime (claude, codex, cursor, gemini). Generates status and card files when set.
--oacp-dirNoOverride $OACP_HOME directory
Terminal window
$ oacp add-agent billing-service alice --runtime claude
Added agent 'alice' to project 'billing-service'

Generate runtime-specific configuration files in a repository.

Terminal window
oacp setup <runtime> [--project <project>] [--repo-dir <dir>]

<runtime> is one of claude, codex, cursor, gemini. --project is auto-detected from .oacp if not given. --repo-dir is auto-detected from .git if not given.

Creates boilerplate config files that connect a repo to an OACP workspace. For Claude Code, this generates a CLAUDE.md snippet with the workspace path and inbox check instructions. For Codex, it generates an AGENTS.md snippet.

Cursor runtime (since v0.3.2). oacp setup cursor --project <project> provisions the project-side Cursor agent directory and writes a repo-local .cursor/rules/oacp.todo.mdc placeholder. Cursor-owned rules and memory lifecycle hooks remain deferred.

Memory lifecycle hooks (Claude, since v0.3.0). oacp setup claude also writes .claude/hooks/oacp-memory-pull.sh and registers it under SessionStart in .claude/settings.json. The hook checks for $OACP_HOME/.oacp-memory-repo first and exits silently when memory sync is not enabled — so existing workflows are unaffected on machines that have not opted in via oacp memory init. Since v0.4.3, setup no longer creates or registers an automatic SessionEnd push — explicit wrap-up is the single push path; rerunning setup removes only the exact historical generated registration and leaves any existing script or custom hooks untouched.

Codex startup hook (since v0.4.3). oacp setup codex safely merges one startup-only handler into .codex/hooks.json, wiring oacp session-init to Codex SessionStart — a bounded, truthful ordered-read manifest with optional pull-before-verify memory sync, taking the active model and cwd from the hook payload. Users review and trust the definition with /hooks. Startup file states report verified, meaning the command confirmed readability and updated status.yaml; the hook context tells Codex which files still require ordered reads.

Terminal window
$ oacp setup claude --project billing-service
Generated CLAUDE.md snippet for project 'billing-service'
Wrote .claude/hooks/oacp-memory-pull.sh
Registered hook under SessionStart in .claude/settings.json

Initialize org-level shared memory.

Terminal window
oacp org-memory init

Creates the $OACP_HOME/org-memory/ directory structure for cross-project knowledge sharing. Org memory holds decisions, rules, and events that span multiple projects. Used with oacp write-event to publish events.

$OACP_HOME/org-memory/
├── events/
├── decisions.md
├── rules.md
└── recent.md

Write an event to org-level memory.

Terminal window
oacp write-event --agent <name> --project <project> \
--type <type> --slug <slug> --body <description>

Appends an event entry to $OACP_HOME/org-memory/events/. Events capture cross-project decisions, deployments, rule changes, and other significant outcomes that other agents should know about.

FlagRequiredDescription
--agentYesAgent that produced the event
--projectYesSource project
--typeYesEvent type: decision, event, or rule
--slugYesShort identifier (used in filename)
--bodyYesOne-line description of the event
--relatedNoComma-separated cross-references (e.g., PR #42,issue #15)
--oacp-dirNoOverride $OACP_HOME directory
Terminal window
$ oacp write-event --agent claude --project billing-service \
--type decision --slug rest-api-convention \
--body "Standardized on REST for all public APIs" \
--related "PR #15"

Compile, show, or clear the runtime envelope for an admitted task (since v0.3.5).

Terminal window
oacp envelope compile <message.yaml> --receiver <agent>
oacp envelope show --project <project>
oacp envelope clear --project <project> --receiver <agent>

Turns an admitted message’s declared task_profile plus the receiver’s autonomy config into a runtime envelope at agents/<receiver>/state/active_envelope.json, enforced at the tool-call layer by a static runtime shim (for Claude Code, the oacp-envelope-hook PreToolUse hook registered once by oacp setup claude). Compile at task pickup; clear at completion. Compilation is fail-closed — a missing, unparsable, or invalid profile pauses the task with envelope_compile_error instead of executing unenforced. After a threshold-checkpoint re-authorization, recompile with --extend — it preserves the active envelope’s runtime counters; --force is the different-message restart and resets them. See Receiver Autonomy → Envelope compilation.

Since v0.4.0, oacp envelope clear executes from inside the enforced session: the hook validates the clear against the task’s newest audit record (matched by content, never by filename) and sanctions it only when the record carries a terminal result.final_state (done/error) — completed envelopes no longer strand until a human clears them. Protocol-mandated bookkeeping (audit records, the receiver’s own inbox/outbox, the runtime scratchpad) does not consume the declared expected_files_touched budget. Since v0.4.1, enforcement is session-scoped: the compiled envelope records the harness session that compiled it and no-ops for tool calls from any other session, so a concurrent interactive session in the same repository neither inherits the task’s constraints nor consumes its budget.

Since v0.4.2, the compiler refuses to compile from a message that is not signed-verified when the receiver’s signing.verify_mode is enforce, and the envelope’s message_sha256 names the verified snapshot. --audit <admission-record> handles the one deliberate non-compile: an admitted public_visibility: true task with a recorded human admission approval is stamped envelope_enforcement: none (reason public_visibility_admission_approved) instead of compiling — see Receiver Autonomy → Envelope compilation.

FlagRequiredDescription
--receiverNoReceiver agent the envelope constrains (default: claude)
--projectYes (show/clear)show/clear cannot infer the project and exit 3 without it; compile infers it only from a message path inside $OACP_HOME/projects/<project>/ — otherwise required there too
--configNocompile only — receiver config path (default: agents/<receiver>/config.yaml)
--auditNocompile only — admission audit record for this message; on an admitted public-visibility task with recorded human approval, the envelope is deliberately not compiled and the record is stamped envelope_enforcement: none by rule (since v0.4.2)
--extendNocompile only — recompile over an existing envelope, preserving its counters (re-authorization flow)
--forceNocompile only — overwrite an existing envelope for a different message, resetting counters
--jsonNocompile only — machine-readable output
--oacp-dirNoOverride $OACP_HOME directory
Terminal window
$ oacp envelope compile agents/claude/inbox/20260712_iris_task_request.yaml --receiver claude
# ... execute the task under hook enforcement ...
$ oacp envelope clear --project my-project --receiver claude

Record a human approval, modification, or decline on a paused autonomy audit (since v0.3.5).

Terminal window
oacp autonomy-outcome <audit.yaml> --decision <approved|modified|declined>

Writes the structured result.human_outcome block into a schema-v2 autonomy audit: the decision, actor, timestamp, decision latency computed from the audit’s created_at_utc, and the copied pause reason codes. The write is flock-guarded and atomic, and refuses to overwrite a recorded outcome unless --replace is explicit. Grant handling is separate from task approval — a task approval never silently creates a standing continuation grant. See Receiver Autonomy → Human approval and decline outcomes.

Since v0.4.0, checkpoint-paused records are accepted too — for an auto-accepted admission whose in-place threshold checkpoint breached, latency is measured from the checkpoint’s paused_at_utc rather than admission time. The actor convention is pinned: one canonical, whitespace-free handle per human, fleet-wide (the anonymous default human warns), so cross-receiver outcome analytics can attribute decisions.

FlagRequiredDescription
--decisionYesapproved, modified, or declined
--grant-decisionNonot_requested (default), approved, modified, or denied
--grant-scope-fileNoExplicit replacement scope (required for --grant-decision modified)
--decided-atNoOverride the decision timestamp (ISO-8601 UTC)
--actorNoActor recorded in the outcome block (default: human)
--replaceNoOverwrite a previously recorded outcome
--dry-runNoCompute and print the outcome without writing the audit file
--jsonNoMachine-readable output
Terminal window
$ oacp autonomy-outcome agents/claude/audit/autonomy_decisions/20260713T191200Z_msg-....yaml \
--decision approved

Generate and inspect Ed25519 message-signing keys (since v0.4.0).

Terminal window
oacp key gen [--agent <name>]
oacp key list

oacp key gen creates a dedicated Ed25519 signing key under $OACP_HOME/keys/ (directory 0700, key files 0600 — the directory is excluded from memory sync by construction) plus a public <kid>.pub.json catalog stub for the trust-import flow. The kid is the key’s RFC 7638 JWK thumbprint. oacp key list shows local keys. Requires the optional crypto extra. Key-management and rotation semantics: Message Signing.

FlagDescription
--agentAgent name the key belongs to (inferred if omitted)
--oacp-dirOverride $OACP_HOME directory
--jsonMachine-readable output
Terminal window
$ oacp key gen --agent claude
$ oacp key list

Import, inspect, and revoke trust-root entries (since v0.4.0); sign receiver policy files (since v0.4.2).

Terminal window
oacp trust import <stub.pub.json> --project <name> --agent <receiver>
oacp trust list --project <name>
oacp trust revoke <kid> --project <name> (--agent <receiver> | --all-receivers)
oacp trust sign-policy --project <name> --agent <receiver>

oacp trust import records a <kid>.pub.json stub from oacp key gen in the project’s zero-authority distribution catalog (projects/<name>/trust/catalog.yaml — identity recorded, nothing granted) and pins it active in the receiver’s own allowed_signers.yaml, the only file consulted at verify time. Import is integrity-checked: the kid must be the RFC 7638 thumbprint of its JWK, private key components are refused, same-kid conflicts are refused, and a revoked pin is never silently reactivated. The whole catalog-then-pins transaction is serialized on a project trust lock.

oacp trust revoke handles compromise response without hand-editing trust files — it validates the canonical kid spelling, flips the pin to status: revoked while keeping key material in place, and is safely re-runnable (re-revoking reports unchanged). --all-receivers is all-or-nothing: every target is validated before any pin is written. The trust-root model behind these commands: Message Signing.

oacp trust sign-policy (since v0.4.2) signs the receiver’s config.yaml and trust/allowed_signers.yaml with the receiver’s own local key, under the distinct oacp-policy+yaml JOSE profile with {project, receiver, kind} context binding, and enrolls each target in the machine-local policy-enrollment registry — after which an unsigned policy file is invalid, never unsigned. Trust mutations on an enrolled trust root atomically re-sign it or refuse the write. See Message Signing → Policy-file signing.

FlagDescription
--projectProject workspace name (required)
--agentReceiver whose pins gain or lose the entry; for sign-policy, the receiver whose policy files are signed
--catalog-onlyimport only — record the identity in the catalog, grant no authority
--all-receiversrevoke only — revoke the kid for every receiver in the project that pins it
--kidsign-policy only — sign with this specific key only
--oacp-dirOverride $OACP_HOME directory
--jsonMachine-readable output
Terminal window
$ oacp trust import ~/oacp/keys/8eVCNRv7uT62….pub.json --project my-project --agent claude
$ oacp trust list --project my-project

Verify a message’s auth trailer against receiver-local pins (since v0.4.0).

Terminal window
oacp verify <message.yaml> --project <name> --receiver <agent>

Implements verify-before-parse: strict last-line trailer extraction from the raw bytes, bounded structural checks, EdDSA verification over the exact raw prefix against receiver-local pins only (no network at verify time), then an identity cross-check on the verified prefix. In warn mode each message is annotated as unsigned, signed-unknown-kid, signed-verified, or signed-INVALID — recorded, never rejected. Since v0.4.2, enforce has a real caller: the autonomy gate invokes this verification at message intake, where only a signed-verified message proceeds — every other outcome quarantines an evidence copy into dead_letter/ and exits 3 with an intake_rejected decision. Byte-tampered messages can be set aside with a no-clobber evidence copy in dead_letter/ via --quarantine, without touching the original. --attach-audit records the canonical result.message_auth block into an autonomy audit record — the one supported path for audit stamping. Full protocol semantics: Message Signing.

FlagDescription
--projectProject name (with --receiver)
--receiverReceiver agent whose pins are consulted
--pinsExplicit path to an allowed_signers.yaml (instead of project/receiver resolution)
--quarantineWrite an evidence copy to dead_letter/ when the result is INVALID
--attach-auditRecord the message_auth block into the given autonomy audit YAML
--oacp-dirOverride $OACP_HOME directory
--jsonMachine-readable output
Terminal window
$ oacp verify agents/claude/inbox/20260804_iris_task_request.yaml \
--project my-project --receiver claude
[oacp-auth] signed-verified signer=urn:oacp:agent:…:iris kid=8eVCNRv7uT62…