diff --git a/docs/sol-code.md b/docs/sol-code.md
new file mode 100644
index 0000000..3f2b594
--- /dev/null
+++ b/docs/sol-code.md
@@ -0,0 +1,205 @@
+# sunbeam code — Terminal Coding Agent
+
+`sunbeam code` is a terminal-based coding agent powered by Sol. It connects to Sol's gRPC `CodeAgent` service and provides an interactive TUI for writing code, asking questions, and executing tools — with Sol handling the AI reasoning and the CLI handling local file operations.
+
+## Quick Start
+
+```bash
+sunbeam code # start a session (auto-detects project)
+sunbeam code start --model devstral-small # override the model
+sunbeam code start --endpoint http://sol:50051 # custom Sol endpoint
+sunbeam code demo # demo the TUI without Sol
+```
+
+## How It Works
+
+```mermaid
+sequenceDiagram
+ participant User
+ participant TUI as sunbeam code TUI
+ participant Agent as Background Agent
+ participant Sol as Sol gRPC
+
+ User->>TUI: sunbeam code
+ TUI->>TUI: Discover project context
+ TUI->>Agent: Spawn background tasks
+ Agent->>Sol: StartSession (project, capabilities)
+ Agent->>Sol: IndexSymbols (tree-sitter symbols)
+ Sol-->>Agent: SessionReady (session_id, model)
+ Agent-->>TUI: Connected
+
+ User->>TUI: Type message, press Enter
+ TUI->>Agent: Chat request
+ Agent->>Sol: UserInput (text)
+
+ loop Tool calls
+ Sol-->>Agent: ToolCall (is_local=true)
+ Agent->>Agent: Check permissions
+ alt needs approval
+ Agent-->>TUI: Show approval prompt
+ User->>TUI: yes / always / no
+ TUI->>Agent: Decision
+ end
+ Agent->>Agent: Execute tool locally
+ Agent->>Sol: ToolResult
+ end
+
+ Sol-->>Agent: TextDone (response + tokens)
+ Agent-->>TUI: Display response
+```
+
+## Project Discovery
+
+On startup, the CLI discovers project context from the current working directory:
+
+- **Project name** — directory basename
+- **Custom instructions** — `.sunbeam/prompt.md` (injected into Sol's system prompt)
+- **Tool configuration** — `.sunbeam/config.toml` (model + tool permissions)
+- **Git state** — current branch + `git status --short`
+- **File tree** — recursive scan (max depth 2, skips `target/`, `node_modules/`, hidden dirs)
+
+All of this is sent to Sol in the `StartSession` message so it has full project context.
+
+## Symbol Indexing
+
+After connecting, the CLI extracts code symbols from the project using tree-sitter and sends them to Sol via `IndexSymbols`. Sol indexes these in OpenSearch for code search during the session.
+
+Supported languages:
+
+- **Rust** — functions, structs, enums, traits
+- **TypeScript/JavaScript** — functions, classes, interfaces, types
+- **Python** — functions, classes, methods
+
+Each symbol includes name, kind, signature, docstring, line numbers, and a preview of the body.
+
+## Tool Execution
+
+Sol decides which tools to call. Tools marked `is_local=true` execute on your machine; everything else runs on the server.
+
+### Client-Side Tools
+
+| Tool | Default Permission | Description |
+|------|-------------------|-------------|
+| `file_read` | always | Read file contents (with optional line ranges) |
+| `file_write` | ask | Write or create files |
+| `search_replace` | ask | Apply SEARCH/REPLACE diffs to files |
+| `grep` | always | Search files with ripgrep or grep |
+| `bash` | ask | Execute shell commands |
+| `list_directory` | always | List directory tree (with depth limit) |
+
+### LSP Tools
+
+Auto-detected based on project files:
+
+| Project File | Server |
+|-------------|--------|
+| `Cargo.toml` | `rust-analyzer` |
+| `package.json` or `tsconfig.json` | `typescript-language-server` |
+| `pyproject.toml`, `setup.py`, `requirements.txt` | `pyright-langserver` |
+| `go.mod` | `gopls` |
+
+LSP tools: `lsp_definition`, `lsp_references`, `lsp_hover`, `lsp_diagnostics`, `lsp_symbols`. These are advertised as client capabilities in `StartSession` — Sol only registers tools for LSP servers the client can actually spawn.
+
+### Server-Side Tools
+
+Sol can also call its own server-side tools during coding sessions: `search_code`, `search_archive`, `search_web`, `research`, and others. These execute on Sol's side — no local action needed.
+
+## Tool Permissions
+
+Configure in `.sunbeam/config.toml`:
+
+```toml
+[model]
+name = "devstral-2" # override default model
+
+[tools]
+file_read = "always" # always, ask, never
+file_write = "ask"
+bash = "never" # block shell commands entirely
+search_replace = "ask"
+grep = "always"
+list_directory = "always"
+```
+
+Permissions:
+- **`always`** — execute immediately, no prompt
+- **`ask`** — show approval prompt with three choices: *yes*, *yes, always allow*, *no*
+- **`never`** — deny silently, Sol gets an error response
+
+Choosing "yes, always allow" upgrades the permission to `always` for the rest of the session (in-memory only).
+
+## TUI
+
+```mermaid
+flowchart TD
+ subgraph Layout
+ title[Title Bar
project | branch | model | tokens | connection]
+ conversation[Conversation Area
user + assistant messages,
tool output, status]
+ input[Input Bar
current line]
+ end
+
+ title --> conversation
+ conversation --> input
+```
+
+**Key bindings:**
+
+| Key | Action |
+|-----|--------|
+| Enter | Send message |
+| Ctrl+C | Quit |
+| Alt+L | Toggle debug log view |
+| Up/Down | Navigate input history |
+| Page Up/Down | Scroll conversation |
+
+The TUI shows real-time status updates as Sol thinks and executes tools. Approval prompts appear inline when a tool needs permission.
+
+## Session Resumption
+
+Sessions are tied to a project path + git branch. If a session already exists for the current context, Sol resumes it — the TUI loads conversation history and you can continue where you left off.
+
+## Code Reindexing
+
+Separately from coding sessions, you can trigger repo indexing into Sol's code search:
+
+```bash
+sunbeam reindex-code # all repos
+sunbeam reindex-code --org studio # specific org
+sunbeam reindex-code --repo studio/sol --branch main # specific repo + branch
+```
+
+This calls Sol's `ReindexCode` gRPC endpoint, which walks Gitea repos, extracts symbols via tree-sitter, and indexes them to OpenSearch.
+
+## Architecture
+
+The `sunbeam code` command is structured as three concurrent layers:
+
+```mermaid
+flowchart TD
+ subgraph "Main Thread"
+ tui[TUI Event Loop
ratatui, 50ms poll]
+ end
+
+ subgraph "Tokio Runtime"
+ agent[Agent Loop
chat processing,
tool execution]
+ heartbeat[Heartbeat
1s ping to Sol]
+ end
+
+ subgraph "Sol (remote)"
+ grpc_service[gRPC CodeAgent]
+ orchestrator[Orchestrator]
+ mistral[Mistral AI]
+ end
+
+ tui <--> |crossbeam channels| agent
+ agent <--> |gRPC stream| grpc_service
+ heartbeat --> |health check| grpc_service
+ grpc_service --> orchestrator
+ orchestrator --> mistral
+```
+
+- **TUI** (main thread) — Ratatui event loop, renders conversation, handles input, shows tool approval prompts
+- **Agent** (tokio task) — Manages the gRPC session, executes client-side tools, bridges between TUI and Sol via crossbeam channels
+- **Heartbeat** (tokio task) — Pings Sol every second, updates the connection indicator in the title bar
+
+The TUI never blocks on network calls. All gRPC communication happens in the agent task, with events flowing back via bounded channels.