|
| 1 | +# CLAUDE.md — Codebase CLI |
| 2 | + |
| 3 | +## What This Is |
| 4 | + |
| 5 | +An AI coding agent CLI written in Go. Goal: build a **better Claude Code** — simpler |
| 6 | +architecture, any LLM provider, single binary, zero runtime dependencies. |
| 7 | + |
| 8 | +This is NOT a Claude Code clone. We study CC's source as a benchmark for feature coverage |
| 9 | +and learn from their architectural mistakes. Every feature we add should be a better |
| 10 | +implementation, not a copy-paste of their approach. |
| 11 | + |
| 12 | +## Quick Reference |
| 13 | + |
| 14 | +``` |
| 15 | +Language: Go 1.24 |
| 16 | +TUI: BubbleTea (Charm) |
| 17 | +Styling: Lipgloss |
| 18 | +Highlighting: Chroma |
| 19 | +Binary name: codebase |
| 20 | +Config dir: ~/.codebase/ |
| 21 | +Sessions: ~/.codebase/sessions/ |
| 22 | +``` |
| 23 | + |
| 24 | +## Build & Run |
| 25 | + |
| 26 | +```sh |
| 27 | +go build -o codebase . |
| 28 | +./codebase # run in current dir |
| 29 | +./codebase -dir /some/path # run in specific dir |
| 30 | +./codebase -model claude-sonnet-4-20250514 # override model |
| 31 | +./codebase -resume # resume previous session |
| 32 | +CODEBASE_NOBOOT=1 ./codebase # skip boot animation |
| 33 | +``` |
| 34 | + |
| 35 | +## Test |
| 36 | + |
| 37 | +```sh |
| 38 | +go test ./... # all tests |
| 39 | +go test -run TestToolReadFile # specific test |
| 40 | +go test -v -count=1 ./... # verbose, no cache |
| 41 | +``` |
| 42 | + |
| 43 | +## Architecture Overview |
| 44 | + |
| 45 | +See `docs/ARCHITECTURE.md` for the full blueprint and migration plan. |
| 46 | + |
| 47 | +### Current Structure (pre-refactor) |
| 48 | + |
| 49 | +``` |
| 50 | +main.go Entry point, config loading, flag parsing |
| 51 | +app.go BubbleTea root model — routes between screens (boot/setup/chat) |
| 52 | +chat.go Main chat TUI (1,603 LOC — god object, being refactored) |
| 53 | +agent.go Agent loop — goroutine that drives LLM ↔ tool cycle |
| 54 | +tools.go Tool definitions + execution dispatcher (switch statement) |
| 55 | +git_tools.go Git-specific tools (status, diff, log, commit, branch) |
| 56 | +llm.go OpenAI-compatible LLM client + SSE streaming |
| 57 | +llm_anthropic.go Anthropic Messages API adapter + streaming |
| 58 | +permission.go Permission system (ask/trust-tool/trust-all) |
| 59 | +compact.go Conversation compaction via LLM summarization |
| 60 | +session.go Session persistence to ~/.codebase/sessions/ |
| 61 | +commands.go Slash commands (/help, /clear, /compact, /status, etc.) |
| 62 | +glue.go Sidecar LLM for intent routing, narration, titles |
| 63 | +plan.go Planning mode (Q&A before building) |
| 64 | +render.go Viewport rendering helpers, tool block formatters |
| 65 | +search.go Web search (Tavily, Brave, SearXNG, DuckDuckGo) |
| 66 | +boot.go Demoscene boot animation (plasma, 3D cube, pixel font) |
| 67 | +audio.go Chiptune synthesizer (4-channel MOD tracker, pure Go) |
| 68 | +setup.go First-run setup wizard |
| 69 | +diagnostics.go Post-edit language checkers (Go, TypeScript, Python) |
| 70 | +notify.go Notification manager (status bar messages) |
| 71 | +highlight.go Syntax highlighting via Chroma |
| 72 | +theme.go Color themes (dark, light, retro) |
| 73 | +dotenv.go .env file loader |
| 74 | +``` |
| 75 | + |
| 76 | +### Data Flow |
| 77 | + |
| 78 | +``` |
| 79 | +User Input → chatModel.Update() |
| 80 | + → slash command? → commands.go handler |
| 81 | + → agent message? → agent.go goroutine |
| 82 | + → LLM streaming via llm.go / llm_anthropic.go |
| 83 | + → tool calls dispatched via tools.go |
| 84 | + → permission checks via permission.go |
| 85 | + → results sent back as AgentEvent on channel |
| 86 | + → chatModel renders events via render.go |
| 87 | +``` |
| 88 | + |
| 89 | +### Key Patterns |
| 90 | + |
| 91 | +- **Channel-based concurrency**: Agent runs in goroutine, sends events on `eventCh`, |
| 92 | + TUI receives them in `Update()`. No shared mutable state. |
| 93 | +- **Segment-based rendering**: Conversation is `[]segment` (text/user/tool/divider/error). |
| 94 | + Avoids fragile ANSI string manipulation. |
| 95 | +- **Debounced viewport**: Streaming rebuilds throttled to 50ms to prevent TUI thrashing. |
| 96 | +- **Read-only parallel execution**: Tools declaring `EffectReadsFS` run concurrently. |
| 97 | +- **Atomic writes**: Multi-edit uses write→rename for crash safety. |
| 98 | + |
| 99 | +## Environment Variables |
| 100 | + |
| 101 | +### Required (one of) |
| 102 | +``` |
| 103 | +OPENAI_API_KEY OpenAI or compatible provider API key |
| 104 | +ANTHROPIC_API_KEY Anthropic API key (auto-detects protocol) |
| 105 | +``` |
| 106 | + |
| 107 | +### Optional — LLM |
| 108 | +``` |
| 109 | +OPENAI_BASE_URL Custom endpoint (Groq, Ollama, OpenRouter, etc.) |
| 110 | +OPENAI_MODEL Override default model |
| 111 | +``` |
| 112 | + |
| 113 | +### Optional — Glue sidecar |
| 114 | +``` |
| 115 | +GLUE_API_KEY Separate key for cheap/fast model |
| 116 | +GLUE_BASE_URL Separate endpoint for glue |
| 117 | +GLUE_FAST_MODEL Fast model for intent/titles (default: same as main) |
| 118 | +GLUE_SMART_MODEL Smart model for planning/narration |
| 119 | +``` |
| 120 | + |
| 121 | +### Optional — Web Search |
| 122 | +``` |
| 123 | +TAVILY_API_KEY Tavily search (recommended) |
| 124 | +BRAVE_API_KEY Brave Search |
| 125 | +SEARXNG_URL Self-hosted SearXNG instance |
| 126 | +SEARCH_API_KEY Alias for TAVILY_API_KEY |
| 127 | +``` |
| 128 | + |
| 129 | +### Optional — Behavior |
| 130 | +``` |
| 131 | +CODEBASE_NOBOOT Skip boot animation |
| 132 | +CODEBASE_NOSOUND Skip boot audio |
| 133 | +``` |
| 134 | + |
| 135 | +## Coding Conventions |
| 136 | + |
| 137 | +### Go style |
| 138 | +- Standard `gofmt` formatting, no exceptions |
| 139 | +- Error wrapping with context: `fmt.Errorf("toolReadFile: %w", err)` |
| 140 | +- Unexported by default. Only export what's needed cross-package (currently single package) |
| 141 | +- Table-driven tests with `t.Run()` subtests |
| 142 | +- Channel direction on parameters: `ch chan<- AgentEvent`, `stop <-chan struct{}` |
| 143 | + |
| 144 | +### File organization |
| 145 | +- One responsibility per file (aspiration — chat.go violates this, fix in progress) |
| 146 | +- Tests in `*_test.go` alongside source |
| 147 | +- Constants and types at top of file, functions below |
| 148 | +- Section headers with `// ──────────` dividers |
| 149 | + |
| 150 | +### Naming |
| 151 | +- Tool functions: `toolReadFile()`, `toolWriteFile()`, etc. |
| 152 | +- Event types: `EventTextDelta`, `EventToolStart`, etc. |
| 153 | +- States: `chatIdle`, `chatStreaming`, `chatPermission`, etc. |
| 154 | +- Messages (BubbleTea): `agentEventMsg`, `flashTickMsg`, etc. |
| 155 | + |
| 156 | +### What to avoid |
| 157 | +- Don't use `panic()` except for true programmer errors |
| 158 | +- Don't use `init()` except for command registration (commands.go) |
| 159 | +- Don't add dependencies without justification — stdlib first |
| 160 | +- Don't add features without updating `docs/ARCHITECTURE.md` |
| 161 | + |
| 162 | +## Refactoring in Progress |
| 163 | + |
| 164 | +The codebase is undergoing a major architectural refactoring. See `docs/ARCHITECTURE.md` |
| 165 | +sections 7-12 for the migration plan. The phases are: |
| 166 | + |
| 167 | +1. **Tool Interface** — Replace switch dispatch with `Tool` interface + `Registry` |
| 168 | +2. **Permission Engine** — Effect-based policies instead of tool-name checks |
| 169 | +3. **LLM Provider Interface** — Adapter pattern instead of protocol branching |
| 170 | +4. **Agent State Machine** — Explicit FSM instead of implicit state in chatModel |
| 171 | +5. **Token Budget Manager** — Proactive budget instead of heuristic compaction |
| 172 | +6. **MCP Support** — External tool servers via mcp-go |
| 173 | +7. **Slash Commands** — Command interface with auto-discovery |
| 174 | + |
| 175 | +When working on this codebase, check which phase is current and follow that plan. |
| 176 | + |
| 177 | +## Competitive Context: Claude Code Benchmark |
| 178 | + |
| 179 | +We have Claude Code's source code for reference. Key things to know: |
| 180 | + |
| 181 | +### What CC does well (learn from) |
| 182 | +- Tools as self-contained modules with schema validation |
| 183 | +- Streaming tool executor with concurrency control |
| 184 | +- Slash command system (50+ commands) |
| 185 | +- MCP integration for extensibility |
| 186 | +- Git worktree isolation for parallel agents |
| 187 | +- Persistent cross-session memory |
| 188 | + |
| 189 | +### What CC got wrong (do better) |
| 190 | +- **React/Ink for TUI**: 512K LOC for a terminal app. BubbleTea is right-sized. |
| 191 | +- **No clean tool interface**: BashTool is 160K bytes. Each tool is a snowflake. |
| 192 | + We use a `Tool` interface — adding a tool is mechanical. |
| 193 | +- **Permission monster**: 300K+ lines of AST parsing, ML classifiers, hooks cascade. |
| 194 | + We use effect-based policies — tools declare effects, policies match on effects. |
| 195 | +- **God object state**: 30+ field AppState. We use an explicit state machine (FSM). |
| 196 | +- **Three compaction strategies**: They don't coordinate. We use one strategy, |
| 197 | + proactive, with a calibrated token budget. |
| 198 | +- **Retrofitted MCP**: 119K lines because tool system wasn't designed for it. |
| 199 | + Our `Tool` interface treats local and MCP tools identically. |
| 200 | +- **Bun lock-in**: No real benefit for a CLI. We ship a single Go binary. |
| 201 | + |
| 202 | +### Design philosophy difference |
| 203 | +CC optimizes for Anthropic-only with maximum features. We optimize for any-LLM-provider |
| 204 | +with maximum simplicity. Our thesis: 80% of CC's value in 5% of the code, by making |
| 205 | +better foundational choices. |
| 206 | + |
| 207 | +When adding features, always ask: "How did CC do this, and what's a simpler way that |
| 208 | +avoids their pain points?" Check `docs/ARCHITECTURE.md` for the specific analysis. |
| 209 | + |
| 210 | +## Project Files Recognized |
| 211 | + |
| 212 | +The CLI reads these files from the project root for context: |
| 213 | +- `AGENTS.md` — agent instructions (OpenAI Codex convention) |
| 214 | +- `CLAUDE.md` — project instructions (Claude Code convention) |
| 215 | +- `CODEX.md` — project instructions (Codex convention) |
| 216 | +- `.cursorrules` — project instructions (Cursor convention) |
| 217 | + |
| 218 | +All are injected into the system prompt at session start. |
| 219 | + |
| 220 | +## Dependencies (keep minimal) |
| 221 | + |
| 222 | +Direct dependencies only: |
| 223 | +- `charmbracelet/bubbletea` — TUI framework |
| 224 | +- `charmbracelet/bubbles` — TUI components (spinner, textinput, viewport) |
| 225 | +- `charmbracelet/lipgloss` — styling |
| 226 | +- `alecthomas/chroma/v2` — syntax highlighting |
| 227 | +- `lucasb-eyer/go-colorful` — color space conversions (boot animation) |
| 228 | + |
| 229 | +Planned additions: |
| 230 | +- `mark3labs/mcp-go` — MCP client (Phase 6) |
| 231 | + |
| 232 | +Do NOT add dependencies for things the stdlib can do (HTTP, JSON, crypto, etc.). |
0 commit comments