1// The bootstrap prompt handed to an agent: the one place its wording lives.2// The origin is the server the agent should talk to (the request's origin3// on the hosted site, 127.0.0.1:8000 in a checkout).45/** The public base URL of this server: `MOSAIC_PUBLIC_URL` when hosted,6 * else the local dev server. */7export function publicOrigin(): string {8 return (Deno.env.get("MOSAIC_PUBLIC_URL") ?? "http://127.0.0.1:8000")9 .replace(/\/$/, "");10}1112/** Install line plus the prompt to paste, for a given origin. */13export function promptFor(origin: string, day?: string | null): string {14 const o = origin.replace(/\/$/, "");15 return [16 "Install the mosaic MCP server (streamable HTTP, no auth) and play:",17 "",18 ` claude mcp add --transport http mosaic ${o}/mcp`,19 "",20 "Then paste this into the agent:",21 "",22 ...bootstrap(o, day).map((l) => " " + l),23 "",24 `Spectate at ${o}/ (live). Replay a finished game at ${o}/?replay=<game_id>; past days at ${o}/calendar.`,25 "",26 ].join("\n");27}2829/** The prompt itself (what "copy prompt" copies). */30export function bootstrap(origin: string, day?: string | null): string[] {31 const o = origin.replace(/\/$/, "");32 const hosted = Deno.env.get("MOSAIC_DAILY") === "1";33 const target = day34 ? `join today's field (${day}): call list_games and join the game whose day is ${day}`35 : "call list_games; if a field is playing, join it";36 const noField = hosted37 ? "If no field is listed yet, today's is still being prepared: wait a few"38 : "If no field is playing, start one (start_mosaic with kind=field, chunks=3,";39 const noField2 = hosted40 ? "minutes and call list_games again. join gives you an"41 : "grow={every_minutes: 30}) and join it. join gives you an";42 return [43 `Using the mosaic MCP server at ${o}/mcp: ${target}. This machine plays under`,44 "an identity: an ed25519 key at ~/.config/mosaic/identity.json (mint it if absent;",45 `any ed25519 tool works, snippets at ${o}/identity, plain text ${o}/identity.md).`,46 `Mint a bearer token at ${o}/api/keys/auth with it and send the token as the`,47 "Authorization header on your MCP requests (or, if you cannot set headers, join",48 "with machine_id, public_key and proof as the spec says). Join with a session",49 `label if several agents run here and the model you are, e.g. model=claude-opus-5. ${noField}`,50 noField2,51 "agent id and a seed tile at a random spot; every reveal, commit and retract",52 "carries that agent id. Play autonomously with observe (agent=<your id>:",53 "your territory and its surroundings), reveal and commit. Read the tool",54 "descriptions for the rules (they are per line of a tile). Reveal your seed",55 "tile first; commit in batches with a one-line intent; when a tile alone is",56 "ambiguous, expand from a tile your group solved or commit a guess; when you",57 "meet another agent your territories merge and you share a frontier. The field",58 "grows during the day and unexplored tiles appear only once your territory",59 "reaches them: observe again after every batch. Your health is your wrong-rate",60 "over your last 2,000 committed cells: under 1.5% healthy, 1.5-4% warning, 4%",61 "death for the day (your territory stays, you write no more). Guessing bleeds",62 "you: commit what you can prove, guess only when a tile is genuinely ambiguous.",63 "Keep playing until observe reports the game ended, without asking me anything.",64 ];65}6667export function bootstrapText(origin: string, day?: string | null): string {68 return bootstrap(origin, day).join("\n");69}