Skip to main content

joust

Parallel prototype orchestrator for coding agents.

Splits one vague feature request into N variants, implements each in an isolated git worktree, lets an agent judge them against a rubric, and gates the final pick on a human.

Joust is in the same family as proctor and magellan: a tool whose --help text is the agent's onboarding. Joust never calls an LLM itself. It manages state, worktrees, and prompts; an agent runner (Claude Code, Codex, or a shell script) does the thinking.

Install

As a Claude Code plugin (recommended)

/plugin marketplace add nclandrei/joust
/plugin install joust@joust

The plugin puts joust on PATH automatically at session start. See docs/plugin.md for the full guide.

As a standalone CLI

uv tool install joust      # or: pipx install joust

Or from a clone for local development:

git clone https://github.com/nclandrei/joust.git
cd joust
uv venv
uv pip install -e .

Then joust --version and joust --help to get started.

Configuration

Joust state lives under $JOUST_HOME (default: ~/.joust/). Set the env var to relocate state — useful in CI or when running multiple joust instances:

export JOUST_HOME=/tmp/joust-ephemeral
joust init demo --goal "..."

There is no other configuration file: every other knob (rubric, runner, model, base ref) is set per-run via joust init/joust runner set.

Shell completion (after install):

joust completion bash >> ~/.bashrc
joust completion zsh  >> ~/.zshrc
joust completion fish >  ~/.config/fish/completions/joust.fish

Platform support

macOS and Linux. Joust uses POSIX file locking (fcntl) so Windows is not supported — try WSL.

The workflow

joust init <slug> --goal "what you are exploring"
joust scenarios suggest --count 3      # prints a brainstorming playbook
joust scenarios add minimal   -d "..."
joust scenarios add power     -d "..."
joust scenarios add opinionated -d "..."
joust runner suggest                   # asks agent to ask user which model
joust runner set --runner claude-code --model opus
joust scenarios approve --yes          # HUMAN gate: approve the scenario set
joust lock                             # materializes N git worktrees
# --- dispatch one subagent per worktree ---
joust record variant-01 --status built --summary "..."
joust record variant-02 --status built --summary "..."
joust record variant-03 --status failed --summary "..."
joust judge                            # prints a judging playbook
joust score variant-01 --correctness 4 --simplicity 5 --fit 5 --extensibility 2 --rationale "..."
joust score variant-02 ...
joust score variant-03 ...
joust compare                          # comparison table
joust diff variant-01                  # files/lines changed in this variant
joust pick variant-01 --yes            # human-only gate
joust merge --yes                      # merge picked variant into the base branch
joust archive --prune                  # clean up losing branches

At any point, joust log prints the append-only event timeline for the active run (joust log --json for machine-readable output, joust log --last 10 for the most recent events).

For a full walkthrough with realistic output at every step, see docs/examples/first-run.md — three rate-limit variants on a Flask endpoint with a custom rubric.

Design principles (borrowed from proctor/magellan)

  1. --help is the onboarding. A fresh agent runs joust --help and joust <cmd> --help and can complete a run without reading source.

  2. No LLM calls. Joust emits static playbooks for brainstorming and judging; the calling agent reads them and acts. That keeps joust deterministic, testable, and model-agnostic.

  3. Contract-first, append-only state. Every run has a manifest.json plus an events.jsonl log. Nothing is mutated in place.

  4. Two human gates. joust scenarios approve --yes sits between brainstorming and worktree creation (so the agent cannot silently lock a run with scenarios it made up). joust pick --yes sits between judging and merging (so the agent cannot silently declare a winner). Both refuse to run without --yes.

  5. Runner is recorded, not assumed. joust runner suggest prints a playbook telling the agent to ask the user which model to dispatch subagents as (e.g. opus / sonnet / haiku). The answer is recorded with joust runner set and shows up in every variant's PROMPT.md. Joust itself never spawns a subagent — the driver does, using the recorded model.

State layout

$JOUST_HOME/                             # default: ~/.joust
  active.json                            # repo_path -> {slug, run_id}
  runs/
    <slug>/
      <run-id>/
        manifest.json
        events.jsonl
        worktrees/
          variant-01/                    # git worktree + PROMPT.md
          variant-02/
          variant-03/
        artifacts/
          variant-01/                    # files copied by `joust record --artifact`

