ollie/AGENTS.md

178 lines
9.4 KiB
Markdown

# AGENTS.md
Project-level context for AI agents working in this repository.
> **⚠️ IMPORTANT: All work must be done in THIS source directory (`~/src/ollie/`).**
> Never edit files under `~/.config/ollie/` — that is an install target.
> Changes made there are overwritten on the next `just install-data`.
> Edit source files here, then run `just` to build and install.
## Project Overview
Ollie is an AI agent runtime inspired by Plan 9: agent state and behaviors are exposed as files in a 9P namespace. Orchestration, scheduling, and UIs are external — shell scripts, editors, web apps. The core is minimal; capabilities come from composing scripts.
## Repository Layout
Monorepo with Git submodules. Each submodule has its own Go module (except `el` which is Elisp and `kde` which is C++/Qt).
```
ollie/ ← you are here
├── agent/ (Go) Agent loop, history, hooks, commands
├── toolsrv/ (Go) Tool server, registry, sandboxed execution
├── session/ (Go) Session lifecycle, config, persistence
├── fs/ (Go) 9P filesystem tree (EDSL-declared, flat package)
│ ├── spec.go Single source of truth — entire namespace declared here
│ ├── fsnode.go Core FsNodeDecl type + Dir/Leaf/TemplateDir constructors
│ └── builder.go BuildTree — walks spec, validates, wires handlers
├── cmd/ (Go) Binaries (olliesrv, ollie-9p, ollie-remote)
├── tools/ (Go) Tool implementations:
│ └── lsp/ LSP bridge + cmd/ binaries (definition, hover, rename, ...)
├── kde/ (C++/Qt6) KDE integration: plasmoid, GUI, Kate plugin, KRunner, tray
├── contrib/elisp (Elisp) Emacs frontend (ellie.el)
├── data/agents/ Agent config JSONs (loaded at runtime)
├── data/prompts/ System prompt templates (markdown)
├── data/tools/ Tool executables + .meta sidecar files (installed to $XDG_CONFIG_HOME/ollie/tools)
├── data/skills/ Domain knowledge modules (markdown)
├── sandbox/ Landlock sandbox config YAML
├── doc/ Architecture docs, usage guide
├── contrib/ Community scripts
└── experiments/ Trial notes
```
### Canonical source for prompts/tools/skills
> **⛔ DO NOT edit `~/.config/ollie/` directly — it is an install target. All changes go in this repo.**
Prompt and tool files live in `data/`. The `just install-data` target copies them to `~/.config/ollie/`.
| Location | Purpose | Deployed by |
|----------|---------|-------------|
| `data/prompts/`, `data/tools/` | Canonical source for all prompts, tools, and skills | `just install-data` |
| `data/skills/` | Domain knowledge modules (markdown) | `just install-data` |
| `kde/` | KDE-specific tool scripts (`gui_*`) | `just install-kde` |
## Build System
```bash
# Build everything:
just
# Individual targets:
just ninep # olliesrv + ollie-9p
just acme # acme frontend
just kde # KDE integration (cmake with ~/.local prefix)
just ollie-remote # remote execution binary
# Install targets (run automatically by the top-level paths):
just install-data # agents, prompts, tools, skills → ~/.config/ollie/
just install-scripts # CLI scripts → ~/.config/ollie/scripts/
just install-contrib # contrib scripts → ~/bin/
just install-kde # KDE plugins, desktop file, env → ~/.local/
just install-el # ellie.el → ~/.config/emacs/ellie/
# Test:
just test # run all tests
just test-core # core tests only
just test-9p # 9p tests only
# Lifecycle:
just uninstall # remove all installed files
just clean # remove build artifacts
```
Requires [just](https://github.com/casey/just): `cargo install just`
## Testing
```bash
# All Go tests (excludes cmd/ollie-remote which needs just to build):
go test $(go list ./... | grep -v cmd/ollie-remote)
# KDE has integration test scripts:
cd kde && ./test-e2e.sh
# ollie-remote requires the just build pipeline to resolve embedded deps:
just ollie-remote
just test
# or individually:
just test-remote
```
**Note on `cmd/ollie-remote`**: This package uses `//go:embed sandbox/default.yaml` and `//go:embed all:tools`. The embedded files are not in the source tree — `just ollie-remote` copies them in before building then cleans up. Running `go test ./...` will fail on this package. Use `just test-remote` or `go test $(go list ./... | grep -v cmd/ollie-remote)` instead.
## Language & Conventions
- **Go** (root module): Go 1.25+, standard library preferred, minimal dependencies.
- **C++20/Qt6/KF6** (kde): CMake build, dual Qt5/Qt6 support where noted.
- **Elisp** (el): single file `ellie.el`.
- **Tool scripts**: Python 3, Bash, or compiled binaries. Must be executable. Metadata lives in a `.meta` sidecar JSON file (see `data/tools/*.meta`).
### Code style
- Go: `gofmt`, short variable names, error returns (no panics), table-driven tests.
- Tool scripts: emit structured output (`STATUS=ok`, `STATUS=error`). Image/LSP tools return JSON content blocks.
- Prompts: markdown, concise, example-driven. Follow the pattern in existing `tools-*.md` files.
## Architecture (key concepts)
1. **One integration surface: 9P filesystem (sessions at `session/{sname}/agent/{aname}/`). Tools, skills, memory on physical filesystem via env vars.
2. **Agent loop** (`agent/loop.go`): Streaming LLM call → parse tool calls → dispatch → loop until no more tool calls or max steps.
3. **Tool dispatch** (`toolsrv/`): `shell` is built-in. All others are external scripts resolved from `$XDG_CONFIG_HOME/ollie/tools`.
4. **Sandbox** (`sandbox/`): Landlock-based. Config in `sandbox/*.yaml` defines filesystem access per profile.
5. **Backends** (`backend/`): Ollama, OpenAI-compatible, Anthropic, Copilot, Kiro, Gemini, CodeWhisperer. Selectable per-session.
6. **Prompts assembled at runtime**: Agent JSON `prompt` array specifies which prompt files to concatenate. Static prompt files can be included directly; the base system prompt is embedded in the binary and always prepended.
7. **9P namespace declared via EDSL**: The entire filesystem is a single recursive `FsNodeDecl` tree in `fs/spec.go`, built by `BuildTree()` in `fs/builder.go`. The `fs/` package is flat — no sub-package — handler files (`rootfiles.go`, `sessionfiles.go`, `agentfiles.go`) are organized by scope. See `doc/edsl.md` for the full reference.
## Key Files
| What | Where |
|------|-------|
| Agent loop | `agent/loop.go` |
| Tool server | `toolsrv/server.go` |
| Remote execution | `toolsrv/remote.go`, `cmd/ollie-remote/` |
| Sandbox enforcement | `sandbox/` |
| 9P filesystem (EDSL spec) | `fs/spec.go` |
| 9P filesystem (builder) | `fs/builder.go` |
| Session management | `session/session.go` |
| System prompt template | Embedded in binary |
| Agent configs | `agents/*.json` |
| Standalone GUI | `kde/gui/` |
| Kate plugin | `kde/kate/` |
## Environment
Config lives in `~/.config/ollie/env`. Key variables:
- `OLLIE_BACKEND` — default backend (ollama, openai, anthropic, copilot, kiro)
- `OLLIE_MODEL` — default model
- Tools live at `$XDG_CONFIG_HOME/ollie/tools` (default: `~/.config/ollie/tools`)
- Memory lives at `$XDG_CONFIG_HOME/ollie/memory` (default: `~/.config/ollie/memory`)
## Adding a new tool
### Script-based tool (Python/Bash)
1. Create an executable script in `data/tools/<name>`
2. Create `data/tools/<name>.meta` with JSON metadata:
```json
{"description":"...","prompt":"...","args":{...},"tier":"hot","readOnly":false}
```
3. Run `just install-data` to install
### Compiled tool (Go)
1. Create a package under `tools/<family>/cmd/<name>/main.go`
- Read JSON args from stdin, write result to stdout, exit 0/1
- Share library code in `tools/<family>/` (e.g. `tools/lsp/`)
2. Create `<name>.meta` alongside `main.go` in the same `cmd/<name>/` directory (same format as above)
3. Add a build target in the justfile that compiles to `{{cfg}}/tools/<name>` **and** installs the `.meta` file alongside it
4. Run `just` to build and install
The `.meta` file lives with the code that produces the tool, not in `data/tools/`. See the `lsp-tools` just target for the canonical pattern.
Both paths produce the same result: an executable + `.meta` in `$XDG_CONFIG_HOME/ollie/tools`.
The registry doesn't distinguish between scripts and binaries.
## Adding a new prompt
1. Write the markdown file in `data/prompts/`
2. If it should be loaded by default, reference it in `agents/default.json`
3. Run `just install-data` to install
## Submodule workflow
The only remaining submodule is `kde/`. For KDE:
```bash
# Update KDE submodule:
git submodule update --remote --merge kde
# Work in the KDE submodule:
cd kde
# ... make changes, commit ...
git push
cd ..
git add kde
git commit -m "update kde submodule"
```
Each submodule has its own remote at `ssh://lkn@lneely.de:44220/lkn/ollie-{name}.git`.
When cloning, use `--recurse-submodules` or run `git submodule update --init --recursive`.
## Environment
The only remaining submodule is `kde/`. For KDE:
```bash
# Update KDE submodule:
git submodule update --remote --merge kde
# Work in the KDE submodule:
cd kde
# ... make changes, commit ...
git push
cd ..
git add kde
git commit -m "update kde submodule"
```
Each submodule has its own remote at `ssh://lkn@lneely.de:44220/lkn/ollie-{name}.git`.
When cloning, use `--recurse-submodules` or run `git submodule update --init --recursive`.