# JCP — The Joule Context Protocol A unified, energy-native, capability-secured protocol for agentic systems. Where today's stack splits across MCP (tools), A2A/ACP (agent-to-agent), an identity layer, and an authorization layer — and standardizes energy nowhere — JCP is one spec, built on one idea: > **A capability and an energy budget are the same object: a signed, bounded, > debited grant. A capability you can't pay for is denied; an expenditure you're > not capable of is denied. One check, made outside the model, sealed in a > receipt.** The design answers the documented failure modes of the current agentic ecosystem, not hypotheticals. Tool descriptions are untrusted input → JCP refuses to take control from a tool's *output*. Prompts can't enforce access control (and a more capable model only follows injected instructions *better*) → JCP decides every action in the runtime, never in the LLM. Agent loops have no cost ceiling → every grant carries a joule budget that's debited and enforced before the side effect. Audit is a mutable telemetry span → JCP seals every decision, allow and deny, as a non-repudiable signed receipt. - **Licence:** Apache-2.0 for reference code (see [`LICENSE`](LICENSE)); CC-BY-4.0 for specification text (see [`LICENSE-SPEC`](LICENSE-SPEC)). - **Status:** v0.3.0 draft. Specification core published ([`SPEC.md`](SPEC.md) + [`conformance/v1/`](conformance/v1/)); reference workspace `jcp-rs/`. ## What's here ``` jcp/ ├── SPEC.md — the normative standard (§1–§12) ├── conformance/v1/ — published vectors (a signed grant + allow/deny receipts, a replayable receipt log) ├── conformance/verify_replay.py — a second reader of that log └── jcp-rs/ — the Apache-2.0 reference implementation ``` ### The reference implementation (`jcp-rs/`) - **`jcp-schema`** — the wire objects: the `did:key` actor, the **Grant** (the metered capability — capability ⊗ joule budget, content-addressed and signed), the **Frame** (every message, with its `control`/`data` trust tag), the family `Energy`/`Provenance` model, canonical det-CBOR content addressing. - **`jcp-grant`** — issuance, signature verification, **attenuation** (object-capability delegation where a child grant can only narrow — capability ⊆, budget ≤, expiry no later, delegation depth − 1), **chain verification** (root-first, hop-by-hop: parent links, holder-issued hops, narrowing, signatures, depth bounds), **revocation** (issuer-only, signed, admitted into a `RevocationSet` only after authority checks), **sharding** (`shard()` splits a grant into siblings whose budgets must sum within the parent — distributed enforcement with no consensus, SPEC §4.5), and **identity continuity** (`KeyLog`: KERI-style pre-committed rotation, SPEC §2.1 — a thief with the current key can't rotate, an owner who lost it still can). - **`jcp-runtime`** — the deterministic enforcer. One ordered check fuses authorization and energy, decided **outside any model**: untrusted-control, revocation, **configured trust roots** (an enforcement point honors only the root-issuer keys it was configured with — `authorized_keys` shape, no CA), audience binding, signature, expiry, capability, and budget — then debit. The first failure names the reason. `decide_chained` enforces full delegation chains: a revoked ancestor kills the subtree, and the cost must fit — and is debited from — **every** link, so sibling delegations share their root's budget and delegation can never mint joules. In the two-phase path `hold` authorizes a call and places its hold in one step, and every decision counts the hold against its grant until `settle` replaces it with the call's debit, so a call decided while a held call's work runs is decided against the remainder less the hold (SPEC §8.1); `hold_chained` and `settle_chained` do the same through a delegation chain, counting the hold against every link. - **`jcp-receipt`** — the `jcp/1` JCR-1 receipt: canonical det-CBOR + COSE_Sign1/EdDSA, byte-compatible with the family verifiers. Allow and deny both seal. The receipt stream is the write-ahead log (SPEC §8.1): a receipt states what it debited where its verdict does not, and a chained receipt records `chain_ids` — every link the decision debited — so `replay_ledger` rebuilds an enforcement point's budget state exactly, in joules, money and the tainted sub-budget, **ancestors included**, from its own verified output with no external index, a hold no receipt settles restoring the most its work could debit, and `replay_mints` rebuilds each standing grant's mint ledger from the firings the stream records (SPEC §4.6); `aggregate` keys a team's receipts by `(grant, subject)` for per-worker cost attribution computed from evidence (SPEC §8.2). - **`jcp-bridge`** — a reference gateway that wraps **existing MCP tool calls and A2A tasks** in Grants and Frames without rewriting the endpoint. It maps each outbound call to a Frame (the tool/method is the action; the `(server, tool)` identity is the content-addressed resource), decides it against the caller's grant *before* the call reaches the endpoint, and seals a receipt — so an existing server keeps its transport while every call becomes capability-scoped, joule-budgeted, decided outside the model, and sealed. Inbound results are framed as untrusted `data`. - **`jcp-a2a`** — the **A2A + AP2 profile**: ingests an open [A2A](https://a2a-protocol.org) **Agent Card** (each advertised `skill` becomes a content-addressed JCP capability, bound to the `a2a::` audience) and an [AP2](https://ap2-protocol.org) payment **mandate** (its authorization, read in **joules**, becomes the grant's budget — a currency mandate yields no budget, because the profile invents no exchange rate), mints one capability-scoped joule-budgeted grant per skill, and gates every A2A task against them through the bridge. A `message/send` targeting a skill the card never advertised — or one past the AP2 budget — is denied **before** it reaches the peer, and the denial seals like an allow. The open agent-interop wire keeps its transport; JCP adds the capability, the energy budget, and the cryptographic audit it lacks. - **`jcp-policy`** — **contextual service policies**: the content-keyed, require-approval layer a static grant audience can't express. A `Policy` matches a call on its action, **content** (a secret marker, a sensitive path, a forbidden recipient), or resource and either **denies** it or **requires approval** — a human consent resolved by an Ed25519 signature over the call's context digest (which binds the **content hash**, never the content, so consent is to one exact call). The verdict composes with the grant decision — the policy is the second, content-aware gate after the capability allows — and seals as a hash-chained **`policy/1`** receipt: the allow, the deny, and the held/approved consent in one audited ledger. The "service policy" shape — allow / deny / require-approval over tool+args+identity, decided outside the model — with the joule budget (on the grant) and the cryptographic audit the incumbent's table-row log lacks. - **`jcp-orchestrate`** — a **cross-harness orchestration profile**: a deterministic reconcile loop (poll → route → dispatch → reconcile → retry) that runs work items across a *heterogeneous* fleet of `Harness` backends, where every dispatch is **capability-gated** (a harness is granted only the task kinds it may handle), **joule-budgeted** (an exhausted harness fails over to the next one with capacity), and **sealed** as a JCR-1 decision receipt *before* it runs. A task whose kind no harness is granted is denied; a flaky harness retries up to a bound; the whole run is an ordered, verifiable ledger of sealed decisions. The compose-many-harnesses shape a meta-harness offers — with the capability, energy budget, and audit it leaves to the platform. - **`jcp-prompt`** — a **signed, content-addressed prompt registry**: immutable prompt **versions** (double-brace `{{ variable }}` templates) with mutable **aliases** (`dev` / `staging` / `production`) resolved by `prompts:/@` (or `prompts://`) URIs — the registry shape the serving ecosystem already uses. The difference: each registered version and each alias **promotion** seals as a hash-chained **`prompt/1`** receipt, and a version's id *is* its template, so swapping the text under a name changes the id and re-pointing an alias is a signed entry in an ordered log. The exact instructions an agent ran under — and which version was live when — become tamper-evident artifacts, not a row someone with write access can edit. - **`jcp-trace`** — ingests an agent run's **OpenTelemetry GenAI trace** (`gen_ai.*` semantic conventions: `chat` / `tool` / `retriever` spans with token usage) and its **evaluation assessments** (judge / human / code feedback), attaches **per-span joules** (measured where a meter is present, else `Estimator` from token counts — provenance never silently upgrades), and seals one **`eval/1` JCR-1 receipt**: the per-span token + joule breakdown with the headline `uj_per_accepted_token` at the **weakest** provenance present, the assessments, a deterministic **quality-gate** verdict (the sealed, declarative analog of a CI assert), and a **readiness projection** an ARL validation-axis claim consumes. The observability stacks *record* a trace and *log* a judge score in a table; this is the interop projection that **seals** the same trace, puts a joule on it, and hash-chains it via `EvalLog` — no new cryptography. The **gate is content-addressed**, so the sealed receipt commits to exactly which bar it was judged against (a tamper-evident artifact, not a mutable in-code `assert`), and **`align_threshold` / `Judge`** calibrate a judge's decision threshold to human pass/fail labels — judge alignment as a reproducible number, not a UI click. Behind the `server` feature, a std-only **OTLP `/v1/traces` receiver** lets any OpenTelemetry exporter POST a `gen_ai.*` trace (with its assessments) and get the sealed `eval/1` receipt back the instant the run ends. - **`jcp-intercept`** — **attested interceptor chains**: a composable, ordered pipeline of transforms *around* each model and tool call — the `before_model` / `after_model` / `before_tool` seams an agent's middleware stack runs, composed onion-order (forward in, reverse out) and stopping at the first refusal or human-approval hold. An interceptor may inspect or **rewrite** the request (redact a secret before it reaches the model, trim stale context), **refuse** it, or **hold** it for a human. The difference from the incumbent's arbitrary in-process hooks: every step seals an **`intercept/1`** JCR-1 receipt carrying the request digest **before and after** the step (so a redaction or a trim is provable — the content itself never sealed, only its hash), the seam, the outcome, and the **metered joules** at their honest provenance (where the meter reads a counter, a seam pass is one reading divided among its steps by each step's thread CPU time, so the steps sum to it exactly and each share is graded `ModelBased`), hash-chained — the exact transform pipeline that produced a model request becomes reconstructable and verifiable by anyone, and a step cannot run un-sealed. Three reference interceptors — `Redact` (a content transform), `CallLimit` (a guardrail), `Approve` (a human-in-the-loop hold) — each reuse a primitive the family already holds rather than reinventing it. - **`jcp-efficiency`** — the **energy-efficiency spec**, surfaced as a sealed receipt. The dark-factory economics turn on four figures — **joules per accepted token, tokens per second, value per token, and the tokens/joules/dollars spent per COMPLETED, VERIFIED unit of work** — and the incumbents publish, at best, a *rate* (cost per token) that can't tell you whether the spend bought a result. An **`efficiency/1`** JCR-1 receipt records all four at honest provenance, hash-chained, and sealed against an **outcome anchor** (`completed` + a verdict) — goal-denominated energy accounting is a live line of work (`jcp-efficiency/MAPPING.md` §0 cites it); what the receipt adds is that the anchor is signed and verifiable rather than reported. A measurement that didn't complete is spend that bought nothing, and the receipt says so. `aggregate` then splits value-delivered from total spend across a chain — charging *every* attempt (including the failed ones) against the results actually delivered — so `tokens_per_completed_unit` / `uj_per_completed_unit` / `value_per_joule` become the honest efficiency a "cost per token" number is designed to hide. Integers and strings only (JCR-1 forbids bools/floats); the rate figures recompute from the sealed inputs on read. - **`jcp-energy`** — the metering ladder (SPEC §5.1): RAPL package counters (Linux powercap, wraparound-corrected, `HwShunt`, only while every package counter is live — `rapl_status()`), NVML GPU energy behind the `nvml` feature (`HwShunt` and `Partial`, since it does not read the CPU's share; only while live — `nvml_status()`), the macOS kernel's per-process CPU energy count (`proc_pid_rusage`'s `ri_energy_nj`; `HwShunt`, whole for in-process CPU work, only while live — `process_energy_status()`; it covers this process's threads, not children, the GPU or DRAM, so a span that reaps a child process or ends with one is `Partial`; each end of a span is read only once the metering thread is seen to have left its core, because the kernel counts a thread's energy into its process's only then, and a span with an end not so checked is the estimate, never a reading; it is live on macOS 27.0.1 where IOReport's CPU rails are not), Apple Silicon IOReport (`HwShunt`, only while every CPU energy rail, each die's on a multi-die part, is live — on macOS 27.0.1 that rail is republished in lumps, so there the rung is declined and `ioreport_status()` says why; `Meter::detect_explained()` names the rung selected and why each one above it was declined), a time×power model at a power the host calibrated (`ModelBased`, `Meter::time_power`), and estimates no host calibrated (`Estimator`): time × the documented default power — the rung `Meter::detect()` falls to, always available — and a constant per-op figure. A vendor counter's reading is real but vendor-opaque and relayed by the platform, and it counts as a reading only while the counter is live (SPEC §5). Measured when the platform exposes it, estimated when it doesn't — and the provenance always says which; a hardware backend that fails mid-reading degrades honestly to the default-power estimate. - **`jcp-gateway`** — the **energy-native MCP gateway**: a JCP enforcement point that sits in front of an MCP server so an existing client/server pair keeps its transport while every `tools/call` becomes capability-scoped, joule-budgeted, and sealed. The novel mechanic is two-phase metered enforcement: the call is *authorized* before it runs (no debit, because the cost isn't yet known, but the allow is sealed as a hold stating the most the call can debit, and written and synced before the call goes upstream, so a gateway that stops mid-call restarts with that much held, and counted against the grant until the call settles, SPEC §8.1), the upstream call is **metered** by the sibling Sandbox standard's energy probe (Apple Silicon IOReport, RAPL, NVML — vendor energy counters, whose readings are real but vendor-opaque and relayed by the platform, and which count as readings only while the counter is live for the work, SPEC §5; otherwise the figure is an estimate and is graded as one), and the metered joules are debited from the grant — so the budget that stops a runaway agent is denominated in joules, not a token estimate. Where the upstream server is a local process whose CPU energy the host's kernel counts live (macOS `proc_pid_rusage`), each call is read on that server's own process tree, the work's own process rather than the machine (SPEC §5.1, rung 3): sealed `HwShunt`, and `Whole` only when nothing was seen missing from the tree (no descendant reaped or exited in the span, no GPU client held, no in-process Neural Engine memory, every member read and quiet at both ends) and the operator has declared, with `--upstream-self-contained`, that the server hands no work to a process outside its tree; otherwise `Partial`, with the response's `_meta` naming why. Every decision, allow and deny, seals into a **hash-chained receipt log**: excise, reorder, or splice a receipt and the chain breaks at that point. A denied call never reaches the server (the live 2025–26 MCP exploits land on tool *output*, which the gateway frames as untrusted `data` that can never exercise a capability), and the `jcp-gateway` binary runs it over stdio in front of any MCP-server subprocess. This is the chokepoint the AI-gateway field occupies, on the two axes nobody there holds: the unit of account is the joule, and the audit is cryptographic and tamper-evident rather than a dollar figure and a span. - **`jcp-wire`** — the `jcp/1` wire binding (SPEC §11): 4-byte length prefix + canonical det-CBOR over any byte stream, with TCP and Unix-socket endpoints and a client. The decoder rejects non-canonical bodies, so a message has exactly one wire form. Requests carry the full delegation chain and are **caller-signed** — the endpoint authenticates from the request itself and denies an impersonation `bad-signature`, sealed like any other decision. Responses carry the deterministic decision and the sealed receipt. - **`jcp-threshold`** — threshold actors (SPEC §2.2): a `did:key` whose private key is split k-of-n with FROST (RFC 9591); the group key is an ordinary Ed25519 key, so a 2-of-3 team issues, holds, and signs wire requests with nothing else in JCP changing. Shares come from a trusted dealer or **distributed key generation** — with DKG the group's private key never exists anywhere, not even momentarily. The two-agent rule for irreversible actions, refused by arithmetic rather than policy. - **`jcp-channel`** — receipt-settled budget channels (SPEC §4.5, the OPTIONAL profile): N enforcement points spend optimistically against one grant and settle by exchanging signed statements of cumulative spend — forged, stale, and regressing statements refused; between settlements the exposure is bounded by the window, and after settlement any overdraft is provable from the signed statements. Where bounded overdraft is unacceptable, `shard()` remains the baseline. - **`jcp-conformance`** — C1–C18 + a negative pack, all checks real (C8 decides over a live socket; C13 drives a FROST 2-of-3 caller; C16 replays ancestor debits from a chained receipt and counts a chained hold on every link; C17 settles a budget channel by signed statement; C18 mints a dealer-free group via DKG), published vectors in `conformance/v1/`. - **`jcp-cli`** — the `jcp` demo: one metered grant driven through an agent loop — legitimate calls allowed and debited, a poisoned tool-result refused structurally, out-of-scope actions and resources denied, the budget stopping a runaway loop, a sub-agent getting a strictly-weaker delegated grant, a signed receipt verified, the detected meter's rung metering a probe of work at the grade it gave that probe, and the issuer revoking the grant — after which the runtime goes dark. `cargo test --workspace` green; `cargo clippy --workspace --all-targets` warning-free. ## The demo, abbreviated ``` costs scripted, no tool runs: sealed as estimates frame verdict reason rem µJ read the db (legit) allow −20000 µJ 80000 tool-result says 'delete db' (poison) DENY untrusted-control 80000 try to delete (not granted) DENY action-not-granted 80000 read prod-secrets (wrong audience) DENY wrong-resource 80000 read again (legit) allow −50000 µJ 30000 read again — budget runs out DENY budget-exceeded 30000 amplification refused: capability exceeds parent receipt allow · 50000 µJ · Estimator · verified true ``` The model never gates itself; the runtime does, and the receipt proves it. The loop's costs are scripted — no tool runs — so they are fixed, to run the budget out at the same row every time, and each receipt grades its cost `Estimator`: a figure nothing read is never sealed as a reading. The demo's `meter` line is the one figure it takes: the detected meter's rung, and a small probe of work at the grade the meter gave that probe — a hardware reading only where the rung's counter read it, otherwise an estimate graded as one. ## Consumers in this repository JCP is not only specified — it is consumed. Three sibling standards gate their real dispatch through it, each with its own adapter crate and tests: - **JouleClaw** (`jouleclaw-rs/crates/jouleclaw-jcp`) — every MCP tool dispatch is decided against a Grant before a byte reaches the tool; an ungranted tool named by an injected instruction is refused and the refusal sealed. - **Sandbox** (`sandbox-rs/crates/sandbox-jcp`) — a unit's execution is authorized against a Grant bound to its image **by content address**; one flipped image byte is a different audience and is denied before the executor is ever invoked. Two receipts per run: the JCP authorization and the sandbox's metered, attested execution. - **Joule Code** (`joule-code-rs/crates/joule-code-jcp`) — every cascade-stage consultation is decided pre-dispatch; the L4 escape hatch to a remote frontier agent exists only when a signed grant names it and can pay for it. ## Relationship to the family JCP composes the primitives the Transaction Science family already proved: `did:key`/Ed25519 identity, capability-gated execution (`sandbox`), the honest `Energy`/`Provenance` model (`proof`), and JCR-1 signed receipts (family-wide). It is where they stop being per-tool adapters and become the protocol.