The terminal is the best agent architecture

Most agent tooling is built on a false premise: that we can predict what context the model needs better than the model can. That means brittle retrieval pipelines and custom APIs for every data type. A simpler pattern works better: replace most custom tools with a filesystem and bash. The sales call summarization agent we built this way dropped from roughly $1.00 to $0.25 per call on Claude Opus 4.5, while output quality improved. The same approach powers d0, our text-to-SQL agent.

The reasoning is straightforward. LLMs are trained on massive amounts of code, so they are already experts at navigating directories, grepping through files, and managing state across a codebase. Give an agent the same tools for any domain, and it brings the same capabilities. Customer support tickets, sales transcripts, CRM records: structure them as files, expose bash, and the model uses familiar patterns to find what it needs.

Agent receives task

Explores filesystem (ls, find)

Searches for relevant content (grep, cat)

Sends context + request to LLM

Returns structured output

The agent and its tool execution run on separate compute. The model's reasoning is trusted; the sandbox limits what its actions can reach.

Most agent context strategies fall into two camps. Prompt stuffing fills the context window until it hits token limits. Vector search handles semantic similarity but is imprecise when you need a specific value from structured data. Filesystems have a different tradeoff.

Structure maps to your domain. Customer records and ticket histories have natural hierarchies that map to directories without flattening relationships into embeddings.

Retrieval is exact. grep -r "pricing objection" transcripts/ returns precise matches, not approximations.

Context loads on demand. A long transcript does not enter the prompt upfront. The agent reads metadata, greps relevant sections, and pulls only what it needs.

Structuring domains as files

The pattern applies across domains. In a customer support system, don't throw raw JSON at the agent:

/customers/

/cust_12345/

profile.json # High-level info

tickets/

ticket_001.md # Each ticket

ticket_002.md

conversations/

2024-01-15.txt # Daily conversation logs

preferences.json

When asked "What was the resolution to my issue?", the agent can ls the tickets directory, grep for "resolved", and read the relevant file.

For a document analysis pipeline:

/documents/

/uploaded/

contract_abc123.pdf

invoice_def456.pdf

/extracted/

contract_abc123.txt

invoice_def456.txt

/analysis/

contract_abc123/

summary.md

key_terms.json

risk_assessment.md

/templates/

contract_analysis_prompt.md

invoice_validation_rules.md

Raw inputs sit in one place, processed outputs in structured directories. The agent can reference prior analysis without reprocessing anything.

Case study: a sales call summary agent

The Sales Call Summary template demonstrates the architecture. The agent reads call transcripts and produces structured summaries covering objections, action items, and insights. It starts with this structure:

gong-calls/

demo-call-001-companyname-product-demo.md # Current call transcript

metadata.json # Call metadata

previous-calls/

demo-call-000-discovery-call.md # Prior discovery call

demo-call-intro-initial-call.md # Initial intro call

salesforce/

account.md # CRM account record

opportunity.md # Deal/opportunity details

contacts.md # Contact profiles

slack/

slack-channel.md # Slack history

research/

company-research.md # Company background

competitive-intel.md # Competitor analysis

playbooks/

sales-playbook.md # Internal sales playbook

The agent explores it the way it would a codebase:

# Explore what's available

$ ls sales-calls/

customer-call-123456-q4.md

metadata.json

# Read the metadata

$ cat sales-calls/metadata.json

# Look for objections

$ grep -i "concern\|worried\|issue\|problem" sales-calls/*.md

The transcript is treated like source code. The agent searches for patterns, reads sections, and assembles context the same way it would debug a program. No custom retrieval logic is involved. Because the agent works against the raw information with tools it already knows well, it can handle edge cases that were never anticipated by hand-written parameters.

Why bash and filesystems win

Native model capabilities. grep, cat, find, awk are not novel skills. Models encountered these tools billions of times in training; they are native behavior, not bolted-on tools.

Scaling with future models. As models improve at coding, this architecture improves with them. Each gain in code comprehension transfers directly to the agent's other domains.

Complete debuggability. Failure shows exactly which files were read and which commands were run. The execution path is visible, no black box.

Isolation-based security. The sandbox confines the agent's exploration, separating what it can reason about from what it can affect.

Minimal code. Writing files into a directory structure replaces building retrieval pipelines per data type.

Getting started

When building an agent, resist creating custom tools. Instead ask whether the domain can be represented as files. If so, filesystem plus bash may be all that's needed. The recently open-sourced bash-tool is a dedicated implementation of this pattern.

  1. AI SDK for tool execution and model calls
  2. bash-tool for sandboxed filesystem access
  3. Sales Call Summary template for a one-click working version

More about building agents with Vercel Sandbox.