Other stacks
Same recipe, different bootstrap: Node CLI · Web Component · REST API (Node) · Java · Go · Rust
Python · Estimated time: ~12 min · Karajan iterations: 1–3
This walkthrough takes you from an empty directory to a merged feature on a small Python project (CLI / library / data script). 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.
You’ll also need Python 3.10+ on PATH (python --version). On macOS we recommend pyenv; on Linux use the distro package; on Windows use the official installer with “Add to PATH” checked.
Bootstrap the project.
mkdir hello-py && cd hello-pypython -m venv .venvsource .venv/bin/activate # Windows: .venv\Scripts\activatepip install --upgrade pippip install pytestgit init -b main && git add -A && git commit -m "chore: scaffold"Create a minimal pyproject.toml so Karajan’s tester knows how to invoke pytest:
[project]name = "hello-py"version = "0.0.1"requires-python = ">=3.10"
[tool.pytest.ini_options]testpaths = ["tests"]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. kj doctor also detects your Python version and registers it in the project profile.
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)' function in src/hello.py that returns \'Hello, <name>!'. Add a pytest test in tests/test_hello.py that imports \the function and asserts the output 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 --statpytestExpected output of pytest:
============================= test session starts ==============================collected 1 item
tests/test_hello.py . [100%]
============================== 1 passed in 0.02s ===============================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-functiongit add -A && git commit -m "feat: add greet(name) function"git push -u origin feat/greet-functiongh 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)' function in src/hello.py that returns 'Hello, <name>!'. Add a pytest 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. Semgrep ships with a Python ruleset out of the box.
For a notebook-heavy or data project, swap the test runner and bump iterations:
kj run "<task>" \ --coder claude \ --reviewer codex \ --max-iterations 8--max-iterations is bumped because data validation loops (numpy / pandas / pytest fixtures) tend to need an extra pass.
Other stacks
Same recipe, different bootstrap: Node CLI · Web Component · REST API (Node) · Java · Go · Rust
Back to the index
How-To index · setup + troubleshooting