Release 1.1.0 — one config file, and a process weight you choose

`project.yaml` at the repo root is now the single source of truth for a
project's configuration, replacing `production/stage.txt`,
`production/review-mode.txt` and `.claude/docs/technical-preferences.md` (all
three still read as a fallback; nothing is force-deleted).

**`modes.rigor` — one question instead of six.** `minimal`, `standard` or
`full` fronts six knobs: `modes.workflow`, `docs.density`, `qa.level`,
`modes.story_granularity`, `modes.review_mode` and `team.size`. It defaults to
`minimal`, which is a change from 1.0's behaviour: the heavier tier was
measured costing several times more to reach working code without producing a
better result, and returning nothing when a fresh developer inherited the
project. Pin `modes.rigor: standard` to keep 1.0's process level.

Also in this release:

- `/settings` to view or change any setting, and `project.local.yaml` for
  per-developer preferences that should not be committed.
- `system_overrides` to hold one system to a higher standard than the rest of
  the project, and `testing.strict` to set per test type whether missing
  evidence blocks a story or warns.
- A story that changes anything the player sees is not closed until the game
  has been launched, observed, and a screenshot retained in
  `production/qa/evidence/`. A parse check is not a run. This holds at every
  rigor level, including `minimal`, where automated tests are waived but the
  look is not.
- The code root is engine-specific and enforced as such: Godot `src/`, Unity
  `Assets/`, Unreal `Source/<Module>/`. Two of the three will not build a
  project laid out any other way.
- Migration tooling for existing projects: `.claude/scripts/migrate-v1-config.sh`
  converts a 1.0 layout, non-destructively by default, with a report to review
  before `--finalize` deletes anything.
- Ask-before-write holds regardless of personal automation settings.