Each variant lives on a branch named joust/<run-id>/<variant-id>, rooted at the SHA of the base ref captured at joust init time.

How to drive it from Claude Code

The simplest usage is a one-paragraph skill:

Read joust --help, then joust scenarios suggest --help. Propose scenarios and register them. Run joust lock. Then spawn one subagent per worktree (use the Agent tool with isolation: "worktree" pointing at each worktree path). Each subagent's prompt is the worktree's PROMPT.md. When they finish, they call joust record. Then call joust judge, fill in scores with joust score, and run joust compare. Stop and ask the human to run joust pick.

Joust stays out of the model layer entirely — it just gives the agent a structured, inspectable place to put its work.

Composition with proctor

If a variant is a UI or end-to-end feature, run proctor inside its worktree to capture manual-test evidence. joust owns "which variant wins"; proctor owns "does this variant actually work". The two are orthogonal.

Housekeeping

  • joust diff <variant> — shows a short-stat diff for the variant's branch against the base, plus the list of changed files. Useful during judging to see at a glance which variant touched what.
  • joust log — prints the append-only event timeline for the active run (init, scenario_add, approve, lock, record, score, pick, merge, archive). Supports --json and --last N.
  • joust merge --yes — merges the picked variant's branch back into the base branch. Takes no positional argument; the winner is read from manifest.picked (set by joust pick). Refuses unless a variant has been picked, --yes is passed, and the base branch hasn't moved past the SHA recorded at joust init (use --force to override the drift check).
  • joust doctor — diagnoses drift between joust state, git's view of worktrees/branches, and the filesystem. Detects stale active pointers (when the run dir has been rm -rfd), missing variant worktrees, and orphan joust/<run-id>/variant-* branches left over from aborted runs. Run joust doctor --fix to clean them up.
  • joust runs — lists every run for the current repo.
  • joust use <slug> <run-id> — switches which run is active in the current repo.
  • joust report — prints filesystem paths for the active run's manifest, events log, and worktrees.
  • joust --version / -V — prints the installed joust version and exits.

Testing

uv pip install -e ".[dev]"
pytest tests/

The smoke test exercises the full pipeline end-to-end against a throwaway git repo and asserts final manifest + events state.

Status

v1.0 — stable, public, installable three ways: Claude Code plugin, PyPI, or from a clone. 44 tests pass across Python 3.11/3.12/3.13 on macOS and Linux in CI.

Milestones reached:

  • v0.2.0 — repo public, PyPI release, CI on push/PR. ✅
  • v0.3.0 — customizable rubric (joust init --rubric ...), richer scenarios suggest playbook that surfaces prior runs, and a full walkthrough at docs/examples/first-run.md. ✅
  • v1.0.0 — Claude Code plugin under plugin/ that puts joust on PATH at session start. See docs/plugin.md. ✅

See docs/superpowers/specs/ for the design.

Metadata

Release files for joust 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for joust 1.1.0
File Size Uploaded
joust-1.1.0.tar.gz 69.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for joust 1.1.0
File Interpreter ABI Platform
joust-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 104.0 kB

Release files / joust-1.1.0.tar.gz

Download URL joust-1.1.0.tar.gz
Size 69.5 kB
Tags Source
SHA-256 checksum
How to use checksums
48b4850c1575085999ec8743939d5aa3dfaaa37c93a51d1e861fa8e1744d296e
BLAKE2b-256 checksum
How to use checksums
2b24bd8df40687d8c2619724345a2d8dcd6d4198adfa098537b3cc0c8032d454
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 25, 2026.

Transparency log

Release files / joust-1.1.0-py3-none-any.whl

Download URL joust-1.1.0-py3-none-any.whl
Size 34.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f6313c4f924ac904ab9f4083e1a939e5303ded1fdb850159efdd662a327702ac
BLAKE2b-256 checksum
How to use checksums
b7cb4eb4bffcdb50226d9590292b5b2619e8ee9744b83ce7335d031aa7ea862d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page