Attenu ops runbook
Install → shadow → curate → enforce → verify, for an operator running Attenu on their own agent app. All
paths assume the packaged attenu CLI (installs from a wheel, no source tree).
Install
pip install attenu-derive
# (brings attenu-guard, the enforcement library, as a dependency)
attenu --version
1. Shadow first (zero risk)
Run your app with the attenu-guard adapter for your framework in observe mode (see
attenu-guard adapter docs). It records every delegation + tool call to the audit ledger, redacted at
capture (names, scope classes, quantity buckets, salted hashes — never values). Nothing is blocked.
2. Day-0 coverage + a draft pack
attenu onboard <recorded-traces>.jsonl --domain my-app --scaffold my-app.yaml
Prints what the shipped kit resolves (reads granted heuristically; money/mail/delete/exec withheld;
unknowns fail-closed) and writes my-app.yaml — a draft domain pack with one entry per uncurated tool
(heuristic guess + a _review note; tier-2 auto-marked requires_grant). Edit every entry: confirm the
scope, drop requires_grant only for tools you deliberately enable. This is the ≤1h step.
3. Verify the pack
attenu coverage <traces>.jsonl --domain my-app # expect curated_share high, unresolved 0
Re-run until unresolved is 0 and the tier-2 tools show as requires_grant (held), not withheld/unresolved.
4. Enforce
Install the shim in enforce mode with the derived authority (see run_adk_enforce for the wiring:
deriver + pack + operator_grants → meet → shim). Grant the tier-2 scopes the app legitimately needs
(operator_grants={"payments.transfer"}); leave the rest held. A call outside the granted authority is
denied before the tool body runs, the machine-readable denial goes back to the model, and a deny lands on
the ledger.
5. Export + verify evidence (offline)
# the app exports a bundle from its audit log (attenu_guard.evidence.export_bundle)
attenu verify bundle.json --pubkey <hex> # --hs256-key is the offline TEST signer only — never the auditor path
Returns {integrity, monotonicity, containment}. An auditor runs this against the bundle with no access
to the engine — a rewritten-and-re-signed log still fails, because the invariants are checked against the
bundle's own contents, not a hash.
Operational controls
- Revocation:
guard.revoke()/guard.revoke_agent(agent_id)cuts a node or a principal chain-wide. - Strike policy (optional):
Guard.issue(strikes=StrikePolicy(n=3, mode="same_scope"))auto-revokes a node after N same-scope denials; off by default; per-installation config. - Key rotation (ledger anchor): rotate the Ed25519 signing key on your schedule; anchors are per-run, so a rotation does not invalidate past anchors (each verifies against the key that signed it).
- TTL: authorities carry a TTL; expired authority denies (
TTL_EXPIRED).
Failure modes
- A benign call is denied → the pack is missing/too tight for that tool.
attenu coverageto find it, add/loosen the curated entry (never below the correct tier), re-verify, redeploy. Fail-closed by design. - A
requires_granttool is blocked → expected until the operator enables its scope (operator_grants). attenu verifyfails integrity → the bundle was altered or the anchor key is wrong. Do not trust the log.attenu verifyfails monotonicity/containment → the ledger claims a delegation/action outside authority; treat as a tampered or buggy producer, not an Attenu enforcement result.
Data custody — what does and does not leave the premises
Attenu collects no background telemetry. The only data that ever leaves is a bundle you export and send,
via attenu_cloud.flywheel.export_for_flywheel (or attenu verify locally, which sends nothing). That bundle
is enforced-redacted and refuses to emit anything unvetted (EvidenceLeakError):
Leaves the premises (redacted): the hash-chained ledger structure — event types, node/agent ids, scopes, decisions (allow/deny), reasons, the derived authorities per node — plus tool-call context restricted to redacted features only (argument shapes, quantity buckets, salted hashes; ceiling context the guard sets). Free-text prompts are replaced by a length+hash marker before the bundle is signed.
Never leaves: raw tool-argument values, raw prompt/task text, tool outputs, customer records. These are caught by an allow-list check that fails the export rather than shipping an unknown field or a raw context value.
The bundle remains offline-verifiable after redaction — attenu verify still confirms integrity, monotonicity
and containment, because redaction only removes and the anchor is computed over the redacted form.