sofos 0.1.18

An interactive AI coding agent for your terminal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# 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/session/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/mod.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/session/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/
├── main.rs              # Entry point
├── cli.rs               # CLI argument parsing
├── error.rs             # Error types
├── error_ext.rs         # Error extensions
├── config.rs            # Configuration (SofosConfig, ModelConfig)
│
├── api/                 # API clients
│   ├── anthropic.rs     # Claude API client
│   ├── openai.rs        # OpenAI API client
│   ├── morph.rs         # Morph Apply API client
│   ├── types.rs         # Message types and serialization
│   └── utils.rs         # API utilities
│
├── mcp/                 # MCP (Model Context Protocol) integration
│   ├── mod.rs           # MCP module exports
│   ├── config.rs        # MCP server configuration loading
│   ├── protocol.rs      # MCP protocol types (JSON-RPC, tools)
│   ├── client.rs        # MCP client implementations (stdio, HTTP)
│   └── manager.rs       # MCP server connection management
│
├── repl/                # REPL components
│   ├── mod.rs           # Main REPL loop and Repl struct
│   ├── conversation.rs  # Message history management
│   ├── prompt.rs        # Prompt rendering
│   ├── request_builder.rs   # API request construction
│   └── response_handler.rs  # Response processing
│
├── session/             # Session management
│   ├── history.rs       # Session persistence + custom instructions
│   ├── state.rs         # Runtime session state
│   └── selector.rs      # Session selection TUI
│
├── tools/               # Tool implementations
│   ├── filesystem.rs    # File operations (read, write, list, etc)
│   ├── bashexec.rs      # Sandboxed bash execution
│   ├── codesearch.rs    # Ripgrep integration
│   ├── image.rs         # Image handling
│   ├── permissions.rs   # 3-tier command permission system
│   ├── types.rs         # Tool definitions for API
│   └── utils.rs         # Tool utilities
│
├── ui/                  # UI components
│   ├── mod.rs           # Main UI utilities and display logic
│   ├── syntax.rs        # Markdown/code syntax highlighting
│   └── diff.rs          # Contextual diff generation and display
│
└── commands/            # Built-in commands
    └── builtin.rs       # Command implementations
```

### 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/ui/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/session/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/mod.rs**
- Main event loop (run method)
- Manages REPL state and user interaction
- Coordinates conversation, tools, and UI

**src/repl/response_handler.rs**
- Iteratively processes assistant responses and tool calls
- Max iterations: 200 (prevents infinite loops)

**src/repl/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:** (src/repl/response_handler.rs)
- 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.