@cosmic-pulse/ludus
v0.18.0
Published
An AI QA team for Unity games — agent-native, engine-native. Spec-driven testing over the official Unity CLI.
Maintainers
Readme
Ludus
An AI QA team for Unity games — agent-native, engine-native.
Ludus turns a coding agent into a QA department for your Unity project. Built on the official Unity CLI, it reads real game state instead of watching pixels: it inspects scenes, executes live C# against the running editor, drives play mode, and judges results deterministically — fast enough to simulate a thousand play sessions a minute.
At its core is a contract: your game carries a LUDUS.md spec — what the game is, its golden path, its rules and invariants — co-written with an agent and kept current by one. Everything else derives from it.
Ludus — Latin for "game," and the training ground where gladiators were drilled before the arena. Your game trains here before it ships.
What the QA team does
- Owns the spec — interactive authoring (
spec init), coverage auditing (what's implemented, what's testable, what's untested), and drift-aware maintenance (spec sync). The agent maintains the document; humans approve what the game should do. - Runs the suite — golden-path tests, edge-case stress, invariant-guided bug hunts, regression probes — every verdict citing the spec clause it violates. Deterministic, CI-gated, headless.
- Plays as the canary — scheduled exploratory sessions that hunt novel states under continuous invariant watch. Findings (with repro scripts) feed back into the suite and the spec: the suite proves the game still does what you said; the canary discovers what you forgot to say.
- Judges the experience — follows your tutorial as a player would, walks the full journey funnel, estimates per-level difficulty (solver analytics + persona simulation), and checks your progression curve against declared design intent.
Why engine-native
Vision-based QA agents watch the screen and play at human speed. Ludus teleports the player, sets state directly, asserts on internals, and Monte-Carlos difficulty — things a screen-watcher can't do, at a cost and speed it can't match.
Status
Pre-release. The harness (session supervision, probes, spec-driven runner, findings ledger) and the QA skills are dogfooded end-to-end against a real commercial mobile game: spec authored from the code, coverage grown clause by clause, real bugs found and reproduced, difficulty curve measured. Interfaces may still change before 1.0.
Install and set up
npm install -g @cosmic-pulse/ludus # or: npx @cosmic-pulse/ludus <command>
cd your-unity-game
ludus init # one command; sets up everythinginit installs the Unity pipeline package, scaffolds .ludus/, writes config, and asks
whether you'd like your coding agent set up to do the QA work. If yes, it adds one section to
AGENTS.md — the cross-agent convention — explaining what Ludus is, which request maps to
which skill, and the ground rules. Files other agents read get a one-line pointer, never a
copy — and CLAUDE.md is created with an @AGENTS.md import if missing, because Claude Code
reads only CLAUDE.md.
Ludus is agent-agnostic: it never asks which agent you use and installs nothing
agent-specific. Skills are referenced where the CLI installed them (ludus skills path), so
they improve when you update Ludus instead of going stale in your repo — --vendor-skills
copies them in if you'd rather pin and commit them.
From then on you just talk to your agent normally — "set up testing for this game", "what should I test next?", "play it and find bugs". You never type skill names.
Getting it in front of your agent. Agent sessions often run in a git worktree, which
contains only committed files — so the wiring reaches them once it's committed on your default
branch, like any other project config. init offers to make that commit for you.
While you're still trying Ludus on a branch, a merge to the default branch is a lot to ask.
If your agent supports it, init offers to set worktree.baseRef: "head" in the project's
settings so new sessions branch from your current HEAD and carry the setup with them — no
merge needed. It's opt-in and off by default, because it changes how every session in that
repo is created, not just QA ones. One verified integration today (Claude Code); others get an
entry when someone has actually confirmed the equivalent.
If your agent runs in a git worktree — most do — Unity opens that copy of the project:
its own Assets, its own ProjectSettings, its own multi-GB Library. Your uncommitted work
isn't in it, and a branch cut before an editor upgrade opens in the old editor. doctor catches
both (worktree-divergence, worktree-editor-version), and pinning "editorVersion" in
ludus.config.json catches the case where every checkout is on the same wrong base.
ludus next answers "what should we do now?" from the project itself rather than from
memory: which of Ludus's capabilities you've used, which are untouched, and the one most worth
doing — an untested play-through outranks a few untested rules, because rules can all pass
while the game is unplayable.
ludus doctor reports on all of this: whether a session can see the setup at all, and
separately whether teammates and CI can.
Flags: --no-agent (CLI-only), --vendor-skills, --instructions <file>, --commit /
--no-commit, --patch-agent-settings / --no-patch-agent-settings.
Using Ludus without an agent
Yes, it works without an agent (ludus init --no-agent) — and init sets you up for it:
it scaffolds an annotated LUDUS.md template that explains the format inline, plus
.ludus/checks/README.md, a walkthrough for writing checks by hand (front-matter, the verdict
contract, the frame-separation rule, and the green-twice/red-by-mutation bar). Fill them in and
the runner does the rest: deterministic execution, clause-cited verdicts, honest coverage,
CI gating, findings ledger. Nothing about the harness requires an agent.
What you give up is the authoring: no one drafts the spec from your code, grows coverage, plays canary sessions, or evaluates difficulty. That's the QA engineer's job — Ludus lets you delegate it to an agent or do it yourself.
Running it on a schedule
QA is repetitive by nature, and every scheduler needs the same two answers: is there
anything left to do, and is the next move even mine to make. ludus next answers both
in its exit code, so nothing has to parse prose or ask a model whether the work is
finished:
| Exit | Meaning | What a scheduler should do |
|---|---|---|
| 0 | nothing left worth doing | stop |
| 1 | the next move needs a human decision | stop and surface the question |
| 2 | work is available and QA can do it unaided | go again |
That is the whole contract, and it is deliberately harness-agnostic. A plain shell loop:
ludus next
while [ $? -eq 2 ]; do
# ...do the top item, however you do it...
ludus next
doneThe same contract drives a nightly cron job, a CI gate, or an agent harness with a
repeat primitive — in Claude Code, /loop supplies the clock and /goal the stopping
condition, and both become facts about the project rather than judgement calls about
whether it feels done. Ludus does not depend on any of them; it just answers the
question they all have to ask.
Pair it with ludus decisions, which exits non-zero while anything is waiting on you,
so an unattended run ends by naming what it needs instead of guessing.
Requirements (current target)
- Unity 6.0+ (primary target: 6.5) — the Unity CLI's pipeline package sets the floor
- Unity CLI (beta channel)
- Node 22.12+ (harness); any MCP-capable coding agent (Claude Code first)
