From 5f263a15b64fafc1d0ce44fedd7193b9f98791ae Mon Sep 17 00:00:00 2001 From: CMaintz Date: Fri, 25 Sep 2026 15:45:27 +0200 Subject: [PATCH 1/2] refactor: declutter root into docs/ + group presets/ by concern Move narrative docs (OVERVIEW/DESIGN/FEATURES) + design specs (designs/) under docs/; root keeps README/LICENSE/CHANGELOG/CONTRACT + the release-please/commitlint/renovate configs. Group presets/ by concern: lint/ (eslint + pmd), security/ (gitleaks), tickets/ (ticket-schema + ISSUE_TEMPLATE), agent/ (agent-loop, code-standards, collaboration), baselines/ (flaky-baseline). habit-hooks/, arch/, prompt-eval/, renovate.json stay put. Consumer-invisible except foundry-init (gitleaks + pmd fetch paths updated); reusable workflows run in the caller's checkout, not foundry's presets. README + narrative-doc cross-links updated. FEATURES inventory table + minor text path-mentions: follow-up. --- README.md | 20 +++++++++---------- DESIGN.md => docs/DESIGN.md | 0 FEATURES.md => docs/FEATURES.md | 0 OVERVIEW.md => docs/OVERVIEW.md | 4 ++-- {designs => docs/designs}/arch-fitness.md | 0 .../designs}/backlog-feature-driver.md | 4 ++-- .../designs}/changed-scope-gate.md | 2 +- {designs => docs/designs}/flake-triager.md | 2 +- {designs => docs/designs}/loop-telemetry.md | 0 {designs => docs/designs}/prompt-eval.md | 0 .../designs}/tooling-brainstorm.md | 0 {designs => docs/designs}/verb-tiers.md | 0 presets/{ => agent}/agent-loop.md | 0 presets/{ => agent}/code-standards.md | 0 presets/{ => agent}/collaboration.md | 0 .../flaky-baseline.example.json | 0 presets/{ => lint}/eslint.config.mjs | 0 presets/{ => lint}/pmd/no-var.xml | 0 presets/{ => lint}/pmd/ruleset.xml | 0 presets/{ => security}/gitleaks.toml | 0 .../ISSUE_TEMPLATE/agent-feature.yml | 0 presets/{ => tickets}/ticket-schema.md | 0 scripts/foundry-init.sh | 6 +++--- 23 files changed, 19 insertions(+), 19 deletions(-) rename DESIGN.md => docs/DESIGN.md (100%) rename FEATURES.md => docs/FEATURES.md (100%) rename OVERVIEW.md => docs/OVERVIEW.md (99%) rename {designs => docs/designs}/arch-fitness.md (100%) rename {designs => docs/designs}/backlog-feature-driver.md (98%) rename {designs => docs/designs}/changed-scope-gate.md (99%) rename {designs => docs/designs}/flake-triager.md (98%) rename {designs => docs/designs}/loop-telemetry.md (100%) rename {designs => docs/designs}/prompt-eval.md (100%) rename {designs => docs/designs}/tooling-brainstorm.md (100%) rename {designs => docs/designs}/verb-tiers.md (100%) rename presets/{ => agent}/agent-loop.md (100%) rename presets/{ => agent}/code-standards.md (100%) rename presets/{ => agent}/collaboration.md (100%) rename presets/{ => baselines}/flaky-baseline.example.json (100%) rename presets/{ => lint}/eslint.config.mjs (100%) rename presets/{ => lint}/pmd/no-var.xml (100%) rename presets/{ => lint}/pmd/ruleset.xml (100%) rename presets/{ => security}/gitleaks.toml (100%) rename presets/{ => tickets}/ISSUE_TEMPLATE/agent-feature.yml (100%) rename presets/{ => tickets}/ticket-schema.md (100%) diff --git a/README.md b/README.md index 4cded1c..5a1ebec 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ Reusable CI workflows, `mise` task templates and config presets behind a single Companion repo: **[cmaintz-skills](https://github.com/CMaintz/cmaintz-skills)** — the agent half (skills, hooks). The seam between them is [CONTRACT.md](./CONTRACT.md), which is copied verbatim into both. -> **New here? Read [OVERVIEW.md](./OVERVIEW.md)** — the full narrative tour of how the gates, habit sensors, skills, and the self-improving `learn` loop fit together. +> **New here? Read [OVERVIEW.md](./docs/OVERVIEW.md)** — the full narrative tour of how the gates, habit sensors, skills, and the self-improving `learn` loop fit together. > -> **[FEATURES.md](./FEATURES.md)** is the canonical inventory of everything Foundry provides — and the backport checklist: anything non-language-specific built in a consumer repo comes back here. +> **[FEATURES.md](./docs/FEATURES.md)** is the canonical inventory of everything Foundry provides — and the backport checklist: anything non-language-specific built in a consumer repo comes back here. ## The idea @@ -65,7 +65,7 @@ jobs: | `ratchet-report.yml` | PR comment showing how the accepted-debt baselines moved | | `autofix.yml` | add an `autofix` label to a PR → runs `mise run fix`, commits + pushes the result | -Split them across `gate.yml` / `quality.yml` / `security.yml` / `bootstrap.yml` (see [OVERVIEW.md](./OVERVIEW.md) §13). +Split them across `gate.yml` / `quality.yml` / `security.yml` / `bootstrap.yml` (see [OVERVIEW.md](./docs/OVERVIEW.md) §13). ### Presets @@ -75,16 +75,16 @@ Shared config and agent-facing docs the scaffold copies (or, for the docs, `@`-i |---|---| | [`habit-hooks/.toml`](./presets/habit-hooks/) | structural-smell config per stack — tests excluded, the language-independent `generic` duplication check everywhere ([details](./presets/habit-hooks/README.md)) | | [`habit-hooks/java/guides/`](./presets/habit-hooks/java/guides/) | per-smell coaching for the Java sensor — concrete "fix toward this", rendered inline in-loop *and* in CI | -| [`pmd/ruleset.xml`](./presets/pmd/) · `pmd/no-var.xml` | tuned Java ruleset (`ExcessiveParameterList` ≥ 8) + the no-`var` rule | -| [`gitleaks.toml`](./presets/gitleaks.toml) · [`renovate.json`](./presets/renovate.json) | secret-scan allowlist starting point + the dependency-update path the "pin everything" rule needs | -| [`code-standards.md`](./presets/code-standards.md) · [`collaboration.md`](./presets/collaboration.md) · [`agent-loop.md`](./presets/agent-loop.md) | agent-facing standing docs — clean code (functions do one thing / SRP), working discipline (branch hygiene + sub-agents), and the self-correcting loop (observe → fix the cause → verify → repeat until green *and* honest) | -| [`ticket-schema.md`](./presets/ticket-schema.md) · [`ISSUE_TEMPLATE/agent-feature.yml`](./presets/ISSUE_TEMPLATE/agent-feature.yml) | the GitHub-Issue ticket the `/feature` driver works — intent, an acceptance-criteria checklist, scope, pointers. Copy the template into a consumer's `.github/ISSUE_TEMPLATE/` | +| [`pmd/ruleset.xml`](./presets/lint/pmd/) · `pmd/no-var.xml` | tuned Java ruleset (`ExcessiveParameterList` ≥ 8) + the no-`var` rule | +| [`gitleaks.toml`](./presets/security/gitleaks.toml) · [`renovate.json`](./presets/renovate.json) | secret-scan allowlist starting point + the dependency-update path the "pin everything" rule needs | +| [`code-standards.md`](./presets/agent/code-standards.md) · [`collaboration.md`](./presets/agent/collaboration.md) · [`agent-loop.md`](./presets/agent/agent-loop.md) | agent-facing standing docs — clean code (functions do one thing / SRP), working discipline (branch hygiene + sub-agents), and the self-correcting loop (observe → fix the cause → verify → repeat until green *and* honest) | +| [`ticket-schema.md`](./presets/tickets/ticket-schema.md) · [`ISSUE_TEMPLATE/agent-feature.yml`](./presets/tickets/ISSUE_TEMPLATE/agent-feature.yml) | the GitHub-Issue ticket the `/feature` driver works — intent, an acceptance-criteria checklist, scope, pointers. Copy the template into a consumer's `.github/ISSUE_TEMPLATE/` | ### From ticket to PR — the `/feature` driver -Foundry answers *"when is a change done?"* — a green gate. The **`/feature`** driver is the thing in front of that — **ticket in, PR out** — the [`feature`](https://github.com/CMaintz/cmaintz-skills) skill in cmaintz-skills, specified in [designs/backlog-feature-driver.md](./designs/backlog-feature-driver.md). Foundry ships the intake it consumes (the schema + issue template above); the driver: +Foundry answers *"when is a change done?"* — a green gate. The **`/feature`** driver is the thing in front of that — **ticket in, PR out** — the [`feature`](https://github.com/CMaintz/cmaintz-skills) skill in cmaintz-skills, specified in [designs/backlog-feature-driver.md](./docs/designs/backlog-feature-driver.md). Foundry ships the intake it consumes (the schema + issue template above); the driver: -1. **Claim** an `agent:ready` ticket — a GitHub Issue on the [`agent-feature`](./presets/ISSUE_TEMPLATE/agent-feature.yml) form ([schema](./presets/ticket-schema.md)) — flipping it to `agent:working` (atomic, WIP = 1) in its own worktree off `origin/main`. +1. **Claim** an `agent:ready` ticket — a GitHub Issue on the [`agent-feature`](./presets/tickets/ISSUE_TEMPLATE/agent-feature.yml) form ([schema](./presets/tickets/ticket-schema.md)) — flipping it to `agent:working` (atomic, WIP = 1) in its own worktree off `origin/main`. 2. **Loop to the gate** — implement → `mise run gate` → act on the failure + habit-hooks coaching → retry, *bounded* (≤ 5 cycles; bail early on no progress, posting the stuck state to the issue thread and flipping `agent:blocked`). 3. **Verify** the result against the ticket's acceptance-criteria checklist — green ≠ correct. 4. **Hand to `/ship`** — which re-gates, runs a fresh-context review against the linked issue, commits, and opens the PR. The driver never opens a PR itself, so there's one trusted path to `main`. @@ -118,7 +118,7 @@ Two ideas do most of the work: The corollary is enforced rather than requested: a PR that changes the ruleset *and* production source fails `ruleset-guard` unless a human labels it `ruleset-change`. Otherwise the cheapest fix for `high-complexity` is `// eslint-disable-next-line`. -Full rationale: [DESIGN.md](./DESIGN.md). +Full rationale: [DESIGN.md](./docs/DESIGN.md). ## Status diff --git a/DESIGN.md b/docs/DESIGN.md similarity index 100% rename from DESIGN.md rename to docs/DESIGN.md diff --git a/FEATURES.md b/docs/FEATURES.md similarity index 100% rename from FEATURES.md rename to docs/FEATURES.md diff --git a/OVERVIEW.md b/docs/OVERVIEW.md similarity index 99% rename from OVERVIEW.md rename to docs/OVERVIEW.md index 516072b..881eb2a 100644 --- a/OVERVIEW.md +++ b/docs/OVERVIEW.md @@ -4,7 +4,7 @@ A narrative tour of the system: the harness engineering, the gates, the habit sensors, the skills, and the loop that lets an agent get better at a codebase over time. If you read one document, read this one. -For the rules themselves see [CONTRACT.md](./CONTRACT.md); for the design +For the rules themselves see [CONTRACT.md](../CONTRACT.md); for the design rationale and decisions see [DESIGN.md](./DESIGN.md). --- @@ -39,7 +39,7 @@ The system is three moving parts, deliberately separated by who consumes them: us. It's the structural-smell sensor layer, and Foundry borrows its tool-independent smell vocabulary as a backbone. -The seam between `foundry` and `cmaintz-skills` is [CONTRACT.md](./CONTRACT.md), +The seam between `foundry` and `cmaintz-skills` is [CONTRACT.md](../CONTRACT.md), copied verbatim into both. If those two copies ever need to differ, the split was wrong. diff --git a/designs/arch-fitness.md b/docs/designs/arch-fitness.md similarity index 100% rename from designs/arch-fitness.md rename to docs/designs/arch-fitness.md diff --git a/designs/backlog-feature-driver.md b/docs/designs/backlog-feature-driver.md similarity index 98% rename from designs/backlog-feature-driver.md rename to docs/designs/backlog-feature-driver.md index 85c71aa..d3cda59 100644 --- a/designs/backlog-feature-driver.md +++ b/docs/designs/backlog-feature-driver.md @@ -53,8 +53,8 @@ preset artifacts in `foundry`. So: | Artifact | Repo | Path | |---|---|---| | The `/feature` driver skill | `cmaintz-skills` | `skills/feature/SKILL.md` (+ helpers) | -| GitHub issue template | `foundry` | `presets/ISSUE_TEMPLATE/agent-feature.yml` | -| Ticket schema (reference) | `foundry` | `presets/ticket-schema.md` | +| GitHub issue template | `foundry` | `presets/tickets/ISSUE_TEMPLATE/agent-feature.yml` | +| Ticket schema (reference) | `foundry` | `presets/tickets/ticket-schema.md` | | Inventory entry | `foundry` | `FEATURES.md` (same session) | Adding a skill is **additive** under CONTRACT versioning — no major bump. diff --git a/designs/changed-scope-gate.md b/docs/designs/changed-scope-gate.md similarity index 99% rename from designs/changed-scope-gate.md rename to docs/designs/changed-scope-gate.md index 913976a..256e266 100644 --- a/designs/changed-scope-gate.md +++ b/docs/designs/changed-scope-gate.md @@ -4,7 +4,7 @@ **Home:** foundry (per-`mise` template) · **Placement weight:** shift-left (local only) **Implemented:** `mise/ts.toml` — `lint` + `test` honour `FOUNDRY_SINCE` (validated -across unset / valid-ref / empty / unresolvable-ref); `presets/agent-loop.md` documents +across unset / valid-ref / empty / unresolvable-ref); `presets/agent/agent-loop.md` documents the activation (fast scoped inner-loop runs, whole-tree final gate); `mise/java.toml` — honest "Gradle already scopes it" note, `novar` folded into `lint` and made ratchet-scoped via `FOUNDRY_BASE_REF`; reusable `java.yml` — separate `no-var` job + diff --git a/designs/flake-triager.md b/docs/designs/flake-triager.md similarity index 98% rename from designs/flake-triager.md rename to docs/designs/flake-triager.md index 9a1023e..7bcceeb 100644 --- a/designs/flake-triager.md +++ b/docs/designs/flake-triager.md @@ -8,7 +8,7 @@ post-processes a test report (JUnit XML *and* vitest JSON) against `flaky-baseli and fails only if a NON-quarantined test failed (quarantined flakes are printed, never hidden); `classify` mode reruns failed tests N times to separate flakes (flip) from real failures (always fail) and surfaces prune candidates (quarantined-but-now-stable). Both -modes tested across formats + quarantined/real/no-baseline cases. `presets/flaky-baseline.example.json` +modes tested across formats + quarantined/real/no-baseline cases. `presets/baselines/flaky-baseline.example.json` (schema); baseline reuses the guard's `snooze` kind — verified add=loosening (needs label), remove=tightening (free), no new guard code. `mise/ts.toml` gains an opt-in `test:flaky` integration task. **Not yet:** live rerun on a real runner (no JVM/node diff --git a/designs/loop-telemetry.md b/docs/designs/loop-telemetry.md similarity index 100% rename from designs/loop-telemetry.md rename to docs/designs/loop-telemetry.md diff --git a/designs/prompt-eval.md b/docs/designs/prompt-eval.md similarity index 100% rename from designs/prompt-eval.md rename to docs/designs/prompt-eval.md diff --git a/designs/tooling-brainstorm.md b/docs/designs/tooling-brainstorm.md similarity index 100% rename from designs/tooling-brainstorm.md rename to docs/designs/tooling-brainstorm.md diff --git a/designs/verb-tiers.md b/docs/designs/verb-tiers.md similarity index 100% rename from designs/verb-tiers.md rename to docs/designs/verb-tiers.md diff --git a/presets/agent-loop.md b/presets/agent/agent-loop.md similarity index 100% rename from presets/agent-loop.md rename to presets/agent/agent-loop.md diff --git a/presets/code-standards.md b/presets/agent/code-standards.md similarity index 100% rename from presets/code-standards.md rename to presets/agent/code-standards.md diff --git a/presets/collaboration.md b/presets/agent/collaboration.md similarity index 100% rename from presets/collaboration.md rename to presets/agent/collaboration.md diff --git a/presets/flaky-baseline.example.json b/presets/baselines/flaky-baseline.example.json similarity index 100% rename from presets/flaky-baseline.example.json rename to presets/baselines/flaky-baseline.example.json diff --git a/presets/eslint.config.mjs b/presets/lint/eslint.config.mjs similarity index 100% rename from presets/eslint.config.mjs rename to presets/lint/eslint.config.mjs diff --git a/presets/pmd/no-var.xml b/presets/lint/pmd/no-var.xml similarity index 100% rename from presets/pmd/no-var.xml rename to presets/lint/pmd/no-var.xml diff --git a/presets/pmd/ruleset.xml b/presets/lint/pmd/ruleset.xml similarity index 100% rename from presets/pmd/ruleset.xml rename to presets/lint/pmd/ruleset.xml diff --git a/presets/gitleaks.toml b/presets/security/gitleaks.toml similarity index 100% rename from presets/gitleaks.toml rename to presets/security/gitleaks.toml diff --git a/presets/ISSUE_TEMPLATE/agent-feature.yml b/presets/tickets/ISSUE_TEMPLATE/agent-feature.yml similarity index 100% rename from presets/ISSUE_TEMPLATE/agent-feature.yml rename to presets/tickets/ISSUE_TEMPLATE/agent-feature.yml diff --git a/presets/ticket-schema.md b/presets/tickets/ticket-schema.md similarity index 100% rename from presets/ticket-schema.md rename to presets/tickets/ticket-schema.md diff --git a/scripts/foundry-init.sh b/scripts/foundry-init.sh index 43a075f..096a3c0 100644 --- a/scripts/foundry-init.sh +++ b/scripts/foundry-init.sh @@ -49,7 +49,7 @@ fetch "mise/$STACK.toml" "$WD/mise.toml" fetch "presets/habit-hooks/$HH.toml" "$WD/.habit-hooks/config.toml" echo "- shared presets" -fetch "presets/gitleaks.toml" ".gitleaks.toml" +fetch "presets/security/gitleaks.toml" ".gitleaks.toml" fetch "presets/renovate.json" "renovate.json" fetch "scripts/ruleset_guard.py" "scripts/ruleset_guard.py" @@ -67,8 +67,8 @@ elif ! grep -qxF '.foundry/' .gitignore 2>/dev/null; then echo " updated: .gitignore (+.foundry/)" fi if [ "$STACK" = "java" ]; then - fetch "presets/pmd/ruleset.xml" "$WD/pmd/ruleset.xml" - fetch "presets/pmd/no-var.xml" "$WD/config/pmd/no-var.xml" + fetch "presets/lint/pmd/ruleset.xml" "$WD/pmd/ruleset.xml" + fetch "presets/lint/pmd/no-var.xml" "$WD/config/pmd/no-var.xml" # jscpd's ignore list (tests + fixtures). Inert while jscpd is disabled in the # config, but pre-placed so that enabling duplication detection doesn't first gate # test code — jscpd walks the dir itself and ignores the config's `files` list. From d4bbe15e38fddc615940ae4e3f4be236f4da9533 Mon Sep 17 00:00:00 2001 From: CMaintz Date: Fri, 25 Sep 2026 23:06:22 +0200 Subject: [PATCH 2/2] fix(docs): 'criticals' -> 'critical' in the gate demo The typos check (lint-workflows) flagged it in the demo cast/svg + its source build-cast.mjs. Fixed all three so they stay consistent (the .cast/.svg are generated from the .mjs; hand-fixed here to match without regenerating the whole cast). --- docs/build-cast.mjs | 2 +- docs/gate-demo.cast | 2 +- docs/gate-demo.svg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/build-cast.mjs b/docs/build-cast.mjs index 4777ece..eed3b61 100644 --- a/docs/build-cast.mjs +++ b/docs/build-cast.mjs @@ -14,7 +14,7 @@ const steps = [ [0.6, ' lint ' + ok + '\r\n'], [0.5, ' typecheck ' + ok + '\r\n'], [0.6, ' test ' + ok + dim(' 142 passed . coverage 91%') + '\r\n'], - [0.6, ' audit ' + ok + dim(' 0 criticals . secrets clean') + '\r\n'], + [0.6, ' audit ' + ok + dim(' 0 critical . secrets clean') + '\r\n'], [0.9, ' ' + badge + dim(' nothing merges without this') + '\r\n'], [1.3, '\r\n' + dim('# linters, types, tests & scanners hold sole authority — the LLM only proposes.') + '\r\n'], [1.4, ' '], diff --git a/docs/gate-demo.cast b/docs/gate-demo.cast index 3271501..4177fe8 100644 --- a/docs/gate-demo.cast +++ b/docs/gate-demo.cast @@ -4,7 +4,7 @@ [1.9,"o"," lint \u001b[1;32mok\u001b[0m\r\n"] [2.4,"o"," typecheck \u001b[1;32mok\u001b[0m\r\n"] [3,"o"," test \u001b[1;32mok\u001b[0m\u001b[90m 142 passed . coverage 91%\u001b[0m\r\n"] -[3.6,"o"," audit \u001b[1;32mok\u001b[0m\u001b[90m 0 criticals . secrets clean\u001b[0m\r\n"] +[3.6,"o"," audit \u001b[1;32mok\u001b[0m\u001b[90m 0 critical . secrets clean\u001b[0m\r\n"] [4.5,"o"," \u001b[1;42m GATE GREEN \u001b[0m\u001b[90m nothing merges without this\u001b[0m\r\n"] [5.8,"o","\r\n\u001b[90m# linters, types, tests & scanners hold sole authority — the LLM only proposes.\u001b[0m\r\n"] [7.2,"o"," "] diff --git a/docs/gate-demo.svg b/docs/gate-demo.svg index ebc60c1..63977db 100644 --- a/docs/gate-demo.svg +++ b/docs/gate-demo.svg @@ -1 +1 @@ -#onedeterministicgate—whileanagentedits,beforeyoupush,andonthePR$miserungatelintoktypecheckoktestok142passed.coverage91%auditok0criticals.secretscleanGATE GREENnothingmergeswithoutthis#linters,types,tests&scannersholdsoleauthority—theLLMonlyproposes. \ No newline at end of file +#onedeterministicgate—whileanagentedits,beforeyoupush,andonthePR$miserungatelintoktypecheckoktestok142passed.coverage91%auditok0critical.secretscleanGATE GREENnothingmergeswithoutthis#linters,types,tests&scannersholdsoleauthority—theLLMonlyproposes. \ No newline at end of file