Skip to content

Muse buyer and seller skills, with a bundled ACP bridge and an offline gate - #985

Draft
maxy-player wants to merge 3 commits into
MakePrisms:mainfrom
maxy-player:w-muse-public-skills
Draft

Muse buyer and seller skills, with a bundled ACP bridge and an offline gate#985
maxy-player wants to merge 3 commits into
MakePrisms:mainfrom
maxy-player:w-muse-public-skills

Conversation

@maxy-player

Copy link
Copy Markdown
Contributor

Two public-use agent skills for operating Maxplayer from a Muse account, published alongside the existing five. They are the Muse layer only — they link to buyer-operate / seller-operate rather than restating them. The five existing skills are untouched, and no crate, protocol or payment code changes.

Draft: opened for review before any acceptance run exists. See the disclosure section — this is deliberately not a general-availability claim.

What is here

Path
muse-buyer/skill.md install into a Muse workspace, MAXPLAYER_HOME on the MCP server process, the two-step funding path, human approval before every paid post, the post_job → get_job → collect loop
muse-buyer/references/verification.md every claim tiered: source-checked / field-reported / unverified
muse-seller/skill.md the ACP bridge + a scheduled worker, the readiness gate, the sandboxing decision, the claim → work → done contract, restart recovery
muse-seller/bin/muse-acp-bridge.py the bundled helper: ACP on stdio ⇄ a queue a scheduled worker claims from
muse-seller/references/{readiness,muse-platform,verification}.md conditional detail, kept out of the operational cores
web/app/test/muse-skills.test.mjs the offline gate, below
.well-known/skills/index.json +2 entries, so both publish in the derived discovery index with digests

Why a bridge exists

maxplayer seller spawns one agent process per job and speaks ACP to it over stdio. A Muse account cannot be that process — its model turns come from a scheduler, not a pipe. So:

maxplayer seller  --ACP/stdio-->  muse-acp-bridge.py  --queue dir-->  a scheduled Muse worker

Every guarantee is enforced and has a test that fails without it:

  • No os.getcwd() fallback for the job workdir. The driver spawns the agent with the seller's cwd, so a fallback silently ships an empty delivery. A session with a missing, relative or unwritable cwd fails instead.
  • The pre-advertise self-probe is queued to the real worker, never answered inline. Answering it in the bridge would prove only that the bridge can write a file, letting a seat advertise over a dead worker path. A test asserts the bridge has not written the sentinel.
  • Atomic throughout: jobs appear by directory rename, claims are exclusive mkdir, done lands by os.replace stamped with its turn id. A stale or late done is never reused, and an expired turn cancels its own job.
  • Cancellation propagates to the worker; reap releases claims held by killed runs without touching pending work, results or config.

Offline gate

One command, no npm install, no network, no relay, no seller daemon, no wallet, no sats:

node --test web/app/test/muse-skills.test.mjs

17 tests, 17 pass locally (node v26.5.0, python3 3.9.6). It fails loudly if python3 is absent rather than skipping — a green run that never executed the bridge is the false pass this work is about. python3 is already a build-time assumption of this package (the serve script).

Negative cases: missing / relative / non-existent session workdir; prompt for an unknown session; the probe not answered inline; five claimants racing one job; expired job; cancelled job; a done stamped with another turn; a turn outliving its budget plus a late result trying to revive it; restart/stale-claim recovery; cancellation. Surface invariants: index↔file↔frontmatter agreement, every published pointer resolving to a shipped file, and asserted absence of identities, absolute home paths, 64-hex keys, invoices and balances.

web/app/test/build.test.mjs also passes 8/8 with the new index entries, which is what proves the derived AgentSkills v0.2.0 discovery index and its SHA-256 digests pick both skills up.

Two documentation corrections from source

  • post_job requires output (required: ["task","output","amount_sats"], additionalProperties: false). The field notes this work drew on omitted it, so no recorded call replays verbatim.
  • maxplayer buyer refuses --home (both spellings), naming MAXPLAYER_HOME — it does not silently ignore it. AGENTS.md agrees the variable belongs on the MCP server process.

Separately, and not changed here because it is outside this PR's scope: the published buyer-operate/skill.md still says maxplayer buyer serve silently ignores --home, describing the pre-#438 behaviour as current. Worth a follow-up by whoever owns that page.

Disclosure — what is not verified

  • No clean-account Muse acceptance run exists. Nobody has taken an empty Muse account through either page: no seat advertised, no job claimed, no sat earned. Both skills and both verification pages mark this an unpassed release gate, not a passing step, and state exactly what would close it.
  • The bridge has never been driven by a real maxplayer seller process. Its ACP behaviour is tested against the protocol as read from driver/acp.rs and driver/acp_driver.rs, not against the daemon.
  • Version skew: the sources read here are workspace version 0.5.5; the field reports were from 0.5.7. Nothing was checked across that gap, and both skills say so.

Deliberately absent

The field reports included an operator workaround for a box where the relay hostname resolved to a dead local intercept — a local forwarder plus a mount-namespace /etc/hosts overlay. It is not published here. The reports themselves record that no supported method exists for that situation, and a restriction workaround is not an installation step. Both skills instruct the reader to report an unreachable relay as a named blocker instead.

No spending, wallet access, tag, merge or deployment was involved in producing this branch.

w-muse-public-skills added 3 commits September 8, 2026 20:29
…gate

The bridge lets a Muse account sell on maxplayer: it speaks the ACP slice the
seller driver uses, publishes each turn as a queue job, and waits for a
scheduled worker run to claim and finish it.

Every guarantee the field shim lacked is enforced and tested offline:
no os.getcwd() fallback for the job workdir, per-session identity on every
prompt, the pre-advertise probe queued for the real worker instead of answered
inline, atomic publish/claim/done, turn identity so a stale or late done is
never reused, and cancellation propagated to the worker.

Gate: node --test web/app/test/muse-skills.test.mjs (12 tests, no network).
…y entries

Two skills for operating maxplayer from a Muse account, published alongside
the existing five. They are the Muse layer and link to buyer-operate /
seller-operate rather than restating them.

muse-buyer: install into a Muse workspace, MAXPLAYER_HOME set on the MCP
server process (buyer refuses --home), the two-step funding path, explicit
human approval of task/target/amount/cap before every paid post with a
re-post needing a fresh yes, and the source-checked trade loop -- including
that post_job requires output, which the field guide's examples omitted.
Recovery is stated only as far as the source supports it.

muse-seller: the bridge plus a scheduled worker, the readiness gate whose nix
check has no bypass, both stranger-facing routes closed until a sandbox
launcher exists (the buyer allowlist admits and vetoes nothing), the
claim -> work -> done contract with done meaning completion, and reap after a
restart. Run history, not the schedule, proves a run happened.

Every claim is tiered in references/verification.md: reproduced offline,
source-checked, or field-reported. Clean-account Muse acceptance was
unavailable, so it is marked an unpassed release gate, not a passing step.

Gate: node --test web/app/test/muse-skills.test.mjs -- 17 tests, no network.
web/app/test/build.test.mjs also passes 8/8 with the new index entries.
…safe-no-sandbox

Source-checked against the maxplayer seller usage text: with both open routes
off and no accept_offers_only_from, the seat claims nothing and says so at
boot. The skill told readers to keep the routes closed without telling them
the list is what makes a closed seat workable at all. Also names the flag that
serves a stranger-facing surface with no containment, as one not to reach for.
@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the MakePrisms Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant