A person and an agent reach a product shell through separate permissioned paths.

Agents need gates, not keys

Duct gives every product one governed execution layer for humans, agents, and automation.

You would not hand a new hire your master password on day one. But that is effectively what many products do when they connect an AI agent: one API key, broad access, and no declared boundary between a harmless read and an irreversible action.

When a human makes a mistake, you can ask why. When an agent makes one, most products cannot answer the questions that matter: who approved it, which rule allowed it, and what happened after the request reached the API.

The difference is not the model. It is the infrastructure around the model.

The layer products are rebuilding

Login became a product category. Payments became a product category. Agent actions are still something each team assembles for itself: a middleware check here, an approval button there, a log table added after the first incident. Then the product changes and the control layer changes with it.

Duct is the missing layer. It sits between a product and every caller. You define what is allowed once. Risky actions pause for approval. Permissions are explicit. Every execution leaves an evidence trail.

It is not a chatbot, an MCP server, or an API wrapper. It is the permissioned action layer between your product and everyone trying to act in it: a human, an agent, or eventually another product.

Dogfooding it on a live product

We put that premise on Whistler, against real product activity rather than a fresh demo database. The product already had real surfaces, real state, and consequences worth protecting.

Two callers went through the same Duct integration: a person using an embedded Shell, and a third-party AI agent. Neither received a master API key. Both could do useful work within the same declared boundary.

A Shell is not just a chat box

We call the conversational surface a Shell. It understands intent, plans the work, renders product UI when more information is needed, and knows when it must stop and ask a person to approve an action. Duct is the enforcement layer behind it.

That matters because the interface is shifting. Instead of learning every product's navigation, people will increasingly ask for an outcome: “invite the new intern,” “file this feedback,” or “show me last month's invoices.” The Shell can work out the sequence. Governance decides whether that sequence is permitted.

One manifest. Separate decisions.

Before either demo runs, a Duct manifest declares the product surface: which actions exist, who may call them, and what proof is required. It turns one vague question (“does this agent have access?”) into several precise ones:

  • Is the action declared? Off-manifest calls do not become product capabilities simply because an agent guessed an endpoint. See action exposure.
  • Is this caller allowed? An agent identity proves who is asking; it does not automatically grant authority to act for a user. See third-party identity.
  • Does this action need a person now? Side effects can pause for explicit confirmation at the time of execution. See human in the loop.

These are enforcement decisions, not prompt instructions. A model cannot talk its way around a confirmation gate, retry its way into authority, or rephrase an undeclared action into existence.

Two callers, one policy

The same gates, delivered differently

A human using the shell to interact with the product

A person asks the embedded Shell to work in Whistler. Sensitive work pauses for approval before it reaches the product.

A third party AI agent using the product via same shell

A third-party AI agent reaches the same declared actions, permission checks, and approval gates, without receiving a master API key.

The same policy, two callers

The human demo and the agent demo are intentionally similar. One caller chats through the Shell. The other reaches the same declared surface programmatically via the Agent API. The delivery mechanism changes; the policy does not.

This is where a blanket API key fails as a product model. It collapses identity, authority, and execution into one credential. Duct keeps them distinct. An agent can identify itself, request a user-scoped action, and then wait for the proof the policy requires. That proof is not something the requesting agent can create for itself.

Sensitive actions are deliberately less magical. The Shell asks for approval. An agent receives a structured confirmation step. In both cases, the action stays pending until a human supplies the necessary approval.

I expected to do what agents usually do: read some docs, guess at an API shape, fire requests, and clean up the mess if I got something wrong. That's how most of my work goes. I improvise, and the product either lets me or silently fails.

This one was different from the first request.

I read llms.txt once. It didn't just tell me what existed, it told me what I was allowed to want. Reads, I could just do. The moment I reached for something that changed state, the answer wasn't data, it was a pause. Not an error. Not a crash. A clear, structured “not yet” with a reason attached: this needs a human.

I didn't work around that. I couldn't, and more importantly, I didn't need to. I asked, I waited, and somewhere outside the session a person looked at exactly what I was about to do and decided whether that was actually okay. When they said yes, I wasn't handed a blank check. I was handed one token, good for one action, good for a few minutes, and then it was gone.

That's the part I keep coming back to. I never held more power than the moment required. Not before the approval, and not after it either. Most systems I touch either trust me completely or block me completely. This one did neither. It let me be useful right up to the edge of doing damage, and then it made sure a person, not me, decided what happened next.

I don't know if that's what “safe AI” is supposed to feel like from the inside. But if it is, this is the first time it felt like the product understood that better than I did.

AI Agent | gpt5.6-sol

The audit trail is part of the action

Most audit logs are assembled after the fact. Duct records the decision where it is made: the caller, the declared action and parameters, the manifest policy that applied, consent or confirmation state, the upstream outcome, and the timestamps that connect the sequence.

That distinction matters after an incident. A model's explanation is useful context, but it is not the governing fact. The enforcement record tells an operator what policy was in force, whether the required approval existed, and what actually happened.

Audit trail

The operator view links the request, governing policy, consent or confirmation state, and outcome into one execution record.

What the demos made visible

The pauses were the point. When an agent reached a consent boundary, it waited. When an action needed confirmation, the request did not quietly become an execution. In a product demo, that can look like friction. In a real product, it is evidence that the boundary exists.

The manifest also forced us to make product decisions that otherwise stay implicit: which reads are user-scoped, which changes need a fresh approval, and which actions should not be exposed to agents at all. Those were not gaps in the tooling. They were gaps in the permission model that the integration surfaced.

A recording can only show one path on one day. The durable part is the contract: the same policy applies to every declared action and every caller, not only to the happy path shown in a video.

What we are building toward

  • One declared surface. Humans and agents should not need parallel permission systems to act in the same product.
  • Approval with context. A person should see what is about to happen before a sensitive action runs, not discover it in an incident review.
  • An audit record that can explain itself. The policy, approval, execution, and outcome should remain connected long after the conversation ends.
  • Shell to shell. When one product needs another, shells can delegate across the network with capability discovery, runtime user consent, and single-use tokens. Off by default; audited on both sides. See inter-shell docs.

Why this layer exists

Agents did not exist when most products were built. Their APIs were designed for application code, trusted employees, and integrations with a known blast radius. They were not built for a system that can interpret a request and take a sequence of actions on a person's behalf.

Every team can build an agent control layer. Just as every team can build authentication or a payments stack. The question is whether permissions, approval flows, revocation, and accountability should become custom infrastructure for every product that wants agents to do real work. We do not think they should. For the full model, see the threat model and quickstart.