Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,68 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.5] - 2026-07-11

### Added

- Receiver autonomy supports sender-marked `oacp-guardrails` fences, negation
fallback, declaration-aware lexical advisories, and a pinned reason-code
taxonomy backed by executable conformance fixtures.
- `external_side_effects: allow_pr_artifacts` permits declared PR, review, and
issue-comment artifacts only for receiver-allowlisted private repositories,
while retaining pre-approval for public/unlisted artifacts, direct main
pushes, merges, deploys, and publishes.
- Autonomy audit output records the full declared task profile, an explicit
breach list, a semantic policy hash, and a shared outcome block including
completion time and materialized-risk telemetry.
- Default-off standing continuation grants now resolve from an explicit prior
human approval in the same conversation thread; sender-declared grant data
alone cannot authorize follow-up scope.
- `oacp autonomy-outcome` atomically records structured approval, modification,
decline, latency, and grant-decision telemetry in schema-v2 autonomy audits.
The subcommand is exposed by the installed CLI starting with this release.
- Envelope compilation: `oacp envelope compile|show|clear`
turns an admitted message's `task_profile` plus receiver config into a
runtime envelope (`active_envelope.json`), enforced at the tool-call layer
by a static Claude PreToolUse hook (`oacp-envelope-hook`, registered once
by `oacp setup claude`). Compilation is fail-closed
(`envelope_compile_error`), envelope drift denies with the canonical
threshold-checkpoint opener, unclassifiable calls escalate to `ask`, and
the audit outcome block records `envelope_enforcement: hooks | none`.
Contract pinned by executable fixtures under `tests/conformance/envelope/`.
- The security policy documents the Tier-1.5 trust ceiling for single-OS-user
hosts: `from` fields are unauthenticated traceability today, future optional
signing would add tamper-evidence and provenance but not same-host
anti-impersonation, and hard isolation requires separate OS users,
containers, or hosts.

### Changed

- The versioning guide documents the staged release pipeline end to end,
replacing the retired single-repo flow.
- Documentation examples and conformance fixtures use neutral example
repository slugs.
- The standard `auto_review` estimate cap is 45 minutes; estimates above 45
still pause and the five-file cap remains unchanged.
- Pricing and commercial matches remain hard pauses but now use the separate
`hard_stop_content_sensitivity` category.
- Follow-up declarations outside a standing grant's time, file, or side-effect
scope re-pause before work begins.

### Fixed

- `doctor --memory` now forwards bounded network timeouts to remote Git fetches
without breaking custom runners that implement the original command interface.
- The MCP stdio coordinator now converts unexpected request exceptions into
structured `-32603` responses instead of crashing the server.
- Undeclared runtime side effects now produce `declaration_error` at the
threshold checkpoint instead of silently completing outside the profile.
- Message validation now accepts and type-checks the six documented
review-loop telemetry fields: `model`, `turns`, `input_tokens`,
`output_tokens`, `wall_time_s`, and `est_cost_usd`.
- Receiver config and doctor validation share one repository-slug regex instead
of maintaining duplicate definitions.

## [0.3.4] - 2026-06-11

