Skip to content
Karajan Code — multiagent coding orchestrator

Karajan Code

Code with several AIs, with guarantees. Your agent writes; Karajan governs: TDD-first method, cross-AI review on every commit, git gates — a false green is impossible.

Your AI agent (Claude Code, Codex, Gemini CLI, Cursor…) writes the code — Karajan governs how it happens. kj installs a method your agent follows on every task (RAG before assuming, card first, tests first) and enforces it with git gates: every commit requires a verdict from a different AI, security findings are never overridable, and the base branch only moves via PR. The maker never grades its own work — and a false green is structurally impossible.

Prompt engineering got one good answer from one good prompt. Context engineering curated what the model saw. The 2026 frontier is loop engineering: you stop prompting the agent by hand and design the system that prompts it, checks it, and decides what happens next — until the goal is met or it hands back to you. Karajan was built around that loop before the term caught on:

  • Maker / checker split — a coder against independent reviewer, tester and security roles, with Solomon judging disputes. The maker never grades its own work.
  • Deterministic verification — TDD, per-HU acceptance tests, SonarQube gates and deterministic guards. Checking is tests, not vibes.
  • The autonomy ladder L1 → L2 → L3 — the interactive | assisted | autonomous axis (v3.7.0). Report, then assisted fixes, then unattended kj autorun — defaulting to interactive, so you opt in.
  • A durable state spine — sessions, the HU Board, journals, the RAG index and kj resume keep the loop alive across runs.

The caveat loop engineering insists on — unattended loops make unattended mistakes — is designed in: autonomous runs list their residual defects, every story lands behind a PR, and kj-trash snapshots destructive operations. Read the full building-block mapping →

One-liner setup

Tell your agent: “read karajancode.com/start.md and do what it says”. It installs the full stack, detects new vs existing project, activates the environment — and stops to WAIT for you whenever a step needs sudo or an account. Install →

Your agent, governed

The playbook lands in CLAUDE.md, AGENTS.md and GEMINI.md from one source: RAG first, card first (kj hu), TDD, ADRs in git (kj adr). Role briefs (kj brief) give your agent the distilled method of triage, planner, architect, tester, security and audit. Work with your agent →

Cross-AI review + git gates

kj review --staged binds a verdict from a different AI to the exact diff — change the code and it must be reviewed again. Disagree? A third AI arbitrates (kj solomon); security findings nobody overrides. The pre-commit gate makes it law. The gates →

RAG over your codebase

Built on install, refreshed on drift: kj rag query answers what the code does so no agent guesses. On existing projects, kj onboard produces an Architecture Brief before anyone touches anything.

Self-healing ecosystem

Your agent hits a kj bug? kj report-issue diagnoses and files it upstream — sanitized, deduped, and only with your approval. Fixes ship back to everyone. Command reference →

Headless mode

The classic multiagent pipeline lives on for CI and automation: kj run orchestrates coder/reviewer/tester subprocess roles unattended, with the same gates. Headless mode →

Governed tournament (v4.15)

One task, N coders in isolated worktree lanes: kj tournament fans out, --score builds a deterministic zero-LLM scoreboard, a cross-AI judge with no conflict of interest picks the winner, and --crown promotes it through the normal review gate — winning earns a candidacy, not a bypass.

The most recent releases, newest first. Older versions live in Architecture › History and the CHANGELOG.

v4.56.0: reviewing someone else’s PR (current)

Section titled “v4.56.0: reviewing someone else’s PR (current)”

kj review --third-party --json lets a reviewer agent review another person’s PR with kj’s reviewer and the target repo’s rules, and returns one JSON document with the verdict, the findings and the PR’s requirement checks (size, commits, tests, secrets, personal data, risky dependencies, semgrep, Sonar), without the own-work gates and without storing a verdict. The Sentinel stops reading shell where a checkpoint already decides (human acts, identity, push), pre-push checks every pushed commit’s identity, and the Steward’s block also stops a commit.

v4.55.0: each HU on the model its tier calls for

Section titled “v4.55.0: each HU on the model its tier calls for”

The coder of each HU runs on the model and effort its tier calls for (trivial, standard or deep) and climbs to the most capable one when an iteration fails; a model you chose always wins and the reviewer is never routed. kj plan fills each HU’s model from its tier, the HU Board can change it, and kj report says how many HUs were routed and how many climbed. Concurrent reviews on one machine share sonar-scanner slots, a reviewer no longer blocks a platform feature it simply does not know, and kj handoff add gets through the Sentinel.

v4.54.0: skills in the prompts, a task window for you

Section titled “v4.54.0: skills in the prompts, a task window for you”

The skills that fit the task (the project’s own first, then the local catalog) reach the coder and the reviewer, up to 3 per role, and starting an HU names them. kj handoff watch keeps, in another terminal, what only you can do (publish, seal, run a script), with date and why, out of the session’s scroll. kj env install wires qmd’s MCP so the agent asks it about docs, notes, ADRs and plans, and the RAG about code. And rag-first counts a kj_rag_query answer cut short.

