Skip to content
Back to skills

Dojo

ASecurity

Autonomous infinite training loop for media-generation craft: each cycle reflects prior human verdicts into the consuming repo's prompt surfaces, scans the registry for the weakest knowledge dimension, researches one candidate technique, generates seed-matched A/B pairs with the LOCAL image/video stack, machine-judges them pairwise, and parks the cycle for human gating in the app's Foundry -> Dojo tab. Human verdicts are consumed by the NEXT cycle, never immediately; approved improvements lan...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 19, 2026
businessrustgoshellbashnoderailstestinggit

Works with

  • cli

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 19, 2026

npx -y skills add xkazm04/ai-registry --skill dojo --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dojo?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dojo
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/xkazm04-dojo/badge)](https://www.skillsdirectory.com/skills/xkazm04-dojo)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dojo
description: "Autonomous infinite training loop for media-generation craft: each cycle reflects prior human verdicts into the consuming repo's prompt surfaces, scans the registry for the weakest knowledge dimension, researches one candidate technique, generates seed-matched A/B pairs with the LOCAL image/video stack, machine-judges them pairwise, and parks the cycle for human gating in the app's Foundry -> Dojo tab. Human verdicts are consumed by the NEXT cycle, never immediately; approved improvements land as prompt-recipe edits and return to the registry as leads. Runs only where the overlay declares a runner (GPU machines); elsewhere it stops at generation and says so, or fabricates a plausible cycle with --fixture for surface and protocol testing. Use to keep image/video prompt recipes improving unattended, to drain parked human verdicts into code, or to exercise the Dojo tab without hardware. Invoke with /dojo [run|status|reflect|--fixture]."
argument-hint: "[run|status|reflect] [--fixture] [--resume <cycle-id>]"
category: ai-native
memory: project
version: 1.5.1
tags: training, media-generation, ab-testing, judge, foundry, loop, craft
allowed-tools: Read, Write, Edit, Bash, PowerShell, Glob, Grep, Monitor, WebSearch, Agent
---
# Dojo — the infinite training loop

A **long-running loop** that trains CRAFT, not weights. The unit of improvement is
a *technique injected into a prompt recipe*, proven by seed-matched pairwise A/B
against the incumbent recipe, gated by human eyes in the app, reflected into the
consuming repo's prompt surfaces, and returned to the registry as leads. Scores
are a pre-filter, never a verdict — the human's pick is the verdict, and the
disagreement between score and eye is the finding worth keeping.

The loop never writes `knowledge/`. It produces EVIDENCE — cycles, pairs, picks,
ledger rows — and hands that evidence to `/deepen` and `/intake`, which own the
corpus. If the answer is "research this subject", the answer is `/deepen`,
dispatched from here; dojo never re-implements its lanes.

The human is never waited on. Cycles park in `awaiting-gate` and accumulate;
whoever opens Foundry -> Dojo gates them on their own clock (K approve / X reject
/ U clear); whichever future cycle runs Phase 0 next consumes the verdicts. That
one-cycle lag is the design, not a limitation: reflection reads a settled ledger,
never a human mid-decision.

## Invocation

```
/dojo run                 # the loop: reflect, then cycle until budget or breaker
/dojo status              # read manifests + ledger, touch nothing
/dojo reflect             # Phase 0 only: drain approved verdicts into code, then stop
/dojo run --fixture       # no runner needed: fabricate a plausible cycle end-to-end
/dojo run --resume <id>   # continue a cycle stopped by budget or a dead process
```

## State and overlay

**All mutable state lives in the CONSUMING repo.** The lane forbids `state/` in a
skill directory for exactly this reason — a copy that mutates diverges on first use.

- `foundry-out/training/<cycle-id>/cycle.json` — the cycle manifest, **the only
  state**. Everything else (pairs on disk, verdicts, logs) is addressed from it.
  The full wire contract is `references/cycle-contract.md` — field names there
  are shared truth with the app's implementation; never rename one side.
- `pipeline/foundry/training-ledger.json` — the git-tracked verdict ledger, the
  cross-machine sync channel. A GPU box generates and parks; any machine that
  pulls sees the human's verdicts; the next Phase 0 anywhere reflects them.
- `pipeline/foundry/training/thumbs/` — one tracked thumbnail per approved
  improvement, the only media that survives a commit.

The overlay `.claude/dojo/config.md` in the consuming repo declares:

| Key | Meaning |
| --- | --- |
| `runner` | Command templates for the local model stack — image and video generation. **Absent on machines without GPUs.** |
| `budget` | Hard spend/time ceiling per cycle window. |
| `dimensions` | The knowledge dimensions this repo trains (allowed subjects). |
| `promptSurfaces` | The reflection map: which file owns which recipe decision. For gravitone: `pipeline/FRAMES-SCENE-PROMPT.md`, `lib/formatBrief.ts` direction[], `app/_phases/frames/shotPrompt.ts`, `lib/foundry/extract/prompts.ts`, `lib/music/plan.ts`. |
| `judges` | The judge providers, and (once earned) which judge is pinned. |

**No runner declared** -> the loop still runs Phases 0-3, then stops at Phase 4
with `runner: absent` and says so plainly — reflection and planning are worth
doing on any machine. Unless invoked with `--fixture`, which fabricates a
plausible cycle (manifest, pairs, picks, parked state) for surface and protocol
testing — design-mastery mode for machines that cannot generate. A fixture cycle
is marked as such in its manifest log and never reaches the ledger as evidence.

## The cycle

Announce each round boundary out loud, scan-sweep's way: `── Cycle <n>:
<dimension>/<subject> ──`. A loop whose cycles are not visible reads as one
runaway session. Each cycle is self-contained — its manifest is written before
the next cycle is chosen, so an interrupted loop loses only the cycle in flight,
and `--resume` picks that one up from its `status`.

### Phase 0 — Reflect (the first act, always)

Read `training-ledger.json` for rows with `reflected: false` and a human verdict.
For each **approved** row:

1. Edit the named prompt surface's DECISION part — a new numbered rule, a
   direction line, a recipe clause — citing the technique by name. The edit goes
   where the overlay's `promptSurfaces` map says that decision lives, never
   guessed from a grep.
2. Add or extend the surface's **regression control**, so the rule cannot silently
   fall out of the prompt later. `FRAMES-SCENE-PROMPT.md` has none — create one on
   first touch, shaped like the repo's existing `pipeline/*-regression.mts`.
3. Commit on a branch for operator review — reflection edits product prompts and
   is never merged by the loop itself.
4. Stamp the row `reflected: <sha>`.
5. File one lead line to `.ai/registry-leads.jsonl` — **earned**: the human
   approved AND the edit landed. Log the consult to `.ai/consults.jsonl`.

A **rejected** improvement gets verdict `not-better` in the ledger and is itself
reflection input: the next plan avoids the failed direction, and the not-better
row is filed as a lead too. Rejections are the most valuable rows — a technique
the literature praises and the human's eye refused is exactly what the corpus
does not yet know.

### Phase 1 — Scan

Prove the instrument first: `node scripts/check-bundles.mjs` (read-only), then
`node scripts/build-index.mjs` (WRITES `index.json`; use `--check` when the
registry checkout is not yours to edit or another session is mid-edit there),
in the registry. Then `node scripts/librarian-scan.mjs --json` (read-only) for
the per-subject scores. **Never count anything yourself** — this registry once
reported 0/267 over a corpus at 267/267 because a counter read a different
shape than the parser emitted. Spot-check one number against one real file
before trusting any score. A `check-bundles` failure in a bundle this cycle does
not consume is reported, not repaired.

Ranking: **demand outranks scan points, and demand means THIS repo's** — the
consuming repo's own `.ai/conform-detail.json` (its live deviations) or a
repeatedly-not-better dimension beats any structural gap. The scan's aggregate
deviation count is a bundle signal across the fleet, not a this-repo signal: a
subject with six consumer deviations and no conformance pair here has never
been deviated on here. Pick **ONE dimension/subject per cycle**, from the
overlay's allowed set. A dimension whose recent cycles all came back not-better
with no new technique in sight is saturated for now; say so and pick the next.
A live deviation the loop's only instrument cannot measure (a schema gap, a
cross-frame property under a still-image A/B) is a standing blind spot; name it
and pass.

**Count the parked backlog before you plan, and report it every cycle.** The
loop never waits on the human, but the human is a resource with a capacity and
this loop has no backpressure: parked cycles accumulate whether or not anyone
is gating them. When the count is high and nothing has been gated in a while,
say so at the TOP of your report rather than in a footnote — the marginal value
of parked cycle N+1 falls as N grows, because every one of them is waiting on
the same scarce act. It is still not a reason to stop generating evidence, but
it IS a reason to prefer, in this order: a cycle that answers a question no
human verdict is needed for (a measurement, a probe with pre-registered
branches); a cycle on a subject with NO parked cycle yet; then anything else.
A reflection branch left unmerged counts as backlog too — check that the shas
in the ledger's `reflected` field are actually ancestors of the main branch,
because a row reading `reflected: <sha>` looks identical whether that commit is
live or has been sitting on a review branch for a week.

### Phase 2 — Research

Banked leads first: `librarian/subjects/media-generation/*.md` "Open leads"
sections are pre-written objectives somebody already scoped — a due lead is
cheaper than a fresh scan. For real research, **DISPATCH `/deepen`** on the
subject; never re-implement its lanes here.

The output of this phase is exactly one candidate technique with a **falsifiable
claim**: *when X, do Y, because Z*. A technique that cannot lose its A/B is not
a technique, it is a preference — send it back.

A banked lead that asks for a MEASUREMENT rather than an improvement (a probe
with pre-registered branches) is not a mismatch for the pairwise instrument —
it collapses into one experiment when the **baseline arm is what the pipeline
does today**. Then the baseline arm alone is the probe, the challenger makes it
a pair, and the two answers are consistent by construction: the branch the
probe lands in predicts whether the challenger can win at all. Prefer this
shape, because it discharges a fleet-level lead and a repo-level A/B for one
render budget.

### Phase 3 — Plan

Write `cycle.json` with `status: "planning"`: 1-2 improvements, each carrying

- `baseline_recipe` — the incumbent, read from the consuming repo's **live**
  prompt surface or `styles.json`, never from memory;
- `challenger_recipe` — the same recipe with the technique injected, and nothing
  else changed;
- a scene roster (reuse `pipeline/foundry/plans/` scenes — known ground beats
  fresh invention) and a **fixed seed list**.

Preflight like train-style's `--dry`: pair count, worst-case cost, the budget
window. Over budget -> STOP with the over-budget sentence; `--resume` continues
when the window has moved. No spend starts without the number having been said.

### Phase 4 — Generate

Through the overlay's runner templates only. **Seed-matched**: the same scene and
the same seed in both arms — the seed is the control that makes the pair a
measurement instead of two rolls. Videos always render a poster still; the
judges and the tab read stills.

Detached-process discipline, verbatim from train-style: anything over ten minutes
must NOT be a Bash background task (it is killed at the ceiling). Launch with
`Start-Process` with redirected output, then poll with Monitor:

```powershell
$log = "pipeline/foundry/logs/dojo-<cycle-id>.log"
Start-Process -FilePath "npx" -ArgumentList <runner args from overlay> -RedirectStandardOutput $log -RedirectStandardError "$log.err" -NoNewWindow
```

**Check the engine's owner before launching.** Where the runner keeps a run-id
registry (gravitone's `guard.py` does), a foreign run-id on the engine is
`runner: busy`: stop the cycle the way `runner: absent` stops it, and say whose
job holds the card. Never force-recycle another job's engine. Two loops on one
card is an interlock problem, not a convention problem; the safety rail below is
the convention and this check is the interlock. Diagnostic rule while polling:
**a unit taking more than 3x its measured per-unit time is contention, not a
bad seed** — re-check the owner instead of waiting out the timeout. But check
the owner FIRST and believe the answer: when no foreign job holds the engine
and the log shows the guard recycling between EVERY unit, the bottleneck is
host memory, not a neighbour, and the two have opposite remedies. Saturation
re-bases the per-unit budget (a recycle-per-unit box runs at roughly 1.5-2x its
measured alone-rate) and no amount of waiting or re-checking improves it; a
failure arriving seconds after a fresh recycle that just freed tens of GB is
NOT a free-RAM problem and chasing the number at the moment of death will burn
a window. When the card is contended rather than absent, `--fixture` still
exercises the protocol.

Track `fail_streak` on the manifest; the breaker trips at **3** consecutive
failures -> `status: "failed"`, stop the cycle, move on next wake. `failed` means
more broadly *the runner did not deliver a judgeable set, and the log says why*
— a breaker, an engine refusal, or a pass that ran out of window all park as
`failed`. A failed cycle is a result, not an embarrassment; the manifest's log
says what broke, and a PNG on disk is a finished render, so `--resume` on a
quiet card needs only the missing units.

### Phase 5 — Judge

Pairwise, blind, one pick + **ONE reason** per pair — never 1-10 scores. Scores
are a pre-filter, never a verdict; a number invites averaging away exactly the
disagreement the loop exists to find. The full protocol, including how
`pick_rate` and `judge_agreement` are computed, is
`references/judge-protocol.md`.

Two judges in early cycles, both logged per pair:

- **the chokepoint judge** — per-image readback via the consuming repo's
  recognize router, then a reasoned pairwise pick via its reason router or a
  dispatched Fable subagent;
- **the Gemini joint judge** — both images plus the claim in ONE multimodal
  request.

This is a meta-A/B over the judges themselves, resolved by evidence: the tab
shows pick-rate and judge agreement; once **>= 3 gated cycles** show one judge
tracking the human better, the overlay pins that judge and the other is dropped,
with the decision recorded in the overlay.

### Phase 6 — Park

Set `status: "awaiting-gate"`, write the cycle log line, then loop to Phase 1
for the next cycle. **A cycle with zero complete duos never parks for a human**,
however it got there: with no pairs there is no thumbnail and no pick rate, and
an empty cycle in the tab risks a fabricated row in the cross-machine ledger.
It stays `failed` with its log. **And a cycle whose claim is a pre-registered
roster does not park on a partial one**, even with duos to show: when the plan
fixed which cells decide which branch, a run missing those cells cannot answer
it, and the cells that die are disproportionately the expensive ones the branch
turns on. Ask what the surviving duos can conclude, not how many there are —
three complete duos that all sit on the easy half of the range are a partial
answer, and a partial answer entering the cross-machine ledger is worse than a
`failed` row, because the next session reads the ledger as settled. Human gating happens in the app (Foundry -> Dojo; K approve
/ X reject / U clear). Commit from the tab is **destructive**: one tracked
thumbnail per approved improvement survives; undecided media is preserved until
someone decides. The loop NEVER waits here — parked cycles accumulate, and
verdicts are picked up by whichever future cycle runs Phase 0.

## Safety rails

- **Never touch another session's files.** Check the consuming repo's active-runs
  ledger where it keeps one; the manifest's `lease` field marks who is driving a
  cycle, and a leased cycle is not yours to resume.
- **One dojo loop per machine.** Two loops share one budget window and one GPU;
  one of them will trip the other. This is the convention; Phase 4's owner check
  is the interlock, and it is the interlock that holds (two eval cycles on
  2026-09-01 honoured the convention on paper and still spent eleven hours on
  two renders because a third job held the card).
- **Never edit `knowledge/`** — evidence goes to `/deepen` and `/intake`.
- **Never edit `styles.json` by hand** — the catalogue is written by commits from
  the app's own commit path.
- **The budget window is a hard stop**, not a suggestion; `--resume` is the only
  way past it, and only once the window has moved.
- Reflection commits land on a branch for operator review, never on main.

## Knowledge sync

Dojo consumes the **media-generation** bundle and pays back into it, on its own
terms rather than the generic clause's, because the loop's whole output is
knowledge-shaped evidence:

- **Read** — resolve subjects through `knowledge/media-generation/index.json`
  and take each subject's `file` **verbatim** from the index. Never construct a
  path from a slug: bundles are nested and depth is dynamic, so a built path
  points at a folder nobody walks. Phase 1 ranks over this read; Phase 3's
  challenger cites the technique it injects.
- **Log every consult** — one line per cycle to `.ai/consults.jsonl`:
  `{"ts":"<ISO>","bundle":"media-generation","subjects":["<slug>"],"techniques":["<slug>"],"deviations":<n>}`.
  Slugs and counts only, never paths. This is the demand signal Phase 1's own
  ranking later reads back.
- **File leads ONLY for human-gated, landed improvements** — a lead is owed when
  the human approved (or rejected — `not-better` leads are the most valuable
  rows) AND the reflection edit landed with its sha in the ledger. Append to
  `.ai/registry-leads.jsonl`:
  `{"ts":"<ISO>","bundle":"media-generation","nearest":"<subject-slug or null>","kind":"technique|application","claim":"<when X, do Y, because Z>","because":"<pick_rate, agreement, and the human verdict>","confidence":"low|medium|high","from":"dojo@<version>"}`.
  The verdict vocabulary is closed — `better` / `not-better` / `unmeasurable` —
  inherited from the sweep lane and intake's Phase 7.5.
- **Never write knowledge itself** — dojo ORIGINATES evidence and dispatches
  `/deepen` (subject research) and `/intake` (source-shaped findings); the
  registry's own intake decides what survives. Say in the report which leads
  were filed, and say plainly when none were.

---

<!-- clause: skill-reflection v6 - stamped by scripts/apply-skill-clauses.mjs from docs/skill-clauses/skill-reflection.md; edit the template, then re-stamp -->
## Skill Reflection

After the work, record only useful observations supported by this run. No lesson is
a valid result. Reflection inherits the task's authorization; it grants no additional
permission to edit another repository, send data, commit, or publish.

**Run log.** Unlike a lesson, this is written on every run that started work - failed and
aborted runs included; skip read-only info modes and runs cancelled before any work. Append
ONE line to `.ai/skill-runs.local.jsonl` at the root of the task's MAIN checkout: local,
gitignored run output inside the task's own repository, never a write into the registry.
A run that worked in a linked worktree logs in the main checkout that worktree belongs to
(`git rev-parse --git-common-dir`, minus `/.git`) - a disposable worktree takes the line
with it when it is removed. `log-run.mjs` resolves this on its own.
The registry pulls it later (`/librarian skills` on the same machine). When a registry
checkout is reachable (`registry.local` in `.ai/manifest.yaml`), prefer its writer, which
stamps project, device and version for you:

```sh
node <registry>/scripts/log-run.mjs --skill dojo --outcome <o> --difficulty <1-5> \
  --provider <claude|openai|xai|qwen|google|other> --model <your model id> [--effort <level>] \
  [--tokens-est <n>] --result "<one sentence>" --comment "<self-reflection>"
```

Otherwise write the line yourself: `{"ts":"<ISO, UTC Z>","skill":"dojo","outcome":…,
"difficulty":…,"provider":…,"model":…,"effort":…|null,"tokensEst":…|null,"result":…,"comment":…}`.

- `outcome`: `shipped` (the goal landed) / `partial` / `no-op` (ran correctly, nothing to
  do) / `parked` (designed or staged, deliberately not landed) / `failed` / `aborted`.
- `difficulty` rates the task as this run met it: 1 trivial - mechanical; 2 routine - the
  method as written; 3 demanding - real judgment calls or one detour; 4 hard - dead ends,
  rework or an operator course-correction; 5 at the edge - partial or failed on the merits.
- `model`/`effort` as your harness states them (`null` effort when you cannot see it).
  `tokensEst` is the drop in the harness's remaining-token counter since this skill was
  invoked, or `null` (with `log-run.mjs`, omit `--tokens-est`); exact figures are measured
  later from transcripts - never guess one.
- `result` is one line (max 240 chars). `comment` (max 2000) is the self-reflection a
  reviewer reads: what worked, what the method made harder, where its instructions were
  wrong, missing or ignored. No filesystem paths or email addresses.
- Never read run logs during a run. They are evidence ABOUT this skill for its reviewer;
  an executor that reads its own diagnosis contaminates the next measurement.

**Project learning.** Only when this run produced an observation that would change how a
future run behaves. A run that went as the method describes writes nothing: an entry that
restates the procedure, records "no issues", or repeats the task is a defect, not a
deliverable. When there is such an observation and local edits are within scope, put one
dated line in the overlay this skill's `## Project overlay` section names, under
`## Skill improvement log`. **Write only into an overlay that already exists.** If the
project has none, put the observation in the response instead - creating a new tracked
file for a reflection is scope the task did not ask for, and a reader who never asked for
the skill has to review it. If the overlay is a structured config (YAML, TOML, JSON),
record the note as comments so the file keeps parsing, or use the response.
Use a supplied memory contract only when its destination and writes are authorized.
Keep project details out of the shared method.

**Method learning.** Identify the installation before editing anything. A local
`.ai/registry-installation.local.json` receipt can identify development versus release,
the registry revision, and selected skill versions. Verify any link's actual target;
do not assume a skill directory is a writable registry link.

- For a pinned release, marketplace cache, ordinary copy, or unknown installation,
  keep a proposal in the project overlay or response. Do not edit the installed method
  or silently relink it. Adoption and rollback are explicit installation operations.
- For a development link, edit the registry only when that checkout is already within
  the accepted task scope. Otherwise report a proposal. Authorized changes belong in
  the source checkout, followed by its gates; commit only when the task authorizes it.
- Record an actual lesson in `LESSONS.md` against the version **used**:
  `## <version-used> - <YYYY-MM-DD> - <project-name>` and concise bullets. A proposal
  must be labeled as such; structural checks are not evidence of field effectiveness.
- Applied skill changes require a version bump: patch for wording, minor for a step
  refinement, major for method redesign. A lesson alone needs no bump. Shared stamped
  clauses are edited in the registry's `docs/skill-clauses/` and regenerated with
  `scripts/apply-skill-clauses.mjs`, never patched in individual installed skills.

**Domain learning.** Follow `## Knowledge sync` when present, within the same scope
and privacy boundaries. A method lesson and a domain knowledge lead are different
artifacts; do not fabricate either to fill a reflection quota.
<!-- /clause: skill-reflection -->

Files in this skill

  • LESSONS.md15.9 KB
  • SKILL.md23.5 KB
  • references/cycle-contract.md4.6 KB
  • references/judge-protocol.md5.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.