Terminal AI Agents Workshop
Table of Contents
Overview
Terminal AI agents represent a paradigm shift in how developers interact with command-line tools. Rather than memorizing flags and piping outputs, developers describe intent and let agents orchestrate tool execution. This research explores patterns for building effective terminal-based AI agents.
Repository: terminal-ai-agents-workshop
Tool Use Patterns
The Tool Abstraction
Terminal agents succeed when tools are well-defined with clear contracts:
- Input schema: JSON Schema defining expected parameters
- Output format: Structured responses agents can parse
- Error handling: Predictable failure modes with actionable messages
- Idempotency: Safe to retry without side effects where possible
Common Tool Categories
| Category | Examples | Agent Considerations |
|---|---|---|
| File System | read, write, glob, grep | Path validation, permission aware |
| Process | bash, background tasks | Timeout handling, output limits |
| Version Control | git status, diff, commit | State awareness, conflict detection |
| Network | fetch, API calls | Rate limiting, caching |
| Analysis | LSP, linting, testing | Context aggregation |
Composition Patterns
Tools compose through several patterns:
- Sequential: Output of one tool feeds input of next
- Parallel: Independent tools run concurrently
- Conditional: Tool selection based on prior results
- Iterative: Repeated tool invocation until condition met
Model Context Protocol (MCP)
MCP standardizes how AI applications connect to external tools and data sources.
Core Concepts
- Servers: Expose tools, resources, and prompts
- Clients: AI applications that connect to servers
- Transports: Communication mechanisms (stdio, HTTP+SSE)
Server Implementation Pattern
from mcp.server import Server from mcp.types import Tool, TextContent server = Server("terminal-tools") @server.tool() async def run_command(command: str, timeout: int = 30) -> str: """Execute a shell command with timeout.""" result = await asyncio.create_subprocess_shell( command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) stdout, stderr = await asyncio.wait_for( result.communicate(), timeout=timeout ) return stdout.decode() if result.returncode == 0 else stderr.decode()
Tool Definition Best Practices
{
"name": "file_search",
"description": "Search for files matching a glob pattern",
"inputSchema": {
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "Glob pattern (e.g., '**/*.py')"
},
"path": {
"type": "string",
"description": "Root directory to search from"
}
},
"required": ["pattern"]
}
}
Agent Architecture
Planning vs Execution
Effective terminal agents separate planning from execution:
- Understand: Parse user intent, gather context
- Plan: Determine tool sequence, identify dependencies
- Execute: Run tools, handle errors, adapt
- Synthesize: Combine results, present to user
Context Management
Terminal agents manage several context types:
- Conversation: Prior messages and decisions
- Codebase: File structure, dependencies, patterns
- Environment: Working directory, available tools
- Task: Current objective and progress
Error Recovery Strategies
| Error Type | Recovery Strategy |
|---|---|
| Tool not found | Search for alternatives, ask user |
| Permission denied | Explain limitation, suggest workaround |
| Timeout | Retry with longer timeout or decompose |
| Parse failure | Request clarification, show raw output |
| Rate limit | Backoff, queue, or switch providers |
Implementation Examples
Claude Code
Anthropic's Claude Code demonstrates production-grade terminal agent patterns:
- Persistent shell sessions with state management
- Parallel tool execution with dependency tracking
- Summarization for context window management
- Hook system for customization
Custom Agents with Agent SDK
from claude_code_sdk import Agent, Tool class TerminalAgent(Agent): def __init__(self): self.tools = [ Tool("bash", self.run_bash), Tool("read_file", self.read_file), Tool("write_file", self.write_file), ] async def run_bash(self, command: str) -> str: # Execute with sandboxing pass async def process(self, user_input: str): # Planning and execution loop pass
Security Considerations
Terminal agents require careful security design:
- Sandboxing: Limit file system and network access
- Command validation: Prevent injection attacks
- Secrets management: Never expose credentials in logs
- Audit logging: Track all tool invocations
- Rate limiting: Prevent runaway execution
Related Research
- Model Context Protocol - Tool use and connector patterns
- Multi-Agent Frameworks - LangGraph, CrewAI, AutoGen
- Agentic Systems Q4 2024 - Research overview