analysis_claude_code/docs/v0-bash-is-all-you-need.md
2026-01-07 11:07:28 +05:30

3.8 KiB

v0: Bash is All You Need

The ultimate simplification: ~50 lines, 1 tool, full agent capability.

After building v1, v2, and v3, a question emerges: what is the essence of an agent?

v0 answers this by going backwards—stripping away everything until only the core remains.

The Core Insight

Unix philosophy: everything is a file, everything can be piped. Bash is the gateway to this world:

You need Bash command
Read files cat, head, grep
Write files echo '...' > file
Search find, grep, rg
Execute python, npm, make
Subagent python v0_bash_agent.py "task"

The last line is the key insight: calling itself via bash implements subagents. No Task tool, no Agent Registry—just recursion.

The Complete Code

#!/usr/bin/env python
from anthropic import Anthropic
import subprocess, sys, os

client = Anthropic(api_key="your-key", base_url="...")
TOOL = [{
    "name": "bash",
    "description": """Execute shell command. Patterns:
- Read: cat/grep/find/ls
- Write: echo '...' > file
- Subagent: python v0_bash_agent.py 'task description'""",
    "input_schema": {"type": "object", "properties": {"command": {"type": "string"}}, "required": ["command"]}
}]
SYSTEM = f"CLI agent at {os.getcwd()}. Use bash. Spawn subagent for complex tasks."

def chat(prompt, history=[]):
    history.append({"role": "user", "content": prompt})
    while True:
        r = client.messages.create(model="...", system=SYSTEM, messages=history, tools=TOOL, max_tokens=8000)
        history.append({"role": "assistant", "content": r.content})
        if r.stop_reason != "tool_use":
            return "".join(b.text for b in r.content if hasattr(b, "text"))
        results = []
        for b in r.content:
            if b.type == "tool_use":
                out = subprocess.run(b.input["command"], shell=True, capture_output=True, text=True, timeout=300)
                results.append({"type": "tool_result", "tool_use_id": b.id, "content": out.stdout + out.stderr})
        history.append({"role": "user", "content": results})

if __name__ == "__main__":
    if len(sys.argv) > 1:
        print(chat(sys.argv[1]))  # Subagent mode
    else:
        h = []
        while (q := input(">> ")) not in ("q", ""):
            print(chat(q, h))

That's the entire agent. ~50 lines.

How Subagents Work

Main Agent
  └─ bash: python v0_bash_agent.py "analyze architecture"
       └─ Subagent (isolated process, fresh history)
            ├─ bash: find . -name "*.py"
            ├─ bash: cat src/main.py
            └─ Returns summary via stdout

Process isolation = Context isolation

  • Child process has its own history=[]
  • Parent captures stdout as tool result
  • Recursive calls enable unlimited nesting

What v0 Sacrifices

Feature v0 v3
Agent types None explore/code/plan
Tool filtering None Whitelists
Progress display Plain stdout Inline updates
Code complexity ~50 lines ~450 lines

What v0 Proves

Complex capabilities emerge from simple rules:

  1. One tool is enough — Bash is the gateway to everything
  2. Recursion = hierarchy — Self-calls implement subagents
  3. Process = isolation — OS provides context separation
  4. Prompt = constraint — Instructions shape behavior

The core pattern never changes:

while True:
    response = model(messages, tools)
    if response.stop_reason != "tool_use":
        return response.text
    results = execute(response.tool_calls)
    messages.append(results)

Everything else—todos, subagents, permissions—is refinement around this loop.


Bash is All You Need.

← Back to README | v1 →