Metadata-Version: 2.4
Name: marauders-mischief
Version: 0.18.0
Summary: An AI-native dev harness. Solemnly swear you're up to no good.
Project-URL: Homepage, https://github.com/sindreespeland/marauders-mischief
Project-URL: Repository, https://github.com/sindreespeland/marauders-mischief
Project-URL: Issues, https://github.com/sindreespeland/marauders-mischief/issues
Author-email: Sindre Espeland <sindre.espeland2001@gmail.com>
License: MIT
License-File: LICENSE
Keywords: agents,ai,claude-code,dev-tools,harness,workflow
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.12
Requires-Dist: jinja2>=3.1.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0.0
Requires-Dist: typer>=0.12.0
Description-Content-Type: text/markdown

# marauders-mischief

> An AI-native dev harness. Solemnly swear you're up to no good.

A workflow for [Claude Code](https://claude.com/claude-code) that makes a coding agent behave like an engineering team instead of a single overcaffeinated junior.

## Why

If you've used a coding agent for more than half an hour, you've watched it do at least one of these:

- Delete the failing test to make the suite green.
- Confidently report "feature shipped" when the feature doesn't work.
- Refactor while you asked it to fix a bug, breaking three other things on the way.
- Lose its mind around the second hour of a long task and forget what you asked for.
- Run overnight in autonomous mode and commit garbage to `main` while you slept.

Agents are very good at writing code. They are very bad at the parts of engineering that aren't writing code: planning, peer review, knowing when to stop, knowing when to ask. Most setups paper over that gap by just letting it happen and hoping for the best.

`mar` is the setup that doesn't. It splits each task into the stages a real team uses (research, plan, build, test, review, integrate), runs each stage in a fresh-context sub-agent that hasn't been defending its own previous choices, and enforces the boundaries mechanically. Not by asking nicely.

## What it does

For every task you give it:

1. **Research** — pulls together what you need to know about the problem (the codebase, the libraries, the prior art). Surfaces options; doesn't decide.
2. **Plan** — an author writes the plan. A skeptic in a fresh context tries to break it. They reconcile, or you do.
3. **Execute** — small steps, fresh agent per step, no accumulated context drift.
4. **Test** — multiple test kinds in parallel: unit, eval, agent-flow, browser, perf. The orchestrator picks which apply to what changed.
5. **Refine** — when something fails, the fix goes in the code. Not in the test. A PreToolUse hook physically blocks the agent from writing to `tests/`, fixtures, snapshots, or eval data.
6. **Simplify** — a cleanup pass. Same author/skeptic pattern. Reverts itself if cleanup regresses anything.
7. **Verify** — a structured pre-PR adherence check. Classifies failures by who should fix them (refine / replan / user) instead of bouncing everything back to refine.
8. **Review + Tester** — fresh-context PR review (inline comments on the actual PR) and functional validation (does the feature work for a user?), in parallel. Optionally a second reviewer from a different model entirely (Codex/GPT) — the surest way to catch what a reviewer trained like your builder would wave straight through.
9. **Integrate** — squash merge with the commit story you approved in step 2.

Every stage runs as a fresh sub-agent. None of them inherit the running history. The only thing that persists between stages is **files**: `plan.md`, `test-report.md`, `verification.md`. Context-as-files, not context-as-tokens. The plan, not the chat log, is the source of truth.

## What it stops

| Failure mode | What stops it |
|---|---|
| Agent weakens a failing test instead of fixing the code | `tests/`, fixtures, snapshots, eval data are write-blocked during refine via the scope hook |
| A refine cycle introduces new failures while patching old ones | Each round is checkpointed; new failures auto-revert and escalate via the `refine-regression-wall` safeguard |
| Plan and shipped reality drift apart | Verify runs 5 mechanical pre-checks (diff vs scope, unresolved questions, unchecked manual steps, deviations triage, plan-quality) before reasoning, with structured evidence required for every adherence claim |
| Long agents lose track of state | Each build step is a fresh sub-agent reading the previous step's handoff file |
| Autonomous mode ships broken work silently | 15+ always-on safeguards pause autonomous sessions on every known silent-failure mode |
| Agent self-grades and rubber-stamps its own work | Author/skeptic split at design-time stages (research, plan, simplify); fresh-context review at Stage 5 |
| Long-lived branches diverge and produce merge nightmares | One phase, one branch, one PR. Squash-merged at integrate. Phases run sequentially |

## Autonomy modes

Pick how much you want to be in the loop:

- **`interactive`** — every gate pauses for your approval.
- **`normal`** — gates pause for important things; routine stuff auto-passes.
- **`streamlined`** — auto-passes if no issues; gates only when something needs you.
- **`autonomous`** — runs end-to-end. You provide no input after `/mar:session-start` until the session finishes or a safeguard pauses it.

All four modes use the same safeguards. Autonomous is allowed to be unattended because the safeguards make it safe to be unattended, not because nobody's looking.

## Programs — when the build is bigger than one session

One session, one task. Fine for a bug or a feature. But a whole app is dozens of sessions over weeks, and every session starts amnesiac — session 12 has no idea what contract session 2 agreed to. That's how greenfield builds rot: each session quietly re-decides settled things, and three weeks in, nothing agrees with anything.

A **program** is the memory that outlives the session. You birth one once with `/mar:program-start` — a visionary and a skeptic argue out the shape of the thing while you call the shots — and it lays down a **spine**: the charter, the invariants you won't trade away, the contracts between the pieces. After that, every session is a **slice**. It reads the spine before it plans, builds against it, and writes back what it learned at integrate. Decisions compound instead of evaporating.

The map stays yours to draw. Births and big pivots are human calls — the agents fill in the territory, they don't redraw it. When the thing stands on its own two feet, `/mar:program-graduate` rolls up the spine and sends it on its way.

Today it runs one slice at a time, in order. The spine is there to keep a long build *honest*, not fast — parallelism across a program comes later.

**YOLO mode (`/mar:program-yolo`) — fully autonomous, from a PRD.** Hand it one north-star spec and nothing else: it births the program from that seed, derives the build sequence, and grinds through the slices end-to-end with no further input. The structure is identical — same birth, slices, spine, graduation — the human just leaves the loop and a built-in driver turns the crank. The safety floor stays intact even here: a market/moat **KILL** halts birth, **contract and charter changes are never auto-decided** (they *park* to a queue the build flows around), and **graduation stays human** (it writes durable memory). "Done" means *build-complete, ready to graduate* — not graduated. Meant for throwaway greenfield/test programs in a dedicated tree, not the venture you can't roll back.

Run it through the launcher to put a **hard cost cap** on the night: `bash ops/workflow/scripts/yolo-run.sh prd.md --budget-usd 100 --max-hours 8`. On Claude Code the dollar cap is a real stop (`--max-budget-usd`); on Cursor there's no per-run dollar cap, so the launcher enforces the wall-clock and you set an account spend limit (or leave on-demand billing off) as the money backstop.

## Going bigger — mar as a worker in a loop

> **Status: experimental, in testing.** mar runs a task end-to-end today. Bolting an external **driver agent** on top — one that dispatches mar sessions on its own — is a thin connection, because mar already exposes the surface to drive. That connection is what we're testing now, not a big build.

mar finishes a task and stops. Right behavior for a task. But a lot of real work isn't one task — it's "keep going until this is *done*," where done is a moving target a human usually babysits. That's a **goal loop**, and it has five parts. Miss one and you don't have a loop, you have a runaway:

- **Goal** — a definition of done you can check: tests pass, CI green, a judge agent's rubric satisfied.
- **Worker** — one fresh-context attempt per turn. A bash agent, a `ralph` iteration, or a whole mar session.
- **Verifier** — deterministic checks first (tests, types, CI), a fresh-context judge for the rest. Never the worker grading its own homework.
- **State** — lives in files and git between turns. The repo is the memory; each turn starts clean.
- **Stop** — goal met, max iterations, budget cap, or "ask the human." A loop without a stop condition is a bug, not a feature.

The trick is **dumb driver, smart iterations**: the thing running the loop is a while-loop or a stop-hook — cheap, boring plumbing. The intelligence lives in the worker and the verifier. (Huntley's `ralph` is literally bash. mar's own refine stage is this exact shape one level down: tests are the verifier, and the hook that blocks edits to `tests/` is what stops the worker from cheating the reward.)

**mar is the premium worker.** Where a bash loop throws a raw agent at the problem, you hand a turn to a full mar session — research, plan, build, review, the works — and get an engineered attempt instead of a vibe. And mar is *made of* goal loops: refine, verification, the program tier itself. Loops all the way down.

**Driving it — four rungs of ambition:**

- **`ralph`** — minimal. A bash loop re-running an agent against `PROMPT.md` until it writes `.ralph-done`. Dumb on purpose. Lives in a worktree; skips permission prompts.
- **`/loop`** (Claude Code) — a standing watchman. Wake on a cadence, walk a checklist, fix the small stuff, spawn a goal loop when there's real work.
- **YOLO mode** (`/mar:program-yolo`) — the one driver mar ships *itself*, scoped to a single program: feed it a PRD and it births and builds the whole thing end-to-end (see "Programs" above). The driver is built-in because the loop is the program tier's own — but it stays scoped to one program; mar still doesn't grow a *general* orchestrator.
- **A driver agent** — the endgame for everything wider than one program. An external orchestrator — **Hermes**, **OpenClaw**, or anything that can drive a CLI — connects to mar from outside: it dispatches sessions across programs and repos, reads the spine for state, and escalates to you only for the calls that are actually yours. mar just has to be *drivable*, and it is.

One rule survives every rung: **contract and charter changes are never auto-*decided*.** A driver earns more rope by explicit promotion, never by drift. Even YOLO mode — which automates *gating*, birth included, from a PRD seed — holds this floor: a kill verdict halts, contract changes *park* for a human instead of being absorbed, and graduation stays human. The decisions that silently corrupt a build if they're wrong are the ones that never go auto — by design, possibly forever.

Parallelism comes from **lanes, not from inside a build**: each concurrent task is its own git worktree, running beside the others. The loop above them stays single-minded; the fan-out is structural.

## Requirements

- **Python 3.12+** — the `mar` CLI and the harness scripts require it. (`mar init`
  will resolve-fail on 3.11 or older.)
- **[uv](https://docs.astral.sh/uv/)** on your machine — the harness's memory
  pipeline and hooks run via `uv run`, so uv is needed at *session* time no matter
  how you install `mar` itself. (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
- A coding-agent CLI: **[Claude Code](https://claude.com/claude-code)** and/or
  **[Cursor CLI](https://cursor.com/cli)** (`cursor-agent`).
- **[`gh`](https://cli.github.com/)** authenticated for your repo (`gh auth login`).

## Install

`mar` is a one-shot scaffolder — you run it to set a repo up, then rarely again
(`mar update`). Install it **per-project**, not globally. Pick one:

**uv venv (recommended):**

```bash
cd my-project
uv venv --python 3.12              # 3.12+ required; uv fetches it if missing
uv pip install marauders-mischief
uv run mar --version               # → mar 0.16.0  (only inside this project)
```

**Ephemeral — nothing installed (uv's tool runner):**

```bash
uvx --from marauders-mischief mar --version
```

**Standard venv + pip:**

```bash
python3.12 -m venv .venv && source .venv/bin/activate
pip install marauders-mischief
mar --version
```

> Installing `mar` globally (`pipx install` / `uv tool install`) works but isn't
> recommended — it's a scaffolder, not a daemon. To undo a global install:
> `uv tool uninstall marauders-mischief` (or `pipx uninstall marauders-mischief`).

In the commands below, `mar` means the binary on your activated venv's PATH; on the
uv-venv route prefix it with `uv run` (e.g. `uv run mar init`).

## Quickstart

```bash
mkdir my-project && cd my-project
git init
gh repo create --private --source=. --remote=origin  # or use an existing repo

mar init                 # Claude Code (default)
# mar init --target both # Claude Code AND Cursor CLI (shared spine, both front doors)
# mar init --target cursor

# Set up the memory pipeline (its own uv project):
cd ops/memory && uv sync && cd -

# Fill in the two files mar wants you to fill in:
#   .brain/CONTEXT.md  — what you're building, in plain language
#   .brain/STATE.md    — where you are right now

git add -A && git commit -m "chore: scaffold mar harness"
```

mar installs once and is **committed to the repo**; git worktrees inherit it (no
re-init per worktree). With `--target both`, choose the harness when you open the
lane — `claude` or `cursor-agent`. See `docs/cursor-adapter-design.md` for the
Cursor adapter (incl. the per-agent model map and `--models` profiles).

Then open Claude Code (or Cursor CLI) and run a session:

```
/mar:session-start "fix the auth token refresh bug"
# picker: size (S/M/L/XL), kind, guidance, autonomy

/mar:plan
# → research, plan, plan-skeptic review

/mar:approve plan

/mar:ship
# → branch, execute, test, refine, simplify, verify, review + tester, draft PR

/mar:approve integrate
# → gh pr ready + gh pr merge --squash
```

For a tiny task (typo, isolated bug) the loop fits in 5-15 minutes. For a multi-day feature you'll plan it as L or XL and run multiple phases sequentially, each one its own PR.

## Slash commands

| Command | What it does |
|---|---|
| `/mar:session-start` | Start a session (size / kind / guidance / autonomy picker) |
| `/mar:plan` | Run the current planning sub-stage |
| `/mar:ship` | The build loop: branch → execute → test → refine → simplify → verify → review + tester → draft PR |
| `/mar:integrate` | Compose the commit story; pause for approval |
| `/mar:approve <gate>` | Pass a gate (research / meta-plan / plan / integrate / …) |
| `/mar:iterate <gate> "<note>"` | Refine the gate's output without losing position |
| `/mar:revise <target> "<note>"` | Back up to a prior stage with a note |
| `/mar:redirect "<direction>"` | Pivot the session entirely |
| `/mar:reject <gate>` | Discard the gate's artifact and back up |
| `/mar:status` | Where am I? |
| `/mar:session-list` | All active and archived sessions |
| `/mar:retrospect <id>` | Post-archive audit; surfaces framework feedback for the maintainer |
| `/mar:program-start` | Birth a program: visionary + skeptic spar over the spine, you arbitrate |
| `/mar:program-yolo` | Birth + build a program end-to-end, fully autonomously, from a single PRD seed |
| `/mar:program-graduate` | Retire a program once the app stands on its own |

There are more (idea capture, session resume, the rest of the program tier, between-session machinery). See `.claude/commands/mar/` after install, or the full spec at `ops/workflow/README.md`.

One session per working tree — the harness won't let two run loose in the same checkout and trample each other's git. Want two going at once? Give each its own `git worktree`; they share the spine, not the working directory.

## What `mar init` writes

```
your-project/
├── CLAUDE.md                   Project-level context. You own it.
├── .brain/                     Curated context. You own it.
│   ├── CONTEXT.md              What you're building.
│   ├── STATE.md                Current state of play.
│   ├── STACK.md                Stack decisions.
│   ├── DECISIONS.md            Why you made the calls you made.
│   └── RISKS.md                What could go wrong.
├── .claude/
│   ├── agents/                 ~30 sub-agents (research, plan, execute, review, …)
│   ├── commands/mar/           26 slash commands (/mar:*)
│   └── settings.json           Hooks + permissions. mar manages its own keys.
├── .cursor/                    Only with --target both / cursor:
│   ├── hooks.json              Cursor hooks (mar-owned). Reads the same ops/ scripts.
│   ├── cli.json                Starter CLI permissions (scaffolded — yours after).
│   └── commands/mar/           The same commands, plain-markdown for Cursor.
├── ops/workflow/               Spec, scripts, templates
└── .mm/lockfile.json           SHA256 of every framework file. `mar update` reads this.
```

With `--target both`, Cursor reads `CLAUDE.md` and `.claude/agents/` natively, so
those aren't duplicated under `.cursor/` — both harnesses share one spine.

Every shipped file falls into one of three classes:

- **framework** — owned by mar. Overwritten on `mar update`. Drift is detected if you edit.
- **scaffolded** — created once at init. Yours forever after. mar never touches.
- **merged** — mar owns specific keys; you own everything else in the same file (`.claude/settings.json`, `.gitignore`).

This split is what lets `mar update` upgrade the framework without clobbering your project.

## Development

```bash
git clone git@github.com:sindreespeland/marauders-mischief.git
cd marauders-mischief
uv sync --dev

uv run pytest
uv run ruff check src tests

# Try mar init against a throwaway directory
mkdir /tmp/test-install && cd /tmp/test-install
uv run --project ~/repos/marauders-mischief mar init
```

## Status

Pre-release (v0.18.0). The build loop is hardened end-to-end and the PR-native flow is live. The last few releases added the program tier (v0.14), an opt-in second reviewer from a rival model (v0.15), a Cursor CLI adapter plus one-session-per-worktree parallelism (v0.16; see `docs/cursor-adapter-design.md`), YOLO mode (v0.17): fully autonomous, PRD-seeded program runs via `/mar:program-yolo`, and — newest — a YOLO launcher with a hard cost cap (v0.18; `yolo-run.sh --budget-usd`). Smoke-test against a throwaway repo before you trust it on anything you'd miss.

Each minor release hardens one stage. See the roadmap below or the GitHub Releases page for what landed when.

## Roadmap

Shipped:

- **v0.5** — phase research: hypothesis-driven, 5-section structured output, optional skeptic
- **v0.6** — phase plan: author + skeptic at per-phase grain, AI-aware checks
- **v0.7** — execute step-decomposition: bounded context per build step
- **v0.8** — multi-kind testing: strategist + parallel runners (unit/eval/agent-flow/browser/perf), target-aware refine
- **v0.9** — simplify hardened: dynamic conventions, targeted re-test, revert on regression
- **v0.10** — refine hardened: protected surfaces (tests/fixtures/snapshots/evals), checkpoint + revert across all four refine loops
- **v0.11** — verify hardened: route-based dispatch (refine/replan/user), mechanical pre-checks, structured evidence
- **v0.12** — PR-native flow: draft PR at Stage 2.2, review/tester in PR mode, squash-merge at `/mar:approve integrate`
- **v0.13** — retrospect redesigned: per-session output, maintainer feedback via chat, no framework-shared file in user repos
- **v0.13.1** — first-run fix: `/mar:ship` auto-creates the phase branch
- **v0.13.2** — `CLAUDE.md` template brought up to date (session awareness, files-as-source-of-truth table, safeguards list, post-v12 repo map)
- **v0.13.3** — critical fix: `.claude/settings.json` hook shape corrected (was being rejected by Claude Code, silently disabling the scope hook)
- **v0.14** — program tier: a 4th level above session, a persistent spine for multi-session greenfield builds; all sub-agents baselined to Opus 4.8
- **v0.15** — opt-in cross-model review: a second reviewer (Codex / GPT-5.5) at Stage 5, advisory, never gating — a different model catches what yours won't
- **v0.16** — Cursor CLI adapter (dual-install, one shared spine, both front doors); one active session per working tree (parallel sessions live in separate worktrees)
- **v0.17** — YOLO mode (`/mar:program-yolo`): fully autonomous, PRD-seeded program runs — birth + slice-chaining driver, contract changes park instead of halting; safety floor (KILL, contract-decisions, graduation) stays human
- **v0.18** — YOLO launcher with a hard cost cap (`yolo-run.sh --budget-usd N`): real per-run dollar stop on Claude Code (`--max-budget-usd`); wall-clock + account-limit guidance on Cursor (no native per-run $ cap); in-band `--budget hours=/slices=` graceful halts

Next:

- `mar update` (drift-aware, with conflict resolution), plus the `mar status` / `mar doctor` stubs filled in
- Cursor v2 — the `best-of-breed` cross-vendor model profile (`.cursor/agents/`) and live-hook verification
- Codex CLI adapter

## Contributing

Issues and PRs welcome at [github.com/sindreespeland/marauders-mischief](https://github.com/sindreespeland/marauders-mischief/issues). Run `/mar:retrospect` after a session if you find friction; the chat output formats framework findings as paste-ready issue bodies.

## License

MIT — see [LICENSE](LICENSE).
