AGENTS.md

  1# Crush Development Guide
  2
  3## Project Overview
  4
  5Crush is a terminal-based AI coding assistant built in Go by
  6[Charm](https://charm.land). It connects to LLMs and gives them tools to read,
  7write, and execute code. It supports multiple providers (Anthropic, OpenAI,
  8Gemini, Bedrock, Copilot, Hyper, MiniMax, Vercel, and more), integrates with
  9LSPs for code intelligence, and supports extensibility via MCP servers and
 10agent skills.
 11
 12The module path is `github.com/charmbracelet/crush`.
 13
 14## Architecture
 15
 16```
 17main.go                            CLI entry point (cobra via internal/cmd)
 18internal/
 19  app/app.go                       Top-level wiring: DB, config, agents, LSP, MCP, events
 20  cmd/                             CLI commands (root, run, login, models, stats, sessions)
 21  config/
 22    config.go                      Config struct, context file paths, agent definitions
 23    load.go                        crush.json loading and validation
 24    provider.go                    Provider configuration and model resolution
 25  agent/
 26    agent.go                       SessionAgent: runs LLM conversations per session
 27    coordinator.go                 Coordinator: manages named agents ("coder", "task")
 28    prompts.go                     Loads Go-template system prompts
 29    templates/                     System prompt templates (coder.md.tpl, task.md.tpl, etc.)
 30    tools/                         All built-in tools (bash, edit, view, grep, glob, etc.)
 31      mcp/                         MCP client integration
 32  session/session.go               Session CRUD backed by SQLite
 33  message/                         Message model and content types
 34  db/                              SQLite via sqlc, with migrations
 35    sql/                           Raw SQL queries (consumed by sqlc)
 36    migrations/                    Schema migrations
 37  lsp/                             LSP client manager, auto-discovery, on-demand startup
 38  ui/                              Bubble Tea v2 TUI (see internal/ui/AGENTS.md)
 39  permission/                      Tool permission checking and allow-lists
 40  skills/                          Skill file discovery and loading
 41  shell/                           Bash command execution with background job support
 42  event/                           Telemetry (PostHog)
 43  pubsub/                          Internal pub/sub for cross-component messaging
 44  filetracker/                     Tracks files touched per session
 45  history/                         Prompt history
 46```
 47
 48### Key Dependency Roles
 49
 50- **`charm.land/fantasy`**: LLM provider abstraction layer. Handles protocol
 51  differences between Anthropic, OpenAI, Gemini, etc. Used in `internal/app`
 52  and `internal/agent`.
 53- **`charm.land/bubbletea/v2`**: TUI framework powering the interactive UI.
 54- **`charm.land/lipgloss/v2`**: Terminal styling.
 55- **`charm.land/glamour/v2`**: Markdown rendering in the terminal.
 56- **`charm.land/catwalk`**: Snapshot/golden-file testing for TUI components.
 57- **`sqlc`**: Generates Go code from SQL queries in `internal/db/sql/`.
 58
 59### Key Patterns
 60
 61- **Config is a Service**: accessed via `config.Service`, not global state.
 62- **Tools are self-documenting**: each tool has a `.go` implementation and a
 63  `.md` description file in `internal/agent/tools/`.
 64- **System prompts are Go templates**: `internal/agent/templates/*.md.tpl`
 65  with runtime data injected.
 66- **Context files**: Crush reads AGENTS.md, CRUSH.md, CLAUDE.md, GEMINI.md
 67  (and `.local` variants) from the working directory for project-specific
 68  instructions.
 69- **Persistence**: SQLite + sqlc. All queries live in `internal/db/sql/`,
 70  generated code in `internal/db/`. Migrations in `internal/db/migrations/`.
 71- **Pub/sub**: `internal/pubsub` for decoupled communication between agent,
 72  UI, and services.
 73- **CGO disabled**: builds with `CGO_ENABLED=0` and
 74  `GOEXPERIMENT=greenteagc`.
 75
 76## Build/Test/Lint Commands
 77
 78- **Build**: `go build .` or `go run .`
 79- **Test**: `task test` or `go test ./...` (run single test:
 80  `go test ./internal/llm/prompt -run TestGetContextFromPaths`)
 81- **Update Golden Files**: `go test ./... -update` (regenerates `.golden`
 82  files when test output changes)
 83  - Update specific package:
 84    `go test ./internal/tui/components/core -update` (in this case,
 85    we're updating "core")
 86- **Lint**: `task lint:fix`
 87- **Format**: `task fmt` (`gofumpt -w .`)
 88- **Modernize**: `task modernize` (runs `modernize` which makes code
 89  simplifications)
 90- **Dev**: `task dev` (runs with profiling enabled)
 91- **Pre-commit flow**: `task fmt lint-fix test`
 92
 93## Code Style Guidelines
 94
 95- **Imports**: Use `goimports` formatting, group stdlib, external, internal
 96  packages.
 97- **Formatting**: Use gofumpt (stricter than gofmt), enabled in
 98  golangci-lint.
 99- **Naming**: Standard Go conventions — PascalCase for exported, camelCase
100  for unexported.
101- **Types**: Prefer explicit types, use type aliases for clarity (e.g.,
102  `type AgentName string`).
103- **Error handling**: Return errors explicitly, use `fmt.Errorf` for
104  wrapping.
105- **Context**: Always pass `context.Context` as first parameter for
106  operations.
107- **Interfaces**: Define interfaces in consuming packages, keep them small
108  and focused.
109- **Structs**: Use struct embedding for composition, group related fields.
110- **Constants**: Use typed constants with iota for enums, group in const
111  blocks.
112- **Testing**: Use testify's `require` package, parallel tests with
113  `t.Parallel()`, `t.SetEnv()` to set environment variables. Always use
114  `t.Tempdir()` when in need of a temporary directory. This directory does
115  not need to be removed.
116- **JSON tags**: Use snake_case for JSON field names.
117- **File permissions**: Use octal notation (0o755, 0o644) for file
118  permissions.
119- **Log messages**: Log messages must start with a capital letter (e.g.,
120  "Failed to save session" not "failed to save session").
121  - This is enforced by `task lint:log` which runs as part of `task lint`.
122- **Comments**: End comments in periods unless comments are at the end of the
123  line.
124
125## Testing with Mock Providers
126
127When writing tests that involve provider configurations, use the mock
128providers to avoid API calls:
129
130```go
131func TestYourFunction(t *testing.T) {
132    // Enable mock providers for testing
133    originalUseMock := config.UseMockProviders
134    config.UseMockProviders = true
135    defer func() {
136        config.UseMockProviders = originalUseMock
137        config.ResetProviders()
138    }()
139
140    // Reset providers to ensure fresh mock data
141    config.ResetProviders()
142
143    // Your test code here - providers will now return mock data
144    providers := config.Providers()
145    // ... test logic
146}
147```
148
149## Formatting
150
151- ALWAYS format any Go code you write.
152  - First, try `gofumpt -w .`.
153  - If `gofumpt` is not available, use `goimports`.
154  - If `goimports` is not available, use `gofmt`.
155  - You can also use `task fmt` to run `gofumpt -w .` on the entire project,
156    as long as `gofumpt` is on the `PATH`.
157
158## Comments
159
160- Comments that live on their own lines should start with capital letters and
161  end with periods. Wrap comments at 78 columns.
162
163## Committing
164
165- ALWAYS use semantic commits (`fix:`, `feat:`, `chore:`, `refactor:`,
166  `docs:`, `sec:`, etc).
167- Try to keep commits to one line, not including your attribution. Only use
168  multi-line commits when additional context is truly necessary.
169
170## Working on the TUI (UI)
171
172Anytime you need to work on the TUI, read `internal/ui/AGENTS.md` before
173starting work.