Skip to content

Contributing

Joey King edited this page Oct 5, 2026 · 4 revisions

Contributing

CONTRIBUTING.md in the repository is the authoritative version; this page is the short form.

What gets added

A change to the runtime starts with a consumer that needs it. The rule is decision 1: abstractions are added when a consumer demonstrates the need, not before. The two consumers today are repo-steward and casework; anything either had to build itself is a candidate (the one recorded exception is the Gate, which came from outside research and which decision 7 says sets no precedent), and the "consumer need" issue form asks who the consumer is, what it built, why the runtime is the right home, and which roadmap item it supports. Open that issue before writing code. A proposal with no consumer behind it is refused rather than deferred, and so is anything that would make the runtime a workflow engine, a multi-agent orchestrator, a prompt or memory framework, or a service. There is no CLA; the maintainer reviews and merges.

Layout

The core module keeps two dependencies. Anything that adds one lives in a nested module with its own go.mod and a directory-prefixed tag (mcp/v0.2.0). Nested modules pin the core to its release tag, so inside the repository the modules resolve each other through a workspace:

go work init . ./providers/ollama ./providers/anthropic ./providers/openai ./mcp ./bench ./export/otel ./proxy ./examples/live ./examples/mcp

go.work is not committed. Every module's go directive is the previous Go release, 1.26; CI runs each on that and the current one, 1.27. A nested module's directive can be no lower than what the core release it pins requires, which go mod tidy enforces, so raising the core's directive drags the nested modules up at their next re-pin. Do not raise it without a reason a consumer can read.

Suites

  • core, with only its own dependencies: GOWORK=off go vet ./... and GOWORK=off go test -race -count=1 ./...
  • each nested module, through the workspace: go vet ./... and go test -race -count=1 ./... in its directory
  • live tests against a local Ollama: go test -tags live -count=1 ./... in providers/ollama and providers/openai
  • examples/scripted runs without a network; examples/live needs Ollama; examples/mcp needs Ollama and Node, and (cd examples/mcp && npm ci --ignore-scripts) once first
  • the Example functions run under go test and their output is checked; keep it deterministic by fixing ids with Config.NewID and printing no timestamps

Testing has the commands in full.

Lint

CI's lint job runs gofmt, staticcheck, and govulncheck at pinned versions, plus a tidy check on the core:

gofmt -l .
GOWORK=off go mod tidy -diff
GOWORK=off staticcheck ./...
GOWORK=off govulncheck ./...

The first two must print nothing. Each nested module runs staticcheck and govulncheck through the workspace. Install the tools at the versions .github/workflows/ci.yml names.

Recordings

No test calls a provider. Replays key on the model name and the canonical rendered request (replay.Key). A change to a prompt, a tool's name, description, or schema, a tool result shape, or an adapter's request mapping changes the key, so the consumers re-record, in the consumer, before the change lands; a recording is comparable only within one commit. The renderer's hooks exist so a consumer's rendered bytes can be kept identical while it adopts the shared code; both consumers proved that when they deleted their copies.

Releasing

The core and each nested module tag independently, and the order in which they are tagged is what proves the graph a consumer resolves actually builds. The procedure, the release check, the three-tags-per-push limit, the rule against bypassing the checksum database, and tag immutability are on Releasing. The changelog's ## [Unreleased] section becomes each release's dated section.

Style

Terse comments that say why; every exported symbol has one and is justified by a consumer. No speculative abstraction: no interface with one implementation and no option nobody passes. Tests named TestX_Behaviour. A row in docs/status.md per control, naming the test that verifies it. A design constraint gets a decision record under docs/decisions. Commit messages have an imperative subject and a body that says why; no attribution trailers.

Security

SECURITY.md says what the runtime defends against, what it leaves to the operator, and how to report a vulnerability without disclosing it publicly. Security Model restates it by attacker.

Clone this wiki locally