The next PR of a card split into stacked PRs can be pushed and opened before the first one’s card is moved, a push no longer contradicts the answer board-sync just gave it, a block kj could not verify says why (usually another gh account active), and a card title or commit message that only mentions sealing the harness or enrolling the phone is read as text.

v4.53.0: the phone stops getting in the way

Section titled “v4.53.0: the phone stops getting in the way”

kj init offers to enroll your phone, kj doctor says plainly what is refused without it, and with no phone at all a person at the terminal can lower the level. kj review --publish-pr puts the cross-AI verdicts on the PR as a GitHub review, kj review warns of dependencies published hours ago, kj harden says how to make the method’s checks required, and starting a card reserves it for a team. Each HU now records its coder model and cost, and kj report adds them up per model; it also leaves the decomposition with its tier, and kj run --profile frugal|standard|deep picks the models. A plan says whether each change extends, reworks or rebuilds existing code, and a rework needs a licence from the module’s mutation score. The supply-chain cooldown can block, kj check says when the audit is due, and the prompt-injection patterns become a catalog the whole family reads.

No version ships without the scenario battery green, and CI runs it on every PR. kj worktree prune retires the kj lanes that are provably abandoned, a correction from the reviewer is named as the method working, and the verdict of a claude reviewer is read even when its answer opens with hook events.

v4.51.1: a spoken threshold that really changes

Section titled “v4.51.1: a spoken threshold that really changes”

kj policy add "PRs can have up to 500 lines" now changes the line limit the policy already has, instead of adding a second one beside it that the stricter limit kept overruling.

v4.51.0: the policy changes only with your seal

Section titled “v4.51.0: the policy changes only with your seal”

An agent could not write your policy, but a change that landed anyway went through commit and CI, judged by the very policy it brought. Now a change to policy.yml or rules.yml is refused wherever it is used, commit, CI and release, until you seal it with kj harden --commit, signed from your phone.

v4.50.0: one board for kj, a replica in yours

Section titled “v4.50.0: one board for kj, a replica in yours”

With the Planning Game or an external board such as Jira or Linear, kj used to step aside and leave no HU Board. Now the HU Board is always kj’s board: every card lives there, kj hu add --ref <id> links its replica in your tracker, and card-first recognises a branch by either id.

A RAG query that names an indexed file now returns that file first, so the rag-first gate opens for a freshly indexed page that ranking alone left out of the top hits, such as an .astro page in a large index. Three high or critical dependency advisories are cleared with patched releases inside the existing ranges.

kj review --staged --task-file now hands the file to the reviewer: the evidence a session passed (an official doc, a spec) used to be dropped, and the reviewer kept rejecting what it never saw. The Sonar pre-gate also finds the token kj saved in its home, so a valid token no longer blocks every code commit.

claude now receives its prompt on stdin, so a security review over a big diff no longer fails with E2BIG, and generated files such as lockfiles enter the reviewer and Solomon prompts as one summary line, so the reviewer sees the real hunks. kj env install also commits the .mcp.json it wires, so a fresh clone keeps the RAG as a native tool.

v4.49.2: plan runs that implement their HU, and a Sentinel that reads commands

Section titled “v4.49.2: plan runs that implement their HU, and a Sentinel that reads commands”

A plan run no longer triages the plan’s original task: it was generating other HUs that ran instead of the plan’s, dropping its Gherkin, and could skip the coder and approve an empty diff. A code HU is no longer approved over a red project suite, and the first release of a freshly hardened repo is no longer blocked by the files its own setup installed. The Sentinel stops reacting to words inside quoted text, accepts the kj rag query it recommends, and no longer reads a body file’s path as an attribution. E2BIG goes straight to the next provider, version ranges are no longer secrets, and the audit keeps to the current project’s Sonar issues.

v4.49.1: plan runs that commit, and a size budget that does not ask

Section titled “v4.49.1: plan runs that commit, and a size budget that does not ask”

kj run --plan stopped before committing every HU, blocked by its own card-first and verdict gates, spec-reviewed the plan again and never handed the coder the domain context; the three are fixed, and the domain context now reaches the coder in every run. The PR size has two tiers: about 150 lines is the ideal, up to 200 is allowed without asking, above it partition. kj harden --report now names the Sentinel and the git hooks when they are missing, and kj harden no longer asks for a seal with nothing to seal.

v4.49.0: plans that converge, gates that stop shouting at kj

Section titled “v4.49.0: plans that converge, gates that stop shouting at kj”

Five field reports from one session against kj plan: the fix loop archived HUs as a status validate rejected, could only add dependencies, and could close a cycle that then slipped into the run. Now archived HUs validate and replacements take over their edges, the fixer removes dependencies and narrows scopes when the feedback asks, and a cycle is named and stops the run. The privacy gate no longer reads a plan id as a credit card, pr-size leaves the shared plan out, the skills catalog no longer brings test fixtures into the project, and the guards absent from CI are vouched by the roster’s signature.

v4.48.3: a seal from an older kj is vouched by the phone

Section titled “v4.48.3: a seal from an older kj is vouched by the phone”

