@@ -1,39 +1,130 @@
# Crush Development Guide
+## Project Overview
+
+Crush is a terminal-based AI coding assistant built in Go by
+[Charm](https://charm.land). It connects to LLMs and gives them tools to read,
+write, and execute code. It supports multiple providers (Anthropic, OpenAI,
+Gemini, Bedrock, Copilot, Hyper, MiniMax, Vercel, and more), integrates with
+LSPs for code intelligence, and supports extensibility via MCP servers and
+agent skills.
+
+The module path is `github.com/charmbracelet/crush`.
+
+## Architecture
+
+```
+main.go CLI entry point (cobra via internal/cmd)
+internal/
+ app/app.go Top-level wiring: DB, config, agents, LSP, MCP, events
+ cmd/ CLI commands (root, run, login, models, stats, sessions)
+ config/
+ config.go Config struct, context file paths, agent definitions
+ load.go crush.json loading and validation
+ provider.go Provider configuration and model resolution
+ agent/
+ agent.go SessionAgent: runs LLM conversations per session
+ coordinator.go Coordinator: manages named agents ("coder", "task")
+ prompts.go Loads Go-template system prompts
+ templates/ System prompt templates (coder.md.tpl, task.md.tpl, etc.)
+ tools/ All built-in tools (bash, edit, view, grep, glob, etc.)
+ mcp/ MCP client integration
+ session/session.go Session CRUD backed by SQLite
+ message/ Message model and content types
+ db/ SQLite via sqlc, with migrations
+ sql/ Raw SQL queries (consumed by sqlc)
+ migrations/ Schema migrations
+ lsp/ LSP client manager, auto-discovery, on-demand startup
+ ui/ Bubble Tea v2 TUI (see internal/ui/AGENTS.md)
+ permission/ Tool permission checking and allow-lists
+ skills/ Skill file discovery and loading
+ shell/ Bash command execution with background job support
+ event/ Telemetry (PostHog)
+ pubsub/ Internal pub/sub for cross-component messaging
+ filetracker/ Tracks files touched per session
+ history/ Prompt history
+```
+
+### Key Dependency Roles
+
+- **`charm.land/fantasy`**: LLM provider abstraction layer. Handles protocol
+ differences between Anthropic, OpenAI, Gemini, etc. Used in `internal/app`
+ and `internal/agent`.
+- **`charm.land/bubbletea/v2`**: TUI framework powering the interactive UI.
+- **`charm.land/lipgloss/v2`**: Terminal styling.
+- **`charm.land/glamour/v2`**: Markdown rendering in the terminal.
+- **`charm.land/catwalk`**: Snapshot/golden-file testing for TUI components.
+- **`sqlc`**: Generates Go code from SQL queries in `internal/db/sql/`.
+
+### Key Patterns
+
+- **Config is a Service**: accessed via `config.Service`, not global state.
+- **Tools are self-documenting**: each tool has a `.go` implementation and a
+ `.md` description file in `internal/agent/tools/`.
+- **System prompts are Go templates**: `internal/agent/templates/*.md.tpl`
+ with runtime data injected.
+- **Context files**: Crush reads AGENTS.md, CRUSH.md, CLAUDE.md, GEMINI.md
+ (and `.local` variants) from the working directory for project-specific
+ instructions.
+- **Persistence**: SQLite + sqlc. All queries live in `internal/db/sql/`,
+ generated code in `internal/db/`. Migrations in `internal/db/migrations/`.
+- **Pub/sub**: `internal/pubsub` for decoupled communication between agent,
+ UI, and services.
+- **CGO disabled**: builds with `CGO_ENABLED=0` and
+ `GOEXPERIMENT=greenteagc`.
+
## Build/Test/Lint Commands
- **Build**: `go build .` or `go run .`
-- **Test**: `task test` or `go test ./...` (run single test: `go test ./internal/llm/prompt -run TestGetContextFromPaths`)
-- **Update Golden Files**: `go test ./... -update` (regenerates .golden files when test output changes)
- - Update specific package: `go test ./internal/tui/components/core -update` (in this case, we're updating "core")
+- **Test**: `task test` or `go test ./...` (run single test:
+ `go test ./internal/llm/prompt -run TestGetContextFromPaths`)
+- **Update Golden Files**: `go test ./... -update` (regenerates `.golden`
+ files when test output changes)
+ - Update specific package:
+ `go test ./internal/tui/components/core -update` (in this case,
+ we're updating "core")
- **Lint**: `task lint:fix`
- **Format**: `task fmt` (`gofumpt -w .`)
-- **Modernize**: `task modernize` (runs `modernize` which make code simplifications)
+- **Modernize**: `task modernize` (runs `modernize` which makes code
+ simplifications)
- **Dev**: `task dev` (runs with profiling enabled)
## Code Style Guidelines
-- **Imports**: Use `goimports` formatting, group stdlib, external, internal packages
-- **Formatting**: Use gofumpt (stricter than gofmt), enabled in golangci-lint
-- **Naming**: Standard Go conventions - PascalCase for exported, camelCase for unexported
-- **Types**: Prefer explicit types, use type aliases for clarity (e.g., `type AgentName string`)
-- **Error handling**: Return errors explicitly, use `fmt.Errorf` for wrapping
-- **Context**: Always pass `context.Context` as first parameter for operations
-- **Interfaces**: Define interfaces in consuming packages, keep them small and focused
-- **Structs**: Use struct embedding for composition, group related fields
-- **Constants**: Use typed constants with iota for enums, group in const blocks
-- **Testing**: Use testify's `require` package, parallel tests with `t.Parallel()`,
- `t.SetEnv()` to set environment variables. Always use `t.Tempdir()` when in
- need of a temporary directory. This directory does not need to be removed.
-- **JSON tags**: Use snake_case for JSON field names
-- **File permissions**: Use octal notation (0o755, 0o644) for file permissions
-- **Log messages**: Log messages must start with a capital letter (e.g., "Failed to save session" not "failed to save session")
- - This is enforced by `task lint:log` which runs as part of `task lint`
-- **Comments**: End comments in periods unless comments are at the end of the line.
+- **Imports**: Use `goimports` formatting, group stdlib, external, internal
+ packages.
+- **Formatting**: Use gofumpt (stricter than gofmt), enabled in
+ golangci-lint.
+- **Naming**: Standard Go conventions — PascalCase for exported, camelCase
+ for unexported.
+- **Types**: Prefer explicit types, use type aliases for clarity (e.g.,
+ `type AgentName string`).
+- **Error handling**: Return errors explicitly, use `fmt.Errorf` for
+ wrapping.
+- **Context**: Always pass `context.Context` as first parameter for
+ operations.
+- **Interfaces**: Define interfaces in consuming packages, keep them small
+ and focused.
+- **Structs**: Use struct embedding for composition, group related fields.
+- **Constants**: Use typed constants with iota for enums, group in const
+ blocks.
+- **Testing**: Use testify's `require` package, parallel tests with
+ `t.Parallel()`, `t.SetEnv()` to set environment variables. Always use
+ `t.Tempdir()` when in need of a temporary directory. This directory does
+ not need to be removed.
+- **JSON tags**: Use snake_case for JSON field names.
+- **File permissions**: Use octal notation (0o755, 0o644) for file
+ permissions.
+- **Log messages**: Log messages must start with a capital letter (e.g.,
+ "Failed to save session" not "failed to save session").
+ - This is enforced by `task lint:log` which runs as part of `task lint`.
+- **Comments**: End comments in periods unless comments are at the end of the
+ line.
## Testing with Mock Providers
-When writing tests that involve provider configurations, use the mock providers to avoid API calls:
+When writing tests that involve provider configurations, use the mock
+providers to avoid API calls:
```go
func TestYourFunction(t *testing.T) {
@@ -70,9 +161,12 @@ func TestYourFunction(t *testing.T) {
## Committing
-- ALWAYS use semantic commits (`fix:`, `feat:`, `chore:`, `refactor:`, `docs:`, `sec:`, etc).
+- ALWAYS use semantic commits (`fix:`, `feat:`, `chore:`, `refactor:`,
+ `docs:`, `sec:`, etc).
- Try to keep commits to one line, not including your attribution. Only use
multi-line commits when additional context is truly necessary.
## Working on the TUI (UI)
-Anytime you need to work on the tui before starting work read the internal/ui/AGENTS.md file
+
+Anytime you need to work on the TUI, read `internal/ui/AGENTS.md` before
+starting work.