ollie/AGENTS.md

10 KiB

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
├── virtfs/           (Go module)   Virtual filesystem EDSL (FsNodeDecl, BuildTree, Tree)
├── toolsrv/          (Go)          Tool server client library (Conn, Dial)
├── cmd/
│   ├── olliesrv/     (Go)          9P server binary
│   │   └── internal/
│   │       ├── fs/                 9P namespace (everything in spec.go)
│   │       │   ├── spec.go         Single source of truth — entire namespace + handlers
│   │       │   └── support.go     Shared utilities (streamChat, stripMarkers, dispatch)
│   │       ├── agent/             Agent loop, history, hooks
│   │       ├── session/           Session lifecycle, persistence
│   │       ├── backend/           LLM backends (ollama, openai, anthropic, etc.)
│   │       └── bypass/            Sandbox bypass broker
│   ├── toolsrv/      (Go)          Tool server binary (sandboxed execution)
│   │   └── internal/
│   │       ├── fs/                 toolsrv 9P namespace (spec.go)
│   │       └── sandbox/           Landlock enforcement
│   ├── ollie-9p/     (Go)          CLI client for the 9P namespace
│   └── ollie-remote/ (Go)          Remote execution agent
├── tools/            (Go)          Tool implementations:
│   └── lsp/                        LSP bridge + cmd/ binaries
├── kde/              (C++/Qt6)     KDE integration: 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
├── 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

# 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: cargo install just

Testing

# 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}/. All control via ctl (rdwr: write command, read response). Tools, skills, memory on physical filesystem via env vars.
  2. Agent loop (cmd/olliesrv/internal/agent/loop.go): Streaming LLM call → parse tool calls → dispatch → loop until no more tool calls or max steps.
  3. Tool dispatch (cmd/toolsrv/): All tools execute remotely through a per-session tool server process. Tools are external scripts resolved from $XDG_CONFIG_HOME/ollie/tools. Load via ctl tool_load <name>.
  4. Sandbox (cmd/toolsrv/internal/sandbox/): Landlock-based. Config in sandbox/*.yaml defines filesystem access per profile. Escape via bypass broker (cmd/olliesrv/internal/bypass/).
  5. Backends (cmd/olliesrv/internal/backend/): Ollama, OpenAI-compatible, Anthropic, Copilot, Kiro, Gemini. 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 virtfs EDSL: The entire filesystem is a single recursive FsNodeDecl tree in cmd/olliesrv/internal/fs/spec.go, built by virtfs.BuildTree(). Every handler is an inline closure — no indirection.

Key Files

What Where
9P namespace (olliesrv) cmd/olliesrv/internal/fs/spec.go
9P namespace (toolsrv) cmd/toolsrv/internal/fs/spec.go
virtfs EDSL virtfs/decl.go, virtfs/builder.go
Agent loop cmd/olliesrv/internal/agent/loop.go
Tool server binary cmd/toolsrv/
Tool server client toolsrv/client9p.go
Remote execution cmd/ollie-remote/
Sandbox enforcement cmd/toolsrv/internal/sandbox/
Session management cmd/olliesrv/internal/session/
System prompt template Embedded in binary (cmd/olliesrv/internal/prompts/)
Agent configs data/agents/*.json
KDE 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:
    {"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:

# 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:

# 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.