AGENTS.md

 1# Rumilo Agent Guide
 2
 3CLI that dispatches specialized AI research subagents for web research and git repository exploration.
 4
 5## Commands
 6
 7```bash
 8bun run dev       # Run CLI via bun (development)
 9bun run build     # Build to dist/
10bun run typecheck # TypeScript check (also: bun run lint)
11```
12
13No test suite currently exists (`test/` is empty).
14
15## Architecture
16
17```
18CLI entry (src/cli/index.ts)
19    ├── web command → runWebCommand() → runAgent() with web tools
20    └── repo command → runRepoCommand() → runAgent() with git tools
21```
22
23### Control Flow
24
251. **CLI** parses args with custom parser (no library), dispatches to command handlers
262. **Command handlers** (`src/cli/commands/`) load config, create workspace, configure tools, invoke `runAgent()`
273. **Agent runner** (`src/agent/runner.ts`) wraps `@mariozechner/pi-agent` - creates `Agent`, subscribes to events, prompts, extracts final message
284. **Tools** are created via factory functions that close over workspace path for sandboxing
295. **Workspace** (`src/workspace/manager.ts`) is a temp directory (cleaned up unless `--no-cleanup`)
30
31### Two Agent Modes
32
33| Mode | Tools | External Services |
34|------|-------|-------------------|
35| `web` | `web_search`, `web_fetch`, `read`, `grep`, `ls`, `find` | Kagi (search), Tabstack (fetch→markdown) |
36| `repo` | `read`, `grep`, `ls`, `find`, `git_log`, `git_show`, `git_blame`, `git_diff`, `git_refs`, `git_checkout` | None (clones repo to workspace) |
37
38## Key Patterns
39
40### Tool Factory Pattern
41
42All tools follow the same signature:
43```typescript
44const createFooTool = (workspacePath: string): AgentTool => ({ ... })
45```
46
47Tools use `@sinclair/typebox` for parameter schemas. Execute functions return `{ content: [{type: "text", text}], details?: {...} }`.
48
49### Workspace Sandboxing
50
51Tools must constrain paths to workspace:
52- `ensureWorkspacePath()` in `src/agent/tools/index.ts` validates paths don't escape
53- `resolveToCwd()` / `resolveReadPath()` in `src/agent/tools/path-utils.ts` handle expansion and normalization
54
55### Config Cascade
56
57```
58defaultConfig → XDG_CONFIG_HOME/rumilo/config.toml → CLI flags
59```
60
61Config uses TOML, validated against TypeBox schema (`src/config/schema.ts`).
62
63### Model Resolution
64
65Model strings use `provider:model` format. `custom:name` prefix looks up custom model definitions from config's `[custom_models]` section. Built-in providers delegate to `@mariozechner/pi-ai`.
66
67### Error Handling
68
69Custom error classes in `src/util/errors.ts` extend `RumiloError` with error codes:
70- `ConfigError`, `FetchError`, `CloneError`, `WorkspaceError`, `ToolInputError`
71
72### Output Truncation
73
74`src/util/truncate.ts` handles large content:
75- `DEFAULT_MAX_LINES = 2000`
76- `DEFAULT_MAX_BYTES = 50KB`
77- `GREP_MAX_LINE_LENGTH = 500` chars
78
79## Gotchas
80
811. **Grep requires ripgrep** - `createGrepTool` checks for `rg` at tool creation time and throws if missing
822. **Web tools require credentials** - `KAGI_SESSION_TOKEN` and `TABSTACK_API_KEY` via env or config
833. **Shallow clones by default** - repo mode uses `--depth 1 --filter=blob:limit=5m` unless `--full`
844. **Pre-fetch injection threshold** - web command with `-u URL` injects content directly if ≤50KB, otherwise stores in workspace
855. **No `.js` extension in imports** - source uses `.js` extensions for ESM compatibility even though files are `.ts`
86
87## Adding a New Tool
88
891. Create `src/agent/tools/newtool.ts` following the factory pattern
902. Export from `src/agent/tools/index.ts` if general-purpose
913. Add to appropriate command's tool array in `src/cli/commands/{web,repo}.ts`
924. Use `ToolInputError` for validation failures