# jkz docs > Human-in-the-loop multi-agent engineering — three phases, twelve roles, you as the final arbiter. ## jkz docs Source: https://docs.j0kz.dev/ Most agent tools optimize for autonomy. jkz optimizes for control. Code work runs through three phases (**plan**, **build**, **QA**) across twelve specialized roles. In each, Opus drafts, an adversarial backend tries to break the work, and a validator confirms. Git is the only source of truth; agents never talk to each other directly. Nothing reaches `main` without you: the system iterates up to three times on its own, but every merge is a human checkpoint. :::tip[Get started] New here? The path from zero to your first merged pull request. - [Quickstart](/get-started/quickstart/) — your first pipeline, end to end. - [Why jkz?](/get-started/why-jkz/) — the problem it solves and the constraints behind it. - [How jkz works](/get-started/how-jkz-works/) — phases, roles, and the deliberation loop. ::: :::note[Build] The day-to-day, once you know the shape of a pipeline. - [Run a pipeline](/build/run-a-pipeline/) — drive a feature from issue to approval. - [Fix a bug](/build/lightweight-routes/) — the lighter path for small, scoped changes. - [Ad-hoc work](/build/lightweight-routes/) — quick edits outside the full pipeline. ::: :::note[Reference] The mechanics, for LLMs and engineers who want the full picture. - [Architecture](/reference/architecture/) — phase boundaries, roles, model routing. - [API reference](/api-reference/) — auto-generated module exports and signatures. - [Design decisions](/reference/design-decisions/) — the ADRs and trade-offs. - [llms.txt](/llms.txt) — this site as a plain-text index, for agents. - [llms-full.txt](/llms-full.txt) — every page concatenated, one document. ::: ## An ad-hoc fix without the full pipeline Source: https://docs.j0kz.dev/get-started/ad-hoc-fix/ Not every change deserves an Architect, an Auditor, and a QA pass. A typo, a wrong error message, a one-line off-by-one — running the full pipeline on those wastes tokens and your time. This tutorial walks you through the **lightweight path** hands-on: you'll ship one small fix with `/jkz:quick` (Builder + Judge, no plan, no QA) and see how much shorter it is than the [full pipeline](/get-started/first-issue-with-plan-checkpoint/). It takes only a couple of minutes. Pick something genuinely tiny and reversible — the whole point is that small changes move fast. :::note[About the outputs below] Command outputs are **illustrative**. jkz wraps live models and external backends, so exact wording, token counts, and timings drift from run to run. The *shape* (which command you run and which agent speaks) is stable, not the byte-for-byte text. ::: ### Before you start Same setup as the other tutorials: **Claude Code CLI** signed in, **`gh`** authenticated against a repo you can safely open a throwaway PR against, and jkz installed (`jkz install` then `jkz init`). If that's not done yet, the [quickstart](/get-started/quickstart/) walks the install end-to-end. ### Step 1 — Pick a genuinely small fix The lightweight path is for changes of roughly 1–10 lines with an obvious approach. Good first targets: - Fix a typo in a user-facing string or an error message. - Correct an off-by-one in a loop bound that you can see is wrong. - Tweak a default value or a config constant. If the change has *a decision in it* — a new feature, an architectural choice, anything touching more than a handful of files — stop and use the [plan-checkpoint route](/get-started/first-issue-with-plan-checkpoint/) instead. The plan and QA phases exist precisely for work with design decisions or wide blast radius; the lightweight path deliberately skips them. ### Step 2 — Let `/jkz:start` size it for you Describe the fix and let the front door route it: ```text /jkz:start ``` ```text > Describe what you want to do. It can be a vague idea, a bug, a feature. you: the retry log says "attemps" — should be "attempts" [triage] complexity: quick confidence: high [duplicates] no open jkz:ready issue matches — creating a new one [brief] type: chore · scope: 1 file · fixes a typo in the retry log message Created issue #88 — chore: fix "attemps" typo in retry log Recommended: /jkz:quick 88 (small, scoped — lightweight pipeline) ``` The **Classifier** (Claude Haiku) sized this as `quick` and recommended `/jkz:quick`. Two things to notice: - A truly `trivial` change (the classifier's smallest bucket) it offers to **just fix inline** — no issue, no PR ceremony. If you'd rather skip even that, you can always edit the file directly on a branch; jkz doesn't force a pipeline on you. - A `standard` result would have recommended the full pipeline instead. `/jkz:quick` re-checks the size on the spot and warns you if the change is actually too big for it. Note the issue number — we'll use `88`. ### Step 3 — Run `/jkz:quick` ```text /jkz:quick 88 ``` This is the minimum viable pipeline: **two agents, one reviewer, no plan, no QA.** ```text jkz:builder reading issue #88 (the issue body is the plan) jkz:builder opened PR #89 — chore: fix "attemps" typo in retry log (Closes #88) jkz:judge PASS — one-character fix, matches the issue, no side effects CR reconciliation: 0 findings jkz:approved ``` What just ran, and what *didn't*: - **No Architect, no plan.** The issue description *is* the plan. The Builder reads it and implements directly in an isolated worktree, then opens the PR. - **The Judge is the sole reviewer.** No CodeRabbit pre-scan and no Inspector — not worth the latency for a one-line change. The Judge calibrates to the small scope. - **No QA phase.** Lens and Sentinel don't run. If the Judge returns **FAIL**, the Doctor applies a fix and the Judge re-reviews — up to three times, then it escalates to you at `jkz:blocked`. Same honest-escalation rule as the full pipeline; it just has fewer moving parts to begin with. ### Step 4 — Merge it yourself The lightweight route does **not** weaken the merge gate. Only a human merges, and only through the server-side workflow with your passphrase: ```bash gh workflow run approve-merge.yml -f pr=89 -f passphrase= ``` The PR merges and issue `88` closes automatically via its `Closes #88` keyword. ### What just happened - You shipped a fix through a **stripped-down loop** — Builder writes it, the Judge reviews it, you merge it. No plan, no QA, far fewer model calls than the full pipeline. - The issue body did the job a plan would do in a bigger change: it *was* the spec. - Everything that makes jkz trustworthy still held — the change ran in an isolated worktree, the PR is the audit trail, and **only your passphrase** got it to `main`. ### Choosing a route next time | You have… | Reach for… | |-----------|-----------| | A typo, a one-line fix, a doc edit | Edit directly, or `/jkz:quick` | | A small scoped change with a clear direction | `/jkz:quick` | | A feature or anything with a design decision | The [plan-checkpoint route](/get-started/first-issue-with-plan-checkpoint/) or the full `/jkz:pipeline` | | A PR a reviewer just failed | `/jkz:fix` (usually automatic) | ### Next steps - [Your first issue with a plan checkpoint](/get-started/first-issue-with-plan-checkpoint/) — the other end of the spectrum: drive every phase by hand with a plan approval up front. - [Lightweight routes](/build/lightweight-routes/) — the reference for `/jkz:quick` and `/jkz:fix`, including how the complexity classifier decides where you land. - [How jkz works](/get-started/how-jkz-works/) — the full three-phase model behind all of this. ## Your first issue with a plan checkpoint Source: https://docs.j0kz.dev/get-started/first-issue-with-plan-checkpoint/ The [quickstart](/get-started/quickstart/) hands one issue to `/jkz:pipeline` and lets it run autonomously, pausing only to approve the plan and the merge. This tutorial takes the **other** path: you drive each phase by hand — `/jkz:plan`, then `/jkz:build`, then `/jkz:review`, then `/jkz:qa` — and stop to look around between them. Same destination, but you control each step. The point is to see where the phase boundaries are and what you get to decide at each one. It takes a few focused minutes plus some waiting while the agents deliberate. Pick a small but real change — something that genuinely benefits from a plan, not a one-line typo. A typo would route to a [lightweight path](/get-started/ad-hoc-fix/); here we want a change worth planning. :::note[About the outputs below] Command outputs are **illustrative**. jkz wraps live models and external backends, so exact wording, token counts, and timings drift from run to run. The *shape* (which command you run, which agent speaks, and what gate you hit) is stable. Treat the snippets as "what you'll roughly see," not byte-for-byte transcripts. ::: ### Before you start You need the same setup as the quickstart: the **Claude Code CLI** signed in, **`gh`** authenticated against a repo you can safely open a throwaway PR against, and jkz installed (`jkz install` then `jkz init`). If you haven't done that yet, run the [quickstart](/get-started/quickstart/) first (it walks the install end-to-end), then come back here for the manual route. For a complete planning loop you'll want an adversarial backend configured (the Auditor challenges the plan). Without one, the audit is skipped and jkz tells you so; the run still works, it's just less rigorous. ### Step 1 — Pick a change worth planning Choose something small but with a real decision in it. Good first targets: - Add a `--json` output mode to a script that currently prints plain text. - Add one new optional field to a status command's output. - Add input validation to a function that currently trusts its caller. Each of these has a question to answer (what shape should the JSON be? what's the default?), which is exactly what makes the plan checkpoint worth seeing. Avoid the ambitious refactor; you want one clear decision, not ten. ### Step 2 — Turn it into an issue with `/jkz:start` `/jkz:start` is the conversational front door. Describe the change in plain language and let it create the issue: ```text /jkz:start ``` ```text > Describe what you want to do. It can be a vague idea, a bug, a feature. you: add a --json flag to the status script so it can print machine-readable output [triage] complexity: standard confidence: high [duplicates] no open jkz:ready issue matches — creating a new one [brief] type: feature · scope: 1 script + tests · adds --json output mode Created issue #214 — feat: add --json output mode to status script Recommended: /jkz:pipeline 214 (standard — full pipeline) ``` It recommends `/jkz:pipeline` — the autonomous route. We're going to ignore that recommendation on purpose and run the phases ourselves, so we see each one as a separate, deliberate step. Note the issue number; we'll use `214` throughout. ### Step 3 — Plan it with `/jkz:plan` ```text /jkz:plan 214 ``` This runs the **Plan** phase and nothing else. The Architect drafts a strategy, the Auditor attacks it, and the Curator calibrates the audit, iterating up to three times on its own, then stops and prints the full plan for you: ```text PLAN jkz:architect drafting plan… jkz:auditor challenge: what's the JSON shape? is --json mutually exclusive with --verbose? jkz:architect revised: documents the schema, makes --json suppress human-readable lines jkz:curator PASS — plan is minimal, the schema is specified, edge cases covered >>> PLAN CHECKPOINT Problem: status script only prints human text; no machine-readable mode. Changes: add --json flag; when set, emit a documented JSON object and suppress the plain-text lines. Add two tests (flag on / flag off). Risk: low — additive flag, existing default output unchanged. Approve this plan? (or send feedback for another iteration) ``` **This is the decision the whole tutorial is built around.** The plan is the artifact, so it's printed in full. Read it. If the JSON shape isn't what you wanted, *don't approve* — type feedback instead, and the Architect plans again (up to three loops). This is the human-in-the-loop promise in its purest form: nothing gets built until the strategy is one you signed off on. When the plan looks right, approve it. `/jkz:plan` stops here — it does **not** roll into building. That's the difference from `/jkz:pipeline`: the phase boundary is a hard stop you cross by typing the next command. ### Step 4 — Build it with `/jkz:build` ```text /jkz:build 214 ``` The Builder implements the approved plan inside an isolated worktree and opens the PR. A CodeRabbit pre-scan and fix loop clean up the obvious issues, and the pre-push validators run their deterministic checks (secrets, debug statements, invariants): ```text BUILD jkz:builder opened PR #215 — feat: add --json output mode (Closes #214) coderabbit pre-scan: 1 finding (missing test for empty input) — fixed validators PASS — no secrets, no debug leftovers, invariants hold ``` Again it stops. You now have a PR with the implementation on it, but no review verdict yet. Take a look at the diff if you like (`gh pr diff 215`) before moving on. ### Step 5 — Review it with `/jkz:review` ```text /jkz:review 214 ``` The **Judge** reviews the diff against the approved plan, and the **Inspector** verifies it: ```text REVIEW jkz:judge PASS — diff matches the plan; JSON schema matches what was approved jkz:inspector PASS — both tests present and meaningful; default output unchanged >>> REVIEW CHECKPOINT PR #215 passed review. For a feature, QA is required. ✅ run QA ⏭ skip QA 🛑 stop ``` If a reviewer returns **FAIL**, you don't fix it by hand — the Doctor applies a targeted patch and the review re-runs, up to three times. If it still can't get a clean pass, it stops at `jkz:blocked` and escalates to you with an honest diagnosis rather than forcing a fix that hides the problem. Because this is a `feature`, QA is required — so we run it. (For a `bug`, `refactor`, or `chore` you could skip QA and go straight to approval here.) ### Step 6 — QA it with `/jkz:qa` ```text /jkz:qa 214 ``` **Lens** (frontend, visual, accessibility) and **Sentinel** (backend, security, performance) run in parallel: ```text QA jkz:lens PASS — N/A for a CLI flag; no web surface touched jkz:sentinel PASS — no injection risk in the JSON encoder; no new attack surface >>> QA CHECKPOINT PR #215 is approved and ready for merge. ``` Same fix loop applies: a FAIL routes to the Doctor, up to three times, before escalating. When QA passes, the PR is approved. ### Step 7 — Merge it yourself jkz never merges for you — that's the core promise. Merge through the server-side gate with your passphrase: ```bash gh workflow run approve-merge.yml -f pr=215 -f passphrase= ``` The merge gate refuses to merge without the passphrase (a GitHub Secret that Claude Code cannot read), so even a misbehaving agent can't push to `main`. The workflow verifies the passphrase, the PR merges, and the issue closes automatically via the `Closes #214` keyword. ### What just happened - You ran the pipeline **one phase at a time** — `/jkz:plan`, `/jkz:build`, `/jkz:review`, `/jkz:qa`, then merge — instead of letting `/jkz:pipeline` advance for you. Each command stopped at its phase boundary. - The **plan checkpoint** was a real decision: you read the strategy and approved it before a single line was written. That's the difference between this route and the autonomous one — you crossed every boundary deliberately. - Adversarial and validator backends challenged the work at each phase; the system was free to self-correct up to three times, then would have escalated honestly rather than hidden a problem. - Nothing reached `main` without your passphrase through the merge gate. ### When to drive phases by hand vs. autonomously Running phase-by-phase like this is the right move when you want to **inspect or intervene between phases** — review the diff before QA, re-plan after seeing the build, or stop after review for a change that doesn't need QA. Once you trust the loop and just want the result, `/jkz:pipeline` runs the same phases back-to-back and only pauses at the plan and the merge. The phases are identical either way; the difference is how many phase boundaries *you* cross manually. ### Next steps - [An ad-hoc fix without the full pipeline](/get-started/ad-hoc-fix/) — the lightweight path for changes too small to plan. - [Run a pipeline](/build/run-a-pipeline/) — the operator's reference for the autonomous `/jkz:pipeline`, with the full phase/checkpoint diagram. - [How jkz works](/get-started/how-jkz-works/) — the three phases, the twelve roles, and the deliberation loop in detail. Stuck mid-run? `/jkz:status` shows where issue `214` sits right now, and `/jkz:resume 214` picks a stalled run back up from its last phase. ## How jkz works Source: https://docs.j0kz.dev/get-started/how-jkz-works/ jkz turns one issue into one merged pull request through three phases (**plan**, **build**, and for features **QA**), staffed by twelve specialized roles. In each phase Opus drafts the work, an adversarial backend tries to break it, and a validator backend confirms the verdict. Agents never talk to each other: every handoff is a Git artifact (a plan comment, a PR diff, a review comment). The pipeline iterates on its own up to three times per phase, but it cannot reach `main`. You do that, and only you. ### The pipeline at a glance ```mermaid flowchart TD issue(["Issue · jkz:ready"]) --> A subgraph PLAN["PLAN — /jkz:plan"] A["Architect drafts"] --> Au["Auditor challenges"] --> Cu["Curator validates"] Cu -. "FAIL · iterate up to 3x" .-> A end Cu --> H1{{"Human approves plan · post-plan ambiguity gate"}} subgraph BUILD["BUILD — /jkz:build → /jkz:review"] Bu["Builder implements"] --> CR["CodeRabbit prescan + fix loop"] --> Val["Pre-push validators"] --> J["Judge reviews"] --> I["Inspector verifies"] I -. "FAIL · Doctor fixes · up to 3x" .-> Bu end H1 --> Bu subgraph QA["QA — /jkz:qa"] L["Lens · frontend / a11y"] S["Sentinel · backend / security"] D{"Doctor fixes"} L -. "FAIL" .-> D S -. "FAIL" .-> D D -. "up to 3x" .-> L D -. "up to 3x" .-> S end I --> L I --> S L --> H2{{"Post-QA ambiguity gate"}} S --> H2 H2 --> M[["Human merges · 4-layer merge gate"]] M --> done(["Merged to main"]) ``` The dotted edges are iteration loops. A failing verdict sends the work back (to the Architect in planning, to the Doctor in build and QA) for up to three attempts. Exhaust those and the pipeline stops and escalates to you rather than forcing a fix that merely passes the checks. ### The three phases #### Plan — `/jkz:plan` The **Architect** designs the implementation strategy: scope and rationale before any code. The **Auditor** then challenges that plan the way a CEO evaluates a proposal — it ignores the effort and asks what is missing, what is vague, and what will fail. The **Curator** validates the audit itself, catching miscalibrated severities and false positives. Up to three iterations, then a **human checkpoint**: you read the plan and approve it. Nothing is built until you do. #### Build — `/jkz:build` → `/jkz:review` The **Builder** implements the approved plan inside an isolated worktree and opens a pull request. A CodeRabbit prescan and fix loop catch the obvious issues first, then pre-push validators run deterministic checks (secrets, leftover debug statements, capability invariants). The **Judge** reviews the diff as a chaos engineer — it assumes there *is* a bug and asks how the code fails. The **Inspector** is the precision filter on that review, verifying edge cases and execution claims. On a FAIL the **Doctor** applies a minimal fix (exactly what broke, nothing more) and the diff goes back through review, up to three times. #### QA — `/jkz:qa` **Lens** and **Sentinel** run in parallel. Lens owns the frontend: visual fidelity, multimodal output, and accessibility. Sentinel owns the operation: backend integrity, security posture, performance, and infrastructure. A FAIL routes to the **Doctor** again, up to three times. QA is **required** for features and **optional** for `bug`, `refactor`, and `chore` issues — small, scoped changes can skip it. ### The twelve roles Each role is a single responsibility with a single model class. Creative roles construct; adversarial roles attack; validators confirm; utility roles support. Dedicated reference pages for each role arrive in Phase 2 of this wiki. | Role | Phase | Class | Model / backend | Purpose | |------|-------|-------|-----------------|---------| | **Architect** | Plan | creative | Opus | Designs the implementation strategy — scope and rationale before code. | | **Auditor** | Plan | adversarial | External backend (endpoint required) | Challenges the plan before code exists: what is missing, vague, or will fail. | | **Curator** | Plan | validator | External validator → Gemini CLI fallback | Validates the audit — calibrates severity, catches false positives and missed gaps. | | **Builder** | Build | creative | Opus | Implements the approved plan in an isolated worktree and opens the PR. | | **Judge** | Build (review) | adversarial | External backend (endpoint required) | Chaos-engineers the diff — assumes a bug exists and asks how it fails. | | **Inspector** | Build (review) | validator | External validator → Gemini CLI fallback | Precision filter on the Judge — verifies edge cases and execution claims. | | **Doctor** | Build / QA (fix) | creative | Opus | Surgical fixes for failing verdicts — minimal change, no scope creep. | | **Lens** | QA | validator | External validator → Gemini CLI fallback | Frontend, visual, multimodal, and accessibility QA; parallel to Sentinel. | | **Sentinel** | QA | adversarial | External backend (endpoint required) | Backend integrity, security, performance, infrastructure; parallel to Lens. | | **Analyst** | Research | creative | Opus | Quantitative research synthesis — every claim has a number, source, and date. | | **Librarian** | Cross-phase | utility | Haiku | Indexes and retrieves project knowledge with source citations. | | **Classifier** | Intake | utility | Haiku | Classifies issue complexity (trivial / quick / standard) to route the pipeline. | That is four creative roles, three adversarial, three validators, and two utility — twelve in all. The Orchestrator (Claude Code itself) is not on the list: it directs the flow but never plans, builds, reviews, or merges. The **Model / backend** column answers the two questions the role list alone cannot. *Can I run jkz with just Opus?* No — the creative roles (Architect, Builder, Doctor, Analyst) are fixed on Opus, but the adversarial roles (Auditor, Judge, Sentinel) **require** a configured external endpoint, with no silent fallback that would let a review skip its challenger. *Which backend does Judge need?* An adversarial OpenAI-compatible endpoint set via `JKZ_JUDGE_ENDPOINT` / `JKZ_JUDGE_MODEL`. Validator roles (Curator, Inspector, Lens) are the forgiving ones: they default to an external validator endpoint and fall back to a local Gemini CLI when none is set. ### The multi-backend pattern Every phase follows the same rhythm: **Opus creates → an adversarial backend challenges → a validator backend confirms.** Diversity is the point — the model that wrote the work is not the model that signs off on it, so a single model's blind spot cannot pass unchallenged. Backends are configurable per role through environment variables (`JKZ__ENDPOINT`, `JKZ__MODEL`), so any OpenAI-compatible provider can fill an adversarial or validator seat. Adversarial roles **require** an endpoint — there is no silent fallback that would let a review quietly skip its challenger. Validator roles fall back to a local Gemini CLI when no endpoint is set. The full routing reference, including fallback tiers, lives in [Architecture](/reference/architecture/). ### Where the human comes in The pipeline is autonomous *between* checkpoints, never *through* them. There are three points where you decide: 1. **Post-plan ambiguity gate + plan approval.** An Opus scan classifies any ambiguity as `TRIVIAL`, `FIX`, or `DECIDE`; a `DECIDE` needs your call. Then you approve the plan before any build begins. 2. **Post-QA ambiguity gate.** The same scan runs again before approval, surfacing anything that needs a human decision after QA. 3. **The merge.** Only you merge to `main`. Merge stays human because prompts alone cannot enforce it — past incidents reached production through agent self-merge. So the gate is server-side, in four layers: | Layer | Mechanism | |-------|-----------| | `merge-gate.yml` | Sets a `pending` commit status on every PR. | | `approve-merge.yml` | A `workflow_dispatch` with a passphrase (a GitHub Secret) flips the status to `success`. Claude Code cannot read Secrets. | | `auto-revert.yml` | Detects any merge lacking `merge-gate=success` and reverts it automatically. | | `guard-destructive.sh` | Blocks the merge and approval commands locally. | The first three are server-side and cannot be bypassed from inside a session. That is the structural guarantee behind "you stay the final arbiter." ### What this is not - **Not zero-touch.** Two ambiguity gates and a human merge are deliberate. jkz optimizes for control, not for getting you out of the loop. - **Not the fast path for trivial fixes.** A typo does not need an Architect. Use [`/jkz:quick`](/build/lightweight-routes/) (Builder + Judge only) for small scoped changes — or just edit the file directly. - **Not free.** Every phase spends tokens across multiple models. The deliberation buys correctness and a verifiable trail; it is not cheaper than a single-shot edit. - **Not a group chat.** Agents never message each other. Git is the only source of truth — if a verdict is not a comment or a commit, it did not happen. ## Install & setup Source: https://docs.j0kz.dev/get-started/install/ This is the from-zero path: what you need installed, how to get jkz onto your machine, how to wire it into a project, and what to put in `.env`. If you just want to run a tiny change end-to-end, the [Quickstart](/get-started/quickstart/) is shorter — come back here when you want the full picture. ### Prerequisites jkz runs **inside Claude Code** — Claude Code is the orchestrator, not a dependency you can swap out. Everything else is a CLI it shells out to. #### Required | Tool | Min version | Why | | --- | --- | --- | | **Claude Code** | current | The orchestrator. Install with `npm install -g @anthropic-ai/claude-code` (or the desktop app from Anthropic). | | **git** | 2.30+ | Source of truth for every handoff. | | **gh** (GitHub CLI) | 2.0+ | jkz drives issues, labels, and PRs through GitHub. Authenticate with `gh auth login`. | | **node** | 18+ | Runs the wrappers, state helpers, and MCP server. | After installing `gh`, confirm you can read and write issues and pull requests on the repo you'll work against: ```bash gh auth status ``` #### Optional — model backend CLIs The adversarial and validator roles run on external backends. You can do a first run without them, but a complete pipeline expects at least an adversarial backend. | Tool | Roles enabled | Install | | --- | --- | --- | | **codex** (OpenAI Codex CLI) | Auditor, Judge, Sentinel | `npm install -g @openai/codex` | | **gemini** (Google Gemini CLI) | Curator, Inspector, Lens | `npm install -g @google/gemini-cli` | | **coderabbit** (CodeRabbit CLI) | Pre-scan enrichment | Install per the CodeRabbit CLI docs (Windows: requires WSL) | :::note[Missing a backend is a degraded run, not a failure] Without an adversarial backend, the review and security phases are skipped. Without a validator backend, the validation and Lens (frontend/visual) checks are skipped. The pipeline tells you which roles it dropped and lets you decide whether to continue — it does not silently pretend the check ran. ::: ### Install jkz jkz lives in a **private** repository, so every install path goes through your authenticated `gh` session. The classic `curl raw.githubusercontent.com … | bash` one-liner returns `404` for private repos — use the `gh api` form instead. #### Remote installer (recommended) ```bash # Fetches install.sh through your authenticated gh session gh api -H "Accept: application/vnd.github.raw" \ /repos/j0KZ/jkz_Multi-Agent_System/contents/install.sh | bash ``` This downloads jkz to `~/.jkz/`, compiles its dependencies, and adds `jkz` to your `PATH`. Reopen your terminal so the new `PATH` takes effect, then: ```bash jkz install # wizard: API keys, notifications, model/backend choices ``` #### From a cloned repo ```bash gh repo clone j0KZ/jkz_Multi-Agent_System # gh handles private-repo auth cd jkz_Multi-Agent_System npm link # global symlink to ./bin/jkz jkz install ``` Reverse the symlink with `npm unlink -g jkz-multi-agent-system`. #### Verify the install ```bash jkz version # prints the version jkz help # lists subcommands: install, init, docker, uninstall, update, version ``` :::caution[Windows] Use **Git Bash**, not native PowerShell. Both install paths work identically under Git Bash. If `jkz` is not found after `npm link`, close and reopen the terminal so the `.cmd`/`.ps1` shims are picked up. ::: ### Standalone vs plugin There are two ways to use jkz, and the difference is *where the runtime lives*. **Standalone** — you work directly inside the cloned `jkz_Multi-Agent_System` repo. The scripts, agents, and state all live in one place. This is the right choice when you're developing jkz itself or trying it out. **Plugin** — you install jkz *into another project* so that repo gets the full pipeline (`/jkz:*` commands, merge-gate workflows, local `state/`). From the target project, or from anywhere once `jkz` is on your `PATH`: ```bash jkz init [dir] # default: current directory ``` `jkz init` generates the plugin entrypoints, the GitHub workflows that enforce the merge gate, and a local `state/` directory for pipeline bookkeeping. This uses a **dual-root** layout — shared code in one place, per-project state in another: - **`JKZ_HOME`** (`~/.jkz/`) — scripts, agents, hooks, MCP server. Shared across every project you install the plugin into. - **`JKZ_TARGET_PROJECT`** (the target dir) — `state/`, deliberations, `.env`, and the merge-gate workflows. One per project. Each command reads `state/.jkz-plugin-env` at startup to resolve these roots, so you don't set them by hand. Remove the plugin from a project with `jkz uninstall [dir]` — it strips the generated artifacts but preserves your `state/`, `.env`, and workflows. ### Configure (`.env`) Copy the example and edit it: ```bash cp .env.example .env ``` The defaults are sane; the values you're most likely to touch are the model IDs for the external backends. ```bash JKZ_GEMINI_MODEL=gemini-3.5-flash JKZ_GEMINI_MODEL_FALLBACK=gemini-3.5-flash JKZ_CODEX_MODEL=gpt-5.4 JKZ_CODEX_MODEL_FALLBACK=gpt-5.3-codex ``` If a primary model returns `404` (model not found), the wrappers retry with the fallback automatically — a warning goes to stderr and the run continues. You can override any role individually; the lookup cascades from the role-specific var to the backend default: ```bash # Judge uses a distinct model; everything else still uses the Codex default. JKZ_JUDGE_MODEL=gpt-4.1-codex # Cascade: JKZ_JUDGE_MODEL → JKZ_CODEX_MODEL → built-in default ``` :::note[Role names are shell identifiers] A per-role variable name must match `^[a-z0-9][a-z0-9_]*$` — no hyphens, since they're invalid in shell variable names. See `.env.example` for the complete cascade, including the shared API-backend vars (`JKZ_API_ENDPOINT`, `JKZ_API_MODEL`, `JKZ_API_KEY`) for any OpenAI-compatible endpoint. ::: #### The merge gate (required) jkz never merges for you. A server-side GitHub Actions workflow refuses to merge a PR without a passphrase that Claude Code cannot read. Set it once per repo: ```bash gh secret set MERGE_PASSPHRASE ``` When a PR is approved, you merge it from your own terminal: ```bash gh workflow run approve-merge.yml -f pr= -f passphrase= ``` This is the core safety guarantee — even a session running with `--permission-mode bypassPermissions`, which skips client-side guard hooks, cannot push to `main`, because the gate lives on the server. ### First run — verify everything works From inside Claude Code, the fastest check is the health command: ```text /jkz:health ``` ```text === jkz Health === [OK] Claude Code CLI 2.1.x [OK] gh CLI authenticated [OK] Node.js 22.x [OK] Plugin commands loaded (/jkz:* available) [WARN] Some CLIs have updates available === Ready === ``` `/jkz:health --fix` updates outdated CLIs; `--deep` also checks auth, MCP, and notifications. If you prefer the shell, the same checks run standalone: ```bash node scripts/run.js health-check.sh ``` A clean install exits `0` with zero critical issues. Warnings about optional CLIs (`codex`, `gemini`) are informational — those roles won't run, but the rest of the pipeline still works. ### Next steps - [Quickstart](/get-started/quickstart/) — install to first merged PR, end to end. - [Why jkz?](/get-started/why-jkz/) — the problem it solves and the constraints behind the design. - [How jkz works](/get-started/how-jkz-works/) — the three phases, the twelve roles, and the deliberation loop. - [Architecture](/reference/architecture/) — phase boundaries, roles, and model routing for the full picture. ## Quickstart Source: https://docs.j0kz.dev/get-started/quickstart/ This is the shortest honest path from "I just installed jkz" to "I shipped a small change through the full pipeline and merged it myself." It takes a few focused minutes of your time plus some waiting while the agents deliberate. Pick a tiny, low-risk change for your first run — the point is to see the pipeline in action, not to ship something important. :::note[About the outputs below] Command outputs are **illustrative**. jkz wraps live models and external backends, so exact wording, token counts, and timings drift from run to run. The *shape* (which agent speaks, in what order, and what gates you hit) is stable. Treat the snippets as "what you'll roughly see," not byte-for-byte transcripts. ::: ### Prerequisites Three things, honestly: - **Claude Code CLI**, signed in. jkz runs as a plugin inside Claude Code — it is the orchestrator. - **`gh` (GitHub CLI), authenticated.** Run `gh auth status` and confirm you can read and write issues and pull requests on the repo you'll test against. The whole pipeline uses GitHub as its source of truth: issues, labels, PR comments. - **A repo you can safely open a throwaway PR against.** Your own sandbox repo is ideal. You need push access and the ability to merge. You do **not** need every external backend configured to do a first run, but a complete pipeline expects an adversarial backend (for the Auditor, Judge, and Sentinel roles). Without one, those reviews are skipped and the system tells you so — that's a degraded run, not a failure. ### Install and set up jkz Install once, globally: ```bash curl -fsSL https://raw.githubusercontent.com/j0KZ/jkz_Multi-Agent_System/main/install.sh | bash ``` Reopen your terminal so `jkz` is on your `PATH`, then run the setup wizard and drop the plugin into your project: ```bash jkz install # wizard: API keys, notifications, model/backend choices jkz init # installs the plugin into the current directory ``` `jkz init` generates the plugin entrypoints, the GitHub workflows that enforce the merge gate, and a local `state/` directory for pipeline bookkeeping. Verify the install from inside Claude Code: ```text /jkz:health ``` ```text === jkz Health === [OK] Claude Code CLI 2.1.x [OK] gh CLI authenticated [OK] Node.js 22.x [OK] Plugin commands loaded (/jkz:* available) [WARN] Some CLIs have updates available === Ready === ``` If `/jkz:health` reports the commands are loaded and `gh` is authenticated, you're ready. (`/jkz:health --fix` updates outdated CLIs; `--deep` also checks auth, MCP, and notifications.) ### Step 1 — Pick a small issue Choose something genuinely small and reversible. Good first targets: - Fix a typo in a README or doc comment. - Add a missing `alt` attribute to one image. - Rename a single flag or constant for clarity. The smaller the change, the faster every phase runs and the cheaper the model calls. Save the ambitious refactor for after you trust the loop. ### Step 2 — Describe it with `/jkz:start` `/jkz:start` is the conversational front door. Run it with no arguments; it asks what you want to do, then does the thinking: ```text /jkz:start ``` ```text > Describe what you want to do. It can be a vague idea, a bug, a feature. you: the footer logo is missing alt text, screen readers skip it [triage] complexity: quick confidence: high [duplicates] no open jkz:ready issue matches — creating a new one [brief] type: chore · scope: 1 file · adds alt="jkz logo" to footer image Created issue #128 — chore: add alt text to footer logo Recommended: /jkz:quick 128 (small, scoped — lightweight pipeline) ``` The orchestrator triages the idea (trivial / quick / standard), checks for a duplicate open issue, writes a short brief, creates the GitHub issue with the right type and complexity labels, and recommends a route. Trivial things it offers to just fix inline — no issue, no ceremony. For this walkthrough we'll take the **full** pipeline so you see every phase, even though a one-line change would normally route to `/jkz:quick`. ### Step 3 — Run the pipeline ```text /jkz:pipeline 128 ``` `/jkz:pipeline` runs all three phases autonomously and pauses at exactly two human checkpoints: **plan approval** and **merge**. Everything between them is the agents working and checking each other. ```text PLAN jkz:architect drafting plan… 1 file, add alt attribute jkz:auditor challenge: confirm alt text is descriptive, not just "logo" jkz:curator PASS — plan is minimal and correct >>> CHECKPOINT 1: approve the plan? [the plan is printed in full here] ``` This is your first decision. The plan is the artifact under review, so it's shown in full — read it, then approve (or send it back for another iteration; planning loops up to three times on its own). Approve, and the build phase starts: ```text BUILD jkz:builder opened PR #129 — chore: add alt text to footer logo (Closes #128) coderabbit pre-scan: 0 actionable findings jkz:judge PASS — diff matches the approved plan, alt text is descriptive jkz:inspector PASS — change verified, no regressions QA jkz:lens PASS — renders correctly, accessibility check passes jkz:sentinel PASS — no security or operational concerns >>> CHECKPOINT 2: PR #129 is approved and ready for merge. ``` If a reviewer returns **FAIL**, you don't have to do anything: the Doctor role applies a fix and the phase re-runs, up to three times. If it still can't get a clean pass, the pipeline stops at `jkz:blocked` and escalates to you with an honest diagnosis rather than forcing a fix that hides the problem. A realistic heads-up on **time and cost**: a standard pipeline makes several model calls per phase across multiple roles, so a full run takes minutes, not seconds, and the external backends bill per call. The smaller your change, the less of both. jkz posts a cost breakdown comment on the PR so you can see what a run actually cost. ### Step 4 — The human checkpoint and merge jkz never merges for you. That's the core promise: the system iterates, but the last step is always yours. When the PR is approved, merge it through the gate: ```bash gh workflow run approve-merge.yml -f pr=129 -f passphrase= ``` The merge gate is a server-side workflow that refuses to merge without your passphrase — so even a misbehaving agent or a stray command cannot push to `main`. Run the command, the workflow verifies the passphrase, and the PR merges. The issue closes automatically via the `Closes #128` keyword in the PR body. ### What just happened - You described an idea in plain language; `/jkz:start` turned it into a labeled, scoped GitHub issue. - `/jkz:pipeline` drove it through **plan → build → QA**, with an adversarial backend trying to break the work and a validator confirming at each phase. - Every handoff happened through GitHub — the PR, its comments, and labels are the full audit trail. Agents never talked to each other directly. - The system was allowed to iterate and self-correct up to three times per phase, but it stopped and asked **you** at the two decisions that matter: approving the plan and authorizing the merge. - Nothing reached `main` without your passphrase through the merge gate. ### Next steps - [Why jkz?](/get-started/why-jkz/) — the problem it solves and the constraints behind the design. - [How jkz works](/get-started/how-jkz-works/) — the three phases, the twelve roles, and the deliberation loop in detail. - [Run a pipeline](/build/run-a-pipeline/) — the day-to-day once you know the shape. - [Architecture](/reference/architecture/) — phase boundaries, roles, and model routing for the full picture. Stuck? `/jkz:status` shows where any issue is in the pipeline, and `/jkz:resume` picks a stalled run back up from where it left off. ## Why jkz? Source: https://docs.j0kz.dev/get-started/why-jkz/ ### The problem Most agentic coding tools optimize for a single property: throughput. One model reads a task, writes code, and reports success. It feels fast because nothing slows it down — not a second opinion, not a test of its own reasoning, not a human who has to agree. The cost is hidden until it isn't. A single agent fails silently: it asserts that a change works, the assertion is plausible, and the error surfaces three commits later, when it is expensive to trace. The two popular escapes both make this worse. Generating code without review compounds errors — each unreviewed change becomes the foundation the next one is built on. Handing the agent full autonomy removes the one thing that made the output trustworthy: an accountable human who decided to ship it. Speed without review is just debt that hasn't been invoiced yet. ### The shape of the answer jkz is built on a different bet: that an explicit, adversarial pipeline with a human at the end produces code you can actually trust, and that the overhead is worth it for work that matters. The pipeline has three phases (**Plan**, **Build**, and **QA**), with a fixed rhythm inside each: one model proposes, a different model challenges it adversarially, and a third confirms the result. Roles are specialized and named. They never negotiate directly; everything they produce flows through the pull request, which is the only place state lives. At the end of every phase, a human reads the result. For the mechanics (the roles, the phase boundaries, the deliberation loop), see [How jkz works](/get-started/how-jkz-works/). ### What jkz commits to These are opinions, not features. They constrain the system on purpose: - **You merge.** The pipeline iterates internally (up to three times per phase), but it never merges on its own. The final decision to ship is always a human's. This is enforced, not merely encouraged. - **Git is the source of truth.** Agents do not message each other. Every plan, critique, and fix is a commit or a PR comment, so the full reasoning trail is auditable after the fact. - **One role, one verb, one owner.** There is never ambiguity about which agent did what, or which model is responsible for a given step. Diffuse accountability is how silent failures hide. - **Shift left.** Errors are caught by the adversarial and validator roles before they reach the human checkpoint. The human arbitrates judgment calls, not typos. ### What jkz does not promise An honest pitch names its costs: - **It is not zero-touch.** A human checkpoint at each phase is the design, not a limitation to be removed later. If you want to walk away and return to merged code, this is the wrong tool. - **It is not faster on trivial work.** For a one-line fix, the full adversarial loop is pure overhead. jkz ships `/jkz:quick` precisely so small changes can skip Plan and QA — but a single-agent loop will still beat it on the truly trivial. - **It costs more in tokens.** Three models per step is more expensive than one. Adversarial review is not free, and jkz does not pretend otherwise. You are buying a higher floor on correctness, and you pay for it. ### When to use jkz — and when not to Reach for jkz when the cost of a silent error is high: features with real surface area, changes touching security-sensitive code, refactors where "it still behaves the same" is the entire point, or any work where you want a defensible record of why each decision was made. The adversarial loop pays off exactly when a mistake would be expensive to discover later. Skip it (or use `/jkz:quick`) when the change is small and self-evidently correct: a typo, a config bump, a one-line fix you could review in the time it takes to read this sentence. Running the full pipeline there buys nothing but latency and tokens. The honest summary: jkz trades speed and token cost for a correctness floor and an audit trail, with a human as the final arbiter. If that trade fits the work in front of you, start with the [Quickstart](/get-started/quickstart/). ## Ambiguity gate Source: https://docs.j0kz.dev/concepts/ambiguity-gate/ A pipeline that resolves every ambiguity by itself will, sooner or later, confidently build the wrong thing. The ambiguity gate exists to catch the moments where a decision belongs to you, not to a model — and to let everything else flow through untouched. It is a scan, not a wall: most ambiguities pass straight through, and only the ones that genuinely need a human stop the line. ### Two inline checkpoints The gate runs twice, at the two seams where a wrong assumption would be most expensive to carry forward: 1. **Post-plan** — after the plan is drafted, before any code is built. An assumption baked into the plan here would propagate through the entire build. 2. **Post-QA** — after QA completes, before the work is handed to you for the final merge decision. This is the last scan before the human checkpoint. At each point an Opus scan reads the work in context and classifies whatever ambiguity it finds. The checkpoints are *inline* — they are part of the phase transition, not a separate command you run. You see them as part of [the pipeline's](/concepts/pipeline/) flow between phases. ### TRIVIAL, FIX, DECIDE Every ambiguity the scan surfaces is sorted into one of three classes, and the class determines what happens next: | Class | Meaning | Action | |-------|---------|--------| | **TRIVIAL** | A non-decision — wording, a detail with one obvious reading | Noted, pipeline continues | | **FIX** | An ambiguity the pipeline can resolve itself, correctly | Resolved inline, pipeline continues | | **DECIDE** | A genuine fork where the choice is yours to make | **Stops — requires a human decision** | The line that matters is between FIX and DECIDE. A FIX is something with a defensible right answer the pipeline can pick on its own. A DECIDE is a fork where reasonable choices diverge and the consequences are yours to own — a product trade-off, a scope boundary, an irreversible call. The gate does not guess on a DECIDE. It surfaces the fork and waits for you. ### Fail-open by design The gate is **fail-open**: if the scan itself errors or cannot run, the pipeline continues rather than blocking. This is deliberate. The ambiguity gate is a safety net for decisions, not a correctness gate — those are the adversarial reviews and [the merge gate](/concepts/merge-gate/), which fail *closed*. An infrastructure hiccup in an advisory scan should not wedge a pipeline that is otherwise healthy. The trade-off is honest: a failed scan means a DECIDE-class ambiguity might slip past unflagged. That residual risk is acceptable precisely because the gate is one of several human checkpoints, not the only one. You still approve the plan, and you still perform the merge — a missed flag narrows the safety margin, it does not open the door to `main`. ### What this is not - **Not a quality gate.** The ambiguity gate decides *who chooses*, not *whether the code is correct*. Correctness is enforced by the adversarial reviews under the [evidence hierarchy](/concepts/evidence-hierarchy/). - **Not a blocking wall by default.** Only a DECIDE stops the line. TRIVIAL and FIX pass through, and a scan failure passes through too. - **Not the only human checkpoint.** It complements the plan approval and the human merge — three separate decisions, not one. ### Related - [The pipeline](/concepts/pipeline/) — the phase transitions where the two checkpoints are wired in. - [Merge gate](/concepts/merge-gate/) — the other gate between you and `main`, and the one that fails *closed*. - [Evidence hierarchy](/concepts/evidence-hierarchy/) — how the pipeline keeps its autonomous decisions honest where the ambiguity gate keeps the human ones human. ## Context management Source: https://docs.j0kz.dev/concepts/context-management/ A pipeline that runs for an hour across a dozen roles generates far more text than a context window can hold. jkz manages this on three fronts: it snapshots critical state *before* the conversation is compacted so nothing is lost, it compresses bulky context sections while protecting the parts that matter, and it truncates oversized model output intelligently rather than blindly cutting from the end. The common thread is that compaction is treated as expected, not exceptional — and the irreplaceable signals are guarded at every step. ### Snapshotting before compaction Claude Code compacts a long conversation to stay within its window. The risk is that an active pipeline's state could be summarized away. jkz defends against this with a PreCompact hook: just before a compaction happens, it writes a JSON snapshot of the pipeline state to a timestamped file under `state/`, so an in-progress run can be recovered afterward. ```text state/pre-compact--.json ``` The snapshot captures the event and the full pipeline state at that moment. The same hook also nudges the session-memory record forward. These files are cleaned up automatically after about a week, so they accumulate during active work and disappear once they are no longer useful. There is a deliberate contract for what survives a compaction. The things that are always preserved are the decision-critical ones: the approved plan, the current pipeline phase and iteration, active agent verdicts, any pending human-decision items, the git state, and the failure context for the current fix cycle. The things safe to drop are the bulky-but-recoverable ones: file contents already committed, intermediate search results, verbose tool output, and resolved review findings. ### Compressing context sections Some context blocks are simply large — a long diff, an accumulated set of patterns. `compress-context.js` shrinks these, but it never compresses blindly. It recognizes the section structure of the context and protects the blocks that carry irreplaceable signal: - `verdict-json` decisions - TL;DR summaries - Accumulated Patterns - compact-plan and plan-digest blocks Everything else is fair game for compression. When a section exceeds its threshold, the tool can offload the full content to disk (under `state/context-offload/`) and keep only a head excerpt inline, so the detail is still retrievable without sitting in the live window. ### Smart truncation of wrapper output The external backends can return very large responses, and feeding all of it into the orchestrator's context would be wasteful. Wrapper stdout is therefore piped through `truncate-output.js`, which caps the size while preserving the parts a verdict actually depends on. The size cap adapts to the situation: | Mode | Default cap | |------|-------------| | Primary | 300 KB | | Fallback model | 100 KB | | Agent mode | 80 KB | Any of these can be overridden with the `JKZ_MAX_OUTPUT_BYTES` environment variable (where `0` disables truncation entirely). Two things make the truncation *smart* rather than crude. First, it extracts and re-inserts the protected blocks (the verdict, the compact-plan, the TL;DR, the Accumulated Patterns) so they survive even when the surrounding prose is cut. Second, when it does have to cut, it keeps a head *and* a tail rather than just lopping off the end, because the conclusion of a review is often as important as its opening. The head/tail split is role-aware: a security reviewer whose conclusions land at the end keeps more of its tail, while a role with front-loaded findings keeps more of its head. One important exception: the full, untruncated output is always preserved where fidelity matters — the complete deliberation record and the PR comment receive the unabridged text. Truncation protects the *live context window*, not the audit trail. ### See also - [Pipeline](/concepts/pipeline/) — the long-running flow this keeps inside the window - [Signal format](/concepts/signal-format/) — the verdict blocks that truncation protects - [Cross-chat](/concepts/cross-chat/) — recovering and sharing state across sessions ## Cross-chat awareness Source: https://docs.j0kz.dev/concepts/cross-chat/ You will often have more than one Claude Code chat open on this project at once — one planning an issue, another fixing a PR, a third just exploring. They share a filesystem and a git repo, so without coordination two sessions could start the same issue, edit the same files, or delete each other's worktrees. Cross-chat awareness is the lightweight registry that stops that. The model is simple: **before a session touches an issue, it asks whether another session already owns it.** ### The chat registry Every session writes a small record under `state/active-chats/` describing what it is working on. `chat-registry.js` manages those records: | Command | What it does | |---------|--------------| | `register` | Adds this session to the registry (pid, branch, issue, description). | | `heartbeat` | Refreshes this session's timestamp — and updates the issue/worktree it owns. | | `check-issue --issue N` | Asks whether another session already owns issue `#N`. | | `is-worktree-active --path P` | Tells cleanup whether a worktree is still in live use. | | `list` | Shows all active sessions and their age. | | `deregister` | Removes this session on shutdown. | Records are written atomically (write-to-temp, then rename) so two sessions updating the registry at the same moment never corrupt it. A record goes **stale after five minutes** without a heartbeat — a session that crashed or was closed stops counting as active, and its issues and worktrees free up. Session identity resolves in order: an explicit `--session` argument, then the `CLAUDE_SESSION_ID` environment variable, then an ancestor-PID lookup, then an unstable fallback. The practical upshot: keep `CLAUDE_SESSION_ID` set, because when it is unset the snapshot and ownership logic can key everything to `anonymous` and lose the per-chat distinction. ### The contested-issue stop Before running a pipeline command on an issue, jkz checks ownership: ```bash node scripts/chat-registry.js check-issue --issue --session "$CLAUDE_SESSION_ID" ``` If that returns **exit code 1**, another chat is already working on issue `#N`. The rule is hard: **stop and warn the user — never edit on a contested issue.** The pipeline commands (`/jkz:plan`, `/jkz:build`, `/jkz:qa`, `/jkz:pipeline`, `/jkz:quick`) run this check automatically as they enter the issue worktree, so the protection is built in. A manual check is only needed for ad-hoc work outside the pipeline. ### File-conflict awareness Ownership is per-issue, but caution is per-file. If the session-start banner shows other active chats, be deliberate about editing files the other session might also be touching. The registry tells you a collision is *possible*; judgment closes the gap. When in doubt, surface the potential conflict rather than racing. ### Heartbeats and worktree cleanup The heartbeat does double duty. It keeps a session alive in the registry, and it is the signal the worktree cleanup consults before deleting anything. `is-worktree-active` is how `worktree.sh cleanup-merged` decides a merged worktree is still in use: a fresh heartbeat referencing that worktree path means "leave it alone." This is the link between the two concepts — cross-chat heartbeats are one of the safety rails that keep [worktree cleanup](/concepts/worktree-isolation/) from removing live work. ### Session snapshots When you switch chats (or come back tomorrow), context should travel with you. Snapshots make that possible. They are stored per-chat in `state/session-snapshots/.json` and capture more than git state: completed work, decisions made, and gotchas worth carrying forward. - `/jkz:save` captures a rich snapshot of the current session. - `/jkz:load` retrieves the most recent snapshot — including one left by *another* session — so a fresh chat can pick up where the last left off. - `/jkz:quit` runs `/jkz:save` and then deregisters the session cleanly. Orphan snapshots (more than 24 hours old with no active chat behind them) are cleaned up on session start, so the store does not grow without bound. ### What this is not - **Not a lock manager.** The registry advises; it does not forcibly prevent a second session from editing. It gives you the information to avoid a collision, and the pipeline commands act on it — but the discipline of stopping on a contested issue is part of the contract. - **Not durable across crashes by itself.** A five-minute stale window means a crashed session releases its claims automatically. That is a feature for recovery, but it means "owned" is a live signal, not a permanent reservation. ### Related - [Worktree isolation](/concepts/worktree-isolation/) — the worktrees whose liveness heartbeats protect. - [Merge gate](/concepts/merge-gate/) — the final human checkpoint that concurrent sessions all converge on. - [How jkz works](/get-started/how-jkz-works/) — the pipeline these sessions are each running. ## Evidence hierarchy Source: https://docs.j0kz.dev/concepts/evidence-hierarchy/ When a jkz agent says a change is correct, the question that matters is not *how confident is it* but *what is the claim made of*. A model can argue persuasively for a wrong answer. So jkz ranks evidence, and the adversarial roles are forbidden from approving on the weakest kind. Confidence is not evidence. A reason is not a result. ### The three levels Every claim an agent makes is one of three kinds, ranked by how hard it is to fake: 1. **Execution** — the output of actually running something: a test result, a command's stdout, a screenshot. The code was run and *this* is what happened. 2. **File citations** — a verbatim quote from a repository file at a specific line: `file.ts:42` with the relevant fragment. The claim points at code that demonstrably exists. 3. **Reasoning** — a logical argument with no direct evidence behind it. "This should work because…" is level 3, however sound the logic sounds. The order is the whole point. Execution beats citation beats reasoning, because each level is harder to produce without the underlying fact being true. You can reason your way to a wrong conclusion effortlessly; you cannot paste passing test output for code that fails. ### Why adversarial roles require level 1 or 2 The adversarial roles (**Auditor** in Plan, **Judge** in Build, **Sentinel** in QA) exist to break the work, and their verdicts gate the pipeline. So their verdicts carry a strict rule: **reasoning alone is never sufficient for approval.** An adversarial PASS must rest on level 1 or level 2 evidence. If the only thing supporting a claim is an argument, the claim does not clear the gate. This is what makes the [create → challenge → confirm rhythm](/concepts/pipeline/) more than theatre. The challenger is not asked whether the work *seems* right; it is asked to show, by execution or citation, that it *is*. A validator then checks that the evidence is real and on point. The discipline is what lets the pipeline iterate autonomously without quietly approving plausible-but-wrong work. ### The gotchas Level 3 evidence often arrives wearing a level 1 costume. These are the disguises the validator roles are trained to strip away: - **"I ran it and it works" — with no output.** Claiming execution is not execution. Without the concrete result pasted in — the stdout, the test summary, the screenshot — the claim is reasoning, level 3. Execution evidence requires the execution's actual output. - **A citation from the wrong file.** Quoting code that is not in the PR diff proves nothing about the change under review. The citation must come from modified or directly affected code; an unrelated file is not evidence about *this* change. - **A citation without a line.** Naming `file.ts` is not a level 2 citation. Level 2 requires `file.ts:line` together with the relevant textual fragment — enough that a reviewer can open the file and see the same thing. Each of these collapses to level 3 once examined. The hierarchy is not just a ranking; it is a checklist for catching arguments that are pretending to be facts. ### What this is not - **Not a confidence score.** A high-confidence reason is still level 3. The hierarchy ranks the *kind* of evidence, not how sure the agent sounds. - **Not applied only to approvals.** A FAIL verdict is held to the same standard — a claim that something is broken should cite the failing output or the offending line, not just assert it. - **Not a substitute for human review.** The hierarchy strengthens the adversarial gates; it does not replace the human checkpoints that still sit between the phases. ### Related - [The pipeline](/concepts/pipeline/) — where the adversarial roles sit and why their verdicts gate each phase. - [How jkz works](/get-started/how-jkz-works/) — the full role catalogue, including the Auditor, Judge, and Sentinel. - [Ambiguity gate](/concepts/ambiguity-gate/) — the other discipline that protects the pipeline's autonomy: surfacing decisions a model should not make alone. ## Fallback Source: https://docs.j0kz.dev/concepts/fallback/ A multi-backend pipeline has more moving parts than a single-model one, and any of them can fail: a model name can 404, an endpoint can rate-limit you, a whole backend can go dark. jkz draws a sharp line between failures it can recover from on its own and failures that need a human in the loop. The first kind retries silently; the second kind stops and asks you. ### Model fallback (automatic) The smallest failure is a model that simply is not there — a renamed or retired model name returns `404 / ModelNotFound`. The wrappers handle this without involving you: each role has a configured fallback model, and the wrapper retries against it. - **Gemini:** `JKZ_GEMINI_MODEL` → `JKZ_GEMINI_MODEL_FALLBACK` - **API (OpenAI-compatible):** `JKZ_API_MODEL` → `JKZ_API_MODEL_FALLBACK`, with a per-role override `JKZ__MODEL_FALLBACK` This is a straight swap of one model for another. Nothing about the pipeline's control flow changes — you get a verdict from the fallback model instead of the primary one. ### Rate-limit fallback (cascade) A busier failure is rate limiting: `429 / RESOURCE_EXHAUSTED`. Here the wrapper first retries with exponential backoff, and only when that budget is exhausted does it escalate through a two-tier cascade. Each layer stamps the completion record with which path served the verdict, so you can always audit how an answer was produced. #### Tier 3 — an OpenAI-compatible provider For validator roles, the first escalation is a different OpenAI-compatible endpoint. If one is configured for the role (or globally), the wrapper dispatches a single attempt there. On success the verdict is propagated verbatim and the run is marked as having used the API tier. On failure (or if no such endpoint is configured), it falls through to the next tier. #### Tier 4 — the in-session model If tier 3 does not rescue the call, the wrapper hands the work back to the orchestrator's own model. The command detects the fallback signal, resolves which model to use, and re-runs the role's analysis in-session. This is the last automatic layer: it keeps the phase moving even when every external backend is throttled. Throughout the cascade, two distinct facts are recorded and should not be confused: - which **tier** fired (an external API endpoint, or the in-session model), and - which **model** the in-session tier dispatched to. The first tells you *which layer* recovered the call; the second tells you *what produced* the answer when the in-session tier was the one that did. ### Service fallback (manual) The largest failures are not a single call going wrong — they are a whole backend being unavailable. These are not recovered silently, because the right response depends on judgment you have and the pipeline does not. The system notifies you and waits for your decision. | Backend down | Behavior | |--------------|----------| | **Opus** (the creative roles) | The pipeline stops. No other agent writes code in its place. The system notifies you and waits. | | **Adversarial backend** (Auditor, Judge, Sentinel) | Review and the security pass are skipped. The system notifies you; you decide whether to continue without them. | | **Validator backend** (Curator, Inspector, Lens) | The validation frontend is skipped. The system notifies you; you decide. | | **Claude Code** (the orchestrator) | Everything stops — it *is* the runtime that drives every other role. | The pattern is deliberate. Recoverable failures (a missing model, a rate limit) are handled where they happen, invisibly. A backend outage is a quality-of-evidence question: running the pipeline without its adversarial reviewer is a real trade-off, so the system surfaces it and leaves the call to you rather than quietly degrading. ### See also - [Pipeline](/concepts/pipeline/) — the phases the fallbacks protect - [Evidence hierarchy](/concepts/evidence-hierarchy/) — why skipping a reviewer is a real trade-off - [Merge gate](/concepts/merge-gate/) — the human checkpoint at the end of every run ## Issue types Source: https://docs.j0kz.dev/concepts/issue-types/ Not all work is the same shape. Adding a feature, fixing a bug, restructuring code, and bumping a dependency each call for a different kind of attention — so jkz tags every issue with one of four types and lets that tag steer the pipeline. The type is not cosmetic: it changes what the Architect plans for, what the reviewers look hardest at, and whether the QA phase runs at all. ### The four types | Type | Label | Plan focus | Review focus | QA | |------|-------|-----------|--------------|-----| | `feature` | *(none)* | Implementation design | Code quality | Required | | `bug` | `bug` | Root cause analysis | Fix correctness | Optional | | `refactor` | `refactor` | Current → target state | Behavior preserved | Optional | | `chore` | `chore` | Mechanical change | No behavior shift | Optional | A `feature` is new behavior, so the plan is about *design* and the review is about *quality* — and because new behavior can break in ways nothing else catches, QA is mandatory. A `bug` flips the emphasis to *root cause*: a fix that treats the symptom without naming the cause is the most common way a bug comes back. A `refactor` is judged against a single promise (behavior is preserved): the plan frames the work as a move from a current state to a target state, and the review checks that nothing observable changed. A `chore` (a dependency bump, a config tweak, a mechanical rename) should shift no behavior at all, so both plan and review stay deliberately minimal. ### QA is required only for features The most consequential difference is the last column. QA runs the deep adversarial and validation pass — and it is **required** for `feature` work but **optional** for `bug`, `refactor`, and `chore`. The reasoning is proportionality: a one-line dependency bump does not warrant the same scrutiny as a new subsystem. You can still opt a bug or refactor into QA when the change earns it; the default just stops the pipeline from over-spending on low-risk work. ### How the type is detected When an issue is created through `/jkz:start`, jkz asks for the type and sets the matching label. From then on, every command resolves the type through a short cascade, taking the first answer it finds: 1. **Pipeline state** — the persisted `issue_type` from a run already in progress. 2. **Label** — `bug`, `refactor`, or `chore` on the GitHub issue. 3. **Default** — `feature`, when nothing else says otherwise. Note that `feature` has no label of its own. Its absence *is* the signal: an issue with none of the three type labels is treated as a feature. The resolved type is persisted in the pipeline state file (`state/pipeline/.json`) under `issue_type`, so later phases agree with earlier ones. ### What the type actually changes The type is not just metadata sitting on the issue — it is injected into the agents' prompts. A type-specific block is appended to the Architect, Builder, Judge, and Inspector prompts depending on the resolved type, the same mechanism used for conditional security analysis. So a `bug` issue literally tells the Architect to lead with root-cause analysis and tells the Judge to weigh fix correctness above stylistic concerns. The label you set at creation time propagates all the way down to how each model is briefed. ### See also - [Pipeline](/concepts/pipeline/) — the three phases each type flows through - [Ambiguity gate](/concepts/ambiguity-gate/) — the human-decision checkpoints - [Merge gate](/concepts/merge-gate/) — why only a human merges, regardless of type ## Merge gate Source: https://docs.j0kz.dev/concepts/merge-gate/ The single hardest rule in jkz is also the simplest to state: **only a human merges to `main`.** The pipeline iterates on its own up to three times per phase, but it cannot reach `main` — you do that, and only you. This is not a guideline the agents are politely asked to follow. It is enforced in four layers, and three of them live on the server where no session can switch them off. ### Why prompts are not enough A prompt that says "never merge" is a request, and a sufficiently determined or misconfigured agent can route around a request. This rule exists because past incidents reached production through agent self-merge. So the gate does not rely on the agent's good behavior. It relies on infrastructure the agent cannot reach: a commit status only a GitHub Secret can flip, and a workflow that reverts anything that slips through. ### The four layers | Layer | Mechanism | Bypassable? | |-------|-----------|-------------| | `merge-gate.yml` | Sets the commit status to `pending` on every PR. | No — server-side | | `approve-merge.yml` | A `workflow_dispatch` with a passphrase (`MERGE_PASSPHRASE`, a GitHub Secret) flips the status to `success`. | No — Claude Code cannot read GitHub Secrets | | `auto-revert.yml` | Detects any merge lacking `merge-gate=success` and reverts it automatically (~30s). | No — server-side | | `guard-destructive.sh` | Blocks `gh pr merge`, `gh workflow run approve-merge`, and direct `gh api .../statuses/` calls locally. | Yes, only under `bypassPermissions` — which is precisely why layers 1–3 exist | The design is deliberately redundant. The local guard (`guard-destructive.sh`) is the friendly first line — it stops the obvious commands inside a session. But because a session run with `--permission-mode bypassPermissions` could disable that guard, the real guarantee is the three server-side layers. The PR sits at `pending` until the passphrase flips it; if something forces a merge anyway, `auto-revert.yml` undoes it within about half a minute. There is no single point you can disable to let an agent merge. ### The passphrase checkpoint The only way to reach `success` is to run the approval workflow with the right passphrase — and the passphrase is a GitHub Secret, which Claude Code cannot read. That asymmetry is the whole mechanism: the agent can prepare everything up to the merge, but the act that authorizes it requires a value only you hold. ```bash # 1. Approve — run this from the terminal, not from Claude Code gh workflow run approve-merge.yml -f pr= -f passphrase= # 2. Merge from the PR button on GitHub, or: gh pr merge ``` `scripts/check-merge-gate.sh --pr ` queries the gate status for a PR by its head SHA, and that check is surfaced in `/jkz:status` so you can see at a glance whether a PR is still `pending` or has been approved. ### The CodeRabbit pre-flight gate The merge gate decides *whether* a merge is authorized. A separate, earlier gate decides whether a PR is even allowed to reach the `jkz:approved` state in the first place. `cr-preflight-gate.sh` blocks the transition to `jkz:approved` while CodeRabbit review threads remain **unresolved without either a human reply or commit coverage**. Its exit codes are explicit: | Exit | Meaning | |------|---------| | `0` | All CR threads have a reply or coverage — or there are no unresolved threads | | `1` | Blocked — one or more unresolved threads with neither reply nor coverage | | `2` | Fail-open — a GraphQL/API infra error; the caller continues with a `WARN` | | `3` | Bad arguments | The fail-open behavior on exit `2` is intentional: an infrastructure hiccup talking to GitHub should not wedge the pipeline, so the caller logs a warning and proceeds. The gate can be bypassed for genuine emergencies with `--force` or `JKZ_CR_GATE_DISABLE=1` — but that is an explicit, visible choice, not a default. ### What this is not - **Not a code-quality check.** The merge gate does not read your diff. It enforces *who* merges, not *what* merges — review and QA are the quality gates upstream of it. - **Not bypassable from inside a session.** The three server-side layers are the point. If a session could turn them off, they would not be a guarantee. - **Not a substitute for the human checkpoints.** The plan approval and the two ambiguity gates are separate decisions. The merge gate is the last one, not the only one. ### Related - [How jkz works](/get-started/how-jkz-works/) — where the merge gate sits relative to the plan and QA checkpoints. - [Cross-chat awareness](/concepts/cross-chat/) — keeping concurrent sessions from racing each other toward the same PR. - [Worktree isolation](/concepts/worktree-isolation/) — where the branch the gate guards is actually built. ## Models & invocation Source: https://docs.j0kz.dev/concepts/models-and-invocation/ jkz is deliberately multi-backend. No single model writes the code, reviews it, and signs off on it — that would let one model's blind spots survive end to end. Instead each role is bound to a model chosen for the *kind* of work it does, and the roles are arranged so that one model's output is challenged by a second and confirmed by a third. This page describes that mapping and how each role is actually invoked at runtime. The failure side of the story (what happens when a model 404s or a backend goes dark) lives in [Fallback](/concepts/fallback/). ### Four kinds of model Every role has a *kind* that determines both which model serves it and where it sits in a deliberation. The kind classification is centralized (`scripts/agent-kind.js`); the pipeline tracks the active kind in its state. | Kind | Roles | Model | Invocation | |------|-------|-------|------------| | `creative` | Architect, Builder, Doctor, Analyst | Claude Opus | Task tool (`model: "opus"`) | | `adversarial` | Auditor, Judge, Sentinel, Research-Auditor | External, configured per role (**required**) | `resolve-wrapper.sh` → endpoint | | `validator` | Curator, Inspector, Lens, Research-Reviewer | External (default), local Gemini CLI fallback | `resolve-wrapper.sh` → endpoint or Gemini | | `utility` | Librarian, Classifier | Claude Haiku | `node scripts/librarian.js`, `node scripts/classify-issue.js` | The orchestrator is a special case: it has no kind, because the orchestrator *is* Claude Code itself — the runtime that drives every other role. (Analyst is exclusive to the [research pipeline](/commands/research/); it does not run in the development pipeline.) ### The create–challenge–confirm pattern The kinds are not just a labelling scheme — they form a pipeline shape that repeats in every phase: 1. A **creative** model (Opus) produces the artifact — a plan, an implementation, a fix. 2. An **adversarial** model challenges it — actively trying to find what is wrong. 3. A **validator** model confirms — checking the result holds up. Planning runs Architect → Auditor → Curator. Review runs Builder → Judge → Inspector. Using *different* model families for the create and challenge steps is the point: an adversarial reviewer that shares the author's training is far more likely to share its mistakes. The asymmetry between adversarial and validator backends (below) follows directly from this — the challenge step is required, so it is not allowed to silently disappear. ### How each kind is invoked **Creative roles** run through the Task tool with `model: "opus"`. The prompt is the role's agent definition (`.claude/agents/.md`) plus the task-specific context; Claude Code consumes the agent frontmatter (`effort`, `maxTurns`, `disallowedTools`). **Adversarial and validator roles** run through a single entry point — `resolve-wrapper.sh`, invoked in the background via `node scripts/run.js`: ```bash node scripts/run.js resolve-wrapper.sh \ --role --pr --prompt "$PROMPT" ``` `resolve-wrapper.sh` does not run a model itself. It *routes* the role to the right backend wrapper based on configuration, then that wrapper calls the model and posts the result back to the PR. **Utility roles** (Haiku) are called directly as Node scripts — the Librarian for fast internal queries, the Classifier for issue-complexity routing. They are not part of any deliberation. ### Endpoint routing For every adversarial and validator role, `resolve-wrapper.sh` decides the backend by evaluating an endpoint cascade in order: 1. `JKZ__ENDPOINT` — a per-role OpenAI-compatible endpoint → `api-wrapper.sh` 2. `JKZ_API_ENDPOINT` — a shared global endpoint → `api-wrapper.sh` 3. No endpoint configured — and here the two kinds diverge: - **Adversarial** roles (Auditor, Judge, Sentinel, Research-Auditor) **exit 4** with an explicit error. The environment variable is the source of truth; there is no silent CLI fallback. The challenge step must run against a real backend or the pipeline stops and tells you. - **Validator** roles (Curator, Inspector, Lens, Research-Reviewer) fall back to the local Gemini CLI (`gemini-wrapper.sh`). This is a backwards-compatibility path — the recommended setup gives every validator role its own `JKZ__ENDPOINT` — for example an Ollama Cloud endpoint with model `glm-5.1:cloud`. The model itself is chosen by a parallel cascade: `JKZ__MODEL` → `JKZ_API_MODEL` → the CLI default. So endpoint and model are configured independently per role, and any role can be pointed at any OpenAI-compatible backend. One opt-in overrides the whole cascade: setting `JKZ__BACKEND=codex` short-circuits routing to the Codex CLI (`codex-wrapper.sh`) before the endpoint check runs — useful when an OAuth-authenticated CLI is a more practical credential path than an API key. > Changing model versions or swapping a backend is a deliberate decision, never an incidental one. The configuration lives in `.env`; do not change it without explicit approval. ### Effort levels Each role runs at an `effort` level matched to its job. The rule across the pipeline: **at least one agent per phase runs at `high`** — there is always a deep pass somewhere in every phase. | Role | Effort | |------|--------| | Auditor, Research-Auditor | `high` (the adversarial anchor) | | Architect | `medium` | | Builder | `low` (a good plan does the heavy lifting) | | Doctor | `low`, scaling to `high` on the final iteration or a wrong-approach signal | | Others | `medium` | ### A note on the Judge The Judge is the adversarial reviewer of the code-review phase. It always runs against its configured endpoint (`JKZ_JUDGE_ENDPOINT`), like any other adversarial role. An older `JKZ_JUDGE_MODE` switch that once selected the Judge's routing is **deprecated** and no longer consulted. The Judge is also distinct from the optional GitHub `@codex` review (`JKZ_CODEX_REVIEW_ENABLED`): that is a separate, PR-level bot review, independent of the adversarial-role routing described here. ### See also - [Fallback](/concepts/fallback/) — what happens when a model 404s, a backend rate-limits, or a whole service goes down - [Pipeline](/concepts/pipeline/) — the phases these roles deliberate within - [Evidence hierarchy](/concepts/evidence-hierarchy/) — the standard the adversarial roles hold arguments to ## The pipeline Source: https://docs.j0kz.dev/concepts/pipeline/ jkz is a state machine with three phases (**Plan**, **Build**, and **QA**) and one rule that never bends: a phase advances only when its work has survived a challenge. Every phase runs the same rhythm. One model creates, a second model attacks the result, a third confirms the verdict. The phase moves forward only when the verdict holds. If you want the gentle, end-to-end tour (the twelve roles, the multi-backend pattern, the mermaid diagram of the whole flow), read [How jkz works](/get-started/how-jkz-works/) first. This page is the mechanical view: the phases as states, the roles mapped onto them, and the loops that gate each transition. ### Three phases, three commands Each phase is a command, and each command produces exactly one kind of Git artifact. Artifacts are how phases hand off — never direct messages between agents. | Phase | Command | Produces | Advances on | |-------|---------|----------|-------------| | **Plan** | `/jkz:plan` | An approved plan comment on the issue | Human approval at the post-plan checkpoint | | **Build** | `/jkz:build` → `/jkz:review` | A pull request with a passing review verdict | Judge + Inspector PASS | | **QA** | `/jkz:qa` | Lens and Sentinel verdicts on the PR | Both PASS, then the post-QA gate | The phases are sequential and gated. Plan does not start building; build does not self-merge into QA; QA does not merge to `main`. Between Plan and Build sits a human checkpoint. After QA sits another. The merge itself is a third human act — see [the merge gate](/concepts/merge-gate/). ### How roles map to phases The create → challenge → confirm rhythm assigns three roles per phase: a **creative** role drafts, an **adversarial** role attacks, a **validator** role confirms. The model that wrote the work is never the model that signs it off, so one model's blind spot cannot pass unchallenged. | Phase | Creates | Challenges | Confirms | |-------|---------|-----------|----------| | **Plan** | Architect | Auditor | Curator | | **Build** | Builder | Judge | Inspector | | **QA** | (the diff under test) | Sentinel | Lens | In Plan and Build the triad is clean: one creates, one attacks, one validates. QA is the exception — there is no fresh creative step, because the artifact under test is the diff that Build already produced. Instead **Sentinel** and **Lens** run in parallel: Sentinel attacks the backend, security, performance, and infrastructure; Lens validates the frontend, visual output, and accessibility. A failure in either routes to the Doctor. The **Doctor** is the cross-phase repair role. It does not belong to a single triad — it is dispatched whenever a verdict fails in Build or QA, applies a minimal targeted patch, and sends the work back through the same challenge. The full catalogue of roles, their model classes, and the configurable backends behind the adversarial and validator seats live in [How jkz works](/get-started/how-jkz-works/). ### Iteration and escalation A failing verdict does not stop the pipeline. It loops the work back to the role that can fix it (the Architect in Plan, the Doctor in Build and QA) for **up to three attempts**. Each attempt sees the prior failure as context, so the loop converges rather than repeating itself. Three is a hard ceiling, not a target. Exhaust the attempts without a clean verdict and the pipeline **stops and escalates to you** with an explicit diagnosis. It does not force a fourth fix that merely passes the checks while hiding the real problem. Honest escalation over a silent hack is a first-class outcome here, not a failure mode — a pipeline that stops and tells you *why* has done its job. ### When QA is required QA is not run on every issue. Whether it is required depends on the issue type: | Issue type | Label | QA | |------------|-------|-----| | `feature` | (none) | **Required** | | `bug` | `bug` | Optional | | `refactor` | `refactor` | Optional | | `chore` | `chore` | Optional | A feature changes behaviour and earns the full QA pass. A scoped bug fix, refactor, or chore can skip it — the change is small enough that Build's review is sufficient. The issue type also tunes what each phase focuses on: a `bug` plan centres on root-cause analysis, a `refactor` review centres on behaviour preservation. For changes too small to deserve the full three-phase loop, there is a lighter route entirely. `/jkz:quick` runs just Builder + Judge, skipping the planning checkpoint and QA — see [lightweight routes](/build/lightweight-routes/). ### What this is not - **Not the role catalogue.** This page maps roles onto phases. For what each role *is* — its model class, its backend, its single responsibility — see [How jkz works](/get-started/how-jkz-works/) and the Agents pages. - **Not a guarantee of three iterations.** Three is the ceiling. Most phases pass on the first or second attempt; the limit exists to bound failure, not to schedule retries. - **Not the merge.** The pipeline prepares everything up to `main` but never crosses it. That last step is yours alone. ### Related - [How jkz works](/get-started/how-jkz-works/) — the full overview: twelve roles, the multi-backend pattern, and the end-to-end diagram. - [Evidence hierarchy](/concepts/evidence-hierarchy/) — the standard the adversarial roles apply when they challenge a phase. - [Ambiguity gate](/concepts/ambiguity-gate/) — the human-decision checkpoints that sit between the phases. - [Merge gate](/concepts/merge-gate/) — why the final step out of the pipeline stays a human-only act. - [Worktree isolation](/concepts/worktree-isolation/) — where each phase's work is actually built. ## Plugin mode Source: https://docs.j0kz.dev/concepts/plugin-mode/ jkz does not have to live inside its own repository. It can be installed into any project as a plugin, leaving that project ready to run the full pipeline with a single command. The design keeps a clean separation between jkz's own code and the state it produces in your project, so the same installation can serve many projects without their pipelines colliding. ### Installing Installation happens in two steps: install jkz once on your machine, then initialize it inside each project you want to use it in. ```bash # 1. Install jkz once (fetches the installer via your authenticated gh session): gh api -H "Accept: application/vnd.github.raw" \ /repos/j0KZ/jkz_Multi-Agent_System/contents/install.sh | bash # Reopen your terminal, then run the setup wizard (API keys, notifications, models): jkz install # 2. Install the plugin into a project (defaults to the current directory): jkz init [dir] ``` Because jkz lives in a private repository, the install step uses your authenticated GitHub CLI session (`gh auth login`) to fetch the installer — there is no public download. ### What it generates in your project `jkz init` writes a small set of artifacts into the target project and leaves everything else alone: ```text target-project/ .claude-plugin/plugin.json # entrypoints pointing at your jkz install .claude/commands/jkz/ # the /jkz:* commands .github/workflows/ # merge-gate, approve-merge, auto-revert hooks/post-merge # delegates to the jkz post-merge script state/ # local pipeline state (gitignored) .jkz-plugin-env # bootstrap: where jkz lives, where state goes .env # per-project config (gitignored) ``` The GitHub workflows are the important part: they install the server-side [merge gate](/concepts/merge-gate/) into your project so the human-only-merge guarantee travels with the plugin. The `state/` directory and `.env` are gitignored, so your project's history stays clean while each run's pipeline state is kept locally. ### The dual-root layout The reason one installation can serve many projects is that jkz separates *where its code lives* from *where your state lives*. Two roots: - **`JKZ_HOME`** — the jkz installation itself: scripts, agents, hooks, and the MCP server. Shared across every project. - **`JKZ_TARGET_PROJECT`** — your project: its pipeline state, deliberations, `.env`, and workflows. Unique per project. Node scripts and the `/jkz:*` commands read source from `JKZ_HOME` and read or write state under `JKZ_TARGET_PROJECT`. A small bootstrap file resolves these two roots at the start of every command, so a command run in one project never reaches into another's state. ### Uninstalling Removing the plugin is symmetric with installing it, and deliberately conservative about your data: ```bash jkz uninstall [target-dir] ``` This removes the artifacts that `jkz init` generated, but **preserves your data** — `state/`, `.env`, and the workflows stay in place. Uninstalling the plugin does not throw away your pipeline history or your configuration. ### See also - [Pipeline](/concepts/pipeline/) — what the installed commands actually run - [Merge gate](/concepts/merge-gate/) — the server-side workflows the plugin installs - [Cross-chat](/concepts/cross-chat/) — coordinating multiple sessions on one project ## Signal format Source: https://docs.j0kz.dev/concepts/signal-format/ The agents in a jkz pipeline never talk to each other directly. Everything an agent needs flows in through a structured prompt, and everything it decides flows out through structured markers the orchestrator can parse. This is what keeps the system auditable: every verdict is a machine-readable block in the pull request, not an opinion exchanged in a side channel. Three signal shapes carry almost all of that traffic. ### Context Protocol — how agents receive their inputs Agents do not fetch their own context; the orchestrator gives it to them. *How* it does so depends on the kind of agent. For **in-session model agents** (invoked through the Task tool), the orchestrator passes a list of file paths, not file contents: ```xml src/auth/middleware.ts state/pipeline/42-compact-plan.json state/briefs/42-brief.md ``` The agent reads the `required` files before acting (and reports a blocker if one is missing), reads the `optional` ones if they exist, and otherwise proceeds. Passing paths instead of contents keeps the orchestrator's own context window light while still giving the agent full-fidelity data. For **wrapper-based agents** (the external adversarial and validator backends), the orchestrator inlines the actual content as a budgeted "context pack": ```text === CONTEXT PACK === --- PR DIFF (max 50KB) --- --- PLAN (max 10KB) --- --- CODEBASE (max 20KB) --- --- PRIOR FEEDBACK (max 5KB) --- === END CONTEXT PACK === ``` The sections are ordered by priority, and the budgets are hard caps — if the pack is too large, it is truncated from the bottom up, so the diff is the last thing to be cut. ### verdict-json — the primary signal Every agent that renders a decision ends its report with a `verdict-json` block: an HTML comment the orchestrator parses to decide what happens next. It is emitted on *every* verdict, including a clean PASS (where the issues array is simply empty). ```html ``` A few rules make these blocks reliable: - **Only CRITICAL and HIGH** issues appear in `issues[]`. MEDIUM and LOW are omitted to keep the block compact. - **A FAIL must name at least one `must_fix` id.** A FAIL with an empty `must_fix` is contradictory, and the orchestrator treats it as a PASS. - **`false_positives` requires evidence** and is only meaningful for validator roles — it lets a validator flag findings from the prior adversarial agent that turned out to be noise. - The block **must stay inside the HTML comment.** If it leaks outside, it shows up as visible text in the PR and breaks parsing. The `id` carries a one-letter role prefix (`J` for Judge, `I` for Inspector, `L` for Lens, `S` for Sentinel) so a finding can always be traced back to who raised it. The optional `root_cause` classifies *why* something failed (an implementation bug, a missing validation, a security vulnerability, a test gap, and so on) rather than just what it looks like; when unsure, an agent omits it rather than guessing. Why a compact block at all? Because it lets the orchestrator carry a roughly 200-token summary of each iteration into the next one, instead of re-feeding an entire prose review. ### Issue proposal — capturing out-of-scope work Sometimes an agent spots a real problem that does not belong to the current pull request. Rather than expand the PR's scope, it drops a single proposal marker: ```html ``` The orchestrator turns that into a new tracked issue. The discipline around it is narrow on purpose: at most one marker per response, only on FAIL verdicts, with a title that starts with a verb and never contains a `|` (which separates the title from the optional description). It is for systemic follow-up work worth tracking separately — not for restating the current failure. ### See also - [Pipeline](/concepts/pipeline/) — the phases that emit and consume these signals - [Evidence hierarchy](/concepts/evidence-hierarchy/) — what makes a finding's evidence valid - [Context management](/concepts/context-management/) — how oversized signals are truncated ## Worktree isolation Source: https://docs.j0kz.dev/concepts/worktree-isolation/ jkz runs many things at once — several pipelines across several issues, and within a single pipeline several agents that all write code. If they shared one working tree they would clobber each other's branches, files, and `node_modules`. So jkz never lets them. Every issue gets its own git worktree, and every parallel-writing agent gets one too. Isolation is the default, not an optimization you turn on. ### Two layers of worktree The system uses two distinct kinds of worktree, and keeping them straight is the key to understanding everything else on this page. | Layer | Where | Lifetime | Created by | Branch | |-------|-------|----------|------------|--------| | **Issue worktree** | `../jkz-worktree-` (sibling of the repo) | Long-lived — one per issue | `issue-worktree.js ensure` | `jkz/issue-` | | **Agent worktree** | `.claude/worktrees/agent-*` | Ephemeral — one per dispatch | Claude Code's Task tool (`isolation: "worktree"`) | `worktree-agent-` | An **issue worktree** is the desk a pipeline works at. It is created once when work on issue `#N` begins, lives as long as the issue is in flight, and is reused across the plan, build, review, and QA phases. The path convention is deterministic: a sibling directory named `jkz-worktree-`, branched from `main`. An **agent worktree** is scratch space. When Claude Code dispatches a subagent with `isolation: "worktree"` (the Builder and the Doctor, the roles that mutate files), it spins up a throwaway worktree under `.claude/worktrees/`, lets the agent work in it, and tears it down afterward. These are the reason a quick-mode PR often lands on a `worktree-agent-` branch rather than `jkz/issue-`. ### The lifecycle A pipeline command does not just `cd` into a directory. It runs a precise sequence so the session itself moves into the isolated tree and back out again: ```text issue-worktree.js ensure → EnterWorktree → ...work... → ExitWorktree(keep) → (optional) issue-worktree.js cleanup ``` `ensure` is **idempotent**: if the worktree already exists it is reused, if not it is created from the base branch. The same session then switches into it via `EnterWorktree` (no second Claude Code window required), does the phase's work, and switches back out with `ExitWorktree` keeping the tree in place for the next phase. #### The skip guard The pipeline must not nest a worktree inside a worktree. Before entering, it checks two conditions and skips the worktree steps if either holds: - The current git root is already a `jkz-worktree-*` directory (the pipeline is re-entering its own tree), or - `JKZ_USE_CC_WORKTREES=1` (the default) **and** the git root path contains `/.claude/worktrees/` — meaning Claude Code has *already* isolated the session through Agent View or a Task dispatch. The second case is the system deferring to Claude Code's own isolation rather than stacking a redundant jkz worktree on top. Set `JKZ_USE_CC_WORKTREES=0` to force jkz sibling worktrees in every context. ### Cleanup is conservative by design With pipelines finishing all day, merged worktrees pile up. Cleanup exists — but it is built to never delete live work. `worktree.sh cleanup-merged` is **dry-run by default**; nothing is removed until you pass `--apply`. Even with `--apply`, the cleanup refuses any worktree that is: - jkz-locked, - carrying uncommitted changes, or - referenced by a fresh chat-registry heartbeat (another session is using it). And what it does remove, it does not destroy. Deleted worktrees are **moved to `state/worktree-trash/`**, not `rm -rf`'d. They stay registered as git worktrees on a detached HEAD, so moving the directory back restores them. The kill-switch `JKZ_WORKTREE_CLEANUP_DISABLE=1` makes cleanup a no-op even with `--apply`. A second sweep handles the harder case: a worktree left **locked** by a pipeline that never finished. The stale-lock sweep recovers locked worktrees whose owning issue has been *closed* for at least 24 hours, and it confirms across two monitoring cycles before acting. Its safety is tri-state: only an explicit "not active" signal from the chat registry counts as safe to unlock — both "active" and "lookup failed" fail safe and leave the lock alone. Kill-switch: `JKZ_STALE_LOCK_SWEEP_DISABLE=1`. ### What this buys you - **Parallelism without collisions.** Two issues build at the same time on separate branches in separate directories. Within a build, the Builder and Doctor never fight over the same files. - **A clean blast radius.** A failed or abandoned attempt is one directory. Trash it; the rest of the project is untouched. - **Recoverability over destruction.** The cleanup path prefers `mv` to `rm` precisely because an over-eager delete is the one mistake you cannot undo. ### What this is not - **Not free at scale.** Worktrees share the repo's `node_modules` by symlink, but they still accumulate. Past hundreds of stale worktrees git contention shows up — which is exactly why the cleanup sweeps exist. - **Not a place to hand-edit.** You drive the pipeline; the pipeline drives the worktree. Manually invoking the isolation gate or editing inside an agent worktree fights the lifecycle rather than using it. ### Related - [Cross-chat awareness](/concepts/cross-chat/) — how the chat registry decides a worktree is "active" and which session owns an issue. - [Merge gate](/concepts/merge-gate/) — what happens to the branch after the worktree's PR is ready. - [How jkz works](/get-started/how-jkz-works/) — where worktree isolation sits in the full pipeline. ## Lightweight routes — /jkz:quick & /jkz:fix Source: https://docs.j0kz.dev/build/lightweight-routes/ Not every change needs the full plan → build → review → QA loop. A typo, a one-line bug fix, a config tweak — running an Architect, an Auditor, and a QA pass on those wastes tokens and your time. jkz has two lightweight routes for exactly this: **`/jkz:quick`** for small scoped changes, and **`/jkz:fix`** for the surgical repair cycle. This page covers what each does, when to reach for it, and how the complexity classifier decides whether you land here or in the full pipeline. ### How you get routed here When you start from a raw idea or an existing issue, the **Classifier** (Claude Haiku) sizes the work into one of three complexity buckets. The bucket determines the route: | Complexity | What it means | Route | |------------|---------------|-------| | `trivial` | The approach is obvious. Opus can resolve it directly in a chat session — no formal plan or review cycle. May touch multiple files. (Rename a variable, add an env var, fix a clear bug, update docs.) | Direct in chat — no pipeline | | `quick` | A scoped change that benefits from lightweight structure but not a full pipeline. The direction is clear but involves some decisions. (Add a CLI flag with validation, a small feature with tests, a bug that needs investigation.) | [`/jkz:quick`](#jkzquick--builder--judge) | | `standard` | Multi-faceted work: design decisions, multiple system layers, non-obvious implications. (Refactor a subsystem, add an agent role, a feature spanning components.) | Full `/jkz:pipeline` | Classification is hybrid: an LLM call (Haiku) is primary, with a deterministic scoring fallback if the model is unavailable. The fallback adds points for design keywords, layer count, and file count, and subtracts for self-contained one-file changes — `score >= 4` is `standard`, `score <= -2` is `trivial`, everything between is `quick`. A `chore` label biases toward `quick`; a compliance keyword bumps a `trivial` result up to `quick` so it never skips review entirely. The classifier *recommends* — you decide. `/jkz:quick` re-classifies on the spot if the issue has no `complexity:*` label, and if it comes back `standard` it warns you and offers the full pipeline before doing anything. :::note[Source of truth] The complexity definitions and scoring live in the private repo at `scripts/classify-issue.js`. The route behavior is defined in `.claude/commands/jkz/quick.md` and `fix.md`. This page summarizes them for public reference. ::: ### `/jkz:quick` — Builder + Judge `/jkz:quick ` is the minimum viable pipeline: **two agents, one reviewer, no plan, no QA.** ```mermaid flowchart LR issue(["Issue · jkz:ready"]) --> Bu["Builder implements
(issue body = plan)"] Bu --> J["Judge reviews"] J -- PASS --> CR["CR reconciliation"] CR --> approved(["jkz:approved"]) J -. "FAIL · Doctor fixes · up to 3x" .-> Bu ``` The flow is deliberately stripped down compared to the [full pipeline](/get-started/how-jkz-works/): - **No Architect.** There is no formal plan — *the issue description is the plan*. The Builder reads the issue and implements it directly inside an isolated worktree, then opens the PR. - **The Judge is the sole reviewer.** It reviews the diff against the issue body. There is **no CodeRabbit pre-scan** (not worth the latency for a trivial change) and **no Inspector** (the Judge calibrates to the small scope). - **No QA phase.** Lens and Sentinel do not run. - **CR reconciliation, only after a PASS.** Once the Judge passes, CodeRabbit-bot findings are triaged lightweight — the orchestrator classifies each as VALID / FALSE_POSITIVE / OUT_OF_SCOPE / ALREADY_FIXED and fixes the VALID ones directly (no Doctor subagent). If a fix is pushed, the Judge re-reviews once. - **On FAIL, the Doctor fixes — up to 3 times.** Same fix cycle as the full pipeline (see below). Three failed attempts move the issue to `jkz:blocked` and escalate to you. Everything else holds: the change runs in a per-issue worktree, the PR closes the issue via a `Closes`/`Fixes` keyword, and **only a human merges** — the lightweight route does not weaken the merge gate. #### When to use `/jkz:quick` | Use it for | Do **not** use it for | |------------|-----------------------| | Fixes of roughly 1–10 lines | New features | | Documentation-only changes | Architectural changes | | Config changes with obvious scope | Security-sensitive code | | Typo fixes, minor refactors | Anything touching more than ~5 files | If a change has any of the right-hand qualities, reach for the full `/jkz:pipeline` instead — the planning and QA phases exist precisely for work with design decisions or wide blast radius. ### `/jkz:fix` — the Doctor's fix cycle `/jkz:fix --source ` is not a route you usually invoke by hand. It is the **fix cycle** that `/jkz:review` and `/jkz:qa` (and `/jkz:quick`) call automatically whenever a reviewer returns FAIL. Its job: take the failing verdict, apply a minimal targeted fix, and re-trigger the phase that failed. The agent behind it is the **Doctor** (Claude Opus). It changes exactly what broke and nothing more: no scope creep, no opportunistic refactors. What happens inside one fix cycle: 1. **Gather feedback.** Collect the CRITICAL/HIGH findings from the failing verdict (compact `verdict-json` signals on later iterations, full PR comments on the first). 2. **Flaky check.** A classifier spots flaky test failures and re-runs the phase *without* counting it as a fix attempt — a flaky test should not burn the Doctor's budget. 3. **Classify the failure** into one of eight categories (implementation bug, missing validation, missing error handling, security vulnerability, missing requirement, test gap, wrong approach, regression). If the category is `wrong_approach`, a one-time gate lets the **Architect** rewrite the plan before the Doctor tries again (max one rewrite per pipeline). 4. **Loop guard.** From iteration 2 on, jkz compares the new diff against the previous attempt. A near-identical diff triggers a warning so the Doctor changes strategy instead of repeating a dead end. 5. **Fix and re-trigger.** The Doctor applies the patch and the diff goes back through the failed phase — review (Judge + Inspector) or QA (Lens + Sentinel). This repeats **up to three attempts**. If three fixes still don't clear the verdict, the issue moves to `jkz:blocked` and escalates to you with a diagnosis of what was tried — **honest escalation over a silent hack** that merely passes the checks. #### When `/jkz:fix` fires - Automatically, whenever Judge, Inspector, Lens, or Sentinel returns FAIL during a review or QA phase. - Manually, when you want to re-run the Doctor against a known-failing PR: `/jkz:fix --source review` (or `--source qa`). ### Choosing a route at a glance | You have… | Reach for… | |-----------|-----------| | A typo, a one-line fix, a doc edit | Edit directly, or `/jkz:quick` | | A small scoped change with a clear direction | `/jkz:quick` | | A feature, a refactor, anything with design decisions | The full pipeline — start at [How jkz works](/get-started/how-jkz-works/) | | A PR that a reviewer just failed | `/jkz:fix` (usually automatic) | The full plan → build → review → QA pipeline and every command's model line-up are covered in [How jkz works](/get-started/how-jkz-works/) and the [CLI / commands reference](/reference/cli/). ## Run a pipeline — /jkz:pipeline end-to-end Source: https://docs.j0kz.dev/build/run-a-pipeline/ [`/jkz:pipeline `](/commands/pipeline/) drives one issue from `jkz:ready` to a merge-ready PR through four phases — **Plan → Build → Review → QA** — and stops at every point that needs a human. This page is the operator's view: the command you run, what happens between checkpoints, and exactly what you decide at each one. For the conceptual model (the twelve roles, the multi-backend deliberation loop, why merge stays human) read [How jkz works](/get-started/how-jkz-works/) first; this page assumes it. ### The one command ```bash /jkz:pipeline 1234 ``` That is the whole invocation for a fresh run. Three flags adjust it: | Flag | Effect | |------|--------| | `--resume` | Continue an interrupted run from its last `current_phase` (see [Recovering a run](#recovering-a-run)). | | `--from ` | Force the start phase (`plan`, `build`, `review`, `qa`). | | `--silent` | Suppress Telegram checkpoint notifications; approvals still happen in the chat. | The pipeline runs the phases autonomously *between* checkpoints. It never reaches `main` on its own — that is always your call. ### The flow at a glance ```mermaid flowchart TD issue(["Issue · jkz:ready"]) --> PRE subgraph PLAN["PLAN"] A["Architect drafts"] --> Au["Auditor challenges"] --> Cu["Curator validates"] Cu -. "FAIL · iterate up to 3x" .-> A end PRE{{"① You approve the plan
(pre-flight)"}} --> A issue --> PRE Cu --> BUILD subgraph BUILD["BUILD → REVIEW"] Bu["Builder implements + opens PR"] --> CRb["CodeRabbit prescan + fix loop"] --> V["Pre-push validators"] --> J["Judge reviews"] --> I["Inspector verifies"] I -. "FAIL · Doctor fixes · up to 3x" .-> Bu end I --> R{{"② You approve the review
✅ run QA · ⏭ skip QA · 🛑 stop"}} subgraph QA["QA — features required, others optional"] L["Lens · frontend / a11y"] S["Sentinel · backend / security"] D{"Doctor fixes"} L -. "FAIL" .-> D S -. "FAIL" .-> D D -. "up to 3x" .-> L D -. "up to 3x" .-> S end R -- "run QA" --> L R -- "run QA" --> S R -- "skip QA" --> M L --> Q{{"③ You approve QA"}} S --> Q Q --> M[["④ You merge · approve-merge.yml + passphrase"]] M --> done(["Merged to main"]) ``` The hexagonal nodes (①–④) are the human checkpoints. Everything else runs without you. Dotted edges are the iteration loops — a failing verdict sends the work back (to the Architect in planning, to the Doctor in build and QA) for up to three attempts before the pipeline escalates instead of forcing a fix. ### What you do at each checkpoint #### ① Approve the plan (pre-flight) Plan approval happens *before* the autonomous loop begins. The Architect drafts the strategy, the Auditor attacks it, the Curator calibrates the audit — up to three iterations — and then the full plan is printed in the chat: problem, changes, mechanics, the deliberation, the decisions, the risk. You read it and approve (or reject with feedback, which feeds another planning iteration). **Nothing is built until you approve.** An inline **ambiguity gate** (an Opus scan) runs here too, classifying anything unclear as `TRIVIAL`, `FIX`, or `DECIDE`. A `DECIDE` is surfaced for your call; the others are handled or noted automatically. #### ② Approve the review The Builder implements the approved plan in an isolated worktree and opens the PR. A CodeRabbit prescan and fix loop clean up the obvious issues, pre-push validators run deterministic checks (secrets, debug statements, capability invariants), then the **Judge** reviews the diff and the **Inspector** verifies it. When both PASS, you decide what happens next — and the options depend on the issue type: | Issue type | Your options at the review checkpoint | |------------|----------------------------------------| | `feature` | ✅ run QA · ⏭ skip QA and approve · 🛑 stop | | `bug` / `refactor` / `chore` | ✅ advance to QA · ❌ reject and fix · 🛑 stop | QA is **required** for features and **optional** for the other types — small, scoped changes can go straight to approval. A FAIL at review routes to the Doctor for a surgical fix (up to three times), then re-runs the review. #### ③ Approve QA If QA runs, **Lens** (frontend, visual, accessibility) and **Sentinel** (backend, security, performance, infrastructure) run in parallel. A FAIL routes to the Doctor, up to three times. When QA passes, a second **ambiguity gate** runs, then you approve. (For non-feature issues that skipped QA at ②, the pipeline goes straight from review approval to the merge step.) #### ④ Merge Only you merge to `main`, and you cannot do it from inside the session — the gate is server-side. Trigger the approval workflow with the passphrase (a GitHub Secret that Claude Code cannot read): ```bash gh workflow run approve-merge.yml -f pr= -f passphrase= ``` That flips the merge-gate status to `success`; merge the PR normally afterward. The [merge gate](/concepts/merge-gate/) explains the four layers behind this guarantee. ### Recovering a run A pipeline can stop mid-run — a crash, a timeout, an escalation. Two commands get you back: - **`/jkz:status`** shows where any issue is in the pipeline (current phase, active agent, iteration count). - **`/jkz:resume `** (or `/jkz:pipeline --resume`) diagnoses the interruption and continues from the last recorded phase. Use `--from ` to override the start point. If a phase exhausts its three fix attempts, the issue moves to `jkz:blocked` and the pipeline escalates to you with an explicit diagnosis rather than shipping a fix that merely passes the checks. That is by design — honest escalation over a silent hack. ### When *not* to run the full pipeline A typo does not need an Architect, an Auditor, and a QA pass. For small, scoped work use the [lightweight routes](/build/lightweight-routes/) — `/jkz:quick` (Builder + Judge, no plan, no QA) or `/jkz:fix` (the Doctor's surgical fix cycle) — or just edit the file directly. The complexity classifier recommends the route when you start from an issue; you decide whether to take it. ## ask Source: https://docs.j0kz.dev/commands/ask/ `/jkz:ask [--model codex|gemini] ` routes a one-off question to an external model and hands you back its answer, with no pipeline, PR, phase, or issue attached. It is the quickest way to get a second opinion from a model that is *not* Opus — useful precisely because it sees only what you give it, free of the framing the pipeline would otherwise impose. Every invocation is independent. Session files are deleted before each call, so there is no carryover from one question to the next — the consultant answers fresh each time, exactly the behavior you want for a throwaway query. ### At a glance | | | |------|------| | **Models** | `codex` (default) or `gemini` — `opus` is not supported | | **Context** | None — ad-hoc, no PR/issue/phase | | **Memory** | Ephemeral — session deleted before each call | | **Backends** | [`consultant-codex`](#the-consultants) and [`consultant-gemini`](#the-consultants) | | **Usage** | `/jkz:ask ` · `/jkz:ask --model gemini ` | ### When to use Reach for `/jkz:ask` when you want a focused answer from an outside model without spinning up the deliberation machinery: a sanity check on an approach, a quick read of an error, a "does this look right?" on a snippet. If you provide code, the consultant analyzes it concretely and cites line numbers and function names; if you don't, it answers from its own knowledge and tells you when it is reasoning without grounded evidence. For Opus, just ask Claude directly in the conversation — `/jkz:ask` deliberately targets external models only. For a genuinely contested decision that warrants more than one external voice arguing, use [`/jkz:debate`](/commands/debate/) instead. ### Key behavior You pick the model with `--model` (default `codex`). The remaining text is your question; an empty question is an error. The command writes your prompt to a temp file, deletes any lingering session state to guarantee a clean start, and invokes the backend in the background, polling for the result for up to 30 minutes before timing out. Because no `--pr` or `--issue` is passed, the consultant writes a deliberation file but no sentinel — nothing is posted to GitHub. The answer is displayed back to you with the model attributed (`[consultant-codex]` or `[consultant-gemini]`). ### The consultants `/jkz:ask` and [`/jkz:debate`](/commands/debate/) are fronted by two ad-hoc consultant roles. Both are read-only, hold no memory, and never post to a PR or issue — they exist purely to answer the question in front of them, applying the same evidence hierarchy the pipeline's adversarial roles use (execution > file citations > reasoning). - **`consultant-codex`** — the adversarial backend, selected by `--model codex` (the default). It routes through `resolve-wrapper.sh` to whatever OpenAI-compatible endpoint is configured in `JKZ_CONSULTANT_CODEX_ENDPOINT`; there is no silent fallback, so the endpoint must be set. - **`consultant-gemini`** — the validator backend (Gemini 3.5 Flash), selected by `--model gemini`. It resolves through the same wrapper and falls back to the local Gemini CLI when no endpoint is configured. The backend is resolved per call from the `--model` flag → role (`codex` → `consultant-codex`, `gemini` → `consultant-gemini`) → endpoint configuration. To route either consultant through a custom API endpoint, set `JKZ_CONSULTANT_CODEX_ENDPOINT` or `JKZ_CONSULTANT_GEMINI_ENDPOINT` in `.env`. ## bugs Source: https://docs.j0kz.dev/commands/bugs/ `/jkz:bugs` scans the codebase for bugs and reports what it finds. It runs at three levels of depth, so you can pick between a five-second sanity check and a slower, adversarial sweep depending on how much you want to spend. ### At a glance | | | |------|------| | **`quick`** *(default)* | Deterministic scan only (~5s) | | **`deep`** | Adds the test suite, a dependency audit, and cross-file analysis | | **`full`** | Adds adversarial review, anti-pattern detection, and stale-state checks | | **Runs** | `bugs-scan.js` for the deterministic pass | | **Usage** | `/jkz:bugs [quick \| deep \| full]` | ### When to use Reach for `quick` when you want a fast read on whether the tree is in obvious trouble — it runs deterministic checks (syntax, validators) and returns in a few seconds. Use `deep` before a larger change when you want the test suite and dependency audit folded in. Use `full` when the cost of a missed bug is high and you want a second, adversarial opinion on top of the automated findings. The results are **advisory**: `/jkz:bugs` is a standalone scan, not a pipeline gate. For the gated review of a specific change, that is the [Judge](/agents/judge/) and the QA phase. ### Key behavior The command parses its argument to pick a level, then runs the deterministic scanner and presents findings as a Markdown table grouped by severity (high first), with a per-severity summary at the end. If nothing turns up, it says so plainly. - **`deep` and `full`** also run the test suite and report totals (passed / failed), plus a dependency audit and cross-file analysis. - **`deep` and `full`** dispatch an Opus subagent to analyze the raw findings in context — separating real bugs from false positives, giving root-cause analysis for high-severity items, and suggesting fixes. - **`full`** additionally launches an adversarial review via the [Sentinel](/agents/sentinel/) role to catch logic errors, race conditions, and edge cases the deterministic scanner missed. For a broader, category-by-category sweep of project health rather than a bug hunt, see [`/jkz:quality`](/commands/quality/). ## build Source: https://docs.j0kz.dev/commands/build/ `/jkz:build ` runs the phase where a plan becomes code. The [Builder](/agents/builder/) (Claude Opus) takes the strategy approved in [`/jkz:plan`](/commands/plan/) and implements it faithfully inside an isolated [worktree](/concepts/worktree-isolation/), then opens the pull request that every later phase reviews. It makes no architectural decisions — those were settled in planning — and it cannot reach `main`. ### What it does The command orchestrates the **build** phase of [the pipeline](/get-started/how-jkz-works/): ```mermaid flowchart LR plan(["jkz:building
(approved plan)"]) --> Bu["Builder implements
in isolated worktree"] Bu --> PR["Opens PR · Closes #N"] PR --> review(["jkz:reviewing"]) ``` - The **Builder** implements the approved plan exactly: atomic commits, matching the existing style, no opportunistic refactors. - It works inside its own worktree — writes are confined there, never to the main checkout. - It opens a pull request targeting `main` with a `Closes #N` (or `Fixes #N`) keyword so the eventual merge auto-closes the issue. - It reports back a build summary (files created/modified/deleted, deviations, acceptance-criteria coverage) and a structured `jkz:verdict-json` signal: `COMPLETE` or `BLOCKED`. When a plan step is impossible — a file was renamed, an API changed, a dependency is missing — the Builder **stops and reports `BLOCKED`** rather than fabricating success. A blocked build is a valid outcome that escalates to you, not a failure to hide. ### When to run it - After a plan has been approved in [`/jkz:plan`](/commands/plan/). - As the build stage of `/jkz:pipeline`, which runs it automatically after plan approval. - To resume an interrupted build (see below). ### Inputs | Input | Required | Notes | |-------|----------|-------| | Issue number | Yes | `/jkz:build `. | | Approved plan | Yes | The plan that passed Architect → Auditor → Curator. The Builder treats it as the brief. | | Codebase context | Gathered automatically | The current state of the files the plan touches. | In [`/jkz:quick`](/build/lightweight-routes/) there is no Architect plan: the issue body *is* the plan and the Builder implements it directly. ### Resume support A build is resumable. If a previous run was interrupted, the command reads a `.jkz-checkpoint` in the worktree and continues from the last completed stage — committed work is never redone. ```text planning → implementing → tested → committed → pushed → pr_created ``` ### What phase it drives | | | |--|--| | Phase label | `jkz:building` → `jkz:reviewing` (when the PR opens) | | Active agent | [Builder](/agents/builder/) | | Can open a PR | Yes | | Can merge / push to `main` | No — blocked by capability invariants and the [merge gate](/concepts/merge-gate/) | ### Human checkpoint The build phase has no checkpoint of its own — the human gates sit on either side: plan approval before it, and review → QA → merge after it. The Builder's only escape hatch is an honest `BLOCKED` verdict, which stops the pipeline and escalates to you. ### See also - [How jkz works](/get-started/how-jkz-works/) — the build phase in the full pipeline flow. - [Builder](/agents/builder/) — the agent this command dispatches. - [`/jkz:plan`](/commands/plan/) — the phase before, which produces the approved plan. - [`/jkz:review`](/commands/review/) — the next phase, once the PR is open. - [Worktree isolation](/concepts/worktree-isolation/) · [Merge gate](/concepts/merge-gate/) — why the Builder is confined and cannot merge. ## calibrate Source: https://docs.j0kz.dev/commands/calibrate/ `/jkz:calibrate` takes the patterns the pipeline has been accumulating in its memory store and folds the significant ones into the calibration sections of the validator agents — the place where a recurring, validated signal becomes a standing instruction the agent carries into every future review. It is how the system turns "we have seen this kind of issue before" into "watch for this kind of issue." The promotion is not automatic. Each candidate pattern is judged by a three-model tribunal, and a minority veto can block a pattern even when the majority would admit it — the same adversarial caution the pipeline applies everywhere, pointed inward at its own learning loop. ### At a glance | | | |------|------| | **Purpose** | Promote memory-store patterns into validator calibration sections | | **Gate** | Three-model tribunal with minority veto | | **Targets** | Validator agents (e.g. Judge, Inspector, Lens, Curator) | | **Modes** | `--dry-run` (preview diff) · `--role ` (single agent) | | **Usage** | `/jkz:calibrate` · `/jkz:calibrate --dry-run` · `/jkz:calibrate --role judge` | ### When to use Run `/jkz:calibrate` after the pipeline has built up enough deliberation history for patterns to be meaningful — typically alongside or after reviewing [`/jkz:insights`](/commands/insights/). It is the deliberate step that converts observed, repeated signals into agent behavior. Start with `--dry-run` to see exactly which patterns would be promoted and how each agent file would change before writing anything. ### Key behavior By default the command calibrates all validator agents; `--role ` scopes it to one. It evaluates candidate patterns per agent, runs each through the tribunal, and reports how many candidates were considered, which were approved versus rejected, and any tribunal failures or vetoes. With `--dry-run` it emits the unified diff without touching agent files; without it, it confirms which agent files were updated. The result is a tightening loop: validated patterns become calibration instructions, which sharpen the next round of reviews. ## commit Source: https://docs.j0kz.dev/commands/commit/ `/jkz:commit` puts a CodeRabbit review *in front of* the commit. Instead of committing first and discovering problems later in the PR, it scans the staged diff, classifies what CodeRabbit finds, applies the fixes worth applying, and only then writes the commit — so the change that lands is already cleaned up. ### Usage ``` /jkz:commit ``` It works on whatever is staged. If nothing is staged but you have unstaged changes, it asks how to stage them (`git add -A`, a selective add, or staging manually) rather than guessing. ### The flow ```mermaid flowchart LR stage(["Staged changes"]) --> skip{"Trivial or
non-code only?"} skip -- yes --> commit["Commit
(conventional message)"] skip -- no --> loop["CR fix loop
(up to 3x)"] loop --> commit commit --> push{"Push?"} push -- "you choose" --> done(["Done"]) ``` - **Skip heuristic.** The CodeRabbit scan is skipped when the diff is under ~10 changed lines, or when every staged file is non-code (`.md`, `.json`, `.yml`, `.lock`, and similar). Trivial changes go straight to the commit. - **CR fix loop — up to 3 iterations.** Each pass scans the staged diff (via the CodeRabbit reviewer, falling back to the CLI wrapper), then classifies every finding as **VALID** (a real issue — gets fixed), **FALSE_POSITIVE** (dismissed with a `file:line` citation), or **LOW_SIGNAL** (informational — skipped). Valid fixes are applied surgically and re-staged. The loop ends as soon as a pass yields no valid findings, or after the third iteration. - **Commit.** The `commit-commands:commit` skill writes a conventional-commit message from the staged diff. The loop never commits mid-iteration — it stages fixes and commits once at the end. - **Push is opt-in.** Nothing is pushed unless you say so; if the branch has no upstream it uses `git push -u origin HEAD`. ### When to use it Reach for `/jkz:commit` on ad-hoc work — outside the [pipeline](/commands/pipeline/) — when you want a quick CodeRabbit pass before committing without opening a PR first. For a fuller pre-PR sequence that also runs format, lint, tests, and simplify, use [`/jkz:ship`](/commands/ship/), which reuses this same loop. To run the loop against an *existing* PR instead of staged changes, use [`/jkz:cr-fix`](/commands/cr-fix/). Because it only ever degrades gracefully when CodeRabbit is unavailable — warning and proceeding rather than blocking — `/jkz:commit` is safe to make a habit of. ## cost Source: https://docs.j0kz.dev/commands/cost/ `/jkz:cost [] [--phase ] [--json]` tells you what a pipeline run cost, in API-equivalent dollars, broken down by phase, role, and iteration. The number is computed from `scripts/pricing.json` regardless of whether the run used OAuth or a metered API key — it is a relative-comparison figure, the right lens for spotting which agent or phase is eating the budget. Rows that ran while CodeRabbit was active — a review with CR findings injected, or the QA pass-gate loop — are flagged with `(CR)`, so the CodeRabbit overhead is visible without digging. ### At a glance | | | |------|------| | **Scope** | One pipeline issue (defaults to the active issue in `STATE.json`) | | **Breakdown** | Phase × role × iteration, `(CR)`-flagged where applicable | | **Pricing** | API-equivalent from `scripts/pricing.json` (OAuth or API) | | **Modes** | Standard report · `--attribute ` orchestrator-token capture | | **Usage** | `/jkz:cost 1167` · `/jkz:cost --phase reviewing` · `/jkz:cost --json` | ### When to use Run `/jkz:cost` whenever you want to understand where a pipeline's tokens went — after a run that felt expensive, when tuning effort levels, or when deciding whether CodeRabbit overhead is justified. The interpretation notes call out the patterns worth acting on: CR overhead above 30% of the grand total, a single role consuming more than half a phase, or repeated iterations on the same role that hint the upstream Builder or Architect plan needs more effort. ### Key behavior With no argument the command resolves the active issue from `state/STATE.json`; pass an issue number to target a specific run, `--phase` to narrow to one phase (`planning`, `build`, `reviewing`, `qa`, `fixing`, `ad-hoc`), or `--json` for the raw data instead of the markdown table. Coverage comes from the `token_usage` table in `state/metrics.db`: Opus subagents via the subagent-stop hook, adversarial/validator/API agents via wrapper post-processing, and orchestrator tokens captured manually through `--attribute`. ### `--attribute` mode A PR written entirely inside a Claude Code orchestrator session — no Task subagents, no `/jkz:*` commands — leaves no rows in `token_usage`, because the per-role hooks never fire for the orchestrator itself. `--attribute ` is the manual opt-in that closes that gap: it reads the session JSONL transcripts in the PR's window, aggregates per-model token totals, and writes them under `phase=ad-hoc`, `role=orchestrator`. Two guards keep the numbers honest. A **refusal gate** aborts if any turn contains a `Task` block or a `/jkz:*` command marker — those tokens are already captured by the pipeline hooks, and double-attributing them would inflate the cost. **Anti-double-counting** subtracts overlapping rows already present for the same issue and model inside the window. The write is an idempotent UPSERT: re-running with the same window replaces rather than accumulates, so the totals stay stable. Use `--dry-run` to preview the planned rows as JSON before committing them. ## cr-fix Source: https://docs.j0kz.dev/commands/cr-fix/ `/jkz:cr-fix` runs the CodeRabbit review-and-fix cycle against an **open pull request**. Where [`/jkz:commit`](/commands/commit/) scans staged changes before they are committed, `/jkz:cr-fix` operates on a PR that already exists: it pulls in CodeRabbit's findings (both the live CLI scan and the bot comments already on GitHub), fixes what is genuinely wrong, and tidies up the review threads. ### Usage ``` /jkz:cr-fix [] ``` The PR number is optional but recommended — with it, the command seeds the first iteration from existing CodeRabbit bot comments on the PR, locates the PR's worktree to run the CLI where the code lives, and pushes + resolves threads at the end. It records a rollback SHA before touching anything. ### The flow ```mermaid flowchart LR pr(["Open PR"]) --> loop["CR fix loop (up to 3x)
scan · classify · fix · stage"] loop --> commit["Single commit"] commit --> push["Push"] push --> resolve["Resolve addressed threads"] resolve --> oos{"Out-of-scope
findings?"} oos -- yes --> issue["Create follow-up issue"] oos -- no --> summary(["Summary comment on PR"]) issue --> summary ``` - **Seeded from the bot.** On the first iteration the loop merges the live CodeRabbit CLI scan with the inline and PR-level comments the CodeRabbit bot already posted on GitHub — so nothing the bot flagged is missed, and a finding appearing in both sources is classified only once. - **Five-way classification.** Every finding is labelled **VALID** (fixed), **FALSE_POSITIVE** (dismissed with a `file:line` citation), **OUT_OF_SCOPE** (a real issue in pre-existing code, not this PR — collected for a follow-up issue), **ALREADY_FIXED**, or **LOW_SIGNAL** (skipped). The loop converges as soon as a pass finds nothing valid, or after the third iteration. - **One commit, not many.** Fixes are staged across the loop and committed once (`fix: address CodeRabbit findings`). The push is guarded — it checks the PR is still `OPEN` first — and then [resolves every addressed review thread](/concepts/merge-gate/) so the PR is clean. - **Out-of-scope findings survive as an issue.** Before creating a follow-up issue, each out-of-scope finding is re-verified against the current code (the cited snippet must still be present); only surviving findings are written, and a duplicate open issue is never created. - **Rollback is manual.** The loop never auto-reverts. If something went wrong, `git reset --soft ` undoes every commit it made. ### When to use it Use `/jkz:cr-fix` to clear CodeRabbit feedback on a PR — whether the PR came from the [pipeline](/commands/pipeline/) or from ad-hoc work. It is the PR-facing counterpart to the staged-changes loop in [`/jkz:commit`](/commands/commit/), and it shares the same classification discipline that the [review](/commands/review/) and [QA](/commands/qa/) phases use when they reconcile CodeRabbit findings. :::note `/jkz:cr-fix` fixes **multiple** findings in a loop. To accept a single CodeRabbit suggestion interactively with per-change approval, the `coderabbit:autofix` skill is the narrower tool. ::: ## debate Source: https://docs.j0kz.dev/commands/debate/ `/jkz:debate ` stages a structured argument between models so a hard decision gets pressure-tested from more than one direction before you commit to it. It is the on-demand version of the adversarial deliberation that jkz runs inside the pipeline — except you point it at any question, not just a plan or a diff. The premise is the same one that drives the whole system: a single model arguing with itself tends toward its own blind spots, while two or three models with different training challenge each other's reasoning. The debate surfaces the disagreement explicitly instead of hiding it inside one confident answer. ### At a glance | | | |------|------| | **Participants** | 2–3 models: Opus + an adversarial backend + a validator backend | | **Phases** | Constructive → Development → Crystallization | | **Early exit** | Unanimous consensus, a concession, or decisive execution evidence | | **Skill** | Runs the `debate-plan` protocol | | **Output** | A debate summary: positions, consensus, disagreements, recommendation | | **Usage** | `/jkz:debate ` · `/jkz:debate --models opus,adversarial` | ### When to use Reach for `/jkz:debate` when a decision is genuinely contested and the cost of getting it wrong is real — an architectural fork, a trade-off between two viable approaches, a claim you want stress-tested before it lands in a plan. It is deliberately *not* for simple questions or single-model tasks; a question with an obvious answer wastes the deliberation. If the topic is vague, the command asks you to sharpen it first: what question needs answering, what the competing options are, and what context matters. ### Key behavior By default the debate runs three kinds of model — one creative ([Opus](/agents/architect/)'s tier), one adversarial backend, and one validator backend — each seeing the others' prior arguments. You can narrow the panel with `--models`. The protocol moves through three phases: - **Constructive** — each model presents its position with evidence, in sequence, so later speakers see earlier ones. - **Development** — models challenge each other's positions and defend their own, grounded in evidence rather than assertion. - **Crystallization** — each model states a final position with a confidence level (HIGH / MEDIUM / LOW) and names the points of consensus and remaining disagreement. After every iteration the debate checks for an early exit: if the models reach unanimous consensus, if one concedes, or if execution evidence settles the question, the debate ends early and presents the result. The final output is a summary — positions, consensus, disagreements, a synthesized recommendation, and the strongest evidence cited — handed to you for the final decision. As with everything in jkz, the models deliberate; the human decides. ## deps Source: https://docs.j0kz.dev/commands/deps/ `/jkz:deps` audits the project's dependencies for known vulnerabilities and presents the results as a Markdown report. It can stop at reporting, apply the fixes that carry no breaking-change risk, or — behind an explicit confirmation gate — preview and apply breaking upgrades. ### At a glance | | | |------|------| | **Runs** | `deps-audit.js --dir ` | | **`--create-issue`** | File the findings as a `jkz:ready` issue | | **`--fix`** | Apply safe (non-breaking) fixes | | **`--fix --force`** | Preview breaking changes (exit code 2 — does **not** apply) | | **`--fix --force --confirmed`** | Apply breaking changes after human review | | **`--preventive`** | Scan multiple directories for vulnerabilities | | **Usage** | `/jkz:deps [--create-issue]` | ### When to use Run it on a cadence to stay ahead of advisories, or before a release to make sure no known-vulnerable package is shipping. Use `--fix` to clear the safe vulnerabilities in one pass; reach for `--fix --force` only when a remediation requires a breaking upgrade and you are ready to review the migration. ### Key behavior The audit reports vulnerabilities found in the dependency tree. The fix modes form a deliberate ladder of risk: - **`--fix`** applies only safe, non-breaking fixes and reports how many vulnerabilities were resolved and how many remain. - **`--fix --force`** runs in **preview mode** — it exits with code `2` and prints a table of breaking changes with migration hints, but applies nothing. - **`--fix --force --confirmed`** applies those breaking changes, and is meant to run only after you have reviewed the preview. - **`--preventive`** scans several directories at once (optionally scoped with `--preventive-dirs`), skipping any directory without a lockfile. **Compliance tiers.** When the audit can resolve an issue number (from an argument or the branch name), it reads that issue's compliance tier from pipeline state. Tier 2 auto-activates a full `--supply-chain` audit; tier 1 reports normally but recommends running with `--supply-chain` for the complete picture. This ties the depth of the audit to the regulatory weight of the work — see the [merge gate](/concepts/merge-gate/) for where these tiers come from. `--create-issue` writes the report to an issue body and files it through `issue-create.js` with the `jkz:ready` label. ## deslop Source: https://docs.j0kz.dev/commands/deslop/ `/jkz:deslop` strips the tells of AI-generated prose from your text files. Filler phrases, hedging words, verbose constructions, and over-used em dashes accumulate quietly in generated documentation; this command finds and removes them while preserving every bit of technical meaning. ### At a glance | | | |------|------| | **Scope** | Modified `.md` files this session, or a file you pass | | **Targets** | Filler, hedging, verbosity, em-dash overuse, redundant adverbs | | **Guarantee** | Preserves all technical content and meaning | | **Usage** | `/jkz:deslop []` | ### When to use Run it on documentation, READMEs, or comment-heavy files after a generation pass, before publishing prose you want to read cleanly. With no argument it cleans the `.md` files you changed this session (via `git diff`); pass a file to target one specifically. If nothing modified turns up, it asks which file you mean. ### What it cleans - **Filler phrases** — "It's worth mentioning", "It should be noted that", "As mentioned earlier", "In this context". - **Hedging** — "Essentially", "Basically", "Fundamentally", "Significantly", "Effectively". - **Verbose constructions** — "In order to" → "To", "Utilize" → "Use", "Prior to" → "Before", "Due to the fact that" → "Because". - **Em-dash overuse** — more than two em dashes in a single paragraph; the extras become commas or periods. - **Redundant adverbs** — "very unique", "completely eliminate", "absolutely essential". - **Bullet repetition** — consecutive bullets that all open with the same word pattern. ### Key behavior The command applies the fixes — removing filler (and fixing the sentence capitalization that follows), swapping verbose constructions for concise alternatives, thinning excess em dashes, dropping redundant adverbs, and varying bullet openings — then reports the changes per file with before/after examples. Technical content and meaning are left untouched. This is the prose counterpart to [`/jkz:simplify`](/commands/simplify/), which does the same kind of cleanup for code rather than writing. ## dev-self-review Source: https://docs.j0kz.dev/commands/dev-self-review/ `/jkz:dev-self-review` is an internal consistency check you run *before* opening a PR. It collects everything you've changed relative to `main`, works out which parts of the jkz integration checklist apply, and dispatches a fresh reviewer subagent to read the diff as a whole — the kind of cross-file mismatch that is invisible while you're editing one file at a time. ### Usage ``` /jkz:dev-self-review ``` It reviews **all** pending changes — committed on the branch, staged, unstaged, and untracked — with no arguments. If there are no changes, it says so and exits. ### How it works ```mermaid flowchart LR diff["Collect full diff
(committed + staged + unstaged + untracked)"] --> scope["Identify which
checklist categories apply"] scope --> ctx["Read the full context files
(not just the diff)"] ctx --> rev["Dispatch reviewer subagent"] rev --> verdict(["PASS / NEEDS_FIX"]) ``` - **Deterministic diff collection.** The command unions committed (`main...HEAD`), staged, unstaged, and untracked files so nothing in flight is missed — untracked files are read in full. - **Scope-driven checklist.** Which checklist categories are active depends on what you touched: editing `step-gate.js` activates the DEPS and checkpoint-map checks; editing command files or `review.md` / `qa.md` / `build.md` activates crash-recovery and wrapper-invocation checks; touching `CLAUDE.md`, the [rules](/reference/architecture/) files, or the docs activates documentation-sync; touching agent definitions activates the agent-capabilities check. - **Full context, not just the patch.** The reviewer reads the *whole* files involved in an integration, because a consistency problem usually lives in the relationship between a changed line and an unchanged one. - **Fresh subagent.** The reviewer ([`feature-dev:code-reviewer`](/agents/judge/) on Opus) does not inherit your read history — everything it needs is put in its prompt. It returns a findings table and a verdict: **PASS** (ready to open the PR) or **NEEDS_FIX** (fix and re-run). ### When to use it Run `/jkz:dev-self-review` just before opening a PR on jkz itself — especially after a change that spans commands, rules, docs, or agent definitions, where a single edit can leave two files out of sync. It is a lighter, self-directed cousin of the pipeline's [review phase](/commands/review/): no PR is required, and the goal is to catch integration drift early rather than to gate a merge. ## doc-sync Source: https://docs.j0kz.dev/commands/doc-sync/ `/jkz:doc-sync` checks whether the documentation still matches reality. It scans the current project state and compares it against the auto-doc markers embedded in the docs, then reports each discrepancy — the places where the code moved on and the prose didn't. ### Usage ``` /jkz:doc-sync [--no-llm] [--json] [--file ] [--create-issues] ``` | Flag | Effect | |------|--------| | *(none)* | Scan and present the discrepancies in Markdown | | `--no-llm` | Run the deterministic scan only, without the LLM pass | | `--json` | Emit machine-readable output | | `--file ` | Restrict the check to a single doc | | `--create-issues` | Open one `jkz:ready` issue per doc whose discrepancy count is greater than zero | ### Key behavior - **Marker-driven comparison.** The check runs `doc-sync.js`, which reads the auto-doc markers in the documentation and compares them against the scanned project state, surfacing per-doc discrepancies. - **`--create-issues` turns drift into work.** With this flag, each doc that has drifted gets its own `jkz:ready` issue, deduplicated against existing open issues with the same title. This is how the [Hermes](/reference/architecture/) Mon+Thu cron keeps unactioned drift from sitting silently in otherwise-green reports. The flag is skipped when combined with `--no-llm`. - **Output you can pipe.** The default presentation is Markdown for a human; `--json` makes it consumable by other tooling. ### When to use it Run `/jkz:doc-sync` after a change that alters something the docs describe — a renamed flag, a new label, a moved script — to confirm the documentation kept up. On its own it is a read-only report; reach for `--create-issues` when you want the drift converted into tracked work rather than just listed. It pairs naturally with the documentation-sync category of [`/jkz:dev-self-review`](/commands/dev-self-review/), which catches the same class of drift in a single pending diff. ## e2e Source: https://docs.j0kz.dev/commands/e2e/ `/jkz:e2e` drives a real browser through your running application. Opus generates test scenarios by exploring the codebase for routes and user flows, then Sonnet executes each scenario step by step via the `agent-browser` CLI. The result is a report — passes, failures, and screenshots — that you read, not a gate the pipeline enforces. ### At a glance | | | |------|------| | **Generates** | Scenarios via an Opus subagent | | **Executes** | Steps via Sonnet driving `agent-browser` | | **URL cascade** | `--url` → `JKZ_E2E_BASE_URL` → prompt | | **Output** | Per-run report and screenshots under `state/e2e/` | | **Results** | **Advisory** — never block the pipeline | | **Usage** | `/jkz:e2e [--url ]` | ### When to use Run it against a locally running build (or any reachable URL) when you want to exercise critical user flows — navigation, forms, authentication — end to end. It is a manual command: invoke it when you want the coverage, not as part of every pipeline run. ### Prerequisites `agent-browser` must be installed (`npm install -g agent-browser`); the command stops early if it is missing. The target app must be reachable at the resolved URL — `/jkz:e2e` checks before generating any scenarios and stops if the app is down. ### Key behavior The base URL is resolved from the `--url` argument, then the `JKZ_E2E_BASE_URL` environment variable, and finally by asking you. Each run gets its own timestamped directory under `state/e2e/` holding the generated `scenarios.json`, per-scenario results, screenshots, and an aggregated `report.md`. - **Scenario generation** — Opus inspects `package.json`, router configs, page components, and API routes, then emits up to `JKZ_E2E_MAX_TESTS` (default 10) self-contained scenarios as JSON. Each scenario opens its own page and closes the browser at the end. - **Execution** — Sonnet runs each step through `agent-browser` (`open`, `click`, `fill`, `assert_visible`, and so on), verifying the result before moving on. Screenshots follow `JKZ_E2E_SCREENSHOT_MODE` (default `on-failure`; also `always` or `never`). - **Report** — results are aggregated into a summary table and failure details. Because the results are advisory, `/jkz:e2e` complements rather than replaces the gated review in the [QA phase](/commands/qa/) — it tells you whether the app *behaves* correctly in a browser, which static review cannot. ## fix Source: https://docs.j0kz.dev/commands/fix/ `/jkz:fix --source ` is the **fix cycle**. It is rarely something you invoke by hand — `/jkz:review`, `/jkz:qa`, and [`/jkz:quick`](/commands/quick/) call it automatically whenever a reviewer returns FAIL. Its job: take the failing verdict, apply a minimal targeted fix, and re-run the phase that failed. The agent behind it is the **[Doctor](/agents/doctor/)** (Claude Opus) — the surgeon of the pipeline. It changes exactly what broke and nothing more: no scope creep, no opportunistic refactors. ### Usage ``` /jkz:fix --source review # re-run review (Judge + Inspector) after the fix /jkz:fix --source qa # re-run QA (Lens + Sentinel) after the fix ``` `--source` tells the cycle which phase failed and therefore which agents to re-trigger after the patch. ### What happens inside one cycle ```mermaid flowchart LR fail(["Reviewer FAIL"]) --> flaky{"Flaky?"} flaky -- yes --> rerun(["Re-run · no attempt spent"]) flaky -- no --> classify["Classify failure
(8 categories)"] classify --> guard["Loop guard
(iter 2+)"] guard --> doctor["Doctor applies
minimal patch"] doctor --> retrigger(["Re-trigger failed phase"]) ``` 1. **Gather feedback.** Collect the CRITICAL / HIGH findings from the failing verdict (compact `verdict-json` signals on later iterations, full PR comments on the first). 2. **Flaky check.** A classifier spots flaky test failures and re-runs the phase *without* counting it as a fix attempt — a flaky test should not burn the Doctor's budget. 3. **Classify the failure** into one of eight categories (implementation bug, missing validation, missing error handling, security vulnerability, missing requirement, test gap, wrong approach, regression). If the category is `wrong_approach`, a one-time gate lets the [Architect](/agents/architect/) rewrite the plan before the Doctor tries again (max one rewrite per pipeline). 4. **Loop guard.** From iteration 2 on, jkz compares the new diff against the previous attempt. A near-identical diff triggers a warning so the Doctor changes strategy instead of repeating a dead end. 5. **Fix and re-trigger.** The Doctor applies the patch and the diff goes back through the failed phase — review ([Judge](/agents/judge/) + Inspector) or QA ([Lens](/agents/lens/) + [Sentinel](/agents/sentinel/)). This repeats **up to three attempts**. If three fixes still don't clear the verdict, the issue moves to `jkz:blocked` and escalates to you with a diagnosis of what was tried — **honest escalation over a silent hack** that merely passes the checks. ### When it fires - **Automatically**, whenever the Judge, Inspector, Lens, or Sentinel returns FAIL during a review or QA phase. - **Manually**, when you want to re-run the Doctor against a known-failing PR: `/jkz:fix --source review` (or `--source qa`). :::note[Deep dive] This page is the command reference. The fix cycle is covered in context alongside [`/jkz:quick`](/commands/quick/) in [Lightweight routes](/build/lightweight-routes/). Source of truth: `.claude/commands/jkz/fix.md` in the private repo. ::: ## health Source: https://docs.j0kz.dev/commands/health/ `/jkz:health` is the system's self-diagnostic. It checks the tools jkz depends on, tells you which ones are out of date and *why that matters*, and surfaces the infrastructure signals — stale worktrees, incomplete deliberations, API reachability — that quietly accumulate during real work. It is the interactive surface over the same health data that the session-start banner and the monitoring loop read. ### At a glance | | | |------|------| | **Checks** | CLI versions, changelogs, relevance insights, infrastructure | | **`--fix`** | Auto-update outdated CLIs and clean stale worktrees | | **`--deep`** | Add auth, MCP, and notification checks | | **Reads** | `health-check.sh`, changelog review, desire-path and permission audits | | **Usage** | `/jkz:health [--fix \| --deep]` | ### When to use Run `/jkz:health` when the session-start banner flags outdated CLIs or stale data, before a long pipeline run, or whenever something feels off in the toolchain. Use `--fix` when you want it to act on what it finds — updating CLIs and cleaning up stale [worktrees](/concepts/worktree-isolation/) — and `--deep` before relying on auth, MCP servers, or notifications. ### Key behavior The command runs `health-check.sh` with flags derived from your arguments, then presents the result in sections: - **CLI versions** — a table of installed-vs-latest for each tool jkz uses, marking which are outdated. The version data is also summarized on the [CLI reference](/reference/cli/) page. - **Changelog highlights** — for each outdated CLI, the breaking changes (flagged **BREAKING**) and notable features or fixes, plus a relevance analysis that ranks which changes actually matter to jkz and suggests actions. - **Desire paths** — unknown flags or commands that agents have tried, surfaced so real gaps in the tooling become visible. - **Frozen artifacts** *(plugin mode only)* — drift between the installed plugin and its frozen artifacts, with an update suggestion when they diverge. - **Permission audit** — a scan for dangerous `allowedTools` patterns, highlighting critical findings. - **Infrastructure** — GitHub API reachability, stale worktree count, incomplete deliberations, and — in `--deep` mode — auth, MCP, and notification status. When `--fix` is not passed but outdated CLIs or stale worktrees are found, the command points you to `/jkz:health --fix` rather than acting silently. The cleanup it offers respects the same safety rules as the rest of the system — it never removes a locked worktree or one with uncommitted changes (see [worktree isolation](/concepts/worktree-isolation/)). ## insights Source: https://docs.j0kz.dev/commands/insights/ `/jkz:insights` reads the deliberation record in `state/deliberations/` and turns it into pipeline analytics: how often each role passes, how much agents agree within a phase, how many tokens they burn, and whether the run is staying inside its SLOs. It is the command for stepping back from any single run and asking how the deliberation system as a whole is behaving over time. Alongside the headline metrics it runs a groupthink monitor, because the entire premise of jkz — adversarial models challenging each other — fails quietly if the validators start rubber-stamping the adversarials. The insights surface that drift before it hides inside a confident-looking pass rate. ### At a glance | | | |------|------| | **Source** | Deliberation history in `state/deliberations/` + `state/memory.db` | | **Core metrics** | Pass rates, agent agreement, token usage, SLO status | | **Groupthink** | Agreement rate, directional asymmetry, validator novelty | | **Optional** | `--skills` (candidate skills) · `--trends` (14d vs prior 14d) | | **Usage** | `/jkz:insights` · `/jkz:insights --trends` · `/jkz:insights --role judge` | ### When to use Run `/jkz:insights` periodically once a pipeline has accumulated history — patterns become reliable after roughly ten real runs. It is the right tool when a role seems to be failing too often, when you suspect validators are no longer adding independent signal, or when you want to confirm the pipeline is operating within its defined SLOs before trusting its verdicts. ### Key behavior The command runs two scripts and presents both: `analyze-deliberations.js` for the core metrics and `groupthink-monitor.js` for independence signals. It accepts filters — `--role`, `--phase`, `--json` — and two analytical add-ons: `--trends` compares the last 14 days against the prior 14 (improving, declining, or stable per role), and `--skills` runs skill discovery to cluster recurring patterns into candidate skills. Each metric comes with an interpretation. A role under 50% pass rate across two or more real runs flags its agent definition for review; agreement below 70% suggests prompts that need aligning, while above 90% signals strong calibration. On the groupthink side, an agreement rate above 85% or validators consistently more lenient than adversarials are the warnings that the panel is no longer providing independent signal. Where data is thin — fewer than ten runs, or pre-enrichment records showing `phase: unknown` — the command says so rather than over-reading the numbers. ## issue Source: https://docs.j0kz.dev/commands/issue/ `/jkz:issue` creates a GitHub issue **directly** from a plan file or a free-text description. It is the counterpart to [`/jkz:start`](/commands/start/): where `/jkz:start` walks a conversational funnel (triage, duplicate check, targeted questions), `/jkz:issue` assumes you already know what you want and turns your input into a properly labeled, classified issue in one pass. ### Usage ``` /jkz:issue --from-plan Create an issue from a plan file /jkz:issue Create an issue from a free-text description ``` - `--from-plan ` reads an existing plan file. The path is canonicalized and **must resolve inside the repository** — a trust boundary for user-supplied paths. The title is taken from the first `# ` heading, falling back to the file name. - `` takes free text directly. The title is derived from the first line. ### What it does ```mermaid flowchart TD input(["Plan file or free text"]) --> type["Classify issue type
(bug · feature · refactor · chore)"] type --> triage["Derive triage level
(urgency keywords → normal/critical)"] triage --> enrich["Phase 1 · pre-merge enrichment
(CBM scope · implementation detection · template)"] enrich --> gate{"Existing
implementation?"} gate -- "yes" --> ask["Human gate · continue anyway?"] gate -- "no" --> create ask -- "continue" --> create["Phase 2 · create
(classify · gh create · alignment · state)"] ask -- "cancel" --> stop(["Stop · investigate first"]) create --> reco(["Issue created · route recommended"]) ``` 1. **Type classification.** The issue type (`bug` / `feature` / `refactor` / `chore`) is detected from the content and title. The type drives the label and downstream pipeline focus. 2. **Triage.** Urgency keywords (`urgent`, `blocker`, `critical`, `hotfix`, `production`, `regression`, …) bump the triage level from `normal` to `critical`. 3. **Pre-merge enrichment.** A first pass enriches the body with codebase-memory scope, selects a template, and — importantly — runs **implementation detection**: it looks for code that may already implement what the issue describes. 4. **Implementation gate.** If existing implementations are detected, `/jkz:issue` shows the matching files and asks whether to create the issue anyway. Choosing *cancel* stops so you can investigate before filing a near-duplicate of already-shipped work. 5. **Create.** The second phase classifies complexity, creates the issue via the issue primitive (baking in the `jkz:ready` label plus the type label), runs the alignment checkpoint, registers any `Blocked by: #N` relationships, and writes pipeline state. ### What you get A new issue labeled `jkz:ready` (plus a type label and a `complexity:*` classification), and a single routing recommendation based on the classified complexity: | Complexity | Recommendation | |------------|----------------| | `trivial` | Apply directly in chat — no pipeline | | `quick` | [`/jkz:quick `](/commands/quick/) — the lightweight route | | `standard` | [`/jkz:pipeline `](/commands/pipeline/) — the full pipeline | `/jkz:plan ` (planning only) is always offered as an alternative. **You decide which route to take** — `/jkz:issue` files the issue and recommends, it does not start a pipeline. :::note[Why a primitive, not raw `gh issue create`] Issues always flow through the issue primitive so they pick up the `jkz:ready` label, the type label, the complexity classification, and the alignment checkpoint. A guard hook blocks raw `gh issue create` for exactly this reason — see [conventions](/reference/architecture/). ::: ### Related - [`/jkz:start`](/commands/start/) — the conversational entry point that creates an issue from a vague idea. - [`/jkz:refine`](/commands/refine/) — enrich an existing issue with a brief before planning. ## load Source: https://docs.j0kz.dev/commands/load/ `/jkz:load` is the other half of [`/jkz:save`](/commands/save/). It retrieves the **most recent session snapshot** — typically written by another chat at shutdown — and presents it so you can continue where that session left off, with its reasoning context intact rather than reconstructed from the git log. ### Usage ``` /jkz:load ``` No arguments. `/jkz:load` finds the latest snapshot and the current pipeline state. ### What it shows ```mermaid flowchart TD snap["Display latest snapshot"] --> mem["Show session memory
(if available)"] mem --> state["Read pipeline STATE.json"] state --> present["Present a unified summary"] present --> ask(["What would you like to work on?"]) ``` The summary pulls together, from the snapshot and pipeline state: - **What was done** — completed work and the decisions made. - **What worked / didn't** — approaches to keep and approaches to avoid. - **Pipeline status** — phase and PR, from the snapshot plus `STATE.json`. - **Next steps** — what the previous session intended to do next. - **Gotchas** — pitfalls flagged for whoever picks the work up. - **Git state** — branch, uncommitted changes, recent commits. If no snapshot is found, `/jkz:load` falls back to `.claude/context.md` and presents that instead. It closes by asking what you'd like to work on. :::note[Cross-chat continuity] Snapshots are stored per-chat under `state/session-snapshots/`. `/jkz:load` retrieves the **most recent** one — which is usually from a *different* session, exactly the case where loading is most useful. See [cross-chat awareness](/concepts/cross-chat/). ::: ### Related - [`/jkz:save`](/commands/save/) — capture the snapshot that `/jkz:load` reads. - [`/jkz:quit`](/commands/quit/) — orderly shutdown; saves the snapshot you'll later load. ## memory-promote Source: https://docs.j0kz.dev/commands/memory-promote/ `/jkz:memory-promote ` evaluates one memory file and answers a focused question: is this worth promoting into a durable rule, should it stay a memory, or has it earned archival? It is the per-file complement to [`/jkz:memory-review`](/commands/memory-review/), which surfaces *which* files are promotion candidates; this command decides what to do with a specific one. A memory that recurs, is non-obvious, and is not already documented elsewhere is a candidate for promotion to a rule or a CLAUDE.md section, where it carries more weight and applies more consistently. The scoring makes that judgment explicit rather than leaving it to intuition. ### At a glance | | | |------|------| | **Input** | One memory filename (lists available files if omitted) | | **Score** | Five weighted dimensions, totalled | | **Recommendation** | `promote` · `keep` · `archive` | | **Gate** | Human checkpoint — no automatic action | | **Usage** | `/jkz:memory-promote feedback_checkpoint_context.md` | ### When to use Run `/jkz:memory-promote` on the candidates that [`/jkz:memory-review`](/commands/memory-review/) flags, or any time you are unsure whether a memory has graduated into something that belongs in the rules. It is a scoring-and-decision tool, not a bulk operation — point it at one file at a time. ### Key behavior If no filename is supplied, the command lists the available memory files and asks which to evaluate. It then scores the file across five weighted dimensions — document redundancy (×0.30), pattern (×0.20), specificity (×0.20), relevance (×0.15), and uniqueness (×0.15) — and presents the breakdown with a total and a recommendation of **promote**, **keep**, or **archive**. Crucially, it stops there. The command never acts on its own: promotion, retention, and archival all wait on your decision at a human checkpoint. If you choose to promote, it asks where the content should land — a new rule file, a CLAUDE.md section — and implements it; archival is confirmed before anything is deleted. ## memory-review Source: https://docs.j0kz.dev/commands/memory-review/ `/jkz:memory-review [--stale-days N]` is the full audit of your memory directory. Where [`/jkz:memory-status`](/commands/memory-status/) gives you the headline, this command shows the detail: which files have gone stale, which pairs overlap, which memories are already covered by an existing rule, which are missing their structural markers, and which are worth promoting. The goal is curation. Memory accretes — a healthy directory is one that is periodically pruned of the stale and the redundant, so the remaining signal is the signal that belongs in context. ### At a glance | | | |------|------| | **Output** | Six sections: stale, overlaps, redundancy, needs-rewrite, promotion candidates, stats | | **Defaults** | 30-day stale threshold, 0.6 overlap similarity | | **Tuning** | `--stale-days ` to change the stale window | | **Companions** | [`/jkz:memory-status`](/commands/memory-status/) · [`/jkz:memory-promote`](/commands/memory-promote/) | | **Usage** | `/jkz:memory-review` · `/jkz:memory-review --stale-days 60` | ### When to use Run `/jkz:memory-review` when [`/jkz:memory-status`](/commands/memory-status/) reports `needs_review` or `critical`, or on a regular cadence to keep the directory lean. It is the right tool when memory feels noisy, when you suspect duplicate entries, or before deciding whether a particular memory has outlived its usefulness. ### Key behavior The command runs `memory-curate.js` in review mode and presents the results as six markdown tables: - **Stale files** — name, age in days, and the date source the age was derived from. - **Overlapping pairs** — two files and their similarity percentage, candidates for merging. - **Redundancy analysis** — each memory classified as `new_rule`, `extends_existing`, or `already_covered`, with the matched section and source. - **Needs rewrite** — files missing the `**Why:**` and/or `**How to apply:**` markers. - **Promotion candidates** — memories worth scoring with [`/jkz:memory-promote`](/commands/memory-promote/). - **Stats** — totals, by-type breakdown, and redundancy summary counts. Each section comes with a suggested action: merge overlaps, archive `already_covered` entries, add missing markers to rewrite candidates, and run [`/jkz:memory-promote`](/commands/memory-promote/) on promotion candidates. The command surfaces findings and recommends — it does not delete or rewrite on its own. ## memory-status Source: https://docs.j0kz.dev/commands/memory-status/ `/jkz:memory-status` is the at-a-glance view of your memory directory's health. It answers a single question fast: is the memory in good shape, or does it need attention? Run it when you want the headline numbers without the full audit. It is the lightest of the three memory commands — a dashboard, not an investigation. When it flags trouble, it points you at [`/jkz:memory-review`](/commands/memory-review/) for the details. ### At a glance | | | |------|------| | **Output** | Health verdict + key metrics + by-type breakdown | | **Metrics** | Total files, stale (>30d), overlap pairs | | **Verdict** | `good` · `needs_review` · `critical` | | **Companions** | [`/jkz:memory-review`](/commands/memory-review/) · [`/jkz:memory-promote`](/commands/memory-promote/) | | **Usage** | `/jkz:memory-status` | ### When to use Run `/jkz:memory-status` as a periodic pulse check on the memory directory, or whenever a session start warns that memory may be drifting. It does no analysis of its own beyond surfacing the counts — its job is to tell you, quickly, whether deeper curation is warranted. ### Key behavior The command runs `memory-curate.js` in status mode and renders a compact dashboard: a health verdict, a metrics table (total files, stale files older than 30 days, overlap pairs), and a by-type breakdown. The verdict drives the next step — `good` means no action; `needs_review` and `critical` both send you to [`/jkz:memory-review`](/commands/memory-review/) to identify what needs fixing. ## new-chat Source: https://docs.j0kz.dev/commands/new-chat/ `/jkz:new-chat` creates an isolated workspace for a **second Claude Code window** on the same project — without file or branch collisions with your current session. It builds a git [worktree](/concepts/worktree-isolation/) as a sibling directory of the repo, on a fresh branch, and copies the config the new session needs to start immediately. ### Usage ``` /jkz:new-chat [--from ] ``` - `` — a short descriptor matching `[a-z0-9][a-z0-9-]{0,30}` (e.g. `docs-audit`, `pr-921`, `spike-eval`). Required. - `--from ` — base the new worktree on `` instead of `main`. Optional; rarely needed — prefer branching from `main` unless you're deliberately stacking on in-flight work. ### What it does The new worktree: - lives as a **sibling directory** of the repo, - sits on a **fresh branch** based on `origin/main` by default (or `--from `), - has its own working tree and its own `HEAD`, - inherits `.env` and `.claude/settings.local.json`, so the new session is ready to go. On success you'll see the worktree path, the new branch name, and which config files were copied. Then **open a new Claude Code window** with that path as the working directory. Your current session stays put, on its own branch in the original repo. ### Cleanup When the parallel session is done, from any clone: ```bash git worktree remove git branch -D chat/- # if the branch is no longer needed ``` :::note[new-chat vs. pipeline worktrees] `/jkz:new-chat` is for *you* — a deliberate second window for parallel exploration. It is distinct from the per-issue worktrees the pipeline creates automatically when you run [`/jkz:quick`](/commands/quick/) or [`/jkz:pipeline`](/commands/pipeline/). See [worktree isolation](/concepts/worktree-isolation/) for how the two layouts differ. ::: ### Related - [Worktree isolation](/concepts/worktree-isolation/) — the isolation model behind parallel chats. - [Cross-chat awareness](/concepts/cross-chat/) — coordinating multiple sessions on one project. ## perf-audit Source: https://docs.j0kz.dev/commands/perf-audit/ `/jkz:perf-audit` looks for performance improvements, but holds every proposal to a deliberately high bar. An optimization is accepted only if it is **measurably impactful, behaviorally identical, and cleanly contained**. That strictness is intentional: it rejects cosmetic micro-optimizations that usually pass as performance work. ### At a glance | | | |------|------| | **Scope** | Files modified this session, or a path you pass | | **Gate** | Three criteria — all must PASS or the proposal is rejected | | **Action** | Applies only the accepted proposals | | **Usage** | `/jkz:perf-audit []` | ### The three criteria Every proposed optimization must pass **all three**. If any one fails, the proposal is rejected. 1. **Needle-moving** — it reduces algorithmic complexity (for example O(n²) → O(n log n)), eliminates redundant I/O, or measurably cuts memory allocation. A cosmetic rename or a "best practice" with no measurable impact fails this test. 2. **Isomorphic** — for all valid inputs the output is identical to the original. Anything that changes observable behavior, error handling, or side effects fails. 3. **Clear path** — the change is contained within the scope files and needs no cascading dependency, test, or interface changes. Touching a public contract fails. ### When to use Run it after writing or changing hot-path code, or when you suspect a function is doing more work than it needs to. With no argument it audits the files you changed this session (via `git diff`); pass a file or directory to target something specific. Non-code files — Markdown, config JSON, lockfiles — are skipped. ### Key behavior For each candidate the command profiles algorithmic complexity, I/O patterns, and memory behavior, then evaluates the change against the three criteria with an explicit PASS/FAIL and supporting evidence — a Big-O proof, an I/O-count reduction, or a memory delta. It reports accepted and rejected proposals (the rejected ones with their reason), then **applies only the accepted changes**, preserving existing functionality. This is the efficiency-focused sibling of [`/jkz:simplify`](/commands/simplify/), which targets readability and reuse rather than raw performance. ## pipeline Source: https://docs.j0kz.dev/commands/pipeline/ `/jkz:pipeline ` runs the complete jkz pipeline end to end with minimal intervention. It is the route for `standard`-complexity work — a feature that spans layers, a refactor with design decisions, anything where the plan deserves a checkpoint before code is written and QA deserves a checkpoint before merge. The pipeline is autonomous, not unattended. Plan approval happens **pre-flight**, before the loop starts. Then, inside the loop, you intervene at exactly three points: the review approval, the QA approval, and the final manual merge. Everything between those gates — agent dispatch, iteration, fix cycles — runs on its own. ### At a glance | | | |------|------| | **Phases** | Plan → Build → Review → QA → Completion | | **Human checkpoints** | 3: review approval, QA approval, manual merge | | **Plan approval** | Pre-flight (before the loop) | | **Best for** | `standard` complexity — multi-layer features, refactors with design decisions | | **Worktree** | Auto-enters an isolated per-issue worktree | | **Usage** | `/jkz:pipeline [--resume] [--from ] [--silent]` | ### When to use Reach for `/jkz:pipeline` when the [complexity classifier](/build/lightweight-routes/) sizes an issue as `standard`: the work touches multiple system layers, carries non-obvious implications, or needs a design decision before implementation. If the change is a one-liner, a typo, or a scoped fix, the [lightweight routes](/build/lightweight-routes/) (`/jkz:quick`, `/jkz:fix`) are the better fit — running a full Plan → Build → Review → QA loop on a trivial change wastes both tokens and your time. ### Key behavior The pipeline walks every phase of the [full pipeline](/get-started/how-jkz-works/), reusing each phase command's steps and overriding only the checkpoint behavior: - **Plan** — [Architect](/agents/architect/) → [Auditor](/agents/auditor/) → [Curator](/agents/curator/), iterating up to 3×, then a human approval checkpoint *before* the loop continues. - **Build** — [Builder](/agents/builder/) implements inside the worktree and opens a PR, followed by the review's prescan and fix loop. - **Review** — [Judge](/agents/judge/) → [Inspector](/agents/inspector/), with the [Doctor](/agents/doctor/) fixing failures (up to 3×), then your review approval. - **QA** — [Lens](/agents/lens/) and [Sentinel](/agents/sentinel/) run in parallel; the Doctor fixes any failure. QA is required for features and optional for `bug` / `refactor` / `chore`. - **Completion** — the PR is left ready for the human merge. The pipeline never merges on its own — that gate is enforced server-side by the [merge gate](/concepts/merge-gate/). Each phase runs inside an isolated [per-issue worktree](/concepts/worktree-isolation/), so parallel pipelines on different issues never collide. The run is resumable: `--resume` continues from the persisted `current_phase`, and `--from ` starts at a specific phase. `--silent` collapses status notifications to terse one-liners for unattended runs. ### Where it fits `/jkz:pipeline` is the orchestrated superset of the individual phase commands (`/jkz:plan`, `/jkz:build`, `/jkz:review`, `/jkz:qa`). Use those when you want to drive a single phase by hand; use `/jkz:pipeline` when you want the whole thing to run with three checkpoints. See [How jkz works](/get-started/how-jkz-works/) for the phases in full context. ## plan Source: https://docs.j0kz.dev/commands/plan/ `/jkz:plan ` runs the **first phase** of the pipeline: it turns a GitHub issue into an approved implementation strategy before a single line of code exists. The [Architect](/agents/architect/) designs the plan, the [Auditor](/agents/auditor/) attacks it, and the [Curator](/agents/curator/) calibrates that audit — iterating up to three times — and then it stops and waits for you. Nothing is built until you approve the plan. ### What it does The command orchestrates the **plan** phase of [the pipeline](/get-started/how-jkz-works/): ```mermaid flowchart LR issue(["Issue · jkz:ready"]) --> A["Architect drafts"] A --> Au["Auditor challenges"] Au --> Cu["Curator validates"] Cu -. "FAIL · iterate up to 3x" .-> A Cu --> H{{"Human approves plan
+ post-plan ambiguity gate"}} H --> build(["jkz:building"]) ``` - The **Architect** (Claude Opus) designs the approach: the key decisions, the scope boundaries, the files to touch, the build sequence, and the verification criteria. - The **Auditor** (adversarial backend) challenges that plan the way a skeptic evaluates a proposal — it ignores the effort and asks what is missing, what is vague, and what will fail. - The **Curator** (validator backend) validates the audit itself, catching miscalibrated severities and false positives. This repeats up to **three iterations**. Each handoff is a Git artifact — the plan and every review land as comments on the issue, never as a direct conversation between agents. ### When to run it - Before any build, on a `standard`-complexity issue that needs a design decision documented and reviewed. - When you want a human checkpoint on the approach before committing engineering effort. - As the first stage of `/jkz:pipeline`, which chains plan → build → review → QA automatically. For trivial or quick-complexity work, skip planning entirely and use [`/jkz:quick`](/build/lightweight-routes/) (Builder + Judge, no plan). ### Inputs | Input | Required | Notes | |-------|----------|-------| | Issue number | Yes | `/jkz:plan `. If no issue exists yet, create one first. | | Issue body + labels | Read automatically | The requirements, type label, and any `complexity:*` label. | | Codebase context | Gathered automatically | The Architect uses Glob/Grep to find and read the files relevant to the task. | | Dependency blockers | Checked automatically | A `Blocked by: #N` relationship on an open issue surfaces as a warning before planning. | The command enters an isolated per-issue [worktree](/concepts/worktree-isolation/) before doing any work. ### What phase it drives | | | |--|--| | Phase label | `jkz:ready` → `jkz:planning` → `jkz:building` (on approval) | | Iterations | Up to 3 (Architect → Auditor → Curator), then escalate or checkpoint | | Active agents | [Architect](/agents/architect/), [Auditor](/agents/auditor/), [Curator](/agents/curator/) | ### How issue type changes the plan The Architect's focus shifts with the issue's type label: | Type | Plan focus | |------|-----------| | `feature` | Implementation design | | `bug` | Root-cause analysis | | `refactor` | Current → target state | | `chore` | Mechanical change | ### Human checkpoint The plan phase ends at a **mandatory human checkpoint** — one of the few points where the pipeline hands control back to you: 1. **Post-plan ambiguity gate.** An Opus scan classifies any ambiguity as `TRIVIAL`, `FIX`, or `DECIDE`. A `DECIDE` item needs your call before approval. 2. **Plan approval.** Unlike the review and QA checkpoints, the plan *is* the artifact under review — so it is displayed in full in the chat. You read it and approve it. Approval transitions the issue to `jkz:building`; nothing is built until you do. ### See also - [How jkz works](/get-started/how-jkz-works/) — the plan phase in the full pipeline flow. - [Architect](/agents/architect/) · [Auditor](/agents/auditor/) · [Curator](/agents/curator/) — the three agents this command dispatches. - [`/jkz:build`](/commands/build/) — the next phase, once the plan is approved. - [Lightweight routes](/build/lightweight-routes/) — `/jkz:quick` when a change is too small to plan. - [CLI / commands](/reference/cli/) — every `/jkz:*` command at a glance. ## qa Source: https://docs.j0kz.dev/commands/qa/ `/jkz:qa ` runs the final review phase before merge. [Lens](/agents/lens/) (validator backend) and [Sentinel](/agents/sentinel/) (adversarial backend) review the pull request **in parallel** — Lens owns what the user sees, Sentinel owns the operation and the attack surface. A FAIL routes to the [Doctor](/agents/doctor/), up to three times. QA is required for features and optional for smaller changes. ### What it does The command orchestrates the **QA** phase of [the pipeline](/get-started/how-jkz-works/): ```mermaid flowchart LR pr(["jkz:qa
(review passed)"]) --> P["Pre-validated checks"] P --> L["Lens · frontend / a11y"] P --> S["Sentinel · backend / security"] L -- PASS --> H{{"Post-QA ambiguity gate"}} S -- PASS --> H L -. "FAIL · Doctor · up to 3x" .-> L S -. "FAIL · Doctor · up to 3x" .-> S H --> merge[["Human merges · 4-layer merge gate"]] ``` - **Lens** owns the frontend: visual fidelity, multimodal output, and accessibility. - **Sentinel** owns the operation: backend integrity, security posture, performance, and infrastructure. - They run **in parallel** — the one case where two agents work the same issue at once. - A FAIL from either routes to the [Doctor](/agents/doctor/) for a surgical fix, then back through QA, up to three attempts. - After a PASS, a CR reconciliation closes out any remaining CodeRabbit-bot findings. ### When to run it - After [`/jkz:review`](/commands/review/) passes, for any `feature` issue. - As the QA stage of `/jkz:pipeline`, which runs it automatically after review. QA is **required** for `feature` issues and **optional** for `bug`, `refactor`, and `chore` — small, scoped changes can skip it. ### Inputs | Input | Required | Notes | |-------|----------|-------| | PR number | Yes | `/jkz:qa `. The PR should have passed `/jkz:review`. | | PR diff | Read automatically | Lens and Sentinel receive the full diff. | | Pre-validated checks | Computed automatically | Deterministic findings injected into the Sentinel prompt. | ### What phase it drives | | | |--|--| | Phase label | `jkz:qa` → `jkz:approved` (PASS) or `jkz:fixing` (FAIL) | | Iterations | Up to 3 Doctor fix cycles on FAIL | | Active agents | [Lens](/agents/lens/), [Sentinel](/agents/sentinel/), [Doctor](/agents/doctor/) on FAIL | | Parallelism | Lens and Sentinel run concurrently | ### Human checkpoint QA ends at the **last two human-facing gates** before code reaches `main`: 1. **Post-QA ambiguity gate.** The same Opus scan as the plan phase runs again — classifying ambiguities as `TRIVIAL`, `FIX`, or `DECIDE` — surfacing anything that needs your decision after QA. 2. **The merge.** Only you merge to `main`. The [merge gate](/concepts/merge-gate/) enforces this server-side in four layers; no session can self-merge. ### See also - [How jkz works](/get-started/how-jkz-works/) — the QA phase in the full pipeline flow. - [Lens](/agents/lens/) · [Sentinel](/agents/sentinel/) · [Doctor](/agents/doctor/) — the agents this command dispatches. - [`/jkz:review`](/commands/review/) — the phase before, which gates entry to QA. - [Merge gate](/concepts/merge-gate/) — the four-layer guarantee that only a human merges. - [CLI / commands](/reference/cli/) — every `/jkz:*` command at a glance. ## quality Source: https://docs.j0kz.dev/commands/quality/ `/jkz:quality` runs a broad quality scan over the target project and presents the results as a Markdown report. Where [`/jkz:bugs`](/commands/bugs/) hunts for defects, `/jkz:quality` takes the wider view: formatting, linting, security, dead code, and the slow-accumulating debt that does not break the build but erodes the codebase. ### At a glance | | | |------|------| | **Runs** | `quality-scan.js --dir ` | | **`--fix`** | Auto-fix formatting and linting only (with confirmation) | | **`--create-issue`** | File the findings as a `jkz:ready` issue | | **`--category `** | Scan a single category | | **`--quick`** | Run only the original five categories | | **Usage** | `/jkz:quality [--fix] [--create-issue] [--category ] [--quick]` | ### When to use Run it periodically to take the project's pulse, before a release, or whenever you want a categorized picture of code health rather than a list of bugs. Pass `--create-issue` when the findings warrant tracked follow-up work, and `--category` when you only care about one dimension (say, `deadcode` or `security`). ### Key behavior The default run scans all **thirteen** categories: `formatting`, `linting`, `security`, `ai`, `deadcode`, `todos`, `deps`, `crlf`, `config`, `coverage`, `console-log`, `stubs`, and `dry-check`. `--quick` restricts the run to the original five — `formatting`, `linting`, `security`, `ai`, `deadcode`. - **`--fix`** auto-fixes only the safe categories — **formatting and linting** — and confirms which ones before touching anything, then reports what it changed. It does not auto-fix security, dead code, or anything that requires judgment. - **`--create-issue`** writes the full report to an issue body and files it through `issue-create.js` with the `jkz:ready` label, so the findings enter the normal workflow. - **`--category `** filters the scan to one of the categories above. For a vulnerability-focused audit of third-party packages specifically, use [`/jkz:deps`](/commands/deps/) instead — it goes deeper on the dependency tree than the `deps` category here. ## quick Source: https://docs.j0kz.dev/commands/quick/ `/jkz:quick ` runs the **smallest pipeline jkz has**: two agents, one reviewer, no plan, no QA. It is the route for changes that are too small to justify an Architect, an Auditor, and a QA pass — a one-line fix, a doc edit, a config tweak — but still deserve a review and the merge gate. ### Usage ``` /jkz:quick ``` The issue number is required. If the issue has no `complexity:*` label, `/jkz:quick` classifies it on the spot; if it comes back `standard`, it warns you and offers the full `/jkz:pipeline` before doing anything. ### The flow ```mermaid flowchart LR issue(["Issue · jkz:ready"]) --> Bu["Builder implements
(issue body = plan)"] Bu --> J["Judge reviews"] J -- PASS --> CR["CR reconciliation"] CR --> approved(["jkz:approved"]) J -. "FAIL · Doctor fixes · up to 3x" .-> Bu ``` - **No Architect.** There is no formal plan — *the issue description is the plan*. The [Builder](/agents/builder/) reads the issue and implements it directly inside an isolated [worktree](/concepts/worktree-isolation/), then opens the PR. - **The [Judge](/agents/judge/) is the sole reviewer.** It reviews the diff against the issue body, with no CodeRabbit pre-scan and no Inspector — calibrated to the small scope. - **No QA phase.** Lens and Sentinel do not run. - **CR reconciliation runs only after a PASS.** CodeRabbit-bot findings are triaged lightweight (VALID / FALSE_POSITIVE / OUT_OF_SCOPE / ALREADY_FIXED); VALID fixes are applied directly and the Judge re-reviews once. - **On FAIL, the [Doctor](/agents/doctor/) fixes — up to 3 times.** Three failed attempts move the issue to `jkz:blocked` and escalate to you. Everything else holds: the change runs in a per-issue worktree, the PR closes the issue via a `Closes`/`Fixes` keyword, and **only a human merges** — the lightweight route does not weaken the [merge gate](/concepts/merge-gate/). ### When to use it | Use it for | Do **not** use it for | |------------|-----------------------| | Fixes of roughly 1–10 lines | New features | | Documentation-only changes | Architectural changes | | Config changes with obvious scope | Security-sensitive code | | Typo fixes, minor refactors | Anything touching more than ~5 files | If a change has any of the right-hand qualities, reach for the full `/jkz:pipeline` instead. :::note[Deep dive] This page is the command reference. For how the complexity classifier decides whether you land here, and how `/jkz:quick` relates to the [`/jkz:fix`](/commands/fix/) cycle, see [Lightweight routes](/build/lightweight-routes/). ::: ## quit Source: https://docs.j0kz.dev/commands/quit/ `/jkz:quit` performs an **orderly shutdown**: it preserves context for the next chat, surfaces what's still in flight, and cleanly deregisters this session from the [cross-chat registry](/concepts/cross-chat/). It does not close the window for you — it leaves you informed and lets you close when ready. ### Usage ``` /jkz:quit ``` No arguments. ### What it does ```mermaid flowchart TD pr0["Fetch live PR state
(before save, so it's accurate)"] --> save["Save session context
(reuses a fresh snapshot if <5 min old)"] save --> mem["Memory-promotion review
(informational only)"] mem --> learn["Extract learnings"] learn --> prs["Check open + pipeline PRs
+ issue-closure verification"] prs --> lock["Release worktree lock
(if pipeline done + issue closed)"] lock --> dereg["Deregister chat"] dereg --> done(["Safe to close"]) ``` 1. **Fetch live PR state first.** Open PRs and the pipeline PR are fetched from GitHub *before* writing context, so the saved state reflects reality rather than stale conversational memory. 2. **Save context.** `/jkz:quit` runs [`/jkz:save`](/commands/save/) internally — you do **not** need to call it separately. If a snapshot from this session is already fresh (under 5 minutes old), it reuses it instead of re-capturing. 3. **Memory-promotion review.** A deterministic filter looks for memory-promotion candidates and classifies them with Haiku. Results are shown as information only — quit never blocks or waits for input. Act on them later with `/jkz:memory-promote` if you choose. 4. **Extract learnings.** Learnings are extracted from the snapshot, fail-open. 5. **Check PRs.** A combined table shows the pipeline PR (even if merged) and other open PRs, with merge-state status (`CLEAN`, `DIRTY`, `BLOCKED`, `UNKNOWN`). For a merged pipeline PR, it verifies that the `Closes/Fixes/Resolves #N` issues actually closed — and **warns** if an issue is still open after merge. 6. **Release a finished worktree lock.** If the current directory is an issue worktree, the pipeline reached `approved`/`completed`, **and** the owning issue is `CLOSED`, the worktree lock is released so cleanup can reclaim it without waiting for the 24-hour stale-lock sweep. All three conditions are required; otherwise the lock is preserved. 7. **Deregister the chat** from the active-chat registry. ### What it tells you at the end - Context was saved (snapshot + `.claude/context.md`). - The chat was deregistered. - A PR status summary. - Any background tasks still in flight (crons, plus a note for non-enumerable background work). - That you can safely close the window. :::caution[Run it from the worktree] If you're working inside an issue worktree, run `/jkz:quit` **from that worktree directory**, not the parent repo — that's where the lock-release check runs, so it can reclaim the worktree once the pipeline is done. ::: ### Related - [`/jkz:save`](/commands/save/) — the context save that `/jkz:quit` runs internally. - [`/jkz:load`](/commands/load/) — how the next session picks up what `/jkz:quit` saved. - [Cross-chat awareness](/concepts/cross-chat/) — why orderly shutdown matters with parallel chats. ## refine Source: https://docs.j0kz.dev/commands/refine/ `/jkz:refine` is the bridge between a thin issue and a plannable one. It runs a **lightweight pre-plan refinement**: it explores the relevant code, asks you a small budget of targeted questions based on what it actually found, and produces a structured **brief** that downstream agents pick up automatically — so the [Architect](/agents/architect/) starts planning with context instead of guessing. ### Usage ``` /jkz:refine ``` The issue number is required. `/jkz:refine` reads the issue's title, body, and labels to seed the refinement. ### How it works ```mermaid flowchart LR issue(["Issue #N"]) --> type["Detect issue type
(bug · refactor · feature)"] type --> explore["Explore the codebase
(grounded in issue body)"] explore --> ask["Ask targeted questions"] ask --> brief["Build & save brief"] brief --> out(["state/briefs/<N>-brief.md"]) ``` 1. **Detect the issue type.** Labels decide the type, with `bug` winning over `refactor`, which wins over the `feature` default. The type shapes how exploration and questions are framed. 2. **Explore.** `/jkz:refine` reads the code referenced by the issue body — it grounds its questions in the real codebase rather than asking in the abstract. 3. **Ask targeted questions.** Questions are generated from what exploration surfaced, sized to the issue. The point is to resolve ambiguity *before* a plan is drawn, not after. 4. **Build and save the brief.** Your answers plus the exploration notes become a structured brief saved to `state/briefs/-brief.md`, keyed by a hash of the issue body so staleness can be detected later. ### What you get A brief written to `state/briefs/-brief.md`. The next step is [`/jkz:plan `](/commands/plan/) — the Architect reads the brief **automatically**, so the refinement carries forward without you having to paste anything. If the issue body is sparse (under ~50 words), `/jkz:refine` offers to post the brief as a comment on the issue for traceability. :::note[refine vs. start] [`/jkz:start`](/commands/start/) refines a *vague idea* into a brand-new issue. `/jkz:refine` refines an *existing issue* that already has a number. Reach for `refine` when an issue was filed thin and needs sharpening before the pipeline runs. ::: ### Related - [`/jkz:plan`](/commands/plan/) — consumes the brief to design the implementation. - [`/jkz:start`](/commands/start/) — the conversational front door that also refines, but for new ideas. ## research Source: https://docs.j0kz.dev/commands/research/ `/jkz:research [topic]` runs a financial research pipeline that mirrors the rest of jkz: one model produces, an adversarial pair challenges, and the work iterates before it is delivered. Instead of code, the artifact is a researched report with sources, data, and deliverables — and instead of a PR, the deliberation gate is an audit loop that has to pass before output is generated. ### At a glance | | | |------|------| | **Phases** | SCOPE → RESEARCH → AUDIT (up to 3×) → OUTPUT | | **Research** | Analyst (Opus) gathers evidence and produces the draft | | **Audit** | Research-Auditor (adversarial) + Research-Reviewer (validator) | | **Types** | `investment` · `market` · `due-diligence` · `supply-chain` · `derivative` | | **Resumable** | Yes — resumes from existing artifacts under `research//` | | **Usage** | `/jkz:research [topic]` | ### When to use Use `/jkz:research` when you need a structured, evidence-backed financial deliverable rather than a quick answer — an investment thesis, a market sizing, a due-diligence risk matrix, a supply-chain map, or a catalyst-driven derivative valuation. The pipeline is built for work that benefits from an adversarial audit before you trust the conclusions. For a one-off lookup, a chat question is faster; `/jkz:research` is worth running when the output needs to withstand scrutiny. ### Key behavior The pipeline moves through four phases, each persisting state so a run can be resumed from where it stopped: - **SCOPE** *(conversational)* — if no brief exists, the command asks a short series of questions: the research type, the topic (sanitized to a kebab-case slug), and the priority questions that shape the work. The output is a research brief. - **RESEARCH** — the Analyst, running on Opus, gathers evidence and produces three artifacts: the report draft, the analysis data, and a sources log. Research MCP servers are invoked on demand during gathering, with a graceful fallback when a server is unavailable. - **AUDIT** — an adversarial Research-Auditor and a validator Research-Reviewer challenge the draft, iterating up to three times. The audit is the deliberation gate: output is not generated until it completes. - **OUTPUT** — the deliverables are generated from the audited draft. Resumption is automatic: pass a `topic` and the command detects which artifacts already exist under `research//` and restarts from the right phase — brief present means resume at RESEARCH, a complete audit means resume at OUTPUT, and existing deliverables mean the run is already done. Each research type (`investment`, `market`, `due-diligence`, `supply-chain`, `derivative`) shapes the questions, the analysis, and the deliverables; the `derivative` type adds a bottom-up CAPM stage with an explicit confirmation gate. ## resume Source: https://docs.j0kz.dev/commands/resume/ Pipelines get interrupted: a session crashes, you stop a run mid-flight, a lock expires, a fix cycle fails. `/jkz:resume ` is how you get back on track. It **diagnoses** what state the pipeline is in, presents that diagnosis clearly, and — only after you confirm — **delegates** to the correct command to continue from the exact point it stopped. ### Usage ``` /jkz:resume ``` ### What it diagnoses `/jkz:resume` reads the pipeline checkpoint and classifies the interruption into one of six types, each with its own handling: | Interruption | What it means | Handling | |--------------|---------------|----------| | `completed` | Pipeline already finished | Nothing to resume | | `running` | A lock is active — another session may be processing it | Wait, or inspect with [`/jkz:status`](/commands/status/) | | `blocked` | The fix cycle exhausted its attempts | Shows the postmortem; offers re-plan / manual fix / close | | `crash` | An unexpected interruption | Presents the recommended resume point for confirmation | | `stopped` | The run was stopped deliberately | Presents the recommended resume point for confirmation | | `fail` | A phase failed | Presents the recommended resume point for confirmation | For the recoverable types, the diagnosis includes the current phase, the last completed step and the next step, the associated PR and its state, lock status, fix-cycle counts, and the issue's age — so you can see precisely where the pipeline is before deciding. ### The principle: diagnose, then delegate `/jkz:resume` never auto-executes a recovery. It surfaces a **recommended action** (for example, "re-run review on PR #44" or "re-plan from scratch") and asks you to confirm. On confirmation it releases any expired lock and hands control to the target command (`/jkz:plan`, `/jkz:review`, `/jkz:qa`, `/jkz:pipeline`, …). For a `blocked` pipeline it presents options rather than a single recommendation, because the right move — re-plan, fix manually, or close — is a judgment call. If there is no pipeline state for the issue at all, `/jkz:resume` tells you so and points you to `/jkz:pipeline ` to start fresh. :::note[Source of truth] The diagnosis logic lives in `scripts/resume-diagnose.js` and the command flow in `.claude/commands/jkz/resume.md` in the private repo. To inspect a pipeline without resuming, use [`/jkz:status`](/commands/status/). ::: ## review Source: https://docs.j0kz.dev/commands/review/ `/jkz:review ` runs the phase that scrutinizes the Builder's diff before it can reach QA. The [Judge](/agents/judge/) (adversarial backend) reviews the pull request assuming there *is* a bug, and the [Inspector](/agents/inspector/) (validator backend) is the precision filter on that review. A failing verdict does not reach you — it routes straight to the [Doctor](/agents/doctor/)'s fix cycle, up to three times. ### What it does The command orchestrates the **review** stage of the build phase in [the pipeline](/get-started/how-jkz-works/): ```mermaid flowchart LR pr(["jkz:reviewing
(PR open)"]) --> CR["CodeRabbit pre-scan
+ CR fix loop"] CR --> Val["Pre-push validators"] Val --> J["Judge reviews"] J --> I["Inspector verifies"] I -- PASS --> qa(["jkz:qa"]) I -. "FAIL · Doctor fixes · up to 3x" .-> J ``` - A **CodeRabbit pre-scan** and fix loop catch the obvious issues first. - **Pre-push validators** run deterministic checks on the diff (secrets, leftover debug statements, capability invariants) and feed the results to the Judge as Level-1 evidence it should not re-flag. - The **Judge** chaos-engineers the diff against the approved plan: it assumes a bug exists and asks how the code fails. - The **Inspector** verifies the Judge's findings — edge cases and execution claims — filtering out noise and confirming what's real. - After a **PASS**, a CR reconciliation triages any remaining CodeRabbit-bot findings (VALID / FALSE_POSITIVE / OUT_OF_SCOPE / ALREADY_FIXED) before the issue advances. On a **FAIL**, the [Doctor](/agents/doctor/) applies a minimal targeted fix and the diff goes back through review — up to three attempts before the pipeline escalates to a human. ### When to run it - After [`/jkz:build`](/commands/build/) has opened the PR. - As the review stage of `/jkz:pipeline`, which runs it automatically after the build. ### Inputs | Input | Required | Notes | |-------|----------|-------| | PR number | Yes | `/jkz:review `. The PR should have been created by `/jkz:build`. | | PR diff | Read automatically | The Judge and Inspector receive the full diff plus the approved plan. | | Pre-validated checks | Computed automatically | Deterministic findings injected into the Judge's prompt. | ### What phase it drives | | | |--|--| | Phase label | `jkz:reviewing` → `jkz:qa` (PASS) or `jkz:fixing` (FAIL) | | Iterations | Up to 3 Doctor fix cycles on FAIL | | Active agents | [Judge](/agents/judge/), [Inspector](/agents/inspector/), [Doctor](/agents/doctor/) on FAIL | ### How issue type changes the review | Type | Review focus | |------|-------------| | `feature` | Code quality | | `bug` | Fix correctness | | `refactor` | Behavior preserved | | `chore` | No behavior shift | ### Human checkpoint Review is an internal gate, not a human checkpoint — its job is to catch problems automatically. A FAIL routes to the Doctor rather than to you; the human decision points sit at plan approval (before) and the post-QA gate plus the merge (after). The pipeline escalates to you only if three fix attempts cannot clear the verdict. ### See also - [How jkz works](/get-started/how-jkz-works/) — the review stage in the full pipeline flow. - [Judge](/agents/judge/) · [Inspector](/agents/inspector/) · [Doctor](/agents/doctor/) — the agents this command dispatches. - [`/jkz:build`](/commands/build/) — the phase before, which opens the PR. - [`/jkz:qa`](/commands/qa/) — the next phase, once review passes. - [Lightweight routes](/build/lightweight-routes/) — `/jkz:fix`, the Doctor's fix cycle invoked on a FAIL. ## save Source: https://docs.j0kz.dev/commands/save/ `/jkz:save` preserves the **reasoning context** of the current session so it survives the chat window. It writes two things: a structured snapshot (consumed by [`/jkz:load`](/commands/load/)) and a human-readable `.claude/context.md`. Because multiple Claude Code chats can run on the same project, saving is how knowledge crosses between them — see [cross-chat awareness](/concepts/cross-chat/). ### Usage ``` /jkz:save ``` No arguments. `/jkz:save` reads the current session and captures everything relevant. ### What it captures ```mermaid flowchart TD mem["Read session memory
(incremental, Haiku-maintained)"] --> ctx["Build reasoning context
(done · decisions · next steps · gotchas)"] ctx --> bg["Capture background tasks
(crons; note for non-enumerable bg)"] bg --> snap["Write snapshot
state/session-snapshots/<id>.json"] snap --> md["Write .claude/context.md
(human-readable)"] ``` 1. **Session memory as the base.** Any incrementally maintained session memory seeds the snapshot, then is enriched with what this session adds. 2. **Reasoning context.** A concise record of what was completed, the decisions made (with rationale), what worked and what didn't, the next steps, and the gotchas to watch for. 3. **Background tasks (best-effort).** Crons are enumerable and recorded. Background subagents and background bash shells are *not* enumerable — they live inside the session and die when it closes — so if any were started, they're noted as free text rather than dropped silently. 4. **The snapshot** is written per-session to `state/session-snapshots/.json`. 5. **`.claude/context.md`** holds the same information in a short, human-readable form (10–20 lines): what was worked on, current state, key decisions, and active branches. ### Why it matters A snapshot is what lets a *different* chat run [`/jkz:load`](/commands/load/) and continue your work with full reasoning context — not just the git state. The session id keys the snapshot; if it is unset, the snapshot falls back to `anonymous`, which weakens cross-chat continuity and token attribution. :::note[You rarely call this directly] [`/jkz:quit`](/commands/quit/) runs `/jkz:save` internally as its first step, so an orderly shutdown already captures context. Call `/jkz:save` on its own when you want a mid-session checkpoint without quitting. ::: ### Related - [`/jkz:load`](/commands/load/) — retrieve the most recent snapshot from another session. - [`/jkz:quit`](/commands/quit/) — orderly shutdown that saves, then deregisters the chat. ## ship Source: https://docs.j0kz.dev/commands/ship/ `/jkz:ship` is the full pre-PR sequence for work done *outside* the [pipeline](/commands/pipeline/). It takes the current branch through format → lint → test → simplify → CodeRabbit pre-commit → commit, then optionally pushes and opens a PR. No issue, no pipeline state, no agents — just the quality gates applied to whatever you've been editing. ### Usage ``` /jkz:ship [--skip-tests] [--skip-simplify] ``` | Flag | Effect | |------|--------| | *(none)* | Full sequence: format, lint, test, simplify, CR pre-commit, commit | | `--skip-tests` | Skip the test step | | `--skip-simplify` | Skip the simplify step | It refuses to run on `main` — you must be on a feature branch with changes to process. ### The sequence ```mermaid flowchart LR fmt["Format"] --> lint["Lint"] --> test["Test"] --> simp["Simplify"] --> cr["CR pre-commit loop"] --> commit["Commit"] --> pr{"Push + PR?"} pr -- "you choose" --> done(["Done"]) ``` - **Format & lint** run over the modified files only (the staged + unstaged union), per directory, via `quality-scan.js`. If the scanner is unavailable the step warns and continues rather than aborting. Files touched by these steps are re-staged. - **Test** runs `npm test` (not the runner directly, so it inherits the notification kill-switch). On failure it stops and asks whether to continue or abort — it never silently ships failing code. Skipped with `--skip-tests`. - **Simplify** reviews staged code files for unnecessary complexity and applies refinements that change *how*, not *what* — preserving behavior. Non-code files are skipped, as is the whole step under `--skip-simplify`. - **CR pre-commit + commit** reuse the [`/jkz:commit`](/commands/commit/) loop: the same skip heuristic, the same up-to-three-iteration CodeRabbit classify-and-fix cycle (VALID / FALSE_POSITIVE / LOW_SIGNAL), and the same conventional-commit skill at the end. - **Push + PR is opt-in.** When you confirm, it pushes with `git push -u origin HEAD` and opens a PR with `gh pr create --fill`. Declining leaves you with a clean local commit and a summary of what ran. ### When to use it `/jkz:ship` is for ad-hoc branches that never entered the pipeline but still deserve the same quality bar before a PR — a quick fix, a docs sweep, a small refactor you made directly. It composes the [`/jkz:commit`](/commands/commit/) loop with the quality scans and tests; if you only want the CodeRabbit-before-commit step, reach for `/jkz:commit` alone, and if you want to clear CodeRabbit feedback on an *existing* PR, use [`/jkz:cr-fix`](/commands/cr-fix/). Like the rest of jkz, it stops short of the merge: shipping here means *ready for review*, and [only a human merges](/concepts/merge-gate/). ## simplify Source: https://docs.j0kz.dev/commands/simplify/ `/jkz:simplify` reviews the code you changed for unnecessary complexity, redundancy, and unclear naming, then applies the refinements. Its guiding rule is narrow and strict: change *how* the code reads, never *what* it does. ### At a glance | | | |------|------| | **Scope** | Files changed this session, or a file you pass | | **Targets** | Reuse, clarity, efficiency, nesting, naming | | **Guarantee** | Preserves all existing functionality | | **Usage** | `/jkz:simplify []` | ### When to use Run it after writing a feature or fix, when the code works but reads more densely than it should. With no argument it simplifies the files you changed this session (via `git diff`); pass a file to target one specifically. Non-code files — Markdown, config JSON, lockfiles — are skipped. ### Key behavior For each file in scope the command reviews for unnecessary complexity and nesting, redundant code and abstractions, unclear variable and function names, consolidation opportunities, nested ternaries (preferring `switch`/`if-else`), and overly compact code that sacrifices readability. It then applies the refinements and reports each change with a brief rationale. The discipline matters as much as the cleanup: - **Preserve functionality.** Change HOW, never WHAT. - **Prefer explicit over compact.** Three clear lines beat one clever line. - **Do not over-simplify.** It will not collapse readable code into something terse just to cut a line. This is the readability-and-reuse counterpart to [`/jkz:perf-audit`](/commands/perf-audit/), which targets measurable performance rather than clarity. For cleaning up prose rather than code, see [`/jkz:deslop`](/commands/deslop/). ## skill-audit Source: https://docs.j0kz.dev/commands/skill-audit/ `/jkz:skill-audit` scans skill files for security problems. Skills are executable instructions the agents load and follow, so a malicious or careless one is a real attack surface — this command checks them for the patterns that matter. ### At a glance | | | |------|------| | **Runs** | `skill-security-audit.js --json --verbose` | | **Default scope** | `.claude/skills/` | | **Custom scope** | Any path passed as an argument | | **Verdict** | PASS / WARN / FAIL | | **Usage** | `/jkz:skill-audit [/path/to/skills]` | ### When to use Run it before installing a third-party skill, after authoring or editing one, or as a periodic check on the skills directory. Point it at a custom path when you want to vet skills that live outside the default `.claude/skills/` location. ### What it scans for The scanner looks for six categories of risk: - **Code injection** — patterns that would execute arbitrary code. - **Prompt injection** — instructions designed to subvert the agent's behavior. - **Data exfiltration** — attempts to send data off the machine. - **jkz-specific violations** — actions the framework forbids (for example, anything that would bypass the [merge gate](/concepts/merge-gate/)). - **Filesystem escape** — access outside the intended scope. - **Secret exposure** — credentials or tokens left in the open. ### Key behavior The command runs the scanner and presents a verdict — **PASS**, **WARN**, or **FAIL** — alongside the count of files scanned and findings by severity (critical / high / medium). When findings exist, it lists them in a table (severity, file, line, category, pattern) and gives targeted recommendations: a **FAIL** enumerates the critical findings that must be fixed, a **WARN** lists the high-severity items worth a look, and a **PASS** confirms the skills are clean. For a broader, non-security sweep of project health, see [`/jkz:quality`](/commands/quality/). ## start Source: https://docs.j0kz.dev/commands/start/ `/jkz:start` is the front door. You do not need an issue number — *this command creates the issue*. You bring a rough idea ("the bot should show pipeline cost", "something's off with notifications", "let's add a retry to the webhook handler") and jkz turns it into a well-formed, labeled issue with a recommended route, without you having to know whether the work is trivial, quick, or standard. ### Usage ``` /jkz:start ``` No arguments. jkz asks you to describe what you want, then walks a short routing funnel. ### How it routes you `/jkz:start` walks four steps in order and **stops at the first match** — so it never spends effort exploring the codebase or drafting a brief for work that does not need a pipeline. ```mermaid flowchart TD idea(["You describe an idea"]) --> triage{"Step 0 · Trivial?"} triage -- "trivial + high confidence" --> resolve(["Resolve inline · no issue"]) triage -- "otherwise" --> dup{"Step 1 · Duplicate?"} dup -- "clear match" --> existing(["Point to existing issue"]) dup -- "no match" --> refine["Step 2 · Refine
(type · purpose · explore · questions · brief)"] refine --> create["Step 3 · Create issue + recommend route"] ``` 1. **Triage.** A Haiku classifier sizes the idea. If it comes back `trivial` *with high confidence*, jkz offers to resolve it inline in the chat — no issue, no pipeline. (Low confidence always continues to refinement; jkz reads the code before deciding.) 2. **Duplicate check.** jkz searches open `jkz:ready` issues. If one clearly matches, it points you there instead of creating a near-duplicate. 3. **Refinement.** jkz classifies the issue type (`bug` / `feature` / `refactor` / `chore`), extracts the purpose (asking one clarifying question if the intent is vague), explores the relevant code, and asks a small budget of targeted questions sized to the provisional complexity. The answers become a structured **brief**. 4. **Issue creation + recommendation.** jkz creates the issue via the issue primitive — baking in the `jkz:ready` label, the type label, and a `complexity:*` classification, and running its alignment checkpoints inline. Then it recommends a route. ### What you get at the end A new issue labeled `jkz:ready`, a brief saved under `state/briefs/`, and a single clear recommendation based on the classified complexity: | Complexity | Recommendation | |------------|----------------| | `trivial` | Apply directly, or [`/jkz:quick`](/commands/quick/) | | `quick` | [`/jkz:quick`](/commands/quick/) — the [lightweight route](/build/lightweight-routes/) | | `standard` | `/jkz:pipeline` — the full plan → build → review → QA loop | You always decide which route to take — jkz recommends, it does not act on its own. `/jkz:plan` (planning only) is offered as an alternative in every case. :::note[Source of truth] The behavior summarized here lives in the private repo at `.claude/commands/jkz/start.md`, and complexity classification in `scripts/classify-issue.js`. This page is the public reference. ::: ### When to use `/jkz:start` - You have an idea but no issue yet, and you are not sure how big the work is. - You want jkz to size the change and route you, rather than guessing between quick and the full pipeline yourself. If you already have a GitHub issue, skip straight to [`/jkz:quick`](/commands/quick/) for small scoped work or `/jkz:pipeline` for anything with design decisions. For the full picture of how the pipeline runs after an issue exists, see [How jkz works](/get-started/how-jkz-works/). ## status Source: https://docs.j0kz.dev/commands/status/ `/jkz:status` is the dashboard. It is **read-only** — it changes nothing — and answers the question "what is the pipeline doing right now?" across every active issue, or in detail for one. ### Usage ``` /jkz:status # all active work /jkz:status # detailed status for one issue ``` ### What it shows Run without an argument, `/jkz:status` aggregates the live state of the whole pipeline: - **Active issues** — every issue carrying a `jkz:` phase label, with its phase, active agent, and last-updated time. - **Open PRs** — jkz-labeled pull requests with their review status and **merge-gate** state (`pending` / `approved` / `not_found`). - **Recent agent activity** — live wrapper output from the last couple of minutes, so you can see which agent is working and on what. - **Worktrees** — the per-issue [isolated worktrees](/concepts/worktree-isolation/) and their branches. - **Dependencies** — the `blocked_by` / `blocks` graph, showing which issues are clear and which are gated on a blocker. - **Pipeline mode** — fix-cycle counts and notification backend status for issues running under `/jkz:pipeline`. - **System health** — reachability of the adversarial and validator backends, the GitHub API, notifications, plus stale-worktree and CLI-freshness counts. #### Detailed view for one issue Passing an issue number drills in: the full timeline of agent invocations, all deliberation files, the associated PR and its review status, the dependency chain with each blocker's phase, the pipeline checkpoint data (fix counts, timestamps, approval state), recent phase transitions and per-phase durations, and — if it ran — the Sentinel meta-audit verdict. :::note[Source of truth] The status assembly lives in `.claude/commands/jkz/status.md` in the private repo. For CLI-version freshness and breaking-change detail, run `/jkz:health`; to *recover* an interrupted pipeline rather than just inspect it, use [`/jkz:resume`](/commands/resume/). ::: ## vault Source: https://docs.j0kz.dev/commands/vault/ `/jkz:vault` is the backlog for ideas you are not ready to act on yet. When research surfaces something worth keeping — a feature worth building later, an approach worth revisiting, a finding that does not belong in the current task — the vault holds it so it is not lost between sessions. It is a deliberate "leave it for later" store, separate from issues and separate from memory. ### At a glance | | | |------|------| | **Purpose** | Persistent store for researched ideas, across sessions | | **Scopes** | Project (auto-detected) and global | | **Search** | FTS5 full-text search | | **State** | Items carry a status you can change; triggers can surface them | | **Backed by** | `scripts/vault.js` | | **Usage** | `/jkz:vault [show \| search \| global \| status \| triggers] ...` | ### When to use Use `/jkz:vault` whenever an idea is worth keeping but not worth doing now — "save this for later", "what do we have pending", "mark this as ready". It is the natural companion to [`/jkz:research`](/commands/research/): research produces ideas, the vault retains them, and a status change promotes one when its time comes. ### Key behavior The command dispatches to a small set of subcommands, each a thin wrapper over `scripts/vault.js`: - **(no argument)** — list every item, project and global, as a table. - **`show `** — display the full contents of a single vault item. - **`search `** — FTS5 full-text search, scoped to the current project. - **`global`** — list only the global-scope items. - **`status `** — change an item's status (for example, mark a saved idea as ready to work). - **`triggers`** — list all triggers, the conditions that resurface vault items at the right moment. Project scope is detected automatically, so items stay associated with the project they came from while global items remain available everywhere. When there is nothing to show, the command says so plainly rather than returning an empty table. ## Architect Source: https://docs.j0kz.dev/agents/architect/ The **Architect** is the first role the pipeline reaches. It is a *creative* role: it constructs the plan that every later phase is measured against. Its job is to understand the full picture before committing to a single approach. No alternatives, no hedged language: one plan, fully owned. A good plan is not a checklist. Every step must be specific enough that a Builder can implement it without asking a question, and rigorous enough to survive the Auditor and Curator that come next. ### At a glance | | | |---|---| | **Phase** | Plan | | **Class** | creative | | **Model** | Claude Opus | | **Invocation** | Task tool (`model: "opus"`) | | **Source** | `.claude/agents/architect.md` | As a creative role the Architect runs on Claude Opus and is dispatched through the Task tool, the same mechanism that drives the Builder and Doctor. It reasons deeply before drafting rather than optimizing for speed — a shallow plan forces Builder rework and Auditor rejection, which costs more than the upfront thinking. ### What it does Before drafting, the Architect reasons through the risks and mitigations for its chosen approach, the codebase assumptions that must hold, and the acceptance criteria that would prove success. It analyzes the issue against a 32-dimension spec taxonomy, marking each dimension `DEFINED`, `PARTIAL`, or `ABSENT`, so its design decisions are traceable: a reviewer can see exactly which choices came from the spec and which were the Architect's own. `DEFINED` dimensions are constraints, not suggestions — the plan may fill gaps but never silently contradict what the spec defines. It never proposes a change to a file it has not read. When the issue omits a file's current state, the Architect reads it first rather than guessing structure from a name. ### Inputs and outputs | Inputs | Outputs | |--------|---------| | Issue description (what to build or change) | A structured Markdown plan: spec adoption map, objective, scope, numbered implementation steps, data-flow paths, files affected, dependencies, a premortem risk table, acceptance criteria, and a testing strategy | | Research pre-docs, if any | A `jkz:compact-plan` signal — a ~250-token structured summary that downstream agents (Judge, Inspector, Lens, Sentinel) consume instead of the full narrative | | Codebase context — relevant files, patterns, conventions | An optional `jkz:adr-json` signal for significant architectural decisions, and a `jkz:spec-map` signal recording the dimension analysis | | Previous-iteration feedback from the Auditor and Curator (on iteration 2–3) | | ### Where it sits in the flow The Architect opens the Plan phase. Its plan flows as a Git artifact (never a direct message) to the **[Auditor](/agents/auditor/)**, which challenges it, and then to the **[Curator](/agents/curator/)**, which validates the audit. A `FAIL` verdict from either sends the plan back to the Architect to revise, up to three iterations. When the plan clears review it reaches a human checkpoint: you read it and approve before any code is written. See **[How jkz works](/get-started/how-jkz-works/)** for the full Plan → Build → QA pipeline, and **[Architecture](/reference/architecture/)** for model routing and fallback details. ## Auditor Source: https://docs.j0kz.dev/agents/auditor/ The **Auditor** is the adversarial seat in the Plan phase. It reviews a plan without regard for the effort that went into it — only whether it will deliver. Its job is to find what is missing, what is vague, and what will fail — before a single line of code is written. Adversarial does not mean obstructive. The Auditor defaults to `PASS` unless a finding clears a high bar: a concrete, evidence-backed problem that will produce a wrong outcome. Style preferences, naming, and "I would have organized it differently" are noise, not findings. ### At a glance | | | |---|---| | **Phase** | Plan | | **Class** | adversarial | | **Model** | External backend, configurable per role | | **Invocation** | `node scripts/run.js resolve-wrapper.sh --role auditor` | | **Source** | `agents/auditor.md` | The Auditor runs on an external, OpenAI-compatible backend resolved at runtime from `JKZ_AUDITOR_ENDPOINT` and `JKZ_AUDITOR_MODEL`. As an adversarial role the endpoint is **required** — there is no silent fallback to a local CLI, because a review must never quietly skip its challenger. The diversity is deliberate: the model that wrote the plan (Opus) is not the model that challenges it. ### What it does The Auditor applies an **evidence hierarchy** to every claim — execution beats file citations, which beat reasoning. A `CRITICAL` finding must rest on evidence level 1 or 2 (something runnable or a real file citation); a `CRITICAL` backed only by reasoning is downgraded or dropped. Theoretical "what if X happens" risks need a path showing X is actually reachable. It verifies file references the plan makes, checks for missing steps and unhandled error cases, and challenges stated assumptions. Every `FAIL` ships with a specific suggested fix, not just an objection. A review is capped at ten issues; if more surface, the lowest-severity ones are dropped to keep the signal high and the false-positive cost low. ### Inputs and outputs | Inputs | Outputs | |--------|---------| | The Architect's full plan | A Markdown review: a TL;DR, an *Issues Found* list (each with severity, category, location, description, evidence, and suggested fix), and a **PASS** / **FAIL** verdict | | Codebase context for verification | A `jkz:verdict-json` signal carrying the compact verdict for downstream agents | | The original issue description | An *Accumulated Patterns* section feeding the pipeline's pattern-learning loop | ### Where it sits in the flow The Auditor is the second role in the Plan phase. It receives the Architect's plan as a Git artifact and posts its review the same way — agents never message each other. Its verdict then goes to the **[Curator](/agents/curator/)**, which validates the audit itself. A `FAIL` routes the plan back to the **[Architect](/agents/architect/)** for revision, up to three iterations before the pipeline escalates to you. See **[How jkz works](/get-started/how-jkz-works/)** for the full pipeline and **[Architecture](/reference/architecture/)** for backend routing and the fallback tiers. ## Builder Source: https://docs.j0kz.dev/agents/builder/ The **Builder** is where a plan becomes code. It takes the strategy the [Architect](/agents/architect/) designed and the [Auditor](/agents/auditor/) and [Curator](/agents/curator/) signed off on, and it implements it faithfully inside an isolated worktree — then opens the pull request that every later role reviews. The Builder does not make architectural decisions. Those were made in planning. Its discipline is execution: implement the plan exactly, match the existing style, and report any deviation honestly rather than quietly improving things it was not asked to touch. ### Model & backend | Property | Value | |----------|-------| | Class | creative | | Model | Claude Opus | | Invocation | Task tool (`model: "opus"`) | | Isolation | Its own worktree — writes are confined to the worktree, never the main checkout | | Can open a PR | Yes | | Can merge / push to `main` | No — blocked by capability invariants and the merge gate | The Builder runs as a creative role: Opus drafts the work, and the adversarial and validator backends downstream challenge and confirm it. The model that writes the code is never the model that signs it off. ### Inputs The Builder receives a Git-mediated brief, never a conversation with another agent: - **Approved plan** — the plan that passed Architect → Auditor → Curator review. - **Codebase context** — the current state of the files it will modify. - **Issue description** — the original requirements. In [`/jkz:quick`](/reference/cli/) there is no Architect plan: the issue body *is* the plan, and the Builder implements it directly. - **Worktree path** — the isolated worktree where it works. ### Outputs - **The implementation** — production code committed in atomic commits, matching existing conventions. - **A pull request** targeting `main`, with a `Closes #N` (or `Fixes #N`) keyword so the merge auto-closes the issue. - **A build report** listing every file created, modified, or deleted, plus any deviations from the plan and confirmation that each acceptance criterion is addressed. - **A structured verdict signal** (`jkz:verdict-json`) the orchestrator parses without reading the prose: `COMPLETE` or `BLOCKED`, the PR number, files changed, deviations, and the error-handling sites it introduced. When a plan step is impossible (a file was renamed, an API changed, a dependency is missing), the Builder **stops and reports** rather than fabricating success. A `BLOCKED` verdict is a valid outcome, not a failure. ### Iteration limits The Builder produces the first version of the diff. From there the build loop owns iteration: the [Judge](/agents/judge/) reviews, the [Inspector](/agents/inspector/) calibrates, and on a FAIL the [Doctor](/agents/doctor/) applies the fix — up to **three** fix cycles before the pipeline escalates to a human. The Builder is re-invoked only when an interrupted build needs to resume; it picks up from the first incomplete stage and never redoes committed work. ### See also - [Judge](/agents/judge/) — reviews the Builder's diff as a chaos engineer. - [Inspector](/agents/inspector/) — calibrates the Judge's findings on that diff. - [Doctor](/agents/doctor/) — applies surgical fixes when the diff fails review. - [How jkz works](/get-started/how-jkz-works/) — the Build phase in the full pipeline flow (the dedicated `/jkz:pipeline` end-to-end page lands in a later wiki pass). - [CLI / commands](/reference/cli/) — `/jkz:build` and `/jkz:quick`, the commands that dispatch the Builder. ## Classifier Source: https://docs.j0kz.dev/agents/classifier/ The **Classifier** is the intake triage. Before any phase begins, it reads a GitHub issue and answers one question: how much pipeline does this deserve? A typo does not need an Architect; a multi-system refactor should not skip planning. The Classifier makes that call so the routing happens up front, not halfway through. | | | |---|---| | **Model** | Claude Haiku 4.5 (configurable via `JKZ_CLASSIFY_MODEL`) | | **Class** | utility | | **Phase** | Intake — runs before the pipeline starts | | **Invocation** | `node scripts/classify-issue.js --title "..." --body "..." [--labels "bug,refactor"]` | ### Mission Classify an issue's complexity into one of three tiers and recommend the route that fits it. The output drives [`/jkz:start`](/reference/cli/), which is where most issues enter the system. ### Hybrid by design The Classifier is not a pure LLM call. It is deterministic signal extraction *plus* Haiku judgment: - **Signals first.** A deterministic pass extracts ground truth from the issue text — files mentioned and how many layers they span, design and compliance keywords, code blocks, and the number of Acceptance Criteria items. These are facts, not opinions. - **Haiku decides.** Those signals are handed to Haiku as verified context, and the model returns the classification with reasoning. - **Deterministic fallback.** If the LLM is unavailable, a scoring heuristic over the same signals produces a verdict anyway. The Classifier never fails closed. ### What it returns A single JSON object: | Field | Values | |-------|--------| | `complexity` | `trivial` · `quick` · `standard` | | `confidence` | `high` · `medium` · `low` | | `recommended_pipeline` | the route to take | | `reasoning` | why this tier | | `signals` | the deterministic facts the decision was built on | ### How the verdict routes the work | Complexity | Route | |------------|-------| | `trivial` | Handle it directly in chat — no pipeline. | | `quick` | [`/jkz:quick`](/reference/cli/) — Builder + Judge, no plan or QA. | | `standard` | The full pipeline, planning first. | The classification is cached as a `complexity:*` label on the issue, so the same answer is reused rather than recomputed each time the issue is touched. When confidence is anything below `high`, the recommendation is to read the referenced files before committing to a route — the Classifier flags its own uncertainty rather than hiding it. ## Curator Source: https://docs.j0kz.dev/agents/curator/ The **Curator** closes the Plan phase. It is a *validator*, and its subject is not the plan directly but the **Auditor's review of it**. It looks for anomalies in the audit: a false positive, a miscalibrated severity, a gap the Auditor missed. If the Auditor missed something obvious, the rest of the review is suspect; if it flagged something unreal, it has wasted an iteration cycle. ### At a glance | | | |---|---| | **Phase** | Plan | | **Class** | validator | | **Model** | External validator backend (default Ollama Cloud); local Gemini CLI fallback | | **Invocation** | `node scripts/run.js resolve-wrapper.sh --role curator` | | **Source** | `agents/curator.md` | The Curator runs on a validator backend resolved from `JKZ_CURATOR_ENDPOINT` / `JKZ_CURATOR_MODEL`, defaulting to Ollama Cloud (`glm-5.1:cloud`). Unlike adversarial roles, a validator does not require a configured endpoint: when none is set, it falls back to a local Gemini CLI. This keeps the validator seat filled even in a minimal setup. ### What it does The Curator must act as **tiebreaker**. When the Architect and Auditor disagree, it never defers the decision back — it provides a reasoned judgment with evidence from the codebase. It protects in both directions: against false `FAIL`s from an overly aggressive Auditor that waste iteration cycles, and against false `PASS`es from a lazy one that lets a bad plan through. It re-checks the Auditor's file citations, since a hallucinated reference invalidates the finding that rests on it. It also runs a spec-fidelity meta-check: when the Architect's plan defines spec dimensions, the Curator confirms the Auditor actually verified the plan against them, flagging a missed check when the Auditor issued a `PASS` without it. ### Inputs and outputs | Inputs | Outputs | |--------|---------| | The Architect's original plan | A Markdown validation report: a TL;DR, an *Audit Quality Assessment* scoring coverage, accuracy, severity calibration, and constructiveness | | The Auditor's review (issues and verdict) | *Issues with the Audit* (missed issues, false positives, wrong severities) and *Additional Issues Found* the Auditor missed | | Codebase context for verification | A **PASS** / **FAIL** verdict with a `jkz:verdict-json` signal, plus an *Accumulated Patterns* section | | The original issue description | | ### Where it sits in the flow The Curator is the final role in the Plan phase. It reads the plan and the Auditor's review as Git artifacts and posts its own report the same way. A `PASS` advances the plan to the human checkpoint — where you approve before any build begins. A `FAIL` sends the plan back to the **[Architect](/agents/architect/)**, with the **[Auditor](/agents/auditor/)** re-challenging the revision, for up to three iterations. See **[How jkz works](/get-started/how-jkz-works/)** for the full Plan → Build → QA pipeline and **[Architecture](/reference/architecture/)** for validator routing and the fallback tiers. ## Doctor Source: https://docs.j0kz.dev/agents/doctor/ The **Doctor** is called when something fails review. Its job is surgical intervention: enter, fix exactly what is broken, and exit. No collateral damage, no extra changes, no "while I'm here" improvements. The smallest correct fix is the best fix. Before proposing anything, the Doctor enumerates the root-cause hypotheses, rules each out with evidence from the diff and test output, and commits to the single fix with the highest confidence — not a menu of options. It has up to **three** attempts. If it cannot resolve the issue, it escalates honestly to a human rather than forcing a fix that passes the checks but hides the real problem. ### Model & backend | Property | Value | |----------|-------| | Class | creative | | Model | Claude Opus | | Invocation | Task tool (`model: "opus"`) | | Isolation | Its own worktree — writes confined to the worktree | | Turn budget | `maxTurns: 5` per invocation, a guard against over-fixing | | Can open a PR | No — it patches the existing branch the Builder opened | | Can merge / push to `main` | No | The Doctor serves both fix cycles: the Build phase (after a [Judge](/agents/judge/) or [Inspector](/agents/inspector/) FAIL) and the QA phase (after a Lens or Sentinel FAIL). ### Inputs - **Feedback report** — the issues from Judge / Inspector (review) or Lens / Sentinel (QA). - **Root-cause classifications** — structured `root_cause` categories from the adversarial agents, used as the starting hypothesis. - **Historical root-cause patterns** — similar past fixes and their outcomes, from the memory store. - **PR diff** — the current state of the changes. - **Approved plan** — the original plan, for reference. - **Iteration number** — attempt 1, 2, or 3. - **Previous fix attempts** — what was tried before, so the Doctor never retries a failed approach. ### Outputs - **The fix** — minimal code changes that address the root cause, committed to the PR branch. - **A fix report** — per issue: acknowledge, diagnose, fix, verify; plus files modified and any new risk introduced. - **A verdict signal** (`jkz:verdict-json`) — `FIXED`, `PARTIAL`, or `BLOCKED`, with issues fixed, issues remaining, and files changed. - **A diagnosis signal** (`jkz:diagnosis-json`) — root cause confirmed, hypotheses explored, approach taken, what failed, and what the next iteration should try. Emitted on every iteration so reasoning carries across attempts. The Doctor maps each fix to its root cause: `missing_validation` adds validation only at the identified boundary, `wrong_approach` waits for an Architect plan rewrite, `regression` fixes both the original issue and what the previous fix broke. It never fabricates a passing test result. ### Iteration limits Up to **three** attempts. The Doctor thinks harder, not faster, on later iterations: a repeated shallow analysis produces the same failed fix. On a third failure, or whenever the root cause stays unclear, it stops and escalates with an explicit diagnosis of what it tried and why it did not work. Honest escalation beats a silent hack: the human needs that information to intervene. ### See also - [Judge](/agents/judge/) and [Inspector](/agents/inspector/) — produce the verdicts the Doctor fixes. - [Builder](/agents/builder/) — wrote the code the Doctor repairs; both are Opus creative roles confined to a worktree. - [How jkz works](/get-started/how-jkz-works/) — the Build and QA fix cycles in context (the dedicated `/jkz:pipeline` end-to-end page lands in a later wiki pass). - [CLI / commands](/reference/cli/) — `/jkz:fix`, the command that dispatches the Doctor. ## Inspector Source: https://docs.j0kz.dev/agents/inspector/ The **Inspector** is the precision filter on the [Judge](/agents/judge/)'s chaos-engineering review. The Judge operates with high recall — it assumes a bug exists and hunts aggressively, which is correct but produces false positives. The Inspector separates real signal from noise. It has two equally important mandates: **confirm real issues** against the actual code with execution or file-level evidence, and **expose false positives** with evidence so an uncontested FP does not waste a Doctor iteration. It also catches what the Judge missed in the logic, correctness, and structure space — but calibration is its primary value-add. Its rule of last resort: **never mark a real bug as a false positive.** The goal is calibration, not symmetry. If every Judge finding is real, the Inspector confirms them all. ### Model & backend | Property | Value | |----------|-------| | Class | validator | | Model | External / Ollama Cloud backend by default, with a local Gemini CLI fallback | | Invocation | `resolve-wrapper.sh --role inspector --pr `, routed via `JKZ_INSPECTOR_ENDPOINT` | | Endpoint | Optional — validator roles fall back to the local Gemini CLI when no endpoint is configured | | Access | Read-only; posts findings as PR comments | | Can merge / push to `main` | No | ### Inputs - **PR diff** — all changes in the pull request. - **Judge's review** — the adversarial review with its issues and verdict; this is what the Inspector calibrates. - **Approved plan** — for reference. - **Codebase context** — surrounding code, read from the PR worktree so citations are checked against current code. - **CodeRabbit pre-scan** *(optional)* — used to verify whether the Judge caught what CodeRabbit flagged. ### Outputs A validation report posted as a PR comment, with a `jkz:verdict-json` block whose `false_positives` field lists every Judge finding ruled an FP. The report contains: - **TL;DR** — verdict, plus any key false positive, confirmed HIGH/CRITICAL finding, or missed issue. - **Judge Finding Verdicts** — the primary output: a table issuing an explicit verdict on *every* Judge finding — **CONFIRMED**, **FALSE POSITIVE**, or **DOWNGRADE** — each backed by `file:line` or an execution result. No finding is left unresolved. - **Review Quality Assessment** — the Judge's thoroughness, accuracy, severity calibration, and false-positive rate. - **Additional Issues Found** — problems the Judge missed in logic, correctness, and structure (security deep-dives belong to Sentinel in QA). - **Verdict** — `PASS` (ready for QA after filtering FPs) or `FAIL` (lists only confirmed findings that must change). ### Iteration limits The Inspector is iteration-aware. On **iteration 1** it verifies the Judge's findings against the diff and completes the Judge Finding Verdicts table. On **iteration 2+** it checks that the Judge reviewed the [Doctor](/agents/doctor/)'s *changes* rather than re-reviewing the original diff, verifies that file citations point to current (post-fix) code, and confirms each previously reported fix is present. It runs inside the same build loop as the Judge — up to **three** fix cycles before escalation. ### See also - [Judge](/agents/judge/) — the adversarial review the Inspector calibrates. - [Builder](/agents/builder/) — produces the diff under review. - [Doctor](/agents/doctor/) — fixes the findings the Inspector confirms. - [How jkz works](/get-started/how-jkz-works/) — the Build (review) phase in context (the dedicated `/jkz:pipeline` end-to-end page lands in a later wiki pass). - [CLI / commands](/reference/cli/) — `/jkz:review`, the command that dispatches the Inspector. ## Judge Source: https://docs.j0kz.dev/agents/judge/ The **Judge** is a chaos engineer whose job is to break the code before it ships. It does not ask "does this look correct?" It asks "how does this fail?" and "what did the Builder forget to handle?" The Judge assumes there is a bug somewhere and hunts for it across every new code path in the diff. It is the last technical gate before QA. If a fault slips past the Judge, it ships. The Judge tests for attacker behavior, unexpected user input, and failure modes an ops engineer would recognize. When it genuinely finds nothing after working through every probe, that is a valid PASS. Adversarial does not mean obstructive. The Judge defaults to **PASS** unless a finding clears the bar of a concrete, evidence-backed bug that produces a wrong outcome in the diff under review. Style preferences, theoretical attack vectors with no reachable path, and pre-existing issues are not blockers. ### Model & backend | Property | Value | |----------|-------| | Class | adversarial | | Model | External backend, configurable per role | | Invocation | `resolve-wrapper.sh --role judge --pr `, routed via `JKZ_JUDGE_ENDPOINT` / `JKZ_JUDGE_MODEL` | | Endpoint | **Required** — there is no silent fallback to a native CLI; without an endpoint the review is skipped and you decide whether to continue | | Access | Read-only; posts findings as PR comments | | Can merge / push to `main` | No | The Judge runs on a different model than the [Builder](/agents/builder/) that wrote the code. That diversity is the point: a single model's blind spot cannot pass unchallenged. ### Inputs - **PR diff** — all changes in the pull request; the Judge reviews the diff, not the whole codebase. - **Approved plan** — what the Builder was supposed to follow, for plan-compliance checking. - **Codebase context** — surrounding code for the changed files. - **Builder's notes** — any deviations or decisions the Builder documented. - **CodeRabbit pre-scan** *(optional)* — automated results for enrichment; the verdict is never anchored to it. - **Pre-validated checks** *(optional)* — deterministic validator results (secrets, leftover debug, capability invariants), treated as Level 1 evidence and not re-flagged. - **Threat model / ADR** *(optional)* — open threats to verify, and architectural decisions to confirm the implementation honors. ### Outputs A Markdown review posted as a PR comment (and a `jkz:` Check Run when the token allows), with a structured `jkz:verdict-json` block. The review contains: - **TL;DR** — the verdict in 2–4 bullets. - **Issues Found** — each with severity, category, root-cause classification, `file:line`, evidence, and a specific fix. - **Fault Injection Checklist** — mandatory for every new code path: what fails, whether the error is handled, whether failure is silent, whether a test exists. - **Plan Compliance** — which steps were implemented correctly, incorrectly, or missed. - **Verdict** — `PASS` (ready for QA) or `FAIL` (needs fixes). Severity maps directly to the verdict: **P1 (CRITICAL/HIGH) → FAIL**; **P2/P3 (MEDIUM/LOW) → PASS** with notes. A review whose highest finding is P2 or P3 must PASS. ### Iteration limits The Judge is iteration-aware. On **iteration 1** it runs a full review — every changed file, the complete Fault Injection Checklist, full plan compliance. On **iteration 2+** it verifies that the [Doctor](/agents/doctor/)'s fixes resolved the previous findings, runs fault injection only on the new code paths from the fix, and checks whether the fix addressed the root cause or just the symptom. It does not re-flag issues that were already fixed. The build loop allows up to **three** fix cycles before escalation. ### See also - [Inspector](/agents/inspector/) — the precision filter that calibrates the Judge's findings and exposes false positives. - [Builder](/agents/builder/) — produces the diff the Judge reviews. - [Doctor](/agents/doctor/) — fixes the findings on a FAIL. - [How jkz works](/get-started/how-jkz-works/) — the Build (review) phase in context (the dedicated `/jkz:pipeline` end-to-end page lands in a later wiki pass). - [CLI / commands](/reference/cli/) — `/jkz:review` and `/jkz:quick`, the commands that dispatch the Judge. ## Lens Source: https://docs.j0kz.dev/agents/lens/ While [Sentinel](/agents/sentinel/) guards the backend, Lens owns everything the user actually sees: visual fidelity, layout across viewports, loading and empty states, and accessibility. A pixel off, an inconsistent padding, a missing loading indicator — these are not minor details to Lens, they are signals about the care that went into the work. "Almost right" is not something it accepts. Lens is a **reviewer, not an implementer**. It never plans, writes, or patches code. Its single output is a QA report with an explicit verdict. ### At a glance | | | |------|------| | **Phase** | QA | | **Class** | validator | | **Backend** | Validator backend (Ollama Cloud `glm` by default; local Gemini CLI fallback when no endpoint is configured) | | **Runs with** | [Sentinel](/agents/sentinel/), in parallel | | **Fix loop** | A FAIL routes to the [Doctor](/agents/doctor/), up to 3× | | **Invocation** | `node scripts/run.js resolve-wrapper.sh --role lens --pr ` | | **Can merge** | No. Read-only; posts PR comments. | The backend is configurable per role through `JKZ_LENS_ENDPOINT` / `JKZ_LENS_MODEL`. As a validator role, Lens falls back to a local Gemini CLI when no endpoint is set — it never blocks for want of a configured provider. ### Mission Lens performs comprehensive quality assurance focused on **frontend, visual, multimodal, and accessibility** aspects of a pull request. It tests by clicking through actual flows rather than only reading the code, and treats any accessibility regression as automatically high severity. Its scope is strictly what the user sees and interacts with; backend correctness belongs to Sentinel. When a change is a script with no frontend, Lens adapts: it assesses script correctness, edge cases, and the acceptance criteria instead of inventing visual findings. ### Inputs Lens receives every artifact through Git — never a direct message from another agent: - **PR diff** — all changes in the pull request. - **Approved plan** — the original plan and its acceptance criteria. - **Codebase context** — relevant files and the current UI state. - **Screenshots / recordings** — when e2e visual QA is enabled (`JKZ_VISUAL_QA=1`), the orchestrator passes captured screenshots so Lens can inspect rendering, layout, and UI state natively. ### Outputs Lens produces a single Markdown QA report, posted as a PR comment, with these sections: - **TL;DR** — 2–4 bullets: the overall PASS/FAIL verdict plus the key critical, high, and (optionally) medium issues. - **Frontend Assessment** — UI changes, layout across viewports, responsiveness, interactions, and loading / error / empty states. - **Accessibility** — keyboard navigation, screen-reader support (ARIA roles and labels), WCAG AA color contrast, and focus management. - **Visual Consistency** — adherence to the design system, typography, spacing, and theme variables over hardcoded values. - **Acceptance Criteria** — each criterion marked PASS / FAIL / NOT TESTABLE, with the evidence used to verify it. - **Issues Found** — per issue: severity, category, description, reproduction steps, expected vs. actual, and visual evidence. #### Verdict Every report ends with an explicit, machine-parsed verdict: - **PASS** — no critical or high issues. Ready for human review. - **FAIL** — issues that must be fixed, listed. Routes to the Doctor. ### Where Lens fits Lens runs in the QA phase, after the build's Judge → Inspector review passes. It executes alongside Sentinel and reports to the post-QA ambiguity gate before the human merge. See [How jkz works](/get-started/how-jkz-works/) for the QA phase in the context of the full pipeline, and [Sentinel](/agents/sentinel/) for its backend-and-security counterpart. ## Librarian Source: https://docs.j0kz.dev/agents/librarian/ The **Librarian** is jkz's memory desk. It does not create knowledge — it makes existing knowledge findable. When an agent or a human asks "what did we decide about X?" or "where is the pattern for Y?", the Librarian answers with a citation back to the source, never a guess. | | | |---|---| | **Model** | Claude Haiku 4.5 | | **Class** | utility | | **Phase** | Any — a cross-phase support role | | **Invocation** | `node scripts/librarian.js `, or the MCP tool `librarian_query` | ### Mission Index, organize, and retrieve. The Librarian is read-only by design: it never modifies a source file, opens a PR, or posts a comment. Its single job is recall — turning the project's accumulated history into a searchable answer with a source attached. ### What it reads The knowledge base is built from four sources: 1. **Memory files** — `MEMORY.md`, project instructions, `CLAUDE.md`. 2. **Deliberations** — past agent responses, verdicts, ADRs, and accumulated patterns. 3. **Pipeline state** — phase transitions, issue types, iteration counts. 4. **Cross-chat registry** — knowledge from other sessions, when available. ### How retrieval works Two phases. First, an FTS5 BM25 search runs locally and fast — it returns the top-ranked matches in well under a second. Then Haiku synthesizes those matches into a concise answer with the sources cited inline. If Haiku is unavailable, the raw FTS5 results are returned directly rather than nothing at all. Indexing is incremental by default: the `index-latest` subcommand only processes files changed since the last run, which is what the session hooks call. ### The rules it lives by - **Read-only.** It never changes source files, creates PRs, or posts comments. - **Always cite.** Every answer references the file or deliberation it came from. - **No fabrication.** If the knowledge base has no answer, it says so. It never invents one. That last rule is the point of the role. A search engine that occasionally makes things up is worse than no search engine — so the Librarian would rather return "not found" than a plausible fiction. It is the same evidence discipline the rest of the pipeline runs on, applied to recall. ## Orchestrator Source: https://docs.j0kz.dev/agents/orchestrator/ The **Orchestrator** is the one role that is not invoked, because it *is* the runtime: Claude Code itself. It does not design, build, inspect, or operate. It makes all of those happen — in the right order, at the right time, with the right agent. | | | |---|---| | **Model** | Claude Code (Opus) | | **Class** | meta-role (runtime) | | **Phase** | All | | **Invocation** | None — Claude Code *is* the Orchestrator | ### Mission Route agents in the right order, detect when a phase is stuck, and present decisions clearly when the human needs to act. It also adapts how it frames context for each agent — so each gets exactly what it needs and nothing it doesn't. ### What it is not - **Not a participant.** It never writes plans, code, reviews, or tests. It invokes the agents who do. - **Not the boss.** It does not override agent verdicts. If the Judge says FAIL, the PR needs fixes — the Orchestrator routes the failure, it does not overrule it. - **Not autonomous.** The human is the final authority. The Orchestrator facilitates checkpoints; it never skips them. - **The only one who sees everything.** Each agent sees its own input and output. The Orchestrator sees the full timeline — every iteration, every verdict, every drift. ### The state machine The Orchestrator advances issues through a fixed set of legal phase transitions (`jkz:ready` → `jkz:planning` → `jkz:building` → `jkz:reviewing` → `jkz:qa` → `jkz:approved`, with fix loops back through `jkz:fixing`). Any transition not in that table is illegal: if a command attempts one, the Orchestrator halts and reports the violation rather than forcing it. The full table lives in the private repo's `agents/orchestrator.md`. ### How it decides At each phase boundary the Orchestrator picks one of four moves: | Decision | When | |----------|------| | **Advance** | All agents in the phase returned PASS, no CRITICAL/HIGH issues remain, and the evidence hierarchy is satisfied. | | **Iterate** | At least one agent returned FAIL, the count is under three, and the issues are addressable. | | **Escalate to the Doctor** | Review or QA failed on code-level issues fixable by an implementation change. | | **Escalate to the human** | Three iterations exhausted, agents contradict on a CRITICAL issue, a backend is down, or scope is ambiguous. | It also watches for drift: when the same issue recurs across iterations, that is not a bug to fix again — it is a design problem to escalate. Honest escalation beats a fix that merely passes the checks. ### Where you come in The Orchestrator is autonomous *between* checkpoints, never *through* them. It presents every checkpoint in the same four fields (**Situation, Evidence, Options, Recommendation**) so the decision is yours to make on one screen, not buried in raw agent output. And it never merges: only you reach `main`. See [How jkz works](/get-started/how-jkz-works/) for the full set of human gates. ## Sentinel Source: https://docs.j0kz.dev/agents/sentinel/ Sentinel protects the operation. While [Lens](/agents/lens/) owns what the user sees, Sentinel owns what holds it up: backend integrity, security posture, performance, and infrastructure. Nothing ships without its sign-off on the technical foundation. Security vulnerabilities, performance regressions, untested paths — these are not abstract risks to Sentinel, they are real exposures it will not tolerate. It verifies everything, trusts nothing, and demands evidence. Sentinel is **adversarial** by design, but adversarial is not obstructive. It defaults to PASS and only fails on a concrete, evidence-backed exposure introduced or surfaced by the PR. A false-positive CRITICAL costs a wasted Doctor iteration and a misled human — so it calibrates accordingly. ### At a glance | | | |------|------| | **Phase** | QA | | **Class** | adversarial | | **Backend** | External, configurable, **required** — resolved at runtime via `JKZ_SENTINEL_ENDPOINT` / `JKZ_SENTINEL_MODEL` | | **Runs with** | [Lens](/agents/lens/), in parallel | | **Fix loop** | A FAIL routes to the [Doctor](/agents/doctor/), up to 3× | | **Invocation** | `node scripts/run.js resolve-wrapper.sh --role sentinel --pr ` | | **Can merge** | No. Read-only; posts PR comments. | As an adversarial role, Sentinel's endpoint is **mandatory**: there is no silent fallback to a native CLI. If `JKZ_SENTINEL_ENDPOINT` is unset, the wrapper exits with code 4 and the QA phase halts rather than quietly skipping its challenger. Diversity is the point — the model that wrote the code is never the model that signs off on it. ### Mission Sentinel performs the security scan completely, methodically, and without shortcuts. Logic correctness was already addressed by the Judge → Doctor cycle in the build phase; Sentinel revisits logic only if the Doctor's fix introduced a new regression. Its focus is the **trust boundary**: for every new function that accepts external input, Sentinel is the final check before it ships. Its discipline is encoded in a few hard rules: - **Security issues are always at least HIGH.** Any injection, auth bypass, or data exposure is a blocker. - **CRITICAL requires execution or file-citation evidence** — a finding backed only by reasoning is downgraded or dropped. - **Theoretical attacks without a reachable path are not CRITICAL.** "What if an attacker does X" needs a path through the actual diff. - **Pre-existing exposures are out of scope** — filed as separate `jkz:ready` issues, not used to block the PR. ### Inputs Sentinel receives every artifact through Git: - **PR diff** — all changes in the pull request. - **Approved plan** — the original plan and its acceptance criteria. - **Codebase context** — relevant backend files, configs, and dependencies. - **Pre-validated checks** *(optional)* — deterministic validator results (secrets, leftover debug, capability invariants) injected as Level-1 evidence. Sentinel does not re-flag what the validators already caught. - **Threat model** *(when available)* — STRIDE threats from the Architect's plan; Sentinel verifies each mitigation is implemented and effective, and flags unimplemented ones as HIGH. ### Outputs Sentinel produces a single Markdown QA report, posted as a PR comment, with these sections: - **TL;DR** — 2–4 bullets: the PASS/FAIL verdict plus key critical and high findings, with file:line where applicable. - **Backend Assessment** — API changes, database and migrations, error handling, data validation, and state / concurrency. - **Security Scan** — attack-surface mapping first, then a category sweep: injection, authentication, authorization (IDOR, privilege escalation), secrets, data exposure, and dependency CVEs with a reachable exploit path. - **Performance** — N+1 queries, memory and unbounded allocations, latency, and scalability under load. - **Test Coverage** — whether unit and integration tests exist, cover the right paths, and actually pass — run, not just read. - **Issues Found** — per issue: severity, category, root cause, evidence, impact, and a specific fix. #### Verdict Every report ends with an explicit, machine-parsed verdict: - **PASS** — no critical or high issues. The backend is solid. - **FAIL** — issues that must be fixed, listed. Routes to the Doctor. ### Where Sentinel fits Sentinel runs in the QA phase, after the build's Judge → Inspector review passes. It executes alongside Lens and reports to the post-QA ambiguity gate before the human merge. See [How jkz works](/get-started/how-jkz-works/) for the QA phase in the context of the full pipeline, and [Lens](/agents/lens/) for its frontend-and-accessibility counterpart. ## Automations & GitHub integration Source: https://docs.j0kz.dev/subsystems/automations-and-github/ jkz keeps almost nothing in a private database. The pipeline's state machine lives in GitHub labels, inter-agent feedback flows through pull-request comments, and the verdicts that decide whether code advances are posted as Check Runs. GitHub *is* the bus. Two things make that work: a small **automations engine** that reacts to time and to named events, and a set of **integration scripts** that translate pipeline transitions into GitHub mechanics — labels, issue relationships, status comments, and a Projects board. One principle runs through all of it: **the integration layer never blocks.** A relationship that fails to register, a Check Run the token isn't allowed to write, a Projects board that isn't configured — none of these stop the pipeline. Each script traps its own errors and exits clean. The merge gate and the adversarial review layer are the real guardrails; everything here is bookkeeping that *should* succeed and is harmless when it doesn't. ### The automations engine The engine is a trigger-dispatch loop defined in [`scripts/automations/run.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/automations/run.js), driven by a single manifest at [`scripts/automations/config.json`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/automations/config.json). Each entry binds a **trigger** to an **action module**: ```json { "automations": { "ci-failure-main": { "trigger": { "type": "event", "event": "ci.failure.main" }, "action": { "module": "ci-failure-main" }, "enabled": true }, "stale-cleanup": { "trigger": { "type": "interval", "intervalMs": 86400000 }, "action": { "module": "stale-cleanup" }, "enabled": false } } } ``` Two trigger types exist. **Interval** triggers fire on a tick (the Telegram bot's monitoring loop calls `run.js --tick` periodically and runs any interval automation whose time has come). **Event** triggers fire by name — `run.js --event ` dispatches every enabled automation listening for that event. An action is a plain Node module under [`scripts/automations/actions/`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/automations/actions); if the module named in the manifest is missing, that automation is skipped (`status: action_not_found`) rather than crashing the tick. The whole engine is gated behind a single flag: every dispatch path returns early unless `JKZ_AUTOMATIONS_ENABLED=true`. Run state — last run timestamp, run count, last result — is persisted to `state/automations.json`. The currently registered automations: | Automation | Trigger | Enabled | What it does | |------------|---------|---------|--------------| | `ci-failure-main` | event `ci.failure.main` | yes | Auto-creates an issue when CI fails on `main`. | | `cr-plan-ready` | event `jkz.cr-plan-ready` | yes | Logs when CodeRabbit posts a Coding Plan on an issue. | | `stale-cleanup` | interval (24h) | no | Code-hygiene scan — stale TODOs, unused exports, orphan tests, dead config. | | `entropy-scan` | interval (7d) | no | Full-repo scan through the validators (secrets, stubs, `console.log`). Disabled here; runs exclusively from the Hermes cron host to avoid cross-host duplicate issues. | `stale-cleanup` is the most illustrative action. It runs four scanners — stale TODO/FIXME/HACK comments older than 60 days, `module.exports` with no references, test files with no matching source, and config drift (action modules that don't exist, `.env.example` vars never read) — and files a single deduplicated `jkz:ready` + `refactor` issue if anything turns up. Same-day reruns short-circuit on a dedup marker. #### Triggering automations from MCP The automations engine is also reachable over the [MCP server](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/mcp/src/index.ts). Two scoped tools wrap the CLI: - **`list_automations`** (scope `read`) — runs `run.js --list` and returns each automation's name, trigger, enabled flag, last run, run count, and last result. - **`trigger_automation`** (scope `write`) — takes a `name` and runs `run.js --trigger `. Scopes follow a three-tier hierarchy (`read` < `write` < `admin`) enforced on the HTTP transport. A read-only dashboard token can inspect automations but cannot fire them; firing requires a `write` token. ### GitHub as the state machine: labels Every phase of the pipeline is a GitHub label, and the cardinal rule is ownership: **if you didn't add it, don't remove it.** Each label has exactly one owner — the command or script that applies it — and only that owner (or the Orchestrator's `orchestrate.sh transition`, which clears all agent labels on every phase change) may remove it. The full ledger lives in [`docs/LABEL-OWNERSHIP.md`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/docs/LABEL-OWNERSHIP.md); the shape: | Family | Count | Owner | Notes | |--------|-------|-------|-------| | Phase (`jkz:ready` … `jkz:approved`, `jkz:blocked`, `jkz:pipeline`) | 9 | `orchestrate.sh transition` | Mutually exclusive; the transition clears the old one. | | Agent (`jkz:architect`, `jkz:judge`, `jkz:sentinel`, …) | 9 | The phase command that runs the agent | Cleared on transition. | | Type (`bug`, `refactor`, `chore`) | 3 | `/jkz:start`, `/jkz:issue` | Immutable once set; no `jkz:` prefix. | | Automation (`jkz:regression`) | 1 | `monitor.sh` in CI | Created with dedup; not part of the worktree/PR flow. | | Wiki (`docs-worthy`) | 1 | Human triage | Read-only from the pipeline's perspective. | Phase transitions are validated against a state machine — illegal transitions are rejected, not silently applied. ### Issue relationships: blocked-by, epic, sub-issue When an issue body declares a relationship, jkz registers it as a *native* GitHub relationship at creation time — not as prose. Two markers are scanned: - `**Blocked by:** #N` → a blocked-by relationship, registered via [`scripts/gh-blocked-by.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/gh-blocked-by.js). - `**Epic:** #N` / `**Parent:** #N` → a parent/child sub-issue relationship, registered via [`scripts/gh-sub-issue.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/gh-sub-issue.js). The colon after `Epic` / `Parent` is required — without it the line is read as prose, which keeps words like "epicenter" or "parent company" from triggering a false relationship. Both scripts work the same way: resolve the issue numbers to GraphQL node IDs (cached to avoid redundant lookups), then run the `addBlockedBy` / `addSubIssue` (or `remove…`) GraphQL mutation, with the query written to a temp file to sidestep shell-escaping. And both are strictly **fail-open**: every error is logged to stderr and the script exits `0` regardless. A single kill-switch disables all relationship API calls without a code change: ```bash JKZ_GH_RELATIONSHIP_DISABLE=1 ``` ### Verdicts as Check Runs Adversarial and validator verdicts (Judge, Inspector, Lens, Sentinel) post to the PR as a comment *and* as a GitHub Check Run named `jkz:`. The Check Run is written by [`scripts/github-review.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/github-review.js): a `PASS` verdict maps to conclusion `success`, `FAIL` to `failure`, anything else to `neutral`, with the severity counts (`2C 1H 0M`) in the output summary. Check Runs are **best-effort, not gating**. If the token lacks `checks:write`, the API call fails and the error is swallowed — the comment still lands, and the pipeline carries on. Branch protection rules, not these Check Runs, control whether a merge is actually allowed. ### Pinned comments and Projects sync Two more integrations keep the GitHub surface tidy as the pipeline runs: - **Pinned status comments** — [`scripts/pin-status-comment.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/pin-status-comment.sh) pins milestone status comments (pipeline started, plan checkpoint, pipeline complete/blocked) on the issue and unpins the previous one, so the latest status is always the pinned one. It pins via the REST API and falls back to a GraphQL mutation on a 404. - **Projects board sync** — [`scripts/project-sync.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/project-sync.sh) moves the issue's card to the column matching the new phase on every transition. It is entirely optional: it reads `JKZ_PROJECT_NUMBER` (plus per-phase option IDs) from `.env`, and if `JKZ_PROJECT_NUMBER` is unset it exits immediately, a no-op. And on the PR itself, [`scripts/minimize-old-comments.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/minimize-old-comments.sh) collapses superseded agent comments: when a role posts a fresh verdict, the previous comments from that same role are minimized as `OUTDATED` via GraphQL, leaving only the latest visible. A short per-PR-per-role debounce prevents API thrash when several agents post in quick succession. Like the relationship scripts, all four of these trap their errors and exit `0` — a pinned comment that fails to pin, or a board that isn't configured, never interrupts the run. ### The common thread Every integration on this page shares the same contract: **observe and record, never block.** The automations engine skips a missing action instead of throwing; the relationship scripts exit clean on any API error; Check Runs degrade to comments when the token is under-scoped; Projects sync is a no-op when unconfigured. That is deliberate. GitHub is where jkz keeps its state and posts its results, but the authority to *stop* a change lives elsewhere — in the [merge gate](/concepts/merge-gate/) and the adversarial review layer of the [pipeline](/concepts/pipeline/). The integration layer's job is to make the state legible, not to enforce it. ### Related - [Pipeline](/concepts/pipeline/) — the phase flow whose transitions drive labels, Check Runs, pinned comments, and Projects sync. - [Merge gate](/concepts/merge-gate/) — the real enforcement layer behind the best-effort Check Runs. - [Issue types](/concepts/issue-types/) — how `bug` / `refactor` / `chore` type labels shape the pipeline. - [Telegram bot](/subsystems/telegram-bot/) — the monitoring loop that ticks the interval automations. - [Hermes](/subsystems/hermes/) — the cron host that runs `entropy-scan` and other scheduled jobs. ## Classifier & Alignment Validator Source: https://docs.j0kz.dev/subsystems/classifier-and-alignment/ Two checks run at the very front of the system, before a single agent starts deliberating. They answer different questions about the same incoming issue: - **How much pipeline does this deserve?** — the [complexity classifier](#issue-complexity-classifier) routes the issue to `trivial`, `quick`, or `standard`. - **Does the issue body still say what the user asked for?** — the [alignment validator](#issue-alignment-validator) compares the source (a conversation, a brief, or raw input) against the issue body the pipeline will consume, and repairs drift before it propagates. Both are deliberately defensive: a failure in either one falls back to a safe default rather than blocking the work. They steer and correct, but they never stop the user from getting in. ### Issue complexity classifier `scripts/classify-issue.js` reads a GitHub issue and decides how much process it warrants. A typo does not need an Architect; a multi-system refactor should not skip planning. The classifier makes that call up front so the routing happens before any model starts working, not halfway through. #### Hybrid by design The classifier is not a pure LLM call. It combines deterministic signal extraction with a Haiku judgment, and keeps a deterministic scorer in reserve: - **Signals first.** A deterministic pass extracts ground truth from the issue text: the files mentioned and how many layers they span (`scripts`, `agents`, `docs`, `config`, `code`), whether design or compliance keywords appear, whether the body contains a code block, and how many Acceptance Criteria items it lists. These are facts, not opinions. - **Haiku decides.** Those signals are handed to Haiku as verified context alongside the full issue body, and the model returns the classification with one sentence of reasoning. The model is configurable via `JKZ_CLASSIFY_MODEL`. - **Deterministic fallback.** If the LLM is unavailable, a scoring heuristic over the same signals produces a verdict anyway. Design keywords and a layer span of three or more weigh toward `standard`; a present code block weighs toward something simpler; four or more Acceptance Criteria items nudge the score up. The classifier never fails closed. #### What it returns A single JSON object written to stdout: | Field | Values | |-------|--------| | `complexity` | `trivial` · `quick` · `standard` | | `confidence` | `high` · `medium` · `low` | | `recommended_pipeline` | the route to take (`trivial`, `quick`, or `pipeline`) | | `reasoning` | one sentence on why this tier | | `signals` | the deterministic facts the decision was built on | #### How the verdict routes the work | Complexity | Route | |------------|-------| | `trivial` | Handle it directly in chat — no pipeline. | | `quick` | [`/jkz:quick`](/commands/quick/) — Builder + Judge, no plan or QA. | | `standard` | The full [pipeline](/concepts/pipeline/), planning first. | The result is cached as a `complexity:*` label on the issue, so the same answer is reused rather than recomputed every time the issue is touched. When confidence is anything below `high`, the recommendation is to read the referenced files before committing to a route — the classifier flags its own uncertainty rather than hiding it. The classifier is also documented from the agent angle on the [Classifier](/agents/classifier/) page; this section covers it as a subsystem. ### Issue alignment validator `scripts/validate-issue-alignment.js` guards against a subtler failure: the issue body the pipeline reads slowly drifting away from what the user actually asked for. A long planning conversation gets distilled into a brief, the brief becomes an issue body, and at each hop a constraint can get dropped or an entity quietly renamed. The validator runs adversarial checkpoints at those hops and repairs the drift in place. #### Three checkpoints | Checkpoint | Where it runs | Compares | |------------|---------------|----------| | `conversation_vs_brief` | `/jkz:start`, after the brief is built | conversation → brief | | `brief_vs_body` | `/jkz:start`, after the issue is created | brief → issue body | | `input_vs_body` | `/jkz:issue` | raw input → issue body | #### How a checkpoint works Each checkpoint runs the same adversarial pipeline over a *source* and a *target*: 1. **Extract** (Sonnet, with extended thinking) — pull entities and constraints out of the source text, and entities out of the target. 2. **Challenge** (Opus) — an adversarial pass over the Sonnet extraction, catching entities and constraints the first pass missed. The challenger's findings are merged back into the source extraction. 3. **Compare** — a deterministic entity diff plus a semantic constraint check. The constraint check only calls Sonnet for constraints marked `weight: high`; lower-weight items are recorded as warnings, not gaps. This keeps the gate focused on what matters. 4. **Regenerate** — if there are gaps, regenerate the target (brief or body) to close them. #### The triple gate on regeneration A regenerated body is only accepted if it passes three independent checks — otherwise the original (v1) is kept untouched: 1. **Length sanity** — the new version must be at least 70% the length of the original (`v2.length >= v1.length * 0.7`), so a regeneration cannot silently truncate the issue. 2. **Hash sanity** — `sha256(v1) !== sha256(v2)`, so an "accepted" regeneration that changed nothing is rejected. 3. **Entity diff** — every entity in the regenerated text must already be present in the source. This is the anti-hallucination gate: the regenerator may close gaps, but it may not invent new entities. A failure here returns `hallucinated_entities` and the original is preserved. #### Outcomes | Outcome | Meaning | Notification | |---------|---------|--------------| | `aligned` | No gaps detected | silent | | `regenerated` | Gaps closed, the triple gate accepted v2 | warn | | `regen_suspicious` | Gaps detected but the triple gate rejected v2 (kept v1) | warn | | `validator_error` | A runtime error in any component | critical | | `tier_bypass` | `--tier` was `trivial` or `quick` | silent | | `disabled` | `JKZ_ALIGNMENT_DISABLE=1` | silent | | `source_unavailable` | The required source file was missing at pre-check | silent | #### Fail-open by contract The validator never blocks the pipeline by default. Every error path — a missing component, a `gh` failure, an unhandled exception at the top level — resolves to exit 0, and the pipeline carries on with the body it already has. The opt-out for the conversation-persistence path (`JKZ_ALIGNMENT_DISABLE_CONVERSATION_PERSIST=1`) is the expected reason a `source_unavailable` outcome appears: the conversation transcript was deliberately not persisted, so the first checkpoint has nothing to read. When you want the opposite — a hard gate — `JKZ_ALIGNMENT_REQUIRED=1` flips only the failure paths to fail-closed: `validator_error` and unhandled top-level exceptions exit 1. Every other outcome (including `aligned`, `regenerated`, and `regen_suspicious`) still exits 0. #### Privacy and kill-switches Notifications carry **hashes, counts, and durations only — never the raw source text**. A Telegram payload looks like `outcome=regenerated checkpoint=brief_vs_body issue=1587 entity_gaps=2 v1=a1b2c3… v2=d4e5f6… duration_ms=8200`, so source content never leaves the machine through the notification channel. | Kill-switch | Effect | |-------------|--------| | `JKZ_ALIGNMENT_DISABLE=1` | Full rollback — every checkpoint returns `disabled` | | `JKZ_ALIGNMENT_DISABLE_CONVERSATION_PERSIST=1` | Opt the conversation transcript out of persistence (PII opt-out) | | `JKZ_ALIGNMENT_REQUIRED=1` | Fail-closed on error paths only | #### When alignment is skipped The `trivial` and `quick` tiers bypass the validator automatically — there is nothing to gate when the issue routes around the full pipeline. Beyond that, a deliberate `--skip-alignment` exists for cases where the issue body is mechanically derived from a verifiable artifact (a scan output, an audit report, a CodeRabbit thread) that is cited inline in the body. The skip has to be earned per use: it is for bodies a reviewer can independently re-read from the cited source, not for free-form conversations redacted into an issue. ### How they fit together The classifier runs first and decides the route. The alignment validator runs at the intake checkpoints and keeps the issue body honest — and notably, the validator *uses* the classifier's verdict: a `trivial` or `quick` tier short-circuits alignment entirely. Together they make sure that by the time an [Architect](/agents/architect/) or [Builder](/agents/builder/) starts working, the issue has both the right amount of process attached to it and a body that still reflects what the user asked for. ## CodeRabbit & Notifications Source: https://docs.j0kz.dev/subsystems/coderabbit/ Most of jkz is about getting code right before a human sees it. Two subsystems sit across the whole pipeline to make that work without slowing you down. **CodeRabbit** is an external AI reviewer that comments on every pull request, giving the pipeline a second, independent opinion alongside its own agents. The **notification layer** mirrors what those agents are doing to your chat tools and lets you approve, reject, or stop a run from anywhere — so the human-in-the-loop checkpoint does not require you to be sitting at the terminal. ### CodeRabbit integration CodeRabbit is an AI code-review bot that comments on GitHub pull requests. jkz treats it as an additional adversarial reviewer that runs *alongside* the pipeline's own agents (Judge, Inspector, Sentinel) — not as a replacement for them. The pipeline never merges on CodeRabbit's say-so; its findings are triaged like any other signal and folded into the same human checkpoint. #### Where it runs CodeRabbit shows up at three points in a pipeline run: - **PLAN** — `cr-plan-iterate.js` feeds CodeRabbit's comments on the plan PR back into the planning loop, catching design problems before any code is written. Informational and non-blocking. - **BUILD** — CodeRabbit pre-scans the diff, then the **CR fix loop** addresses its findings before the Judge reviews. Pre-push validators run afterward. - **Post-PASS** — once the Judge returns PASS, **CR reconciliation** (`cr-reconcile.js`) catches any findings that landed after the last review iteration, so nothing slips through between the final review and approval. #### Triage discipline Every CodeRabbit finding is classified before any action is taken, and every classification is checked against the **actual diff** — many findings target pre-existing code or rest on a misreading of the change. | Classification | Meaning | Action | |----------------|---------|--------| | **VALID** | Correct, and affects code introduced by this PR | Fix the code | | **FALSE_POSITIVE** | Incorrect or based on a misunderstanding | Reply with a file citation, then resolve | | **OUT_OF_SCOPE** | Valid, but affects pre-existing code rather than this PR | Open a follow-up issue | | **ALREADY_FIXED** | Addressed in an earlier commit | Reply noting it is fixed, then resolve | A `FALSE_POSITIVE` dismissal **requires a file citation** (`path/to/file.ext:LINE`) as evidence — a dismissal without one is re-classified as `VALID` or `OUT_OF_SCOPE`. This keeps the bot's findings honest in both directions: real issues get fixed, and spurious ones get dismissed only with a reason a reviewer can re-check. #### The tools - **`/jkz:cr-fix`** — triage and address multiple findings in one pass. - **`coderabbit:autofix`** — apply a single committable suggestion with per-change approval. - **`cr-reconcile.js`** — fetches CodeRabbit findings as structured JSON for the Orchestrator to triage. It deliberately does **not** classify; classification is the Orchestrator's job, so the rule above is applied with full pipeline context. - **`cr-resolve.sh`** — atomically replies to a review thread **and** resolves it. The two steps must happen together; the script reserves exit code `2` for the "reply posted but resolve failed" case so a thread is never silently left replied-but-unresolved. - **`minimize-old-comments.sh`** — collapses a role's outdated comments when a new review iteration posts, keeping the PR conversation readable. #### The pre-flight gate `cr-preflight-gate.sh` blocks the transition to `jkz:approved` while any CodeRabbit thread is still unresolved. A thread counts as addressed if it has a dismissal reply **or** is covered by a commit pushed after the comment was created. The gate is part of the merge defenses, not a substitute for them — it is bypassable with `--force` or the `JKZ_CR_GATE_DISABLE=1` kill-switch (emergency use only). Finding history is persisted across runs by the `cr-history-*` scripts (ingest, store, query), so the pipeline can see how similar findings were triaged before. ### Notifications A single dispatcher, `notify.sh`, mirrors pipeline activity to one or more backends and surfaces the human checkpoints for approval. It is built to be invisible when healthy and impossible to let block a run. #### Backends Notifications are multi-backend, selected via `JKZ_NOTIFY_BACKEND` (comma-separated for more than one): - **Discord** — threaded posts with pre-seeded reaction emojis for approvals. - **Telegram** — a long-polling daemon (`telegram-bot.js`) with inline-keyboard buttons and full pipeline control from your phone. - **GitHub** — checkpoint state mirrored to the issue for the GitHub approval poller. `notify.sh` **never blocks the pipeline**: it traps errors to `exit 0`, caps every network call with `curl --max-time 5`, and exits silently when notifications are disabled — so a missing or misconfigured backend can never stall a run. #### Levels and events Verbosity is controlled by `JKZ_NOTIFY_LEVEL` (`all`, `checkpoint`, or `critical`) and is overridable per backend, so you can get every agent post in Discord while Telegram only pings you at checkpoints. The dispatcher formats distinct events — `agent-posted`, `phase-transition`, `checkpoint`, `pipeline_complete`, `pipeline_blocked`, `ci_failed`, and pipeline-stuck escalations — each tagged with a model badge and a verdict icon. #### Approvals and feedback At a human checkpoint the pipeline posts approval controls — Discord reactions (✅ ❌ 🛑) or Telegram inline buttons (`[✅ Approve]`, `[❌ Reject]`, `[🛑 Stop]`). Only users listed in `JKZ_APPROVER_IDS` can approve. Replies are captured as bidirectional feedback and consumed at the next checkpoint via `state/threads.json`, which is file-locked (`flock`, with a portable shim on macOS) so concurrent writers never corrupt it. The Telegram bot also runs a monitoring loop with periodic health checks and proactive task discovery, surfacing suggestions as inline buttons — it suggests, and the human acts. The hard kill-switch `JKZ_NOTIFY_FORCE_DISABLE=1` disables all notifications regardless of `.env`; the test suite sets it so a run never sends a real message. The full setup guide — Discord and Telegram credentials, the bot service, and command reference — lives in `docs/notifications.md` in the main repo. ### Related - [Pipeline](/concepts/pipeline/) — the BUILD → REVIEW → QA flow where CodeRabbit and the checkpoints fire. - [Merge gate](/concepts/merge-gate/) — the merge defenses the CodeRabbit pre-flight gate complements. - [Hermes](/subsystems/hermes/) — the always-on agent that reports its scheduled jobs through the same Telegram layer. ## Hermes Source: https://docs.j0kz.dev/subsystems/hermes/ Most of jkz runs in front of you: an interactive Claude Code session driving a pipeline you approve step by step. Hermes is the part that runs when no one is watching. It is a long-lived container on a VPS that executes jkz's scheduled background work — health checks, security audits, cost reports, cleanup, and autonomous research — and reports the results to Telegram. It runs deterministically, mostly without LLM calls, and independently of any open chat. ### The scheduler model Hermes is scheduled by the **Linux `cron` daemon running inside the container** — not by a hand-edited crontab, and not by an LLM. The single source of truth is [`config/cron-registry.json`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/config/cron-registry.json) in the main repo. At container start, the entrypoint runs `scripts/hermes/generate-crontab.sh`, which reads the registry, expands the `${HERMES_JKZ_ROOT}` path variable to the container path, and writes `/etc/cron.d/jkz`. The cron daemon then fires each line on its schedule. The generator is idempotent (it overwrites `/etc/cron.d/jkz` on every run), so the registry is always the authority and `/etc/cron.d/jkz` is never edited by hand. ```text container start → entrypoint → bash scripts/hermes/generate-crontab.sh → reads config/cron-registry.json → writes /etc/cron.d/jkz (paths expanded; "runner": "direct" jobs skipped) → service cron start → cron daemon fires jobs on schedule → wrapper saves state/reports//.json → wrapper posts to Telegram (per thread) ``` **Why cron and not Hermes's own LLM scheduler.** jkz's scheduled jobs are deterministic shell commands — run a script, collect its output, post it. Routing them through an LLM scheduler wasted tokens and added latency for no benefit, so they run as plain cron entries. Hermes does have a separate prompt-based LLM scheduler, but it is reserved for prompt-driven jobs and is not used for the registry above. To pick up a registry change, regenerate without a full restart: ```bash HERMES_JKZ_ROOT=$(pwd) bash scripts/hermes/generate-crontab.sh --dry-run # local preview, no root docker exec hermes-agent bash ${HERMES_JKZ_ROOT}/scripts/hermes/generate-crontab.sh docker exec hermes-agent service cron reload ``` ### The jobs The registry holds **28 jobs**: 26 run under container cron, and 2 are marked `"runner": "direct"` so the generator skips them — they run from the VPS host crontab instead (currently the autobackup and a DST-adjustment helper). Each job wraps its script with `hermes-report-wrapper.sh`, which persists a JSON report to `state/reports//.json` and posts a summary to Telegram. Jobs are organized by Telegram thread: | Thread | Purpose | Examples | |--------|---------|----------| | **29 — System Health** | Operational alerts and the daily digest | `git-sync`, `health-check`, `task-discovery`, `cli-updates`, `slo-check`, `daily-digest`, cost summaries, `research-poll`, `research-bisync` | | **33 — Maintenance** | Weekly audits, security scans, analytics, cleanup, learning | `entropy-scan`, `doc-sync`, `deps-audit`, `bugs-scan`, `supply-chain`, `quality-scan`, `postmortem`, `memory-curate`, `skill-security-audit`, `state-cleanup`, `learning-digest`, `pagefind-validate` | Every day at 07:00 CLT, `daily-digest` aggregates the day's reports into a single traffic-light summary (RED / YELLOW / GREEN), and flags any job that was expected to run but did not report. Two operational jobs are worth calling out: `git-sync` hard-resets the VPS working tree to `origin/main` each night so jobs run against merged code (runtime `state/` is gitignored and never clobbered), and `research-poll` drains the `jkz:research-pending` queue — the entry point to Hermes's autonomous research subsystem, which runs headless `/jkz:research` invocations independently of the BUILD/REVIEW/QA pipeline. ### Cost model Almost every job is a shell command that consumes **zero LLM tokens, zero GPU time, and $0**. Two jobs are deliberate exceptions: - **`doc-sync`** calls Claude Haiku to detect documentation drift — roughly 1K tokens per run, twice a week. - **`research-poll`** calls Opus via `claude --print`, but **only when the `jkz:research-pending` queue is non-empty**. Idle ticks cost nothing; an active queue charges one Opus run per pending issue, bounded by the poller's outer 270 s timeout and `JKZ_HERMES_POLL_MAX_DURATION_SEC` (default 3600 s). ### LLM backends Hermes's *interactive* surfaces — the Telegram bot and CLI — answer through cloud LLM backends, not Claude: **Ollama Cloud** (a paid hosted plan, not a local model and not the free tier) and **Kimi** (Moonshot). Both are cloud-hosted. The only Claude usage on Hermes is the two cron exceptions above, which authenticate through a long-lived `CLAUDE_CODE_OAUTH_TOKEN` stored in the container environment. ### Infrastructure notes - The container `hermes-agent` runs on the project VPS. Jobs execute as the unprivileged user `hermes` (uid 10000). - Every job command references `${HERMES_JKZ_ROOT}` (default `/opt/data/jkz`); the generator expands it at write time so `/etc/cron.d/jkz` holds literal paths. - Docker bind-mounts can create root-owned files in the working tree; correcting ownership to `10000:10000` from the VPS host keeps the `hermes` user able to write. - A DST-adjustment helper recalculates UTC schedules on Chile's daylight-saving transitions, so the Chile-local times the schedules target stay stable across the clock change. ### Related - [Pipeline](/concepts/pipeline/) — the interactive BUILD → REVIEW → QA flow Hermes runs *alongside*, not inside. - [Cross-chat awareness](/concepts/cross-chat/) — how Hermes's `git-sync` and the live sessions share one working tree without colliding. ## Hooks Source: https://docs.j0kz.dev/subsystems/hooks/ Claude Code fires events throughout a session: before a tool runs, after it finishes, when a session starts or ends, when the conversation is about to be compacted. jkz attaches small scripts — **hooks** — to those events. They are fast, deterministic, and mostly invisible until something needs to be stopped or recorded. Two families do very different jobs, and the line between them is the key to understanding the system: - **Guard hooks** run *before* a tool executes (`PreToolUse`). They can **block** an action — refuse a destructive shell command, a credential read, an edit outside the active worktree. A guard is the only kind of hook that can say "no." - **Lifecycle hooks** run *around* session and tool events (`SessionStart`, `SessionEnd`, `PreCompact`, `Stop`, `SubagentStop`, and friends). They never block; they keep state in sync, snapshot context, and feed observability. A lifecycle hook only ever observes and reacts. ### The fail-open contract Every jkz hook follows one non-negotiable rule: **a hook must never crash the session.** Claude Code treats a `PreToolUse` hook that exits with code `1` (or any unexpected non-zero) as a signal to retry — which produces an infinite retry loop. So the contract is strict: - **Exit `2`** — block the action. This is the *only* way to deny. - **Exit `0`** — allow. This is the default for success *and* for every error. Bash guards open with `trap 'exit 0' ERR`: if anything unexpected happens — malformed JSON, a missing dependency, a parser crash — the guard fails *open* and lets the action through. The safety net is downstream: the Judge and Inspector review every change before merge, so a guard that bails out never silently corrupts the pipeline. The Node dispatcher [`hooks/hook-runner.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/hook-runner.js) enforces this mapping centrally. It spawns the real hook with the resolved dual-root environment (`JKZ_HOME`, `JKZ_TARGET_PROJECT`, `JKZ_STATE_DIR`) and then collapses the child's exit code: child exit `2` propagates as `2` (block); *everything else* becomes `0` (allow). It also rejects any hook name containing `/`, `\`, or `..` to prevent path traversal. ```text PreToolUse event → hook-runner.js (or run-from-git-root.sh) → spawn guard with dual-root env → guard exits 2 → BLOCK the tool call → guard exits 0 → ALLOW (success) → guard errors → ALLOW (fail-open via ERR trap) ``` ### Guard hooks Guards are matched to specific tools. The same guard can be attached to several tools, and several guards can stack on one tool — they run in order, and the first `exit 2` wins. | Guard | Tools matched | What it blocks | |-------|---------------|----------------| | [`guard-destructive.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/guard-destructive.sh) | `Bash` | Commands that could destroy work — force pushes, history rewrites, mass deletions — gated by the session's autonomy level. | | [`guard-credentials.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/guard-credentials.sh) | `Bash`, `Read`, `Edit`, `Write` | Any access (read, write, edit, execute) to credential paths. Zero-access model: it blocks outright, with no confirmation prompt. | | [`guard-injection.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/guard-injection.js) | `Edit`, `Write`, `MultiEdit` | Prompt-injection payloads written into files — zero-width characters, RTL/LTR overrides, ANSI escape sequences in the new content. | | [`guard-velocity.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/guard-velocity.js) | `Bash` | Runaway agents: rate-limits Bash calls within a sliding window. Disabled by default (`JKZ_VELOCITY_LIMIT` is unset → `Infinity`). | | [`guard-worktree.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/guard-worktree.sh) | `Edit`, `Write`, `MultiEdit` | Edits to protected pipeline infrastructure (`scripts/`, `hooks/`, `agents/`, `mcp/`, `.claude/`) from outside the active worktree during a build. | | [`guard-issue-create.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/guard-issue-create.sh) | `Bash` | Raw `gh issue create` against this repo, so every issue goes through the `issue-create.js` pipeline (label + type + complexity + alignment). | Two guards have escape hatches for emergencies: `JKZ_ISSUE_GUARD_DISABLE=1` skips the issue-create guard, and the velocity guard stays inert unless `JKZ_VELOCITY_LIMIT` is set. Guards intentionally do *not* try to catch every bypass — a `Bash` `echo > file` can sidestep `guard-worktree.sh`. That is by design: guards stop the obvious foot-guns cheaply, and the adversarial review layer (Judge / Inspector) catches what slips through. ### Lifecycle hooks Lifecycle hooks fire on session and tool events. None of them can block; they exist to keep jkz's state and observability coherent across a session's life. | Event | Hook | Role | |-------|------|------| | `SessionStart` | [`on-session-start.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/on-session-start.sh) | Interactive init: prerequisite checks, pipeline-state GC, worktree summary, vault/memory health, git-hook install. | | `SessionEnd` | [`on-session-end.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/on-session-end.sh) | Cleanup and warnings about active worktrees / in-progress builds; prunes old snapshots. | | `InstructionsLoaded` | `on-instructions-loaded.js` | Injects active-pipeline context as a `system-reminder` when `CLAUDE.md`/rules load. | | `PreCompact` | [`on-pre-compact.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/on-pre-compact.sh) | Snapshots `STATE.json` so an active pipeline can be recovered after the conversation is compacted. | | `Stop` | `on-stop-context-check.js`, `on-stop-message-counter.js`, `memory-sync.py` | Context-budget check, message accounting, and memory sync when a turn ends. | | `StopFailure` | [`on-stop-failure.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/on-stop-failure.sh) | Records unrecoverable errors and infers whether the failure happened inside a subagent. | | `SubagentStart` / `SubagentStop` | `on-subagent-start.sh`, `on-subagent-stop.sh` | Log Task-tool agent lifecycle to `state/subagent-log.jsonl` (and LangFuse). | | `PostToolUseFailure` | `on-tool-failure.sh` | Appends failed tool calls to `state/tool-errors.jsonl`. | | `Notification` | `on-notification.sh`, `on-notification-sound.sh` | Routes notifications (Telegram); plays a sound on idle/permission prompts. | | `PostToolUse` | `context-monitor.js`, `post-crlf-fix.js`, `post-wrapper-validate.js`, `step-audit.js`, `post-pr-capture.js`, `post-task-token-track.js`, `post-memory-audit.js` | After-the-fact bookkeeping: context monitoring, CRLF normalization, wrapper-output validation, step auditing, PR-number capture, token tracking, memory audit. | #### The session-start fast path `on-session-start.sh` does roughly 20 seconds of interactive work — fine for a human starting a session, wasteful for the headless `claude --print` invocations that jkz scripts spawn constantly. It short-circuits those: when `CLAUDE_CODE_ENTRYPOINT=sdk-cli` (the value Claude Code sets for non-interactive `--print` runs), the hook runs only three essential steps (environment validation, expired-lock release, idempotent git-hook install) then exits before the banner. Detection is whitelist-only (only the exact value `sdk-cli` triggers it), so the default interactive path is unchanged. Kill-switch: `JKZ_SESSION_FASTPATH_DISABLE=1` forces the full path. #### The CRLF safety net `post-crlf-fix.js` strips carriage returns from `.sh` files after a Write/Edit. Newer Claude Code versions no longer inject CRLF, but the hook stays as defense in depth: it is a 15-line no-op when no `\r` is present, and it still protects plugin-mode installs running on older CLI versions where the Edit tool may differ. ### The hook server Several lifecycle hooks need to *record* events without slowing the session down. They post to [`hooks/hook-server.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/hook-server.js) — a small local HTTP server for observability. It routes `POST /hooks/event` by `event_type`: - `subagent_stop` → append to `state/subagent-log.jsonl` + LangFuse trace - `notification` → spawn `notify.sh` (skips idle notifications) - `tool_failure` → append to `state/tool-errors.jsonl` - `stop_failure` → append to `state/subagent-log.jsonl` with StopFailure context The server **always returns HTTP 200** — it is observability-only and fail-open. On startup it writes its port to `state/hook-server.port` and its PID to `state/hook-server.pid`, and deletes both on exit. Hooks reach it through `hook-server-client.sh`'s `post_hook_event`, which reads the port file and `curl`s the event with a 2-second timeout; if the server is unreachable, the helper simply returns `0`. Startup is guarded by [`hook-server-lock.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/hook-server-lock.js), a cross-platform `mkdir`-based atomic lock that is held until the server has actually written its port file. That closes the TOCTOU race where two sessions would otherwise both try to start a server: the lock proves readiness before it is released, so only one server binds a port. ### How hooks are registered There are two registration surfaces, and they serve different runtimes: - **[`.claude/settings.json`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/.claude/settings.json)** is the live Claude Code configuration for this repo. Each entry runs through `run-from-git-root.sh`, which resolves the git root and the dual-root environment before invoking the hook. This is the authoritative wiring — every guard and lifecycle hook above is listed here, grouped by event and tool matcher. - **[`hooks/hooks.json`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/hooks.json)** is the plugin-mode manifest. When jkz is installed as a plugin in another project, this compact manifest registers the core hooks through `hook-runner.js`. It is a curated subset of the full `settings.json` wiring. Both paths converge on the same fail-open contract and the same dual-root resolution, so a hook behaves identically whether jkz is the host repo or an installed plugin. ### Related - [Worktree isolation](/concepts/worktree-isolation/) — what `guard-worktree.sh` protects, and why edits are scoped to the active worktree during a build. - [Cross-chat awareness](/concepts/cross-chat/) — how `on-session-start.sh` and `on-session-end.sh` keep multiple sessions from colliding. - [Context management](/concepts/context-management/) — how `on-pre-compact.sh` and the `Stop` hooks preserve state across compaction. - [Pipeline](/concepts/pipeline/) — the BUILD → REVIEW → QA flow whose adversarial review layer is the safety net behind every fail-open guard. ## MCP servers Source: https://docs.j0kz.dev/subsystems/mcp-servers/ jkz speaks the Model Context Protocol (MCP) on two fronts. It **exposes** its own server — `jkz-pipeline` — so any MCP-compatible client can read pipeline state and drive transitions without going through a slash command. And it **bundles** a handful of third-party servers, most of them finance data sources, so the same client can pull market and economic data alongside pipeline work. Every server is declared in `.mcp.json` at the project root. That file is the single source of truth for which servers exist and how they launch; nothing here needs configuring in `.claude/settings.json`. ### The jkz-pipeline server This is the one server jkz ships itself. It turns the pipeline into a programmable surface: instead of running `/jkz:status` in a chat, a client can call `get_status` and get the same answer as structured data. It is the API behind the CLI. It exposes **16 tools**, grouped by what they let a caller do: | Capability | Tools | |------------|-------| | **Read** — inspect state, never change it | `get_status`, `get_metrics`, `health_report`, `get_deliberation_state`, `query_env`, `list_sessions`, `list_automations`, `list_vault`, `librarian_query`, `query_governed_patterns` | | **Write** — change pipeline state | `init_project`, `transition_phase`, `set_agent`, `trigger_automation` | | **Admin** — session snapshots | `save_session`, `restore_session` | The grouping is not cosmetic — it maps directly onto the access scopes described below. #### Two transports The server runs in one of two modes, chosen at launch: | Transport | When | Audience | Auth | |-----------|------|----------|------| | **stdio** | Default | A local client on the same machine (the trusted case) | None | | **HTTP** | Opt-in | A networked client reaching the server over a port | Required | Over **stdio** the server trusts its caller — it is a local process the operator already controls — so every tool is available and no credentials are involved. This is the normal mode for a developer's own machine. Over **HTTP** the server is reachable across a network, so it gates access with a token and a scope. HTTP mode is what makes remote and monitored deployments possible. #### Scopes When the server runs over HTTP, every tool requires one of three scopes, and the scopes are hierarchical — a higher scope satisfies a lower requirement: - **`read`** — call any read tool. - **`write`** — call read and write tools (everything except session snapshots). - **`admin`** — call everything, including the session snapshot tools. So an `admin` token can do what a `write` token can, which can do what a `read` token can. A token is granted exactly one scope, and a call that asks for more than the token carries is rejected with an `insufficient_scope` error rather than silently downgraded. Over stdio there is no scope check at all — the local caller is already trusted, so the scope model simply does not apply. #### Authenticating over HTTP An HTTP client presents its token as a standard `Authorization: Bearer ` header. The server matches the token against its store and reads the scope the token was granted; the call proceeds only if that scope covers the tool. Two endpoints are deliberately left **outside** the auth gate so they can be reached without credentials: - **`/health`** — a liveness check. - **`/metrics`** — Prometheus-format metrics, so a scraper can collect them without being handed a pipeline token. The `/mcp` endpoint — where the actual tool calls go — always sits behind the auth gate. ### Finance servers These are third-party servers jkz wires in for market and economic data. They are not part of the pipeline; they ride alongside it so the same client can reach financial data during research and analysis work. | Server | What it provides | |--------|------------------| | **polygon** | Market data across equities, options, ETFs, indices, FX, and crypto — both real-time and historical (quotes, trades, aggregates). | | **yahoo-finance** | Historical price data for stocks. | | **fred** | Federal Reserve Economic Data — macroeconomic time series (rates, inflation, employment, and the rest of the FRED catalogue). | | **octagon** | Financial research agents and prediction-market data. | `fred` and `octagon` each need an API key (`FRED_API_KEY`, `OCTAGON_API_KEY`) supplied through the environment; `polygon` and `yahoo-finance` run without one. ### Other bundled servers Three more servers round out the set. They are not finance sources and not the pipeline, but they share the same `.mcp.json` declaration: - **context-mode** — context indexing and search. - **codebase-memory-mcp** — the codebase knowledge graph used for code exploration and tracing. - **playwright** — browser automation for end-to-end and web checks. ### Related - [How jkz works](/get-started/how-jkz-works/) — the pipeline these tools query and drive. - [The pipeline](/concepts/pipeline/) — the phases and transitions exposed by `transition_phase` and `get_status`. - [Architecture](/reference/architecture/) — where the MCP server code sits in the wider project. ## Pattern learning loop Source: https://docs.j0kz.dev/subsystems/pattern-learning/ Every pipeline run produces deliberations — the Auditor's challenge to a plan, the Judge's read of a diff, the Sentinel's security pass. Most systems throw that reasoning away once the verdict is posted. jkz keeps it. The pattern learning loop turns each deliberation into reusable signal: it extracts the recurring observations an agent makes, scores them by how often they hold up, feeds the best ones back into future prompts, and quietly demotes the ones a validator later calls a false positive. The effect is a pipeline that accumulates judgment across runs rather than starting cold every time. This is a closed loop with four moving parts — **store**, **score**, **re-inject**, **correct** — and it is scoped per project, so patterns learned on one repository never leak into another. None of it is on the critical path: every step is fail-open, so a missing database or a parse error degrades to "no patterns this run", never a blocked pipeline. ### The four stages ```text deliberation ──store──▶ SQLite (patterns table) │ score (success rate × time decay × context) │ re-inject (token-budgeted) ──▶ next agent prompt │ validator verdict ──correct──▶ penalize false positives / reinforce on PASS │ └──▶ back into the store ``` The three scripts behind it live in the main repo: - [`scripts/memory-store.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/memory-store.js) — the SQLite store and its CLI (storage, scoring, lifecycle). - [`scripts/format-patterns.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/format-patterns.js) — budget-controlled formatting for prompt injection. - [`scripts/feedback-loop.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/feedback-loop.js) — the deterministic correction step that runs after each validator verdict. ### Store Deliberations and the patterns derived from them live in a local SQLite database (via `better-sqlite3`). The `patterns` table holds the core data: each row is a short piece of text an agent produced, tagged with the `role` that produced it, a `success_count` and `ignore_count`, the `last_used` timestamp, an optional embedding, and a `lifecycle_state`. Rows are unique on `(text_hash, role)` and stamped with a `project_id`, which is how scoping stays airtight — a query for the Judge's patterns on this project never sees another project's rows. Patterns are not authored by hand. They are extracted from stored deliberations and classified into categories (an `observation`, a `causal` link, or a hard `rule`), then upserted: if the same text from the same role already exists, its `success_count` is incremented rather than a duplicate created. ### Score A pattern's worth is not a flat count — it decays. When patterns are queried for injection, each row is scored on the fly: - **Success rate** — `success_count` over `success_count` plus the accumulated ignore weight (`ignore_weight_score`, a float that grows with each validator rejection, falling back to a plain `ignore_count`). A pattern that keeps getting validated and never ignored trends toward 1.0; one that validators keep rejecting trends toward 0. - **Time decay** — multiplied by `exp(−daysSinceUse / 14)`, so a pattern unused for two weeks is worth roughly a third of a fresh one. The exception: a pattern reinforced three or more times is immune to decay — once the pipeline has confirmed it that often, it stops aging. - **Category weight** — a `rule` is multiplied by 1.3 and a `causal` link by 1.1, because a hard rule is worth surfacing over a loose observation. - **Context boost** — if the current issue's labels or changed files overlap with the context a pattern was learned in, its score gets a small bump. This is the `--labels` / `--phase` relevance signal: patterns from similar situations score higher. When embeddings are available, the final score blends semantic similarity to the query with the decayed score (60/40). Patterns move through a five-state lifecycle — `observed` on first sight, `candidate` once seen twice, `verified` once they recur across distinct contexts, `active` after an explicit promotion, and `deprecated` if they age out without being used. The automatic transitions run up to `verified`; the jump to `active` is a separate, human-approved promotion. ### Re-inject Scored patterns are formatted back into agent prompts by `format-patterns.js`, under a strict token budget — **800 tokens for adversarial roles** (Auditor, Judge, Sentinel) and **500 for everyone else**. The budget is the whole point: historical context is valuable only until it crowds out the actual task, so injection is capped and patterns below a minimum score (0.1) are dropped entirely. The formatter renders each pattern as one line tagged with its track record — `5x validated`, `-2 net, 3x ignored`, or a raw `score:0.42` for newer patterns — and notes provenance (`via:auditor`) when a pattern came from a different role. If everything fits, it injects the full list; if not, it falls back to a pre-computed summary or, failing that, truncates to the highest-scoring lines. The result lands in the prompt as a `=== HISTORICAL PATTERNS (role) ===` block. If the remaining prompt space is too small to be useful, injection is skipped rather than forced. ### Correct The loop's discipline comes from the correction step, which runs after a validator finishes. The pipeline pairs an adversarial role with the validator that checks it — by convention the Curator checks the Auditor in Plan, the Inspector checks the Judge in Review, and the Lens checks the Sentinel in QA. The pairing isn't hardcoded in the correction step: the roles are handed to `feedback-loop.js` at runtime via `--adversarial-role` and `--validator-role`. When the validator's verdict (read from its [`verdict-json`](/concepts/signal-format/) block) lists **false positives**, `feedback-loop.js` locates the matching text in the adversarial deliberation (by exact substring, or by fuzzy token overlap as a fallback) and penalizes that pattern with `increment-ignore`. Two details make the penalty trustworthy: - **Per-role weight.** The penalty is scaled by the *adversarial* role whose pattern is being demoted — not by the validator that flagged it. Patterns tagged `sentinel` or `inspector` are penalized at weight 1.5; all other roles at 1.0, so a high-confidence role's misfires lose ground faster. - **Regression marking.** If a pattern that had repeatedly held up (the `was_validated` flag) is suddenly ignored, it is flagged as a regression — a previously trusted signal that has started misfiring deserves attention, not a silent demotion. On a **PASS** verdict the loop reinforces instead of penalizing, but only behind an [evidence gate](/concepts/evidence-hierarchy/): patterns are reinforced only when the adversarial deliberation is grounded in Level-1 (execution output) or Level-2 (file:line citation) evidence. Pure-reasoning verdicts (Level 3) reinforce nothing — otherwise the pipeline would learn to approve by narrative. When reinforcement does fire, the top or file-relevant patterns get a bump and the patterns that *weren't* reinforced are aged a step, so stale signal cleans itself up. A final, slower signal closes the loop at the end of a run. When a pipeline completes, [`outcome-score`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/memory-store.js) records whether the merged work ultimately passed or failed, so patterns are graded not just on intermediate verdicts but on whether the change they shaped actually held up. ### Why it stays out of the way The loop is deliberately invisible during normal operation. It writes to a local database, injects a few hundred tokens, and corrects itself — all fail-open. If `better-sqlite3` isn't installed, if a deliberation file is malformed, or if a query times out, every stage swallows the error and returns nothing rather than stalling the [pipeline](/concepts/pipeline/). You feel it only in the aggregate: over many runs, the adversarial roles stop re-raising the false positives a validator has already dismissed, and they keep surfacing the checks that have repeatedly caught real problems. ## Research & finance pipeline Source: https://docs.j0kz.dev/subsystems/research-finance/ The same pipeline that builds code (one model creates, an adversarial backend challenges, a validator confirms) also drives financial research. `/jkz:research` is that pattern pointed at a question instead of a codebase: an Analyst investigates and writes, a Research-Auditor fact-checks adversarially, and a Research-Reviewer validates the methodology. The output is not a pull request but a set of deliverables — a report, structured data, and a sourced evidence log — that have survived the same kind of scrutiny. This page covers the flow, the three agent roles, the finance data servers the pipeline pulls from, and how Hermes runs research on a schedule without a human at the keyboard. ### The four phases `/jkz:research [topic]` runs in four phases. If a `topic` is supplied and a brief already exists, it resumes from the phase the work last reached rather than starting over. | Phase | Who runs it | What happens | |-------|-------------|--------------| | **SCOPE** | Conversational (you + the orchestrator) | Pin down the question: research type, subjects, horizon, deliverables, source priorities. Produces a `brief.md`. | | **RESEARCH** | Analyst (Opus) | Gather, filter, structure, and draft. Produces three artifacts. | | **AUDIT** | Research-Auditor + Research-Reviewer, in parallel | Adversarially fact-check and validate the methodology, up to 3 iterations. | | **OUTPUT** | Deliverable generator | Turn the audited artifacts into Google Workspace documents. | #### SCOPE — frame the question SCOPE is a short interview. It asks seven priority questions — research type, topic, holding horizon, subjects, deliverables, restrictions, and what specifically matters — and persists the answers to `research//brief.md`. Five research types steer the rest of the run: `investment`, `market`, `due-diligence`, `supply-chain`, and `derivative`. Two gates keep a vague request from becoming a vague report: - An **intake gate** scores how clearly the question is posed. Above a high-confidence threshold it proceeds; in the middle band it shows you a refined version of the query; below the low threshold it asks clarifying questions before continuing (with a single re-evaluation budget). - An optional **source-weights** step lets you tell the Analyst which kinds of sources to lean on, recorded in the brief as advisory weights. For the `derivative` type, SCOPE also resolves the subject company to an exchange ticker — trying Polygon first and falling back to Octagon — so downstream valuation has a concrete instrument to work from. ##### Stage 0: bottom-up CAPM (derivative only) When the research type is `derivative`, an extra stage runs before the Analyst is invoked: a bottom-up cost-of-equity and WACC computation. It assembles its inputs from the finance servers — the risk-free rate from FRED, a beta regression from Polygon price history (falling back to Yahoo Finance), the equity risk premium from Damodaran's published tables, and fundamentals from Octagon — then computes a defensible cost-of-equity band and pauses for your confirmation. The point is to fix the discount rate **once**, deterministically, so the Analyst never silently re-derives it. The Analyst copies the result verbatim rather than recalculating. #### RESEARCH — the Analyst draughts The Analyst (Opus) does the actual investigation. It works through a four-step funnel — **gather** raw data, **filter** signal from noise, **restructure** into JSON, then **draft** the report against the type's template — and pulls evidence through a four-level search protocol: finance MCP servers first, then mandatory web sources (Damodaran), then recommended sources, then free web search as a last resort. Every data point carries a confidence tag and a freshness stamp; when a number can't be found, the Analyst declares the omission and the searches it tried rather than inventing a value. It produces three artifacts: | Artifact | What it holds | |----------|---------------| | `report.md` | The finished report, following the type's template, with confidence and freshness tags and any declared omissions. | | `analysis-data.json` | Structured data matching the template's spreadsheet schema, including a `contradictions[]` array when sources disagree. | | `sources-log.json` | An evidence log — for each data point, the tool used, the attempts made, and how it resolved. | #### AUDIT — challenge and validate AUDIT runs two agents in parallel against the draft, mirroring the main pipeline's adversarial-then-validator split: - The **Research-Auditor** fact-checks adversarially — recomputing arithmetic, resolving cited URLs, checking that sources actually support the claims, and scoring completeness against the template. - The **Research-Reviewer** validates the *methodology* — is the analytical framework sound and standard, does the report answer what the brief asked, are the confidence distribution and freshness reasonable. Both emit a verdict. The Auditor passes only on **zero CRITICAL findings, zero HIGH findings, and completeness ≥ 90%**; the Reviewer passes on a sound-methodology / brief-compliant verdict. If both pass, the audit reports are written and the run proceeds to OUTPUT. If either fails, Doctor (Opus) applies a targeted fix and the audit re-runs — up to **3 iterations**. After the third failure the run proceeds anyway, but the reports are marked unresolved so the gaps are visible rather than hidden. The Reviewer also surfaces `knowledge_gaps[]` (open questions worth a follow-up), which are presented to you at the end. #### OUTPUT — generate deliverables The audited artifacts are rendered into Google Workspace deliverables — a document, a spreadsheet, slides, and a PDF — with a manifest recording what was produced. Partial generation is reported distinctly from a clean success, so a half-finished export is never mistaken for a complete one. ### The research roles The research pipeline reuses the main pipeline's three-part structure, with its own dedicated agents. The parallel is exact: | Research role | Main-pipeline analogue | Kind | Backend | |---------------|------------------------|------|---------| | **Analyst** (`.claude/agents/analyst.md`) | Architect / Builder | Creative | Claude Opus | | **Research-Auditor** (`agents/research-auditor.md`) | Auditor / Judge | Adversarial | External backend (`JKZ_RESEARCH_AUDITOR_ENDPOINT`) — required, no silent fallback | | **Research-Reviewer** (`agents/research-reviewer.md`) | Curator / Inspector | Validator | External validator backend (default Ollama Cloud), Gemini fallback | **The Analyst is the creator.** Like the Architect drafting a plan or the Builder writing code, it produces the primary artifact under Opus, with CFA-level rigor as its standing instruction: every claim has a number, every number a source, every source a date. **The Research-Auditor is the adversary.** Like the Auditor challenging a plan or the Judge challenging a diff, it runs on a required external backend and is told to find what the Analyst would rather not have found — buried miscalculations, sources that don't support their claims, optimistic assumptions dressed as facts. It works from an 8-point checklist (numeric consistency, source verification, cross-referencing, unsupported claims, completeness, accounting consistency, honest gap declaration, contradiction audit), extended to a 21-point checklist for `derivative` valuations. Its output is an errata document graded by severity, plus a machine-readable verdict. **The Research-Reviewer is the validator.** Like the Curator or Inspector confirming the work holds together, it checks methodology and brief-compliance rather than re-litigating facts — confirming the framework is standard (CAPM/WACC/DCF per Damodaran, structured market sizing, sourced assumptions) and that the report actually answers the question. It also returns the knowledge-gaps list. The Doctor — the same fix agent used in the code pipeline — closes the loop when the audit fails, applying minimal patches to the report, the data, or the sources log between iterations. ### Finance data sources The Analyst and the CAPM stage pull market and economic data through the finance MCP servers bundled with jkz. The servers themselves are documented in detail on the [MCP servers page](/subsystems/mcp-servers/); in the research context their roles are: | Server | Used for | |--------|----------| | **fred** | Macroeconomic series — the risk-free rate for CAPM, plus rates, inflation, and employment data. | | **polygon** | Market data — price history for beta regressions, quotes and aggregates across equities, options, FX, and crypto. | | **yahoo-finance** | Fallback price history when Polygon coverage is short. | | **octagon** | Financial research agents, company fundamentals, and prediction-market data; also the fallback for ticker resolution. | Beyond the MCP servers, the Analyst treats **Damodaran's** published datasets (betas, equity risk premiums) as mandatory web sources, fetching and indexing large documents so it can retrieve only the relevant fragments rather than re-downloading them. ### Running research unattended Research does not have to be driven from a chat. **Hermes** — jkz's operational layer — can run the pipeline on a schedule. The mechanism is label-driven: an issue tagged `jkz:research-pending` (created directly, via a Telegram `/research ` command, or proposed by a periodic suggestion job) is picked up by a poller that runs every five minutes, processes pending issues FIFO under a single-worker lock, and invokes `/jkz:research` non-interactively. Each run's deliverables are synced to Google Drive under a per-run folder, with state and logs kept locally. Idle cost is zero — when there is nothing tagged, the poller exits early and no model is invoked. Kill-switches disable the poller, the bisync, or the whole research feature independently. The operational details (folder layout, cron cadence, timeouts, and the issue-body schema) are on the [Hermes page](/subsystems/hermes/). ## Telegram bot Source: https://docs.j0kz.dev/subsystems/telegram-bot/ The pipeline runs unattended for long stretches: a `/jkz:pipeline` invocation can spend an hour cycling through plan, build, and QA without anyone watching the terminal. The Telegram bot is the layer that watches for you. It runs a fixed set of health checks on a timer, surfaces anything that has gone wrong, and proposes work that is waiting to start — but it never acts on its own. Every suggestion lands as a button you press. The bot observes and recommends; you decide. Two loops drive it: a **monitoring loop** that samples system health, and a **task discovery loop** that scans GitHub for actionable work. Both report to the project's Telegram chat. ### The monitoring loop Every ten minutes the bot runs eleven health checks concurrently and folds their results into one report. Each check returns a status — `ok`, `warn`, or `error` — and a short detail string. The checks are independent and isolated: a check that throws is caught and downgraded to a `warn` rather than taking the whole loop down. | Check | What it watches | |-------|-----------------| | `active_agents` | Agents that have gone idle, via `lastActivity` tracking | | `ci_status` | The health of the latest CI runs | | `stale_worktrees` | Worktrees lingering past their expected lifetime | | `deliberation_errors` | Errors recorded in agent deliberation logs | | `github_api` | Remaining headroom on the GitHub API rate limit | | `git_drift` | Whether local `HEAD` has fallen behind `origin/main` (a sign git-sync failed) | | `cli_versions` | Outdated CLIs and breaking changes — read from cache, never the network | | `slo_compliance` | Pipeline SLOs evaluated over a rolling window | | `worktree_cleanup` | Removes worktrees for issues that have reached a terminal state | | `quota_restoration` | Probes whether an exhausted Codex quota has recovered | | `stale_locks` | Recovers worktree locks whose owning issue is already closed | The report is persisted to `state/bot-monitor-report.json` after every cycle, so the most recent system snapshot is always available on disk even between Telegram messages. The bot is Docker-aware: when the project runs inside a container it issues shell commands through the container and reads state files natively from the mounted workspace. :::note The on-demand `/health` command in the bot runs a smaller subset of these checks (the eight that are cheap and side-effect-free) for a quick status readout. The full eleven-check sweep — including the cleanup and lock-recovery checks that mutate state — only runs on the timed loop. ::: ### Alerts and debouncing Health findings do not flood the chat. Each distinct alert is debounced with a **thirty-minute cooldown**: once an alert fires, the same alert stays silent for thirty minutes even if the underlying condition persists across loop cycles. This keeps a single ongoing problem (a rate-limit warning, a stuck agent) from posting every ten minutes. ### Background refreshes A few maintenance tasks ride the same ten-minute clock but run on longer intervals, counted in cycles: | Task | Cadence | Trigger | |------|---------|---------| | Monitoring loop | every cycle | 10 min | | Task discovery | every 3rd cycle | 30 min | | Changelog cache refresh | every 6th cycle | 60 min | The changelog refresh is fire-and-forget: it kicks off `changelog-review.js` in the background to keep the CLI-version cache warm, so the `cli_versions` check stays fast (it only ever reads the cache). ### Proactive task discovery Every thirty minutes — every third monitoring cycle — the bot scans GitHub for work that is ready but idle. It looks for four conditions: - **`jkz:ready` issues with no active pipeline** — work that is queued but unstarted. - **Stale PRs open longer than 24 hours** — surfaced as informational, not as a problem to fix. - **Blocked issues** — issues waiting on an unresolved dependency. - **Stale pipelines older than two hours** — a run that has stalled mid-phase. Each finding is offered as a Telegram inline keyboard: a message with buttons the human can tap to act. The system suggests; the human acts. Nothing starts a pipeline, merges a PR, or unblocks an issue automatically. #### Staying under the callback limit Telegram caps `callback_data` — the payload attached to an inline button — at 64 bytes. A jkz command with an issue number and context easily exceeds that. The bot works around the limit with a `pendingCommands` pattern: the full command is stored server-side and the button carries only a short key that points to it. When the button is pressed, the bot looks up the real command by its key. This keeps every button well under the 64-byte ceiling regardless of how long the underlying command is. ### Where this lives The checks themselves are defined in `scripts/monitoring-checks.js`; task discovery lives in `scripts/task-discovery.js`; and the bot that schedules both loops, debounces alerts, and renders the inline keyboards is `scripts/telegram-bot.js`. ## Wiki generator Source: https://docs.j0kz.dev/subsystems/wiki-generator/ This site is generated. The pages you are reading were not hand-written into `jkz-docs` — they were extracted from the private `jkz_Multi-Agent_System` repository, assembled into prose, screened for leaks, and published as a pull request that a human approved. The subsystem that does this is **wiki-generator**, an internal jkz skill that runs on a schedule and treats one rule as inviolable: **every published byte must trace to a source artifact that has already passed sanitization.** It is the only part of jkz that crosses the public/private boundary, so it is built to fail closed. If any stage before publishing breaks, the run stops and nothing reaches the public mirror. ### The pipeline at a glance wiki-generator is an eight-phase pipeline. The phases run in a fixed order, and the loop **breaks on the first failure** — so `publish`, the only phase that writes to the public repo, never runs unless every upstream phase succeeded. ```mermaid flowchart LR A[config] --> B[extract] B --> C[diff] C --> D[sanitize] D --> E[generate] E --> F[guard] F --> G[publish] G --> H[prune] D -. fail .-> X[abort, nothing published] F -. fail .-> X ``` | Phase | What it does | Writes to public repo? | |-------|--------------|------------------------| | **config** | Loads `wiki-generator.config.json` (paths, modules, repo URL, enabled generators) | No | | **extract** | Reads signatures, JSDoc/TSDoc, comments, closed issues, changelog, and READMEs from the source repo | No | | **diff** | Hashes inputs and detects what actually changed, so unchanged pages are not regenerated | No | | **sanitize** | Runs the adversarial sanitizer suite — the hard gate | No | | **generate** | Builds pages with a per-generator model mix (mechanical, Haiku, or Sonnet) | No | | **guard** | Final hallucination check against the source; no I/O, pure verification | No | | **publish** | Opens a content PR on `jkz-docs` via the scoped bot token | **Yes** | | **prune** | Archives stale state files and old run artifacts | No (source-side state) | ### Extractors — read the private repo, never the API The extract phase pulls raw material from the private repository. File contents are read from a **local checkout, never via the GitHub API**, so the pipeline's token needs no `Contents` access on the source repo at all. What extractors collect: - **Signatures and types** — parsed from the AST (`ast_extractor`). - **Doc comments** — JSDoc/TSDoc blocks (`jsdoc_extractor`). - **Closed issues** — pulled over GraphQL with a cursor for incremental runs (`issue_extractor`), the narrative source for "what shipped." - **Changelog, config comments, READMEs** — for changelog history, configuration docs, and module summaries. Issue extraction is the one place a token is used, and it is scoped to **read-only** on the source repo. ### Sanitizers — the hard gate Sanitizing is not a cleanup pass; it is a blocking gate. The suite must clear **100%** or the run aborts before a single page is generated. It composes several independent screens: - **Path blocklist** — refuses anything sourced from `.claude/`, `state/`, `secrets/`, and other internal paths. This is the contract that keeps internal structure off the public site. - **Secret and entropy detection** — flags credentials, tokens, and high-entropy strings. - **PII sanitizer** — strips personal data. - **Implementation and issue-log sanitizers** — remove internal implementation detail and redact issue-thread content. Because sanitizers run *before* generation and the loop breaks on failure, a leak cannot reach the model, the PR, or the public repo. The suite is adversarial by design: new fixtures that defeat detection block the merge until detection is fixed. ### Generators — the right model for each page Generation is deliberately heterogeneous. Mechanical pages use **no LLM at all** (deterministic and cheap); structural pages use **Haiku 4.5** for low latency; narrative pages use **Sonnet 4.6** for richer prose. | Generator | Model | Why | |-----------|-------|-----| | API reference | none | AST + doc comments rendered straight to markdown — the single source of truth for signatures | | Reference catalogs & project stats | none | Read frontmatter / config / stats output → markdown | | `llms.txt` / `llms-full.txt` | none | Mechanical concatenation | | Sidebar | Haiku 4.5 | Simple structure, low latency | | Module docs | Sonnet 4.6 | Contextual narrative; embeds the API reference, never duplicates it | | Workflow & architecture docs | Sonnet 4.6 | How-to guides and mermaid overviews | | Changelog "What's New" | Sonnet 4.6 | Narrative of recent PRs grouped by type | | Issue entries | Sonnet 4.6 | Per-category narrative from closed issues | The API reference is authoritative for signatures: module docs that need a signature **link to** the adjacent API page rather than restating it, so the two never drift. ### Guard — the last check before crossing the boundary The guard phase is the final pre-publish verification. It re-screens the generated, LLM-authored body against the source material to catch hallucination — content the model invented that has no grounding in the extracted artifacts. It performs **no writes**; it only verifies, and any failure aborts the run before `publish`. Golden snapshots provide a second line of defense, surfacing unexpected drift before a human ever reviews the PR. ### Publisher — the only phase that mutates the public repo If and only if every prior phase passed, the publisher opens a content PR on `jkz-docs`. It runs under a single **fine-grained PAT** scoped to exactly two repositories: read-only issues on the source repo, and `Contents` + `Pull requests` write on `jkz-docs`. A classic, account-wide token is rejected. The PR carries a generated body, and CI on `jkz-docs` re-runs the sanitizer suite, checks links, and validates `llms.txt` — the same guarantees, enforced again on the public side. ### The human-in-the-loop model wiki-generator ships with **HITL on by default** (`WIKI_HITL_REQUIRED=true`). The pipeline prepares everything up to a pull request and then **stops**: a human reviews the diff and merges. This mirrors jkz's core rule — the machine does the work, the human crosses the final line. - **HITL on (default):** the PR waits for manual approval. Sanitizers and CI still run, so a broken or leaky PR is visibly broken and is not merged. - **HITL off (future):** a green CI run could auto-merge via the bot token. The switch is only ever flipped after confirming the adversarial suite has had no false negatives across recent runs. Either way the sanitizer gate stays critical, not lax. Turning off the human gate would never turn off the leak gate. ### Operation The pipeline is run by **Hermes on a daily schedule** (04:35 America/Santiago), staggered after the documentation-sync job to avoid collision. To avoid stacking work, a run **auto-skips** if the previous PR has not merged within 48 hours. Operational events route to dedicated Telegram topics — run summaries and warnings to one, sanitizer and sync failures to another — and the bot token is rotated on a fixed 90-day cadence. ### What this is not - **Not the development pipeline.** wiki-generator documents jkz; it is not the Plan → Build → QA loop that *builds* jkz. For that, see [the pipeline](/concepts/pipeline/). - **Not a free-form writer.** Every page traces to an extracted, sanitized artifact. The guard phase exists precisely to reject content that does not. - **Not self-merging.** With HITL on, it stops at a PR. A human merges. ### Related - [The pipeline](/concepts/pipeline/) — the three-phase development loop wiki-generator documents. - [Evidence hierarchy](/concepts/evidence-hierarchy/) — the same "trace every claim to a source" discipline, applied to deliberation. - [Architecture](/reference/architecture/) — where this subsystem sits in the wider system. - [Design decisions](/reference/design-decisions/) — the ADRs behind the stack choices, including the docs site itself. ## Autonomy & auto-improvement Source: https://docs.j0kz.dev/operations/autonomy/ jkz is built around a deliberate split: it is **autonomous in execution** and **human-gated at the boundaries**. Inside a pipeline run the agents plan, build, review, and fix without asking permission for every step. But the moments that are expensive to get wrong — approving a plan, accepting a review, merging to `main` — stay the owner's call. This page maps where that line sits, how far the dial can be turned, and the three mechanisms that let the system discover and propose its own work without ever taking the final decision away from you. ### The autonomy dial Two independent settings control how much the system does on its own. They compose: one governs which *commands* are allowed to run, the other governs whether the pipeline *waits* at its checkpoints. #### Guard levels — what may run The [`hooks/guard-destructive.sh`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/hooks/guard-destructive.sh) `PreToolUse` hook enforces an autonomy profile set by `JKZ_AUTONOMY_LEVEL` in `.env`. It is a blocklist that fails closed: a blocked command exits non-zero with a machine-parseable `{"blocked":true,…}` line on stderr. | Level | Blocks | When to use | |-------|--------|-------------| | `trusted` (default) | Clearly destructive ops only — force-push to `main`, `git reset --hard`, `rm -rf` outside an allowlist, `DROP`/`TRUNCATE`/unqualified `DELETE`, pipe-to-shell, `gh pr merge`, and merge-gate bypass attempts | Normal development | | `standard` | Identical to `trusted` today (reserved for future per-project differentiation) | Reserved | | `restricted` | Everything in `trusted`, **plus** any `git push`, all publishing (`npm publish`, `docker push`, …), and GitHub write operations (`gh issue edit`, `gh pr comment`, `gh api -X POST/PATCH/PUT/DELETE`) | Audit mode, fully autonomous agents | The `rm -rf` allowlist — `node_modules`, `dist`, `build`, `__pycache__`, `.cache`, `jkz-worktree-*`, `*.pyc` — is always permitted regardless of level, so routine cleanup never trips the guard. #### Auto-approve — whether the pipeline waits By default the pipeline pauses at its three human checkpoints and waits for an explicit approval (a Telegram reaction or a terminal input). Setting `JKZ_AUTO_APPROVE=true` makes those checkpoints approve themselves and fire an `auto_approved` notification, so a run proceeds end to end after a single invocation. | Checkpoint | `false` (default) | `true` | |------------|-------------------|--------| | Plan | Waits for human approval | Auto-approves | | Review | Waits for human approval | Auto-approves for all issue types — non-features **never** skip QA | | QA | Waits for human approval | Auto-approves | | **Merge** | **Human-only** | **Unchanged — the human still merges manually** | The two settings are orthogonal: `JKZ_AUTONOMY_LEVEL` decides which commands the guard will run, `JKZ_AUTO_APPROVE` decides whether the checkpoints block. The one thing neither can change is the merge boundary. ### What stays the owner's decision No combination of flags lets an agent merge to `main`. This is the hard floor of the autonomy model, and it is enforced *server-side* so that a prompt — however it is phrased, and even under `bypassPermissions` — cannot reach production on its own. The merge gate is four layers deep: | Layer | Mechanism | Bypassable? | |-------|-----------|-------------| | `merge-gate.yml` | Sets the commit status to `pending` on every PR | No — server-side | | `approve-merge.yml` | A `workflow_dispatch` that flips the status to `success`, gated by a `MERGE_PASSPHRASE` held in GitHub Secrets | No — Claude Code cannot read GitHub Secrets | | `auto-revert.yml` | Detects any merge that lacks `merge-gate=success` and reverts it automatically (~30s) | No — server-side | | `guard-destructive.sh` | Blocks `gh pr merge`, `gh workflow run approve-merge`, and status-mutating `gh api` calls | Yes, under `bypassPermissions` — which is exactly why layers 1–3 exist | To merge, the owner runs `approve-merge.yml` with the passphrase from a terminal — outside Claude Code — and then merges. The system iterates internally up to three times per phase, but it never crosses this line. Everything else in this page is about helping the owner decide *what* to work on; this layer guarantees the owner alone decides *when it ships*. ### Proactive task discovery — the system suggests, the human acts Execution is reactive by design: a pipeline starts when you point it at an issue. Proactive task discovery is the counterweight — it lets the system notice work that *should* be started and surface it, without starting anything itself. [`scripts/task-discovery.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/task-discovery.js) runs every **30 minutes** (every third monitoring cycle) and scans GitHub issues, open PRs, and local pipeline state for four conditions: - `jkz:ready` issues with no active pipeline — ready to start. - Stale PRs open more than 24 hours — informational only. - Blocked issues whose blocker may have resolved. - Stale pipelines idle more than 2 hours — candidates to resume. Each finding carries a suggested `action` (`pipeline`, `quick`, `resume`, or `null` for purely informational items) and is offered through a Telegram inline keyboard. The human taps to act; the system never auto-dispatches. The keyboard uses a `pendingCommands` indirection to stay under Telegram's 64-byte `callback_data` limit. This is the human-in-the-loop pattern in its purest form: **the system finds the work, the owner chooses whether to do it.** ### Smart maintenance — triage by reversibility Where task discovery surfaces *known* work, smart maintenance hunts for *latent* problems — missing dependencies, stale references, lingering TODOs — and routes each finding by how safe it is to act on automatically. The on-demand [`claude-maintenance.yml`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/.github/workflows/claude-maintenance.yml) workflow (dispatch only) classifies every finding against one heuristic: **trivial = a deterministic command with no design decision; everything else is complex.** - **Trivial** findings (a missing dependency, an absent build artifact) are auto-fixed via a PR on a `maint/weekly-*` branch. The fix still flows through the merge gate — it lands in a PR, never directly on `main`. - **Complex** findings (a stale reference, a TODO that implies a decision) become one issue per finding, each with its own impact analysis, so a human can decide on them individually. Auto-fix PRs are opened with a fine-grained `MAINTENANCE_PAT` (rotated every 90 days) precisely so the merge gate and CI fire on them the same way they fire on human-authored PRs — the automation gets no shortcut around the gate. ### Sharpening itself — the pattern-learning feedback loop Beyond discovering work, the system tunes *how it reasons*. Every deliberation feeds a learning loop that makes the next prompt slightly better calibrated. Patterns extracted from agent deliberations are stored in SQLite via [`scripts/memory-store.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/memory-store.js) and re-injected into future prompts by [`scripts/format-patterns.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/format-patterns.js) under a strict token budget (800 tokens for adversarial roles, 500 for constructive ones). The loop closes through [`scripts/feedback-loop.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/feedback-loop.js): - When a validator (Inspector, Curator, Lens) marks a finding a **false positive**, the corresponding adversarial pattern is penalised (`increment-ignore`), so a noisy heuristic gradually stops being injected. - On a **PASS** verdict, the top contributing patterns are reinforced. Contextual metadata (`--labels`, `--phase`) boosts patterns drawn from *similar* pipeline contexts, so a lesson learned on a security review surfaces preferentially on the next security review. The agents are not retrained, but the evidence they are handed each run is shaped by what proved useful — and what proved noisy — in the runs before. ### The auto-improvement story The clearest demonstration of the model is that the pipeline has, in large part, **built itself**. The self-improvement roadmap in [`docs/roadmap-auto-improvement.md`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/docs/roadmap-auto-improvement.md) framed the gap directly: the pipeline executes work excellently but, left alone, *cannot discover work* — it waits to be pointed at an issue. The roadmap's job was to close that gap by layering monitoring and issue-creation capabilities on top, with the human still approving every proposal and every merge. Each roadmap item was itself fed through the pipeline as an issue, and the tiers are now complete: | Capability | Tier | What it added | |------------|------|---------------| | Agent issue proposals | 1 | Any FAIL verdict can emit a `jkz:propose-issue` marker; the command offers to create a deduplicated follow-up issue. | | Post-merge workflow | 1 | A `post-merge.sh` that cleans merged worktrees and re-checks health. | | Deliberation analytics | 2 | `/jkz:insights` over `state/deliberations/*` — agreement, timeline, token usage. | | Issue decomposition | 2 | The Architect proposes a sub-issue split when a plan crosses complexity thresholds. | | Continuous monitoring | 3 | A scheduled job that runs health checks on `main` and files `jkz:regression` issues. | | Cross-issue dependency tracking | 3 | A state-tracked `blocked_by` / `blocks` graph with cycle detection. | | Notifications + autonomous pipeline | 3 | The notification system and the reaction-driven `/jkz:pipeline` that chains all phases. | The throughline is consistent with everything above: each capability widened what the system can *propose* — work to start, regressions to fix, splits to consider — while the decisions that matter stayed with the owner. The pipeline got better at finding its own work; it never got the power to ship it unattended. ### Related - [SLOs & monitoring](/operations/slos-and-monitoring/) — the ten-minute monitoring loop whose cycle counter drives proactive task discovery every third tick. - [Pattern learning](/subsystems/pattern-learning/) — the deliberation-to-pattern store and feedback loop described here, in full. - [Memory](/operations/memory/) — the broader memory system the pattern store sits inside. - [Pipeline](/concepts/pipeline/) — the PLAN → BUILD → REVIEW → QA flow whose checkpoints the autonomy dial governs. - [`/jkz:status`](/commands/status/) — surfaces pipeline state, SLO compliance, and the merge-gate status on demand. ## Maintenance & fallback runbook Source: https://docs.j0kz.dev/operations/maintenance-and-fallback/ Running jkz day to day raises two recurring operational questions: *how do we keep the repository from slowly rotting* — accumulating missing builds, stale dependencies, and dead `CLAUDE.md` references — and *what happens when a model or a backend fails mid-pipeline*. This page is the runbook for both. The first half covers the **smart maintenance** workflow you trigger on demand; the second half is the **fallback runbook** — what recovers automatically, and what stops and asks you to decide. For the conceptual treatment of fallback, see [Fallback](/concepts/fallback/); this page is the operator's view, with the env vars, exit codes, and triggers you actually reach for. ### Smart maintenance Maintenance is an **on-demand** workflow — [`claude-maintenance.yml`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/.github/workflows/claude-maintenance.yml) is wired to `workflow_dispatch` only, so nothing runs it on a schedule. An operator starts it from the Actions tab (**Run workflow**) or from the terminal: ```bash gh workflow run claude-maintenance.yml ``` It deliberately checks **only the things the daily monitor does not already cover**. The monitor owns health checks, unit tests, `npm audit`, and regression issues; maintenance fills the gaps the monitor leaves — dependency drift, build rot, stale references, and lingering TODOs. #### What the job does The workflow runs on `ubuntu-latest` with a 20-minute timeout and a small fixed setup before any analysis happens: 1. Checkout with full history (`fetch-depth: 0`), authenticated with the `MAINTENANCE_PAT` secret. 2. Node 20, then `npm ci --ignore-scripts` for the root dependencies. 3. [`node scripts/deps-audit.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/deps-audit.js) to surface dependency state. 4. The [`anthropics/claude-code-action`](https://github.com/anthropics/claude-code-action) step, driving **Claude Sonnet 4.6** (`--model claude-sonnet-4-6`), runs the scan → classify → act loop below under a tightly scoped permission allow/deny list. #### Scan The agent collects findings from five checks: 1. `TODO` / `FIXME` / `HACK` comments in source files (excluding `node_modules`, `.git`, `state/`, `dist/`). 2. Outdated dependencies via `npm outdated`. 3. Open issues with no activity in the last 30 days. 4. Spot-checks that `CLAUDE.md` references existing files and commands. 5. A weekly performance audit — recent merged PRs and CI runs cross-referenced against the four SLO thresholds in [`scripts/slos.json`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/slos.json). A complex issue is created **only if** an SLO threshold is breached. #### Classify Every finding is sorted into one of three buckets. The dividing heuristic is simple: a fix is **trivial** when it is a deterministic command with no design decision behind it; everything else is **complex**. | Class | Examples | What it triggers | |-------|----------|------------------| | **Trivial** | Missing dependency (`npm outdated` shows `MISSING`) → `npm install`; missing build output (`dist/` absent) → `npm install && npm run build` | An auto-fix PR | | **Complex** | `TODO` / `FIXME` / `HACK` in source; `CLAUDE.md` referencing a nonexistent path | A separate issue per finding | | **Informational** | Issues idle for 30+ days | No action on its own — see below | If a trivial fix actually fails when run, it is downgraded to **complex** and reported as an issue rather than silently dropped. #### Act What happens next depends on which buckets are non-empty: - **Trivial findings** are applied on a single branch named `maint/weekly--`, committed (`fix: weekly maintenance auto-fix `), pushed, and opened as one PR titled `[Maintenance] Auto-fix - ` listing each fix. - **Complex findings** each become a **separate** issue titled `[Maintenance] - `, with `## Finding`, `## Impact`, and `## Suggested approach` sections. - **Informational findings** never get their own issue. They are appended as an `## Informational` section to one of the complex issues — and only if a complex issue is already being created. - **No findings** → the workflow does nothing. It does not open empty PRs or issues. #### Guardrails The maintenance agent operates under hard limits enforced by its permission set and prompt: - It does **not** add labels — the triage workflow owns labelling. - It does **not** merge PRs — the human merges through the [merge gate](/concepts/merge-gate/). - It edits files only through `git` operations, never the `Write` or `Edit` tools. - It does **not** create regression issues — that is the daily monitor's job. - It never pushes to `main`; only to `maint/weekly-*` branches. #### The maintenance token The workflow authenticates with `MAINTENANCE_PAT` — a **fine-grained personal access token on a 90-day rotation** — rather than the default `GITHUB_TOKEN`. This is deliberate: a PR opened with the default Actions token does not trigger downstream workflows, so the [merge gate](/concepts/merge-gate/) and CI would never fire on an auto-fix PR. The PAT makes those auto-fix PRs behave like any human-opened PR, gate and all. ### Fallback runbook A multi-backend pipeline can fail in three escalating ways: a model name that no longer exists, an endpoint that throttles you, or a whole backend that is down. jkz recovers the first two automatically and stops to ask you about the third. The [Fallback concept page](/concepts/fallback/) explains *why* the line is drawn there; what follows is *what to set and what to do*. #### A model 404s — automatic The smallest failure is a renamed or retired model returning `404 / ModelNotFound`. Each role has a configured fallback model, and the wrapper retries against it without involving you. Set these in `.env`: - **Gemini:** `JKZ_GEMINI_MODEL` → `JKZ_GEMINI_MODEL_FALLBACK` (default `gemini-3.5-flash`). - **API (OpenAI-compatible):** `JKZ_API_MODEL` → `JKZ_API_MODEL_FALLBACK`, with a per-role override `JKZ__MODEL_FALLBACK`. This applies inside `gemini-wrapper.sh`, `api-wrapper.sh`, and `gemini-invoke.js`. Control flow is unchanged — you simply get a verdict from the fallback model. #### A backend rate-limits — automatic cascade On `429 / RESOURCE_EXHAUSTED` the wrapper first retries with backoff, then escalates through a two-tier cascade. Each layer stamps the completion record with `fallback_tier` so you can audit which path produced a verdict. **Tier 3 — an OpenAI-compatible provider.** Applies to validator roles routed through `gemini-wrapper.sh` (`lens`, `curator`, `inspector`, `qa`, `research-reviewer`, `consultant-gemini`). When the retry budget is exhausted and a tier-3 endpoint resolves, the wrapper dispatches one attempt there. The resolver `bash scripts/resolve-provider-fallback.sh endpoint ` reads the per-role triple `JKZ__PROVIDER_FALLBACK_ENDPOINT` / `_MODEL` / `_API_KEY` first, then the global pair `JKZ_PROVIDER_FALLBACK_ENDPOINT` / `_MODEL` (exit 0 = resolved, 1 = partial config, 2 = not configured). On success the verdict is propagated verbatim, the sentinel records `fallback_tier="api"`, and LangFuse logs verdict `TIER3_API`. On failure or missing config it falls through to tier 4. **Tier 4 — the in-session model.** If tier 3 does not rescue the call, the wrapper exits **75** and writes a sentinel with `status="fallback"`. The command (`plan.md`, `review.md`, `qa.md`) detects this in its polling loop, resolves a provider through a three-level cascade — the sentinel's `fallback_provider`, then `resolve-provider-fallback.sh `, then `sonnet` on script failure — and re-runs the role in-session via the Task tool with `fallback_effort` (default `medium`) and extended thinking when `fallback_thinking="true"`. Per-role defaults when nothing is configured: `auditor`→`sonnet`, `lens`→`sonnet`; `curator`, `inspector`, `judge`, `sentinel`→`opus`. When you audit a fallback run, keep two fields distinct: - **`fallback_tier`** — `"api"` if tier 3 was *attempted* (whether it served the verdict or was rejected and handed off to tier 4), or `"task"` if tier 3 was never attempted (no or partial tier-3 config) and the call went straight to tier 4. Records *which path* the run took. Note that a tier-4 hand-off after a rejected tier-3 attempt still carries `fallback_tier="api"`. - **`fallback_provider`** — `"opus"` / `"sonnet"` / `"haiku"`. *Which model* the tier-4 Task tool dispatched to. Only meaningful when the tier-4 Task tool actually fired. #### A backend is down — manual The largest failures are not a single call going wrong but a whole backend being unavailable, and the right response depends on judgment the pipeline does not have. Backends are configured per role via `JKZ__ENDPOINT` (cascade: per-role → `JKZ_API_*`). Adversarial roles **require** an endpoint — if it is missing the wrapper exits **4** and the pipeline halts. Validator roles fall back to a local Gemini CLI when no endpoint is set. The system notifies you and waits: | Backend down | Behavior | |--------------|----------| | **Opus** (creative roles) | Pipeline stops. No other agent codes in its place. System notifies and waits. | | **Adversarial endpoint** (Auditor, Judge, Sentinel, Research-Auditor) | Review and the Sentinel security pass are skipped. System notifies; you decide whether to continue. | | **Validator endpoint** (Curator, Inspector, Lens, Research-Reviewer) | QA frontend and Inspector are skipped. System notifies; you decide. | | **External API endpoint** (any role on `JKZ__ENDPOINT`) | `api-wrapper.sh` captures the HTTP error and persists error state. Pipeline notifies. | | **Codex CLI** (`JKZ__BACKEND=codex`) | Wrapper exits 78 (missing CLI), 76 (auth error), or other internal codes (75 / 77). Pipeline notifies; you decide. | | **Claude Code** (the orchestrator) | Everything stops — it *is* the runtime that drives every other role. | The split is deliberate: recoverable failures are handled where they happen, invisibly, while a backend outage is a quality-of-evidence question — running without an adversarial reviewer is a real trade-off — so the system surfaces it and leaves the call to you rather than silently degrading. ### See also - [Fallback](/concepts/fallback/) — the conceptual model behind this runbook - [SLOs & monitoring](/operations/slos-and-monitoring/) — the daily monitor that maintenance complements - [Merge gate](/concepts/merge-gate/) — the human checkpoint the `MAINTENANCE_PAT` lets auto-fix PRs reach ## Memory Source: https://docs.j0kz.dev/operations/memory/ A multi-agent pipeline that forgets everything between runs repeats its mistakes forever. jkz remembers on three independent layers, each tuned to a different shape of knowledge: - **File-based auto-memory** — durable facts about *you* and *this project*, written as plain Markdown and loaded into every session. - **Agent-memory** — small per-role notebooks where individual agents (Builder, Architect, …) record gotchas they hit on the job. - **`memory.db`** — a SQLite store that learns *patterns* from the pipeline's own deliberations and re-injects them into future prompts, with a feedback loop that rewards what works and penalises what produces noise. A fourth, smaller piece — `memory-versions.js` — gives any of these a versioned audit trail. And two subagents, the **memory-auditor** and the **signal-discoverer**, keep the file-based layer accurate over time. The layers don't talk to each other. Each answers a different question: *who is the user and what is this project* (file-based), *what did this agent learn last time* (agent-memory), and *which review patterns actually hold up* (`memory.db`). ### File-based auto-memory This is the layer you can read with `cat`. It lives in a per-project memory directory, keyed off the project's absolute path with separators normalised to dashes — so `/home/user/my_repo` resolves to a directory ending in `-home-user-my-repo/memory/`. Inside are two kinds of file: - **`MEMORY.md`** — a one-line-per-fact index. It is loaded into context at the start of every session, so it must stay terse. Each line is a clickable pointer: `- [Title](file.md) — one-line hook`. - **Topic files** — one Markdown file per fact, carrying the detail. `MEMORY.md` never holds the content itself, only the pointer. Each topic file opens with YAML frontmatter that classifies the fact by `type`: | `type` | What it holds | |--------|---------------| | `user` | Who the user is — role, expertise, standing preferences. | | `feedback` | Guidance on *how to work* — corrections and confirmed approaches, with the reason why. | | `project` | Ongoing work, goals, or constraints not derivable from the code or git history. | | `reference` | Pointers to external resources — dashboards, tickets, URLs. | The body links related facts with `[[wiki-style]]` slugs, so the memory set forms a small graph rather than a flat list. #### What gets written — and what doesn't The bar for creating a memory is deliberately high, because a noisy memory file costs context on every future session. A fact earns a file only when it is **recurrent** (useful beyond this one task), **not already documented** (absent from `CLAUDE.md`, the rules, or `docs/`), **non-obvious** (a fresh session couldn't infer it from the code), and **actionable** (it says *do X* or *avoid Y*). One-time fixes, restatements of existing rules, and session-specific decisions are explicitly out of scope. #### Recall and promotion **Recall** is automatic and layered. Global preferences (`~/.claude/CLAUDE.md`), the project's own `CLAUDE.md`, and the working `MEMORY.md` index all load at session start; the heavier topic files are pulled in on demand when a fact becomes relevant. Recalled memories arrive inside `` blocks — they are background context, not fresh instructions, and they reflect what was true *when written*, so anything they name (a file, a flag, a function) is verified against the live codebase before being acted on. **Promotion** moves a fact up the hierarchy as its scope widens. A working-memory note that proves it belongs in the project's permanent rules can graduate into `CLAUDE.md` or a `.claude/rules/` file; conversely, a `MEMORY.md` that grows too long has its detail demoted into topic files to keep the index lean. The `memory-promote` skill scores a candidate against weighted criteria — documentation redundancy, whether it captures a reusable pattern, specificity, relevance, and uniqueness — and recommends *promote*, *keep*, or *archive*. The companion `memory-review` and `memory-status` skills surface stale entries (untouched for a long stretch), overlapping pairs, and promotion candidates so the set can be curated rather than left to rot. ### Agent-memory Where file-based memory is about the user and the project, **agent-memory** is about an individual agent's craft. Each role gets its own notebook under [`.claude/agent-memory/`](https://github.com/j0KZ/jkz_Multi-Agent_System/tree/main/.claude/agent-memory) — for example `.claude/agent-memory/builder/` and `.claude/agent-memory/architect/`. The structure mirrors file-based memory: a local `MEMORY.md` index plus one topic file per fact. These notes are operational lessons an agent hit while doing its job — the kind of thing that would otherwise be relearned every invocation. A Builder note might record how to recover from a detached HEAD in a shared repo, or that the wiki-generator enforces a per-file test-LOC budget. The notebook is scoped to that role: the Builder's lessons don't leak into the Architect's prompt unless something explicitly references them. ### `memory.db` — the pattern-learning store The third layer is a SQLite database at [`state/memory.db`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/memory-store.js), managed by [`scripts/memory-store.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/memory-store.js) (~3,500 lines, schema version 22). It opens in WAL mode with a busy timeout for safe concurrent access, and degrades gracefully: if the native `better-sqlite3` binding isn't available, every query returns empty rather than crashing the pipeline. It stores far more than file-based memory ever could: - **`deliberations`** — every agent verdict and full response (Judge, Inspector, Sentinel, …), with the extracted verdict, summary, token count, and an optional embedding for similarity search. - **`patterns`** — learned decision rules distilled from those deliberations. Each pattern carries a role, success and ignore counters, a lifecycle state, and per-project isolation so one repo's lessons don't bleed into another. - **`fix_memory`** and **`experiment_journal`** — what the Doctor tried on a failing issue, which approaches failed, which succeeded, and across how many iterations. - **`finding_signatures`** — a cross-pipeline fingerprint of recurring bugs, so the same finding can be tracked as it opens, gets fixed, or regresses. #### The pattern-learning loop This is what makes `memory.db` more than a log. Patterns extracted from deliberations are **re-injected into future prompts**, and a feedback loop adjusts their standing based on real outcomes. 1. **Injection.** Before an agent runs, [`scripts/format-patterns.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/format-patterns.js) selects that role's top patterns by a decay-weighted score and formats them into the prompt under a strict token budget — roughly 800 tokens for adversarial roles (Auditor, Judge, Sentinel) and 500 for constructive ones. If everything fits, it includes it all; if not, it falls back to a pre-computed summary or greedy truncation, so the budget is never blown. 2. **Reinforcement.** After a verdict, [`scripts/feedback-loop.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/feedback-loop.js) reads the result. On a **PASS** backed by Level 1 or Level 2 evidence — actual execution output, or `file:line` citations, per the [Evidence Hierarchy](/concepts/evidence-hierarchy/) — it reinforces the patterns that informed the decision and draws *informed-by* edges between cross-role patterns. Reasoning-only verdicts don't qualify; the evidence gate keeps the loop grounded. 3. **Penalisation.** When a validator (Inspector, Sentinel, Lens) marks a finding as a false positive, the loop calls `increment-ignore` on the responsible pattern, with a heavier weight for validator roles. Patterns that keep generating noise sink in the ranking and eventually fall out of injection entirely. Patterns also move through a **lifecycle** — `observed → candidate → verified → active → deprecated` — with transitions driven by how many times, and in how many distinct contexts, a pattern has proved itself. A brand-new observation has to earn its way to *active* before it carries real weight. A representative slice of the CLI: ```bash # Record a learned pattern for a role node scripts/memory-store.js store-pattern --role judge --text "..." --delib-id # Retrieve the top patterns for a role (decay-ranked) node scripts/memory-store.js query-patterns --role judge --limit 10 # Penalise a false-positive pattern node scripts/memory-store.js increment-ignore --role inspector --text "..." # Reward validated patterns after a PASS node scripts/memory-store.js reinforce-patterns --role judge --ids 12,34 ``` ### Versioning — `memory-versions.js` [`scripts/memory-versions.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/memory-versions.js) is a small standalone library (and CLI) that keeps a version history for individual memory entries — every change to a value is stored with a timestamp, so an entry can be inspected or rolled back. It writes to `~/.hermes/memory_versions.json` by default (overridable via `JKZ_MEMORY_VERSIONS_FILE`), keeps the last 10 versions per key (pruning the oldest beyond that), and writes atomically to stay safe under concurrent updates. A *restore* doesn't overwrite history — it appends a new version pointing back at the old value, so every rollback is itself auditable. ```bash node scripts/memory-versions.js --action history --key node scripts/memory-versions.js --action restore --key --version 3 ``` It is built as a reusable component rather than a tightly-wired pipeline tool, so other systems (such as the Hermes agent) can adopt it independently. ### Keeping memory honest — the maintenance subagents File-based memory decays if left alone: facts go stale as the code moves on, duplicates accumulate, and useful lessons from recent sessions never get written down. Two Opus subagents counter that, and the `extract-learnings` skill orchestrates them. - **memory-auditor** ([`.claude/agents/memory-auditor.md`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/.claude/agents/memory-auditor.md)) validates existing entries against the *current* codebase and git history. It flags memories that are stale, contradicted by the code, redundant with another entry, or carrying a wrong date — and it requires concrete evidence (a Glob, Grep, or `git log` result) for every finding, so it never flags on a hunch. - **signal-discoverer** ([`.claude/agents/signal-discoverer.md`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/.claude/agents/signal-discoverer.md)) works the other direction: it mines recent session history for knowledge worth persisting — user corrections, architectural decisions, recurring patterns, behavioural preferences — and proposes them as new memories, generalised into reusable principles rather than one-off incidents. The **`extract-learnings`** skill ties them together into a consolidation pass: it locates the memory directory and reads the existing set, runs the auditor and the discoverer **in parallel**, deduplicates and ranks their combined output down to a handful of high-impact candidates, and presents them with diffs for approval before anything is written. Note that `agents/shared-refinement.md` is an internal shared prompt fragment used by these agents, not a standalone agent in its own right. ### How the layers fit together | Layer | Backed by | Holds | Loaded | |-------|-----------|-------|--------| | File-based auto-memory | `memory/MEMORY.md` + topic files | User, feedback, project, reference facts | Index every session; topics on demand | | Agent-memory | `.claude/agent-memory//` | Per-role operational lessons | When the agent runs | | `memory.db` | `scripts/memory-store.js` (SQLite) | Deliberations, learned patterns, fix history | Patterns injected per-prompt, budget-controlled | | Versioning | `scripts/memory-versions.js` | Version history of memory entries | On demand (CLI / library) | Together they give the pipeline a working memory that spans timescales: what was true a moment ago (this run's deliberations), what an agent learned last week (its notebook), and what holds across the whole project's life (the curated file-based set). ## Mutation testing Source: https://docs.j0kz.dev/operations/mutation-testing/ Line coverage tells you which code ran during the tests. It says nothing about whether the tests would *notice* if that code started behaving differently. Mutation testing closes that gap: a runner generates small variants ("mutants") of the source under test — flipping operators, replacing literals, removing blocks — and reports which mutants the suite kills (a test fails) versus which survive (no test failed). A high line coverage with a low mutation score is the classic warning sign: tests that exercise the code without actually asserting on its behavior. jkz uses Stryker Mutator for JavaScript mutation testing. The current scope is intentionally narrow: a spike to validate the workflow before any broader rollout, run locally rather than in CI. ### How to run Each instrumented module has its own npm script, plus batch scripts that chain related modules: ```bash # A single module npm run mutation:atomic-write npm run mutation:vote-resolver npm run mutation:validators-run # ... one mutation: script per module in the scope table below # Batches npm run mutation:batch-a # decision-logic core npm run mutation:batch-b # context-protection modules npm run mutation:batch-c # validators suite npm run mutation:batch-de # analysis & utility modules npm run mutation:batch # pipeline-validation modules ``` Runtime is roughly 10–20 seconds per module at the current scope. Stryker forks a worker process per mutant and runs the corresponding `node --test scripts/.test.js` invocation under each mutation. The batch scripts chain modules with `&&`; because each config sets `thresholds.break: 0`, Stryker exits `0` on score-based results, so the chain only halts on a hard failure (config error, test-runner crash) rather than a low score. ### Where the report lives After a run, two reports are written to `reports/mutation//` (git-ignored): - `mutation.html` — an interactive report; open it in a browser to inspect surviving mutants line by line. - `mutation.json` — machine-readable; useful for scripting follow-up issues or CI gates. A `clear-text` summary (mutation score and killed / survived / timeout / no-coverage counts) is also printed to stdout at the end of each run. ### Current scope Modules marked ✓ meet the 80% gate. Each module has a follow-up issue tracking its surviving mutants for triage; the spike infrastructure (configs, scripts, baseline runs) is complete for all batches. | Module | Score | Gate | |--------|-------|------| | `scripts/saturation-check.js` | 95.77% | ✓ | | `scripts/validators/rules/secrets.js` | 95.21% | ✓ | | `scripts/parse-gemini-stream.js` | 88.14% | ✓ | | `scripts/validators/rules/test-coverage.js` | 86.67% | ✓ | | `scripts/circuit-breaker.js` | 83.82% | ✓ | | `scripts/validators/rules/capabilities.js` | 83.09% | ✓ | | `scripts/validators/rules/dry-check.js` | 83.06% | ✓ | | `scripts/rollback-decision.js` | 81.97% | ✓ | | `scripts/validators/run.js` | 81.37% | ✓ | | `scripts/cluster-findings.js` | 81.32% | ✓ | | `scripts/format-patterns.js` | 77.35% | | | `scripts/step-gate.js` | 72.68% | | | `scripts/error-grouping.js` | 66.09% | | | `scripts/slo-check.js` | 64.75% | | | `scripts/plan-digest.js` | 58.79% | | | `scripts/normalize-judge-verdict.js` | 57.33% | | | `scripts/rubric-score.js` | 56.25% | | | `scripts/extract-findings.js` | 55.17% | | | `scripts/compress-context.js` | 53.33% | | | `scripts/parse-body-deps.js` | 51.69% | | | `scripts/compress-git-output.js` | 48.21% | | | `scripts/truncate-output.js` | 46.93% | | | `scripts/loop-guard.js` | 42.56% | | | `scripts/vote-resolver.js` | 37.58% | | | `scripts/dependency-resolve.js` | 4.84% | | A low score is not automatically a problem: many survivors are *equivalent* mutants — semantically identical to the original (dead-code branches, defensive catches, regex alternation variants) — and need no new test. The per-module follow-up issues record which survivors are equivalents and which are real coverage gaps. ### Configuration Each module has its own `stryker.conf..json` at the repo root, all following the same pattern: - `mutate` — the target source file. - `testRunner: "command"` — wraps the existing `node --test ...` invocation, so no test-framework migration is required. - `coverageAnalysis: "off"` — kept simple for the spike; revisit once the workflow is established. - Reporters: `html`, `json`, `clear-text`. - `concurrency: 2`, `timeoutMS: 60000`. Exception: `step-gate.js` uses `concurrency: 1`, because its tests share tmpdir state and concurrent workers would interfere. ### CI integration CI integration — cadence, gate threshold, where it runs — is intentionally deferred to a separate follow-up issue. The current spike is local-only. ### Interpreting results - **Killed** — a test failed when the mutant was active. Good signal: the suite catches this kind of regression. - **Survived** — no test failed. Either the mutant is equivalent (semantically identical to the original) or the suite has a real gap. Triage each survivor in the HTML report. - **Timeout** — the mutant made the test runner exceed `timeoutMS` (often a real bug, e.g. an infinite loop). Counts as killed in the score. - **No coverage** — the line is not exercised by any test; the mutant could not even run. The mutation score is `(killed + timeout) / (killed + timeout + survived + no-coverage)`. ## Releasing Source: https://docs.j0kz.dev/operations/releasing/ Releasing jkz is a deliberate, manual process. There is no auto-publish on merge: a release happens when a human decides the `[Unreleased]` changes are ready to ship, picks the next version number according to the [SemVer policy](/operations/semver/), and walks the steps below. The changelog is the spine of the whole process — it is both the human-readable record and the machine-readable input that CI uses to populate the GitHub Release notes. ### Steps 1. **Move `[Unreleased]` items into a new released section.** In `CHANGELOG.md`, replace the empty placeholder under `## [Unreleased]` with a fresh empty skeleton, and create a new section above the previous release using the form `## [vX.Y.Z] — YYYY-MM-DD`. The em-dash (`—`) and the `v` prefix are required: `scripts/validate-changelog.js` matches the section by tag, and a hyphen or a missing prefix will not match. 2. **Commit the changelog update.** ```bash git commit -m "release: vX.Y.Z" ``` 3. **Tag the release.** ```bash git tag -a vX.Y.Z -m "Release vX.Y.Z" ``` 4. **Push the commit and the tag.** ```bash git push origin main && git push origin vX.Y.Z ``` 5. **CI validation and GitHub Release.** The release workflow runs `node scripts/validate-changelog.js vX.Y.Z` to verify the section exists and is non-empty, then `node scripts/extract-changelog-section.js vX.Y.Z` to populate the GitHub Release body from that section. ### Validating locally Before pushing the tag you can run the same two checks CI will run, so a malformed changelog section is caught on your machine rather than in the release workflow: ```bash node scripts/validate-changelog.js vX.Y.Z node scripts/extract-changelog-section.js vX.Y.Z ``` Both should succeed, and the extracted section should match what you expect to appear in the GitHub Release notes. If validation fails, it is almost always the section header — check the em-dash, the `v` prefix, and that the section is non-empty. ## SemVer policy Source: https://docs.j0kz.dev/operations/semver/ jkz follows semantic versioning, but the policy only works if everyone agrees on *what counts as the public contract*. A version bump is a statement about compatibility, so the first question for any change is: did it touch a stable surface? The lists below draw that line. Picking the next number then follows mechanically from the bump rules, and the [release process](/operations/releasing/) turns that number into a tag. ### Stable surfaces These are part of the public contract. Backwards-incompatible changes here require a **MAJOR** version bump (vX → v(X+1)). - **CLI subcommands** — `jkz update`, `jkz init`, `jkz docker`, `jkz uninstall`. Removing a subcommand or its flags is breaking. Adding new flags is non-breaking. - **Slash commands** — `/jkz:plan`, `/jkz:build`, and the rest. Renaming or removing one is breaking. - **Agent frontmatter contracts** — the `role`, `kind`, `model`, and `capabilities` field semantics. Changing required fields is breaking. - **Hook contracts** — scripts in `hooks/` invoked by Claude Code. Renaming a hook file or changing its expected JSON output is breaking. - **Frozen artifacts** synced to plugin projects — paths, names, and required content. Adding new artifacts is non-breaking; removing or renaming is breaking. - **`.jkz-version` file format** — line 1 is the version tag. ### Unstable surfaces Changes here are **MINOR or PATCH** depending on intent — never MAJOR, even when they are visible. - Internal scripts in `scripts/` not invoked by `bin/jkz` directly. - Wrapper internals (`codex-wrapper.sh`, `gemini-wrapper.sh`) — the agent invocation contract is stable, the internal flow is not. - Pipeline state JSON shape (`state/pipeline/.json`) — a read-only debugging artifact with no consumer contract. - Memory MD file structure under `memory/` — informal. - Telegram bot internals. ### Bump rules - **MAJOR (vX.Y.Z → v(X+1).0.0)** — any breaking change to a stable surface above. Requires migration notes in the changelog. - **MINOR (vX.Y.Z → vX.(Y+1).0)** — a new feature, agent, command, or hook (non-breaking), or a strictly additive behavior change to a stable surface. - **PATCH (vX.Y.Z → vX.Y.(Z+1))** — a bug fix, a doc-only change, or an internal refactor with no observable effect. ### Pre-releases Pre-release tags look like `v1.4.0-rc1` or `v1.4.0-beta`. They are tagged like normal releases but excluded from `latest` resolution unless `--include-prerelease` is passed to `jkz update` (future work). ### Deprecation Anything on the stable list can be deprecated at a MINOR bump. A deprecation must be: 1. Announced in the changelog under a `### Deprecated` section. 2. Logged at runtime when the deprecated surface is used (for example, `[DEPRECATED] /jkz:foo will be removed in v2.0`). 3. Kept for at least one MAJOR cycle before removal. ## SLOs & monitoring Source: https://docs.j0kz.dev/operations/slos-and-monitoring/ jkz judges its own health on two clocks. The slow clock is a set of **Service Level Objectives (SLOs)** — four quality bars evaluated over a rolling 30-day window that answer "is the pipeline healthy *in aggregate*?" The fast clock is a **monitoring loop** that runs every ten minutes and answers "is anything broken *right now*?" The two are complementary: SLOs catch slow erosion that no single run would reveal, while the loop catches acute failures — a stuck agent, a failing CI run, an exhausted rate limit — fast enough to act on them. ### The four SLOs The thresholds live in [`scripts/slos.json`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/slos.json), and [`scripts/slo-check.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/slo-check.js) evaluates them against the pipeline state files in `state/pipeline/`. Every SLO uses a 30-day window: only pipelines whose `started_at` falls inside the window are counted. | SLO | Threshold | Direction | What it measures | |-----|-----------|-----------|------------------| | `pipeline_completion_rate` | ≥ 0.80 | higher is better | Share of pipelines that reached a terminal phase (`completed`, `approved`, `qa_approved`, …). | | `review_first_pass_rate` | ≥ 0.60 | higher is better | Among pipelines that got past the review phase, the share that needed **zero** review fix cycles. | | `avg_fix_iterations` | ≤ 2.0 | lower is better | Mean fix iterations per pipeline — `review_fix_count + qa_fix_count`, summed and divided by pipeline count. | | `max_pipeline_duration_hours` | ≤ 2 | lower is better | Longest start-to-finish wall-clock time among **completed** pipelines. | #### How a value becomes a verdict `slo-check.js` reduces every pipeline state file to a single inner object (the files are `{ "": { … } }`) and computes the four actuals: - **Completion rate** counts pipelines whose `current_phase` is terminal and divides by the total in the window. - **First-pass rate** filters to pipelines that are *past* reviewing, then takes the fraction with `review_fix_count == 0`. With no past-review pipelines the value is `null`. - **Average fix iterations** sums review and QA fix counts across all pipelines and divides by the count. - **Max duration** walks the completed pipelines, computes `completed_at − started_at` in hours for each, and keeps the maximum. Pipelines with unparseable or negative durations are skipped. Each actual is then compared to its threshold. SLOs without a `comparison` field are ratios where **higher is better**, so they record a `violation` when the actual drops *below* the threshold. SLOs with `comparison: "lte"` (`avg_fix_iterations`, `max_pipeline_duration_hours`) flip the test: they violate when the actual rises *above* the threshold. When there is no data for a metric — for example, no completed pipelines yet — the status is `no_data` rather than a pass or a fail. The result is a structured object with each SLO's `actual`, `threshold`, and `status` (`ok` / `violation` / `no_data`) plus a flat `violations` list. It surfaces in two places: the [`/jkz:status`](/commands/status/) command renders it as a table, and the monitoring loop's `slo_compliance` check (below) turns any violation into a low-severity alert. ### The monitoring loop The Telegram bot ([`scripts/telegram-bot.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/telegram-bot.js)) drives the fast clock. Every **ten minutes** (`MONITOR_INTERVAL_MS`) it runs one monitoring cycle: it executes a battery of independent, non-blocking checks in parallel, routes any non-`ok` results to alerts, and writes a snapshot of the full result set to `state/bot-monitor-report.json`. Every check is an `async` function in [`scripts/monitoring-checks.js`](https://github.com/j0KZ/jkz_Multi-Agent_System/blob/main/scripts/monitoring-checks.js) that returns the same shape: ```text { status: "ok" | "warn" | "error", check: "", detail: "", severity?: "S1".."S4" } ``` The checks are **Docker-aware**: when a project runs in a container, shell commands route through `docker exec -w /workspace`, while state-file reads use the native filesystem (the state directory is bind-mounted and readable from the host). #### The eleven checks The live cycle runs eleven checks. Each is wrapped so a thrown error degrades to a `warn` rather than crashing the cycle. | Check | Watches for | Worst severity | |-------|-------------|----------------| | `active_agents` | Agents idle more than 30 minutes with no stdout activity (`lastActivity` tracking). An idle agent is also cleaned up so it can be re-launched. | S3 | | `ci_status` | Failing CI on open `jkz:reviewing` / `jkz:qa` PRs (`statusCheckRollup` in `FAILURE`/`ERROR`). | S1 | | `stale_worktrees` | Secondary worktrees untouched for more than 4 hours. | S3 | | `deliberation_errors` | Deliberation JSON files with `status: "error"` written in the last 30 minutes. | S1 | | `github_api` | GitHub core rate limit running low (a warning under 100 requests remaining). | S2 | | `git_drift` | Local `HEAD` falling behind `origin/main` (git-sync may have failed). | S2 | | `cli_versions` | Outdated or breaking CLI updates, read from the cached changelog only — no network call. | S2 | | `slo_compliance` | Any of the four SLOs above in `violation` over the 30-day window. | S4 | | `worktree_cleanup` | Worktrees of terminal (merged/closed) pipelines that can be reclaimed. | — | | `quota_restoration` | A previously exhausted Codex quota — probes whether it has recovered and reverts routing if so. | — | | `stale_locks` | Worktrees locked by an issue that has since been closed (two-cycle confirmed sweep, issue #1376). | — | `monitoring-checks.js` defines a few more check functions — groupthink detection, blocked-dependency scanning, post-merge outcome tracking — that are exported for other surfaces but are **not** part of this ten-minute cycle. #### Severity and alerting Checks tag themselves with a severity from **S1** (most urgent — failing CI, deliberation errors) down to **S4** (SLO drift). After every cycle, `routeMonitorAlerts` selects the non-`ok` results worth sending and applies a **30-minute cooldown** (`ALERT_COOLDOWN_MS`) per alert key, so a persistent condition pings the project's Telegram health thread at most twice an hour instead of every cycle. Alerts render with an `ERROR` or `WARN` icon and the check's `detail` text. #### Cadence layered on top of the cycle A few periodic jobs ride the same ten-minute tick using a cycle counter: - **Every 3 cycles (30 min):** proactive task discovery plus an automations tick. - **Every 6 cycles (60 min):** a fire-and-forget refresh of the CLI changelog cache (`changelog-review.js`), which is what keeps the `cli_versions` check's cache-only read meaningful. ### Related - [Pipeline](/concepts/pipeline/) — the PLAN → BUILD → REVIEW → QA flow whose completion, first-pass, and fix-iteration rates the SLOs measure. - [Telegram bot](/subsystems/telegram-bot/) — the host process that runs the monitoring loop and delivers its alerts. - [Worktree isolation](/concepts/worktree-isolation/) — the worktrees that the `stale_worktrees`, `worktree_cleanup`, and `stale_locks` checks keep tidy. - [`/jkz:status`](/commands/status/) — the command that renders the live SLO table on demand. ## State schema Source: https://docs.j0kz.dev/operations/state-schema/ Every jkz run leaves a trail on disk. That trail lives in one place — the `state/` directory — and it is the difference between a pipeline that can be observed, resumed, and audited and one that forgets the moment a process exits. `state/` is runtime-only and git-ignored: nothing in it is source code, and everything in it can be regenerated or discarded. But while a run is live, it is the single source of truth for *where each issue is*, *what each agent decided*, and *which resources are held*. The store is not one format but several, each owned by a different part of the system. The most important — and the only one with a formal, validated contract — is the per-issue pipeline state. ### The pipeline state file Pipeline state lives in `state/pipeline/.json`, one file per issue. Each file uses a nested wrapper: the issue's data sits under a numeric key matching the issue number, with a few bookkeeping fields as top-level siblings. ```json { "": { "current_phase": "building", "active_agent": "builder", "active_agent_kind": "creative", "issue_type": "feature", "pr_number": "42", "started_at": "2026-04-10T12:48:21.988Z", "last_updated": "2026-04-10T13:06:54.627Z", "plan_iterations": "1", "review_fix_count": "0", "qa_fix_count": "0", "review_passed": "true", "qa_passed": "false", "complexity": "standard", "pipeline_run_id": "run-42-20260410124821-6b11c423", "prompt_rewrite_count": "0", "sub_issues": [43, 44], "steps": { "plan": { "architect": { "status": "completed" } } }, "tokens": { "_runs": [] } }, "lastActivity": "2026-04-10T13:06:54.627Z", "heartbeat_pid": 47281 } ``` A few characteristics are worth internalising, because they trip up anyone who reads these files expecting a flat object: - The issue data is **nested under a numeric key**, not at the top level. Reading `current_phase` means going through `data[""].current_phase`. - All scalar pipeline fields are stored as **strings** — including `pr_number`, the iteration counts, and the booleans (`"true"` / `"false"`). Consumers coerce on read. - `lastActivity` and `heartbeat_pid` are **top-level siblings**, not inside the issue object. - `steps` and `tokens` are **opaque record objects** — they carry per-step status and token accounting but are not validated by the UI schema. - **Unknown fields are preserved.** The schema uses passthrough, so a new field written by a future script survives a round-trip through an older reader. `pr_number` deserves a special mention: it is the canonical authority for "which PR closes issue #N", and downstream consumers resolve it through a shared cascade that prefers an explicit argument, then an in-shell hint, then this field, before falling back to scanning open PRs. ### From disk to a typed view The UI server does not consume the raw file. It runs it through `normalizePipelineState()`, which turns the string-heavy, loosely-typed on-disk shape into a typed internal interface. The coercion rules are deterministic: | On-disk field | Normalized field | Type | Coercion | |---|---|---|---| | `current_phase` | `current_phase` | `string` | Default `"unknown"` | | `active_agent` | `active_agent` | `string \| null` | Empty string → `null` | | `issue_type` | `issue_type` | `string` | Default `"feature"` | | `pr_number` | `pr_number` | `number \| null` | `parseInt()`, `NaN` → `null` | | `started_at` | `started_at` | `string \| null` | Direct passthrough | | `last_updated` / `lastActivity` | `last_updated` | `string \| null` | Prefers `last_updated`, falls back to `lastActivity` | | `review_passed` + `qa_passed` | `verdict` | `"PASS" \| "FAIL" \| null` | Both `"true"` → PASS; either `"false"` → FAIL; else `null` | | (not on disk) | `branch` | `null` | Reserved for future use | `verdict` and `branch` are internal to the normalized view and are **not** exposed in the public `PipelineIssue` API — they are computed conveniences, not stored fields. The contract is enforced with Zod schemas defined in `ui/server/schemas/pipeline.ts`: | Schema | Purpose | |---|---| | `PipelineStateOnDiskSchema` | Validates the inner issue object (all fields optional, passthrough) | | `PipelineFileSchema` | Parses the full file: extracts the numeric key, validates inner data, extracts `lastActivity` | | `LiveSessionSchema` | Validates `state/live-session.json` (UI server owned) | | `WatchListSchema` | Validates `state/watch-list.json` (UI server owned) | ### Who writes what Ownership is strict, and it is what keeps concurrent chats and the UI from corrupting each other's view. The rule of thumb: pipeline scripts write pipeline state; the UI server writes its own session files and never touches pipeline state except to read it. | File | Owner | Readers | |---|---|---| | `state/pipeline/.json` | Pipeline scripts (`json-helper.js`, orchestrator) | UI server (read-only) | | `state/live-session.json` | UI server | UI frontend (via API) | | `state/watch-list.json` | UI server | UI frontend (via API) | ### The rest of the store Pipeline state is the contract, but it is a small fraction of what `state/` holds. The surrounding directories are less formal — most are append-only logs or caches — but they are what make a run observable after the fact and recoverable after a crash. - **`deliberations/`** — one JSON record per agent invocation, the durable transcript of every verdict. Each record carries `role`, `timestamp`, `status`, the agent's `response`, the `model` and `endpoint` that produced it, the `pr`/`issue`/`phase` it ran against, the `command` that triggered it, `duration_ms`, and a `tokens` accounting block. This is the layer that answers *what did the Judge actually say on iteration 2*. - **`session-snapshots/`** — one file per chat session (`.json`), capturing rich reasoning context — completed work, decisions, gotchas — alongside git state and pipeline status. `/jkz:save` writes them; `/jkz:load` retrieves the most recent from another session. When `CLAUDE_SESSION_ID` is unset, the snapshot is keyed `anonymous`. - **`locks/`** — worktree and pipeline locks. A lock has a TTL (1800s by default) after which it is considered expired and reclaimable, which is how a crashed run stops blocking the issue it was holding. - **`circuit/`** — one file per external service (`codex.json`, `gemini.json`, `api-ollama-com.json`, …) recording circuit-breaker state. An open circuit short-circuits calls to a service that has been failing; the breaker half-opens after a cooldown to test recovery. - **`active-chats/` and `active-worktrees/`** — the cross-chat registry's view of which session owns which issue and worktree, so a second chat can refuse to edit a contested issue. #### The SQLite databases Four `.db` files hold the structured, queryable state that does not fit a per-run JSON file: | Database | Holds | |---|---| | `memory.db` | The pattern-learning store — patterns mined from deliberations, re-injected into future prompts, with a feedback loop that reinforces what works and penalises noise. By far the largest of the four. | | `metrics.db` | Pipeline metrics used to evaluate SLOs (completion rate, fix iterations, durations). | | `cr-history.db` | CodeRabbit review history, used to reconcile and de-duplicate findings across iterations. | | `chat.db` | The chat registry backing cross-chat awareness — heartbeats, issue ownership, worktree paths. | ### Why it is shaped this way The split is deliberate. The one piece other processes depend on — pipeline state — has a strict, versioned, passthrough-tolerant contract so the UI server can read it without breaking when the pipeline adds a field. Everything else is append-only logs and caches: cheap to write, safe to lose, and never on the critical path of a transition. A run can be killed at any point and the next session reconstructs *where it was* from the pipeline file and *what happened* from the deliberations, while locks and circuit state make sure a dead run stops holding resources it can no longer use. When something in a run looks wrong, the [troubleshooting guide](/operations/troubleshooting/) is the companion to this page — it maps symptoms back to the files and scripts that own them. ## Troubleshooting Source: https://docs.j0kz.dev/operations/troubleshooting/ Most pipeline failures have a known cause and a one-line fix. This page is organised symptom-first: find the error message or behavior you are seeing in the index, jump to the entry, and apply the fix. Each entry names the source file where the behavior — and its remedy — actually live, so you can verify rather than trust. ### Symptom index | Symptom / error | Entry | |-----------------|-------| | Guard emits JSON on stderr, scripts break when parsing | [Guard hooks](#guard-emits-json-on-stderr) | | A guard allows a command it should have blocked | [Fail-open guards](#fail-open-guard-hooks) | | `'\r': command not found` when running scripts | [CRLF line endings](#crlf-breaking-bash-scripts) | | `echo`, `cat`, `pwd` fail with cryptic errors | [Bash builtins](#bash-builtins-broken-in-the-sandbox) | | `Permission denied` or script not found in `scripts/*.sh` | [Script permissions](#windows-script-execution-permissions) | | Empty or garbled stdin from PowerShell | [PowerShell stdin](#powershell-stdin-pipe-failure) | | `Argument list too long` when invoking wrappers | [Large prompts](#large-prompts-exceed-cli-argument-limits) | | `bash -n` reports errors on valid scripts | [bash -n in the sandbox](#bash--n-returns-a-false-exit-code) | | `Can not approve your own pull request` | [Self-approval](#cannot-approve-your-own-pr) | | `BLOCKED by jkz guard: gh pr merge` | [Merge blocked](#pr-merge-blocked) | | `orchestrate.sh transition` rejects the transition | [Phase validation](#phase-validation-fails) | | Stale worktrees reported by the health check | [Stale worktrees](#stale-worktrees) | | Judge rate-limited differently than Auditor/Sentinel | [Codex quota](#the-judge-uses-a-separate-quota) | | Gemini wrapper returns empty or garbled response | [Gemini JSON](#gemini-json-parse-failure) | | Pipeline stage skipped unexpectedly | [Model fallback](#model-fallback-behavior) | | `mcpServers` in `settings.json` rejected | [MCP config](#mcp-config-validation-error) | | `mcp/dist/index.js` not found | [MCP build](#mcp-server-build-fails) | | Circuit breaker blocks a service that is working | [Circuit breaker](#circuit-breaker-blocks-a-healthy-service) | | "near-duplicate fix detected" / Doctor in a loop | [Loop guard](#loop-guard-warns-about-duplicate-fix-attempts) | | Cost report shows "N/A" in the cost column | [Pricing](#cost-report-shows-na-for-pricing) | ### Guard and hooks #### Guard emits JSON on stderr **Symptom.** Pipeline scripts that parse guard output break, because they receive a JSON line followed by human-readable text instead of plain text. **Cause.** `hooks/guard-destructive.sh` emits structured JSON on stderr when it blocks a command: ```text {"blocked":true,"pattern":"","level":""} BLOCKED by jkz guard: command matches pattern '' ``` **Fix.** For pipeline scripts, the simplest reliable signal is the exit code: `2` means blocked, `0` means allowed. If you must inspect the reason, parse the `blocked` field from the first stderr line as JSON. **Source.** `hooks/guard-destructive.sh`. #### Fail-open guard hooks **Symptom.** A guard hook occasionally allows a command it should have blocked — rare, and only on parse errors. **Cause.** This is intentional. Claude Code `PreToolUse` hooks that exit with a code other than `0` or `2` cause infinite retry loops, so the guards trap errors and fail open (`trap 'exit 0' ERR`) rather than risk hanging the session. **Fix.** None — it is a platform constraint. Judge and Inspector code review are the safety net behind it. **Source.** `hooks/guard-destructive.sh`, `hooks/guard-worktree.sh`. ### Claude Code sandbox and Windows #### Bash builtins broken in the sandbox **Symptom.** `echo`, `cat`, `pwd`, `cd`, `test`, `set` fail with cryptic errors inside Claude Code. **Cause.** Claude Code passes Windows file descriptors that MSYS2 cannot use as POSIX fds. External commands (`node`, `git`, `codex`, `gemini`) are unaffected because they read handles directly. **Fix.** Run shell scripts through Node, which spawns bash with proper pipes: `node scripts/run.js