BREAKING CHANGES: - owlen-core no longer depends on ratatui/crossterm - RemoteMcpClient constructors are now async - MCP path validation is stricter (security hardening) This commit resolves three critical issues identified in project analysis: ## P0-1: Extract TUI dependencies from owlen-core Create owlen-ui-common crate to hold UI-agnostic color and theme abstractions, removing architectural boundary violation. Changes: - Create new owlen-ui-common crate with abstract Color enum - Move theme.rs from owlen-core to owlen-ui-common - Define Color with Rgb and Named variants (no ratatui dependency) - Create color conversion layer in owlen-tui (color_convert.rs) - Update 35+ color usages with conversion wrappers - Remove ratatui/crossterm from owlen-core dependencies Benefits: - owlen-core usable in headless/CLI contexts - Enables future GUI frontends - Reduces binary size for core library consumers ## P0-2: Fix blocking WebSocket connections Convert RemoteMcpClient constructors to async, eliminating runtime blocking that froze TUI for 30+ seconds on slow connections. Changes: - Make new_with_runtime(), new_with_config(), new() async - Remove block_in_place wrappers for I/O operations - Add 30-second connection timeout with tokio::time::timeout - Update 15+ call sites across 10 files to await constructors - Convert 4 test functions to #[tokio::test] Benefits: - TUI remains responsive during WebSocket connections - Proper async I/O follows Rust best practices - No more indefinite hangs ## P1-1: Secure path traversal vulnerabilities Implement comprehensive path validation with 7 defense layers to prevent file access outside workspace boundaries. Changes: - Create validate_safe_path() with multi-layer security: * URL decoding (prevents %2E%2E bypasses) * Absolute path rejection * Null byte protection * Windows-specific checks (UNC/device paths) * Lexical path cleaning (removes .. components) * Symlink resolution via canonicalization * Boundary verification with starts_with check - Update 4 MCP resource functions (get/list/write/delete) - Add 11 comprehensive security tests Benefits: - Blocks URL-encoded, absolute, UNC path attacks - Prevents null byte injection - Stops symlink escape attempts - Cross-platform security (Windows/Linux/macOS) ## Test Results - owlen-core: 109/109 tests pass (100%) - owlen-tui: 52/53 tests pass (98%, 1 pre-existing failure) - owlen-providers: 2/2 tests pass (100%) - Build: cargo build --all succeeds ## Verification - ✓ cargo tree -p owlen-core shows no TUI dependencies - ✓ No block_in_place calls remain in MCP I/O code - ✓ All 11 security tests pass Fixes: #P0-1, #P0-2, #P1-1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
310 lines
11 KiB
Markdown
310 lines
11 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
OWLEN is a Rust-powered, terminal-first interface for interacting with local and cloud language models. It uses a multi-provider architecture with vim-style navigation and session management.
|
|
|
|
**Status**: Alpha (v0.2.0) - core features functional but expect occasional bugs and breaking changes.
|
|
|
|
## Build, Test & Development Commands
|
|
|
|
### Building
|
|
```bash
|
|
# Build all crates
|
|
cargo build
|
|
|
|
# Build release binary
|
|
cargo build --release
|
|
|
|
# Run the TUI (requires Ollama running)
|
|
./target/release/owlen
|
|
# or
|
|
cargo run -p owlen-cli
|
|
|
|
# Build for specific target (cross-compilation)
|
|
dev/local_build.sh x86_64-unknown-linux-gnu
|
|
```
|
|
|
|
### Testing
|
|
```bash
|
|
# Run all tests
|
|
cargo test --all
|
|
|
|
# Test specific crate
|
|
cargo test -p owlen-core
|
|
cargo test -p owlen-tui
|
|
cargo test -p owlen-providers
|
|
|
|
# Linting and formatting
|
|
cargo clippy --all -- -D warnings
|
|
cargo fmt --all -- --check
|
|
|
|
# Pre-commit hooks (install once with `pre-commit install`)
|
|
pre-commit run --all-files
|
|
```
|
|
|
|
### Developer Tasks
|
|
```bash
|
|
# Regenerate screenshots for documentation
|
|
cargo xtask screenshots
|
|
cargo xtask screenshots --no-png # skip PNG generation
|
|
cargo xtask screenshots --output images/
|
|
|
|
# Regenerate repository map after structural changes
|
|
scripts/gen-repo-map.sh
|
|
|
|
# Platform compatibility checks
|
|
scripts/check-windows.sh # Windows GNU toolchain smoke test
|
|
```
|
|
|
|
### Running Individual Tests
|
|
```bash
|
|
# Run a specific test by name
|
|
cargo test test_name
|
|
|
|
# Run tests with output
|
|
cargo test -- --nocapture
|
|
|
|
# Run tests in a specific file
|
|
cargo test --test integration_test_name
|
|
```
|
|
|
|
## Architecture & Key Concepts
|
|
|
|
### Workspace Structure (Cargo workspace with 13+ crates)
|
|
- **owlen-core**: Core abstractions, provider traits, session management, MCP client layer (UI-agnostic)
|
|
- **owlen-tui**: Terminal UI built with ratatui (event loop, rendering, vim modes)
|
|
- **owlen-cli**: Entry point that parses args, loads config, launches TUI or headless flows
|
|
- **owlen-providers**: Concrete provider adapters (Ollama local, Ollama Cloud)
|
|
- **owlen-markdown**: Markdown parsing and rendering
|
|
- **crates/mcp/**: Model Context Protocol infrastructure
|
|
- **llm-server**: Wraps owlen-providers behind MCP boundary (generate_text tools)
|
|
- **server**: Generic MCP server for file ops and workspace tools
|
|
- **client**: MCP client implementation
|
|
- **code-server**: Code execution sandboxing
|
|
- **prompt-server**: Template rendering
|
|
- **xtask**: Development automation tasks (screenshots, etc.)
|
|
|
|
### Dependency Boundaries
|
|
- **owlen-core is the dependency ceiling**: Must stay free of terminal logic, CLIs, or provider HTTP clients
|
|
- **owlen-cli only orchestrates startup/shutdown**: Business logic belongs in owlen-core or library crates
|
|
- **owlen-mcp-llm-server is the only crate that directly talks to providers**: UI/CLI communicate through MCP clients
|
|
|
|
### Multi-Provider Architecture
|
|
```
|
|
[owlen-tui / owlen-cli]
|
|
│
|
|
│ chat + model requests
|
|
▼
|
|
[owlen-core::ProviderManager] ──> Arc<dyn ModelProvider>
|
|
│ ▲
|
|
│ │ implements ModelProvider
|
|
▼ │
|
|
[owlen-core::mcp::RemoteMcpClient] ────────┘
|
|
│ (JSON-RPC over stdio)
|
|
▼
|
|
┌────────────────────────────────────────────────┐
|
|
│ MCP Process Boundary (spawned per provider) │
|
|
│ │
|
|
│ crates/mcp/llm-server ──> owlen-providers::* │
|
|
└────────────────────────────────────────────────┘
|
|
```
|
|
|
|
Key points:
|
|
- **ProviderManager** tracks health, merges model catalogs, and dispatches requests
|
|
- **RemoteMcpClient** bridges MCP protocol to ModelProvider trait
|
|
- **MCP servers** isolate provider-specific code in separate processes
|
|
- **Health & availability** tracked via background workers and surfaced in TUI picker
|
|
|
|
### Event Flow & TUI Architecture
|
|
1. User input → Event loop → Message handler → Session controller → Provider manager → Provider
|
|
2. Non-blocking design: TUI remains responsive during streaming (see `agents.md` for planned improvements)
|
|
3. Modal workflow: Normal, Insert, Visual, Command modes (vim-inspired)
|
|
4. AppMessage stream carries async events (provider responses, health checks)
|
|
|
|
### Session & Conversation Management
|
|
- **Conversation** (owlen-core): Holds messages and metadata
|
|
- **SessionController**: High-level orchestrator managing history, context, model switching
|
|
- Conversations stored in platform-specific data directory (can be encrypted with AES-GCM)
|
|
|
|
### Configuration
|
|
Platform-specific locations:
|
|
- Linux: `~/.config/owlen/config.toml`
|
|
- macOS: `~/Library/Application Support/owlen/config.toml`
|
|
- Windows: `%APPDATA%\owlen\config.toml`
|
|
|
|
Commands:
|
|
```bash
|
|
owlen config init # Create default config
|
|
owlen config init --force # Overwrite existing
|
|
owlen config path # Print config location
|
|
owlen config doctor # Migrate legacy configs
|
|
```
|
|
|
|
## Coding Conventions
|
|
|
|
### Commit Messages
|
|
Follow [Conventional Commits](https://www.conventionalcommits.org/):
|
|
```
|
|
<type>[optional scope]: <description>
|
|
|
|
[optional body]
|
|
|
|
[optional footer(s)]
|
|
```
|
|
|
|
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`, `build`, `ci`
|
|
|
|
Example: `feat(provider): add support for Gemini Pro`
|
|
|
|
### Pre-commit Hooks
|
|
Hooks automatically run on commit (install with `pre-commit install`):
|
|
- `cargo fmt`
|
|
- `cargo check`
|
|
- `cargo clippy --all-features`
|
|
- File hygiene (trailing whitespace, EOF newlines)
|
|
|
|
To bypass (not recommended): `git commit --no-verify`
|
|
|
|
### Style Guidelines
|
|
- Run `cargo fmt` before committing
|
|
- Address all `cargo clippy` warnings
|
|
- Use `#[cfg(test)]` modules for unit tests in same file
|
|
- Place integration tests in `tests/` directory
|
|
|
|
## Provider Development
|
|
|
|
### Adding a New Provider
|
|
Follow `docs/adding-providers.md`:
|
|
1. Implement `ModelProvider` trait in `owlen-providers`
|
|
2. Set `ProviderMetadata::provider_type` (Local/Cloud)
|
|
3. Register with `ProviderManager` in startup code
|
|
4. Optionally expose through MCP server
|
|
5. Add integration tests following `crates/owlen-providers/tests` pattern
|
|
6. Document config in `docs/configuration.md` and default `config.toml`
|
|
7. Update `README.md`, `CHANGELOG.md`, `docs/troubleshooting.md`
|
|
|
|
See `docs/provider-implementation.md` for trait-level details.
|
|
|
|
### MCP Tool Naming
|
|
Enforce spec-compliant identifiers: `^[A-Za-z0-9_-]{1,64}$`
|
|
- Use underscores or hyphens (e.g., `web_search`, `filesystem_read`)
|
|
- Avoid dotted names (legacy incompatible)
|
|
- Qualify with `{server}__{tool}` when multiple servers overlap (e.g., `filesystem__read`)
|
|
|
|
## Repository Automation
|
|
|
|
OWLEN includes Git-aware automation for code review and commit templating:
|
|
|
|
### CLI Commands
|
|
```bash
|
|
# Generate commit message from staged diff
|
|
owlen repo commit-template
|
|
owlen repo commit-template --working-tree # inspect unstaged
|
|
|
|
# Review branch or PR
|
|
owlen repo review
|
|
owlen repo review --owner Owlibou --repo owlen --number 42 --token-env GITHUB_TOKEN
|
|
```
|
|
|
|
### TUI Commands
|
|
```
|
|
:repo template # inject commit template into chat
|
|
:repo review [--base BRANCH] [--head REF] # review local changes
|
|
```
|
|
|
|
## Key Files & Entry Points
|
|
|
|
### Main Entry Points
|
|
- `crates/owlen-cli/src/main.rs` - CLI entry point (argument parsing, config loading)
|
|
- `crates/owlen-tui/src/app/mod.rs` - Main TUI application and event dispatch
|
|
- `crates/owlen-core/src/provider.rs` - ModelProvider trait definition
|
|
|
|
### Configuration & State
|
|
- `crates/owlen-core/src/config.rs` - Configuration loading and parsing
|
|
- `crates/owlen-core/src/session.rs` - Session and conversation management
|
|
- `crates/owlen-core/src/storage.rs` - Persistence layer
|
|
|
|
### Provider Infrastructure
|
|
- `crates/owlen-providers/src/ollama/` - Ollama local and cloud providers
|
|
- `crates/mcp/llm-server/src/main.rs` - MCP LLM server process
|
|
- `crates/owlen-core/src/mcp/remote_client.rs` - MCP client implementation
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests
|
|
Place in `#[cfg(test)]` modules within source files for isolated component testing.
|
|
|
|
### Integration Tests
|
|
Place in `tests/` directories:
|
|
- `crates/owlen-providers/tests/` - Provider integration tests
|
|
- Test registration, model aggregation, request routing, health transitions
|
|
|
|
### Focus Areas
|
|
- Command palette state machine
|
|
- Agent response parsing
|
|
- MCP protocol abstractions
|
|
- Provider manager health cache
|
|
- Session controller lifecycle
|
|
|
|
## Documentation Structure
|
|
|
|
- `README.md` - User-facing overview, installation, features
|
|
- `CONTRIBUTING.md` - Contribution guidelines, development setup
|
|
- `docs/architecture.md` - High-level architecture (read first!)
|
|
- `docs/repo-map.md` - Workspace layout snapshot
|
|
- `docs/adding-providers.md` - Provider implementation checklist
|
|
- `docs/provider-implementation.md` - Trait-level provider details
|
|
- `docs/testing.md` - Testing guide
|
|
- `docs/troubleshooting.md` - Common issues and solutions
|
|
- `docs/configuration.md` - Configuration reference
|
|
- `docs/platform-support.md` - OS support matrix
|
|
|
|
## Important Implementation Notes
|
|
|
|
### When Working on TUI Code
|
|
- Modal state machine is critical: Normal ↔ Insert ↔ Visual ↔ Command
|
|
- Status line shows current mode (use as regression check)
|
|
- Non-blocking event loop planned (see `agents.md`)
|
|
- Command palette state lives in `owlen_tui::state`
|
|
- Follow Model-View-Update pattern for new features
|
|
|
|
### When Working on Providers
|
|
- Never import providers directly in owlen-tui or owlen-cli
|
|
- All provider communication goes through owlen-core abstractions
|
|
- Health checks run on background workers
|
|
- Model discovery fans out through ProviderManager
|
|
|
|
### When Working on MCP Integration
|
|
- RemoteMcpClient implements both MCP client traits and ModelProvider
|
|
- MCP servers are short-lived, narrowly scoped binaries
|
|
- Tool calls travel same transport as chat requests
|
|
- Consent prompts surface in UI via session events
|
|
|
|
## Platform Support
|
|
|
|
- **Primary**: Linux (Arch AUR: `owlen-git`)
|
|
- **Supported**: macOS 12+ (requires Command Line Tools for OpenSSL)
|
|
- **Experimental**: Windows (GNU toolchain, some Docker features disabled)
|
|
|
|
Cross-platform testing: Use `dev/local_build.sh` and `scripts/check-windows.sh`
|
|
|
|
## Dependencies & Async Runtime
|
|
|
|
- **Async runtime**: tokio with "full" features
|
|
- **TUI framework**: ratatui 0.29 with palette features
|
|
- **HTTP client**: reqwest with rustls-tls (no native-tls)
|
|
- **Database**: SQLx with sqlite, tokio runtime
|
|
- **Serialization**: serde + serde_json
|
|
- **Testing**: tokio-test for async test utilities
|
|
|
|
## Security & Privacy
|
|
|
|
- Local-first: LLM calls route through local Ollama by default
|
|
- Session encryption: Set `privacy.encrypt_local_data = true` for AES-GCM storage
|
|
- No telemetry sent
|
|
- Outbound requests only when explicitly enabling remote tools/providers
|
|
- Config migrations carry schema version and warn on deprecated keys
|