The Credential Is Part of the Interface

ACI got the shape of the call right and left the authority behind it alone. A tool reached three ways has three different credential stories, and the oldest one — ambient secrets in your home directory — is the one agents break.

· 8 min read

agents security aci cloister mache developer-tools

the map · part 8 of 8

cloister · part 3 of 3


The argument that agents need purpose-built interfaces is settled at this point. The SWE-agent group named it — the agent-computer interface, ACI — and the diagnosis was right: agents are a distinct class of consumer, and handing them the interface built for humans, or the one built for other programs, produces exactly the friction you would predict.

I have written about that framing before, and it is one of the more useful ideas of the last few years. It is also scoped too narrowly.

ACI discussions are about the shape of the call. Which commands exist. What they return. Whether an invalid edit is rejected before it lands rather than discovered by a build three minutes later. All real, all worth getting right.

But an interface is not only how you ask. It is also what makes the answer permissible. And on that question the same tool, reached three different ways, gives three different answers — which is a strange thing to accept in a discipline that just spent five years arguing that interfaces matter.

The day this post went up, Cloudflare announced @cloudflare/computer: “your agent needs a computer, not a container.” A virtual filesystem the agent reads and edits, read/write/edit/ls/exec tools over it, and a scheduler that splits execution between lightweight isolates and full containers, with operations “gated, audited and observed.”

They are not the first to arrive. Mintlify built ChromaFS in March — a virtual filesystem over their documentation database, agents exploring it with grep, cat and ls, “the illusion of one” — and named the trend outright: “Agents are converging on filesystems as their primary interface.” Theirs is read-only, so the outbound-credential question never arises; the access control it does need lives in the substrate, as metadata filtering at the query layer rather than OS permissions. Worth noticing: when the authority question gets answered at all, it gets answered underneath.

I recognize that computer, because it is the one I have been building since February. mache’s first commit is February 9 — FUSE work by the third commit of day one — and the argument went up on the 23rd: the agent’s interface should be cd, ls, cat and validated writes over structure rather than bytes. Today mache projects the code graph and ley-line-open serves the projection as a FUSE mount; cloister is the runtime, the gated, audited place where the exec happens. Down to the instrument, then — Cloudflare’s container runtime also reaches its filesystem over a FUSE mount.

So the year reads: the mount and the argument in February, ChromaFS in March, @cloudflare/computer in August. Three arrivals at one shape from three starting points is the best news the shape has had, because an architecture is easier to argue for once other people reach it independently.

And the announcement repeats the omission this post exists to name. Credentials, tokens, the environment the exec’d process runs with, what its network can reach — none of it appears in the piece. The agent’s computer now has a name, a package, a filesystem and an audit trail, and authority is still not part of the interface.

Three surfaces, three postures

Take any capable tool — something that talks to a cloud provider, a package registry, a git host. It is reachable three ways, and each one answers where does the authority come from differently.

As an HTTP API: an explicit token, presented per call, scoped by whoever issued it. There is an authorization step and it is visible.

As a CLI: ambient credentials. ~/.aws/credentials, ~/.npmrc, ~/.config/gh/hosts.yml, the system keychain. Nothing is presented per call, because nothing needs to be — the credential is simply there, readable by anything running as you.

As an MCP server: the protocol decoupled where a tool lives from how it is invoked, and left the credential question to the server author. In practice that means the CLI posture wearing a protocol — the server wraps a CLI, or holds the same key the CLI would have read.

Three interfaces to one capability, three unrelated stories about authority. If a tool exposed three different argument orders depending on how you reached it, we would call that a defect.

The ambient credential assumed you were typing

The middle posture is the one worth sitting with, because it is not a mistake. It is a correct optimization for an assumption that used to hold.

Ambient credentials exist so that you do not re-authenticate on every command. The design assumes the thing running is a person who just typed something — and if that person can run aws, they could equally read ~/.aws/credentials themselves. Under that assumption the file grants nothing the shell did not already grant, and the convenience is free.

Agents void the assumption in one specific way that matters more than the usual “agents are automated” framing. An agent reads text it did not write — a README, a dependency description, an issue comment, a web page — in the middle of a run, and that text can influence what it does next. So these two sentences become the same sentence:

  • anything you run can read your secrets
  • anything that reads a malicious file can read your secrets

The credential store did not change. The population of things that can reach it did.

This is the same argument I made about giving tools calls instead of keys, arriving from a different direction: there, the problem was the tool holding a secret it could be talked into leaking. Here it is that the tool never had to be given anything, because the secret was already lying in the path of every process.

What MCP actually decoupled

MCP’s real contribution is not a better tool format. It is that a caller stopped needing to know where a tool lives or how it is packaged. Invocation moved away from location.

That is a substrate-shaped observation: the invocation boundary is a genuine seam rather than an implementation detail. Correct, and why the idea spread.

It stops one step short of the corollary. A seam that can relocate a tool can also hold that tool’s credential. If the caller no longer needs to know where the thing runs, the caller has already accepted an intermediary — and an intermediary is exactly the thing that can make a call on your behalf without handing over what makes the call possible.

Put it in the substrate, not in every tool

So the position, stated plainly: identity, credential isolation, and the audit trail belong in the layer all three surfaces traverse, not solved again inside each tool.

That is what cloister is. Its framing: MCP servers are just the first tenants. Anything HTTP-shaped joins the same route table without touching the substrate, and external tools are reachable as native processes, OCI services, Unix-domain-socket peers, or HTTP services — with identity and credential handling unchanged across all of them.

The mechanism is deliberately blunt. The vault exposes an operation that makes a request using a stored credential, and has no operation that returns one. Use-don’t-fetch is not a policy about when it is appropriate to fetch a key; the fetch is absent from the interface, so a compromised tenant asking for the secret is asking for a method that does not exist. Identity is proof of possession rather than a bearer token, which I have argued separately, and the per-call proof is the thing the ambient model structurally could not have — there was no call to attach it to.

Underneath, when a tool runs confined, the home directory is simply never granted. ~/.ssh, ~/.npmrc, ~/.bash_history are unreachable without appearing in any deny list, because the ambient store was never in scope to begin with.

The consequence that looks like a bug

There is one result of this I want to state up front, because it reads as a defect and is not.

Under confinement you cannot use a Claude subscription. A subscription authenticates through the macOS keychain, and the sandbox blocks keychain access on purpose, so the tool reports that it is not logged in. You set an API key instead.

That is the whole thesis arriving as an inconvenience. The keychain is the ambient credential store; closing the ambient path means closing it for the convenient case too. An exception carved out for the login you happen to like is not a smaller version of the property — it is the absence of the property, since the attack does not care which credential store it reads.

I would rather ship the inconvenience than a guarantee with a hole in it that I put there myself.

What this does and does not settle

The gaps, named precisely. The allowlist of what a confined tool may reach was built by hitting errors and adding what broke; it covers git and a coding harness, which makes it complete up to what has been exercised and no further. The several runtimes a declared shape can lower to — local workerd, native processes, OCI, a microVM on macOS, Cloudflare — are not identical security boundaries. Fail-closed peer enforcement is still an operator cutover rather than the default.

What the argument does establish is the claim itself: the credential posture is part of the interface, not a separate concern layered on afterwards, and solving it once underneath beats solving it three times, badly, in each tool.

The ACI argument was that agents deserve interfaces designed for them rather than inherited from us. Ambient credentials in a home directory are the most thoroughly inherited thing in the stack — a convenience built for a person at a keyboard, still sitting in the path of every process an agent spawns. That is part of the interface, and the attacker already treats it as one.