kranz 0.2.2

Git-native mission control for governed, validated AI coding-agent work.
Documentation

Kranz

Git-native mission control for headless coding agents. Kranz is a local governance and evidence harness—named for Gene Kranz, the Apollo flight director. An orchestrator plans, fresh-context workers implement one feature at a time, independent validators judge each milestone, and a human steers as project manager. The harness never touches the spacecraft; it runs the room.

The product is the few seconds between an agent wanting to act and a human trusting it. The consent surface — plan approval, command grants, the merge gate — is kranz's answer to that interval, and the flight-surgeon console (kranz outcomes) measures it: grant-latency buckets turn "do you actually review?" into data.

Built in Rust with Claude Code as the default runtime. Role-specific backends also support Codex CLI, Factory Droid, Kimi Code, Cursor, ACP-compatible agents, and OpenAI-compatible local inference. Claude sessions can use a repository's CLAUDE.md and .claude/skills; a repository's own .claude/settings.json, hooks, and .mcp.json are never loaded, because they run commands before the model's first turn (only the operator's user-level settings apply). Git is the source of truth; an append-only, hash-chained event log makes every mission kill -9-safe.

┌───────────┐   plan/judge    ┌────────────────────────────────┐
│ you (PM)  │◄──────────────► │ orchestrator (opus, read-only) │
└─────┬─────┘                 └───────────────┬────────────────┘
      │ kranz msg / dashboard                 │ engine loop (§4.5)
      ▼                                       ▼
  events.jsonl ◄── single writer ──  workers (sonnet, fresh session per
  state.json                         feature) → validators (scrutiny +
  plan.json (committed)              functional, fresh per milestone)

Quick start

Prerequisites: Rust 1.88+, Git, and at least one configured agent backend. The default is the Claude Code CLI (claude), installed and authenticated. Kranz discovers it on PATH and in the usual install locations, or you can set KRANZ_CLAUDE_BIN / claudeBinary in configuration. Other backends have role and sandbox restrictions; run kranz ready before the first mission.

git clone https://github.com/craigcode/kranz.git
cargo install --path kranz/crates/cli --locked  # installs the current source
cd /path/to/your/repo             # must be a git repo

# 0. Onboard the repo. This detects common Rust/Node/Python gates, adds the
#    runtime ignore template, and optionally registers it with multi-repo serve.
kranz init --register
# Unfamiliar toolchain: repeat --gate, e.g. kranz init --gate "make verify"

# 1. Plan interactively — contract first, then milestones/features.
#    /plan renders the proposal + cost estimate; approval commits plan.json
#    onto a new branch kranz/mission-<id>.
kranz plan "Add a REST endpoint with auth, then a small CLI client"

# 2. Execute unattended. Live role-tagged event tail; Ctrl-C (or kill -9) is
#    safe — rerun to resume from the event log.
kranz run

# 3. Watch / steer from another terminal or the dashboard:
kranz status                      # terminal tree + tokens/cost
kranz msg "swap feature 4 for X"  # queued between worker runs
kranz msg --interrupt "stop"      # aborts the current worker first
kranz pause | kranz resume
kranz config show                 # effective merged config (+ the layer files)
kranz config set worker.model opus       # edit .kranz/config.json (validated)
kranz config role worker opus xhigh      # MID-MISSION: applies at next worker spawn
kranz serve --open                # Mission Control dashboard (browser)

kranz serve includes an embedded dashboard bundle. When developing the UI, run cd <kranz checkout>/apps/dashboard && npm install && npm run build && npm run sync-embedded; kranz serve will prefer that fresh build automatically (searching --dashboard DIR, $KRANZ_DASHBOARD_DIST, <repo>/apps/dashboard/dist, installed asset dirs such as ~/.kranz/dashboard/dist, then the kranz checkout used to build the binary, before falling back to the embedded bundle).

Desktop app: cd apps/dashboard && npm install && npm run build && npx tauri dev (reads KRANZ_REPO; see apps/dashboard/README.md).

Install

From source — the current code. This path builds the public repository and includes the embedded web dashboard:

git clone https://github.com/craigcode/kranz.git
cargo install --path kranz/crates/cli --locked

If you already have a checkout, run cargo install --path crates/cli --locked from its root.

With Cargo — a versioned release. Request v0.2.1 explicitly so Cargo cannot silently install the older 0.0.1 placeholder:

cargo install kranz --version 0.2.2 --locked

If crates.io reports that 0.2.1 is unavailable, use the source install above. Cargo builds the CLI's three library dependencies automatically. Check the published crate versions for registry availability; a public GitHub repository does not publish a crate automatically.

Prebuilt binaries. Check the GitHub Releases page for platform archives, checksums, and license notices. If the requested version has no archives yet, use the source or versioned Cargo install above. kranz licenses prints the bundled project, Rust dependency, and dashboard notices.

Homebrew distribution is intentionally deferred until the v0.2.0 Cargo and GitHub installations have been proven on clean hosts.

Agent runtime and authentication

Kranz orchestrates agent CLIs; it does not install them or sign into their accounts. Install at least one supported runtime from its vendor, authenticate it outside Kranz, and leave its native executable discoverable on PATH. Claude Code is the default. Codex, Factory Droid, Kimi Code, Cursor, ACP peers, and OpenAI-compatible local endpoints can be selected per role. API-key authentication is passed only through each backend's sanctioned variable, not through the ambient environment. See Agent backends, then run kranz ready before the first mission.

