Skip to content

Extension map ​

Keel has exactly two extension philosophies, and which one applies depends on what kind of thing you are changing:

  1. Protocol / primitive changes (a new execution primitive, a new transport, a new event kind, a new loop implementation) are in-repo, spec-first work. They touch the kernel or a protocol package and must go through the repository's OpenSpec process.
  2. Assembly / policy changes (which provider, which tools, which services, which external backend) are configuration and service-graph work. They do not change the ledger.

Before choosing a seam, know the visibility rule: every runtime package lives under internal/, so they can only be imported by code inside this module. "Embedding the runtime" therefore means working in a checkout of this repository (or a fork) — see Embed the runtime.

Decision table ​

I want to…SeamPage
Run the core inside my own process / binaryinternal/servicehost.Boot + the kernel seams, or a new cmd/ in a forkEmbed the runtime
Add or replace a service (provider, projection, compaction, telemetry…)servicegraph.ServiceDescriptor + loadout.Config.ProvideWrite a service descriptor
Replace the agent loopthe agentloop.Loop contract + the pinned PI conformance manifest (fail-closed)Write a service descriptor
Talk to an external agent runtime (a sidecar that owns its own sessions)AgentBackend over the external gateway (external.backends)Connect an external backend
Expose an external tool serverToolProvider (external.tools)Connect an external backend
Add a model provider or change protocolsprovider.StreamFn + provider.ResolveProviderWrite a provider adapter
Add a tool to the model's toolboxagenttool.ToolRegistry (kernel side) or the host registry (tools.allow filters it)Embed the runtime
Add a product capability (plugin, hook, trigger, sub-agent, approval)the Harness extension surface (internal/agentext today; plugin standard documented in the Harness line)Harness plugins
Add a new event kindin-repo change: kindRegistry + internal/store constants + transcript/SSE/R1 rules move togetherEvents and protocol
Change storage or add a tablein-repo change: internal/store/schema.sql or a numbered kernel migrationStorage and runtime
Build a UIthe Harness API + SSE (versioned /v1, capability discovery)AgentAPI reference

The two hard rules ​

A service may be replaced; a service may not change the ledger. Services receive narrow seams (kernel.Committer, kernel.Reader, kernel.LeaseManager, kernel.ExternalSessions, internal/kernel/seams.go) and commit proposals; the kernel decides what becomes a fact. If your change needs to write events, allocate seq, reorder commits, or bypass tenant/lease checks, you are changing the kernel — which means a spec, a migration number and the R1 parity gate, not a plugin.

The conformance gate is fail-closed. Any service that provides ctx.loop must present a PI conformance manifest whose canonical hash equals its pin; a missing declaration is a rejection, not a pass. If you replace the loop, run the suite and declare it deliberately (internal/loadout/conformance.go:55, internal/loadout/conformance.go:18).

Where the work lands ​

ChangeFiles you touchGate you must run
New service descriptorinternal/loadout/*, your factory, testsgo test -race ./internal/loadout ./internal/servicegraph ./internal/servicehost; then scripts/acceptance-all.sh if the default assembly changed
New loopinternal/agentloop implementation + declarationPI conformance suite + R1 diff + the loop conformance gate
External backendtenant document (external.backends) + a provider processgo test -race ./internal/gateway ./internal/externalgw + scripts/external-gateway-smoke.sh
Provider adapterinternal/provider + registry entryprovider stream tests; real-model E2E if credentials allow
New event kindkindRegistry, store constants, transcript/SSE/R1 rulesR1 diff (whitelist outside zero difference) + full acceptance-all.sh

The gates themselves are documented in Test and accept.

Apache-2.0 (MIT notices kept for files moved from pigo)