0007. Integrating Keelgate¶
- Status: Accepted
- Date: 2026-10-06
- Phase: T4
Context¶
AGENTS.md makes Keelgate the only thing that may govern a side effect, and confines every import
of it to src/tycheon/governance/. Phase T4 is where that boundary acquires code. Reading
Keelgate's integration contract and source showed it is further from the brief than assumed: its
telemetry and evals modules are empty, its OutcomeMetric protocol is not defined, it is not
on PyPI and has no tags, and its MCP HTTP transport shares one grant across callers.
Decision¶
- One module, no bypass. All
keelgateimports are intycheon.governance. Tests enforce: no import elsewhere, no use of Keelgate internals, notry/except ImportErrorfallback around a Keelgate import, and no call to the raw analytics functions fromserve/oragents/(so the governed tool is the only way in). - A policy overlay, not a new pack. Keelgate's
finance_basicis vetted and deny-by-default but does not know Tycheon's analytics capabilities and auto-allows small paper trades. A small PythonPolicyEnginewraps it: analytics are allowed asREADonly; a paper trade the pack would allow is raised toREQUIRE_APPROVAL; it can raise or deny, never lower; any error is a denial. This avoids writing new Rego (a place Keelgate's own history found a fail-open) while making "never auto-approved" a tested property. - Least-privilege grants per agent, exact capabilities, re-issued before expiry with a fresh budget window. REST and MCP callers get their own service principals.
as_ofis trusted context, not an argument. Services readas_of, tenant and data from aContextVarthe runtime binds around each gateway call. Tool inputs have noas_offield and unknown fields are rejected.- The draft/verify/revise cycle runs on Keelgate's
Loop, with Tycheon's writer as its planner role and Tycheon's verifier as its verifier role, to get budgets, revision limits, checkpoints and audit rather than reimplement them. - MCP over stdio only. Keelgate's HTTP transport cannot identify callers.
- Dependencies.
keelgate>=0.1,<0.2in theagentsandserveextras (never the base install). Until Keelgate is released,[tool.uv.sources]pins a commit (uv-only, not in published metadata).mcpmoves to>=2.3,<3to match Keelgate. - Gaps are stand-ins, labelled. Telemetry uses the OpenTelemetry API directly; outcome
metrics are registered under Keelgate's entry-point group in a shape of Tycheon's own
(
tycheon.metrics); evals are pytest suites onkeelgate.testing.FakeLLM. Each is a small, isolated change when Keelgate ships the real thing.
Consequences¶
- A published
tycheon[agents]is not installable until Keelgate is on PyPI. - Whether Keelgate can discover Tycheon's metrics is untested until it defines the protocol.
- Tycheon is coupled to one Keelgate commit until then; the architecture tests keep the blast radius to one package.
Alternatives considered¶
Importing Keelgate across the codebase (rejected: AGENTS.md); a new Rego pack (more safety-critical
code to get right); trusting the model-supplied as_of (rejected: a model could ask for the
future); exposing MCP over HTTP with one shared grant (a confused deputy).