Skip to content

Maintenance commands

These eight commands aren’t part of the build pipeline — they’re the housekeeping around it: inspect the config, watch a run, read the post-mortem, resume a paused session, undo a run, detect plan drift, garbage-collect old state, update Karajan itself. Each is small enough that a full page would be padding; collected here, they share one mental model.

Each section uses a compact shape: what it does, when to reach for it, the options, and the reasoning where it isn’t obvious.


What it does: Prints the effective karajan.config.yml (global layered with project-local) — the actual values a run will use, not just the file. --json for tooling; --edit opens it in $EDITOR.

When to use: Confirm what a run will do before running it (“which provider is the reviewer right now?”); make a one-value change without the kj init wizard (kj config --edit).

When not: Changing a role’s provider is clearer via kj agents set (typed + validated) than hand-editing YAML. Full first-time setup is kj init.

FlagDefaultWhen to flip it
--jsonoffProgrammatic consumption / diffing config across machines.
--editoffOpen the config in $EDITOR for a hand edit.

Reasoning: kj config shows the resolved config, not the raw file, because the value that bites you is the effective one after global+project layering — a raw-file viewer would hide exactly the merge that causes “why is it using Codex here?“.


What it does: Shows the live pipeline dashboard for the current/last run — current stage, HU progress, recent log lines. -n controls how many log lines.

When to use: A kj run is working and you want a quick textual pulse without opening the board; checking where a long run is stuck.

When not: Multi-HU visual tracking is the HU Board. Post-run metrics (tokens, timings) are kj report, not kj status.

FlagDefaultWhen to flip it
-n, --lines <n>50Raise for more log context on a stuck stage; lower for a terse pulse.

Reasoning: status is the headless-friendly counterpart to the board — same underlying run-log reader, no web server, so it works over SSH or in a tmux pane where opening :4000 isn’t an option.


What it does: Prints the report for the latest session (or --session-id): stages, timings, token usage, cost, decisions. --trace gives the chronological stage-by-stage breakdown; --list enumerates session ids; --pg-task filters by Planning Game card.

When to use: Post-mortem of a finished run — “where did the time/tokens go?”; comparing two runs’ cost; auditing what Solomon decided and why.

When not: Live progress is kj status / the board. report is retrospective; it doesn’t tail an in-flight run.

FlagDefaultWhen to flip it
--listoffEnumerate session ids to pick one.
--session-id <id>latestReport on a specific past session.
--format <text|json>textjson for tooling.
--traceoffChronological stage-by-stage trace with per-stage timing/tokens.
--currency <usd|eur>usdDisplay cost in the other currency.
--pg-task <cardId>noneFilter reports to one Planning Game card.

Reasoning: --trace exists because an aggregate (“12 min, 400k tokens”) doesn’t tell you which stage was expensive; the chronological breakdown is what turns a report from a number into a diagnosis.


What it does: Resumes a session paused by Solomon (a question that blocked the run) with kj resume <sessionId> --answer "<text>".

When to use: A run paused asking for a decision; you supply it and the run continues from the pause.

When not: A session frozen by quota exhaustion is a different recovery path — kj standby resume, not kj resume. The split is deliberate (decision-wait vs time-wait); see the kj standby reasoning.

FlagDefaultWhen to flip it
--answer <text>noneThe decision that unblocks the pause. The whole point of the command.
--jsonoffScripted resumption.

Reasoning: Paused ≠ failed. A run that needs a human decision shouldn’t discard its accumulated context waiting for one — kj resume re-enters exactly at the pause with the answer injected, the same “the work isn’t wasted” principle behind kj standby.


What it does: Reverts the last pipeline run. Soft by default (resets to the pre-run commit, keeps changes staged so you can inspect them); --hard discards them entirely.

When to use: A kj run produced something you don’t want; kj undo to get back to the pre-run state. Soft to review what it did first, --hard when you’re sure it’s garbage.

When not: Reverting a specific old run isn’t this — undo targets the last run. For older history, use git directly.

FlagDefaultWhen to flip it
--hardoff (soft reset)Discard all changes from the last run with no review. Irreversible — be sure.

Reasoning: The default is soft because the common case after a bad run is “what did it actually do?” — destroying the diff before you can read it is the wrong default. --hard is the explicit “I’ve seen enough” opt-in.


What it does: Read-only drift detection between the code and the latest plan (or --plan <id>). Reports where the implementation diverged from what the plan said; changes nothing.

When to use: After hand-edits between plan runs, to see if the code still matches the plan; before resuming a --plan run that’s been paused for a while.

When not: It doesn’t fix drift, only reports it. To re-align, feed the findings into kj run or update the plan (kj plan fix).

FlagDefaultWhen to flip it
--plan <planId>latestDiff against a specific plan instead of the most recent.
--jsonoffCI drift gate.

Reasoning: Drift is silent until it bites mid-run; a read-only detector you can run cheaply (no LLM) turns “the plan and the code disagree” into something you find on purpose, not by surprise three HUs in.


What it does: Garbage-collects stale plans, sessions and HU batches. Dry-run by default — prints what would be removed; --yes actually deletes. Retention windows are tunable; --nuke is the scorched-earth option.

When to use: ~/.karajan accumulated cruft after heavy dogfooding; periodic housekeeping. Always run it once without --yes first to see the blast radius.

When not: Removing one specific plan is kj plan delete; cleaning the board’s batches specifically is kj board cleanup. kj clean is the broad GC across all state.

FlagDefaultWhen to flip it
--yesoff (dry-run)Actually delete. Without it, nothing is removed.
--nukeoffRetention=0 everywhere + wipe the HU board DB. “I want it all gone.”
--plan-days <n>30Keep finalised plans longer/shorter.
--draft-days <n>60Retention for draft plans.
--session-days <n>7Retention for finalised sessions.
--hu-days <n>14Retention for HU story batches.

Reasoning: Dry-run-by-default is the load-bearing decision: a GC that deletes on first invocation is a footgun, so kj clean makes you see the list before --yes makes it real — the same “safe by default, destruction is opt-in” rule as kj undo --hard.


What it does: Updates Karajan itself to the latest version from npm.

When to use: A new release is out and you want it. (In repos where kj is linked to a working copy, you don’t — you consume the source tree directly.)

When not: Don’t kj update a checkout you’re developing against; it’s for npm-installed Karajan, not a linked dev copy.

No flags.

Reasoning: It’s a thin convenience wrapper over the npm install so “update Karajan” is one obvious command rather than something you have to remember the package name for.


  • kj run — the pipeline all of these orbit.
  • kj plankj sync diffs against it; kj plan delete is the targeted version of kj clean.
  • kj board — visual counterpart to kj status; kj board cleanup is the targeted version of kj clean.
  • kj standby — quota-freeze recovery; the counterpart to kj resume’s pause recovery.
  • kj agents — the typed way to change what kj config --edit would hand-edit.