Skip to content

kj triage

kj triage answers “how big is this task, and which roles should run for it?” without running anything. It’s the classification kj run performs internally to decide what to enable — surfaced so you can see (and sanity-check) the decision before committing to a run.

kj triage takes a task description and returns a complexity classification (trivial / simple / medium / complex), the inferred task type (sw / infra / doc / add-tests / refactor), and a recommended set of pipeline roles to activate for it — plus, for larger tasks, a suggested decomposition. It’s a single fast LLM call; it writes nothing and runs no coder.

This is the same logic kj run uses when --enable-triage is on (or --auto-simplify is collapsing the pipeline for a trivial task). Running it standalone lets you preview “would Karajan think this is a one-liner or a six-HU epic?” and decide whether to plan, simplify, or just run.

Output is human-readable by default, --json for tooling.

  • Sizing before committingkj triage "<task>" to decide plan-first vs run-directly.
  • Sanity-checking auto-simplify — confirm Karajan won’t downgrade a task you consider risky.
  • CI routing--json to branch a pipeline: trivial → kj code, complex → kj plan + kj run.
  • Estimating role cost — see which roles a task would pull in before paying for them.
  • You’re going to run it anywaykj run triages internally; a separate call is redundant latency unless you need the decision before running.
  • The task is obviously trivial or obviously huge — you don’t need a classifier to tell you a typo is trivial.
  • You want gap analysis, not sizing — that’s kj discover; triage sizes, discover finds what’s missing.
FlagDefaultWhen to flip itInteraction
[task] (arg)The task to classify. Required unless --task-file.
--task-file <path>noneLong task / spec file.Supersedes the inline [task].
--triage <name>configOverride the triage agent.
--triage-model <name>tier-drivenPin the triage model — usually a cheap/fast one is fine.
--jsonoffCI routing / tooling.
Terminal window
kj triage "Add CSV export to the reports page"

What happens: returns e.g. simple, type sw, recommended roles coder, reviewer, sonar — telling you this doesn’t need planner/architect. Run it directly.

Terminal window
level=$(kj triage --task-file task.md --json | jq -r .level)
[ "$level" = complex ] && kj plan --task-file task.md || kj run --task-file task.md

What happens: the pipeline plans complex tasks and runs simple ones directly, driven by the classification.

Terminal window
kj triage "Migrate auth to JWT with refresh rotation"

What happens: likely complex, recommends planner + security + tester — confirming a --mode paranoid run is warranted, not overkill.

kj triage is the routing brain of kj run made inspectable. The design reason it exists standalone: pipeline shape is a decision, and decisions the tool makes invisibly are decisions users can’t trust or override intelligently. By exposing the classifier, “why did Karajan skip the reviewer on that task?” becomes answerable before the run, not archaeology after it. It’s intentionally one cheap call — triage’s job is to be a fast cost-saver (don’t run six roles on a typo), so a triage that was itself expensive would defeat its purpose.

The classification feeds two kj run behaviours that look opposite but share this engine: --auto-simplify uses a low complexity verdict to strip roles out, and --mode paranoid / --enable-* use a high one to justify adding them. Both are the same question — “what does this task actually need?” — which is why triage returns recommended roles, not just a size label: the size alone doesn’t tell you what to do, the role recommendation does.

  • kj run--enable-triage runs this inside the pipeline; --auto-simplify acts on its verdict.
  • kj discover — complementary: finds gaps/ambiguities rather than sizing.
  • kj plan — what triage recommends for complex tasks.
  • Pipeline roles → triage — the role this command runs standalone.