After upgrading kj, kj release check denied the hook a human had sealed with the previous version, because the check re-renders it with the new template. A seal made by another version is now vouched for by the phone’s signature over those bytes; unsigned, it stays denied and says to re-seal. Also carries 4.48.2: the HU Board starts on a global install.

v4.48.2: the HU Board starts on a global install

Section titled “v4.48.2: the HU Board starts on a global install”

The board ships inside the main package, and three of its dependencies (ws, @xterm/xterm, node-pty) were only declared by its own package, so a global install could not start it. They are declared by the main package now, node-pty as optional because it is native and only the embedded terminal needs it.

The Quality workflow runs in the language root when the app lives in a subdirectory, kj rag query no longer reindexes the whole repo before answering when the index is old, and the rag-first gate lets a barrel (index.ts, __init__.py, mod.rs) be edited once the RAG answered about its folder.

The agent no longer asks the human by chat for what kj refused it. Every deny of the Sentinel leaves a record with the gate’s own words, and kj handoff add registers a handoff only against that record, so the why is the gate’s, never the agent’s; kj handoff list|show read it by id. Also fixed: untracking an inherited runtime file no longer needs --no-verify, and the agent can report through kj report-issue, the very command the Sentinel sends it to.

v4.47.0: the level that protects whoever does not know the risk exists

Section titled “v4.47.0: the level that protects whoever does not know the risk exists”

Security level max by default: every act of the catalog (sealing the supervisor, approving rules, enrolling another phone, lowering the level) is signed from the phone over the exact bytes and refused without one; kj security show|normal|max reads and changes the level, and lowering it is itself a signed act that says what is done and why. A lost phone is replaced with the one-time recovery code shown at the first enrollment, never by reinstalling: the code is spent on use, a new one is issued and the lost phone is revoked. CI judges every change of the roster of phones. And the relay’s rules, which rejected every seal since 4.46 with a 403, admit what the signing page shows.

“I see ‘sentinel’, but what am I signing? you could be deceiving me.” The signing request now carries what changes, file by file: new, modified or deleted, lines added and removed, a one-line summary, the diff (cut and privacy-scanned), the branch and what generated it. The page speaks the browser’s language, Spanish or English, folds the diff under each file and says that the sha256 shown are what the signature guarantees. Also: a closed catalog of human acts with one mechanism and an architecture test that watches it (enrolling the phone runs the four layers itself), and a card’s criteria reach the HUs at decomposition time, so none is left without an HU.

v4.45.0: approved means the card’s criteria are in the diff

Section titled “v4.45.0: approved means the card’s criteria are in the diff”

A run ended approved with none of the card’s three acceptance criteria implemented. With a card read, a different AI than the coder now reads each criterion against the diff before the run says approved and answers one by one: covered, with the evidence, or not. An uncovered criterion goes back to the coder; on the HU path the result says approved:false with the list; a judge with no readable verdict never grants an approval. Also: kj harden after a version bump no longer blocks itself against the seal, and kj update never downgrades a kj linked from its source tree.

v4.44.1: the run says what it could not do

Section titled “v4.44.1: the run says what it could not do”

Six field reports from one day on a fresh project: a run approved with no push and no PR and no word about it, five commits under two identities, branches named after invented HUs, a card that could not be read and a pipeline that went on without it, and an agent with kj installed and never hardened routing around every gate by hand. Now a push or PR that fails travels in the run’s result with its remedy (the workflow scope refusal names the exact fix); one git identity is resolved once and every commit of the run carries it; with a card the branch is feat/<CARD-ID>-<slug> on both paths; a card that cannot be read stops the run before it starts; a Claude host without the Sentinel harness stops it too, and an issue for karajan-code goes through kj report-issue. The first session of each version invites to enroll the phone (ADR 0018).

v4.43.0: the pipeline commits only its own work

Section titled “v4.43.0: the pipeline commits only its own work”

One run approved a step with the reviewer disabled, no implementation and a failing test, staged 22 untracked harness files into the commit and committed 960 lines where the plan allowed 150. Now a simple task keeps its cross-AI review, and with no review the pipeline stamps no verdict and commits nothing; under TDD the project’s own test suite runs every iteration and a red suite goes back to the coder; the PR budget is applied before the commit, with kj pr-size’s count; and the commit holds only what the run changed, by path, with the verdict bound to that exact diff. The Sentinel also denies git add -A and any staging of the agent’s runtime files, the pre-commit hook refuses them however they got there, and a question that changed nothing (domain documents) is no longer asked.

Sessions working on other projects reported in one day what the method got wrong for them, and every one is fixed. An approved review was read as a rejection because the reviewer wrapped its verdict in an envelope: now what kj cannot read is the reviewer’s failure, retried and saved, never a defect handed to the coder. The RAG ledger compared paths as text, so an index built through a symlinked workspace dropped every hit and rag-first denied every edit: now it compares real paths and names what it drops. The coder no longer commits before the review, a scratch file outside the repo is not a source, Sonar skips a repo without src/ in one line, read-only pipelines no longer trip the Sentinel, a preflight timeout is a warning, kj status sees a dead run, and kj harden commits the contract it generates.

