Abstract
Adoption fails when a control tool asks people to replace the agent, editor, or work pattern they already use. Writ therefore begins with writ connect claude, codex, cursor, or opencode. The user keeps the existing agent.
The native hook records visible tool calls by default. The user can then add a small tool list. A writ file can add exact authority to one selected session. The managed model loop remains available when the task needs evidence that the native hook cannot supply.
1. The adoption constraint
A separate agent interface adds another place to configure models, tools, context, and user habits. That cost arrives before the user sees a result.
Writ moves the first result to one command. The command installs a native user hook and writes private state under ~/.writ. It does not change MCP configuration. It does not require a writ file or model key.
2. Native integrations
Each integration package contains two contracts: the hook file format and the event codec. Shared code installs Writ-owned hook commands, preserves unrelated hooks, writes a digest, reports status, and removes only the commands that Writ installed.
Connection is idempotent. A dry run writes nothing. A changed Writ-owned hook is not overwritten. Disconnection preserves other hook entries and existing records.
The default connection belongs to the user and applies in every project. --project selects a project connection. When both scopes exist, every tool call must pass both policies. A project policy can narrow the user policy. It cannot widen it.
Configuration, connections, reusable writs, organization policy state, and project records stay under ~/.writ. Writ does not create a project .writ directory. WRIT_HOME selects another state root.
3. One action contract
Agent events use different tool names and envelopes. Writ converts each event into one action request. The request contains the agent, session, source, normalized tool name, provider tool name, visible arguments, and coverage.
The source can be a built-in tool, local MCP, remote MCP, hosted tool, or an unknown boundary. The coverage says who runs the action and whether Writ observed the request, result, or effect.
Bash, exec_command, and another agent-specific identifier remain in the record.shell. A policy can use the common action class.A named allow rule matches either identity. An organization policy can therefore allow a common action class and still restrict one provider name when needed.
4. Basic and normal decisions
The default profile is observe. Writ records the request and reported result. It returns allow for every valid event.
The normal profile is enforce. --read-only allows normalized read and search actions. --allow accepts exact normalized or provider names. It does not accept pattern syntax.
A denied call creates an argument-bound approval request. An approval can allow one matching retry or matching calls in the current run. An organization allow-list denial is final and cannot be changed by user or project approval.
5. Coverage is an output
The connection command and status command report four boundaries. They do not infer full control from a successful install.
Tool results are reports from the agent. Connected Writ does not independently observe filesystem, network, or service effects.
6. The MCP boundary remains available
Writ still serves an MCP boundary for clients that need it. A local proxy starts a command over standard input and output. A remote proxy connects to a Streamable HTTP endpoint over HTTPS.
The bridge relays the complete MCP message stream, including cancellation and server requests. It checks tools/call before forwarding. Remote credentials come from environment-variable references. Redirects cannot change origin.
7. Advanced use keeps the existing agent
A writ file is not required for connection. In advanced use, the user selects one observed session and applies every clause that its capability plan can enforce. Other sessions keep their normal connection policy.
writ start does not launch or replace the agent. It refuses the activation when the hook cannot enforce an authored clause. writ finish records human satisfaction. writ finish --cancel does not attest satisfaction.
Use writ issue when the task needs the managed model loop. It can charge model usage, check worktree changes, apply remedies, and run satisfaction checks. An omitted bound is authored-unbounded. Managed issue adds operational defaults of 25 iterations, $1.00, and 15 minutes.
Do not put secrets in a writ document or placeholder value. Attached activation state stores the bound document.
8. Organization policy is an outer layer
An organization publishes a JSON bundle with an Ed25519 signature, sequence, issue time, expiry time, allowed tool patterns, approval patterns, redaction pointers, and bound ceilings. Writ stores the source URL and a separately supplied public trust key in the project's state under ~/.writ.
The resolver rejects a bad signature, expiry, rollback to a lower sequence, or different content at the same sequence. A verified cache can cover a source outage only until signed expiry. The effective policy hash and source state enter the run record.
9. Records remove secrets before they become evidence
Writ redacts before storage. Built-in rules replace common secret fields, bearer tokens, secret assignments, and private-key blocks. Organization JSON Pointers add exact fields. The replacement enters the record as [REDACTED].
A normal native tool-call entry stores normalized arguments and a digest of exact provider arguments. Exact provider arguments stay transient. They can enter the record only in an explicit approval request, after redaction.
Each entry contains the previous entry hash. Each append creates an Ed25519-signed checkpoint for the current root. The checkpoint also binds the run and effective policy metadata.
The entry tables and checkpoint table are append-only. Redaction reduces disclosure risk. It does not replace review before a record is published.
10. Verification is separate from the database
writ record export produces a portable JSON bundle. writ record verify checks every link, the complete root, the checkpoint signature, and the trusted key ID without opening the source database.
An independent witness receives only the run ID, sequence, root hash, record signer key ID, and a fresh nonce. It returns a receipt signed with a separate key. The nonce prevents an old receipt from satisfying a new request.
Record verification proves integrity and signer identity. It does not prove that the recorded tool result or external effect is true.
11. Failure and process boundaries
Enforcement denies a call when Writ cannot verify an active organization policy or cannot write the decision record. Observe mode can allow a hook failure only when no organization layer requires enforcement.
A local process under the same operating-system account can still replace binaries, change configuration, or reach resources outside Writ. Use an account, container, or host boundary when that threat is in scope.
12. Implementation status
Implemented: native hooks for Claude, Codex, Cursor, and OpenCode; normalized action policy; visible built-in and MCP checks; local and remote MCP proxying; argument-bound approvals; pre-storage redaction; append-only hash chains; signed checkpoints; portable verification; signed organization policy inheritance; valid offline policy cache; and independent witness receipts.
Known limits: agent hook coverage differs; connected results are agent reports; hosted tools are not visible in every agent; local processes need operating-system isolation against a same-account attacker; and record integrity is not proof of an external effect.
The product test is now direct: connect an existing agent, make one tool call, read one record, and add one limit without leaving the agent.