Skip to content

Architecture Overview

0xfauzi edited this page Aug 25, 2026 · 5 revisions

Architecture Overview

Start with the live atlas: https://0xfauzi.github.io/kstrl/atlas/. It is generated from the code, so it cannot drift from it: every component, what it does, what flows between them and in which direction, which parts are built and which are planned, in layers you can switch between (how a spec becomes a merged pull request; who measures what; what feeds back to the agent; where you stand; how autonomy is earned and lost; what carries between runs; how you see what happened). Click any component to see what it is to its neighbours, and step through a journey to watch one spec cross the system. This page is the prose orientation over that map. The canonical deep dive is ARCHITECTURE.md; the adversarial role taxonomy with invariants and known limitations is docs/adversarial-design.md.

The loops, and how fast each one runs

kstrl is easiest to read as a set of nested loops, each with its own clock, each measuring what the faster loop inside it produced and handing a target to it. The phase chain below is what happens inside one tick of the accept and integrate loops.

Rate Loop What acts What measures What it steers toward
seconds implement the engineer agent (a fast sensor, once evidence shows the loop iterates: R10.12) one story's acceptance criteria
minutes accept retry with a structured context mechanical checks, reviewer, security review the component's PRD
tens of minutes integrate schedule and merge contract tests, the dampener (R10.6) the manifest satisfied
hours intake queue admission queue state, spend, inbox, open PRs (R10.7), safe mode (R10.4) the queue drained within bounds
days trust the autonomy level run outcomes, calibration, health trending (R8.4) the autonomy the evidence supports
weeks learn playbook and prompt changes (R9) attribution, calibration the harness's own detection rates
days operate (R8.7, R8.8) the release driver runtime errors, health probes the shipped service's objectives

The rule that holds every loop together: what acts never measures its own result. The design behind this table, with what is closed today and what each cycle closes, is docs/control-loop-design.md.

The seven loops, each with its sensor, its controller and its set point

Generated from the same model as the atlas; a change in the picture is a change in the system.

The factory flow

The Work layer: how a spec becomes a merged pull request

Only the components the Work layer touches are drawn. The atlas shows the same edges with the other six layers switchable.

A run starts from a markdown spec (or a SpecKit artifact directory, or a hand-written prd.json for single-component runs):

  1. Architect / PRD red-team (LLM). Decomposes the spec into a component DAG with per-component PRDs and EARS-style acceptance criteria. Halts on blocker-severity spec issues (SpecBlockerError) - there is no override flag; the spec gets fixed, not the gate.
  2. Per component, in DAG order (sequential or parallel, each in an isolated git worktree cut from origin/<base>):
    • Phase 0 - Feedforward (mechanical): module map, public interfaces, import graph, conventions - context assembled without token cost.
    • Knowledge prefix: durable facts from prior runs injected into the engineer's context.
    • Engineer (LLM): iterates until complete; must emit a ## Self-Critique block.
    • Phase 1 - Mechanical verify (no LLM): tests, typecheck, lint, diff-scope, bad-patterns; optional dead-code, mutation, fixtures.
    • Phase 2 - Reviewer (LLM): PRD-criterion verdicts plus concern categories (scope creep, test quality, security concern, ...).
    • Phase 2.5 - Security (LLM): OWASP/CWE-mapped threat review.
    • Knowledge distiller (LLM): writes durable facts to disk before the PR merges, preserving the true-delta invariant.
    • E6 checkpoint (human, optional): pause before PR merge.
    • PR create + merge via gh.
  3. Phase 3 - Contract testing (mechanical): merged tier branches run cross-component integration tests; a failing tier bisects to the breaking component and re-runs it.
  4. Evolution journal: every component outcome, error signature, cost, and finding summary is recorded.

Phase numbers are sticky by convention: new phases take fractional numbers so ordering semantics never shift. The planned release stage (tracker item R8.7 on the Roadmap) will be Phase 4.

The spec-to-merge journey, all thirteen steps at once

The eight roles

Role Kind Catches
Architect / PRD red-team LLM Spec ambiguity, missing failure modes, unstated assumptions
Engineer LLM Implements one story per iteration
Mechanical verifier No LLM Test/type/lint failures, diff-scope violations, bad patterns
Code reviewer LLM PRD violations, scope creep, test quality
Security reviewer LLM OWASP-mapped vulnerability categories
Contract tester No LLM Cross-component integration breaks
Knowledge distiller LLM Durable facts worth carrying to future runs
Human checkpoint Human Whatever the machines missed (optional, config-gated)

The events substrate

The filesystem is the event bus. Every run writes .kstrl/runs/<run_id>/events.jsonl - schema-versioned, typed events (~38 kinds: component_started, verification_result, pr_merged, circuit_breaker_tripped, ...). Decoding is total: unknown events degrade losslessly, torn tail lines are skipped, and sinks are observability, never control flow.

Every surface is a projection of that stream: the Textual dashboard (ks dash, the bare-ks home shell), ks status for scripts and CI, the optional one-way Linear mirror. Nothing is displayed that cannot be reconstructed from the run directory.

Run IDs are kind-prefixed (factory-, decompose-, feature-, understand-) and sort chronologically across kinds.

State layout

.kstrl/
  runs/<run_id>/events.jsonl     # the event stream (the record)
  runs/<run_id>/components/<id>/ # per-component logs and phase evidence
  knowledge/<component>/<run>/   # durable facts (markdown, per-fact files)
  evolution.jsonl                # component outcomes, error signatures
  experiments.tsv                # metrics for trend analysis
  worktrees/<run>/<component>/   # isolated build workspaces
  factory.lock                   # single-run flock

Agents and adapters

Four adapters: claude-code (CLI), codex (CLI), claude-sdk (optional extra, in-loop budget enforcement, opt-in only - auto-selection never picks it), and custom (any command). All subprocess execution runs through a deadline streamer with process-group kill; every subprocess in the system has a bounded timeout. An OS-level sandbox (write-scope = worktree, network deny by default) applies where the agent supports it.

Safety and budgets

Defense in depth, all config-gated: per-phase and per-component timeouts, a no-progress circuit breaker (unchanged diff + unchanged failures = halt), an adversarial-call budget shared across review/security/distill phases, a run-level token budget enforced at phase boundaries, a 5 MB output cap per agent invocation, and run/worktree flocks. Reviewer and security findings distinguish infrastructure_error ("never ran") from "ran clean" - an empty findings list is a safe success signal.

Configuration

kstrl.toml sections mirror config dataclasses ([agent], [factory], [verify], [security], [timeout], [breaker], [sandbox], [knowledge], [evolution], [notify], [linear], ...). Precedence: CLI flag > KSTRL_* env > kstrl.toml > dataclass default. See kstrl.toml.example and docs/env-vars.md.

Clone this wiki locally