10 · E2E walking skeleton: brief → finished game, fully autonomous #11
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cmoriarty/trog#11
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The milestone-closing integration ticket.
trog run "a cozy fishing game with a day/night cycle"produces a tiny finished Phaser game with nobody watching:Done when: one command, zero intervention, playable URL at the end.
E2E walking skeleton: brief → finished game, fully autonomousto 10 · E2E walking skeleton: brief → finished game, fully autonomousDesign note (from 03.1/03.2 work): where OpenCode fits
Two harnesses, one brain. The graph and OpenCode are both host applications around the same llama.cpp endpoint — the model never speaks MCP or LangChain; each host does its own schema-binding and tool loop.
_research_invoke), critiqueDivision: ideation / preproduction / slice spec / alpha-beta reviews stay direct ChatOpenAI (document work — current code already right). Production / alpha / beta implementation nodes change character in this ticket: instead of
llm.ainvoke → commit doc, a node doesNode = producer; OpenCode = the developer seat hired for the task. Git + ledger remain the only truth crossing the boundary — LangGraph can't checkpoint inside an OpenCode session and doesn't need to; the workspace result lands in git, which is what the git-is-truth design already assumes.
Session mechanics — decide in this ticket:
opencode run "<task>"— headless one-shot in a workspace container; simple, transcript on exitopencode serve+ HTTP API/SDK — long-lived service, per-task sessions, streamable eventsLean (2): ticket 08's "opencode-style live feed" then becomes literally OpenCode's event stream surfaced in the studio, not a reimplementation.
Wiring already decided elsewhere: OpenCode confirmed as the code agent (03.1 audit — revisit trigger: persistent tool-call failures → cheap A/B vs Qwen Code, same endpoint config). Point sessions at Phaser 4's in-repo
skills/; agent-facing phase prompts ship as SKILL.md in the game repo. Websearch MCP (common-mcps, 03.2) can mount into OpenCode config too — same endpoint the graph's toolbelt uses.Budget note from the firefly run (issue #5): gate loops already cost ~40 min; OpenCode build sessions add real wall-clock on top — plan run budgets accordingly.
Design note: llama-swap belongs here (if anywhere), not in the conductor
Evaluated (2026-07-24) whether llama-swap should replace the asset conductor's brain up/down — verdict: no. It's demand-driven OpenAI-endpoint multiplexing; the conductor's swap is a scheduled drain window against non-LLM ComfyUI seats, and demand-driven semantics are exactly wrong there (a brain request mid-drain would evict a generator mid-render; trog wants runs to PARK instead — the
model_swap_interrupthandshake).Where it fits: this ticket. If the OpenCode seat wants a coder-tuned model while the graph brain runs Qwen-general, that's LLM-vs-LLM arbitration on the same GPUs with the same OpenAI protocol — llama-swap's home turf:
modelfieldBRAIN_URLand OpenCode's endpoint both point at the proxy; each names its modelDecide during implementation whether OpenCode actually benefits from a different model than the brain (the 03.1 audit found Qwen3.6-27B strong for both roles — a second model must earn its VRAM swap cost with a measurable coding win).
Moved from #8 (studio feed): production-graph adoption of the feed contracts — (1) maintain the
todosstate key ([{text, status: pending|in_progress|done}], see phasewalk for the reference implementation) so the studio todo strip tracks real runs; (2) interrupt-node steering — the feed currently steers by stop-and-fold (halt run, append guidance, rerun on checkpointed state, verified working); graph-levelinterrupt()nodes would fold guidance mid-node without killing the run. Both belong with the walking-skeleton work.First end-to-end run: failed, deliberately stopped
The walking skeleton is built and deployed; the first real
trog run "a cozy fishing game with a day/night cycle"was abandoned rather than finished, because the art it generated is unusable. Writing down what worked, what broke, and what that cost.What is in place
opencode/— the code agent seat, pinnedopencode-ai@1.18.7. One container per session (opencode servebinds a server to one project directory, so a shared server could only ever build one game), raised and torn down by the orchestrator like a generator seat.trog_lib/codeseat.py— workspace unpacked from the repo archive, session driven over HTTP, the diff committed back as ONE commit via a newforgejo.commit_files. No Forgejo credential enters the container: the agent gets a directory, not a push token. Per-sessionOPENCODE_SERVER_PASSWORD(verified: no auth 401, wrong password 401, correct 200).assets → drain → build ⇄ gate_playtest → alpha → build_alpha → beta → build_beta → ship. Milestone walk uncapped (the plan lists what it lists); repair capped, which is what makes an unattended run terminate. Nodes maintaintodosand narrate tomessages, so a real run drives the studio.check_phase— build phases judged by what runs: entry committed, every referenced asset present at that commit, a passing playtest for that commit.trog run "<brief>"— one command, streams phase/todo transitions, resumes from the checkpoint if a run is interrupted.Proven on real hardware
The seat path works. A build session against a scratch repo:
...and the headless browser on that exact commit:
PASS (60.1 fps; 1 canvas; 36 colors; motion 0.42). Build → commit → playtest gate is real.The run itself got through ideation, preproduction (fun gate: pass), vertical slice (bar gate: pass), a 4-milestone production plan parsed cleanly from the brain's own table, a 27-asset spec, and a full drain: 14 images, 14 sounds, 3 animations, then critics and a regeneration pass.
Why it was stopped
Every sprite and UI asset is RGB with no alpha channel — the subject painted onto an opaque background. In Phaser each would composite as a solid rectangle. The build agent would have loaded them and produced a game of dark boxes.
Worse, the visual critic passed one of them. Its reasoning about
bird.png:The brief asked for separation FROM the sky — a cutout. The critic read it as "contrasts nicely with the sky painted into the picture."
Root cause is upstream of the critic and predates this ticket:
pixel_post.pyflattens to RGB at every stage and no workflow removes a background. The pipeline has never been able to produce a transparent sprite. #11 is simply the first thing that would have loaded one into a game engine. Filed as #34.Fixed along the way (all found by running it, not by testing it)
execution_seconds=3600.01 Worker job cancelled. The run died mid-drain with four milestones to go.BG_JOB_TIMEOUT_SECS=86400, plustrog runnow resumes from the checkpoint, because a cap is not a guarantee — a redeploy or a crash ends a run just as dead.doneand skipped an hour of work.jobprogresswas wired into the one-off worker only, so every drain job came backprogress: {}. Image and audio hid it by finishing an item a minute; animate at ten minutes an item looked hung.Where this leaves the ticket
Not done. The done-condition is "one command, zero intervention, playable URL at the end", and no run has reached it. The process spine, the code agent, the drain integration and the playtest gate are all proven individually on real hardware; the blocker is #34, because a run that ships a game of opaque rectangles has not met the bar even if it produces a URL.
Next: fix #34, then re-run end to end.