Other stacks
Same recipe, different bootstrap: Python · Web Component · REST API (Node) · Java · Go · Rust
Recommended · Estimated time: ~10 min · Karajan iterations: 1–2
This walkthrough takes you from an empty directory to a merged feature on a small Node CLI project. The recipe is deliberately minimal so you can re-run it on a real codebase by swapping the bootstrap step for cd <your-repo>.
You should already have done the common setup: npm install -g karajan-code, kj init inside the project, and a green kj doctor. If kj doctor is red, fix that first — kj run will refuse to start otherwise.
Bootstrap the project.
mkdir hello-cli && cd hello-clinpm init -ynpm install --save-dev vitestgit init -b main && git add -A && git commit -m "chore: scaffold"Edit package.json so the test runner is wired up:
{ "type": "module", "scripts": { "test": "vitest run" }}Initialize Karajan in the repo.
kj initkj doctorkj init creates .karajan/ and writes the orchestrator config; kj doctor confirms the agent CLIs, Docker, Ollama, and ports are all healthy.
Describe the feature in natural language.
No spec file. No JSON. Just the task as you’d describe it to a colleague:
kj run "Add a 'greet <name>' command to bin/cli.js that prints \'Hello, <name>!'. Add a Vitest test that runs the CLI via execa \and asserts the stdout for the name 'world'." \ --methodology tdd \ --coder claude \ --reviewer codex \ --reviewer-fallback claude \ --max-iterations 5Watch the run on the HU Board.
Open http://localhost:4000 in another tab while the pipeline runs. You’ll see, in real time:
You can also tail the same trace in the terminal:
kj tailInspect the result.
git statusgit diff --statnpm testExpected output of npm test:
✓ tests/cli.test.js (1) ✓ greets the given name (42ms)
Test Files 1 passed (1) Tests 1 passed (1)Merge.
Karajan does not push or merge for you by default — that’s your call. When you’re happy with the diff:
git checkout -b feat/greet-commandgit add -A && git commit -m "feat(cli): add greet <name> command"git push -u origin feat/greet-commandgh pr create --fillOr, if you want Karajan to also open the PR for you, add --auto-commit --auto-pr to the kj run invocation.
The same run launched via the MCP from any MCP-capable client (Cursor, Claude Desktop, Codex):
{ "tool": "kj_run", "params": { "task": "Add a 'greet <name>' command to bin/cli.js that prints 'Hello, <name>!'. Add a Vitest test.", "methodology": "tdd", "coder": "claude", "reviewer": "codex", "reviewerFallback": "claude", "maxIterations": 5 }}Add --mode strict and the deterministic security collectors:
kj run "<task>" \ --mode strict \ --enable-security \ --enable-sonarcloud \ --methodology tddThis wires the OSV-Scanner and Semgrep collectors into the audit, and gates the merge on the Sonar quality gate as well as the reviewer verdict.
For air-gapped or budget-constrained runs, swap the coder to OpenCode with a local model:
kj run "<task>" \ --coder opencode \ --coder-model gemma-local/coder \ --reviewer claude \ --max-iterations 8--max-iterations is bumped because local models tend to need an extra loop or two.
Other stacks
Same recipe, different bootstrap: Python · Web Component · REST API (Node) · Java · Go · Rust
Back to the index
How-To index · setup + troubleshooting