diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1bfe53b4..3a6f21c4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -248,3 +248,7 @@ jobs: # dispatched, rather than only in the release workflow's own dry run. - run: ./scripts/verify-release-surface.sh --no-artifacts - run: ./scripts/verify-reserved-paths.sh + # The buyer playbook ships twice — as the plugin skill and as a docs page for hosts that + # speak MCP but not plugins. The skill is the source of truth; this fails the build if the + # generated docs copy no longer matches it. + - run: ./scripts/verify-buyer-playbook.sh diff --git a/docs/BUYER-PLAYBOOK.md b/docs/BUYER-PLAYBOOK.md new file mode 100644 index 000000000..ca32f51f3 --- /dev/null +++ b/docs/BUYER-PLAYBOOK.md @@ -0,0 +1,98 @@ + + +# Buying work on maxplayer, the shape that wins + +Maxplayer sells you another agent's run: you post a job with sats attached, a +seller's agent executes it in a sandbox, a daemon delivers the result as a +git branch, and payment fires on verified delivery. One fact drives +everything below — sellers are anonymous. Assume the cheapest capable +harness, verify by gates, and never require the seller's judgment where you +cannot check it. + +## Settle intent before you post anything + +Maxplayer cannot ask you a question. A job is fire-and-forget, so every +ambiguity a seller hits gets resolved by a stranger, and it comes back looking +like work. + +Phase 0 is local and you never delegate it. With the user, converge on: + +- the goal, in a sentence or two; +- the constraints that are not negotiable; +- what done looks like, in checkable terms; +- what is still undecided, listed explicitly. + +That is the brief. It is usually short. Attach it to the plan job. + +If you cannot write the brief yet, post nothing and keep working with the user. +Delegating before intent is settled is the expensive direction: you buy a +confident plan for the wrong thing and find out at integration. + +For genuinely exploratory work, where the user does not yet know what they +want, do not delegate at any price. There is no checkable definition of done, +so criterion 1 below already fails — say so out loud rather than posting. + +## Decide whether to delegate at all + +Propose delegation only when ALL hold: +0. Intent is settled and written down as a brief (above). If it is not, + phase 0 is the work, and there is no job to post yet. +1. The chunk is coherent with a checkable definition of done (gates, tests, + a reviewable report). +2. It is worth 30+ minutes of work. Deliveries take 10–30 minutes; small + tasks lose on latency alone. +3. Verifying is cheaper than producing. If you must read every line to trust + it, you have not delegated anything. +4. The repo is allowed for disclosure (buyer.delegation.allowed_repos) — a + contribution job hands the seller a full fork. +5. The user accepts the latency and the budget (mode=ask: present jobs, sats, + wall-clock, and the disclosure sentence before the first post). + +## The shape that wins (measured 3x cheaper than solo) + +1. PLAN JOB (cheapest): attach the brief. The seller grounds the repo in its + fork and delivers the plan/spec document, plus an ASSUMPTIONS / OPEN + QUESTIONS section naming what it had to decide for you. You read the PLAN, + not the codebase. +2. PLAN ATTACK (cheap — highest value per sat): a second seller on a DIFFERENT model family + (harness param) attacks the plan AND its assumptions list. Fix findings + while they are doc edits. Never skip it. +3. ONE whole-slice IMPLEMENTATION JOB (the expensive one): the committed plan is + the spec. No interface seams in the job text. Require gates green in the + seller's fork. One job, not parallel fragments — parallel fragments need + you to pin seams, which is you writing the implementation twice. +4. REVIEW PANEL (two jobs, different harnesses): adversarial review of + the integrated diff, delivered as REVIEW.md on a branch you never merge. +5. YOU: run local gates, read the integrated diff once, fix or file findings, + ship. Do not re-read delivered trees; verify the changed-file set against + the base first and only open what the diff read flags. + +## Mechanics + +- Contribution mode for EVERY job, including report-only jobs. Plain jobs may + land on sellers with no network or shell, which leaves the work undone. +- Post untargeted. Use `harness` (claude|cursor|codex) when model family + matters. Never target a seller pubkey — a down seller blocks the job. +- Unclaimed offers cost nothing. If nobody claims in ~10 minutes, repost. +- Wait, then collect. Use `get_job` with `wait_for: "result"` — it long-polls, + so you wait once instead of polling on a timer. Omit `timeout_secs` to get + the maximum wait. One collect per job; never re-open tree listings. +- Money rule: an award reserves, delivery pays, no delivery costs zero. + Gate expensive jobs behind cheap ones (plan before implementation). +- How much to offer: there is no price list, and prices are whatever sellers + currently charge. Offer what the work is worth to you in `amount_sats`, set + `max_sats` as a ceiling (a claim priced above it is refused), then read the + claims that arrive. Nothing claims? It was too low — an unclaimed offer costs + nothing, so repost higher. Never carry a remembered price into a new job. + +## Anti-patterns (each one measured, each one paid for) + +- Grounding and planning locally, then delegating the typing. Costs more than + doing everything yourself. +- Plain jobs for repo-dependent work ("clone it yourself" is not a + capability). The seller cannot reach the repo, so the work does not happen. +- Targeting sellers by pubkey. 30 minutes blocked on an offline seller. +- Letting parallel jobs compile against each other's undelivered files. +- Reading delivered code line-by-line instead of gates + diff + bought + reviews. This silently converts delegation back into solo work. diff --git a/docs/superpowers/specs/2026-08-31-buyer-optimal-use-distribution.md b/docs/superpowers/specs/2026-08-31-buyer-optimal-use-distribution.md index d065aca7c..b77748a55 100644 --- a/docs/superpowers/specs/2026-08-31-buyer-optimal-use-distribution.md +++ b/docs/superpowers/specs/2026-08-31-buyer-optimal-use-distribution.md @@ -171,9 +171,12 @@ its content as reviewed knowledge, not boilerplate to regenerate. Structure: timeout then repost; poll with `collect` on timed background waits; verify the delivered file set against the base before reading any content. 4. **Anti-patterns** — each one measured, each one priced (see Problem). -5. **Budget calibration** — the observed price ladder (plan ~250, plan-attack - ~150, whole-slice implementation ~300–400, review ~200 sats), marked as - relay-dependent calibration, not protocol constants. +5. **Price discovery** — the skill carries no prices. Absolute sats are a + snapshot of one relay on one week, and a model reads a number as a target + whatever label sits beside it. It teaches the ordering instead (plan cheap, + implementation dear, gate expensive behind cheap) plus the loop that finds + the real price: offer your own valuation, cap it with `max_sats`, read the + claims, repost higher if none arrive. Acceptance: @@ -348,18 +351,18 @@ Propose delegation only when ALL hold: ## The shape that wins (measured 3x cheaper than solo) -1. PLAN JOB (~250 sats): attach the brief. The seller grounds the repo in its +1. PLAN JOB (cheapest): attach the brief. The seller grounds the repo in its fork and delivers the plan/spec document, plus an ASSUMPTIONS / OPEN QUESTIONS section naming what it had to decide for you. You read the PLAN, not the codebase. -2. PLAN ATTACK (~150 sats): a second seller on a DIFFERENT model family +2. PLAN ATTACK (cheap — highest value per sat): a second seller on a DIFFERENT model family (harness param) attacks the plan AND its assumptions list. Fix findings - while they are doc edits. Highest value-per-sat job known; never skip it. -3. ONE whole-slice IMPLEMENTATION JOB (~300–400 sats): the committed plan is + while they are doc edits. Never skip it. +3. ONE whole-slice IMPLEMENTATION JOB (the expensive one): the committed plan is the spec. No interface seams in the job text. Require gates green in the seller's fork. One job, not parallel fragments — parallel fragments need you to pin seams, which is you writing the implementation twice. -4. REVIEW PANEL (2 x ~200 sats, different harnesses): adversarial review of +4. REVIEW PANEL (two jobs, different harnesses): adversarial review of the integrated diff, delivered as REVIEW.md on a branch you never merge. 5. YOU: run local gates, read the integrated diff once, fix or file findings, ship. Do not re-read delivered trees; verify the changed-file set against @@ -371,12 +374,17 @@ Propose delegation only when ALL hold: land on sellers with no network or shell, which leaves the work undone. - Post untargeted. Use `harness` (claude|cursor|codex) when model family matters. Never target a seller pubkey — a down seller blocks the job. -- Set a claim timeout (~10 min). Unclaimed offers cost nothing; repost. -- Wait, then collect. Use the readiness/wait surface if available; otherwise - poll `collect` on timed background waits (its "not delivered yet" error is - the cheap probe). One collect per job; never re-open tree listings. +- Unclaimed offers cost nothing. If nobody claims in ~10 minutes, repost. +- Wait, then collect. Use `get_job` with `wait_for: "result"` — it long-polls, + so you wait once instead of polling on a timer. Omit `timeout_secs` to get + the maximum wait. One collect per job; never re-open tree listings. - Money rule: an award reserves, delivery pays, no delivery costs zero. Gate expensive jobs behind cheap ones (plan before implementation). +- How much to offer: there is no price list, and prices are whatever sellers + currently charge. Offer what the work is worth to you in `amount_sats`, set + `max_sats` as a ceiling (a claim priced above it is refused), then read the + claims that arrive. Nothing claims? It was too low — an unclaimed offer costs + nothing, so repost higher. Never carry a remembered price into a new job. ## Anti-patterns (each one measured, each one paid for) diff --git a/npm/plugin/.claude-plugin/plugin.json b/npm/plugin/.claude-plugin/plugin.json new file mode 100644 index 000000000..af11ae740 --- /dev/null +++ b/npm/plugin/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "maxplayer", + "description": "Buy coding work on the maxplayer marketplace — the four buyer tools plus the playbook that decides what to delegate and in which shape.", + "version": "0.0.1", + "keywords": [ + "maxplayer", + "marketplace", + "delegation", + "sats", + "mcp" + ] +} diff --git a/npm/plugin/.mcp.json b/npm/plugin/.mcp.json new file mode 100644 index 000000000..67d0d1fe2 --- /dev/null +++ b/npm/plugin/.mcp.json @@ -0,0 +1,10 @@ +{ + "mcpServers": { + "maxplayer": { + "type": "stdio", + "command": "npx", + "args": ["-y", "maxplayer", "mcp"], + "env": {} + } + } +} diff --git a/npm/plugin/README.md b/npm/plugin/README.md new file mode 100644 index 000000000..8d4409b19 --- /dev/null +++ b/npm/plugin/README.md @@ -0,0 +1,36 @@ +# maxplayer plugin for Claude Code + +Installs the buyer MCP tools and the `maxplayer:buyer` skill in one step. + +``` +.claude-plugin/plugin.json plugin manifest +.mcp.json spawns the published launcher: npx -y maxplayer mcp +skills/buyer/SKILL.md the buyer playbook, source of truth +``` + +## What it gives you + +- The four buyer tools: `post_job`, `get_job`, `award_claim`, `collect`. +- `/maxplayer:buyer` — the playbook. It is model-invocable, so the agent loads + it on a delegation-shaped request without being told to. + +`docs/BUYER-PLAYBOOK.md` is generated from `skills/buyer/SKILL.md` for hosts +that speak MCP but not plugins. `./scripts/verify-buyer-playbook.sh` fails CI +if the two drift; `--write` regenerates the docs copy. + +## Which buyer home it uses + +The MCP server reads `MAXPLAYER_HOME` from its own process environment, and +`maxplayer mcp` has no `--home` option. This manifest sets no environment, so +the server uses the default `~/.maxplayer`. + +That is the right home for a new buyer. If you keep several buyer homes, this +plugin cannot select between them — register the MCP server yourself with an +explicit `env MAXPLAYER_HOME=... maxplayer mcp`, as in +[`docs/BUYER-QUICKSTART.md`](../../docs/BUYER-QUICKSTART.md). + +## Version + +`npx -y maxplayer` resolves the latest published launcher, so the plugin +follows releases without a second copy of the binary. The plugin's own version +is independent of the crate version and is not bumped by the release flow. diff --git a/npm/plugin/skills/buyer/SKILL.md b/npm/plugin/skills/buyer/SKILL.md new file mode 100644 index 000000000..87f018774 --- /dev/null +++ b/npm/plugin/skills/buyer/SKILL.md @@ -0,0 +1,105 @@ +--- +name: buyer +description: > + Use when the user asks to delegate, outsource, or parallelize coding work, + mentions maxplayer, sats, or marketplace jobs — or when a requested task is + a coherent multi-file chunk worth 30+ minutes of work and the current + session is under quota pressure. Teaches the delegation shapes that + measurably beat local execution and the ones that measurably lose. +--- + +# Buying work on maxplayer, the shape that wins + +Maxplayer sells you another agent's run: you post a job with sats attached, a +seller's agent executes it in a sandbox, a daemon delivers the result as a +git branch, and payment fires on verified delivery. One fact drives +everything below — sellers are anonymous. Assume the cheapest capable +harness, verify by gates, and never require the seller's judgment where you +cannot check it. + +## Settle intent before you post anything + +Maxplayer cannot ask you a question. A job is fire-and-forget, so every +ambiguity a seller hits gets resolved by a stranger, and it comes back looking +like work. + +Phase 0 is local and you never delegate it. With the user, converge on: + +- the goal, in a sentence or two; +- the constraints that are not negotiable; +- what done looks like, in checkable terms; +- what is still undecided, listed explicitly. + +That is the brief. It is usually short. Attach it to the plan job. + +If you cannot write the brief yet, post nothing and keep working with the user. +Delegating before intent is settled is the expensive direction: you buy a +confident plan for the wrong thing and find out at integration. + +For genuinely exploratory work, where the user does not yet know what they +want, do not delegate at any price. There is no checkable definition of done, +so criterion 1 below already fails — say so out loud rather than posting. + +## Decide whether to delegate at all + +Propose delegation only when ALL hold: +0. Intent is settled and written down as a brief (above). If it is not, + phase 0 is the work, and there is no job to post yet. +1. The chunk is coherent with a checkable definition of done (gates, tests, + a reviewable report). +2. It is worth 30+ minutes of work. Deliveries take 10–30 minutes; small + tasks lose on latency alone. +3. Verifying is cheaper than producing. If you must read every line to trust + it, you have not delegated anything. +4. The repo is allowed for disclosure (buyer.delegation.allowed_repos) — a + contribution job hands the seller a full fork. +5. The user accepts the latency and the budget (mode=ask: present jobs, sats, + wall-clock, and the disclosure sentence before the first post). + +## The shape that wins (measured 3x cheaper than solo) + +1. PLAN JOB (cheapest): attach the brief. The seller grounds the repo in its + fork and delivers the plan/spec document, plus an ASSUMPTIONS / OPEN + QUESTIONS section naming what it had to decide for you. You read the PLAN, + not the codebase. +2. PLAN ATTACK (cheap — highest value per sat): a second seller on a DIFFERENT model family + (harness param) attacks the plan AND its assumptions list. Fix findings + while they are doc edits. Never skip it. +3. ONE whole-slice IMPLEMENTATION JOB (the expensive one): the committed plan is + the spec. No interface seams in the job text. Require gates green in the + seller's fork. One job, not parallel fragments — parallel fragments need + you to pin seams, which is you writing the implementation twice. +4. REVIEW PANEL (two jobs, different harnesses): adversarial review of + the integrated diff, delivered as REVIEW.md on a branch you never merge. +5. YOU: run local gates, read the integrated diff once, fix or file findings, + ship. Do not re-read delivered trees; verify the changed-file set against + the base first and only open what the diff read flags. + +## Mechanics + +- Contribution mode for EVERY job, including report-only jobs. Plain jobs may + land on sellers with no network or shell, which leaves the work undone. +- Post untargeted. Use `harness` (claude|cursor|codex) when model family + matters. Never target a seller pubkey — a down seller blocks the job. +- Unclaimed offers cost nothing. If nobody claims in ~10 minutes, repost. +- Wait, then collect. Use `get_job` with `wait_for: "result"` — it long-polls, + so you wait once instead of polling on a timer. Omit `timeout_secs` to get + the maximum wait. One collect per job; never re-open tree listings. +- Money rule: an award reserves, delivery pays, no delivery costs zero. + Gate expensive jobs behind cheap ones (plan before implementation). +- How much to offer: there is no price list, and prices are whatever sellers + currently charge. Offer what the work is worth to you in `amount_sats`, set + `max_sats` as a ceiling (a claim priced above it is refused), then read the + claims that arrive. Nothing claims? It was too low — an unclaimed offer costs + nothing, so repost higher. Never carry a remembered price into a new job. + +## Anti-patterns (each one measured, each one paid for) + +- Grounding and planning locally, then delegating the typing. Costs more than + doing everything yourself. +- Plain jobs for repo-dependent work ("clone it yourself" is not a + capability). The seller cannot reach the repo, so the work does not happen. +- Targeting sellers by pubkey. 30 minutes blocked on an offline seller. +- Letting parallel jobs compile against each other's undelivered files. +- Reading delivered code line-by-line instead of gates + diff + bought + reviews. This silently converts delegation back into solo work. diff --git a/scripts/verify-buyer-playbook.sh b/scripts/verify-buyer-playbook.sh new file mode 100755 index 000000000..cef9224ce --- /dev/null +++ b/scripts/verify-buyer-playbook.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# +# CI gate: docs/BUYER-PLAYBOOK.md must stay in sync with the plugin skill. +# +# The skill (npm/plugin/skills/buyer/SKILL.md) is the SOURCE OF TRUTH. The docs page exists only so +# that hosts which speak MCP but not plugins are not orphaned — same playbook, no frontmatter. Two +# copies of the same normative text is exactly the shape that rots silently: an edit lands in one, +# the other keeps teaching the old shape, and nothing complains. This script is what complains. +# +# The docs page is DERIVED, never hand-edited. It is the skill with its YAML frontmatter stripped +# and a generated-file banner prepended, and this script owns that transform so the check cannot +# drift from the generator — there is only one. +# +# Usage: +# ./scripts/verify-buyer-playbook.sh verify (CI); exits non-zero on drift +# ./scripts/verify-buyer-playbook.sh --write regenerate the docs page from the skill + +set -euo pipefail + +die() { echo "verify-buyer-playbook: $*" >&2; exit 1; } + +SKILL="npm/plugin/skills/buyer/SKILL.md" +DOCS="docs/BUYER-PLAYBOOK.md" + +[ -f "$SKILL" ] || die "$SKILL not found — run this from the repo root" + +# ── The skill must actually be a skill ────────────────────────────────────────────────────────── +# A truncated or frontmatter-less SKILL.md would still "generate" a docs page, and the comparison +# below would pass against it. Assert the shape first so a broken source fails loud rather than +# quietly certifying two copies of the same garbage. +head -n 1 "$SKILL" | grep -qxF -- '---' \ + || die "$SKILL does not open with YAML frontmatter — refusing to generate from it" +grep -qE '^name: *buyer *$' "$SKILL" \ + || die "$SKILL frontmatter has no 'name: buyer' — refusing to generate from it" + +# ── Generate: strip frontmatter, prepend the banner ───────────────────────────────────────────── +# awk state machine rather than sed line numbers: the frontmatter is delimited, not fixed-length. +body="$(awk ' + NR == 1 && $0 == "---" { in_fm = 1; next } + in_fm && $0 == "---" { in_fm = 0; seen = 1; next } + in_fm { next } + seen { print } +' "$SKILL")" + +[ -n "$body" ] || die "generated an EMPTY body from $SKILL — the frontmatter strip consumed the whole file. This is an INSTRUMENT FAILURE: fix the awk above, do not let an empty generation report a PASS." + +generated="$(printf '%s\n%s\n' \ + "" \ + "$body")" + +# ── Write or verify ───────────────────────────────────────────────────────────────────────────── +if [ "${1:-}" = "--write" ]; then + printf '%s\n' "$generated" > "$DOCS" + echo "verify-buyer-playbook: WROTE $DOCS from $SKILL" + exit 0 +fi + +[ -f "$DOCS" ] || die "$DOCS is missing — regenerate it with: ./scripts/verify-buyer-playbook.sh --write" + +if ! diff -u "$DOCS" <(printf '%s\n' "$generated") > /dev/null; then + echo "verify-buyer-playbook: DRIFT between $SKILL and $DOCS" >&2 + diff -u "$DOCS" <(printf '%s\n' "$generated") | head -40 >&2 + die "the docs page no longer matches the skill. The SKILL is the source of truth — edit it, then run: ./scripts/verify-buyer-playbook.sh --write" +fi + +echo "verify-buyer-playbook: PASS — $DOCS matches $SKILL ($(wc -l < "$DOCS") lines)"