AGENTS.md · git:20260914.65c875d · 2026-09-14 · sha256 e3ab8a09aef881c0
AGENTS.md git:20260914.65c875dA
Immutable. This exact content never changes and is served at /api/v1/blob/e3ab8a09aef881c0.
# AGENTS.md Guidance for coding agents working in this repo. README.md is the CLI/TUI user guide; API.md is the Go library reference; SANDBOX.md covers sandboxing; WORKFLOWS.md is the swarm/workflow guide, with format-2 details in docs/swarm-state-model.md. Consult and update them as noted below. ## Overview `polly` is an LLM harness: CLI + TUI (`cmd/polly`) built on a Go library (`llm`, `tools`, `messages`, `schema`, `sessions`, `skills`, `subagent`, `swarm`, `workflow`, `worktree`, `artifacts`). Module: `github.com/alexschlessinger/pollytool`, Go 1.27. Request flow: `main` → provider router (`llm.NewMultiPass`) → `llm.NewAgent` → agent loop (each iteration `llm.Prepare` adapts the request to the model's capabilities, then `ChatCompletionStream` routes on the `provider/` prefix; each provider package under `llm/<provider>/` builds the wire request, converts messages, parses stream events through its adapter, and fetches its own model catalog and embeddings; they share the request contract in `llm/internal/contract`, which the root `llm` package re-exports, and the catalog helpers in `llm/internal/catalog`) → tool calls run in parallel via `tools.ToolRegistry` → results fed back until done or `ErrMaxIterations`. Key types: `llm.LLM`/`Agent`/`AgentCallbacks`, `messages.ChatMessage`/`StreamEvent`, `tools.Tool`/`ToolRegistry`/`ToolError`, `schema.ToolSchema`, `sessions.Store`, `subagent.Runner`. ## Build & test ```bash CGO_ENABLED=0 go build ./... # no cgo: sqlite is modernc.org/sqlite go vet ./... go test ./... # tests are *_test.go colocated with code ``` CI (`.github/workflows/test.yml`) runs build + vet + tests on Linux/macOS, cross-compiles 5 GOOS/GOARCH targets including Windows, and runs `-race` on the packages listed in `.github/ci.sh`. Windows runtime tests are disabled. `.github/ci.sh [test|race|cross|all]` is the shared entry point; see [local CI](.github/local-ci/README.md) for portable Linux containers, disposable macOS VMs, and GitHub runner setup. Verify all three commands above before declaring done. - Sandbox security tests are opt-in: `POLLYTOOL_REQUIRE_SANDBOX_TESTS=1 go test ./tools/sandbox` (macOS/Linux only). - POSIX-only tests skip via a per-package `skipIfWindows(t)` helper (see `tools/skip_test.go`), not build tags. Use it for anything needing POSIX shell/sandboxing so the Windows CI leg passes. - `POLLYTOOL_*` env vars configure everything (`POLLYTOOL_ANTHROPICKEY`, `MODEL`, `SANDBOX`, etc.); test-only ones: `POLLYTOOL_REQUIRE_SANDBOX_TESTS`, `POLLYTOOL_CLIPBOARD_TEST`. ## Conventions - Commits: `area: lowercase imperative summary`, no period. Areas match package/topic: `llm`, `tools`, `sessions`, `mcp`, `repl`, `tests`, `skills`, `sandbox`, … - Packages are flat top-level domains; one concept per file; stdlib `testing` with `t.Fatalf`, `t.TempDir()`, plain assertions. - Errors: `fmt.Errorf` with `%w`; tool failures return `*tools.ToolError` (structured, serialized as JSON). - Functional options for registries/clients (`With*`). - Platform-split files (`*_darwin.go`, `*_windows.go`, `*_unix.go`, `*_other.go`) — check whether a change belongs in all variants. ## Adding things - **Provider**: package `llm/<provider>/` exporting `NewProvider`, `ListModels` (built on `llm/internal/catalog`), and optionally `Embed` and `DefaultBaseURL`; one row in `defaultProviders()` (`llm/multipass.go`) wires them and carries every routing rule as a `providerSpec` field (base URL scoping, keyless access, host routing, catalog shape). Nothing else in `llm` names a provider. Env key `POLLYTOOL_<PROVIDER>KEY` via `getEnvVarNameForProvider`. Update API.md §Providers and README §Models. - **Builtin tool**: implement `tools.Tool` in `tools/<name>.go` (or a declarative `tools.Func`); register in `NewToolRegistry` (`tools/registry.go`) or via `RegisterNative`. Rich output → `OutputTool`; long-running exemption → `UntimedTool`. If it spawns processes it must go through the sandbox factory; if it touches paths it must policy-check like the builtin file tools. Update README §Built-in tools. - **Sandbox preset/config**: update SANDBOX.md (see its "How policies merge" section). ## Sandbox rules Sandboxing is default-on for bash, shell tools, and stdio MCP servers (bubblewrap on Linux, Seatbelt on macOS); it fails closed, tool metadata cannot opt out, and credential paths are denied by default. Never add a code path that runs a child process outside the sandbox factory, and never weaken deny-list behavior without updating SANDBOX.md. ## Gotchas - Do not commit the `polly` binary (34 MB, gitignored at repo root), the `textfx` experiment binary (`go build ./experiments/...` drops it at the repo root; gitignored there and under `experiments/textfx/`), or runtime data. - `.gopath/` (~1.4 GB) is a local GOPATH cache, gitignored — not repo source. `.claude/worktrees/`, `.polly-shots/`, `.zvec-grep/`, `.tmux-tmp/` are scratch; work from the repo root or greps will hit duplicate trees. Agent-facing skills live in `.agents/skills/`. - `skills.Message` is deliberately field-order-compatible with `messages.ChatMessage` to break an import cycle — do not reorder fields. - Tool wrappers must preserve media output: use `NamespacedTool.ExecuteOutput` when wrapping; don't drop `OutputTool` semantics. - Provider quirks are intentional: reasoning models reject `temperature`; OpenAI reasoning items are model-locked and dropped on model switch; Anthropic has a legacy vs adaptive thinking split (`legacyThinkingPrefixes`).