In a repository with history, kj generated 28 files of contract and left them to the agent, whose own PR-size rules forbid such a commit. Now kj env install and kj bootstrap commit what they just generated: only those files, never what you had dirty or staged, and never on the base branch, where kj names the files and how to commit them on a branch. Also: a compiled rule can say why it is compiled the way it is, the reviewer of a proposal blocks only on material weakness, and a rejected review no longer vetoes your approval: its objections come first, and you decide.

The rules you write in your MD files stop depending on the agent remembering them. kj reads them, compiles each into a condition over a tool call, and checks every call before it runs, MCP tools included; a deny names the rule and the MD it comes from. You approve the compilation from your own terminal, after a different AI has reviewed it rule by rule, and what you read is ordered by what can hurt. Rules that come from your private files are kept out of git. Also: CI now verifies the phone’s signature of a seal against the versioned roster, a new ADR is born proposed, and kj audit treats a static site as the frontend it is.

An audit counted fifteen KJ_ALLOW_* escapes, and the agent could raise every one of them by prefixing a command. ADR 0015 removes them all, in the Sentinel, in kj review and in the git hooks: a gate that needs an escape is a gate to fix. Each decision that really belongs to the project has its own channel outside the session, from a PR to policy.yml to the large-pr-justified label. Also fixed: a body-file path followed by ;, solomon’s position from a file, restoring a file the session removed, ai-trash keeping uncommitted work, and a Sonar pregate that read the previous analysis.

A coder blocked by rag-first wrote the same change with shell heredocs and discarded a user’s uncommitted line with git checkout. Now the repo is written through Edit and Write only, and a session cannot throw away work it did not make. The Sentinel’s guards moved out of template strings into real modules with unit tests. The method’s rules reach the agent at the moment of the action, and come back after every compaction. And a session no longer changes the policies that govern it: Karajan governs, and every deny says so.

The phone now signs everything it shows, the kj version and its own expiry included, so an approval cannot outlive what the human saw. A cleanup that deletes code and corrects the comments it left behind is no longer taken for new code that needs tests. A versioned .ragignore says what stays out of the RAG. And the two limits that kept being found only when a gate blocked, the size of a PR and the format of a commit message, are now said while the work is being written: kj pr-size measures the branch with the CI’s own budget, and the commit hook rejects what CI would.

v4.36.0 — one index and one board per project

Section titled “v4.36.0 — one index and one board per project”

Every project on a machine shared one RAG store and one board view, so a query from one repo could bring back another repo’s code, and the board’s own search did exactly that. Now each project keeps its index in its own .karajan/rag.db, and kj rag migrate moves it there from the old shared store without re-embedding anything. The board starts by itself, like Sonar, and kj opens it on that project’s view alone, /p/<slug>, where the settings, the embedded terminal and the search act on that project and no other. The canon kj ships stays shared in its own store, reached with kj rag query --library. The index also stops depending on a list of languages: any text file your project versions goes in, and what stays out (binaries, generated files, secrets) is said with its reason. And in a repo managed with Rulesync, kj writes its rules into .rulesync/rules/karajan.md, so rulesync generate spreads them instead of erasing them.

v4.35.1 — a gate that names what it compares against

Section titled “v4.35.1 — a gate that names what it compares against”

Nine fixes in a day, most reported by a sibling project on the same machine. The quality gate runs inside a lane again: the scanner’s SCM plugin could not open a linked worktree, so every change made the way the method prescribes went through with no gate and no red to say so. The harness integrity warning now names the kj it is judging, its version and whether it is a linked development tree, because a session had built a ritual of running kj harden twenty times a day without ever learning why. And the JSON rewrite guard stops policing files outside the repository, after eight review rounds each found a real way through a pattern-based reading of shell text.

v4.35.0 — where kj cannot know, you say so

Section titled “v4.35.0 — where kj cannot know, you say so”

Fourteen issues had been sitting open, some of them for months, and they all said the same thing: a gate that cries wolf teaches you to disable gates. A PHP cache prefix called EXPERIMENTS_HANDOFF_TOKENS_NAMESPACE was a critical hardcoded-key finding, because two credential rules accuse by the NAME of the identifier and never look at the value. A .astro file can never be in the RAG index, yet rag-first demanded the RAG had answered about that exact file. A tracked .gitignore was rewritten without asking. A provider CLI rejected the flag combination kj hands it, and those flags were a constant in the source. Every one had the same workaround: an escape variable that switches the whole protection off, then gets pasted on every command until nobody remembers what it silenced. So now, where kj cannot know, you declare it in your versioned config, where it gets reviewed like any other line: guards.output.non_secret_assignments, agents.<name>.task_args, board.unverifiable. And where kj can know, it computes the fact: kj rag covers <file> answers whether the index can hold that file at all, with a different remedy for each of four reasons.

v4.34.0 — a gate that blocks its own repair

Section titled “v4.34.0 — a gate that blocks its own repair”

