OCAP in the Age of Agents
Capabilities keep losing on usability, not correctness.
Nobody says capability-based security is wrong. It keeps being rejected because it is hard to use. This is an experiment in making it ergonomic for coding agents, with the failures left in.
The problem
An agent reads text it did not write and holds authority to act. That is a confused deputy: a program whose authority can be steered by someone else’s input. A sandbox confines the process. A capability limits who may ask for what, and can be narrowed as it is handed down.
The hypothesis
Designation is authorization. When you name the folder the agent works in, or the host it may fetch from, that act already is the grant. No second “allow this?” prompt to click through.
We are testing whether that holds for real tasks. It may not.
Demo
Three beats, each a real recorded run, nothing staged:
- Success. A confined task finishes inside its grant. TODO: recording.
- Failure. A run that fails, with its cause. TODO: recording.
- An exfiltration attempt, stopped. A task file carries a link with a token
in it. The agent tries to fetch the link, and the network caveat refuses it
before any connection is made. The task file was written to exercise this
path; the agent’s choice to try was its own. The agent then declines to guess
what the page held and asks the operator to choose, one option being an
explicit grant of that host.
newt ocap denialsrecords the refusal.
newt 0.8.0 (433e736c3729) with ornith-1.5-35b, a real run. The token is synthetic (example.net); no real credential is involved. No file was written. About 97 seconds of idle waiting are trimmed.
What broke
Every row is a public issue or PR.
| What we tried | What broke | Where |
|---|---|---|
| Confined agent creates a git worktree | Git’s own helper programs were refused | agent-bridle #407, newt-agent #2630 |
| Approve a denied command | The model was asked to retry instead of the command re-running with the grant | newt-agent #2628 |
| Denial message | The model probed the fence because the denial did not name the axis and target | newt-agent #2629 |
| Host-scoped network grant | Spawned commands did not get the narrowed grant | newt-agent #2619 |
| Record a refused network fetch | The refusal was not written to the denial journal, so the demo had no receipt | newt-agent #2643, #2645 |
TODO: add the measured numbers (approvals per task, denial-probing) once the recordings exist.
What is not claimed
- Write-fencing is not read, exec or network confinement.
- No benchmark or refactoring result is claimed until it has been witnessed.
Where this sits
Runtime sandboxes such as OpenShell enforce a boundary outside the agent. That is complementary. Capabilities add delegation: authority that can be narrowed and handed on, never widened. Independent designs reached the same core: zcap and UCAN.
Try it
- newt-agent, the agent harness
- agent-bridle, the capability layer
- The Cruel Symmetry, the idea in essay form: give the exact key, not the keyring
A personal project. Views are my own.