Upgrading from 1.0 or earlier: see UPGRADING.md. Full list of changes:
CHANGELOG.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xvzG3i7pWQg4LjyDwWMXd
This commit is contained in:
Donchitos
2026-09-23 12:25:11 +10:00
co-authored by Claude Opus 5
parent 984023ddac
commit d05699707f
291 changed files with 24374 additions and 7740 deletions
+55
View File
@@ -0,0 +1,55 @@
---
paths:
- ".claude/agent-memory/**"
---
# Agent Memory Rules
**Agent memory is the one place an agent may write without asking — and the only
one.** `.claude/agent-memory/` is gitignored, per-agent, and never ships. That
exemption exists because the memory is the agent's own working notes about how to
do its job, not a project artifact.
It does **not** extend anywhere else. The Collaboration Protocol still governs
every file under `src/`, `design/`, `docs/`, `production/` and `assets/`: ask
first, naming the path. Writing a memory is never a substitute for asking, and a
memory must never be used to record something the user declined to have written.
## Never record a temporary absence as a durable fact
This is the failure this file exists to prevent, and this repo is unusually
exposed to it.
**CCGS ships as a template the user clones *as their game*.** So on day one every
agent observes the same things — no `src/`, no GDDs, no engine configured, no
`tests/performance/` — and every one of those observations is **guaranteed to
stop being true**. A memory reading *"this repo is the framework, not a game;
perf requests have no target"* is accurate when written and actively harmful two
weeks later, when it tells a future run to return BLOCKED on a project that now
has a build. The agent will not re-derive it; that is what memory is for.
So:
- **Prefer recording a method over a state.** "Confirm an engine project and a
captured profile exist before profiling; return BLOCKED naming what is missing
rather than estimating" is durable. "There is no game here" is a timestamp.
- **If you must record a state, state what invalidates it**, on the same line:
`INVALIDATED WHEN: project.yaml declares an engine, or src/ contains game code.`
A reader with no other context must be able to tell whether the note still
holds.
- **Never record absence of a game, of assets, of tests or of config as a
settled property of the project.** Those are the states CCGS exists to move a
user out of.
## Disclose the write
Say in your response that you recorded a memory and where. An unmentioned write
is indistinguishable from no write, and the user cannot correct a note they do
not know exists — the same reason a skipped check has to announce itself
(`.claude/rules/skill-authoring.md`, obligation 3).
## Verify before you trust
A recalled memory reflects what was true when it was written. If it names a file,
a path, a setting or a count, **check that it still holds before acting on it**.
Memory is a starting point for investigation, never evidence.
+21 -9
View File
@@ -9,7 +9,19 @@ paths:
- File naming: lowercase with underscores only, following `[system]_[name].json` pattern
- Every data file must have a documented schema (either JSON Schema or documented in the corresponding design doc)
- Numeric values must include comments or companion docs explaining what the numbers mean
- Use consistent key naming: camelCase for keys within JSON files
- Use consistent key naming: **`snake_case` for keys within JSON files**, matching
the `[system]_[name].json` file convention one line above and the engine idiom
every other standard in this repo uses.
> **On Unity and Unreal this costs you a mapping layer — budget for it rather
> than changing the keys.** `JsonUtility` binds by *exact field name*, and C#
> fields are `camelCase` per `naming.variables`, so a snake_case file cannot bind
> directly to the type that consumes it. Use a private nested DTO whose fields
> are the wire format and which maps once into your real type, or take a
> dependency that supports a naming policy (Newtonsoft `SnakeCaseNamingStrategy`,
> `System.Text.Json` `JsonNamingPolicy`). Do **not** switch the file to camelCase
> to avoid the DTO: keys are the cross-engine contract. Write the DTO and
> document it as a wire-format boundary — that is the intended shape.
- No orphaned data entries — every entry must be referenced by code or another data file
- Version data files when making breaking schema changes
- Include sensible defaults for all optional fields
@@ -21,16 +33,16 @@ paths:
```json
{
"goblin": {
"baseHealth": 50,
"baseDamage": 8,
"moveSpeed": 3.5,
"lootTable": "loot_goblin_common"
"base_health": 50,
"base_damage": 8,
"move_speed": 3.5,
"loot_table": "loot_goblin_common"
},
"goblin_chief": {
"baseHealth": 150,
"baseDamage": 20,
"moveSpeed": 2.8,
"lootTable": "loot_goblin_rare"
"base_health": 150,
"base_damage": 20,
"move_speed": 2.8,
"loot_table": "loot_goblin_rare"
}
}
```
+4 -1
View File
@@ -5,7 +5,10 @@ paths:
# Design Document Rules
- Every design document MUST contain these 8 sections: Overview, Player Fantasy, Detailed Rules, Formulas, Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria
- The 8 GDD sections are: Overview, Player Fantasy, Detailed Rules, Formulas, Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria
- **How many are required depends on `modes.workflow`** — all 8 at `full`, 5 (+ Formulas when the system **defines numeric rules**: rates, curves, thresholds, costs, damage, drop weights — anything a balance pass would tune) at `standard`, none at `minimal` (the design record there is `design/game-brief.md`). Resolve the tier before flagging a section as missing; see `.claude/docs/workflow-modes.md`
- **The Formulas test is what the system defines, not what it is called.** A system's `Category` in `systems-index.md` is a hint — `Gameplay`, `Economy` and `Progression` almost always qualify — never the test. Do not gate Formulas on a category token: the categories `/map-systems` writes (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio · Narrative · Meta`) do not include `combat` or `AI`, which are example systems *within* `Gameplay`. Every site stating this rule must state the same test.
- **Section-name alias**: The GDD template and `/design-system` author this section as `## Detailed Design`; the design standard calls it **Detailed Rules**. These are the SAME required section — accept either heading and never rewrite one into the other.
- Formulas must include variable definitions, expected value ranges, and example calculations
- Edge cases must explicitly state what happens, not just "handle gracefully"
- Dependencies must be bidirectional — if system A depends on B, B's doc must mention A
+112
View File
@@ -0,0 +1,112 @@
---
paths:
- ".claude/skills/**"
- ".claude/agents/**"
---
# Skill and Gate Authoring
**A check that cannot report that it did not run is not a check.**
The same shape recurs across unrelated subsystems, so treat it as the default
risk in any check you write, not as an unusual mistake.
The failure is always the same trade: a step that could not run produces output
indistinguishable from a step that ran and found nothing. Nobody reading the
output can tell which happened, and the permissive reading is the one that gets
believed, because it is the one that lets work proceed.
## The five obligations
### 1. Every gating verdict needs a "could not assess" value
If a skill emits a verdict something else depends on, its vocabulary must include
one — `NOT ASSESSED`, or the local equivalent — and the report must say *which*
of the reasons applied. A vocabulary of three confident verdicts forces every
unknown into a claim.
**Rank it deliberately.** It must outrank the pass value: a run that could not
assess part of its scope has not established that the scope is good. It must
**not** outrank the failure values: a known problem is more actionable than an
unknown, and demoting a real failure behind an access problem buries it.
**`NOT ASSESSED` is not a gentler failure verdict.** "I looked and found nothing"
and "I could not look" have different fixes — one needs work done, the other
needs access granted or an input classified. Collapsing them sends the reader to
the wrong fix.
### 2. An absent value may not default to the permissive one
Especially when **nothing in the framework writes that key**. Before defaulting,
check who sets it: a key with a reader and no writer takes its default branch on
every project that ever runs, so that branch is not an edge case — it is the
behaviour.
Over-running a check costs minutes. Under-running one ships the category unrun.
### 3. A skipped step announces itself
In the output, not only in the source. If a phase, category, or agent did not run
— wrong engine, missing config, unavailable input, a `team.size` that collapses
the pipeline — the artifact must say so by name. A silent skip and a successful
one are the same artifact.
A rule enforced in the body and never surfaced in the output is, to the reader,
identical to no rule at all.
### 4. Never assert what you cannot source — and wire the gap to the verdict
Where this repo pins external facts (`docs/engine-reference/**`), do not fill a
gap from training data. Write the gap down instead: `NOT SOURCEABLE — <what> is
not covered by <path>`.
**Flagging alone is not enough.** A named gap that does not reach the verdict is
just a comment. Wire it: a category with no sourced inputs must force obligation
1's value, so the gap makes the pass unreachable rather than sitting beside it.
A confidently wrong pattern list is worse than an absent one — it produces a scan
that looks thorough, finds nothing, and reads as a pass.
### 5. Gates derive their covered set; they do not enumerate it
An allowlist pins what was known when it was written and is silent about
everything added since. Derive the set from what the repo actually contains, so a
new skill or agent cannot ship outside coverage by simply not being on a list.
**If the category is not mechanically crisp, say so in the gate and keep the
list.** A gate that fires on forty files does not get fixed, it gets muted — and
a muted gate is worse than a narrow one, because it reads as coverage. When you
keep a list, record *why* derivation failed and state the obligation to extend it.
Two further gate rules earned the hard way:
- **Assert something that cannot be true by accident.** A check for the word
"unity" was satisfied by a file path, and case-insensitively by "community".
Assert a distinctive token instead.
- **A gate you have not watched fail is not a gate.** Break the thing it guards,
confirm it fails, restore. One mutation per tool invocation — a batch that
times out leaves the repo holding a broken file, and `trap … EXIT` does not
survive `SIGTERM`.
## Evidence
Every row below is a real instance this rule was written to prevent.
| Where | What was indistinguishable from success |
|---|---|
| `team-*` engine step | Specialist skipped when no engine configured — output identical to a run that consulted one |
| `team-ui` accessibility gate | Passed vacuously; its criterion file did not exist |
| `yaml-helper` | Locked key in `project.local.yaml` dropped in silence; user saw the default they were overriding |
| all nine `team-*` | Pipeline printed six agents and ran one, with no statement of the difference |
| `/security-audit` | Godot-only greps returned zero hits on Unity/Unreal, and zero hits read as clean |
| `unity/VERSION.md` | "Post-cutoff" table listed pre-cutoff versions, inverting the signal it exists to send |
| `/security-audit` | `platform.multiplayer` had a reader and no writer; the network category never ran, on any project |
| `test-evidence-review` | No verdict for "could not check", so an unverifiable story got a verdict saying it was verified |
| the gate meant to catch all of this | Was a hand-written list, and read green over the gap |
## The test to apply
Before shipping a skill or gate, ask: **if this step silently did not run, what
would the output look like?**
If the answer is "the same", it is not finished.
+12 -1
View File
@@ -12,7 +12,18 @@ paths:
- Performance tests must specify acceptable thresholds and fail if exceeded
- Test data must be defined in the test or in dedicated fixtures, never shared mutable state
- Mock external dependencies — tests should be fast and deterministic
- Every bug fix must have a regression test that would have caught the original bug
- Every bug fix must have a regression test that would have caught the original bug —
and **you must watch it fail before you trust it.** Run the new test against the
unfixed code, confirm it fails, then apply the fix and confirm it passes. A
regression test that has only ever been seen passing is not known to test anything.
> This is `.claude/rules/skill-authoring.md`'s "a gate you have not watched fail
> is not a gate", applied to tests. It is written out here because stating the
> *goal* is not enough. A regression test for an iteration-order defect can use
> a fixture where no cell takes part in two transfers per tick — it then passes
> against the very bug it was written for, and looks authoritative doing it. The
> fixture, not the assertion, is what makes it useless, and only running it
> against the unfixed code exposes that.
## Examples