Six gates blocked the one action that would have turned them green. The release check wanted the landing deployed and the guard treated that deploy as a publication, so the only way through was switching the whole gate off. board-sync refused the second half of a card after accepting that cards get split. The supervisor read its own development as tampering, and the command used to unblock it destroyed the seal that made unblocking unnecessary. A stray */ took the policy evaluator down and the guard denied Edit, Write and Bash at once, which is exactly what repairing the file needed. Now a gate distinguishes a command that consumes its red state from one that repairs it, always on a verifiable fact: an item declaring remedied_by, another open pull request for the card, a hash a human sealed, the file a diagnostic names. Where the fact is missing it still blocks, every lift is printed, and the Stop gate is untouched.

You choose who writes and who reviews, and until now that choice only held inside kj run. The panel now travels with the playbook every host reads at session start, and kj code invokes YOUR coder with the card, its criteria, the project boundary and what the RAG answers about the task. Underneath, the declared chain of models is finally connected: its schema had been in the config since February and nobody ever built the piece in between, while five agents each resolved a retired model silently and before anything you had declared. Now the agents return the failure, your chain decides, the provider default is its tail rather than a hidden first step, and an exhausted chain says what was tried and in what order. kj also remembers a retired model so the next run does not pay for it again, without editing your pin. And three field reports closed the other half: what kj writes into a project now speaks that project’s language, instead of telling a Python repo to prefer const.

v4.32.0 — you start without forcing anything

Section titled “v4.32.0 — you start without forcing anything”

kj bootstrap takes an empty directory to a project under the method in one command, in the order that works, and makes the contract commit itself instead of leaving you to fight the gates you just installed. kj doctor and kj check now look at the repository too, naming each symptom with the literal command that repairs it: a harness that governs nothing, a contract no clone would inherit, a clone with no declared identity. And the two proofs that were missing arrived: the project declares whether it actually runs, so a tree that was already broken is said BEFORE implementing rather than blamed on the next change, and what a person SEES stops being closed on a green suite — the walkthrough travels in the verdict next to the sonar and rag blocks, warning rather than blocking, because the browser misses native modals and a gate that fires often teaches people to skip gates.

Patch. kj privacy scan blocked every landing deploy over the Firebase web key the phone-signing page carries in the browser, a key that is public by design: it still blocks, because the shape alone cannot tell which Google key it is, but it now names the declared exit and what actually protects that key. The flaky runflow-events failure turned out not to be a timeout: with no coder transcript the leak detector flagged every new $HOME entry, so a write from another test killed the flow and retried it. Attribution and severity are now separate things. And the supervisor seal, stuck since 4.28.1 because its provenance recorded a raw path CI could not reproduce, was regenerated on 4.31.0 and landed — which immediately exposed the last piece: the release check was the one call site that never applied the provenance lift, so the first version cut after a seal was denied by that seal.

v4.31.0 — the cold start stops asking you to force it

Section titled “v4.31.0 — the cold start stops asking you to force it”

