An agentic game development studio, inspired by my first attempt with more focus on LangGraph, Modern Game Development strategies, and JS game building libraries rather than traditional frameworks like Godot, Unity or Love2D.
  • Python 45.8%
  • HTML 45.3%
  • TypeScript 5.6%
  • CSS 1.4%
  • Dockerfile 0.9%
  • Other 1%
Find a file
Chris Moriarty 21966fd393
All checks were successful
tests / studio (push) Successful in 1m23s
tests / pytest (push) Successful in 2m15s
Upgrade stack 105 to vLLM v0.28.0 (rebased Turing FlashInfer patch)
Rebase pre-verified: flashinfer pinned at the identical 0.6.16.post3,
gate line byte-identical, sm75 kernels still built, fp8-KV validation
unchanged, and #53912 requires MTP which stays disabled. Measured on
the 21k agent-turn bench vs the v0.27.1 baselines: cold 21k prefill
12.6s -> 9.8s, decode @20k 46-49 -> 51.4 t/s, short 54 -> 56 t/s,
KV pool identical at 971,740 tokens, no CUDA errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 22:00:59 -04:00
.forgejo/workflows ci: bump the venv cache key 2026-07-28 01:46:03 -04:00
audio-server docs: conductor-era truth pass; drop dead driver CLIs 2026-07-26 12:09:08 -04:00
brain feat: trogdor-coder — one Q8 brain, whole rig, the full 262k window (#38) 2026-07-29 13:00:08 -04:00
cli feat: brain bake-off — same pencil, four hands (#38) 2026-07-28 18:43:38 -04:00
docs feat: the editor gets eyes — draw, look, revise (#38 round 3) 2026-07-29 10:13:27 -04:00
experiments Upgrade stack 105 to vLLM v0.28.0 (rebased Turing FlashInfer patch) 2026-08-27 22:00:59 -04:00
graphify-out feat: graphify knowledge graph of the repo (#26) 2026-07-26 12:36:31 -04:00
opencode fix: tell OpenCode the brain has eyes — attachment: true (#38) 2026-07-29 17:06:21 -04:00
playtest fix: roster-driven brain default, assets-phase brain selector, dedupe 2026-07-26 12:14:34 -04:00
scripts feat: install Phaser's own agent skills in the code seat (ticket 10, never wired) 2026-07-28 10:54:12 -04:00
server fix: the caption is the agent's eyes — vision rides the text channel (#38) 2026-07-29 17:37:16 -04:00
studio fix: don't yank the reader back down, and give the MoE a repetition remedy 2026-07-28 00:51:58 -04:00
tests fix: the caption is the agent's eyes — vision rides the text channel (#38) 2026-07-29 17:37:16 -04:00
.env.example feat: trog profile — switch the rig layout without hand-editing four vars 2026-07-27 22:22:02 -04:00
.gitignore feat: graphify knowledge graph of the repo (#26) 2026-07-26 12:36:31 -04:00
AGENTS.md docs: commit agent onboarding (CLAUDE.md) + AGENTS.md pointer 2026-07-26 12:15:09 -04:00
CLAUDE.md docs: the fixture sprites carry alpha now, and why fresh matters 2026-07-28 00:34:09 -04:00
CONTRIBUTING.md docs: README overhaul for first-class open source (#26) 2026-07-26 14:43:37 -04:00
docker-compose.build.yml feat: brief in, playable game out — the walking skeleton 2026-07-27 17:35:31 -04:00
docker-compose.yml feat: pixel art as two tools — draw, look, tweak (#38 merge arm) 2026-07-29 16:10:02 -04:00
LICENSE chore: Apache-2.0 license 2026-07-26 12:02:32 -04:00
Makefile feat: brief in, playable game out — the walking skeleton 2026-07-27 17:35:31 -04:00
README.md feat: let a profile keep the brain resident (#35 part 2) 2026-07-27 21:39:30 -04:00
requirements-dev.txt feat: measured progress for asset jobs; tweaks write back where you asked 2026-07-27 12:35:00 -04:00
ruff.toml refactor: repo quality audit — conductor parse-once, assetq argparse, comfy_item decomposed, ruff in CI 2026-07-24 00:04:46 -04:00
trogtoo.md docs: trogtoo.md — plan for Trog Too restart on the vLLM brain 2026-08-22 02:02:35 -04:00

Trog

A self-hosted collaborative AI game development studio.

pytest dependencies-up-to-date license

Give trog a one-sentence game idea. A checkpointed LangGraph state machine walks it through a real production process — ideation, prototypes, a vertical slice, milestone builds, alpha, beta, ship — writing code and generating art, music, and sfx along the way, while humans watch, steer, and judge from a web studio. The result is a playable web game: a URL you send to friends.

flowchart LR
    IDEA(["💡 game idea"]) --> STUDIO
    subgraph STUDIO["T r o g"]
        direction LR
        AGENTS["🤖 agents<br/>design · code · art · music"] <--> PEOPLE["🧑‍🤝‍🧑 people<br/>watch · steer · judge · play"]
    end
    STUDIO --> GAME(["🕹️ a playable web game<br/>a URL you send to friends"])
    GAME -. "playtests & feedback" .-> STUDIO

    classDef idea fill:#fff3c4,stroke:#d4a72c,color:#1f2328
    classDef game fill:#d3f9d8,stroke:#2f9e44,color:#1f2328
    classDef ppl fill:#e7f5ff,stroke:#339af0,color:#1f2328
    classDef bot fill:#f3f0ff,stroke:#845ef7,color:#1f2328
    class IDEA idea
    class GAME game
    class PEOPLE ppl
    class AGENTS bot

The trog studio mid-run: the live agent feed on the left, the production map lighting up the current phase on the right

Status: pre-1.0, under heavy development.

Table of contents

Usage

Install the CLI once (uv tool install --from cli/ trog-cli), point it at your stack (TROG_URL), then most things are one-liners:

trog run "a cozy fishing game with a day/night cycle"   # brief → playable URL
trog image "red car driving at night pixel art" --size 64x64
trog sfx "finger snap"
trog music "calm tavern theme" --seconds 45 --loop
trog animate "knight walking" --base assets/sprite/knight.png
trog critique "a shiny red apple" apple.png     # judge any file, real critics
trog playtest trog-games/my-game                # run a game headless: gates + shots
trog process-asset-queue                        # drain whatever the brain queued
trog status                                     # orchestrator · brain · queue
trog test                                       # quick suite, no GPU swaps
trog update --dependencies                      # guided pin bumps: confirm, deploy, test, keep/revert

How it works

The production process is a checkpointed LangGraph state machine, served by Aegra (Apache-2.0, FastAPI + Postgres): Checkpoints are the quiet superpower: every step can be rewound, edited, forked, and resumed — "undo three decisions ago" is a feature, not a restore-from-backup.

flowchart TD
    subgraph WEB["the studio"]
        UI["▶️ play · 👀 observe · ✋ interrupt · 📝 edit · 🎨 tweak · 🩺 debug"]
    end

    subgraph TROGDOR["Trog Server"]
        AEGRA["Aegra<br/>Agent Protocol server<br/>auth · SSE streams · runs"]
        GRAPH["LangGraph<br/>the production state machine<br/>phases · gates · retries"]
        PG[("Postgres<br/>every step checkpointed:<br/>rewind · fork · resume")]
        GATE["mcp server<br/>check_phase gates<br/>commit-keyed ledger"]
        ZOO["the zoo<br/>image · music · sfx · video<br/>models hot-swapped per job"]
        PLAY["playtest<br/>headless browser<br/>screenshots · console · video"]
    end

    REPO[("📦 game repo on Forgejo<br/>git is truth")]

    UI <-->|"stream + resume"| AEGRA
    AEGRA <--> GRAPH
    GRAPH --- PG
    GRAPH --> GATE
    GRAPH --> ZOO
    GRAPH --> PLAY
    GATE --> REPO
    PLAY --> REPO

    classDef web fill:#e7f5ff,stroke:#339af0,color:#1f2328
    classDef core fill:#f3f0ff,stroke:#845ef7,color:#1f2328
    classDef data fill:#fff3c4,stroke:#d4a72c,color:#1f2328
    class UI web
    class AEGRA,GRAPH,GATE,ZOO,PLAY core
    class PG,REPO data
piece what it is its one job status
studio web app — studio/, React SPA on :2027 the window into everything: play, watch, steer feed, map, brain selector; files/play panes 🚧
trog CLI + orchestrator cli/ typer client → orchestrator :8200 one-off assets on demand: seats, GPU tenancy, brain bracketing
aegra Agent Protocol server (FastAPI + Postgres) run & stream the graphs; checkpoint every step
the graph LangGraph state machine (server/graphs/) the production process itself — phases, gates, retries docs phases; code-writing phases 🚧
the brain brain/ — llama-swap + pinned llama.cpp one endpoint :8090; the request's model field swaps the resident LLM
mcp server thin wrapper over trog_lib verification deterministic check_phase, commit-keyed ledger
the zoo ComfyUI + audio seats, raised per job image / music / sfx / video, models hot-swapped
playtest headless browser service run the game; screenshots, console, gates, video
game repos one Forgejo repo per game git is truth

Principles the code actually enforces:

  1. The graph owns the process from the first commit. The orchestrator is the design, not an add-on.
  2. Verification lives in tools, not prompts. A claim isn't done until check_phase says so — keyed to the exact commit it ran on.
  3. Every generator has a critic. Sometimes the critic is you.
  4. Humans are first-class nodes. Interruption, judgment, and play are part of the graph, not exceptions to it.
  5. Git is truth.
  6. Code 100% Apache-2.0, 100% self-hosted — nothing phones home. Model weights are guests: recommended defaults are open-weight and swappable, each under its own license (see below).

Trog is model-agnostic by design. The framework talks to seats over plain HTTP contracts; which model answers is configuration:

  • Brain (LLM): any OpenAI-compatible endpoint. Self-hosted, the roster is one YAML file (brain/rosters/<name>.yaml, picked by BRAIN_ROSTER) — add a GGUF, add an entry, and it appears in the studio's brain selector. Pointing BRAIN_URL + BRAIN_API_KEY at a cloud provider works the same way.
  • Image / animate seats: ComfyUI workflows (server/trog_lib/workflows/) — swap the checkpoint in the workflow JSON and drop the weights in MODELS_ROOT.
  • Audio seats: env-pointed checkpoints (audio-server/).

The defaults below are the winners of trog's own benchmarks (bake-offs and eye/ear tests, receipts in docs/) — recommendations, not requirements:

role default weights license (summary — verify upstream)
brain (default) Qwen3.6-27B Apache-2.0
brain (roster) Qwen3.6-35B-A3B, Qwen3 Coder Next, Gemma 4 31B Apache-2.0 / Gemma Terms
image FLUX.2-dev FLUX Non-Commercial License — weights for non-commercial use; generated outputs may be used commercially
image (fine lane) Z-Image-Turbo + elusarca pixel LoRA Apache-2.0 (both)
animate Wan 2.2 I2V-A14B + pix3lwalk LoRA Apache-2.0 (Wan); LoRA per its CivitAI listing
music ACE-Step 1.5 Apache-2.0
sfx Stable Audio Open Stability AI Community License (free under revenue threshold)
vocals HeartMuLa-oss-3B see upstream

License summaries are good-faith shorthand, not legal advice — check the upstream license before shipping anything commercial, and swap any seat whose terms don't fit your use.

Hardware profiles: one env var describes your rig

How the models above land on your GPUs is a hardware profile — one named YAML bundle in server/trog_lib/profiles/ declaring which cards each generation seat occupies, which workflow serves each image/animate lane, and which brain roster the rig is sized for. Two stack env vars select it:

TROG_PROFILE=trogdor    # seat→GPU maps + workflow lanes (orchestrator)
BRAIN_ROSTER=trogdor    # LLM lineup (brain/rosters/<name>.yaml, baked into
                        # the brain image; keep in step with the profile)

Shipped profiles:

profile rig what changes
trogdor-quality (= trogdor, the default) 4× 16 GB the reference layout every benchmark ran on: image seat owns the rig (FLUX.2 sharded), animate on three cards, audio beside it on the fourth. The brain is bracketed — stopped for each seat, restarted after
trogdor-speed 4× 16 GB same box split along its own NVLink/NUMA seam: the brain is resident on GPU0+1 and never stopped, all three seats live on GPU2+3. The brain⇄seat swap disappears; the art gets worse, because klein-4b and Wan TI2V-5B are smaller models than FLUX.2-dev and Wan-A14B
single-24gb 1× 24 GB image runs the single-GPU Z-Image seat, roster shrinks to the 27B at 32K ctx, everything serializes — and i2i/animate jobs fail fast with a clear error naming the profile, because stated trade-offs beat mid-render OOMs

A profile also says whether the brain yields its cards at all (brain: {gpus, resident, cpuset}). A resident brain removes the largest single cost in a run — the cold model swap around every seat — and is only safe when no seat shares its cards, which the profile loader enforces rather than trusts.

A profile's GPU sets are also the parallelism truth table: disjoint sets run beside each other, overlapping sets take turns. Layering is defaults < profile < envSEAT_GPUS_IMAGE/_ANIMATE/_AUDIO still override the card maps for ad-hoc experiments, no file needed.

To fit a new rig: copy a profile, point its lanes at any workflow in server/trog_lib/workflows/, add a sized roster in brain/rosters/ if the reference one doesn't fit, set the two env vars. pytest tests/test_profiles.py validates every shipped profile names real workflows. Full walkthrough: docs/self-hosting.md.

The production process

The graph's shape comes from Richard Lemarchand's A Playful Production Process (the Naughty Dog method, scaled down): timeboxed preproduction, a vertical slice that sets the quality bar, milestone-driven production with playtests and a juice pass, and gates that can send work backward, not just retry.

flowchart LR
    I["🌱 ideation<br/>brief → concept"] --> P["🧪 preproduction<br/>tiny disposable prototypes"]
    P --> F{"is it fun?"}
    F -->|"not yet — iterate"| P
    F -->|"yes"| V["💎 vertical slice<br/>small, but final quality"]
    V --> Q{"hits the bar?"}
    Q -->|"no — back to the lab"| P
    Q -->|"yes"| G["🎨 assets<br/>spec → queue → drain"]
    G --> M["🏗️ full production<br/>one code-agent session<br/>per milestone"]
    M --> R{"does it run?"}
    R -->|"no — here are the errors"| M
    R -->|"yes, next milestone"| M
    R -->|"all built"| A["α<br/>feature-complete"]
    A --> B["β<br/>content-complete"] --> S(["🚀 ship"])

    classDef gate fill:#ffe3e3,stroke:#e03131,color:#1f2328
    classDef ship fill:#d3f9d8,stroke:#2f9e44,color:#1f2328
    class F,Q,R gate
    class S ship

Two kinds of node do the work. Document phases call the brain and commit one markdown artifact. Build phases hire a developer: the node writes a task, the orchestrator raises an OpenCode seat inside a checkout of the game repo, and the session's work comes back as one commit. The graph never holds a working tree — git is the only truth crossing that boundary, which is what makes a build session something a run can survive.

The does it run? gate is the only one that isn't an opinion: a headless browser loads the committed build, and a failure goes back to the developer with the console errors and the missing files attached.

Every ◇ is a LangGraph conditional edge, and the judge at each one can be an agent or a human. Phases start from template scaffolds (server/templates/) so the agent never wakes up in an empty directory. One trog-specific addition: retry caps — a human team can argue with a gate, but an unattended run must terminate, so each gate has a budget and a capped gate advances with the override written into the release notes. An autonomous studio should confess its compromises.

The signature move is the interrupt:

sequenceDiagram
    autonumber
    participant You
    participant Studio
    participant Graph as LangGraph

    Graph->>Studio: streaming... "implementing double-jump"
    You->>Studio: ✋ make the jump floatier
    Studio->>Graph: interrupt(guidance)
    Note over Graph: checkpoint saved<br/>guidance folded into state
    Graph->>Studio: resumed — "lowering gravity, adding coyote time"
    You->>Studio: ▶️ play the new build

Asset generation swaps models per job and runs in one of two modes: autonomous (a vision/audio critic judges every asset against its brief) or human-in-the-loop (you judge, from the studio). Verdicts are keyed to the exact commit of the asset they judged — edit the asset and the old verdict is stale by construction.

Testing

One entry point (trog test …), tiered — use the cheapest tier that can catch the bug you're hunting:

tier command time proves
quick suite trog test minutes unit + critics + playtest fixture + mock asset cycle — every tier that needs no GPU swap
unit make test seconds parsers, manifests, lib logic (pure pytest, no services)
critic trog test critics seconds judges the fixture repo's known assets against the standing baseline — zero generation
playtest trog test playtest seconds the good fixture game passes AND the broken sentinel fails
mock asset trog test asset --mock minutes the whole drain path on stub seats with declared verdict expectations — zero GPUs
studio UI trog test ui (--headed to watch) ~1 min user-level Playwright run against the live studio, including a real send→stream→reply
seat one-off trog image/sfx/… varies one real seat, one item
quality trog test asset ~30 min model-contract truths on the real seats; judge the review page by eye
regression trog test regression ~40 min all of the above plus the real asset run, PASS/FAIL report

Two standing fixtures keep the judges honest, in both directions: the critic fixture's baseline is 6 pass / 1 fail (the failing orange is a deliberate sentinel — the file is an apple, the brief says orange), and the playtest fixture pairs a working game with a broken sentinel that loads and must still fail.

Roadmap

Work is tracked as milestones on the repo's issue tracker: v1 — single-user autonomous (in flight) → v2 — human in the loopv3 — multi-user. The end state of v3 is game development as a party activity: friends watching the stream, voting at gates, tweaking assets, and playing every build minutes after it lands.

Background

Trog is the second attempt. The first — Agentic Game Development Studio (deprecated) — taught three expensive lessons, and each one is a founding decision here:

  1. The orchestrator can't be an afterthought. LangGraph was bolted on late and never fit. In trog, the graph is the process from the first commit.
  2. Wrong game framework. LLMs write dramatically better web games than Löve/Lua games. The research agrees: OpenGame, GameDevBench, and Phaser 4 shipping AI agent skills in-repo.
  3. The studio is the project. Long runs where the only status view was logs proved to be a boring way to build games. Visibility, interruption, and human interaction are designed in from the start this time.

Contributing

See CONTRIBUTING.md for the dev setup, the test tiers to run before pushing, and the conventions that aren't obvious (lint-only ruff, no new make targets, fixtures that are supposed to fail). Agent onboarding lives in CLAUDE.md — much of trog is built by the kind of agents it hosts.

Acknowledgements

License

Apache-2.0 © Chris Moriarty. SPDX-License-Identifier: Apache-2.0

Model weights are not distributed with this repository and carry their own licenses — see the models table.