The host-binding layer for JCP + Mesh + jcp-efficiency: carry energy-metering, capability-gating, and attested receipts into third-party AI coding agents (Claude Code, Cursor, Windsurf, Antigravity, Zed, JetBrains, OpenCode) through their own extension seams, without forking them. Grounded in research: no host exposes its agent loop to extensions, but all expose three seams — a per-action gate (PreToolUse-hook family / ACP request_permission), a model-call meter (base_url proxy / OTel gen_ai.*), and a receipt surface. SPEC.md normalizes those seams + defines conformance profiles (claude-code reference, hooks-family, acp, opencode, cline, vscode, meter-only). §7 states the honest limit: a host adapter alone cannot meter the host agent's tokens — a complete figure needs the meter seam. Name is provisional (steward's call). Reference impl (joulehook-rs + the claude-code plugin) lands next. Co-Authored-By: Claude Opus 4.8 <[email protected]>
12 KiB
JouleHook — Metered, Gated, Attested Agent Work in Any Host
Version: 0.1.0-draft.1 · Status: Draft · Profile: joulehook/1
Specification text: CC-BY-4.0 · Reference code (joulehook-rs/): Apache-2.0
Provisional name. The steward may rename the standard; the profile string, receipt kind, and seam names are the stable surface.
JouleHook is the open standard for carrying energy-metering, capability-gating, and attested receipts into a third-party AI coding agent or editor — through the host's own extension seams, without forking it. It does not replace the host's agent or its model. It binds the three seams that every host already exposes — a per-action gate, a model-call meter, and a receipt surface — to a decide-outside-the-model grant check, an honest energy meter, and a sealed receipt. One agent's work becomes a metered, gated transaction — in Claude Code, Cursor, Windsurf, Antigravity, Zed, JetBrains, or OpenCode — from one core.
JouleHook is one of the Transaction Science open standards.
Transaction Science is the steward, not the proprietor: the seam interfaces and the
right to fork are public. JouleHook builds on three sibling standards rather than
re-inventing them: JCP (../jcp) supplies the grant + decision model,
Mesh (../mesh) supplies the metering front door, and
jcp-efficiency supplies the efficiency/1 receipt.
§1 Why JouleHook exists
An energy-accounted, methodology-gated coding loop is worth little if it only runs in one editor. Developers already live in Claude Code, Cursor, Antigravity, Zed, and OpenCode, and no host exposes its built-in agent loop to a third-party extension: you cannot, from an extension, observe the host agent's token consumption or intercept its native file/shell tools. A naïve "one native plugin per editor that wraps the agent" is therefore impossible by construction.
But every host does expose the same three seams, and JouleHook is the normative contract over them:
- A gate — the host lets an external process (or an in-process hook) approve,
deny, or rewrite a tool action before it executes. This is the
PreToolUse-hook family (Claude Code, Cursor, Windsurf, Antigravity, Cline, OpenCode) and ACPsession/request_permission(Zed, JetBrains, Neovim). - A meter — the one place every agent's tokens are authoritative and every
request can be refused is the model-call boundary: an OpenAI/Anthropic-shaped
proxy addressed by a
base_urloverride, or the host's own OpenTelemetrygen_ai.*export. - A receipt surface — a place to carry verifiable artifacts back to the user: MCP resources, a status line, or a panel.
JouleHook standardizes the shape of what rides those seams, so a single core is written once and bound to each host by a thin adapter.
§2 The three seams (the whole standard)
| Seam | Binds to (host mechanisms) | JouleHook contract | Backed by |
|---|---|---|---|
| Gate (§3) | PreToolUse-hook family; ACP request_permission |
Normalized ActionDecision (allow / deny / ask / rewrite) + sealed decision receipt |
JCP grant (../jcp) |
| Meter (§4) | base_url proxy; OTel gen_ai.* ingest |
efficiency/1 per completed unit; joule-ceiling enforced at the model boundary |
Mesh (../mesh), jcp-efficiency |
| Receipt (§5) | MCP resources; status line; panel | Hash-chained, verifiable efficiency/1 + decision receipts |
jcp-efficiency, jcp-receipt |
A conformant deployment binds at least the Gate seam or the Meter seam, MUST seal
receipts (§5), and MUST state honest provenance (§7). Binding all three is the
full profile (§6).
§3 The Gate seam (normative)
§3.1 The normalized action event
A host presents a pending tool action to the gate. JouleHook normalizes the host's
native schema into a host-agnostic ActionEvent:
| Field | Type | Meaning |
|---|---|---|
session_id |
string | The host session. |
tool |
string | The action's tool name (host-native or mcp__<server>__<tool>). |
input |
object | The tool's arguments (e.g. {"command":"npm test"}, {"path":..,"content":..}). |
cwd |
string | Working directory. |
content_id |
string | null | Content id of the target, when derivable (a file, a command). |
An adapter MUST map its host's hook payload onto ActionEvent losslessly for the
fields the host provides, and MUST NOT fabricate a content_id it cannot derive.
§3.2 The decision
The gate returns an ActionDecision:
allow— the action proceeds unchanged.deny— the action is blocked;reasonis surfaced to the agent.ask— a human is asked to approve (bound to the host's approval UI where one exists; otherwise degrades todeny).rewrite— the action proceeds withupdated_inputsubstituted (e.g. a redaction).
The decision MUST be reached outside the model — it is a deterministic function of
the ActionEvent and the active JCP grant, never a request to the LLM (JCP §
decide-in-the-runtime). An adapter that asks the host's model to self-approve is
non-conformant.
§3.3 The JCP binding
The gate decision is a JCP capability + budget check:
- Resolve the active
SignedGrantfor the session. Verify its issuer signature. - The action
tool×content_idMUST be permitted by the grant's capability set; an action the grant does not hold isdeny. - If the action carries an estimable cost, the grant's joule budget MUST be ≥ the
estimate; over budget is
deny. Onallow, the spent amount is debited. - The decision —
allowanddenyalike — is sealed (§5).
§3.4 Host bindings (informative)
| Host | Gate mechanism | deny signal |
|---|---|---|
| Claude Code | PreToolUse hook (external process, JSON on stdin) |
permissionDecision:"deny" / exit 2 — blocks even under --dangerously-skip-permissions |
| Cursor | .cursor/hooks.json (beforeShellExecution, beforeMCPExecution, …) |
permission:"deny" / exit 2 |
| Windsurf | Cascade hooks (pre_run_command, pre_write_code, …) |
exit 2 |
| Antigravity | hooks.json PreToolUse |
allow_tool:false + deny_reason |
| OpenCode | tool.execute.before (in-process TS) |
throw to deny / mutate args to rewrite |
| Cline | SDK beforeTool (fail_closed); file PreToolUse |
{cancel} |
| Zed / JetBrains / Neovim | ACP session/request_permission |
reject |
The four external-process hooks (Claude Code, Cursor, Windsurf, Antigravity) share a JSON-in / decision-out shape; a single gate binary MAY serve all four behind a per-host input adapter. OpenCode/Cline are served by a thin in-process shim that calls the same core; Zed/JetBrains by an ACP agent (§6).
§4 The Meter seam (normative)
§4.1 The model-call boundary
Authoritative token accounting and enforceable spend control exist at exactly one place common to every host: the model call. A JouleHook meter binds there by one of two methods:
- Proxy (enforcing) — an OpenAI/Anthropic-shaped endpoint the host is pointed at
via
base_url/ANTHROPIC_BASE_URL. It reads the authoritativeusageon every response, converts tokens→microjoules at honest provenance, and MAY refuse a request whose estimated cost exceeds the active grant's joule ceiling (a hard reject before the request reaches the provider). This is the Mesh front door (../mesh); itsusage.energycarries the receipt. - Telemetry (observing) — ingest of the host's native OpenTelemetry GenAI
export (
gen_ai.usage.input_tokens/output_tokens), where the host emits it (Claude Code, VS Code/Copilot, Gemini CLI, Codex). Observe-only: it cannot refuse.
§4.2 The unit and the ceiling
The meter MUST produce an efficiency/1 receipt per completed, verified unit of
work (jcp-efficiency), carrying microjoules per accepted token at honest
provenance and the outcome anchor. A joule ceiling declared on the session grant
MUST be enforced by a Proxy meter (reject over budget) and, where only a Telemetry
meter is present, MAY be enforced only after the fact (the run is metered, not
capped) — which the adapter MUST disclose (§7).
§5 The Receipt seam (normative)
Every gate decision and every completed unit seals as a receipt:
- Decision receipts — each
allow/denyfrom §3, sealed as a JCP decision receipt (non-repudiable, hash-chained). efficiency/1receipts — each completed unit from §4.
Receipts MUST be verifiable by a third party holding the steward's public key, MUST
hash-chain within a session, and SHOULD be surfaced through the host's receipt
surface (MCP resources, a status-line figure, or a panel). Where the meter is bound
via the Mesh proxy and the energy figure is attested (sandbox-tee::energy), the
receipt MAY carry the attestation commitment (efficiency/1.energy_attestation) and
its honest trust level.
§6 Conformance profiles
A JouleHook adapter declares one or more profiles. Each names the seams it binds:
| Profile | Host(s) | Gate | Meter | Receipt |
|---|---|---|---|---|
claude-code |
Claude Code | PreToolUse hook | proxy or OTel | MCP + statusline |
hooks-family |
Cursor, Windsurf, Antigravity | hooks.json | proxy or OTel | MCP + panel |
acp |
Zed, JetBrains, Neovim | request_permission |
own the loop | session/update |
opencode |
OpenCode | tool.execute.before |
own the loop or proxy | tui.toast |
cline |
Cline | beforeTool |
own the loop or proxy | registered tool |
vscode |
VS Code family (Open-VSX) | own contributed tool only | proxy or OTel | status bar + webview |
meter-only |
Continue, any OTel host | — | OTel data/gen_ai.* |
dashboard |
Minimal conformance: bind ≥1 seam and seal receipts (§5) with honest provenance
(§7). full conformance: bind all three seams for a host, with a Proxy meter
(enforceable ceiling) and hash-chained receipts.
The reference profile is claude-code: a single installable plugin bundling the
gate hook, an MCP receipt server, and a status-line joule meter — the deepest gate
available anywhere and the clearest end-to-end demonstration.
§7 The honest limit (normative honesty)
A host-side adapter, alone, cannot meter the host agent's own tokens or its built-in (non-adapter) tool calls — those are invisible from every host's extension sandbox (confirmed across VS Code, Cursor, Windsurf, Antigravity, Zed, JetBrains). Therefore:
- A complete energy figure REQUIRES the Meter seam (§4) bound via proxy or OTel. An adapter that presents a whole-session energy figure without a bound meter is non-conformant — it may only report the energy of work that passed through its own tools, and MUST label it as such.
- An adapter whose only meter is Telemetry (§4.1) MUST disclose that its joule ceiling is observed, not enforced.
Overclaiming coverage is a conformance failure, not a rounding of the truth.
§8 Security and trust
JouleHook inherits JCP's stance: every action is decided in the runtime, never in
the LLM, because a tool description and a tool result are untrusted input. The gate
is a deterministic function; a deny binds regardless of the host's permission mode
where the host allows a hook to override it (e.g. Claude Code PreToolUse fires
before the permission check). Receipts are non-repudiable and hash-chained. The
adapter runs inside the host's trust domain and MUST NOT weaken it: it adds gates and
receipts, it does not remove the host's own approvals.
§9 Relationship to the sibling standards
JouleHook is the host-binding layer, not a re-implementation:
- JCP decides and grants (capability ⊗ joule budget = one signed grant); JouleHook binds that decision to each host's gate seam.
- Mesh meters and routes at the model front door; JouleHook points a host at it as the Meter seam and enforces the ceiling.
jcp-efficiencyis the receipt; JouleHook carries it through each host's receipt surface, optionally with an attested energy figure (sandbox-tee::energy).
The contribution of JouleHook is the normative seam contract + the conformance profiles that make one metered, gated, attested loop portable across agents that would otherwise each need a bespoke integration.