### Fixed
Expand Down Expand Up @@ -192,6 +254,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Checkout step in github-release workflow job (#19)
- Pre-release audit fixes: SHA-pinned actions, dangling doc refs (#15, #16)

[0.3.5]: https://github.com/kiloloop/oacp/compare/v0.3.4...v0.3.5
[0.3.4]: https://github.com/kiloloop/oacp/compare/v0.3.3...v0.3.4
[0.3.3]: https://github.com/kiloloop/oacp/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/kiloloop/oacp/compare/v0.3.1...v0.3.2
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ When running inside a configured agent runtime, `--from` can be omitted β€” OACP

## Coming from `claude -p`?

`claude -p` runs an agent synchronously and headless β€” your script blocks while it works, and as of June 15 programmatic usage draws from a separate metered credit.
`claude -p` runs an agent synchronously and headless β€” your script blocks while it works, and there's no session to glance at, attach to, or steer mid-run.

OACP routes the same work to a **standing interactive Claude Code session** instead: `oacp send` queues the task, the session picks it up and runs it async, you're not blocked β€” and because it's a real interactive session, it stays on your subscription.
OACP routes the same work to a **standing interactive Claude Code session** instead: `oacp send` queues the task, the session picks it up and runs it async, you're not blocked β€” and the session is right there to watch and steer. Once tasks are messages, review loops, handoffs, and multi-agent coordination come with the shape.

**[From `claude -p` to an interactive Claude Code session β†’](docs/from-claude-p.md)** β€” paste-into-your-agent setup, the honest tradeoffs, and where it fits.

Expand Down
15 changes: 15 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ OACP is a file-based coordination protocol. Security considerations include:
- **Script injection** β€” Report any case where user-controlled input in message fields can lead to command injection via OACP scripts.
- **Path traversal** β€” Report any case where message fields or script arguments can read or write files outside the intended directories.

### Trust ceiling on shared hosts (Tier 1.5)

On a single-OS-user host, OACP cannot *cryptographically prevent* one agent
from impersonating another, because key-read access and inbox-write access
collapse to the same uid. Today, `from` fields are unauthenticated and provide
traceability only β€” not identity assurance. Message signing (an optional
extension under design, not yet implemented) would add tamper-evidence and
third-party-verifiable identity provenance for honest agents; it would still
not provide same-host anti-impersonation. Hard inter-agent isolation requires
one OS user per agent (Tier-2), containers, or separate hosts with enforced
access controls. Hardware-backed keys can strengthen future signing identity
assurance, but they do not isolate a shared filesystem or process space. Treat
any `from` field on a shared host as **provenance, not an anti-spoofing
guarantee.**

## Acknowledgments

We appreciate responsible disclosure and will credit reporters in release notes (unless you prefer to remain anonymous).
7 changes: 6 additions & 1 deletion SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ Messages are YAML files. Filename convention: `<timestamp>_<from>_<type>.yaml`
| `subject` | string | Subject line |
| `body` | string | Message content (multi-line markdown) |

**Optional fields:** `expires_at`, `channel`, `autonomy_hint`, `related_packet`, `related_pr`, `conversation_id`, `parent_message_id`, `context_keys`
**Optional fields:** `expires_at`, `channel`, `autonomy_hint`, `related_packet`,
`related_pr`, `conversation_id`, `parent_message_id`, `context_keys`, plus the
review-loop telemetry fields `model`, `turns`, `input_tokens`, `output_tokens`,
`wall_time_s`, and `est_cost_usd`

`autonomy_hint` is an advisory sender hint, such as `auto_proceed`. Receivers
remain authoritative: local autonomy config, message content, safety defaults,
Expand All @@ -88,6 +91,8 @@ interactive human confirmation.

Receiver autonomy is defined by `agents/<receiver>/config.yaml` and the
scope-envelope contract in [`docs/protocol/autonomy.md`](docs/protocol/autonomy.md).
Sender-marked `oacp-guardrails` body fences and the 45-minute standard
`auto_review` cap are defined there as well.

### Message Types

Expand Down
28 changes: 14 additions & 14 deletions docs/from-claude-p.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# From `claude -p` to an interactive Claude Code session

On June 15, programmatic Claude usage β€” `claude -p`, the Agent SDK, Claude Code GitHub Actions, third-party tools β€” moves onto a separate metered monthly credit. Interactive Claude Code and chat stay on your subscription, unchanged.
`claude -p` is how most people first script a Claude agent. It works β€” but if you run agents in automation, it's worth asking a question the one-liner never forces: **why is the agent headless and synchronous in the first place?**

It's a reasonable change: programmatic usage is heavier and burstier than a person typing. But if you run agents in automation, it's worth asking a different question than "how do I dodge the meter" β€” **why is the agent headless and synchronous in the first place?**
(A pricing footnote, since earlier versions of this page led with it: Anthropic explored moving programmatic usage β€” `claude -p`, the Agent SDK, Claude Code GitHub Actions β€” onto a separate metered credit, but paused that change before it took effect; per the June 15 announcement no such credit exists, subscription limits are unchanged, and advance notice is promised before any future version.)

This guide is built to be handed to your agent. Read the first half for the *why*; paste the setup block into your Claude Code session for the *how*.

> **Setup is a one-time ~5 minutes. Every task after that is one `oacp send` β€” async, non-blocking, on your subscription.**
> **Setup is a one-time ~5 minutes. Every task after that is one `oacp send` β€” async, non-blocking, observable.**

## The shape of `claude -p`

`claude -p "do X"` is synchronous and headless:

- it **blocks** β€” your script waits for the agent to finish
- it runs **headless** β€” no session to glance at, attach to, or steer mid-run
- after June 15, it's **metered** β€” programmatic usage draws from the separate credit pool
- it's **one-shot** β€” one prompt in, one result out; there's no queue behind it, and coordinating several calls is your script's problem

That shape was always a compromise. You wanted to script an agent, and `claude -p` was the way to do it from a shell. Synchronous-and-headless came along for the ride.

Expand All @@ -24,10 +24,10 @@ Run the agent as a **standing interactive Claude Code session**, and *send* it w

```
Before: claude -p "do X"
blocks Β· headless Β· metered after Jun 15
blocks Β· headless Β· one-shot

After: oacp send β†’ a standing interactive session picks it up
async Β· you're not blocked Β· on your subscription
async Β· you're not blocked Β· a session you can watch
```

Concretely β€” the call that replaces `claude -p "do X"`:
Expand All @@ -39,23 +39,23 @@ oacp send my-project --from sender --to claude --type task_request \

Same prompt, different delivery. The text you'd have handed to `claude -p` becomes the message `--body`; `oacp send` drops it in the interactive session's inbox, and the session picks it up and runs it. Sending the prompt as an OACP message is the whole trick β€” it routes the work into a session running in interactive mode instead of a headless `claude -p` call.

The session is a real interactive Claude Code session β€” so it stays on your subscription. You're not spoofing interactive mode; you're using it, and feeding it a queue.
The session is a real interactive Claude Code session β€” you're not spoofing interactive mode; you're using it, and feeding it a queue.

This isn't only about the credit. Async is the right shape for most automation β€” a build, an overnight refactor, a research job β€” none of it needs your script to sit and wait. And once tasks are messages in an inbox, you get real multi-agent coordination β€” review loops, handoffs, several agents on one project β€” instead of a pile of blocking shell calls.
Async is the right shape for most automation β€” a build, an overnight refactor, a research job β€” none of it needs your script to sit and wait. And once tasks are messages in an inbox, you get real multi-agent coordination β€” review loops, handoffs, several agents on one project β€” instead of a pile of blocking shell calls.

## Your options, honestly

Two real choices if June 15 affects you.
Two real choices.

**1. Pay the metered credit (or API rates).** Simplest. Low programmatic volume β€” the included credit may cover you; past that it's API pricing. Already on the API β€” nothing changes. No new tooling; it just costs money at scale.
**1. Keep `claude -p`.** Simplest. It's one line, it works, and nothing about your setup changes. If your automation is a single blocking call and you never need to see inside it, this is fine.

**2. OACP β€” run interactive for real, feed it a queue.** Run a real interactive Claude Code session and send it work. It stays on your subscription because it genuinely *is* an interactive session. Not a one-liner β€” it's a workflow change. In exchange you get real agent coordination, not just a credit workaround.
**2. OACP β€” run interactive for real, feed it a queue.** Run a real interactive Claude Code session and send it work. Not a one-liner β€” it's a workflow change. In exchange you get async dispatch, a session you can watch and steer, and real agent coordination.

Option 1 is the no-effort path that costs money at volume. Option 2 is a one-time workflow change that doesn't. Pick on that.
Option 1 is zero effort and stays synchronous, headless, one-shot. Option 2 is a one-time workflow change that removes all three. Pick on that.

## What OACP is

OACP isn't a June-15 tool. It's a file-based protocol for coordinating AI agents β€” inbox/outbox messaging, structured review loops, shared memory β€” no server, no daemon, just files in a directory. It was built to run a multi-agent fleet; the `claude -p` transition is **one usage** of it. Full picture: the [README](../README.md) and [SPEC](../SPEC.md). The companion [oacp-skills](https://github.com/kiloloop/oacp-skills) repo packages the runtime guidance β€” skills that teach Claude, Codex, and other agents to operate the protocol.
OACP isn't a `claude -p` replacement tool. It's a file-based protocol for coordinating AI agents β€” inbox/outbox messaging, structured review loops, shared memory β€” no server, no daemon, just files in a directory. It was built to run a multi-agent fleet; the `claude -p` swap is **one usage** of it. Full picture: the [README](../README.md) and [SPEC](../SPEC.md). The companion [oacp-skills](https://github.com/kiloloop/oacp-skills) repo packages the runtime guidance β€” skills that teach Claude, Codex, and other agents to operate the protocol.

## Set it up β€” paste this into your agent

Expand Down Expand Up @@ -142,7 +142,7 @@ oacp-do() {

**Request-response callers** β€” CI doing `RESULT=$(claude -p ...)` and using the output inline. Works too, but not a one-liner: the caller also arms `oacp watch --agent sender` to catch the reply. Worth it for a real pipeline β€” just know it's more than a swap.

**If you just want zero workflow change** and don't care about coordination β€” keep `claude -p` and pay the meter (option 1). OACP earns its setup cost when you have more than one agent, recurring work, or you want to see and steer what the agent is doing. If that's not you, we'd rather say so.
**If you just want zero workflow change** and don't care about coordination β€” keep `claude -p` (option 1). OACP earns its setup cost when you have more than one agent, recurring work, or you want to see and steer what the agent is doing. If that's not you, we'd rather say so.

## Try it

Expand Down
26 changes: 24 additions & 2 deletions docs/guides/doctor.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ No project, no config, no commit required β€” just install and run.

## What doctor checks

Doctor organizes its output into five categories. When run without `--project`, only the first category (Environment) runs. With `--project <name>`, all five categories are evaluated.
Doctor organizes its output into six categories. When run without `--project`, only the first category (Environment) runs. With `--project <name>`, all six categories are evaluated.

### 1. Environment

Expand Down Expand Up @@ -50,7 +50,19 @@ Validates YAML files against protocol expectations.
- **packets/** β€” parses all `.yaml`/`.yml` files and reports syntax errors
- **status.yaml** β€” checks required fields (`runtime`, `status`, `capabilities`, `updated_at`), validates enum values, and verifies timestamp format

### 5. Agent Status
### 5. Autonomy

Validates each agent's receiver-autonomy setup (see `docs/protocol/autonomy.md`).

- **config.yaml** β€” validates `autonomy.default_mode`, `auto_review_thresholds`
(numeric + policy keys, including `external_side_effects: pause |
allow_pr_artifacts | allow`), `allow_without_task_profile` entries, and
receiver-controlled `private_repo_allowlist` entries, and
`continuation_grants`; an absent config is fine (defaults to `always_pause`)
- **audit directory** β€” warns if `agents/<agent>/audit/autonomy_decisions/` is missing
- **orphaned policy refs** β€” warns when an audit event's `policy_path` points at a config file that no longer exists

### 6. Agent Status

Checks each agent's `status.yaml` for presence and freshness.

Expand Down Expand Up @@ -104,6 +116,14 @@ $ oacp doctor --project my-project
[+] claude/status.yaml β€” valid
[+] codex/status.yaml β€” valid

[!] Autonomy
[+] claude/audit/autonomy_decisions β€” present
[+] claude/config.yaml β€” valid
[+] claude/autonomy audit β€” no orphaned policy refs
[!] codex/audit/autonomy_decisions β€” missing
mkdir -p $OACP_HOME/projects/my-project/agents/codex/audit/autonomy_decisions
[+] codex/config.yaml β€” absent; defaults to always_pause

[!] Agent Status
[+] claude/status.yaml β€” present
[!] codex/status.yaml β€” stale (updated 26h ago)
Expand Down Expand Up @@ -179,6 +199,8 @@ oacp doctor # environment checks only
oacp doctor --project <name> # full workspace + agent checks
oacp doctor --json # machine-readable JSON output
oacp doctor --project <name> --json # full checks in JSON format
oacp doctor --project <name> --fix # auto-fix safe issues (missing inbox dirs, missing/stale status.yaml)
oacp doctor --memory # advisory checks for OACP_HOME memory git sync
oacp doctor -o report.txt # save report to file
```

Expand Down
1 change: 0 additions & 1 deletion docs/guides/prompt_caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ Codex CLI sends the full prompt to the Codex API on each invocation. There is no

4. **Lean on diff-only context**
- For PR fix loops, pass the diff + findings rather than full file contents
- `run_agent_task.sh` already scopes context to changed files

## Gemini

Expand Down
Loading