2026-03-22 15:13:56 +00:00
# Sol
2026-03-21 15:53:49 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
A virtual librarian for Matrix. Sol lives in your chat rooms, archives conversations in OpenSearch, and responds with the help of Mistral AI — with end-to-end encryption, tool use, per-user memory, a multi-agent architecture, and a gRPC coding agent service.
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
Sol is built by [Sunbeam Studios ](https://sunbeam.pt ) as part of our self-hosted collaboration stack.
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
## What Sol Does
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
- **Matrix Presence** — Joins rooms, reads the vibe, decides when to speak. Direct messages always get a response; in group rooms, Sol evaluates relevance before jumping in.
- **Message Archive** — Every message is indexed in OpenSearch with full-text and semantic search. Sol can search its own archive via tools.
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
- **Tool Use** — Mistral calls tools mid-conversation: archive search, code search, room context retrieval, web search, a sandboxed TypeScript/JavaScript runtime (deno_core), and parallel research agents.
2026-03-22 15:13:56 +00:00
- **Per-User Memory** — Sol remembers things about the people it talks to. Memories are extracted automatically after conversations, injected into the system prompt before responding, and accessible from scripts via `sol.memory.get/set` .
- **User Impersonation** — Sol acts on behalf of users when calling external services. PATs are auto-provisioned via admin APIs and stored securely in OpenBao (Vault). OIDC-to-service username mappings handle identity mismatches.
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
- **Gitea Integration** — Devtools agent: list repos, search issues, create issues, list PRs, get file contents, search code, create pull requests — all as the requesting user.
- **Identity Management** — Kratos integration for user account operations: create, get, list, update, delete users via the admin API.
2026-03-22 15:13:56 +00:00
- **Multi-Agent Architecture** — An orchestrator agent with personality + tools + web search. Domain agent delegation is dynamic — only active agents appear in instructions. Agent state is persisted in SQLite with instructions hash for automatic recreation on prompt changes.
- **Conversations API** — Persistent conversation state per room via Mistral's Conversations API, with automatic compaction at token thresholds. Per-message context headers inject timestamps, room info, and memory notes.
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
- **Code Indexing** — Tree-sitter symbol extraction from Gitea repos (Rust, Python, TypeScript, Go, Java). Indexed to OpenSearch for hybrid keyword + semantic code search.
- **gRPC Coding Agent** — Bidirectional streaming service for `sunbeam code` TUI sessions. Transport-agnostic orchestrator emits events; gRPC bridge translates to protobuf. JWT auth in production, dev mode for local use.
- **Research Tool** — Spawns parallel micro-agents with depth control for multi-step research tasks.
- **Web Search** — Self-hosted search via SearXNG. No commercial API keys needed.
2026-03-22 15:13:56 +00:00
- **Multimodal** — `m.image` messages are downloaded from Matrix via `mxc://` , converted to base64 data URIs, and sent as `ContentPart::ImageUrl` to Mistral vision models.
- **Reactions** — Sol can react to messages with emoji when it has something to express but not enough to say.
- **E2EE** — Full end-to-end encryption via matrix-sdk with SQLite state store.
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
## Architecture
2026-03-21 15:53:49 +00:00
2026-03-22 15:00:51 +00:00
```mermaid
flowchart TD
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
subgraph Clients
matrix[Matrix Sync Loop]
grpc[gRPC CodeAgent<br/>sunbeam code TUI]
2026-03-22 15:00:51 +00:00
end
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
subgraph Engagement["Engagement (Matrix only)"]
2026-03-22 15:00:51 +00:00
eval[Evaluator]
rules[Rule Checks]
llm_eval[LLM Evaluation<br/>ministral-3b]
end
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
subgraph Core
orchestrator[Orchestrator<br/>Event-driven, transport-agnostic]
tools[Tool Registry]
agents[Agent Registry<br/>Orchestrator + domain agents]
end
subgraph Tools
server_tools[Server-Side Tools<br/>search_archive, search_code,<br/>list_rooms, get_room_members,<br/>get_room_context, run_script,<br/>search_web, research,<br/>gitea_*, identity_*]
client_tools[Client-Side Tools<br/>file_read, file_write,<br/>search_replace, grep, bash,<br/>list_directory, lsp_*]
2026-03-22 15:00:51 +00:00
end
subgraph Persistence
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
sqlite[(SQLite<br/>conversations, agents,<br/>service_users)]
opensearch[(OpenSearch<br/>archive, memory, code)]
end
subgraph External
mistral[Mistral AI<br/>Agents + Conversations API]
gitea[Gitea<br/>repos, issues, PRs, code]
searxng[SearXNG<br/>web search]
vault[OpenBao<br/>user tokens]
kratos[Kratos<br/>identity management]
2026-03-22 15:00:51 +00:00
end
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
matrix --> eval
2026-03-22 15:00:51 +00:00
eval --> rules
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
rules --> |MustRespond| orchestrator
2026-03-22 15:00:51 +00:00
rules --> |no rule match| llm_eval
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
llm_eval --> |MaybeRespond| orchestrator
llm_eval --> |React/Ignore| matrix
grpc --> orchestrator
orchestrator --> mistral
orchestrator --> tools
tools --> server_tools
tools --> |relay to client| client_tools
server_tools --> opensearch
server_tools --> gitea
server_tools --> searxng
server_tools --> kratos
orchestrator --> |response| matrix
orchestrator --> |events| grpc
orchestrator --> sqlite
matrix --> |archive| opensearch
matrix --> |memory extraction| opensearch
agents --> mistral
2026-03-21 15:53:49 +00:00
```
2026-03-22 15:13:56 +00:00
## Engagement Pipeline
2026-03-21 15:53:49 +00:00
2026-03-22 15:00:51 +00:00
```mermaid
sequenceDiagram
participant M as Matrix
participant S as Sync Handler
participant E as Evaluator
participant LLM as ministral-3b
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
participant O as Orchestrator
2026-03-22 15:00:51 +00:00
M->>S: m.room.message
2026-03-22 15:13:56 +00:00
S->>S: Archive message
S->>S: Update conversation context
2026-03-22 15:00:51 +00:00
S->>E: evaluate(sender, body, is_dm, recent)
2026-03-22 15:13:56 +00:00
alt Own message
2026-03-22 15:00:51 +00:00
E-->>S: Ignore
else @mention or matrix.to link
E-->>S: MustRespond (DirectMention)
else DM
E-->>S: MustRespond (DirectMessage)
else "sol" or "hey sol"
E-->>S: MustRespond (NameInvocation)
2026-03-22 15:13:56 +00:00
else No rule match
E->>LLM: Relevance evaluation (JSON)
2026-03-22 15:00:51 +00:00
LLM-->>E: {relevance, hook, emoji}
alt relevance >= spontaneous_threshold (0.85)
E-->>S: MaybeRespond
else relevance >= reaction_threshold (0.6) + emoji
E-->>S: React (emoji)
2026-03-22 15:13:56 +00:00
else Below thresholds
2026-03-22 15:00:51 +00:00
E-->>S: Ignore
end
end
alt MustRespond or MaybeRespond
2026-03-22 15:13:56 +00:00
S->>S: Check in-flight guard
S->>S: Check cooldown (15s default)
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
S->>O: Generate response
end
```
## Orchestrator
The orchestrator is a transport-agnostic, event-driven pipeline that sits between input sources (Matrix sync, gRPC sessions) and Mistral's Agents API. It has no knowledge of Matrix, gRPC, or any specific UI — transport bridges subscribe to its events and translate to their protocol.
```mermaid
flowchart LR
subgraph Input
matrix_bridge[Matrix Bridge]
grpc_bridge[gRPC Bridge]
end
subgraph Orchestrator
request[GenerateRequest]
engine[Engine<br/>tool loop]
events[OrchestratorEvent<br/>broadcast channel]
2026-03-22 15:00:51 +00:00
end
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
subgraph Output
matrix_out[Matrix Room]
grpc_out[gRPC Stream]
end
matrix_bridge --> request
grpc_bridge --> request
request --> engine
engine --> events
events --> matrix_out
events --> grpc_out
2026-03-22 15:00:51 +00:00
```
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Events emitted during response generation:
| Event | Description |
|-------|-------------|
| `Started` | Generation begun, carries routing metadata |
| `Thinking` | Model is generating |
| `ToolCallDetected` | Tool call found in output (server-side or client-side) |
| `ToolStarted` | Tool execution began |
| `ToolCompleted` | Tool finished with result preview |
| `Done` | Final response text + token usage |
| `Failed` | Generation error |
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Tool dispatch routes calls to either the server (Sol executes them) or the client (relayed to the gRPC TUI for local execution). The orchestrator parks on a oneshot channel for client-side results, transparent to the tool loop.
## gRPC Coding Agent
Sol exposes a `CodeAgent` gRPC service for `sunbeam code` TUI sessions. The protocol is defined in `proto/code.proto` .
```mermaid
sequenceDiagram
participant CLI as sunbeam code
participant gRPC as gRPC Service
participant O as Orchestrator
participant M as Mistral
CLI->>gRPC: StartSession (project context, capabilities)
gRPC->>gRPC: Create Matrix room, auth
gRPC-->>CLI: SessionReady (session_id, room_id, model)
CLI->>gRPC: IndexSymbols (tree-sitter symbols)
gRPC->>gRPC: Index to OpenSearch
CLI->>gRPC: UserInput (text)
gRPC->>O: GenerateRequest
O->>M: Conversation append
alt Server-side tool
O->>O: Execute locally
gRPC-->>CLI: Status (TOOL_RUNNING → TOOL_DONE)
else Client-side tool
gRPC-->>CLI: ToolCall (is_local=true)
CLI->>CLI: Execute (file_read, bash, etc.)
CLI->>gRPC: ToolResult
gRPC->>O: Resume tool loop
end
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
M-->>O: Response text
gRPC-->>CLI: TextDone (full_text, token usage)
```
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Two RPC methods:
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
- **`Session` ** — Bidirectional stream for interactive coding sessions
- **`ReindexCode` ** — On-demand Gitea repo indexing via tree-sitter
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Auth: JWT validation via JWKS in production, fixed dev identity when `grpc.dev_mode = true` .
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
## Tool System
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
### Server-Side Tools
2026-03-22 15:00:51 +00:00
| Tool | Parameters | Description |
|------|-----------|-------------|
| `search_archive` | `query` (required), `room` , `sender` , `after` , `before` , `limit` , `semantic` | Search the message archive (keyword or semantic) |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `search_code` | `query` (required), `language` , `repo` , `branch` , `limit` | Search the code index for functions, types, patterns |
2026-03-22 15:00:51 +00:00
| `get_room_context` | `room_id` (required), `around_timestamp` , `around_event_id` , `before_count` , `after_count` | Get messages around a point in time or event |
| `list_rooms` | * (none) * | List all rooms Sol is in with names and member counts |
| `get_room_members` | `room_id` (required) | Get members of a specific room |
| `run_script` | `code` (required) | Execute TypeScript/JavaScript in a sandboxed deno_core runtime |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `search_web` | `query` (required), `limit` | Search the web via SearXNG |
| `research` | `query` (required), `depth` | Spawn parallel micro-agents for multi-step research |
2026-03-22 15:13:56 +00:00
| `gitea_list_repos` | `query` , `org` , `limit` | List or search repositories on Gitea |
| `gitea_get_repo` | `owner` , `repo` (required) | Get details about a specific repository |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `gitea_search_code` | `query` (required), `repo` , `limit` | Search code across Gitea repositories |
2026-03-22 15:13:56 +00:00
| `gitea_create_issue` | `owner` , `repo` , `title` (required), `body` , `labels` | Create a new issue as the requesting user |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `gitea_create_pr` | `owner` , `repo` , `title` , `head` , `base` (required), `body` | Create a pull request as the requesting user |
2026-03-22 15:13:56 +00:00
| `gitea_get_file` | `owner` , `repo` , `path` (required), `ref` | Get file contents from a repository |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `identity_create_user` | `email` , `name` (required) | Create a new user account via Kratos |
| `identity_get_user` | `email` (required) | Get user account details |
| `identity_list_users` | `limit` | List all user accounts |
| `identity_update_user` | `email` (required), `name` , `active` | Update a user account |
| `identity_delete_user` | `email` (required) | Delete a user account |
Tools are conditionally registered — Gitea tools only appear when `services.gitea` is configured, Kratos tools when `services.kratos` is configured, LSP tools when the client advertises capabilities.
### Client-Side Tools (gRPC sessions)
| Tool | 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 |
| `bash` | ask | Execute shell commands |
| `list_directory` | always | List directory tree |
| `lsp_definition` | always | Jump to definition |
| `lsp_references` | always | Find all references |
| `lsp_hover` | always | Type info + docs |
| `lsp_diagnostics` | always | Compiler errors |
| `lsp_symbols` | always | Document/workspace symbols |
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
### `run_script` Sandbox
2026-03-21 15:53:49 +00:00
2026-03-22 15:00:51 +00:00
The script runtime is a fresh V8 isolate per invocation with:
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
- **TypeScript support** — Code is transpiled via `deno_ast` before execution
- **Timeout** — Configurable via `behavior.script_timeout_secs` (default 5s), enforced by V8 isolate termination
- **Heap limit** — Configurable via `behavior.script_max_heap_mb` (default 64MB)
2026-03-22 15:00:51 +00:00
- **Output** — `console.log()` + last expression value, truncated to 4096 characters
2026-03-22 15:13:56 +00:00
- **Temp filesystem** — Sandboxed `sol.fs.read/write/list` with path traversal protection
2026-03-22 15:00:51 +00:00
- **Network** — `sol.fetch(url)` restricted to `behavior.script_fetch_allowlist` domains
2026-03-21 15:53:49 +00:00
2026-03-22 15:00:51 +00:00
Host API (`sol.*` ):
```typescript
2026-03-22 15:13:56 +00:00
sol.search(query, opts?) // Search message archive
sol.rooms() // List joined rooms → [{name, id, members}]
sol.members(roomName) // Get room members → [{name, id}]
2026-03-22 15:00:51 +00:00
sol.fetch(url) // HTTP GET (allowlisted domains only)
2026-03-22 15:13:56 +00:00
sol.memory.get(query?) // Retrieve memories relevant to query
sol.memory.set(content, category?) // Save a memory note
sol.fs.read(path) // Read file from sandbox
sol.fs.write(path, content) // Write file to sandbox
sol.fs.list(path?) // List sandbox directory
2026-03-22 15:00:51 +00:00
```
All `sol.*` methods are async — use `await` .
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
## Code Indexing
Sol indexes source code from Gitea repositories using tree-sitter for symbol extraction. Symbols are stored in OpenSearch and searchable via the `search_code` tool and adaptive breadcrumbs.
```mermaid
flowchart LR
subgraph Sources
gitea_repos[Gitea Repos<br/>via API]
sidecar[sunbeam code<br/>IndexSymbols]
end
subgraph Extraction
treesitter[Tree-Sitter<br/>Rust, Python, TypeScript,<br/>Go, Java]
end
subgraph Storage
opensearch_code[(OpenSearch<br/>sol_code index)]
end
subgraph Consumers
search_code_tool[search_code tool]
breadcrumbs[Adaptive Breadcrumbs<br/>project outline + hybrid search]
end
gitea_repos --> treesitter
sidecar --> opensearch_code
treesitter --> opensearch_code
opensearch_code --> search_code_tool
opensearch_code --> breadcrumbs
```
Each symbol is a `SymbolDocument` with file path, repo name, language, symbol name/kind, signature, docstring, line numbers, content, branch, and source. The `ReindexCode` gRPC endpoint triggers on-demand indexing for specific orgs, repos, or branches.
2026-03-22 15:13:56 +00:00
## Memory System
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
### Extraction (Post-Response, Fire-and-Forget)
2026-03-22 15:00:51 +00:00
After each response, a background task sends the exchange to `ministral-3b` with a structured extraction prompt. The model returns `{"memories": [{"content": "...", "category": "preference|fact|context"}]}` . Categories are normalized via `normalize_category()` — valid categories are `preference` , `fact` , `context` ; anything else falls back to `general` .
2026-03-22 15:13:56 +00:00
### Storage (OpenSearch)
2026-03-22 15:00:51 +00:00
Each memory is a `MemoryDocument` with: `id` , `user_id` , `content` , `category` , `created_at` , `updated_at` , `source` (`"auto"` or `"script"` ). The index name defaults to `sol_user_memory` . User isolation is enforced at the Rust level via `user_id` filtering on all queries.
2026-03-22 15:13:56 +00:00
### Pre-Response Loading
2026-03-22 15:00:51 +00:00
Before generating a response, the responder loads up to 5 memories:
2026-03-22 15:13:56 +00:00
1. **Topical query ** — Semantic search against the trigger message
2. **Recent backfill ** — If fewer than 3 topical results, fill remaining slots with most recent memories
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
Memory notes are injected into the system prompt (legacy path) or per-message context header (Conversations API path) as a `## notes about {display_name}` block.
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
## Archive
2026-03-22 15:00:51 +00:00
Every message event is archived as an `ArchiveDocument` in OpenSearch:
2026-03-22 15:13:56 +00:00
- **Batch indexing** — Messages are buffered and flushed periodically (`opensearch.batch_size` default 50, `opensearch.flush_interval_ms` default 2000)
- **Embedding pipeline** — Configurable via `opensearch.embedding_pipeline` for semantic search
2026-03-22 15:00:51 +00:00
- **Edit tracking** — `m.replace` events update the original document's content
- **Redaction** — `m.room.redaction` sets `redacted: true` on the original
- **Reactions** — `m.reaction` events append `{sender, emoji, timestamp}` to the document's reactions array
2026-03-22 15:13:56 +00:00
- **Backfill** — On startup, conversation context is backfilled from the archive; reactions are backfilled from Matrix room timelines (last 500 events per room)
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
- **Cross-room visibility** — Search results from other rooms are filtered by member overlap (`behavior.room_overlap_threshold` , default 0.25)
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
## Agent Architecture
2026-03-22 15:00:51 +00:00
```mermaid
stateDiagram-v2
2026-03-22 15:13:56 +00:00
[*] --> CheckHash: Startup
CheckHash --> Restore: Hash matches
CheckHash --> Recreate: Hash changed
Restore --> CheckServer: Agent ID in SQLite
Restore --> SearchByName: Not in SQLite
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
CheckServer --> Ready: Exists on Mistral server
CheckServer --> SearchByName: Gone from server
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
SearchByName --> Recreate: Not found
Recreate --> Ready: Agent created, conversations reset, * sneezes *
2026-03-22 15:00:51 +00:00
Ready --> [*]
```
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
### Orchestrator
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
The orchestrator agent carries Sol's full personality (system prompt) plus all tool definitions converted to `AgentTool` format, including web search. It's created on startup if `agents.use_conversations_api` is enabled.
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
When the system prompt changes, the instructions hash detects staleness and the agent is automatically recreated. All existing conversations are reset and Sol sneezes into all rooms to signal the context reset.
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Agent names can be prefixed via `agents.agent_prefix` — set to `"dev"` in local development to avoid colliding with production agents on the same Mistral account.
2026-03-22 15:13:56 +00:00
### Domain Agents
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Domain agents are defined in `agents/definitions.rs` . The delegation section in the orchestrator's instructions is built dynamically — only agents that are actually registered appear.
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
### User Impersonation
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
Sol authenticates to OpenBao via Kubernetes auth (role `sol-agent` ) and stores per-user PATs at `secret/sol-tokens/{localpart}/{service}` . The `service_users` SQLite table maps Matrix localparts to service-specific usernames, handling cases where OIDC auto-registration produces different names.
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
For Gitea, PATs are auto-provisioned via the admin API on first use. The username is discovered by direct match or email-based search.
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
## Persistence
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
SQLite database at `/data/sol.db` (configurable via `matrix.db_path` ), WAL mode.
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
### Tables
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
- **conversations** — room_id (PK), conversation_id, estimated_tokens, created_at
- **agents** — name (PK), agent_id, model, instructions_hash, created_at
- **service_users** — (localpart, service) PK, service_username, created_at
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
### Recovery Behavior
2026-03-22 15:00:51 +00:00
On startup, if the database fails to open:
1. Log error
2. Fall back to in-memory SQLite (conversations won't survive restarts)
3. After sync loop starts, send `*sneezes*` to all joined rooms to signal the hiccup
2026-03-22 15:13:56 +00:00
The same sneeze happens when the orchestrator agent is recreated due to prompt changes.
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
## Configuration Reference
2026-03-22 15:00:51 +00:00
Config is loaded from `SOL_CONFIG` (default: `/etc/sol/sol.toml` ).
### `[matrix]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `homeserver_url` | string | * required * | Matrix homeserver URL |
| `user_id` | string | * required * | Bot's Matrix user ID |
2026-03-22 15:13:56 +00:00
| `state_store_path` | string | * required * | Path for Matrix SDK SQLite state |
2026-03-22 15:00:51 +00:00
| `db_path` | string | `/data/sol.db` | SQLite database for persistent state |
### `[opensearch]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `url` | string | * required * | OpenSearch cluster URL |
| `index` | string | * required * | Archive index name |
| `batch_size` | usize | `50` | Messages per flush batch |
| `flush_interval_ms` | u64 | `2000` | Flush interval in milliseconds |
| `embedding_pipeline` | string | `tuwunel_embedding_pipeline` | Ingest pipeline for semantic embeddings |
| `memory_index` | string | `sol_user_memory` | Memory index name |
### `[mistral]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `default_model` | string | `mistral-medium-latest` | Model for response generation |
| `evaluation_model` | string | `ministral-3b-latest` | Model for engagement evaluation + memory extraction |
| `research_model` | string | `mistral-large-latest` | Model for research tasks |
| `max_tool_iterations` | usize | `5` | Max tool call rounds per response |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `tokenizer_path` | string? | * (none) * | Path to local `tokenizer.json` (downloads from HuggingFace Hub if unset) |
2026-03-22 15:00:51 +00:00
### `[behavior]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `response_delay_min_ms` | u64 | `100` | Min delay before direct response |
| `response_delay_max_ms` | u64 | `2300` | Max delay before direct response |
| `spontaneous_delay_min_ms` | u64 | `15000` | Min delay before spontaneous response |
| `spontaneous_delay_max_ms` | u64 | `60000` | Max delay before spontaneous response |
| `spontaneous_threshold` | f32 | `0.85` | LLM relevance score to trigger spontaneous response |
| `reaction_threshold` | f32 | `0.6` | LLM relevance score to trigger emoji reaction |
| `reaction_enabled` | bool | `true` | Enable emoji reactions |
2026-03-22 15:13:56 +00:00
| `room_context_window` | usize | `200` | Messages to keep in group room context |
| `dm_context_window` | usize | `200` | Messages to keep in DM context |
2026-03-22 15:00:51 +00:00
| `backfill_on_join` | bool | `true` | Backfill context from archive on startup |
| `backfill_limit` | usize | `10000` | Max messages to backfill |
| `instant_responses` | bool | `false` | Skip response delays (for testing) |
| `cooldown_after_response_ms` | u64 | `15000` | Cooldown before another spontaneous response |
2026-03-22 15:13:56 +00:00
| `evaluation_context_window` | usize | `200` | Recent messages sent to evaluation LLM |
2026-03-22 15:00:51 +00:00
| `detect_sol_in_conversation` | bool | `true` | Use active/passive evaluation prompts based on Sol's participation |
| `evaluation_prompt_active` | string? | * (built-in) * | Custom prompt when Sol is in conversation |
| `evaluation_prompt_passive` | string? | * (built-in) * | Custom prompt when Sol hasn't spoken |
| `script_timeout_secs` | u64 | `5` | Script execution timeout |
| `script_max_heap_mb` | usize | `64` | V8 heap limit for scripts |
| `script_fetch_allowlist` | string[] | `[]` | Domains allowed for `sol.fetch()` |
| `memory_extraction_enabled` | bool | `true` | Enable post-response memory extraction |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `room_overlap_threshold` | f32 | `0.25` | Min member overlap for cross-room search visibility |
| `silence_duration_ms` | u64 | `1800000` | Duration Sol stays quiet when told to (30 minutes) |
2026-03-22 15:00:51 +00:00
### `[agents]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `orchestrator_model` | string | `mistral-medium-latest` | Model for orchestrator agent |
| `domain_model` | string | `mistral-medium-latest` | Model for domain agents |
| `compaction_threshold` | u32 | `118000` | Token estimate before conversation reset (~90% of 131K context) |
| `use_conversations_api` | bool | `false` | Enable Conversations API path (vs legacy chat completions) |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
| `coding_model` | string | `mistral-medium-latest` | Model for `sunbeam code` sessions |
| `research_model` | string | `ministral-3b-latest` | Model for research micro-agents |
| `research_max_iterations` | usize | `10` | Max tool calls per research micro-agent |
| `research_max_agents` | usize | `25` | Max parallel agents per research wave |
| `research_max_depth` | usize | `4` | Max recursion depth for research agents |
| `agent_prefix` | string | `""` | Name prefix for agents (e.g. `"dev"` to avoid production collisions) |
### `[grpc]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `listen_addr` | string | `0.0.0.0:50051` | gRPC server listen address |
| `jwks_url` | string? | * (none) * | JWKS URL for JWT validation (required unless `dev_mode` ) |
| `dev_mode` | bool | `false` | Disable JWT auth, use fixed dev identity |
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
### `[vault]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `url` | string | `http://openbao.data.svc.cluster.local:8200` | OpenBao/Vault URL |
| `role` | string | `sol-agent` | Kubernetes auth role name |
| `mount` | string | `secret` | KV v2 mount path |
### `[services.gitea]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `url` | string | * required if enabled * | Gitea API base URL |
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
### `[services.kratos]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `admin_url` | string | * required if enabled * | Kratos admin API URL |
### `[services.searxng]`
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `url` | string | * required if enabled * | SearXNG API URL |
2026-03-22 15:13:56 +00:00
## Environment Variables
2026-03-22 15:00:51 +00:00
| Variable | Required | Description |
|----------|----------|-------------|
2026-03-22 15:13:56 +00:00
| `SOL_MATRIX_ACCESS_TOKEN` | Yes | Matrix access token |
| `SOL_MATRIX_DEVICE_ID` | Yes | Matrix device ID (for E2EE state) |
| `SOL_MISTRAL_API_KEY` | Yes | Mistral API key |
| `SOL_GITEA_ADMIN_USERNAME` | No | Gitea admin username (enables devtools agent) |
| `SOL_GITEA_ADMIN_PASSWORD` | No | Gitea admin password |
| `SOL_CONFIG` | No | Config file path (default: `/etc/sol/sol.toml` ) |
| `SOL_SYSTEM_PROMPT` | No | System prompt file path (default: `/etc/sol/system_prompt.md` ) |
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
## Dependencies
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Sol talks to seven external services:
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
- **Matrix homeserver** — [Tuwunel ](https://github.com/tulir/tuwunel ) (or any Matrix server)
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
- **OpenSearch** — Message archive, user memory, and code symbol indices
- **Mistral AI** — Response generation, engagement evaluation, memory extraction, agents + conversations
2026-03-22 15:13:56 +00:00
- **OpenBao** — Secure token storage for user impersonation PATs (K8s auth, KV v2)
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
- **Gitea** — Git hosting API for devtools agent (repos, issues, PRs, code search, indexing)
- **Kratos** — Identity management for user account operations
- **SearXNG** — Self-hosted web search (no API keys required)
2026-03-22 15:00:51 +00:00
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Key crates: `matrix-sdk` 0.9 (E2EE + SQLite), `mistralai-client` 1.1.0 (private registry), `opensearch` 2, `deno_core` 0.393, `tonic` 0.14 (gRPC), `tree-sitter` 0.24, `rusqlite` 0.32 (bundled), `ruma` 0.12, `tokenizers` 0.22.
2026-03-21 15:53:49 +00:00
2026-03-22 15:13:56 +00:00
## Building
2026-03-21 15:53:49 +00:00
```sh
cargo build --release
```
2026-03-22 15:13:56 +00:00
Docker (cross-compile to x86_64 Linux, vendored deps):
2026-03-21 15:53:49 +00:00
```sh
docker build -t sol .
```
2026-03-22 15:13:56 +00:00
Production build + deploy:
2026-03-21 15:53:49 +00:00
```sh
2026-03-22 15:00:51 +00:00
sunbeam build sol --push --deploy
2026-03-21 15:53:49 +00:00
```
2026-03-22 15:13:56 +00:00
The Dockerfile uses a two-stage build: deps layer (cached until Cargo.toml/vendor change) → source layer (only Sol code recompiles). Final image is `gcr.io/distroless/cc-debian12:nonroot` .
2026-03-22 15:00:51 +00:00
2026-03-22 15:13:56 +00:00
## Testing
2026-03-21 15:53:49 +00:00
```sh
cargo test
```
docs: comprehensive README rewrite — orchestrator, gRPC, code indexing, new tools
Cover the transport-agnostic orchestrator, gRPC CodeAgent service,
tree-sitter code indexing, client/server tool dispatch, research tool,
SearXNG web search, Kratos identity tools, breadcrumbs, and all new
config sections.
2026-03-24 12:58:18 +00:00
Integration tests against the Mistral API require a `.env` file with `SOL_MISTRAL_API_KEY` :
```sh
cargo test --test integration_test
```
2026-03-22 15:13:56 +00:00
## License
Sol is dual-licensed:
- **Open Source** — [GNU Affero General Public License v3.0 ](LICENSE ) (AGPL-3.0-or-later). You can use, modify, and distribute Sol freely under the AGPL. If you run a modified version as a network service, you must share your changes under the same license.
- **Commercial** — For organizations that want to use Sol without AGPL obligations (private modifications, proprietary integrations, no source disclosure), a commercial license is available. The commercial license grants unlimited internal use but does not permit redistribution.
For commercial licensing or other licensing questions, contact [hello@sunbeam.pt ](mailto:hello@sunbeam.pt ).