From c87865ee0ea7186c511ffb3914eae28014537a14 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Mon, 19 Oct 2026 16:32:22 -0500 Subject: [PATCH] sage: row 64 D2 evidence, scratch-root builder, driver, check and both coder manifests (mos-0863 D2, #1557 comment 29228) --- agents/sage/work/queue-64/d2/d2-build.mjs | 47 +++++ agents/sage/work/queue-64/d2/d2-check.mjs | 22 +++ agents/sage/work/queue-64/d2/d2-check.txt | 2 + .../sage/work/queue-64/d2/d2-claude-run.txt | 6 + agents/sage/work/queue-64/d2/d2-comment.mjs | 34 ++++ agents/sage/work/queue-64/d2/d2-drive.mjs | 76 +++++++++ agents/sage/work/queue-64/d2/d2-pi-run.txt | 4 + .../queue-64/d2/manifest-claude-code.json | 112 ++++++++++++ agents/sage/work/queue-64/d2/manifest-pi.json | 103 +++++++++++ .../work/queue-64/d2/scratch-business-pi.json | 161 ++++++++++++++++++ 10 files changed, 567 insertions(+) create mode 100644 agents/sage/work/queue-64/d2/d2-build.mjs create mode 100644 agents/sage/work/queue-64/d2/d2-check.mjs create mode 100644 agents/sage/work/queue-64/d2/d2-check.txt create mode 100644 agents/sage/work/queue-64/d2/d2-claude-run.txt create mode 100644 agents/sage/work/queue-64/d2/d2-comment.mjs create mode 100644 agents/sage/work/queue-64/d2/d2-drive.mjs create mode 100644 agents/sage/work/queue-64/d2/d2-pi-run.txt create mode 100644 agents/sage/work/queue-64/d2/manifest-claude-code.json create mode 100644 agents/sage/work/queue-64/d2/manifest-pi.json create mode 100644 agents/sage/work/queue-64/d2/scratch-business-pi.json diff --git a/agents/sage/work/queue-64/d2/d2-build.mjs b/agents/sage/work/queue-64/d2/d2-build.mjs new file mode 100644 index 000000000..7a4581a22 --- /dev/null +++ b/agents/sage/work/queue-64/d2/d2-build.mjs @@ -0,0 +1,47 @@ +// D2 scratch root (mos-0863 D2, mos-0847): the example file plus the plug-in keys, nothing live. +// Usage: node d2-build.mjs writes d2/config/{config.json,businesses/mosaic-stack.json} +import { chmodSync, mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs"; +import { join } from "node:path"; +import { spawnSync } from "node:child_process"; +const LAND = "/mnt/storage/scratch/sage-r64/land"; +const D2 = "/mnt/storage/scratch/sage-r64/d2"; +const harness = process.argv[2]; +if (!["pi", "claude-code"].includes(harness)) throw new Error("harness?"); +const FAR = "2099-01-01"; +const secrets = join(D2, "secrets"); +mkdirSync(secrets, { recursive: true, mode: 0o700 }); +const w = (f, o) => { mkdirSync(join(f, ".."), { recursive: true }); writeFileSync(f, JSON.stringify(o, null, 2) + "\n"); }; +const doc = JSON.parse(readFileSync(join(LAND, "packages/business/examples/mosaic-stack.example.json"), "utf8")); +const edits = []; +// Every /home/you token path and YYYY-MM-DD date becomes a stand-in file and a far date. +const walk = (o, at) => { + for (const [k, v] of Object.entries(o)) { + if (v && typeof v === "object") walk(v, `${at}.${k}`); + else if (k === "file" && typeof v === "string" && v.startsWith("/home/you/")) { + const f = join(secrets, v.split("/").pop()); + writeFileSync(f, "placeholder-not-a-token"); chmodSync(f, 0o600); + o[k] = f; edits.push(`${at}.file -> stand-in`); + } else if ((k === "expires" || k === "rotateBy") && v === "YYYY-MM-DD") { o[k] = FAR; edits.push(`${at}.${k} -> ${FAR}`); } + } +}; +walk(doc, ""); +let n = 1; for (const r of Object.values(doc.roles)) if (r.tracker && "botId" in r.tracker) r.tracker.botId = n++; +if (doc.tracker?.sync && "botId" in doc.tracker.sync) doc.tracker.sync.botId = n++; +edits.push("botIds 1..n (example has 0)"); +doc.vars["tracker.baseUrl"] = "http://127.0.0.1:9"; doc.vars["gitea.baseUrl"] = "http://127.0.0.1:9"; edits.push("baseUrls -> 127.0.0.1:9"); +for (const m of Object.values(doc.launch.models)) m.provider = "anthropic"; +doc.launch.limits.models = { anthropic: doc.launch.limits.models["your-provider"] }; edits.push("your-provider -> anthropic"); +doc.roles.coder.vars = { ...doc.roles.coder.vars, harness, thinking: "medium" }; edits.push(`coder vars harness ${harness}, thinking medium`); +doc.plugins = { ...(doc.plugins ?? {}), harness: ["pi", "claude-code"] }; edits.push("plugins.harness [pi, claude-code]"); +const project = join(D2, "project"); +if (!existsSync(join(project, ".git"))) { + mkdirSync(project, { recursive: true }); + const g = (...a) => { const r = spawnSync("git", ["-c", "user.name=d2", "-c", "user.email=d2@example.invalid", "-C", project, ...a], { encoding: "utf8" }); if (r.status) throw new Error(r.stderr); }; + g("init", "-q", "-b", "main"); writeFileSync(join(project, "README.md"), "D2 scratch project\n"); g("add", "README.md"); g("commit", "-q", "-m", "one"); +} +doc.projects.stack.root = project; edits.push("projects.stack.root -> scratch repo on main"); +w(join(D2, "config", "config.json"), { configVersion: 1, environment: "development", dataRoot: join(D2, harness === "pi" ? "datapi" : "data"), + execution: { backend: "docker", provider: "zai", model: "glm-5.3-flash", adapter: "mock" } }); +w(join(D2, "config", "businesses", "mosaic-stack.json"), doc); +mkdirSync(join(D2, harness === "pi" ? "datapi" : "data"), { recursive: true, mode: 0o700 }); +console.log(edits.join("\n")); diff --git a/agents/sage/work/queue-64/d2/d2-check.mjs b/agents/sage/work/queue-64/d2/d2-check.mjs new file mode 100644 index 000000000..5268dc0ab --- /dev/null +++ b/agents/sage/work/queue-64/d2/d2-check.mjs @@ -0,0 +1,22 @@ +import { readFileSync } from "node:fs"; +import { createHash } from "node:crypto"; +const D2 = "/mnt/storage/scratch/sage-r64/d2", LAND = "/mnt/storage/scratch/sage-r64/land"; +const want = JSON.parse(readFileSync(`${LAND}/roles/coder.json`, "utf8")).skills; +for (const h of ["claude-code", "pi"]) { + const raw = readFileSync(`${D2}/manifest-${h}.json`); + const m = JSON.parse(raw); + const prompt = readFileSync(`${D2}/prompt-${h}.md`, "utf8"); + const names = (m.skills ?? []).map((s) => s.name); + let files = 0, bad = 0, inPrompt = 0; + for (const s of m.skills) for (const [path, sha256] of Object.entries(s.files)) { const f = { path, sha256 }; + files++; + const src = readFileSync(`${LAND}/skills/${s.name}/${f.path}`); + if (createHash("sha256").update(src).digest("hex") !== f.sha256) bad++; + const open = `\n`; + if (prompt.includes(open + src.toString("utf8"))) inPrompt++; + } + const markers = (prompt.match(/^\` marker in prompt.md, under \`## Skills\`. No credential value appears in either manifest or prompt. + +${fence} +${chk} +${fence} + +
manifest-claude-code.json + +${fence}json +${fs.readFileSync(D + "manifest-claude-code.json", "utf8").trim()} +${fence} +
+ +
manifest-pi.json + +${fence}json +${fs.readFileSync(D + "manifest-pi.json", "utf8").trim()} +${fence} +
+ +Sage`; +fs.writeFileSync("d2-comment.json", JSON.stringify({ body })); diff --git a/agents/sage/work/queue-64/d2/d2-drive.mjs b/agents/sage/work/queue-64/d2/d2-drive.mjs new file mode 100644 index 000000000..81d5b1ddf --- /dev/null +++ b/agents/sage/work/queue-64/d2/d2-drive.mjs @@ -0,0 +1,76 @@ +// D2 driver: one managed coder session on the scratch root, real modules from the land tree. +// Usage: node d2-drive.mjs . Prints no credential value. +import { readFileSync, existsSync, copyFileSync } from "node:fs"; +import { join } from "node:path"; +import { homedir } from "node:os"; +const LAND = "/mnt/storage/scratch/sage-r64/land"; +const D2 = "/mnt/storage/scratch/sage-r64/d2"; +const [harness, mode] = process.argv.slice(2); +const { Client } = await import(`${LAND}/packages/bus/src/client.mjs`); +const { readSessions, SESSION_CREDENTIALS } = await import(`${LAND}/packages/seat/src/session.mjs`); +const { bootConfig, loadSystem } = await import(`${LAND}/packages/cli/src/config.mjs`); +const { startHost, startTimeOf } = await import(`${LAND}/packages/cli/src/host.mjs`); +const { createLauncher } = await import(`${LAND}/packages/cli/src/launcher.mjs`); +const { AGENT_MARKERS } = await import(`${LAND}/packages/cli/src/transport.mjs`); + +const env = { ...process.env, MOSAIC_CONFIG: join(D2, "config", "config.json"), MOSAIC_ROLES_DIR: join(LAND, "roles"), MOSAIC_CLAUDE_BIN: join(homedir(), ".local/bin/claude") }; +for (const k of AGENT_MARKERS) delete env[k]; +delete env.NODE_TEST_CONTEXT; +for (const k of SESSION_CREDENTIALS.flat()) delete env[k]; +// The host's session credential file holds one name, CLAUDE_CODE_OAUTH_TOKEN. Loaded, never printed. +for (const line of readFileSync(join(homedir(), ".config/mosaic-dev/secrets/claude-session.env"), "utf8").split("\n")) { + const m = line.match(/^\s*(?:export\s+)?([A-Z_][A-Z0-9_]*)=(.*)$/); + if (m) env[m[1]] = m[2].replace(/^(['"])(.*)\1$/, "$2"); +} +console.log("credential names loaded:", SESSION_CREDENTIALS.flat().filter((k) => env[k]).join(",")); + +const business = "mosaic-stack"; +const logs = []; +const log = (l) => { logs.push(l); console.log("log:", l); }; +const system = loadSystem({ env }); +const boot = bootConfig({ system, businessId: business, env }); +const host = await startHost({ boot, business, log }); +const launcher = createLauncher({ host, system, env, sessionDefaults: { pollInterval: 100 }, log }); +let code = 0; +try { + await launcher.listen(); + const bind = async (role, run) => { + const b = await host.bindLaunch({ business, role, run, harness: "claude-code", pid: process.pid, startTime: startTimeOf(process.pid) }); + const c = new Client({ path: host.path, cap: b.cap }); + await c.call("role.claim"); + return { b, c }; + }; + const chief = await bind("chief", `chief-d2-${harness}`); + const cto = await bind("cto", `cto-d2-${harness}`); + const launched = await launcher.fromSession(chief.b.cap, "coder"); + console.log("launch:", JSON.stringify(launched)); + if (!launched.ok) throw new Error("launch refused"); + const run = launched.result.run; + const runDir = readSessions(boot.dataRoot ?? system.dataRoot).find((s) => s.run === run)?.runDir + ?? join(system.dataRoot, "launches", business, run); + const manifest = join(runDir, "bundle", "manifest.json"); + for (let i = 0; i < 100 && !existsSync(manifest); i++) await new Promise((r) => setTimeout(r, 100)); + copyFileSync(manifest, join(D2, `manifest-${harness}.json`)); + copyFileSync(join(runDir, "bundle", "prompt.md"), join(D2, `prompt-${harness}.md`)); + console.log("runDir:", runDir); + if (mode === "turn") { + const sent = await cto.c.call("message.send", { to: "coder", class: "REQUEST", body: "D2 check for row 64. Reply in one line: list the skill names in your Skills section, and nothing else. Don't use any tool." }); + const end = Date.now() + 240000; + let reply; + while (!reply && Date.now() < end) { + reply = (await cto.c.call("message.receive")).find((m) => m.in_reply_to === sent.id); + if (!reply) await new Promise((r) => setTimeout(r, 1000)); + } + console.log("reply:", reply ? JSON.stringify({ from_role: reply.from_role, from_run: reply.from_run, body: reply.body.slice(-600) }) : "NONE in 240 s"); + if (!reply) code = 3; + } else { + await new Promise((r) => setTimeout(r, 3000)); + } +} catch (e) { + console.log("error:", e.message); + code = 2; +} finally { + await launcher.close(); + await host.close(0); +} +process.exit(code); diff --git a/agents/sage/work/queue-64/d2/d2-pi-run.txt b/agents/sage/work/queue-64/d2/d2-pi-run.txt new file mode 100644 index 000000000..ba83bd65a --- /dev/null +++ b/agents/sage/work/queue-64/d2/d2-pi-run.txt @@ -0,0 +1,4 @@ +credential names loaded: CLAUDE_CODE_OAUTH_TOKEN +launch: {"ok":true,"result":{"run":"r3455505dd5da","instance":"coder","harness":"pi","model":"claude-sonnet-5-5"}} +runDir: /mnt/storage/scratch/sage-r64/d2/datapi/launches/mosaic-stack/r3455505dd5da +log: run r3455505dd5da (coder) ended: stopped diff --git a/agents/sage/work/queue-64/d2/manifest-claude-code.json b/agents/sage/work/queue-64/d2/manifest-claude-code.json new file mode 100644 index 000000000..2fa5a6c79 --- /dev/null +++ b/agents/sage/work/queue-64/d2/manifest-claude-code.json @@ -0,0 +1,112 @@ +{ + "bundleVersion": 1, + "business": "mosaic-stack", + "instance": "coder", + "definition": "coder", + "run": "rc13bcd555652", + "launchedBy": "chief", + "resolvedDigest": "5629393ba23a5318bb6b70568e78b79b36c7b388eb7a52ff088fcee9d870e604", + "harness": "claude-code", + "provider": "anthropic", + "model": "claude-sonnet-5-5", + "modelKey": "sonnet", + "thinking": "medium", + "route": "primary", + "routeReason": null, + "harnessVersion": "2.1.303 (Claude Code)", + "builtins": [ + "Read", + "Write", + "Edit", + "Bash", + "Grep", + "Glob" + ], + "typed": [ + "mcp__mosaic__send_message", + "mcp__mosaic__push_working", + "mcp__mosaic__request_review", + "mcp__mosaic__read_spec", + "mcp__mosaic__write_record", + "mcp__mosaic__raise_decision", + "mcp__mosaic__list_agents", + "mcp__mosaic__inbox", + "mcp__mosaic__trail" + ], + "untyped": [ + "task.update.assigned", + "task.scope.change" + ], + "webSource": null, + "skills": [ + { + "name": "ms-unslop", + "path": "/mnt/storage/scratch/sage-r64/d2/data/launches/mosaic-stack/rc13bcd555652/bundle/skills/ms-unslop", + "sha256": "0eace7c537ae711876cc82137aa5e4f84f1a2145676de8cfb2fe963f32efb530", + "files": { + "SKILL.md": "0eace7c537ae711876cc82137aa5e4f84f1a2145676de8cfb2fe963f32efb530" + } + }, + { + "name": "ms-sdlc", + "path": "/mnt/storage/scratch/sage-r64/d2/data/launches/mosaic-stack/rc13bcd555652/bundle/skills/ms-sdlc", + "sha256": "f81aa1adf33f9d46f9783df3eeec9f705c5b65c37d48d7708cdb923eac0c5478", + "files": { + "SKILL.md": "f81aa1adf33f9d46f9783df3eeec9f705c5b65c37d48d7708cdb923eac0c5478" + } + }, + { + "name": "ms-file-read", + "path": "/mnt/storage/scratch/sage-r64/d2/data/launches/mosaic-stack/rc13bcd555652/bundle/skills/ms-file-read", + "sha256": "28f9b76bb89f8aadfb3b8933255c54e360af741b050a7738cb0a904f7835a95e", + "files": { + "SKILL.md": "28f9b76bb89f8aadfb3b8933255c54e360af741b050a7738cb0a904f7835a95e" + } + }, + { + "name": "ms-file-write", + "path": "/mnt/storage/scratch/sage-r64/d2/data/launches/mosaic-stack/rc13bcd555652/bundle/skills/ms-file-write", + "sha256": "ad9ee2d00b87b2c6fa36b7863c0034b8883f7e1fa2aa5390e67121eda0165e14", + "files": { + "SKILL.md": "ad9ee2d00b87b2c6fa36b7863c0034b8883f7e1fa2aa5390e67121eda0165e14" + } + } + ], + "reliesOn": [ + "S0-1 command hook deny, no --bare", + "S0-2 hook wrapped as || exit 2", + "S0-3 a missing gate blocks through the wrapper", + "S0-4 timeout -k 2 10 || exit 2 with hook timeout 20", + "S0-5 bash is limited by the tool limit only" + ], + "gateTimeout": { + "n": 10, + "k": 2, + "hook": 20 + }, + "files": { + "prompt.md": "ac87d103061dc25a362e4df196ad06d73d9b0868ab1b4aa0ac59338e9b5b0332", + "policy.json": "94f5b3f5b26bc72c60f119c5a7c2b52219dbf6d3ea11153a15210fa1698bdb1c", + "tools.json": "18a2f015bdbf419ed7f6634724a68971f4ef3cee3bb9749c112681513b52a3b3", + "settings.json": "b1172a211542dba492cb5773afa3a2ce578af7503d13c04b4060ed0d38266ffa", + "mcp.json": "1cb0c79bce23651432d7374f5b030a8c3f5eb86273c55b207faf8897dbd996f5" + }, + "sources": { + "gate": { + "path": "/mnt/storage/scratch/sage-r64/land/packages/harness/src/gate.mjs", + "sha256": "a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b" + }, + "tools": { + "path": "/mnt/storage/scratch/sage-r64/land/packages/harness/src/tools.mjs", + "sha256": "051b0a699e9f034cc70c992f4dda546a982b6e55695ef1e001d32c240761c5a4" + }, + "claudeGate": { + "path": "/mnt/storage/scratch/sage-r64/land/packages/harness/src/claude-gate.mjs", + "sha256": "32b5090760c95eea0e1232ff36ec13a1d9b58335b2eade621196dec1ebdbe784" + }, + "mcpServer": { + "path": "/mnt/storage/scratch/sage-r64/land/packages/harness/src/mcp-server.mjs", + "sha256": "ce0107c3b21e07925b6543b6b925da8b8768823448d4fcf30b620883cfd2d39e" + } + } +} diff --git a/agents/sage/work/queue-64/d2/manifest-pi.json b/agents/sage/work/queue-64/d2/manifest-pi.json new file mode 100644 index 000000000..c82d78d2b --- /dev/null +++ b/agents/sage/work/queue-64/d2/manifest-pi.json @@ -0,0 +1,103 @@ +{ + "bundleVersion": 1, + "business": "mosaic-stack", + "instance": "coder", + "definition": "coder", + "run": "r3455505dd5da", + "launchedBy": "chief", + "resolvedDigest": "caa2d2e17ae04a5e124aca80cab28bb1e14aed687074838992c227b746da21ba", + "harness": "pi", + "provider": "anthropic", + "model": "claude-sonnet-5-5", + "modelKey": "sonnet", + "thinking": "medium", + "route": "primary", + "routeReason": null, + "harnessVersion": "0.85.1", + "builtins": [ + "read", + "write", + "edit", + "bash", + "grep", + "find", + "ls" + ], + "typed": [ + "send_message", + "push_working", + "request_review", + "read_spec", + "write_record", + "raise_decision", + "list_agents", + "inbox", + "trail" + ], + "untyped": [ + "task.update.assigned", + "task.scope.change" + ], + "webSource": null, + "skills": [ + { + "name": "ms-unslop", + "path": "/mnt/storage/scratch/sage-r64/d2/datapi/launches/mosaic-stack/r3455505dd5da/bundle/skills/ms-unslop", + "sha256": "0eace7c537ae711876cc82137aa5e4f84f1a2145676de8cfb2fe963f32efb530", + "files": { + "SKILL.md": "0eace7c537ae711876cc82137aa5e4f84f1a2145676de8cfb2fe963f32efb530" + } + }, + { + "name": "ms-sdlc", + "path": "/mnt/storage/scratch/sage-r64/d2/datapi/launches/mosaic-stack/r3455505dd5da/bundle/skills/ms-sdlc", + "sha256": "f81aa1adf33f9d46f9783df3eeec9f705c5b65c37d48d7708cdb923eac0c5478", + "files": { + "SKILL.md": "f81aa1adf33f9d46f9783df3eeec9f705c5b65c37d48d7708cdb923eac0c5478" + } + }, + { + "name": "ms-file-read", + "path": "/mnt/storage/scratch/sage-r64/d2/datapi/launches/mosaic-stack/r3455505dd5da/bundle/skills/ms-file-read", + "sha256": "28f9b76bb89f8aadfb3b8933255c54e360af741b050a7738cb0a904f7835a95e", + "files": { + "SKILL.md": "28f9b76bb89f8aadfb3b8933255c54e360af741b050a7738cb0a904f7835a95e" + } + }, + { + "name": "ms-file-write", + "path": "/mnt/storage/scratch/sage-r64/d2/datapi/launches/mosaic-stack/r3455505dd5da/bundle/skills/ms-file-write", + "sha256": "ad9ee2d00b87b2c6fa36b7863c0034b8883f7e1fa2aa5390e67121eda0165e14", + "files": { + "SKILL.md": "ad9ee2d00b87b2c6fa36b7863c0034b8883f7e1fa2aa5390e67121eda0165e14" + } + } + ], + "reliesOn": [ + "S0-1 tool_call block", + "S0-2 a throw blocks", + "S0-3 a missing -e refuses to start", + "S0-4 external wall clock plus agent_end check", + "S0-5 bash is limited by the tool limit only" + ], + "gateTimeout": null, + "files": { + "prompt.md": "ba0b4971d4ee8ed230840472b998aa2325c1917f8c922c20cb4f840a3106fbbf", + "policy.json": "eca86aeacf131c1d5d0cd83ffc58c03b03b013fd2712acdd3187cbcb222c43dd", + "tools.json": "18a2f015bdbf419ed7f6634724a68971f4ef3cee3bb9749c112681513b52a3b3" + }, + "sources": { + "gate": { + "path": "/mnt/storage/scratch/sage-r64/land/packages/harness/src/gate.mjs", + "sha256": "a74ef2db4093c0c797ba9e7e28e4e4df0ceac9040385f00e60a273f39af9610b" + }, + "tools": { + "path": "/mnt/storage/scratch/sage-r64/land/packages/harness/src/tools.mjs", + "sha256": "051b0a699e9f034cc70c992f4dda546a982b6e55695ef1e001d32c240761c5a4" + }, + "piExtension": { + "path": "/mnt/storage/scratch/sage-r64/land/packages/harness/src/pi-extension.mjs", + "sha256": "fcba4b8dfd9dde947a79f88376d880f383e2a04ee3c0a9ba2fa5af641fe61b35" + } + } +} diff --git a/agents/sage/work/queue-64/d2/scratch-business-pi.json b/agents/sage/work/queue-64/d2/scratch-business-pi.json new file mode 100644 index 000000000..f2cd1c377 --- /dev/null +++ b/agents/sage/work/queue-64/d2/scratch-business-pi.json @@ -0,0 +1,161 @@ +{ + "businessVersion": 1, + "id": "mosaic-stack", + "human": "jason", + "arbiters": { + "delivery": "pm", + "technical": "cto" + }, + "projects": { + "stack": { + "root": "/mnt/storage/scratch/sage-r64/d2/project" + } + }, + "vars": { + "tracker.baseUrl": "http://127.0.0.1:9", + "gitea.baseUrl": "http://127.0.0.1:9" + }, + "tracker": { + "sync": { + "bot": "bot-mosaic-stack-sync", + "botId": 5, + "credentials": { + "vikunja": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/sync-vikunja.token", + "expires": "2099-01-01" + } + } + }, + "labels": {} + }, + "roles": { + "pm": { + "definition": "pm", + "holder": "sage", + "tracker": { + "bot": "bot-mosaic-stack-pm", + "botId": 1 + }, + "credentials": { + "gitea": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/pm-gitea.token", + "rotateBy": "2099-01-01" + }, + "vikunja": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/pm-vikunja.token", + "expires": "2099-01-01" + } + }, + "vars": { + "model": "opus" + } + }, + "cto": { + "definition": "cto", + "holder": "darkwing", + "tracker": { + "bot": "bot-mosaic-stack-cto", + "botId": 2 + }, + "credentials": { + "gitea": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/cto-gitea.token", + "rotateBy": "2099-01-01" + }, + "vikunja": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/cto-vikunja.token", + "expires": "2099-01-01" + } + }, + "vars": { + "model": "opus" + } + }, + "coder": { + "definition": "coder", + "tracker": { + "bot": "bot-mosaic-stack-coder", + "botId": 3 + }, + "credentials": { + "gitea": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/coder-gitea.token", + "rotateBy": "2099-01-01" + }, + "vikunja": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/coder-vikunja.token", + "expires": "2099-01-01" + } + }, + "vars": { + "model": "sonnet", + "harness": "pi", + "thinking": "medium" + } + }, + "reviewer": { + "definition": "reviewer", + "tracker": { + "bot": "bot-mosaic-stack-reviewer", + "botId": 4 + }, + "credentials": { + "gitea": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/reviewer-gitea.token", + "rotateBy": "2099-01-01" + }, + "vikunja": { + "file": "/mnt/storage/scratch/sage-r64/d2/secrets/reviewer-vikunja.token", + "expires": "2099-01-01" + } + }, + "vars": { + "model": "opus" + } + }, + "chief": { + "definition": "chief-of-staff", + "vars": { + "model": "opus" + } + }, + "assistant": { + "definition": "assistant", + "holder": "mos", + "vars": { + "model": "opus" + } + } + }, + "launch": { + "by": "chief", + "instances": [ + "coder", + "reviewer" + ], + "models": { + "opus": { + "provider": "anthropic", + "model": "claude-opus-5-5" + }, + "sonnet": { + "provider": "anthropic", + "model": "claude-sonnet-5-5" + } + }, + "limits": { + "models": { + "anthropic": { + "claude-opus-5-5": 4, + "claude-sonnet-5-5": 4 + } + } + } + }, + "plugins": { + "harness": [ + "pi", + "claude-code" + ] + } +}