Status: Draft. Not yet ratified. Refine before committing. Last updated: 2026-05-25
Masques pivots from in-session identity injection (an agent dons a masque mid-conversation) to agent factory (the MCP server spawns a fresh agent process with the masque baked in as turn-0 system prompt). The surface to any agent ecosystem is an MCP server (masques-mcp) exposing spawn, status, and terminate. The Claude Code plugin's /don becomes sugar that proxies to the MCP server.
The current model (don/doff a masque inside a live conversation) has four model-behavior problems that won't show up in evals but will erode trust in production:
- Doff doesn't actually un-do. The masque's lens and the work done under it remain in the context window. The "baseline" you return to remembers being the masque. Reputation scoring of subsequent sessions is contaminated.
- Mid-stream identity competes with turn-0 instructions. A system prompt at turn 1 dominates the model. A masque injected at turn 30 is one more message — the model can and does drift back to its original identity under pressure.
- The lock is voluntary. Today's "one masque at a time" is a YAML file the agent is asked to honor. An adversarial or sloppy agent can ignore it. Process boundaries cannot.
- Telemetry attribution is ambiguous. "Was this token emitted as the masque, or during the transition?" — no clean answer when both identities share one context. Reputation scoring depends on clean attribution.
The factory model: each masque session is its own subprocess, started with the masque YAML as its first system prompt. The agent is the masque for its lifetime. No drift, no contamination, structural lock, unambiguous telemetry.
Mirrors the whiteboard sketch:
┌─────────────────┐
│ Calling agent │ (Claude Code / Cursor / Cline / SDK / custom)
│ (any MCP- │
│ speaking) │
└────────┬────────┘
│ MCP: spawn(masque, intent)
▼
┌─────────────────┐ ┌────────────────────┐
│ masques-mcp │────────▶│ ClickHouse │
│ (agent factory)│ query │ (reputation) │
│ │ │ masques.ai │
│ │────────▶├────────────────────┤
│ │ gate │ TigerBeetle │
│ │ │ (ledger of $) │
└────────┬────────┘ │ masques.ai │
│ spawn └────────────────────┘
▼
┌─────────────────┐
│ Masque process │ (Claude Agent SDK or pluggable backend)
│ (system prompt │
│ = masque YAML)│
└────────┬────────┘
│ OTEL spans/metrics/logs
▼
┌─────────────────┐ ┌────────────────────┐
│ Local OTEL │────────▶│ DuckDB (local) │
│ collector │ │ - self-knowledge │
└─────────────────┘ │ - sampling buffer │
└─────────┬──────────┘
│ forward
▼
┌────────────────────┐
│ ClickHouse │
│ (reputation) │
└────────────────────┘
Key shifts from current state:
- Surface goes from "Claude Code plugin commands" → "MCP server + plugin sugar"
- Identity injection goes from "system prompt mutation at turn N" → "spawn subprocess at turn 0"
- Lock goes from "YAML file the agent reads" → "process boundary"
- Telemetry attribution goes from "best effort" → "tagged at source with
masque.session_id" - Payment gate goes from "design doc" → "MCP server enforces before
spawnreturns"
Size: ~1 hour Deliverables:
- Fix
bddatabase repo-ID mismatch (bd migrate --update-repo-id) - Sync version:
plugin.jsonandmarketplace.jsonmust match - CHANGELOG entry noting the upcoming pivot so users aren't surprised
Size: ~3-5 days Deliverables:
- MCP server binary exposing three tools:
spawn(masque: string, intent?: string) → { session_id, status }status(session_id) → { state, masque, started_at, last_event }terminate(session_id) → { final_state, duration_ms }
- Reads
*.masque.yamlfrom${MASQUES_HOME}and${CLAUDE_PLUGIN_ROOT}/personas - Spawns Claude Agent SDK subprocess with
lens+contextas system prompt - Session state persisted to
${MASQUES_HOME}/sessions/{uuid}.session.yaml - Structured stdout/stderr proxy so the calling agent gets streaming output
- No payment, no reputation gate yet — that's later phases. This is the skeleton.
Open question: implementation language (see Open Questions §1).
Size: ~2-3 days Deliverables:
- Update Claude Code plugin:
/donbecomes a thin wrapper that callsmasques-mcp.spawnand proxies the subprocess;/doffcallsterminate;/idand/listread MCP session state - Integration docs for: Cursor, Cline, Claude Agent SDK, custom MCP clients
examples/directory with minimal "hello, Codesmith" snippets for each ecosystem- README rewrite (audience: agent developers, not Claude Code users specifically)
Size: ~3-5 days Deliverables:
- Spawned masque process emits OTEL to local collector, every span tagged with
masque.session_id,masque.name,masque.version - Synthesize span-like records from Claude Code metrics/logs (agents don't natively emit spans — wrap the log stream)
- DuckDB ingests JSONL exports, maintains rolling "self-knowledge" view per masque
- Forward sampled traces to ClickHouse on masques.ai
- Reputation aggregation MV in ClickHouse (build on existing
006_reputation.sql)
Size: ~1-2 weeks Deliverables:
- Host TigerBeetle on masques.ai infrastructure (Docker, persistent volume, backup policy)
- Account structure decided (see Open Questions §3): agent prepaid account, author receivable account, escrow account per pending session
masques-mcp.spawn:- queries ClickHouse for masque reputation (block if below threshold)
- queries TigerBeetle for agent balance (block if insufficient)
- creates pending two-phase transfer (escrow)
- returns session_id
masques-mcp.terminate:- calculates final cost from telemetry (per-token / per-minute / per-tool-call — decision needed)
- posts the transfer (or partial-post + void remainder)
- Author payout flow: TigerBeetle balance → Solana wallet (devnet first, mainnet behind flag)
- Contact Protocol integration:
spawn= Tuning + Bond;terminate= Settlement; refund/dispute = Disavowal
Size: ~2 days Deliverables:
- README pitched at "any agent developer," not Claude Code users
docs/quickstart-adopter.md— how to integrate masques into your agent stackdocs/quickstart-author.md— how to publish a masque and get paiddocs/what-is-masques.md— cold-reader explainer
Size: ~half day Deliverables:
- Single static
index.html(inline CSS, no build step) - Hero, what-it-is, install/integrate snippet, link to GitHub
- Deploy to Cloudflare Pages / Vercel / Netlify
- In-session masque switching. A session has one masque from start to end. Switching means spawning a new session.
.claude/masque.session.yamlas a lock. The session file becomes purely advisory (display state for/id). The lock is the process boundary.- The "agent dons the masque" framing. Replaced with "the agent commissions a masque-shaped subagent."
- Masque YAML schema (
lens,context,attributes,spinnerVerbs) — no changes needed - All 30+ existing personas — they become spawn targets
- The plugin commands (
/don,/doff,/id,/list,/inspect,/sync-manifest,/audience,/performance) — kept, internally rewired - TUI for team composition (
tui/masque) — unchanged - ClickHouse schema (numbered migrations
001–006) — mostly intact, may needsession_idcolumn on sessions table - DuckDB judge service — continues to work on JSONL exports
- MCP server language. Zig (matches TUI + ContactProtocol, single static binary, no runtime) vs Python (Claude Agent SDK is Python-first, faster prototyping). Lean: start in Python for SDK convenience, rewrite hot paths in Zig if profiling demands.
- Subprocess I/O proxying. How does the calling agent receive the spawned masque's output? Options: (a) stream via MCP tool result chunks, (b) the calling agent connects directly to the subprocess via a returned socket/handle, (c) NDJSON over stdout. Each has implications for latency and client complexity.
- TigerBeetle account structure. Prepaid (agent loads balance before
spawn) vs postpaid (metered, settled later)? Escrow per session vs running balance? Seedocs/session-prompts/tigerbeetle-integration.mdfor prior thinking. - Pricing model. Per-session flat? Per-token? Per-minute? Per-tool-call? Determines how much escrow
spawnneeds to lock. - Reputation gate failure mode. Hard block, soft warning, or dynamic pricing dial? What threshold, who sets it, how appealable.
- Solana specifics. Native SOL or USDC? Mainnet behind a flag, or devnet only until launch? Wallet management for masque authors — managed custody, BYO keys, or both?
- Contact Protocol maturity. Current state at
~/git/ContactProtocolis "toy minimal implementation in Zig." Co-develop with Phase 4, or wait until CP v1 and ship Phase 4 with a simpler bilateral handshake first? - Backwards compatibility. How long do we keep the old in-session model working? Options: (a) deprecated-but-functional through v1.x, removed in v2.0; (b) hard cutover at v2.0; (c) feature flag in
plugin.json. - Multiple concurrent masques per user. A single user could have several
masques-mcp.spawncalls in flight (different masques for different parallel tasks). Allowed? Limit? Per-account quota? - The "feeling" loss. Mid-session don/doff felt like becoming the masque. Factory model feels like commissioning one. Is there a UX layer that preserves the embodied feel while keeping the process-boundary honesty?
- MCP isn't universal yet. Cursor and Cline support is recent; older agent frameworks won't have it. Mitigation: keep a fallback CLI binary that wraps the MCP server for shell-out integrations.
- Spawning subprocesses adds latency. Cold-start of Claude Agent SDK could be 1-3s. Mitigation: warm pool of pre-spawned blank workers that get the masque applied just-in-time.
- Payment infra is regulated. TigerBeetle + Solana = real money. Need to think about KYC, transaction monitoring, refund policies before mainnet. Mitigation: devnet-only through Phase 4, mainnet behind explicit "I understand" gate.
- The pivot strands existing users. Anyone who built on the v1.0 in-session model will need to migrate. Mitigation: deprecation period (Open Q §8), migration guide in docs.
This roadmap is a working draft. Refine the open questions, adjust phasing, then move to beads epics and begin Phase 0.
The agent-factory/spawn model above is one way to reach paid masques. A simpler
delivery route emerged: ship Masques as an MCP server. The monetization
then gates MCP tool calls
rather than spawning processes — cleaner than the escrow-on-don/settle-on-doff
design in tigerbeetle-integration.md.
Refined (still deferred) payment vision:
- Authors are paid per masque use — the marketplace goal, unchanged.
- Hosted on
masques.ai, alongside the OpenGander MCP stack (SSE + OAuth2). - Micropayments via Solana or TigerBeetle, with credit-card/wallet ↔ subscription budget escrow accounts: a user funds a budget; dons draw from it; authors get paid out. OAuth identity (Phase B) keys both reputation and the budget account.
- Phase A (the local, free, stdio MCP server) ships with none of this. Payment
is Phase C, design-only, and stays in
docs/future/.