cmd/codey flag parsing, wiring, REPL
internal/llm Messages API: types, HTTP, SSE, pricing
internal/agent turn loop, conversation state, compaction, sessions
internal/tools the tool registry and the tools
internal/diag language servers and linters, and what they say about an edit
internal/skills discovery and parsing of SKILL.md, Codey's own and Claude Code's
internal/websearch the search command, the URL jail, HTML to text
internal/mcp MCP client: starts the configured servers, offers their tools
internal/config saved defaults: model, effort, approvals, web search, theme, diagnostics
internal/approval allow / deny / ask, with shell analysis and Claude Code's permission rules
internal/ccsettings Claude Code's MCP servers, permission rules and CLAUDE.md, and who may grant what
internal/ask questions the agent puts to you mid-task, and the tool for it
internal/hooks the lifecycle, published: fan-out, and the config's commands
internal/herdr reporting agent state to the herdr pane Codey is running in
internal/attach pictures pasted into a prompt: clipboard, files, markers
internal/metrics JSONL event log
internal/ui line-based terminal rendering
internal/acp Agent Client Protocol: the wire, and its vocabulary
internal/serve Codey as an agent another program drives, over ACP
internal/tui full-screen Bubble Tea front end, and the setup wizard
evals task suite and runner
Two rules hold the shape: agent never imports ui or tui, so the eval
runner and the ACP front end can drive the loop headless; and every tool returns (string, error)
where the error is text the model reads, not an exception Codey swallows.
A failed edit is a normal event in the transcript.
The TUI obeys the first rule through two one-way hatches. Events reach it via
agent.Observe, forwarded into the Bubble Tea loop with Program.Send, which
is safe from the agent's goroutine. Approvals go out the same way and then
block the agent on a reply channel until a key arrives, and questions take the
same hatch with an answer on the way back. Those channels are buffered and the
wait honours the turn's context, so neither side can strand the other.
./evals/selftest.sh # no API calls: checks the tasks measure something
go run ./evals -n 3 # the real thing
Ten tasks, a fresh temp directory per run, full transcripts under
evals/runs/<timestamp>/. See METRICS.md.