Add .cursorrules and README documentation

This commit is contained in:
Thomas Marchand
2025-12-14 21:15:58 +00:00
parent d5bde0a97e
commit 6718437c0b
2 changed files with 300 additions and 0 deletions

131
.cursorrules Normal file
View File

@@ -0,0 +1,131 @@
# Open Agent - Cursor Rules & Project Philosophy
## Project Overview
Open Agent is a minimal autonomous coding agent implemented in Rust. It is designed to be:
- **AI-maintainable**: Rust's strong type system and compiler provide immediate feedback
- **Self-contained**: No external dependencies beyond OpenRouter for LLM access
- **Full-access**: Has complete access to the local machine (filesystem, terminal, network)
## Architecture Philosophy
### "Tools in a Loop"
The agent follows the Cursor architecture pattern: an LLM with access to tools that can be called iteratively until a task is complete. The core loop is:
1. Receive task from user via HTTP API
2. Build context (system prompt + tools + user task)
3. Call LLM
4. If LLM requests tool calls: execute them, feed results back, goto 3
5. If LLM produces final response: return to user
### Separation of Concerns
```
api/ - HTTP interface only, no business logic
agent/ - Core agent loop and prompt construction
llm/ - LLM client abstraction (OpenRouter implementation)
tools/ - Individual tool implementations, each isolated
config.rs - All configuration in one place
```
### Tool Design Principles
Each tool should:
- Have a single, clear purpose
- Return human-readable output (the LLM needs to understand it)
- Handle errors gracefully (return error messages, don't panic)
- Be stateless (no tool should depend on another tool's state)
- Include comprehensive JSON schema for parameters
## Code Style Guidelines
### Rust Conventions
- Use `anyhow::Result` for error handling in application code
- Use `thiserror` for library error types that need to be matched
- Prefer `async_trait` for async trait methods
- Use `tracing` for logging, not `println!`
### Documentation
- Every public item should have a doc comment
- Module-level docs should explain the module's purpose
- Tool descriptions should be clear enough for an LLM to understand
### Error Messages
- Error messages should be actionable
- Include context (what were we trying to do?)
- Include the underlying error when relevant
## API Contract
The HTTP API is the **only** interface to the agent. It exposes:
```
POST /api/task - Submit a new task
GET /api/task/{id} - Get task status and result
GET /api/task/{id}/stream - Stream progress via SSE
GET /api/health - Health check
```
### Task Lifecycle
1. `POST /api/task` returns immediately with task ID
2. Client can poll `GET /api/task/{id}` or stream via SSE
3. Task runs asynchronously in background
4. Result includes status, final response, and execution log
## Extending the Agent
### Adding a New Tool
1. Create a new struct in `src/tools/`
2. Implement the `Tool` trait:
- `name()` - unique identifier
- `description()` - clear description for LLM
- `parameters_schema()` - JSON schema for arguments
- `execute()` - actual implementation
3. Register it in `ToolRegistry::new()` in `src/tools/mod.rs`
### Adding a New LLM Provider
1. Implement the `LlmClient` trait in `src/llm/`
2. The trait requires only `chat_completion()` with tool support
3. Update `Agent::new()` to use the new client based on config
## Environment Variables
```
OPENROUTER_API_KEY - Required. Your OpenRouter API key
DEFAULT_MODEL - Optional. Default: openai/gpt-4.1-mini
WORKSPACE_PATH - Optional. Default: current directory
HOST - Optional. Default: 127.0.0.1
PORT - Optional. Default: 3000
MAX_ITERATIONS - Optional. Default: 50
```
## Testing Approach
- Unit tests for individual tools (mock filesystem/commands)
- Integration tests for agent loop (mock LLM responses)
- End-to-end tests with real LLM (expensive, run manually)
## Security Considerations
This agent has **full machine access**. It can:
- Read/write any file the process can access
- Execute any shell command
- Make network requests
When deploying:
- Run as a limited user
- Use workspace isolation
- Consider a sandbox for terminal commands
- Never expose the API publicly without authentication
## Future Improvements
- [ ] WebSocket support for bidirectional streaming
- [ ] Semantic code search (embeddings-based)
- [ ] Background task persistence (survive restarts)
- [ ] Multi-model support (use different models for different tasks)
- [ ] Rate limiting and cost tracking
- [ ] Authentication for the HTTP API

169
README.md Normal file
View File

@@ -0,0 +1,169 @@
# Open Agent
A minimal autonomous coding agent with full machine access, implemented in Rust.
## Features
- **HTTP API** for task submission and monitoring
- **Tool-based agent loop** following the "tools in a loop" pattern
- **Full toolset**: file operations, terminal, grep search, web access, git
- **OpenRouter integration** for LLM access (supports any model)
- **SSE streaming** for real-time task progress
- **AI-maintainable** Rust codebase with strong typing
## Quick Start
### Prerequisites
- Rust 1.70+ (install via [rustup](https://rustup.rs/))
- An OpenRouter API key ([get one here](https://openrouter.ai/))
### Installation
```bash
git clone <repo-url>
cd open_agent
cargo build --release
```
### Running
```bash
# Set your API key
export OPENROUTER_API_KEY="sk-or-v1-..."
# Optional: configure model (default: openai/gpt-4.1-mini)
export DEFAULT_MODEL="openai/gpt-4.1-mini"
# Start the server
cargo run --release
```
The server starts on `http://127.0.0.1:3000` by default.
## API Reference
### Submit a Task
```bash
curl -X POST http://localhost:3000/api/task \
-H "Content-Type: application/json" \
-d '{"task": "Create a Python script that prints Hello World"}'
```
Response:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending"
}
```
### Get Task Status
```bash
curl http://localhost:3000/api/task/{id}
```
Response:
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"task": "Create a Python script that prints Hello World",
"model": "openai/gpt-4.1-mini",
"iterations": 3,
"result": "I've created hello.py with a simple Hello World script...",
"log": [...]
}
```
### Stream Task Progress (SSE)
```bash
curl http://localhost:3000/api/task/{id}/stream
```
Events:
- `log` - Execution log entries (tool calls, results)
- `done` - Task completion with final status
### Health Check
```bash
curl http://localhost:3000/api/health
```
## Available Tools
| Tool | Description |
|------|-------------|
| `read_file` | Read file contents with optional line range |
| `write_file` | Write/create files |
| `delete_file` | Delete files |
| `list_directory` | List directory contents |
| `search_files` | Search files by name pattern |
| `run_command` | Execute shell commands |
| `grep_search` | Search file contents with regex |
| `web_search` | Search the web (DuckDuckGo) |
| `fetch_url` | Fetch URL contents |
| `git_status` | Get git status |
| `git_diff` | Show git diff |
| `git_commit` | Create git commits |
| `git_log` | Show git log |
## Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `OPENROUTER_API_KEY` | (required) | Your OpenRouter API key |
| `DEFAULT_MODEL` | `openai/gpt-4.1-mini` | Default LLM model |
| `WORKSPACE_PATH` | `.` | Working directory for file operations |
| `HOST` | `127.0.0.1` | Server bind address |
| `PORT` | `3000` | Server port |
| `MAX_ITERATIONS` | `50` | Max agent loop iterations |
## Architecture
```
┌─────────────────┐ ┌─────────────────┐
│ HTTP Client │────▶│ HTTP API │
└─────────────────┘ │ (axum) │
└────────┬────────┘
┌────────▼────────┐
│ Agent Loop │◀──────┐
│ │ │
└────────┬────────┘ │
│ │
┌─────────────┼─────────────┐ │
▼ ▼ ▼ │
┌──────────┐ ┌──────────┐ ┌──────────┐
│ LLM │ │ Tools │ │ Tools │
│(OpenRouter)│ │(file,git)│ │(term,web)│
└──────────┘ └──────────┘ └──────────┘
└──────────────────────────────┘
(results fed back)
```
## Development
```bash
# Run with debug logging
RUST_LOG=debug cargo run
# Run tests
cargo test
# Format code
cargo fmt
# Check for issues
cargo clippy
```
## License
MIT