stacklok / stacklok/mecatl

Tamper-evident tool-call records behind HookRunner / EventLog

Open
#1,666 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
152
Forks
16
Avg merge
14h 48m
Merged PRs (30d)
536

Description

Opening this per CONTRIBUTING to agree on scope before any code; I'd plan to implement whichever shape you pick.

Think of the harness as a workshop and the event log as the shop's own logbook. This stations a notary at the bench: one sealed slip when a tool is handed over, one when it comes back, stapled together by the first slip's own fingerprint.

docs/agent-identity-model.md names the gap: "The audit trail is the harness's word. The event log records what happened, but it is self-attested. An operator, auditor, or downstream service cannot verify that a given action traces back through a specific subagent, agent, and user."

What this would add. Each tool call becomes a signed, content-addressed record. At PreToolUse: a planned record binding the tool name, CallID, and a digest of Input. At PostToolUse: an outcome record with a digest of the result and confirmed/failed from IsError (both already on the PostToolUse Input payload), carrying the planned record's content address as its parent; CallID is only the lookup key that finds which planned record to point at, the link itself is the content address, verified by recomputation. A third party with the issuer's public key verifies tamper-evidence, chain order, and non-repudiation of each record after the fact, without the harness's log. It is not independence from the harness — a key the harness holds is still the harness signing — which is why who holds the key is #478's question and this composes with it rather than competing. Nor is it the "traces back through a specific subagent, agent, and user" half of your gap: SessionID and user identity do not enter the record as fields (anything inside a tool payload is committed only within the payload digest); attribution is the issuer's job, not the record's.

The format is an individual IETF Internet-Draft, work in progress and not WG-adopted, profiling SCITT signed statements: draft-mih-scitt-agent-action-capsule-04 (https://datatracker.ietf.org/doc/draft-mih-scitt-agent-action-capsule/). The Go producer is action-state-group/capsule-emit-go (Apache-2.0; depends on veraison/go-cose and fxamacker/cbor; not yet tagged as a release, which I'd fix before proposing anything in-tree). The Python producer, capsule-emit, ships the same planned→outcome shape for other frameworks and carries the verifier; the emit→verify round-trip test lives in the out-of-tree repo's CI, so nothing here ever puts Python in your test matrix.

Two shapes, both on ports you already ship.

  1. port.HookRunner: a native Go HookRunner on capsule-emit-go, out of tree, in-process.
  2. port.EventLog / port.ToolCallRecorder: seal at the durable append rather than in the request path. I'd want your read on which process that lives in — if the durable append is at the relay per AGENTS.md, this is a relay-side implementation, not a loop-side port — and whether the log carries the pre-call event; if it only sees completed calls, shape 2 emits one record per call rather than a planned/outcome pair.

Non-goals and limits. Records only; never blocks or mutates (that stays with the guardrail checker and permission policy). Only digests are sealed — data minimization, not confidentiality; low-entropy inputs like paths or short commands would need salted commitments, which the producer supports. Fail-open by default: if the recorder is unavailable the call proceeds, and a gap shows as a planned CallID with no outcome record — veto that default if you'd rather. Individual records are verifiable; that nothing was omitted is not, and that is what registration with a transparency service buys, deferred here.

Questions. Which port, and which process for shape 2? Out of tree is my proposal, with a link from the extension-points docs if you keep a list of community implementations; in-tree only if you'd want it, wherever you'd put it.

Disclosure: I co-maintain capsule-emit and am on a paid engagement with Action State Group.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with docs/agent-identity-model.md and AGENTS.md, then inspect the port.HookRunner, port.EventLog, and port.ToolCallRecorder entry points. Resolve which port and process owns the work, and whether pre-call events are available, before defining scope. Done means an agreed implementation shape with its verification, attribution, and fail-open behavior specified.

Written by the indexing model from the issue text.

Assessment

Tech stack
cryptography, go
Domain
backend-api-design, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.