|
| 1 | +# Sofos - AI Coding Assistant Project Context |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +Sofos is a terminal-based AI coding assistant powered by Anthropic's Claude API. It's built in Rust for maximum performance and security. The assistant can read/write files, search code, execute bash commands, and search the web - all within a sandboxed environment. |
| 6 | + |
| 7 | +**Core Philosophy:** |
| 8 | +- Security first: All operations are sandboxed to the workspace directory |
| 9 | +- Fast and efficient: Native Rust implementation with optional ultra-fast editing via Morph API |
| 10 | +- Developer-friendly: Interactive REPL with session persistence and custom instructions |
| 11 | +- Transparent: All tool executions are visible to the user |
| 12 | + |
| 13 | +## Architecture |
| 14 | + |
| 15 | +### Key Design Decisions |
| 16 | + |
| 17 | +1. **Dual Session Storage Format** (src/history.rs) |
| 18 | + - `api_messages`: Anthropic API format for continuing conversations |
| 19 | + - `display_messages`: UI-friendly format for showing conversation history |
| 20 | + - This separation ensures Claude sees proper API format while users see original UI |
| 21 | + |
| 22 | +2. **Tool Calling Pattern** (src/repl.rs) |
| 23 | + - Assistant returns content blocks (text + tool_use) |
| 24 | + - REPL executes tools and collects results |
| 25 | + - Results sent back as user message with tool_result blocks |
| 26 | + - Recursive handling allows Claude to use multiple tools in sequence |
| 27 | + |
| 28 | +3. **Two-Level Instructions** (src/history.rs) |
| 29 | + - `.sofosrc`: Project-level, version controlled |
| 30 | + - `.sofos/instructions.md`: Personal, gitignored |
| 31 | + - Both appended to system prompt at startup |
| 32 | + |
| 33 | +4. **Sandboxing Strategy** (src/tools/filesystem.rs, src/tools/bashexec.rs) |
| 34 | + - All paths validated before operations |
| 35 | + - Parent directory traversal blocked (`..`) |
| 36 | + - Absolute paths rejected |
| 37 | + - Symlinks checked to prevent escape |
| 38 | + - Bash commands filtered through blocklist |
| 39 | + |
| 40 | +## Code Organization |
| 41 | + |
| 42 | +### Directory Structure |
| 43 | + |
| 44 | +``` |
| 45 | +src/ |
| 46 | +├── api/ # Anthropic API integration |
| 47 | +│ ├── client.rs # HTTP client for Claude API |
| 48 | +│ ├── morph.rs # Morph Apply API client (optional) |
| 49 | +│ ├── types.rs # Message types and serialization |
| 50 | +│ └── mod.rs |
| 51 | +├── tools/ # Tool implementations |
| 52 | +│ ├── filesystem.rs # File operations (read, write, list, etc) |
| 53 | +│ ├── bashexec.rs # Sandboxed bash execution |
| 54 | +│ ├── codesearch.rs # Ripgrep integration |
| 55 | +│ ├── types.rs # Tool definitions for API |
| 56 | +│ └── mod.rs |
| 57 | +├── conversation.rs # Message history management |
| 58 | +├── history.rs # Session persistence + custom instructions |
| 59 | +├── repl.rs # Main REPL loop and display logic |
| 60 | +├── syntax.rs # Markdown/code syntax highlighting |
| 61 | +├── cli.rs # Command-line argument parsing |
| 62 | +├── error.rs # Error types |
| 63 | +├── session_selector.rs # TUI for session selection |
| 64 | +└── main.rs # Entry point |
| 65 | +``` |
| 66 | + |
| 67 | +### Key Files |
| 68 | + |
| 69 | +**src/api/types.rs** |
| 70 | +- Defines Message, ContentBlock, and MessageContentBlock enums |
| 71 | +- Handles serialization/deserialization for Anthropic API |
| 72 | +- Supports both regular and server-side tools (like web_search) |
| 73 | + |
| 74 | +**src/history.rs** |
| 75 | +- SessionMetadata: Preview and timestamps for session list |
| 76 | +- Session: Dual storage (api_messages + display_messages) |
| 77 | +- DisplayMessage: Enum for user messages, assistant responses, and tool executions |
| 78 | + |
| 79 | +**src/repl.rs** |
| 80 | +- Main event loop (run method) |
| 81 | +- handle_response: Recursively processes assistant responses and tool calls |
| 82 | +- display_session: Reconstructs conversation UI when resuming |
| 83 | +- Max recursion depth: 50 (prevents infinite loops) |
| 84 | + |
| 85 | +**src/conversation.rs** |
| 86 | +- Manages in-memory message history |
| 87 | +- Trims to MAX_MESSAGES (500) to prevent token overflow |
| 88 | +- Builds system prompt with features list and custom instructions |
| 89 | + |
| 90 | +**src/tools/filesystem.rs** |
| 91 | +- validate_path: Security-critical path validation |
| 92 | +- All operations check sandboxing before execution |
| 93 | +- File size limit: 10MB to prevent memory issues |
| 94 | +- User confirmation required for deletions |
| 95 | + |
| 96 | +**src/tools/bashexec.rs** |
| 97 | +- COMMAND_BLOCKLIST: Dangerous commands that are always rejected |
| 98 | +- Output size limit: 50MB |
| 99 | +- No sudo, no file modifications, no directory changes |
| 100 | +- Read-only operations only |
| 101 | + |
| 102 | +## Code Conventions |
| 103 | + |
| 104 | +### Rust Style |
| 105 | +- Follow standard Rust idioms and conventions |
| 106 | +- Use meaningful variable names (no single-letter except in loops) |
| 107 | +- Prefer `Result<T>` over `panic!` for error handling |
| 108 | +- Use `?` operator for error propagation |
| 109 | +- Keep functions focused and under ~100 lines |
| 110 | + |
| 111 | +### Error Handling |
| 112 | +- Custom `SofosError` enum in src/error.rs |
| 113 | +- Always provide context in error messages |
| 114 | +- Use `map_err` to add context when propagating errors |
| 115 | +- Display user-friendly error messages in REPL |
| 116 | + |
| 117 | +### Testing |
| 118 | +- Unit tests in the same file under `#[cfg(test)]` |
| 119 | +- Use `tempfile::TempDir` for filesystem tests |
| 120 | +- Mock API calls in tests (don't require real API keys) |
| 121 | +- Test security features thoroughly (path validation, sandboxing) |
| 122 | + |
| 123 | +### Documentation |
| 124 | +- Add doc comments (`///`) for public APIs |
| 125 | +- Explain "why" not just "what" in complex sections |
| 126 | +- Keep comments up-to-date with code changes |
| 127 | +- README.md is the primary user documentation |
| 128 | + |
| 129 | +## Security Considerations |
| 130 | + |
| 131 | +**Critical Security Features:** |
| 132 | + |
| 133 | +1. **Path Validation** (filesystem.rs:validate_path) |
| 134 | + - Canonicalize paths to resolve symlinks |
| 135 | + - Check that canonical path starts with workspace |
| 136 | + - Reject parent traversal (`..`) |
| 137 | + - Reject absolute paths |
| 138 | + - This is the first line of defense - NEVER bypass! |
| 139 | + |
| 140 | +2. **Bash Command Filtering** (bashexec.rs) |
| 141 | + - Blocklist of dangerous commands (`rm`, `sudo`, `chmod`, etc) |
| 142 | + - No output redirection (`>`, `>>`, `|`, `&`) |
| 143 | + - No directory changes (`cd`, `pushd`, `popd`) |
| 144 | + - No background execution (`&`) |
| 145 | + - Read-only operations only |
| 146 | + |
| 147 | +3. **File Size Limits** |
| 148 | + - Read operations: 10MB limit |
| 149 | + - Bash output: 50MB limit |
| 150 | + - Prevents memory exhaustion attacks |
| 151 | + |
| 152 | +4. **User Confirmations** |
| 153 | + - Delete operations require interactive confirmation |
| 154 | + - Shows what will be deleted before execution |
| 155 | + - User can cancel by declining |
| 156 | + |
| 157 | +**When Adding New Features:** |
| 158 | +- Always consider security implications first |
| 159 | +- Add path validation for any new file operations |
| 160 | +- Update blocklist if adding bash command capabilities |
| 161 | +- Test with malicious inputs (path traversal attempts, etc) |
| 162 | + |
| 163 | +## Important Implementation Details |
| 164 | + |
| 165 | +### Session Persistence |
| 166 | + |
| 167 | +**Session File Location:** |
| 168 | +- Stored in `.sofos/sessions/{session_id}.json` |
| 169 | +- Index file: `.sofos/sessions/index.json` |
| 170 | +- Entire `.sofos/` directory is gitignored |
| 171 | + |
| 172 | +### Message Flow |
| 173 | + |
| 174 | +**User sends message:** |
| 175 | +1. REPL adds to conversation history as user message |
| 176 | +2. Creates API request with all messages + system prompt |
| 177 | +3. Sends to Claude API |
| 178 | + |
| 179 | +**Claude responds with tools:** |
| 180 | +1. Response contains text + tool_use blocks |
| 181 | +2. REPL adds full response (with both text and tool_use) to history as assistant message |
| 182 | +3. Executes each tool sequentially |
| 183 | +4. Collects all tool results |
| 184 | +5. Adds all results as single user message |
| 185 | +6. Makes new API request (recursive call to handle_response) |
| 186 | + |
| 187 | +**Important:** Tool results must be in a user message, with tool_use_id matching the original tool_use id. |
| 188 | + |
| 189 | +### Custom Instructions Loading |
| 190 | + |
| 191 | +**Load order (history.rs:load_custom_instructions):** |
| 192 | +1. Load `.sofosrc` from project root (if exists) |
| 193 | +2. Load `.sofos/instructions.md` from workspace (if exists) |
| 194 | +3. Combine with headers ("# Project Instructions", "# Personal Instructions") |
| 195 | +4. Append to system prompt |
| 196 | + |
| 197 | +**Display:** |
| 198 | +- If either file exists, show "Loaded custom instructions" in green |
| 199 | +- Silent if neither exists |
| 200 | + |
| 201 | +### Recursion Depth Limiting |
| 202 | + |
| 203 | +**Problem:** Claude can make infinite tool calls if it gets stuck in a loop |
| 204 | + |
| 205 | +**Solution:** (repl.rs:handle_response) |
| 206 | +- Track recursion depth in REPL struct |
| 207 | +- MAX_RECURSION_DEPTH = 50 |
| 208 | +- If exceeded, show warning and stop |
| 209 | +- Reset to 0 at start of new user message |
| 210 | + |
| 211 | +### Thinking Animation |
| 212 | + |
| 213 | +When waiting for Claude's response after tool execution: |
| 214 | +- Show animated spinner ("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏") |
| 215 | +- Orange color (0xFF, 0x99, 0x33) |
| 216 | +- "Thinking..." text |
| 217 | +- Clears when response arrives |
| 218 | + |
| 219 | +## Dependencies |
| 220 | + |
| 221 | +### Core Dependencies |
| 222 | +- `tokio`: Async runtime for HTTP requests |
| 223 | +- `reqwest`: HTTP client for API calls |
| 224 | +- `serde`, `serde_json`: Serialization/deserialization |
| 225 | +- `colored`: Terminal colors and formatting |
| 226 | +- `rustyline`: REPL with readline support |
| 227 | +- `clap`: Command-line argument parsing |
| 228 | + |
| 229 | +### Optional Dependencies |
| 230 | +- `ripgrep`: Code search functionality (runtime check) |
| 231 | +- Morph API: Ultra-fast code editing (via MORPH_API_KEY) |
| 232 | + |
| 233 | +### Why These Choices? |
| 234 | +- `tokio` + `reqwest`: Industry standard for async HTTP in Rust |
| 235 | +- `rustyline`: Best readline implementation for Rust CLIs |
| 236 | +- `colored`: Simple, cross-platform terminal colors |
| 237 | +- Native dependencies minimal (only ripgrep, which is optional) |
| 238 | + |
| 239 | +## Testing Strategy |
| 240 | + |
| 241 | +### What to Test |
| 242 | +- Path validation with various malicious inputs |
| 243 | +- Bash command blocklist effectiveness |
| 244 | +- Session save/load with different formats |
| 245 | +- Message trimming behavior |
| 246 | +- Tool execution and result collection |
| 247 | + |
| 248 | +### What Not to Test |
| 249 | +- Actual Claude API responses (too expensive, non-deterministic) |
| 250 | +- Actual file I/O in most cases (use TempDir) |
| 251 | +- Network requests (mock when possible) |
| 252 | + |
| 253 | +### Running Tests |
| 254 | +```bash |
| 255 | +cargo test # All tests |
| 256 | +cargo test filesystem # Just filesystem tests |
| 257 | +cargo test -- --nocapture # Show println output |
| 258 | +``` |
| 259 | + |
| 260 | +## Common Tasks |
| 261 | + |
| 262 | +### Adding a New Tool |
| 263 | + |
| 264 | +1. Define tool in `src/tools/types.rs` (get_tools or get_tools_with_morph) |
| 265 | +2. Implement execution in appropriate file (filesystem.rs, bashexec.rs, etc) |
| 266 | +3. Add match arm in `src/tools/mod.rs` (ToolExecutor::execute) |
| 267 | +4. Test the new tool thoroughly |
| 268 | +5. Update README.md with tool description |
| 269 | + |
| 270 | +### Adding a New API Field |
| 271 | + |
| 272 | +1. Update types in `src/api/types.rs` |
| 273 | +2. Add serde attributes for proper serialization |
| 274 | +3. Handle in response processing (repl.rs:handle_response) |
| 275 | +4. Test with actual API if possible |
| 276 | + |
| 277 | +### Debugging Tool Execution |
| 278 | + |
| 279 | +Set `SOFOS_DEBUG=1` environment variable: |
| 280 | +```bash |
| 281 | +SOFOS_DEBUG=1 cargo run |
| 282 | +``` |
| 283 | + |
| 284 | +This prints: |
| 285 | +- Recursion depth at each step |
| 286 | +- Number of tools being executed |
| 287 | +- Tool success/failure and output length |
| 288 | +- Conversation state before API calls |
| 289 | + |
| 290 | +## Version Compatibility |
| 291 | + |
| 292 | +### Anthropic API |
| 293 | +- Uses Claude Messages API (not legacy Completions) |
| 294 | +- Model: claude-sonnet-4-5 (default) |
| 295 | +- Supports tool calling and server-side tools (web_search) |
| 296 | +- API version: 2023-06-01 |
| 297 | + |
| 298 | +### Morph API |
| 299 | +- Uses Morph Apply REST API |
| 300 | +- Model: morph-v3-fast (default) |
| 301 | +- Optional integration via MORPH_API_KEY |
| 302 | +- Provides `morph_edit_file` tool when available |
| 303 | + |
| 304 | +## Future Considerations |
| 305 | + |
| 306 | +**Potential Improvements:** |
| 307 | +- Streaming responses for faster perceived performance |
| 308 | +- Multiple parallel tool executions (currently sequential) |
| 309 | +- Richer TUI with panels and split views |
| 310 | +- Plugin system for custom tools |
| 311 | +- Configuration file for default settings |
| 312 | + |
| 313 | +**Constraints:** |
| 314 | +- Keep binary size small (currently ~5MB) |
| 315 | +- Maintain zero-setup experience (except API keys) |
| 316 | +- Keep security as top priority |
| 317 | + |
| 318 | +## When Working on This Codebase |
| 319 | + |
| 320 | +**Always:** |
| 321 | +- Test security features when making changes to filesystem or bash tools |
| 322 | +- Update both README.md and this .sofosrc when adding features |
| 323 | +- Run `cargo test` before committing |
| 324 | +- Add helpful error messages for user-facing errors |
| 325 | + |
| 326 | +**Never:** |
| 327 | +- Skip path validation in file operations |
| 328 | +- Add commands to bash without security review |
| 329 | +- Panic in user-facing code (use Result and show errors gracefully) |
| 330 | +- Break the tool calling protocol (tool_use -> tool_result matching) |
| 331 | +- Commit API keys or sensitive data |
| 332 | + |
| 333 | +**Code Review Checklist:** |
| 334 | +- [ ] Security: Path validation present and correct? |
| 335 | +- [ ] Security: New bash commands in blocklist if needed? |
| 336 | +- [ ] Error handling: All Results properly handled? |
| 337 | +- [ ] Tests: Added tests for new functionality? |
| 338 | +- [ ] Docs: Updated README if user-visible change? |
| 339 | +- [ ] UX: Error messages clear and actionable? |
| 340 | + |
| 341 | +--- |
| 342 | + |
| 343 | +This file is loaded by Sofos and appended to the system prompt, providing deep project context for AI-assisted development. |
0 commit comments