Crates and API stability

Most users install only kranz. Cargo fetches the other crates because they are reusable components of the product:

Crate Provides
kranz The CLI, kranz serve, and embedded Mission Control dashboard.
kranz-engine Mission orchestration, isolation, gates, validation, evidence, and controlled local merging.
kranz-server The REST/WebSocket mission host used by kranz serve and custom front ends.
kranz-slack The Slack Socket Mode bridge for operating and observing missions.

The three library crates are public for reuse, but their Rust APIs are early and evolving in the v0.2 line. Pin exact versions if embedding them; semantic compatibility is not yet promised beyond Cargo's normal pre-1.0 rules.

The four roles

Role Job Lifetime Sees Touches Default
Orchestrator Plans contract-first; judges worker reports; converts or waives findings; decides respawns, dirty trees, unblocks; judges agent-judgement assertions at the final gate One long-lived session per mission (resumable/re-seedable) Digest, plan, reports, findings — never raw transcripts Nothing — read + git-inspect only; the engine writes/commits plan.json/plan.md opus · high
Worker Implements exactly one feature: tests first, implement until green, lint/build, commit [feature-id]-prefixed, end with a WorkerReport Fresh per feature (bounded respawns) Its spec + criteria + goal — never the mission transcript Edits + Bash in the repo; denied push/publish/network/sudo sonnet · medium
Validator · scrutiny Adversarial review of the milestone diff: tests asserting implementation, dead criteria, integration seams, out-of-intent regressions Fresh per validation round Milestone spec, contract, start-sha..HEAD diff Read-only + inspect commands opus · high
Validator · functional Judges the engine-captured results of contract commands and configured test/build/lint scripts; reports pass/fail from bounded verbatim evidence Fresh per validation round Contract results + milestone criteria Read-only; optional explicitly configured live-QA tools sonnet · medium

Two validators catch different failures: functional judges whether the engine-run gates worked; scrutiny catches "it runs but it's wrong"—passing tests that assert the implementation, unwired criteria, and broken seams between features.

How it works

  • Contract first. Planning defines behavioural assertions before any feature exists. Command assertions gate mission completion mechanically; the rest are judged by the orchestrator against the full mission diff.
  • Fresh contexts. No worker ever sees the mission transcript — only its feature spec, criteria, and a plan excerpt. Validators never see the worker's reasoning, only the diff and the contract.
  • Bounded loops. Failing validation converges to a blocked milestone (loud in UI and CLI) after maxFixCyclesPerMilestone, never to infinite spend. Worker respawns are capped; per-run dollar budgets are enforced by the CLI itself.
  • Permissions per role (§4.7). Orchestrator: read + git-inspect only. Workers: edits allowed, deny-listed from push/publish/network. Validators: read-only + the contract's commands. Denials surface as events (the dashboard shows guardrails firing). --dangerously-allow-all exists, is loud, and is never the default.
  • Kranz never pushes by default. The mission branch is the deliverable; you review and open the PR. The sole exception is an explicit cloud handoff: kranz exec --push <configured-remote> may publish one completed kranz/* branch for human review, never a base branch, tag, force-push, or merge.

Layout

Path What
crates/engine orchestration core: event log, reducer, backends, runners, mission loop
crates/cli the kranz binary
crates/server axum REST + WebSocket (docs/protocol.md)
apps/dashboard Mission Control UI (React/Vite) + Tauri shell
docs/ design notes, protocol, dashboard reference
.kranz/missions/<id>/ per-repo mission data (events.jsonl, state.json, plan.json, transcripts)

Config: .kranz/config.json (project) over ~/.kranz/config.json (global) — per-role models/effort/budgets, fix-cycle caps, deny patterns. Defaults use model aliases (opus, sonnet) so they track the latest releases. Inspect and edit the layers with kranz config show|set|unset (--global targets the home file; edits are validated before writing and only shape future missions); kranz config role <role> <model> [effort] is the mid-mission path — it queues a config-change on the running mission, like Slack's /kranz config.

kranz init is additive and idempotent: it never replaces an existing gate suite, and it preserves existing .gitignore and global-config keys. Pass --register [--id ID] [--display-name NAME] to add the canonical root to the dashboard/Slack host catalog. Its first-run report calls out the safe worktree isolation default and a zero-mission calibration cold start.

The human-triggered Merge action uses the tracked .kranz/merge-gates.json from the live base branch (schema and examples: docs/merge-gates.md). Each gate declares a command, optional repo-relative working directory, and optional changed-path prefixes; missing or invalid suites fail closed. Because the mission branch does not supply the suite that judges it, a mission cannot weaken its own merge checks or secret waivers. Gates run on the exact pinned mission/base integration commit in a scratch worktree; only that tested commit can advance the base.

Development

cargo test --workspace          # full workspace suite; no model calls by default
cargo test -p kranz-engine -- --ignored   # + live smoke test (spawns claude)
node scripts/mock-server.mjs    # dashboard dev harness with a canned mission

The full contributor gate and pull-request expectations are in CONTRIBUTING.md. Security issues belong in the private reporting channel described by SECURITY.md, not a public issue.

Cloud (preview)

Kranz is local-first and never pushes during ordinary local missions or gated merge. Cloud missions (M6, preview — not yet exercised end-to-end) may use the explicit kranz exec --push <configured-remote> handoff to publish the completed mission branch as a reviewable kranz/* ref only — never main, a tag, force-push, or merge. See the Dockerfile and the cloud deploy runbook.