You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+81-62Lines changed: 81 additions & 62 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,4 @@
1
-
# writ
2
-
3
-
**Codification gate and Merkle audit chain for Go agents.**
1
+
# writ — cryptographic audit trail for AI calls
4
2
5
3
```
6
4
go get github.com/opskernel-io/writ
@@ -10,55 +8,34 @@ go get github.com/opskernel-io/writ
10
8
11
9
## The problem
12
10
13
-
Autonomous coding agents run with whatever permissions you gave them at setup time. There is no runtime gate that asks "is this call within policy?" before the LLM acts, and standard observability logs can be edited after the fact.
11
+
EU AI Act Article 12 requires automatic, tamper-evident logging of AI system decisions over the system's lifetime. Enforcement begins August 2, 2026.
12
+
13
+
Most teams building on LLM APIs have neither: standard observability logs can be edited after the fact, and database rows have no chain-integrity check.
14
14
15
15
---
16
16
17
17
## What writ does
18
18
19
-
-**Blocks unauthorized agent calls before execution** — the codification gate intercepts every outbound LLM API call at the process level and evaluates it against your OPA policy before it leaves
20
-
-**Logs every agent decision in a tamper-evident chain** — SHA-256-linked Merkle chain; altering any entry breaks verification from that point forward
21
-
-**Routes tasks to the cheapest model tier that can handle them** — Ollama (free/local) → Claude Sonnet → Claude Opus, enforced by policy
22
-
-**Reloads policy without restarting** — OPA hot-reload via file watch; policy changes take effect on the next call
19
+
-**Drop-in Go SDK** — `writ.New(cfg)` wraps your `*anthropic.Client`; one line at construction time, zero behaviour change in existing agent code
20
+
-**Merkle audit chain** — every LLM call is SHA-256-linked to the previous entry; post-hoc modification is detectable by anyone who runs `writ verify`
21
+
-**Optional OPA policy gate** — Rego rules run before each call; unauthorized calls never reach the API, violations are logged with chain entries
| License | Apache 2.0 + commercial | MIT | Commercial | MIT |
25
+
## Article 12 compliance status
36
26
37
-
**The key distinction from Asqav:** Asqav logs what happened after execution. writ controls what is allowed to happen before execution. These are different architectural positions: authorize-then-enforce vs. observe-and-record. In a regulated environment you need both; writ's gate is the piece no other tool ships.
**The key distinction from Microsoft AGT:** The Agent Governance Toolkit has OPA enforcement and Ed25519 signing. It has no tamper-evident audit log. writ's Merkle chain fills that specific gap.
40
-
41
-
---
42
-
43
-
## EU AI Act Article 12
44
-
45
-
EU AI Act Article 12 requires automatic, technical, tamper-evident logging over the lifetime of high-risk AI systems. Enforcement begins August 2, 2026.
46
-
47
-
**Three requirements met in full:**
48
-
- Automatic logging — the gate emits chain entries without human action per call
- Traceability — every gate decision links to its chain entry by AuditID
51
-
52
-
**Three requirements partially met (remediation paths defined, days not weeks):**
53
-
- Tamper-evident — SHA-256 chain detects alteration; filesystem-level write protection (`chattr +a` + `writ.ChainProtected()`) closes the gap
54
-
- Lifetime coverage — chain is append-only within a process run; cross-restart hash linking closes the gap
55
-
- Granularity — input hashes logged by default; `StoreFullInputs: true` opt-in logs the full input data
56
-
57
-
**Two named gaps:**
58
-
-**RFC 3161 timestamping** — chain timestamps are machine-generated but not externally signed. Integration roadmap: `github.com/digitorus/timestamp`. Commercial tier: hosted eIDAS-compliant timestamping.
59
-
-**6-month retention management** — the open-source core writes to local storage with no managed expiry. Commercial-tier feature.
60
-
61
-
writ-core is suitable for teams building toward Article 12 compliance. The three partial requirements close with days of engineering. The commercial tier closes the two named gaps.
35
+
Three partial requirements have defined close paths:
36
+
-**Filesystem-level tamper protection** — `writ.ChainProtected()` sets `chattr +a` on Linux; prevents in-place overwrites without breaking the chain
37
+
-**Cross-restart chain continuity** — chain is append-only within a process run; session boundaries are flagged explicitly in `VerifyFull()` for auditor review
38
+
-**Full input capture** — input hashes logged by default; `StoreFullInputs: true` writes full request/response JSON to a sidecar JSONL for replay
anthropic.NewUserMessage(anthropic.NewTextBlock("refactor the auth module")),
91
-
}),
66
+
Messages: []anthropic.MessageParam{
67
+
anthropic.NewUserMessage(anthropic.NewTextBlock("summarise the Q3 results")),
68
+
},
92
69
})
93
70
if err != nil {
94
71
vardenial *writ.DenialError
@@ -103,34 +80,58 @@ if err != nil { ... }
103
80
defer stream.Close() // writes the streaming-complete audit entry
104
81
105
82
// For tool use and other non-LLM events:
83
+
h:= sha256.Sum256([]byte(filePath))
106
84
client.Audit(writ.AuditEvent{
107
85
ActionType: "write_file",
108
86
Actor: writ.ActorAgent,
109
-
InputHash: writ.HashInput([]byte(filePath)),
87
+
InputHash: fmt.Sprintf("%x", h),
110
88
Result: "success",
111
89
})
112
90
113
-
// Verify the chain (run in CI or on-demand audits):
91
+
// Verify chain integrity (run in CI or on-demand audits):
114
92
err = writ.Verify("/var/writ/audit.chain")
115
93
```
116
94
117
95
**Helm (Kubernetes):** writ-core is a library dependency of your agent process, not a sidecar. Add to your agent container's Go dependencies. See `docs/helm/` for a reference values.yaml with policy ConfigMap mounting.
118
96
97
+
A runnable end-to-end demo is at [`examples/demo/`](examples/demo/).
98
+
119
99
---
120
100
121
-
## Supported agents
101
+
## What's in v0
122
102
123
-
v0 targets **Go agents that call `anthropic.Client` directly** — any agent built with `github.com/anthropics/anthropic-sdk-go`. Drop `writ.New()` in at the client construction site.
103
+
-`writ.New()` SDK wrapping `*anthropic.Client`
104
+
- SHA-256 Merkle chain — append-only JSONL, filesystem protection (`chattr +a`) on Linux
105
+
- OPA codification gate — Rego policy evaluation before each call; hot-reload via file watch without restart
106
+
-`writ verify` CLI — standalone chain verification for CI pipelines
107
+
-`StoreFullInputs` mode — sidecar JSONL with full request/response JSON for audit replay
124
108
125
-
| Agent | v0 support | Notes |
126
-
|---|---|---|
127
-
| Custom Go agent (anthropic-sdk-go) |**✓ Supported**|`writ.New()` wraps at construction time — one line |
128
-
| Cursor | Roadmap | Cursor proxies all LLM calls through its own servers; requires HTTP middleware path (ADR #20) |
129
-
| Devin | Not planned | Cognition cloud-only; no user-controlled process to intercept |
109
+
Not in v0: managed timestamp authority, 6-month retention service, multi-agent cross-chain tracing.
130
110
131
-
**Cursor:** writ cannot intercept at the SDK level because Cursor routes every LLM call through Cursor's backend regardless of your API key. The roadmap item (ADR #20) is a local HTTP proxy that Cursor can be configured to route through via its OpenAI-compatible base-URL override. Not yet implemented.
111
+
---
132
112
133
-
**Devin:** Devin is a fully cloud-hosted system. There is no user-controlled process making LLM calls — Cognition's infrastructure handles all inference. writ integration is not viable without a Cognition self-hosted tier.
113
+
## Known limitations
114
+
115
+
-**Process-level boundary only** — writ intercepts at the SDK call site in your process. A transitive dependency that constructs its own `anthropic.Client` bypasses the gate. See the threat model ADR for the scope and mitigation options.
116
+
-**Single-process append assumption** — no concurrent writers to the same chain file. Multi-process setups require separate chain files or the pluggable `AuditStore` interface.
117
+
-**No timestamp authority in OSS tier** — chain timestamps are machine-generated, not externally signed. eIDAS-compliant timestamping is a commercial-tier feature.
| License | Apache 2.0 + commercial | MIT | Commercial | MIT |
131
+
132
+
**From Asqav:** Asqav logs what happened after execution. writ controls what is allowed to happen before execution. These are different architectural positions: authorize-then-enforce vs. observe-and-record. In a regulated environment you need both; writ's gate is the piece no other tool ships.
133
+
134
+
**From Microsoft AGT:** The Agent Governance Toolkit has OPA enforcement and Ed25519 signing. It has no tamper-evident audit log. writ's Merkle chain fills that specific gap.
134
135
135
136
---
136
137
@@ -162,6 +163,22 @@ The gate sits between your agent's code and the LLM API call — not between you
162
163
163
164
---
164
165
166
+
## Supported agents
167
+
168
+
v0 targets **Go agents that call `anthropic.Client` directly** — any agent built with `github.com/anthropics/anthropic-sdk-go`. Drop `writ.New()` in at the client construction site.
169
+
170
+
| Agent | v0 support | Notes |
171
+
|---|---|---|
172
+
| Custom Go agent (anthropic-sdk-go) |**✓ Supported**|`writ.New()` wraps at construction time — one line |
173
+
| Cursor | Roadmap | Cursor proxies all LLM calls through its own servers; requires HTTP middleware path (ADR #20) |
174
+
| Devin | Not planned | Cognition cloud-only; no user-controlled process to intercept |
175
+
176
+
**Cursor:** writ cannot intercept at the SDK level because Cursor routes every LLM call through Cursor's backend regardless of your API key. The roadmap item (ADR #20) is a local HTTP proxy that Cursor can be configured to route through via its OpenAI-compatible base-URL override. Not yet implemented.
177
+
178
+
**Devin:** Devin is a fully cloud-hosted system. There is no user-controlled process making LLM calls — Cognition's infrastructure handles all inference. writ integration is not viable without a Cognition self-hosted tier.
179
+
180
+
---
181
+
165
182
## License
166
183
167
184
The writ-core SDK is Apache 2.0. Use it, fork it, embed it, build commercial products on top of it.
@@ -184,13 +201,15 @@ The writ-core SDK is Apache 2.0. Use it, fork it, embed it, build commercial pro
184
201
185
202
---
186
203
204
+
## Early access
205
+
206
+
writ is pre-launch. To request early access or discuss Article 12 compliance requirements: [writ.opskernel.io](https://writ.opskernel.io) or reach out directly via [opskern.io](https://opskern.io).
207
+
208
+
---
209
+
187
210
## Related
188
211
189
212
-**[hookd](https://opskernel.io)** — governs external AI traffic: MCP server verification, replay detection, per-source audit. writ governs what agents do internally; hookd governs what external servers agents call.
-**[Asqav](https://github.com/jagmarques/asqav-sdk)** — MIT Python SDK for agent audit trails with RFC 3161 timestamps. Complementary to writ (observe-and-record layer); writ adds the pre-execution gate that Asqav does not have.
192
215
-**[EU AI Act Article 12 text](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32024R1689)** — the specific requirement writ's architecture addresses.
193
-
194
-
---
195
-
196
-
*writ is built by [OpsKern](https://opskern.io). Early access: [writ.opskernel.io](https://writ.opskernel.io)*
0 commit comments