Factory Missions — readiness plan and mission catalogue
Factory Missions on Dark Cosmos — readiness plan + mission catalogue
Section titled “Factory Missions on Dark Cosmos — readiness plan + mission catalogue”Written 2026-09-30 from Chris’s brief: “come up with suitable missions we can run in the factory droid interface, for example a mission to go through and update all the old looking graphics to the ones made by Opus 5.5.” Companion plan:
2026-09-30-cheap-model-subagent-eval.md(which model to put in each mission seat).
0. What a Mission actually is (verified against docs.factory.com, 2026-09-30)
Section titled “0. What a Mission actually is (verified against docs.factory.com, 2026-09-30)”Not a prompt and not a skill. /missions (alias /mission) starts a three-phase product feature:
- Conversation — Droid interrogates the goal, pushes back, asks for constraints.
- Plan — features grouped into milestones, plus the skills each part needs (it reuses existing skills and writes new ones during planning).
- Mission Control — an orchestrator spawns worker agents (roughly one run per feature) and validator agents (2 runs per milestone: scrutiny + user-testing). You can pause it, talk to it, tell it to mark a stuck item done, or re-scope mid-flight.
Cost heuristic from the docs: total runs ≈ #features + 2 × #milestones — a floor, not a ceiling,
because validation creates fix-features.
Headless form (this is what makes missions schedulable):
droid exec --mission --auto high \ --worker-model glm-5.3 --worker-reasoning-effort high \ --validator-model claude-opus-5-5 --validator-reasoning-effort high \ -f mission.mdMission Mode requires --auto high or --skip-permissions-unsafe. Settings equivalents:
missionOrchestratorModel, missionModelSettings.{workerModel,validationWorkerModel,skipScrutiny,skipUserTesting}.
Missions inherit MCP servers, skills, hooks, custom droids and AGENTS.md/CLAUDE.md. That
inheritance is the whole reason §1 exists.
1. Pre-flight — three gaps that must close before the first mission
Section titled “1. Pre-flight — three gaps that must close before the first mission”1.1 The 23 bh-* skills are invisible to Droid (blocking)
Section titled “1.1 The 23 bh-* skills are invisible to Droid (blocking)”Droid discovers project skills in .factory/skills/, .agents/skills/, .agent/skills/ and
personal ~/.factory/skills/. This repo’s skills live in .claude/skills/ — none of them are
loaded, in this session or any mission worker. Same for .claude/agents/ (bh-implementer,
bh-reviewer, bh-visual-qa, bh-feedback-triage), which Droid reads from .factory/droids/.
There is no .factory/ directory in the repo at all today.
Chris’s call (2026-09-30): port them as Factory-native copies, not symlinks.
- Use the installed
port-claude-code-artifact-to-droidskill for the mapping rules. .claude/skills/bh-*/SKILL.md→.factory/skills/bh-*/SKILL.md. Frontmatter differences that matter: Droid wantsname+description(routing surface),allowed-tools(metadata only, not a sandbox),disable-model-invocation: truefor anything with side effects — set that onbh-deploy,bh-appstore-release,bh-live-debug-deployso no mission worker can ship a build..claude/agents/*.md→.factory/droids/*.md. Model pins change:opus→claude-opus-5-5,sonnet→claude-sonnet-5-5./droidshas a built-in Import from Claude Code flow that does this mapping; run it, then hand-check the model IDs and tool lists.- Drop provider-specific internals during the port (Claude Code tool names:
Write→Create,Bash→Execute,ApplyPatchadded for OpenAI models). - Keep
.claude/intact and working — Claude Code sessions still use it. The repo.gitignorealready re-includes.claude/{agents,hooks,scripts,skills,workflows}; add the same re-include for.factory/so the ported copies are tracked and Toby gets them. - Drift risk, name it out loud: two real copies means two sources of truth. Mitigation: a
scripts/test/skills-parity.test.mjsthat diffs the instruction bodies (ignoring frontmatter) and fails the gate when they diverge. Cheap, and it converts a silent fork into a red test.
1.2 Mission QA cannot drive a Godot game out of the box
Section titled “1.2 Mission QA cannot drive a Godot game out of the box”Missions validate by exercising the running app. Factory ships agent-browser (web/Electron) and
tuistory (terminal UIs). Dark Cosmos is neither, so the default user-testing validator has nothing
to drive and will either no-op or thrash — this is exactly the “worker keeps failing validation”
troubleshooting case in the docs.
The repo is unusually well equipped to fix this, because a programmatic way to play the game already
exists: ai/skilled_auto_player.gd, scripts/soak.sh, tools/story_auto/story_trace.gd,
scripts/ui-sweep.sh, tools/sim_bench, scripts/gate.sh, scripts/check-test-count.sh.
Build scripts/mission-qa.sh — one command, logs to disk, modest resource use, exactly the
shape the Missions docs ask for:
scripts/mission-qa.sh [--fast|--full] 1. scripts/gate.sh (GUT suite + determinism + count guard + presets) 2. scripts/soak.sh (N seeded survival runs, invariant + death-cause sweep) 3. tools/story_auto/story_trace.gd (a story run that must actually finish; nonzero if not) 4. scripts/ui-sweep.sh (only when --full or UI files changed; RMSE vs baselines) → everything tees to reports/mission-qa/<utc-timestamp>/*.log, exit nonzero on any failureThen reference it from a new .factory/skills/bh-mission-qa/SKILL.md so validators find it by
description instead of guessing. Until that exists, run missions with
missionModelSettings.skipUserTesting: true and keep scrutiny on (scrutiny is code review,
which works fine here).
⚠️ mission-qa.sh must adopt the project.godot snapshot-and-restore that gate.sh and
economy-careers.sh already do — any windowed Godot invocation can silently mangle that file.
1.3 Autonomy, and the things a mission must never touch
Section titled “1.3 Autonomy, and the things a mission must never touch”Mission Mode needs --auto high. On this repo that is a real hazard: high autonomy permits
git push, and two developers now share main. Non-negotiables to encode in AGENTS.md/CLAUDE.md
before the first run (they are conventions today, enforced by nothing):
- Never
git pushfrom a mission worker. Missions work on a branch or a worktree (droid exec -w <name>); Chris or Toby merges. The 2026-09-27 incident where a subagent pushed toorigin/mainagainst instructions is the precedent. - Never
cp/rsyncintoplatform/tvos/(replaces a symlink, forks the tree). - Never hand-edit
sim/constants.gdBUILD(scripts/bump-build.shis the only writer). - Never re-pin a determinism baseline — that needs
bh-determinism-repinand a human call. - No deploys, no App Store uploads, no
wranglerwrites, no remote-config publish. - Ban them mechanically too:
permissionRulesin.factory/settings.json(droid rules check --command 'git push origin main' --jsonpreviews a decision before you trust it).
2. Model seating for a mission
Section titled “2. Model seating for a mission”Three independent seats, each its own cost/quality tradeoff. Multipliers from the live catalogue:
| Seat | Recommendation | Multiplier | Why |
|---|---|---|---|
Orchestrator (missionOrchestratorModel) |
claude-opus-5-5 @ medium |
1.6× | Planning is where Missions pay off, and it is a small share of total runs. Chris’s own finding: 5.5 is materially better at graphics/perf reasoning. |
Worker (workerModel) |
Per-mission; see the catalogue’s “worker” column. Default glm-5.3 @ high |
0.56× | Bulk of the runs, so bulk of the cost. The companion eval plan exists to replace this guess with data. |
Validator (validationWorkerModel) |
claude-opus-5-5 @ high |
1.6× | Validation is the only thing standing between a false-green worker report and main. Do not economise here — see bullet-heaven-subagent-model-haiku and the Wyrm-XP false-green in bullet-heaven-claude-capability-map. |
Note: auto (Factory Router) cannot reach Opus 5.5 — its candidate pool tops out at
claude-opus-5 (memory reference_factory_router_pool.md). Pin 5.5 explicitly in the mission
settings; do not assume auto will find it.
3. The mission catalogue
Section titled “3. The mission catalogue”Ranked by (value × fit), where “fit” means: bounded, decomposable into features, and objectively validatable by a script. Every mission below assumes §1 is done.
M1 — Art refresh: every old-looking asset re-directed by Opus 5.5 ★ Chris’s idea
Section titled “M1 — Art refresh: every old-looking asset re-directed by Opus 5.5 ★ Chris’s idea”Goal. Nothing in the shipping game still reads as pre-Nova/pre-liquid-glass. Per Chris’s call:
fresh Opus 5.5-directed generation per asset, with no existing set frozen as the target — 5.5 acts
as art director per asset against DESIGN.md’s two real pillars (single confident cyan accent;
fixed per-kind identity colour), not as a copier of render/*/nova/.
Why it is a mission and not a session. It is ~30-50 discrete assets, each an independent unit of
work with the same repeatable loop, and it has a real gate (ui-sweep + an in-engine windowed
check). That is the textbook Missions shape.
Known inventory to triage in the planning phase (the mission’s first feature is the audit, not a guess):
render/enemy_sprites/top level:ghost.png,orbiter.png,spider.png,warden.png— July 2026 Recraft-era, sitting beside the ~112-file Nova set inrender/enemy_sprites/nova/.render/ship_sprites/ship3d_*.png— 11 hull bakes from 1 July, beside the newerrender/ship_sprites/nova/.- Obsidian cruiser is on a placeholder Aurum-copy sprite (art-pipeline doc §4.1).
- Ship Tilt flipbook only exists for
cobalt— 5 angle frames; every other hull is unhandled (§4.3). - 12 promotable enemy types get a generic elite buff and no bespoke art (§4.6).
- Icons, the upgrade-tier indicator (§4.2 — genuinely undesigned, exclude, see below).
Per-asset feature loop (this is the skill the planning phase should produce,
.factory/skills/bh-art-refresh/SKILL.md):
- Classify via the art-pipeline decision tree: swarm-scale → procedural, never a baked-glow sprite;
hero/singular with an in-engine source →
tools/ship_previewbake; genuinely one-off → generate. - Quote the exact hex values from
data/bible.json/NeonThemeinto the prompt (the colour-discipline fix in art-pipeline §2c.2), never free-associate colour. - Produce it: prefer the proven in-repo route — code-drawn PIL designs in
tools/nova_units/nova_unit_designs.py(how the 5 drone sprites and the Nova roster were made,--preview-*then--export-*); external generation only where hand-authored detail genuinely beats a procedural shape. tools/glow_bakeif and only if boss/hero scale.- Verify windowed, through the matching preview tool. Headless Godot cannot show the real pixels; the gate never compiles shaders.
git diff project.godotimmediately after any windowed run.scripts/ui-sweep.shfor UI-visual changes; re-bless only after a human eyeballs it.- Apply the
bh-polish-auditfour-question lens before calling the asset done.
Milestones. (1) Audit + style brief + the skill itself. (2) Enemy sprites. (3) Ship hulls + Obsidian cruiser + tilt flipbooks. (4) Icons/UI art. (5) Final sweep + device check.
Validation. mission-qa.sh --full per milestone; plus a contact sheet PNG per milestone for
Chris, because the real acceptance test is his eye and a validator agent cannot substitute for it.
Explicitly out of scope (mission planning must not silently absorb these): the upgrade-tier indicator (undesigned, needs a design pass with Chris) and the full OKLCH palette overhaul (subjective, flagged “wants Chris’s eye”).
Worker model. claude-opus-5-5 — this is precisely the graphics work where Chris has found 5.5
materially better, and the asset count is low enough that the multiplier is affordable. Do not
economise this one.
Rough size. ~25 features / 5 milestones ≈ 35 runs floor.
Risk. Medium. Art is reversible and gated by Chris’s eye; the danger is volume of near-miss assets, which the style-brief feature (milestone 1) exists to prevent.
M2 — NEXT_TASKS.md debt sweep
Section titled “M2 — NEXT_TASKS.md debt sweep”Goal. Close the mechanical, already-diagnosed items in the housekeeping backlog.
Pre-scoped by earlier sessions, each with a named file and line:
fx/fx_manager.gd:578_spawn()allocates a Dictionary per particle → parallel typed arrays.sim/enemy_attacks.gd— six per-tick passes rebuild a Dictionary wholesale; mirrorupdate_lancers’ in-place mutation.ui/weapon_panel.gd:133— per-frame full weapon-view build to read oneglyphfield.cooldown_frac()duplicated across ~13sim/weapon_*.gd→ aWeaponCooldown.frachelper.tools/ui_sweep/sweep.gdmissing the one-lineMetaStore.disk_io_enabled = falseguard.- ui-sweep captures under-represent the device (1920×1080 unstretched vs 1280×720 base; linear not
sRGB) →
size_2d_override+ sRGB conversion + re-bless. - The windowed shader-compile smoke check the gate still lacks.
Why a mission. Perfectly decomposable, zero design judgement, and gate.sh is a hard objective
judge. This is the best first mission to run — lowest risk, and it exercises the whole apparatus.
Validation. mission-qa.sh --full. Determinism baselines must hold untouched: any worker that
wants a re-pin has failed, not succeeded.
Worker model. The eval’s winner; glm-5.3 until then. Milestones: 3 (perf items / tooling
items / test-and-gate items) so validation lands often.
Size. ~8 features / 3 milestones ≈ 14 runs. Risk: low.
M3 — Remote-config tunable batches
Section titled “M3 — Remote-config tunable batches”Goal. Continue converting consts to remote tunables, batch by batch (84 live on BUILD 230).
bh-tunable-batch already encodes the repeatable loop, and tools/remote_config/liveness_probe.gd
gives a per-batch objective check. A mission is a near-mechanical driver of an existing skill — the
cheapest possible proof that mission orchestration works on this repo.
Guardrails to state in the mission file: publishing a live config patch is out of scope (human
step); the BIOMASS_TRIGGER <= BIOMASS_TARGET cross-key validation gap is open and must be checked
by eye per patch; never add an unverified-dead field as a tunable (EXCLUDED_FIELDS in
content/bible_overlay.gd).
Size. ~6 features / 2 milestones ≈ 10 runs. Worker: cheap model. Risk: low.
M4 — main.gd and sim.gd decomposition
Section titled “M4 — main.gd and sim.gd decomposition”Goal. main.gd._new_run() is ~510 lines mixing ~8 concerns; main.gd is 158KB; sim/sim.gd
has regrown since the 11-module split (next carve-out plan already written in
docs/research/2026-09-28-code-cleanup-audit.md §3).
Pure code motion, no behaviour change — which makes it ideal mission work and dangerous in exactly one way: pure relocation must never move the determinism baseline. Make that the mission’s stated invariant and let every milestone’s validation prove it.
Milestones. One per extracted helper (_setup_sim_and_content, _setup_renderers,
_setup_ui_and_hud, _setup_dev_overlays), then the sim carve-out. Frequent milestones here are
the point: a drifted refactor is expensive to unwind.
Size. ~10 features / 5 milestones ≈ 20 runs. Worker: mid-tier — mechanical but wide-context. Risk: medium (large diffs, easy to lose a line in the noise; validator model matters).
M5 — Test-coverage hardening against the false-green class
Section titled “M5 — Test-coverage hardening against the false-green class”Goal. Kill the specific failure mode this project has actually shipped twice: a test that asserts
the robust quantity and skips the fragile one. Story/Tutorial enemies awarded zero XP for months;
Wyrm kills awarded ~0 XP while test_wyrm_death_pays_the_kill_economy_once_not_per_segment passed
green (it checked kills and gold, both flat constants, never XP, the only biomass-derived value).
Features. For every spawn path in the codebase, a test that drives the real
spawn→kill→_sweep_dead cycle and asserts awarded XP (never hand-sets pending_levelups or enemy
HP). Then the same lens on drones, elites, bosses and co-op payouts.
The acceptance bar that makes this mission worth running: every new test must be shown to fail on the broken code — a worker has to demonstrate the mutation, not just a green run. Encode that in the mission file; it is the one instruction that converts test-writing from theatre into evidence.
Size. ~12 features / 3 milestones ≈ 18 runs. Worker: needs a model that can reason about the sim’s tick ordering — mid/high tier. Risk: low (tests only), value: high.
M6 — Site + docs accuracy sweep (~/Claude/bullet-heaven-site)
Section titled “M6 — Site + docs accuracy sweep (~/Claude/bullet-heaven-site)”Goal. Keep the public site’s rosters and stats sourced from data/bible.json + live sim consts
instead of drifting. It drifted badly once already: 7→16 weapons, 17→25 enemies, boss HP off by 2-4×.
Cross-repo, prose-heavy, objectively checkable against the bible. Two hard rules for the mission
file: deploy only via that repo’s scripts/deploy-site.sh, never a raw wrangler pages deploy .;
and verify the specific page is served (sitemap grep), because an Active build proves nothing —
the site served a 2.5-month-stale snapshot while everyone believed pushes deployed.
Marketing copy also inherits the veracity rules in dark-cosmos-launch-assets (no “14 elements /
91 reactions”; ~6 wielded elements, ~10 named reactions, frame reactions as a mechanic with no
count).
Size. ~8 features / 2 milestones ≈ 12 runs. Worker: cheap (prose + lookups). Risk: low,
but it writes to a public surface — keep disable-model-invocation on any deploy skill.
M7 — Dead-code and dead-field removal
Section titled “M7 — Dead-code and dead-field removal”Catalogued and confirmed-dead already: ELITE_XP_MULT, the boss-pacing consts
(BOSS_FIRST_TIME/BOSS_INTERVAL/SWARM_BURST_*/ELITE_BOSS2_*/ELITE_WARDEN_*),
Elemental.apply() plus its ContentDB.reaction() dependency and three test files, and every field
marked dead: in EXCLUDED_FIELDS.
Blocked on Chris’s calls (delete vs rewire, and whether a future reaction-based mode is ever coming). Run it as a mission after those calls, or let the planning conversation surface them as explicit decisions for Chris before any feature is approved. Size: ~6 features / 2 milestones. Risk: low once decided.
Do NOT run as missions
Section titled “Do NOT run as missions”- Anything requiring a determinism re-pin. Needs
bh-determinism-repinand a human judgement about whether the divergence is legitimate. There is still no per-tick trace tool, so the only diagnostic is revert-and-recheck. - Balance and feel. The capability map scores live gameplay feel/balance verification 3/10 and names it structural, not a skill gap. The OKLCH palette overhaul, the frigate/cruiser balance pass and the crit multiplier tuning all want Chris’s eye.
- Open design questions. The 4 unanswered questions in
2026-07-09-dimension-choice-popup-design.md; the shared-ModStateco-op call; whose save P2 uses. A mission will happily invent an answer. - Anything that deploys. Store uploads, TestFlight, remote-config publishes, site deploys.
4. Execution order
Section titled “4. Execution order”- §1 pre-flight (skills + droids port,
mission-qa.sh, permission rules, parity test). Do this as a normal session, not a mission. - M3 (tunable batch) as the smoke test — smallest, most mechanical, existing skill, objective probe. Prove the apparatus.
- M2 (debt sweep) as the first real mission.
- M1 (art refresh) — the headline one, once the loop is trusted and the eval has told us what to seat where.
- M5, M4, M6, M7 as capacity allows.
Log each mission’s actual runs, wall time and credit spend against the
#features + 2 × #milestones estimate. After three missions that table is worth more than any
guidance in this document.