# Sofos - AI Coding Assistant Project Context
## Project Overview
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.
**Core Philosophy:**
- Security first: All operations are sandboxed to the workspace directory
- Fast and efficient: Native Rust implementation with optional ultra-fast editing via Morph API
- Developer-friendly: Interactive REPL with session persistence and custom instructions
- Transparent: All tool executions are visible to the user
## Architecture
### Key Design Decisions
1. **Dual Session Storage Format** (src/history.rs)
- `api_messages`: Anthropic API format for continuing conversations
- `display_messages`: UI-friendly format for showing conversation history
- This separation ensures Claude sees proper API format while users see original UI
2. **Tool Calling Pattern** (src/repl.rs)
- Assistant returns content blocks (text + tool_use)
- REPL executes tools and collects results
- Results sent back as user message with tool_result blocks
- **Loop-based handling** allows Claude to use multiple tools in sequence iteratively
3. **Two-Level Instructions** (src/history.rs)
- `.sofosrc`: Project-level, version controlled
- `.sofos/instructions.md`: Personal, gitignored
- Both appended to system prompt at startup
4. **Sandboxing Strategy** (src/tools/filesystem.rs, src/tools/bashexec.rs)
- All paths validated before operations
- Parent directory traversal blocked (`..`)
- Absolute paths rejected
- Symlinks checked to prevent escape
- Bash commands filtered through blocklist
## Code Organization
### Directory Structure
```
src/
├── api/ # Anthropic API integration
│ ├── client.rs # HTTP client for Claude API
│ ├── morph.rs # Morph Apply API client (optional)
│ ├── types.rs # Message types and serialization
│ └── mod.rs
├── tools/ # Tool implementations
│ ├── filesystem.rs # File operations (read, write, list, etc)
│ ├── bashexec.rs # Sandboxed bash execution
│ ├── codesearch.rs # Ripgrep integration
│ ├── permissions.rs # 3-tier command permission system
│ ├── types.rs # Tool definitions for API
│ └── mod.rs
├── conversation.rs # Message history management
├── diff.rs # Contextual diff generation and display
├── history.rs # Session persistence + custom instructions
├── repl.rs # Main REPL loop and display logic
├── syntax.rs # Markdown/code syntax highlighting
├── cli.rs # Command-line argument parsing
├── error.rs # Error types
├── session_selector.rs # TUI for session selection
└── main.rs # Entry point
```
### Key Files
**src/api/types.rs**
- Defines Message, ContentBlock, and MessageContentBlock enums
- Handles serialization/deserialization for Anthropic API
- Supports both regular and server-side tools (like web_search)
**src/diff.rs**
- Generate contextual diffs showing only changed code blocks
- Uses `similar` crate for accurate line-by-line diffing
- Formats output with colored backgrounds (red for deletions, blue for additions)
- Context lines (default: 2) show unchanged code around changes
- Used by morph_edit_file tool to display what changed
**src/history.rs**
- SessionMetadata: Preview and timestamps for session list
- Session: Dual storage (api_messages + display_messages)
- DisplayMessage: Enum for user messages, assistant responses, and tool executions
**src/repl.rs**
- Main event loop (run method)
- handle_response: Recursively processes assistant responses and tool calls
- display_session: Reconstructs conversation UI when resuming
- Max recursion depth: 50 (prevents infinite loops)
**src/conversation.rs**
- Manages in-memory message history
- Trims to MAX_MESSAGES (500) to prevent token overflow
- Builds system prompt with features list and custom instructions
**src/tools/filesystem.rs**
- validate_path: Security-critical path validation
- All operations check sandboxing before execution
- File size limit: 10MB to prevent memory issues
- User confirmation required for deletions
**src/tools/bashexec.rs**
- Uses PermissionManager for 3-tier command checking
- Validates command structure (paths, redirection, git ops)
- Executes commands with size limits
- Provides detailed rejection messages
**src/tools/permissions.rs**
- PermissionManager: Manages command permission checking
- PermissionSettings: Stores user's allow/deny/ask lists
- Three permission tiers: Allowed, Denied, Ask
- Persists decisions to `.sofos/config.local.toml`
- Predefined lists: ~50 allowed commands, ~30 forbidden commands
- Wildcard matching: `Bash(cargo:*)` matches all cargo commands
- Exact matching: `Bash(cargo build)` matches specific command only
## Code Conventions
### Rust Style
- Follow standard Rust idioms and conventions
- Use meaningful variable names (no single-letter except in loops)
- Prefer `Result<T>` over `panic!` for error handling
- Use `?` operator for error propagation
- Keep functions focused and under ~100 lines
### Error Handling
- Custom `SofosError` enum in src/error.rs
- Always provide context in error messages
- Use `map_err` to add context when propagating errors
- Display user-friendly error messages in REPL
### Testing
- Unit tests in the same file under `#[cfg(test)]`
- Use `tempfile::TempDir` for filesystem tests
- Mock API calls in tests (don't require real API keys)
- Test security features thoroughly (path validation, sandboxing)
### Documentation
- Add doc comments (`///`) for public APIs
- Explain "why" not just "what" in complex sections
- Keep comments up-to-date with code changes
- README.md is the primary user documentation
- **Avoid self-explanatory comments** - only comment what is non-obvious or explains important "why"
- **Keep README clean and simple** - focus on essential user-facing information
## Security Considerations
Ï
**Critical Security Features:**
1. **Path Validation** (filesystem.rs:validate_path)
- Canonicalize paths to resolve symlinks
- Check that canonical path starts with workspace
- Reject parent traversal (`..`)
- Reject absolute paths
- This is the first line of defense - NEVER bypass!
2. **Bash Command 3-Tier Permission System** (permissions.rs + bashexec.rs)
- **Tier 1 (Allowed)**: Predefined safe commands (build tools, read-only operations)
- Automatically executed without user confirmation
- Examples: cargo, npm, ls, cat, grep, git status
- **Tier 2 (Forbidden)**: Predefined dangerous commands
- Always blocked with clear error messages
- Examples: rm, sudo, chmod, mkdir, cd, git push
- **Tier 3 (Ask)**: Unknown commands
- Prompt user for permission
- Can be temporarily allowed or permanently remembered
- Decisions stored in `.sofos/config.local.toml`
- Additional structural checks always enforced:
- No parent traversal (`..`)
- No absolute paths
- No output redirection
- Git operations limited to read-only
3. **File Size Limits**
- Read operations: 10MB limit
- Bash output: 50MB limit
- Prevents memory exhaustion attacks
4. **User Confirmations**
- Delete operations require interactive confirmation
- Unknown bash commands prompt for permission
- Shows what will be executed/deleted before action
- User can cancel by declining
**When Adding New Features:**
- Always consider security implications first
- Add path validation for any new file operations
- Update permission lists if adding bash command capabilities
- Test with malicious inputs (path traversal attempts, etc)
## Important Implementation Details
### Session Persistence
**Session File Location:**
- Stored in `.sofos/sessions/{session_id}.json`
- Index file: `.sofos/sessions/index.json`
- Entire `.sofos/` directory is gitignored
### Message Flow
**User sends message:**
1. REPL adds to conversation history as user message
2. Creates API request with all messages + system prompt
3. Sends to Claude API
**Claude responds with tools (iterative loop):**
1. Response contains text + tool_use blocks
2. REPL adds full response (with both text and tool_use) to history as assistant message
3. Executes each tool sequentially
4. Collects all tool results
5. Adds all results as single user message
6. Makes new API request and **continues loop** with new response
7. **Loop exits** when Claude's response contains no tool calls
**Important:** Tool results must be in a user message, with tool_use_id matching the original tool_use id.
### Tool Iteration Limiting
**Problem:** Claude can make infinite tool calls if it gets stuck in a loop
**Solution:** (repl.rs:handle_response)
- Use an **iterative loop** instead of recursion for constant stack space
- Track iteration count in the loop
- MAX_TOOL_ITERATIONS = 200
- If exceeded, inject a system interruption message into the conversation
- Claude receives the interruption and can provide a summary and suggestions
- Clear, predictable control flow without recursion overhead
- Graceful degradation: Claude knows it was interrupted and can help the user recover
### Thinking Animation
When waiting for Claude's response after tool execution:
- Show animated spinner ("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
- Orange color (0xFF, 0x99, 0x33)
- "Thinking..." text
- Clears when response arrives
## Dependencies
### Core Dependencies
- `tokio`: Async runtime for HTTP requests
- `reqwest`: HTTP client for API calls
- `serde`, `serde_json`: Serialization/deserialization
- `colored`: Terminal colors and formatting
- `rustyline`: REPL with readline support
- `clap`: Command-line argument parsing
- `similar`: Text diffing for visual change display
### Optional Dependencies
- `ripgrep`: Code search functionality (runtime check)
- Morph API: Ultra-fast code editing (via MORPH_API_KEY)
### Why These Choices?
- `tokio` + `reqwest`: Industry standard for async HTTP in Rust
- `rustyline`: Best readline implementation for Rust CLIs
- `colored`: Simple, cross-platform terminal colors
- Native dependencies minimal (only ripgrep, which is optional)
## Testing Strategy
### What to Test
- Path validation with various malicious inputs
- Bash command blocklist effectiveness
- Session save/load with different formats
- Message trimming behavior
- Tool execution and result collection
### What Not to Test
- Actual Claude API responses (too expensive, non-deterministic)
- Actual file I/O in most cases (use TempDir)
- Network requests (mock when possible)
### Running Tests
```bash
cargo test # All tests
cargo test filesystem # Just filesystem tests
cargo test -- --nocapture # Show println output
```
## Common Tasks
### Adding a New Tool
1. Define tool in `src/tools/types.rs` (get_tools or get_tools_with_morph)
2. Implement execution in appropriate file (filesystem.rs, bashexec.rs, etc)
3. Add match arm in `src/tools/mod.rs` (ToolExecutor::execute)
4. Test the new tool thoroughly
5. Update README.md with tool description
### Modifying Bash Command Permissions
**To add a safe command to Tier 1 (Allowed):**
1. Add to `allowed_commands` HashSet in `permissions.rs:new()`
2. Test that command executes without prompting
3. Document in README.md if it's a major addition
**To add a dangerous command to Tier 2 (Forbidden):**
1. Add to `forbidden_commands` HashSet in `permissions.rs:new()`
2. Add helpful error message if needed
3. Test that command is blocked
4. Document restriction in README.md
**User-specific permissions (Tier 3):**
- Stored in `.sofos/config.local.toml` (gitignored)
- Format: `allow = ["Bash(command:*)"]` for wildcards, `allow = ["Bash(exact command)"]` for exact matches
- Can be edited manually or via interactive prompts
### Adding a New API Field
1. Update types in `src/api/types.rs`
2. Add serde attributes for proper serialization
3. Handle in response processing (repl.rs:handle_response)
4. Test with actual API if possible
### Debugging Tool Execution
Set `SOFOS_DEBUG=1` environment variable:
```bash
SOFOS_DEBUG=1 cargo run
```
This prints:
- Recursion depth at each step
- Number of tools being executed
- Tool success/failure and output length
- Conversation state before API calls
## Version Compatibility
### Anthropic API
- Uses Claude Messages API (not legacy Completions)
- Model: claude-sonnet-4-5 (default)
- Supports tool calling and server-side tools (web_search)
- API version: 2023-06-01
- Usage tracking: Automatic token counting and cost calculation
### Morph API
- Uses Morph Apply REST API
- Model: morph-v3-fast (default)
- Optional integration via MORPH_API_KEY
- Provides `morph_edit_file` tool when available
## Future Considerations
**Potential Improvements:**
- Streaming responses for faster perceived performance
- Multiple parallel tool executions (currently sequential)
- Richer TUI with panels and split views
- Plugin system for custom tools
- Configuration file for default settings
**Constraints:**
- Keep binary size small (currently ~5MB)
- Maintain zero-setup experience (except API keys)
- Keep security as top priority
## When Working on This Codebase
**Always:**
- Test security features when making changes to filesystem or bash tools
- Update both README.md and this .sofosrc when adding features
- Run `cargo test` before committing
- Add helpful error messages for user-facing errors
**Never:**
- Skip path validation in file operations
- Add commands to bash without security review
- Panic in user-facing code (use Result and show errors gracefully)
- Break the tool calling protocol (tool_use -> tool_result matching)
- Commit API keys or sensitive data
**Code Review Checklist:**
- [ ] Security: Path validation present and correct?
- [ ] Security: New bash commands in blocklist if needed?
- [ ] Error handling: All Results properly handled?
- [ ] Tests: Added tests for new functionality?
- [ ] Docs: Updated README if user-visible change?
- [ ] UX: Error messages clear and actionable?
---
This file is loaded by Sofos and appended to the system prompt, providing deep project context for AI-assisted development.