Starting a project from an empty directory used to end with the user choosing between forcing a gate and giving up. A field report (issue #1753) opened the map of the whole path: nine gates firing, several of them precisely because the repo had been raised by hand. Epic KJC-PCS-0088 makes the bootstrap a phase with rules of its own, defined by a verifiable fact (the repo has no commit) and ending at the first one. The Stop gate no longer demands coverage over a tree that does not exist, the contract commit passes because there is nothing to branch from, kj init creates the repository instead of skipping the harness and calling it done, an undeclared identity blocks the install rather than every later git call, kj hu add produces a reference the card gate accepts, rag-first stands down while nothing is indexed, and kj go starts in an empty folder. In the other direction, one hole closed: an absent harness now blocks the RAG gate instead of opening it, so not hardening stops being the comfortable way around it.

The session cannot touch what it never asked about (ADR 0010, epic KJC-PCS-0086). The Sentinel keeps a per-session ledger of every RAG query and the sources it returned, and refuses an edit of a source the session never asked about; kj review --staged refuses code the ledger does not cover before any reviewer token, hands the reviewer the twins the RAG returned that the diff does not touch, and stores a rag block in the verdict bound to the diff hash; kj review --check demands it, treating its mode as a claim, never an authorization. kj check fails on sources the index cannot see. The gate uncovered that Solomon’s approval dropped the Sonar and RAG evidence, refusing every arbitrated commit since 4.29.0: fixed. Also: kj audit reports env/config keys resolved with divergent rules across modules, verify-pack exercises the MCP server of the tarball over stdio, a parity test binds every MCP schema parameter to a handler that reads it, and two harness fixes (linked-install home, prettier-identical workflows).

Patch, reported minutes after 4.29.0 shipped (#1730): the postinstall re-registered karajan-mcp with a home inside the npm package (wiped on every reinstall, never where kj init keeps kj.config.yml), under the deprecated KJ_HOME name, and replaced the whole entry, so the user’s KARAJAN_HOME was lost and every MCP tool failed with Config file not found after each update. The home now resolves from KARAJAN_HOME, then what the entry already carried, then the instances registry, then ~/.karajan; the entry keeps every env key the user set, and both Claude and Codex configs write KARAJAN_HOME.

Minor where static analysis stops being discipline and becomes a git gate with the same teeth as the cross-AI verdict (KJC-TSK-0838, after a real case: four PRs reached main with sonarqube.enabled: false and nothing stopped them). The Sonar result now travels inside the verdict record, bound to the exact diff hash, and the pre-commit demands it; coverage is proved against the scanner’s own file index, so a staged source the scan did not see blocks. Sonar disabled, down or partial refuses any diff with code (docs-only passes), no env var lifts it, and the only exception is a human, expiring kj policy grant. Monorepos scan each file from its nearest sonar-project.properties; kj doctor flags enabled: false as a config defect; the method report says which verdicts are proved and which are not. Alongside it, three MCP fixes from the field the same week: the direct tools honour taskFile like kj_run (#1723), kjHome reaches the bootstrap gate and config loading on karajan-core 1.5.0 without touching the process env (#1722), and kj_rag_query scopes its search to the project instead of returning chunks of whatever else was indexed (#1713).

Patch: the environment stops leaving a mess behind. The pre-commit kj harden generates no longer self-detects as AI attribution on the bootstrap commit that versions the supervisor hooks (they CONTAIN the guard pattern by design; #1667). Verification no longer pollutes ~/.claude.json — the tarball’s postinstall was registering karajan-mcp at a throwaway /tmp install path, a CONNECTION_CLOSED MCP in every session; verify now runs with an isolated HOME (#1666). kj doctor gained a check that detects AND auto-repairs a dead karajan-mcp path. And the verdict store cleans itself: .karajan/reviews is garbage-collected opportunistically on every review, with kj review --prune for a manual sweep.

v4.28.1 — no scaffolding on an existing repo

Section titled “v4.28.1 — no scaffolding on an existing repo”

Patch: a headless coder run finished its real subtask, then derailed into inventing a “set up project structure” bootstrap (a rogue verify worktree, a generic multi-stack .gitignore). Two template-level guards close it — the Sentinel now denies raw git worktree add from a session (the sanctioned path is kj worktree start|done), and the coder prompt anchors scope: existing project, implement only the current HU, never scaffold or bootstrap.

Minor where the supervisor seal’s final layer becomes a signature from your phone (KJC-TSK-0822, the user’s chosen answer to «prove you cannot, ever»): a static signer page generates an Ed25519 keypair whose private half never leaves the phone; kj harden --commit paints a QR challenge, the phone shows in clear what is being sealed and one tap signs it, and kj verifies against the enrolled public key. With a phone enrolled the signature is mandatory — the key that approves a supervisor seal simply does not live on the machine the agent controls, verified end-to-end against production. Enrolling that key is itself a human act the session cannot perform. Alongside it, AI attribution is now forbidden by deterministic rules on every surface — commit content, PR body and title, and every gh command that publishes text — after a real catch where a harness default slipped attribution footers past a guard that only watched commit messages. And two session guards born from field reports: the Sentinel denies git worktree remove of the repo’s main tree outright (a derailed run had tried it in a loop), and enrolling the phone key is human-only. The one honest residual — verifying the signature in CI, server-side, so it never depends on kj running unpatched — is scoped for a follow-up.

Minor born from a user’s order worth framing: «I want to actually prove you CANNOT — not even if I order you to». The one operation the security class rightly denies even to the system’s author — versioning what kj harden regenerates of the supervisor — gains its sanctioned channel (ADR 0009): kj harden --commit is a human act. It computes the drift, writes tracked provenance (kj version, generation parameters, sha256 per file), seals the act in the hash-chained decision log, and commits surgically. The gates lift a supervisor diff ONLY when it matches the sealed provenance AND the canonical render kj recomputes — one manual comma stays denied, so even a successful forgery could never weaken the guards. And the “human” part was built adversarially, four layers deep: the Sentinel denies the command in-session (it self-proved by blocking its own author’s session, twice); no real terminal, no deal; a faked pty still DESCENDS from the agent’s process and /proc tells; and after an orphaned double-fork with blind-fed prompts genuinely broke through in the sandbox, a random nonce must be typed back on the process’s real controlling tty. Final battery: five attack classes, zero commits — with the honest residual documented rather than hidden.

Minor where the government explains itself and the board earns the user’s trust back. Exceptions gain a declared scope — project or global (whole machine) — with PHYSICAL provenance: the record’s origin is stamped from the store it was read from, so it cannot be forged by editing text; a global grant demands an expiry, security stays inexemptable in every scope, and kj policy report names each grant’s scope. Every Sentinel message now signs as karajan and links its own documentation: a new gate-by-gate page explains what each of the 12 gates protects and what every KJ_ALLOW_* escape means — a guardrail you don’t understand is one you end up disabling. And the HU-Board obeys two direct user orders: project names derive from the repo and are UNIQUE (a duplicate registers as a loud error, never a twin on the dashboard), and the nav splits into two honest levels — generic buttons on top, the loaded project’s views in their own bar with its name, no confusing project select. Plus the kj-managed CI workflows versioned (with a fail-loud fix caught by the cross-AI reviewer at the template level) and the LOC gate corrected for the monorepo’s built docs.

Minor where the muggle’s journey ends in ONE browser window. ADR 0008 was accepted and shipped the same day: kj go --window opens the board with the agent’s conversation living INSIDE it — not a lookalike chat, the agent’s REAL terminal (a pty bridged over a loopback-only WebSocket, rendered with xterm), so the harness stays exactly what the Sentinel guarantees: the process IS the interactive agent, hooks intact. The surface is closed by construction: agents come from a closed catalog (what travels is which agent, never a command), a single-session 128-bit token is handed out only behind the board’s auth, compared in constant time, and rides the WebSocket as a subprotocol — because URLs end up in logs and subprotocols do not. Closing the panel does not kill the session (reconnect replays the buffer); ending it does, cleanly. The terminal-plus-board of phase 1 remains the default — an addition, never a replacement. The board also learns that a project’s identity is its repo, not its path: worktree lanes no longer register the same repo as a dozen same-named projects. Released alongside its siblings kaRAGan 1.7.0 — Vertex migrated to the Google Gen AI SDK (the old one is past its removal date), environment fallbacks for region and model, and exclude globs that keep secrets out of the corpus before a single byte is read — and kaWATCHan 0.8.0, whose config now declares repo groups, DORA tiers and docs sensitivity rules, validated strictly. Both shaped by a real deployment’s field reports, down to a live probe against the real Vertex API from the instance that runs it in Europe.

Minor where Karajan opens the door to people who have never used a terminal. kj go: ONE command that detects the installed agent (Claude Code or Codex — it asks only when there are two), prepares the project silently the first time, opens the board alongside, and drops the person into a conversation that already follows the method — speaking plain language, saying before doing, never dumping a raw error. What cannot be hidden is said honestly: no agent installed gets the exact install and login commands, because the account is theirs and kj never touches credentials. The installers now finish with exactly one instruction — Listo. Ahora escribe: kj go — and the board kj go opens renders in maggle mode: columns Por hacer / En marcha / Hecho, the nav folded to Tablero | Proyectos | Más (with the way back to expert mode), a launcher that leads with «Pedir trabajo nuevo» and a clear promise of what will happen before it happens, activity without a terminal, and errors that always carry a plain headline and a next step — the stacktrace folded away as technical detail, never the whole message. A developer opening the board directly sees nothing change. The single window (the agent’s REAL terminal embedded in the board via pty, keeping the Sentinel’s hooks intact — an own chat over an SDK was evaluated and discarded precisely because it would trade the guaranteed harness for aesthetics) is proposed as ADR 0008: nothing is implemented until it is accepted. Plus the two fixes from GREBLA’s field-validation campaign: the phantom-E2E detector now sees interpolated labels — in Lit the usual case, not the exception — and a phantom finding points at the TEST file and line, with the dead chunk riding apart as sourceLine.

Minor where Karajan learns to govern the STATE of a project, not just its acts — because decay happens precisely on the days nobody looks. The Karajan Steward ships whole: every declared guarantee answers ONE of four verdicts — ok, broken, unknown (the evidence expired → refresh) and not observable (there was never anywhere to look → instrument), the two honest answers whose absence let a real project degrade for weeks behind a green facade. kj steward sweep leaves the verdict versioned IN the repo (shared memory, never one machine’s record), seals every sweep in the hash-chained decision log, and cards each break as PROPOSED work — evidence, since-when, and a remedy plan that nothing executes unreviewed; the Sentinel says what is broken at the start of work, once per session and impossible to miss, and blocks almost never (only security and persistent red main, only where the project opted in). Phantom coverage gets its two detectors — a call graph for unit tests and LITERAL crossing for E2E, the case a graph cannot see: a spec looking for an aria-label that only existed inside an unreachable method. The whole credibility epic lands with it: member reachability inside a field-validated perimeter with static/instance slots and constructor fields, dead-code reports leading with the DERIVATIVE, delete-only diffs owing no test, sonar vetoing only the lines a PR adds, generated budgets ignoring lockfiles, and a privacy scan that knows a git SHA is not a phone number. Claims-with-evidence reaches written artifacts: a PR body with a datum denied by its own source is refused before the PR exists. Plus an external security contribution — the HU Board token compared in constant time (thank you, @ofri-peretz) — and three field fixes: the Sonar scanner now respects the repo’s own sonar-project.properties, kj board no longer starts a server the config said to keep off, and Windows paths reach ~/.codex/config.toml as valid TOML.

Minor where the family gains its most privileged piece and the method learns to doubt the AI itself. The Karajan Console is born (@karajan-family/console, shipped 0.1.0 → 0.3.0 during this cycle): the admin web console of a family instance — corpus health, people’s access as the service’s real IAM binding, operations as GitHub App workflow runs, all sealed in a hash-chained audit trail, with a no-build static page and two identity providers: Google Sign-In, or Identity-Aware Proxy fully provisioned by terraform — and the console verifies the assertion even behind IAP, because a second layer that trusts the first is decoration. Driven by a real instance from day one: its field reports fixed a concurrency race in the audit chain and shaped the deployment notes. And claims with evidence (accepted ADR): the transcript is the register of sources, kj claims check crosses every hard datum the AI states against what actually ran — backed, unbacked, or denied by its own source, which is a proven hallucination. Plus a guard for a bug JavaScript refuses to report (a class member declared twice: the last one wins in silence — 17 days of an empty tab in production at a real instance), the kj review verdict parser fixed at the path it actually walks, two same-day fixes for a Windows field reporter, a shell-injection hole closed in a reusable workflow, and this repo’s own actions pinned to commit SHAs — what kj generates was already pinned; what kj is had not caught up.

Minor where two rules stop living in the agent’s memory and become gates. Identity lock: every clone declares who works it (kj identity set — gh account + git email, per developer, never tracked; the next kj harden asks, with a human confirming), and the Sentinel refuses gh, git push and any commit-authoring git command under another account BEFORE it runs — authorship resolved by git var under the command’s own environment, wrapper shells and substitutions scanned inside, never an auto-switch. Born from a real incident: one gh call without an explicit switch posted as a client account on a public repo. Board-sync gate: a merged card must be moved in the tracker before anything advances — the Sentinel leaves the branch’s card pending on a verified merge and refuses commit, push, new PR, another merge and the end of the turn until the REAL tracker call clears it (update_card via MCP or kj hu move). It found three production gaps in its first hour and governed the card of its own creation on its first real merge. Plus v4.20.1’s field fix: kj start finally sees the project it is standing in.

Minor born from one field project (a kubernetes demo with its code under backend/): the method was language-agnostic on paper, but three concrete pieces still assumed application code — now the Sentinel counts terraform/k8s/shell/Docker edits as sources (card-first, Stop gate and push gate fire exactly like on a .js), infra has real suites (terraform validate, helm lint, kustomize build, ansible-lint, with checkov chained as the additive deep scan — a missing tool is declared with its install command, never a fake green), and kj audit --security runs checkov through the same best-effort channel as semgrep, because misconfigs ARE security surface. Plus three fixes reported from the field and shipped within hours: codex exec lost --full-auto upstream (now --sandbox workspace-write with a legacy retry), kj start passed the Claude-only haiku to agy (models now filter by provider FAMILY at the chokepoint), and the Sentinel’s own escape hatch existed only in its error message — every KJ_ALLOW_X=1 prefix now works on a simple command, fail-closed on chains, proven the same night it deadlocked its author’s release.

Minor where the method stops trusting a green suite at face value: the mutation pre-gate joins the review — a suite can pass with weak asserts, and surviving mutants prove it. Opt-in (method_gates.mutation: warn|block, it never runs undeclared) and staged-only: warn ships survivors as an advisory inside the reviewer’s task, block rejects BEFORE spending a reviewer token, listing each survivor with its remediation. kj doctor now declares its guarantee level per host — the coupling to Claude Code is not a bug, it is a DISCLOSED gradient: tier A tool-time needs the Sentinel’s synchronous hooks, tier B commit-time git gates are the floor on ANY host, tier C re-checks in CI; run kj from codex or gemini and it tells you exactly which guarantees you kept. A week of field findings lands fixed: kj start no longer calls an infra project empty (nested backend/app/… code and yaml/tf/sh/Dockerfile now count as source), kj agents --help enumerates its real roles and providers self-fed from the constants, and the lane guard learned what a quote pair is after gating its own author. And the family migration turns real: @karajan-family/code ships the same bits as karajan-code — the first dual-publish under the family scope.

Minor where governance stops being a feature of kj and becomes a PACKAGE: @karajan-family/governance ships on npm — Policy, Decision and Exception as first-class abstract objects (deterministic, local, no LLM), with karajan-code as its first consumer, not its owner. The policy layer completes its three tiers: rules fire BEFORE the damage at tool time (with the acting agent’s role), the violating diff never enters at commit time, and CI re-checks the PR against the same policy — covering even a tampered local hook. Exceptions carry the full evidentiary model: who (identity), the exact rule, a justification written at the moment, and a MANDATORY expiry the system executes — an expired exception blocks again on its own, and a rule granted three times gets told to its face that it is no longer an exception but the real policy asking to be changed. Every chokepoint decision leaves a hash-chained, git-anchored trail: rewriting yesterday’s log requires rewriting yesterday’s repo. Plus kj policy add: speak the rule, the engine validates it, nothing lands without your confirmation.

Minor where the whole Karajan family moves under one roof: radar, rag, watch and the landing itself merge into the monorepo with their FULL histories (rewritten under each package path — git log packages/rag tells the whole story; source repos stay frozen as immutable references, and every imported authorship signs the noreply address). The safety prerequisite shipped first: lane isolation — each session mutates only ITS worktree, enforced by the Sentinel’s PreToolUse gate before the damage, with an audited escape (two sessions colliding on one tree was a real incident, never again). And the third pillar: policy as code — .karajan/policy.yml declares per-role rules in a closed, fail-loud vocabulary (a rule the engine cannot enforce is a load error, never a silently dead rule) and kj policy check/eval evaluate them deterministically in warn mode; the deny wiring arrives next. Proof of the roof: this very release updated its landing in the same repository, same PR — the release→landing delegation dance is dead.