The question everyone is asking about AI agents is the wrong one. We keep asking "how do we make agents smarter?" when we should be asking "how do we make agents trustworthy?"
The answer, it turns out, has been hiding in plain sight for fifty years.
The Trust Problem
AI agents need capabilities to be useful. An agent that can't access files, call APIs, or modify systems is just a chatbot with delusions of grandeur. But every capability we grant is a vector for harm—whether through malicious prompt injection, model hallucination, or simple misconfiguration.
Simon Willison calls this the "lethal trifecta": access to private data, exposure to untrusted content, and the ability to communicate externally. When these three capabilities combine in a single agent, you've created the perfect conditions for data exfiltration, privilege escalation, and system compromise. The security community has been sounding this alarm since Anthropic launched the Model Context Protocol (MCP) in late 2024, and the warnings have only grown louder as agent adoption accelerates.
The current discourse offers two paths. The first: give agents broad access and hope guardrails catch the bad stuff. The second: sandbox them so thoroughly they become useless. Neither is satisfactory.
There's a third path. It's not new. It was documented by Doug McIlroy in 1978.
The UNIX Philosophy as Prior Art
"This is the Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface."— Doug McIlroy, Bell System Technical Journal, 1978
McIlroy, inventor of the Unix pipe, wasn't thinking about AI agents when he wrote this. He was thinking about how to build systems that humans could reason about, maintain, and trust. Small programs with clear interfaces. Composition over monoliths. Explicit data flow rather than implicit state.
The UNIX philosophy works because constraints aren't limitations—they're what make systems trustworthy and composable. When grep only searches text, you can reason about what it does. When ls only lists files, you know its blast radius. When every program speaks the same language (text streams), you can connect them in ways their creators never anticipated.
This maps directly to the agent trust problem.
The CLI as Capability Grant
Consider what happens when you build a well-designed CLI tool for a specific task. You're not just writing software—you're drawing a trust boundary.
Take a tool like namecheap-cli that manages DNS records. A full Namecheap API grants access to domain transfers, registrant changes, billing modifications, and a dozen other operations with significant security implications. But a CLI that exposes only DNS record management? That's a policy decision embedded in code. An agent given this tool can update DNS records and nothing else. It cannot transfer domains. It cannot change registrant details. It cannot access billing information.
The CLI is the policy.
This is capability-based security in practice. The concept dates to Saltzer and Schroeder's 1975 paper "The Protection of Information in Computer Systems," which gave us the principle of least privilege: "Every program and every user of the system should operate using the least set of privileges necessary to complete the job."
When you write a focused CLI, you're making explicit decisions about what operations are permitted, what inputs are valid, what outputs are produced. These are exactly the decisions you'd otherwise have to encode in some agent policy language or guardrail system. But with a CLI, the constraints are enforced by the tool itself—the agent literally cannot exceed them.
The Audit Trail Writes Itself
Here's where it gets interesting. When every action is a tool call with structured arguments, you get a complete execution trace for free.
If an agent invokes:
namecheap-cli dns set --domain example.com --type A --value 1.2.3.4
You have:
- A complete record of intent (the command and its arguments)
- A predictable side effect (exactly one DNS record changes)
- An auditable outcome (exit code, stdout, and queryable state after)
- A reproducible operation (you can replay it, diff it, verify it)
Compare this to giving an agent the Namecheap API credentials directly and asking it to "manage DNS." Now you're relying entirely on the agent's judgment about what operations are appropriate, and your audit log is a stream of API calls that require interpretation to understand.
The UNIX model makes verification tractable. Each tool call is a discrete, observable event with documented semantics. You can build monitoring, alerting, and approval workflows around tool invocations in ways that are nearly impossible with unconstrained API access.
The Secrets Problem
But there's a catch. Tools need credentials. APIs require authentication. An agent that manages DNS needs Namecheap API keys. An agent that deploys code needs cloud credentials. An agent that queries databases needs connection strings.
How do you grant an agent access to these secrets without exposing them?
The naive answer is environment variables or configuration files. But environment variables are inherited by child processes, visible in process listings, and frequently logged. Configuration files persist on disk where any process with sufficient access can read them.
The better answer is to never let the secret exist in a place where it can be observed. This is what tools like 1Password CLI, AWS secrets-helper, and HashiCorp Vault's agent do: they inject secrets into a subprocess environment at runtime, scoped to exactly that process's lifetime.
The pattern is: secrets-tool run --command "namecheap-cli dns set ...". The secrets-tool fetches credentials, spawns the subprocess with those credentials in its environment, and terminates. The credentials exist only in that process's memory for the duration of its execution. They never touch disk. They're not visible to sibling processes. They're not in shell history.
Tools like envctl follow this same pattern. The point isn't any one tool—it's the architecture. Define which secrets a process needs, fetch them at execution time, inject them into exactly one subprocess, and let them evaporate when it terminates.
The agent gets the capability (run this tool with these credentials) without getting the secret material. The credentials never touch disk, never persist beyond the operation.
A Worked Example
Let's trace through what this looks like in practice.
An agent needs to update a DNS record. Without the CLI-as-trust-boundary approach:
- Agent has Namecheap API credentials in its context
- Agent decides which API endpoint to call
- Agent constructs the API request
- Agent makes the call
- You hope the agent made the right decision
With the constrained approach:
- A secrets manager holds the Namecheap API credentials (encrypted, never at rest on the agent's system)
namecheap-cliconstrains what operations are possible (DNS only, specific subcommands, validated inputs)- Agent invokes:
secrets-tool run -- namecheap-cli dns set --domain example.com --type A --value 1.2.3.4 - The secrets manager injects credentials into the subprocess
namecheap-clivalidates the command and executes- Audit trail captures the exact operation
- Credentials evaporate when the process terminates
The agent never sees the credentials. It can only perform operations the CLI permits. Every action is logged. The blast radius is contained.
The Broader Vision
This isn't a product. It's a philosophy.
Every sensitive operation should have a purpose-built CLI. Not because CLI tools are fashionable, but because the CLI boundary is a trust boundary. The tool defines what's possible. The interface makes actions auditable. The exit codes and outputs make verification tractable.
Every credential should flow through a secrets management layer that enforces scoping and ephemeral access. Not because secrets managers are cool, but because the alternative is credentials persisted in places where they can be observed, exfiltrated, or misused.
The agent becomes an orchestrator of constrained capabilities rather than a privileged actor. It composes tools to achieve goals, but each tool has clear semantics and bounded effects. The audit trail is the sequence of tool invocations. The security model is the union of individual tool policies.
This is McIlroy's vision applied to a problem he never anticipated. Small programs that do one thing well. Programs that work together. Programs with clear interfaces that can be reasoned about, monitored, and trusted.
The Irony
We've spent decades building systems that violate every principle McIlroy articulated. Monolithic applications with implicit state. APIs that grant broad access by default. Configuration management that scatters credentials across filesystems and environment variables.
Now we're deploying AI agents into these systems and wondering why they're hard to secure.
The fix isn't more AI. It isn't smarter guardrails. It isn't better prompt engineering.
The fix is better architecture. Small tools. Clear interfaces. Explicit capabilities. Auditable operations. Scoped secrets.
The UNIX philosophy isn't nostalgia. It's engineering wisdom that happens to be exactly what agentic AI needs.