session-orchestrator 4.1.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/.agents/skills/session-plan/SKILL.md +1 -1
  2. package/.agents/skills/session-start/SKILL.md +1 -1
  3. package/.agents/skills/ux-grill/SKILL.md +22 -0
  4. package/.claude-plugin/marketplace.json +1 -1
  5. package/.claude-plugin/plugin.json +3 -2
  6. package/.codex-plugin/plugin.json +1 -1
  7. package/.codex-plugin/skills/session-plan/SKILL.md +1 -1
  8. package/.codex-plugin/skills/session-start/SKILL.md +1 -1
  9. package/.codex-plugin/skills/ux-grill/SKILL.md +21 -0
  10. package/.codex-plugin/skills/ux-grill/agents/openai.yaml +5 -0
  11. package/.cursor/commands/ux-grill.md +14 -0
  12. package/.cursor/skills/session-plan/SKILL.md +1 -1
  13. package/.cursor/skills/session-start/SKILL.md +1 -1
  14. package/.cursor/skills/ux-grill/SKILL.md +13 -0
  15. package/.cursor-plugin/plugin.json +1 -1
  16. package/AGENTS.md +2 -1
  17. package/CHANGELOG.md +128 -1
  18. package/README.md +98 -86
  19. package/agents/dialectic-deriver.md +11 -0
  20. package/agents/ux-evaluator.md +1 -1
  21. package/commands/close.md +3 -3
  22. package/commands/go.md +2 -0
  23. package/commands/memory-cleanup.md +4 -3
  24. package/commands/persona-panel.md +1 -1
  25. package/commands/session.md +3 -2
  26. package/commands/ux-grill.md +51 -0
  27. package/docs/README.md +4 -4
  28. package/docs/USER-GUIDE.md +117 -50
  29. package/docs/agent-authoring.md +2 -2
  30. package/docs/baseline.md +55 -1
  31. package/docs/ci-setup.md +1 -1
  32. package/docs/codex-setup.md +9 -0
  33. package/docs/components.md +9 -9
  34. package/docs/cursor-setup.md +1 -0
  35. package/docs/events-schema.md +13 -6
  36. package/docs/github-mirror-protection.md +61 -20
  37. package/docs/instruction-delivery.md +1 -1
  38. package/docs/memory-proposal-flow.md +3 -3
  39. package/docs/migration-v4.md +2 -2
  40. package/docs/migration-v5.md +62 -0
  41. package/docs/owner-config-schema.md +74 -90
  42. package/docs/persona-panel.md +4 -4
  43. package/docs/pi-setup.md +1 -0
  44. package/docs/rule-authoring.md +13 -6
  45. package/docs/scope-collision-guard.md +16 -0
  46. package/docs/session-config-reference.md +55 -22
  47. package/docs/session-config-template.md +9 -5
  48. package/docs/vault-docs-architecture.md +4 -2
  49. package/hooks/_lib/hook-import-set.json +70 -3
  50. package/hooks/_lib/lock-bootstrap.mjs +84 -1
  51. package/hooks/_lib/vcs-create-matcher.mjs +401 -16
  52. package/hooks/enforce-scope.mjs +201 -0
  53. package/hooks/hooks-codex.json +1 -1
  54. package/hooks/hooks-cursor.json +5 -0
  55. package/hooks/hooks.json +7 -2
  56. package/hooks/on-session-start.mjs +171 -49
  57. package/hooks/post-bash-issue-budget-refund.mjs +375 -0
  58. package/hooks/pre-auq-clarity.mjs +70 -18
  59. package/hooks/pre-bash-issue-budget.mjs +170 -26
  60. package/hooks/subagent-telemetry.mjs +106 -20
  61. package/package.json +5 -4
  62. package/pi/prompts/ux-grill.md +12 -0
  63. package/scripts/baseline-archetypes.mjs +28 -0
  64. package/scripts/ci/assert-vitest-green.mjs +4 -2
  65. package/scripts/dialectic-deriver.mjs +32 -8
  66. package/scripts/emit-session.mjs +72 -1
  67. package/scripts/lib/agent-status.mjs +441 -9
  68. package/scripts/lib/auq/schema.mjs +10 -3
  69. package/scripts/lib/auto-dialectic.mjs +0 -68
  70. package/scripts/lib/baseline-archetypes.mjs +439 -0
  71. package/scripts/lib/build-live-signals.mjs +5 -6
  72. package/scripts/lib/ci-status-banner.mjs +29 -6
  73. package/scripts/lib/claude-md-budget-lint.mjs +52 -2
  74. package/scripts/lib/config/issue-budget.mjs +68 -8
  75. package/scripts/lib/config/private-config-dir.mjs +3 -2
  76. package/scripts/lib/config/remote-hosts.mjs +2 -2
  77. package/scripts/lib/config-schema.mjs +79 -0
  78. package/scripts/lib/config.mjs +12 -1
  79. package/scripts/lib/eval/engine.mjs +7 -1
  80. package/scripts/lib/file-lock.mjs +151 -8
  81. package/scripts/lib/git-porcelain.mjs +113 -0
  82. package/scripts/lib/instruction-budget-guard.mjs +415 -47
  83. package/scripts/lib/io.mjs +29 -4
  84. package/scripts/lib/issue-budget-reconcile.mjs +392 -0
  85. package/scripts/lib/issue-budget.mjs +412 -9
  86. package/scripts/lib/learnings/evolve-telemetry.mjs +1 -2
  87. package/scripts/lib/learnings/sizing-subject.mjs +44 -0
  88. package/scripts/lib/locks/staging-fence-lock.mjs +19 -38
  89. package/scripts/lib/locks/state-md-lock.mjs +19 -41
  90. package/scripts/lib/maintenance-due-banner.mjs +450 -0
  91. package/scripts/lib/owner-config.example.yaml +29 -46
  92. package/scripts/lib/owner-yaml.mjs +14 -13
  93. package/scripts/lib/peer-cards/merger.mjs +143 -0
  94. package/scripts/lib/pre-dispatch-check.mjs +20 -14
  95. package/scripts/lib/project-hygiene.mjs +81 -30
  96. package/scripts/lib/quality-gate.mjs +27 -71
  97. package/scripts/lib/reconcile/engine.mjs +19 -1
  98. package/scripts/lib/reconcile/writer.mjs +278 -11
  99. package/scripts/lib/resource-probe/evaluate.mjs +19 -21
  100. package/scripts/lib/rules-sync.mjs +34 -4
  101. package/scripts/lib/scope-echo.mjs +346 -0
  102. package/scripts/lib/session-close-backfill.mjs +182 -40
  103. package/scripts/lib/session-end/phase-skip.mjs +85 -86
  104. package/scripts/lib/session-end/tail-runner.mjs +178 -0
  105. package/scripts/lib/session-lock.mjs +62 -2
  106. package/scripts/lib/session-record-repair.mjs +91 -0
  107. package/scripts/lib/session-schema/constants.mjs +6 -0
  108. package/scripts/lib/session-schema/filters.mjs +26 -1
  109. package/scripts/lib/session-schema/validator.mjs +20 -0
  110. package/scripts/lib/session-shape.mjs +558 -0
  111. package/scripts/lib/session-start-probes.mjs +429 -56
  112. package/scripts/lib/session-token-rollup.mjs +95 -10
  113. package/scripts/lib/state-md/frontmatter-mutators.mjs +22 -34
  114. package/scripts/lib/state-md.mjs +1 -0
  115. package/scripts/lib/subagents-schema.mjs +77 -9
  116. package/scripts/lib/telemetry/pricing.mjs +197 -0
  117. package/scripts/lib/telemetry/sync.mjs +50 -1
  118. package/scripts/lib/test-runner/artifact-paths.mjs +30 -5
  119. package/scripts/lib/test-runner/issue-reconcile.mjs +45 -8
  120. package/scripts/lib/tmux-layout/layouts.mjs +62 -4
  121. package/scripts/lib/ux-grill/collect.mjs +1163 -0
  122. package/scripts/lib/ux-grill/compare.mjs +285 -0
  123. package/scripts/lib/ux-grill/manifest.mjs +618 -0
  124. package/scripts/lib/ux-grill/measures.mjs +431 -0
  125. package/scripts/lib/ux-grill/paths.mjs +224 -0
  126. package/scripts/lib/ux-grill/pencil-coverage.mjs +284 -0
  127. package/scripts/lib/ux-grill/reconcile.mjs +344 -0
  128. package/scripts/lib/ux-grill/run-record.mjs +316 -0
  129. package/scripts/lib/ux-grill/schema.mjs +321 -0
  130. package/scripts/lib/validate/check-skill-script-paths.mjs +33 -10
  131. package/scripts/lib/validate/check-untracked-test-deps.mjs +33 -19
  132. package/scripts/lib/validate/check-unwired-features.mjs +56 -27
  133. package/scripts/lib/vault-mirror/process.mjs +2 -1
  134. package/scripts/lib/vault-status/board-lock.mjs +18 -0
  135. package/scripts/lib/vault-status/board-writer.mjs +8 -0
  136. package/scripts/lib/vault-status/narrative-mirror.mjs +4 -4
  137. package/scripts/lib/wave-resource-gate.mjs +23 -27
  138. package/scripts/lib/wave-sizing.mjs +10 -3
  139. package/scripts/materialize-wave-scope.mjs +68 -14
  140. package/scripts/mcp-server.sh +16 -1
  141. package/scripts/print-applicable-rules.mjs +7 -6
  142. package/scripts/print-learnings-index.mjs +3 -2
  143. package/scripts/release.mjs +7 -2
  144. package/scripts/session-shape.mjs +266 -0
  145. package/skills/_shared/config-reading.md +15 -9
  146. package/skills/_shared/private-capability-context.md +89 -0
  147. package/skills/bootstrap/SKILL.md +60 -209
  148. package/skills/bootstrap/_shared-template.md +99 -14
  149. package/skills/bootstrap/deep-template.md +36 -26
  150. package/skills/bootstrap/fast-template.md +44 -8
  151. package/skills/bootstrap/intensity-heuristic.md +10 -4
  152. package/skills/bootstrap/private-contract.md +119 -0
  153. package/skills/bootstrap/public-fallback.md +30 -18
  154. package/skills/bootstrap/references/bootstrap-ecosystem-health-flow.md +48 -0
  155. package/skills/bootstrap/references/bootstrap-refresh-lock-flow.md +37 -0
  156. package/skills/bootstrap/references/bootstrap-retroactive-flow.md +108 -0
  157. package/skills/bootstrap/references/bootstrap-rules-fetch-bridge.md +64 -0
  158. package/skills/bootstrap/standard-template.md +39 -24
  159. package/skills/claude-md-drift-check/SKILL.md +9 -2
  160. package/skills/claude-md-drift-check/checker.mjs +213 -21
  161. package/skills/discovery/SKILL.md +6 -173
  162. package/skills/discovery/probes/vault-staleness.mjs +35 -5
  163. package/skills/discovery/probes-docs.md +8 -4
  164. package/skills/discovery/probes-supply-chain.md +4 -2
  165. package/skills/discovery/probes-ui.md +8 -4
  166. package/skills/discovery/probes-vault.md +12 -4
  167. package/skills/discovery/references/discovery-interactive-triage.md +139 -0
  168. package/skills/discovery/references/discovery-triage-state.md +54 -0
  169. package/skills/docs-orchestrator/audience-mapping.md +1 -1
  170. package/skills/eval/rubric-v1.md +13 -0
  171. package/skills/evolve/SKILL.md +2 -458
  172. package/skills/evolve/references/evolve-analyze-mode.md +360 -0
  173. package/skills/evolve/references/evolve-dialectic-mode.md +139 -0
  174. package/skills/gitlab-ops/SKILL.md +3 -3
  175. package/skills/grill/SKILL.md +1 -1
  176. package/skills/memory-cleanup/SKILL.md +2 -2
  177. package/skills/plan/mode-new.md +9 -0
  178. package/skills/plan/mode-retro.md +4 -3
  179. package/skills/reconcile/SKILL.md +11 -1
  180. package/skills/session-end/SKILL.md +3 -2
  181. package/skills/session-end/drift-operations.md +20 -5
  182. package/skills/session-end/metrics-collection.md +1 -0
  183. package/skills/session-end/phase-3-2-docs-verification.md +1 -1
  184. package/skills/session-end/phase-3-6-tail.md +27 -67
  185. package/skills/session-end/phase-3-7a-recommendations.md +2 -2
  186. package/skills/session-end/references/phase-2-quality-gate.md +3 -3
  187. package/skills/session-end/references/phase-3-documentation-updates.md +8 -6
  188. package/skills/session-end/references/phase-5-issue-cleanup.md +32 -1
  189. package/skills/session-end/session-metrics-write.md +33 -12
  190. package/skills/session-plan/SKILL.md +46 -180
  191. package/skills/session-plan/references/session-plan-task-classification.md +152 -0
  192. package/skills/session-plan/wave-template.md +8 -15
  193. package/skills/session-start/SKILL.md +41 -7
  194. package/skills/session-start/phase-2-5-docs-planning.md +1 -1
  195. package/skills/session-start/phase-8-5-express-path.md +12 -9
  196. package/skills/session-start/references/operations-contract.md +114 -0
  197. package/skills/session-start/references/phase-1-5-session-continuity.md +2 -0
  198. package/skills/session-start/references/phase-4-ssot-environment-check.md +42 -24
  199. package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +3 -1
  200. package/skills/session-start/soul.md +2 -2
  201. package/skills/test-runner/SKILL.md +1 -1
  202. package/skills/test-runner/rubric-v1.md +2 -2
  203. package/skills/tmux-layout/SKILL.md +3 -1
  204. package/skills/ux-grill/SKILL.md +211 -0
  205. package/skills/ux-grill/rubric-v2.md +201 -0
  206. package/skills/ux-grill/soul.md +76 -0
  207. package/skills/wave-executor/SKILL.md +32 -127
  208. package/skills/wave-executor/circuit-breaker.md +3 -1
  209. package/skills/wave-executor/references/wave-executor-quality-gate.md +61 -0
  210. package/skills/wave-executor/references/wave-executor-state-init.md +86 -0
  211. package/skills/wave-executor/references/wave-loop-dispatch.md +12 -2
  212. package/skills/wave-executor/references/wave-loop-review.md +19 -6
  213. package/skills/wave-executor/references/wave-loop-scope-manifest.md +6 -2
  214. package/templates/_shared/ux-manifest.template.md +149 -0
  215. package/templates/nextjs-minimal/package.json +1 -1
  216. package/templates/node-minimal/package.json +1 -1
  217. package/scripts/lib/multi-provider-build/providers.mjs +0 -64
  218. package/scripts/lib/multi-provider-build/templating.mjs +0 -130
  219. package/scripts/lib/owner-config/coerce.mjs +0 -29
  220. package/scripts/lib/owner-config/constants.mjs +0 -21
  221. package/scripts/lib/owner-config/defaults.mjs +0 -50
  222. package/scripts/lib/owner-config/error.mjs +0 -19
  223. package/scripts/lib/owner-config/index.mjs +0 -13
  224. package/scripts/lib/owner-config/merge.mjs +0 -52
  225. package/scripts/lib/owner-config/validate.mjs +0 -259
  226. package/scripts/lib/owner-config-loader.mjs +0 -170
  227. package/scripts/lib/owner-config.mjs +0 -28
  228. package/scripts/lib/soul-resolve.mjs +0 -130
  229. package/scripts/lib/vault-mirror/render.mjs +0 -8
  230. package/templates/_shared/journey-manifest.md +0 -114
@@ -24,21 +24,39 @@ Idempotency is handled by the writer itself:
24
24
  Shell:
25
25
  ```bash
26
26
  mkdir -p "$REPO_ROOT/.claude"
27
- node "$PLUGIN_ROOT/scripts/lib/rules-sync.mjs" --repo-root "$REPO_ROOT"
28
- cp "$PLUGIN_ROOT/templates/_shared/loop.md" "$REPO_ROOT/.claude/loop.md"
27
+ export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
28
+ RULES_RESULT=$(node --input-type=module <<'NODE'
29
+ import { pathToFileURL } from 'node:url';
30
+ const { syncBootstrapRules } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
31
+ const result = await syncBootstrapRules({ repoRoot: process.env.REPO_ROOT, archetype: process.env.CONFIRMED_ARCHETYPE || undefined });
32
+ process.stdout.write(`${JSON.stringify(result)}\n`);
33
+ if (result.status === 'error') process.exitCode = 2;
34
+ NODE
35
+ ) || exit 2
36
+ printf '%s\n' "$RULES_RESULT"
37
+ while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
38
+ < <(printf '%s\n' "$RULES_RESULT" | jq -r '.created[]')
39
+ if [[ ! -e "$REPO_ROOT/.claude/loop.md" && ! -L "$REPO_ROOT/.claude/loop.md" ]]; then
40
+ cp "$PLUGIN_ROOT/templates/_shared/loop.md" "$REPO_ROOT/.claude/loop.md"
41
+ BOOTSTRAP_FILES+=(.claude/loop.md)
42
+ fi
29
43
  ```
30
44
 
31
45
  The command prints a JSON report (`written` / `skipped` / `preserved` / `errors` / `warnings` / `sanitizer`) and exits non-zero on any error. Surface `errors[]` to the operator; a non-empty `preserved[]` is normal and means a repo-private rule was left alone.
32
46
 
33
47
  Also surface `sanitizer[]` (issue #1098) — `{file, line, kind, text}` records for citations that read fine inside the plugin repo and dangle once vendored (`repo-local-path`, `unresolvable-see-also`). The CLI additionally prints each one to stderr as `rules-sync: sanitizer <kind> <file>:<line> — <text>`. **Report it to the operator; do not act on it automatically** — the sanitizer never rewrites content and never changes the exit code, because silently stripping a citation would change a rule's meaning at vendoring time. A human decides whether the citation is a leak.
34
48
 
35
- Archetype-scoped entries in `rules/_index.md` resolve from `.orchestrator/bootstrap.lock`, which does not exist yet at this step — they report `archetype-unknown` and are skipped. The always-on rules (including `parallel-sessions.md`) are universal and vendor regardless. Re-run `/bootstrap --sync-rules` after the lock is written to pick up the archetype-scoped ones.
49
+ The wrapper re-reads a configured private contract and passes its required plugin
50
+ basenames into the canonical writer. The full set must resolve uniquely before
51
+ any rule is written; source/provenance validation and local preservation still
52
+ apply. On the public path, normal archetype filtering is unchanged. The selected
53
+ ID is explicit during bootstrap; later `/bootstrap --sync-rules` can use the lock.
36
54
 
37
55
  Why: PSA-003 destructive-command safeguards require every consumer repo to carry the parallel-sessions rule. See issue #155. The `loop.md` vendor gives bare `/loop` a repo-aware maintenance prompt (issue #633 Hebel 3).
38
56
 
39
- Why one writer (issue #1060): a literal `cp` from a second source directory bypasses the pre-write validator AND lands a file carrying no provenance header. On the next `--sync-rules` a headerless file is classified as a repo-private override and preserved forever — so the plugin can never update it again, and whichever rival copy is smaller silently wins. `rules/` is the only source with a manifest, archetype scoping, a basename-collision guard and a pre-write validator, so it is the only sanctioned writer to `.claude/rules/`.
57
+ Why one writer (issue #1060): a literal `cp` from a second source directory bypasses the pre-write validator AND lands a file carrying no provenance header. On the next `--sync-rules` a headerless file is classified as a repo-private override and preserved forever — so the plugin can never update it again, and whichever rival copy is smaller silently wins. For every basename declared in `rules/_index.md`, `rules-sync.mjs` is the sole writer: it owns the manifest, archetype scoping, basename-collision guard and pre-write validation. S99 may deliver baseline-only rules after excluding all plugin-owned basenames.
40
58
 
41
- Note: This step runs before the baseline-fetch step (S99/D99), and S99 must NOT overwrite a rule that `rules/` owns. The baseline's copy carries no provenance header, so letting it win would permanently mark the target as a repo-private override the exact failure described above. `.claude/rules/parallel-sessions.md` has therefore been removed from the S99 manifest. Any other basename present in BOTH `rules/_index.md` and the S99 manifest has the same defect and needs the same treatment.
59
+ Note: This step runs before S99/D99. Both the private local rule projection and the optional public fetch filter every basename in `rules/_index.md`, including currently nonmatching scoped entries. `parallel-sessions.md` and any future plugin-owned rule therefore remain under the same single writer.
42
60
 
43
61
  ---
44
62
 
@@ -48,7 +66,13 @@ Copy the opinionated agent templates into the consumer repo:
48
66
 
49
67
  ```bash
50
68
  mkdir -p "$REPO_ROOT/.claude/agents"
51
- cp "$PLUGIN_ROOT/skills/bootstrap/templates/agents/"*.md "$REPO_ROOT/.claude/agents/"
69
+ for _source in "$PLUGIN_ROOT/skills/bootstrap/templates/agents/"*.md; do
70
+ _target=".claude/agents/$(basename "$_source")"
71
+ if [[ ! -e "$REPO_ROOT/$_target" && ! -L "$REPO_ROOT/$_target" ]]; then
72
+ cp "$_source" "$REPO_ROOT/$_target"
73
+ BOOTSTRAP_FILES+=("$_target")
74
+ fi
75
+ done
52
76
  ```
53
77
 
54
78
  This scaffolds 3 opinionated agents (`project-discovery`, `project-code-review`, `project-quality-gate`) following CLAUDE.md Agent Authoring Rules. Consumer repos should edit descriptions/bodies to match project specifics — but keep the frontmatter structure intact (validated by `agent-frontmatter-invalid` probe).
@@ -103,7 +127,13 @@ vault:
103
127
 
104
128
  ## #baseline-fetch — Step S99: (Optional) Fetch Canonical Rules + Agents from Baseline
105
129
 
106
- This step is OPT-IN and only executes when ALL of the following are true:
130
+ For `PATH_TYPE = private` and a confirmed archetype, this step applies only the
131
+ validated local contract rule targets from `private-contract.md`. It is offline,
132
+ rechecks conditional dependencies after scaffolding, preserves existing files,
133
+ and fails closed on an invalid configured contract.
134
+
135
+ For `PATH_TYPE = public`, the existing remote fetch remains OPT-IN and only
136
+ executes when ALL of the following are true:
107
137
  - `baseline-ref` is present in Session Config (e.g., `baseline-ref: main`)
108
138
  - `GITLAB_TOKEN` env var is set
109
139
  - The session-orchestrator plugin includes `scripts/lib/fetch-baseline.mjs`
@@ -116,6 +146,23 @@ Without this step, rules arrive in the repo via Clank's weekly baseline sync MRs
116
146
  **Implementation:**
117
147
 
118
148
  ```bash
149
+ if [[ "${PATH_TYPE:-public}" = "private" ]]; then
150
+ export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
151
+ BASELINE_RULES_RESULT=$(node --input-type=module <<'NODE'
152
+ import { pathToFileURL } from 'node:url';
153
+ const { applyBaselineRules } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
154
+ const result = await applyBaselineRules({
155
+ repoRoot: process.env.REPO_ROOT,
156
+ archetype: process.env.CONFIRMED_ARCHETYPE,
157
+ });
158
+ process.stdout.write(`${JSON.stringify(result)}\n`);
159
+ if (result.status === 'error') process.exitCode = 2;
160
+ NODE
161
+ ) || exit 2
162
+ printf '%s\n' "$BASELINE_RULES_RESULT"
163
+ while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
164
+ < <(printf '%s\n' "$BASELINE_RULES_RESULT" | jq -r '.created[]')
165
+ else
119
166
  BASELINE_REF=$(echo "$CONFIG" | jq -r '."baseline-ref" // empty')
120
167
  BASELINE_PROJECT_ID=$(echo "$CONFIG" | jq -r '."baseline-project-id" // "52"')
121
168
 
@@ -145,6 +192,19 @@ if [[ -n "$BASELINE_REF" && -n "${GITLAB_TOKEN:-}" && -n "${GITLAB_HOST:-}" && -
145
192
  .claude/rules/ai-agent.md
146
193
  .claude/rules/claude-code-usage.md
147
194
  MANIFEST
195
+ # Every plugin-owned basename is excluded, including currently unmatched scoped
196
+ # rules. rules-sync is their sole writer; ownership does not depend on scope.
197
+ export PLUGIN_ROOT RULES_MANIFEST
198
+ node --input-type=module <<'NODE'
199
+ import { readFileSync, writeFileSync } from 'node:fs';
200
+ import path from 'node:path';
201
+ import { pathToFileURL } from 'node:url';
202
+ const { pluginRuleTargets } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
203
+ const owned = new Set(pluginRuleTargets(process.env.PLUGIN_ROOT));
204
+ const files = readFileSync(process.env.RULES_MANIFEST, 'utf8').split('\n')
205
+ .filter(file => file && !owned.has(path.posix.basename(file)));
206
+ writeFileSync(process.env.RULES_MANIFEST, files.join('\n') + '\n');
207
+ NODE
148
208
 
149
209
  echo "Fetching canonical rules from baseline (project $BASELINE_PROJECT_ID, ref $BASELINE_REF)…"
150
210
  # The .mjs CLI is single-file: it prints ONE file body to stdout, exit 0 on success
@@ -153,10 +213,13 @@ MANIFEST
153
213
  SUCCESS_LOG=$(mktemp)
154
214
  while IFS= read -r rule_path; do
155
215
  [[ -z "$rule_path" ]] && continue
216
+ _RULE_CREATED=false
217
+ [[ -e "$REPO_ROOT/$rule_path" || -L "$REPO_ROOT/$rule_path" ]] || _RULE_CREATED=true
156
218
  mkdir -p "$REPO_ROOT/$(dirname "$rule_path")"
157
219
  if node "$PLUGIN_ROOT/scripts/lib/fetch-baseline.mjs" \
158
220
  "$BASELINE_PROJECT_ID" "$rule_path" "$BASELINE_REF" > "$REPO_ROOT/$rule_path"; then
159
221
  printf '%s\n' "$rule_path" >> "$SUCCESS_LOG"
222
+ if [[ "$_RULE_CREATED" = true ]]; then BOOTSTRAP_FILES+=("$rule_path"); fi
160
223
  else
161
224
  # A 404 (or any error) for one rule must not abort the batch — drop the empty
162
225
  # target the redirect created and continue with the next manifest line.
@@ -167,6 +230,8 @@ MANIFEST
167
230
  if [[ -s "$SUCCESS_LOG" ]]; then
168
231
  FETCHED_JSON=$(jq -R . < "$SUCCESS_LOG" | jq -s .)
169
232
  LOCK_FILE="$REPO_ROOT/.claude/.baseline-fetch.lock"
233
+ _FETCH_LOCK_CREATED=false
234
+ [[ -e "$LOCK_FILE" || -L "$LOCK_FILE" ]] || _FETCH_LOCK_CREATED=true
170
235
  mkdir -p "$REPO_ROOT/.claude"
171
236
  FETCHED_JSON="$FETCHED_JSON" BASELINE_PROJECT_ID="$BASELINE_PROJECT_ID" \
172
237
  BASELINE_REF="$BASELINE_REF" LOCK_FILE="$LOCK_FILE" \
@@ -183,6 +248,7 @@ MANIFEST
183
248
  writeFileSync(process.env.LOCK_FILE, JSON.stringify(lock, null, 2) + '\n');
184
249
  "
185
250
  echo "Wrote .claude/.baseline-fetch.lock ($(wc -l < "$SUCCESS_LOG" | tr -d ' ') files)"
251
+ if [[ "$_FETCH_LOCK_CREATED" = true ]]; then BOOTSTRAP_FILES+=(.claude/.baseline-fetch.lock); fi
186
252
  else
187
253
  echo "WARNING: baseline fetch produced no files; rules will arrive via Clank sync MRs (legacy path)" >&2
188
254
  fi
@@ -191,23 +257,39 @@ MANIFEST
191
257
  else
192
258
  echo "Skipping baseline fetch: baseline-ref / GITLAB_TOKEN / GITLAB_HOST not configured (legacy Clank-sync path)"
193
259
  fi
260
+ fi
194
261
  ```
195
262
 
196
- **Failure handling:** If the fetch fails, this step DOES NOT abort bootstrap. The repo still has its scaffold; rules will arrive via the legacy Clank weekly sync MR. The user is informed via stderr.
263
+ **Failure handling:** A private contract/apply error aborts bootstrap. For the public optional remote path, if the fetch fails, this step DOES NOT abort bootstrap. The repo still has its scaffold; rules will arrive via the legacy Clank weekly sync MR. The user is informed via stderr.
197
264
 
198
- **Idempotency:** Re-running bootstrap on an existing repo will overwrite `.claude/rules/*.md` files. Local edits to baseline rules in a repo will be lost on re-fetch — this is intentional (rules are canonical). Repo-specific extensions belong in `.claude/rules/local/*.md` (not fetched).
265
+ **Idempotency:** Private local rules preserve existing files and report them for review. On the public optional remote path, re-running bootstrap on an existing repo will overwrite `.claude/rules/*.md` files. Local edits to baseline rules in a repo will be lost on re-fetch — this is intentional (rules are canonical). Repo-specific extensions belong in `.claude/rules/local/*.md` (not fetched).
199
266
 
200
267
  ---
201
268
 
202
269
  ## #quality-gate-policy — Step 6.5: Quality-Gate Policy File (#183)
203
270
 
204
- Write the canonical quality-gate commands to `.orchestrator/policy/quality-gates.json`. Bootstrap detects the package manager and writes sensible defaults; users may hand-edit afterwards.
271
+ Write canonical commands to `.orchestrator/policy/quality-gates.json`. A private
272
+ contract supplies exact test/typecheck/lint IDs, with `false` and an unavailable
273
+ reason for absent IDs. Public bootstrap retains package-manager defaults.
205
274
 
206
275
  **Idempotency:** Skip this step if `.orchestrator/policy/quality-gates.json` already exists. Do not overwrite user edits.
207
276
 
208
277
  ```bash
209
278
  POLICY_FILE="$REPO_ROOT/.orchestrator/policy/quality-gates.json"
210
- if [[ ! -f "$POLICY_FILE" ]]; then
279
+ if [[ "${PATH_TYPE:-public}" = private ]]; then
280
+ export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
281
+ POLICY_RESULT=$(node --input-type=module <<'NODE'
282
+ import { pathToFileURL } from 'node:url';
283
+ const { writeBaselineQualityPolicy } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
284
+ const result = await writeBaselineQualityPolicy({ repoRoot: process.env.REPO_ROOT, archetype: process.env.CONFIRMED_ARCHETYPE });
285
+ process.stdout.write(`${JSON.stringify(result)}\n`);
286
+ if (result.status === 'error') process.exitCode = 2;
287
+ NODE
288
+ ) || exit 2
289
+ printf '%s\n' "$POLICY_RESULT"
290
+ while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
291
+ < <(printf '%s\n' "$POLICY_RESULT" | jq -r '.created[]')
292
+ elif [[ ! -e "$POLICY_FILE" && ! -L "$POLICY_FILE" ]]; then
211
293
  mkdir -p "$REPO_ROOT/.orchestrator/policy"
212
294
  # Detect package manager via scripts/lib/package-manager.mjs (falls back to npm defaults)
213
295
  PM_JSON="$(node --input-type=module -e "
@@ -226,6 +308,7 @@ if [[ ! -f "$POLICY_FILE" ]]; then
226
308
  "rationale": "Canonical quality-gate commands. Generated by bootstrap. Edit to change test/typecheck/lint invocations across skills. Schema: .orchestrator/policy/quality-gates.schema.json",
227
309
  "commands": $cmds
228
310
  }' > "$POLICY_FILE"
311
+ BOOTSTRAP_FILES+=(.orchestrator/policy/quality-gates.json)
229
312
  echo "Wrote $POLICY_FILE"
230
313
  fi
231
314
  ```
@@ -234,16 +317,18 @@ fi
234
317
 
235
318
  ## #state-md-scaffold — Step 6.6: STATE.md Scaffold (#184)
236
319
 
237
- Scaffold a placeholder `.claude/STATE.md` using the template at `skills/bootstrap/STATE.md.template`. The placeholder records `status: idle` — sessions overwrite it at Pre-Wave 1b.
320
+ Scaffold a placeholder `.claude/STATE.md`. <!-- path-check: example -->
321
+ Use the template at `skills/bootstrap/STATE.md.template`; the placeholder records `status: idle` — sessions overwrite it at Pre-Wave 1b.
238
322
 
239
- **Idempotency:** Skip if `.claude/STATE.md` already exists.
323
+ **Idempotency:** Skip if `.claude/STATE.md` already exists. <!-- path-check: example -->
240
324
 
241
325
  ```bash
242
326
  STATE_FILE="$REPO_ROOT/.claude/STATE.md"
243
- if [[ ! -f "$STATE_FILE" ]]; then
327
+ if [[ ! -e "$STATE_FILE" && ! -L "$STATE_FILE" ]]; then
244
328
  mkdir -p "$REPO_ROOT/.claude"
245
329
  ISO_NOW="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
246
330
  sed "s|<ISO>|$ISO_NOW|g" "$PLUGIN_ROOT/skills/bootstrap/STATE.md.template" > "$STATE_FILE"
331
+ BOOTSTRAP_FILES+=(.claude/STATE.md)
247
332
  echo "Wrote $STATE_FILE"
248
333
  fi
249
334
  ```
@@ -5,6 +5,9 @@
5
5
 
6
6
  Deep tier is a strict superset of Standard tier. Execute all Standard-tier steps first, then the Deep-specific steps below.
7
7
 
8
+ Keep the inherited `BOOTSTRAP_FILES` array. Append each new governance file by
9
+ its relative filename when created; do not append existing files or directories.
10
+
8
11
  ## Step 1–8: Execute Standard Tier
9
12
 
10
13
  Read and execute `skills/bootstrap/standard-template.md` Steps 1–8 in full. Do not skip any step.
@@ -30,7 +33,13 @@ If `VCS` is empty or `none`, skip CI pipeline, issue templates, MR/PR template,
30
33
 
31
34
  ## Step D1: CI Pipeline
32
35
 
33
- Create the CI pipeline file. Mutually exclusive create exactly one based on `VCS`.
36
+ When `PATH_TYPE = private`, keep the selected baseline's rendered CI and
37
+ `ci.profile` from `private-contract.md`. Respect `ci.required: false`; do not
38
+ create a generic Node pipeline for an exempt archetype. A required CI missing
39
+ from staging already aborts. Resolve VCS mismatch explicitly before changing
40
+ canonical CI. Skip the public D1 examples below and continue at D2.
41
+
42
+ For `PATH_TYPE = public`, create exactly one pipeline based on `VCS`.
34
43
 
35
44
  ### If `VCS = gitlab`: `.gitlab-ci.yml`
36
45
 
@@ -208,7 +217,7 @@ Replace `<YYYY-MM-DD>` with today's date in ISO 8601 format (e.g., `2026-04-16`)
208
217
  mkdir -p "$REPO_ROOT/.gitlab/issue_templates"
209
218
  ```
210
219
 
211
- Write `.gitlab/issue_templates/Bug.md`:
220
+ In the consuming repository, create `.gitlab/issue_templates/Bug.md`: <!-- path-check: example -->
212
221
 
213
222
  ```markdown
214
223
  ## Summary
@@ -239,7 +248,7 @@ Write `.gitlab/issue_templates/Bug.md`:
239
248
  <!-- Screenshots, logs, related issues -->
240
249
  ```
241
250
 
242
- Write `.gitlab/issue_templates/Feature.md`:
251
+ In the consuming repository, create `.gitlab/issue_templates/Feature.md`: <!-- path-check: example -->
243
252
 
244
253
  ```markdown
245
254
  ## Summary
@@ -334,7 +343,7 @@ labels: enhancement
334
343
  mkdir -p "$REPO_ROOT/.gitlab/merge_request_templates"
335
344
  ```
336
345
 
337
- Write `.gitlab/merge_request_templates/Default.md`:
346
+ In the consuming repository, create `.gitlab/merge_request_templates/Default.md`: <!-- path-check: example -->
338
347
 
339
348
  ```markdown
340
349
  ## Summary
@@ -492,12 +501,11 @@ If the call fails, log the structured message above and continue. Raw API respon
492
501
 
493
502
  Canonical implementation in [`_shared-template.md#parallel-sessions-rule`](_shared-template.md).
494
503
 
495
- Run `node "$PLUGIN_ROOT/scripts/lib/rules-sync.mjs" --repo-root "$REPO_ROOT"` it vendors every
496
- rule registered in `rules/_index.md` (idempotent: missing→create, identical→skip, differs→overwrite),
497
- and it is the only writer that applies the pre-write validator, the basename-collision guard and the
498
- copy-on-write branch that preserves repo-private rules. The shared partial also runs
499
- `cp "$PLUGIN_ROOT/templates/_shared/loop.md" "$REPO_ROOT/.claude/loop.md"` so bare `/loop` gets a
500
- repo-aware maintenance prompt. See shared partial for full shell command. Issues #155, #633, #1060.
504
+ Execute the shared partial's `syncBootstrapRules` action. It supplies private
505
+ required basenames to `scripts/lib/rules-sync.mjs`, preserving its manifest,
506
+ pre-write validation and local-override checks. The partial appends actual newly
507
+ created rule paths, and creates `.claude/loop.md` only when missing. See the
508
+ shared partial for the executable shell command. Issues #155, #633, #1060.
501
509
 
502
510
  Note: Runs before D99. D99 (via inherited S99) no longer fetches `parallel-sessions.md` from the
503
511
  baseline — that entry was removed from the S99 manifest in #1060. The baseline copy carries no
@@ -511,11 +519,13 @@ Deep tier creates both learnings and sessions metrics plus a schema-linking READ
511
519
 
512
520
  ```bash
513
521
  mkdir -p "$REPO_ROOT/.orchestrator/metrics"
514
- [[ -f "$REPO_ROOT/.orchestrator/metrics/learnings.jsonl" ]] || \
515
- : > "$REPO_ROOT/.orchestrator/metrics/learnings.jsonl"
516
- [[ -f "$REPO_ROOT/.orchestrator/metrics/sessions.jsonl" ]] || \
517
- : > "$REPO_ROOT/.orchestrator/metrics/sessions.jsonl"
518
-
522
+ for _file in learnings.jsonl sessions.jsonl; do
523
+ if [[ ! -e "$REPO_ROOT/.orchestrator/metrics/$_file" && ! -L "$REPO_ROOT/.orchestrator/metrics/$_file" ]]; then
524
+ : > "$REPO_ROOT/.orchestrator/metrics/$_file"
525
+ BOOTSTRAP_FILES+=(".orchestrator/metrics/$_file")
526
+ fi
527
+ done
528
+ if [[ ! -e "$REPO_ROOT/.orchestrator/metrics/README.md" && ! -L "$REPO_ROOT/.orchestrator/metrics/README.md" ]]; then
519
529
  cat > "$REPO_ROOT/.orchestrator/metrics/README.md" <<'README'
520
530
  # Metrics
521
531
 
@@ -530,6 +540,8 @@ Schema: https://github.com/Kanevry/session-orchestrator
530
540
  **Do NOT gitignore** — these files are project artifacts intended to persist
531
541
  across sessions and contributors.
532
542
  README
543
+ BOOTSTRAP_FILES+=(.orchestrator/metrics/README.md)
544
+ fi
533
545
  ```
534
546
 
535
547
  **Idempotent.** Existing files are preserved.
@@ -547,8 +559,10 @@ Standard-template Step S99 already executed as part of "Step 1–8: Execute Stan
547
559
  No additional fetch action is needed here.
548
560
 
549
561
  If S99 ran successfully, `.claude/rules/*.md` and `.claude/.baseline-fetch.lock` are already written
550
- to `$REPO_ROOT`. These files are included in the Deep commit at Step D8 via the `.claude/` entry
551
- in `BOOTSTRAP_FILES`. If S99 was skipped, rules arrive via the legacy Clank weekly sync MR path.
562
+ to `$REPO_ROOT`. Their individual newly created paths remain in `BOOTSTRAP_FILES`
563
+ for the Deep commit at Step D8. If the private contract applies, S99 already
564
+ delivered its local filtered rule union. If public S99 was skipped, rules arrive
565
+ via the legacy Clank weekly sync MR path.
552
566
 
553
567
  ---
554
568
 
@@ -580,6 +594,8 @@ Write `.orchestrator/bootstrap.lock` **atomically** (mktemp + mv prevents a corr
580
594
  process is interrupted mid-write):
581
595
 
582
596
  ```bash
597
+ _LOCK_CREATED=false
598
+ [[ -e "$REPO_ROOT/.orchestrator/bootstrap.lock" || -L "$REPO_ROOT/.orchestrator/bootstrap.lock" ]] || _LOCK_CREATED=true
583
599
  _LOCK_TMP=$(mktemp "$REPO_ROOT/.orchestrator/bootstrap.lock.XXXXXX")
584
600
  cat > "$_LOCK_TMP" << LOCK
585
601
  # .orchestrator/bootstrap.lock
@@ -592,6 +608,7 @@ plugin-version: <session-orchestrator plugin version — read from $PLUGIN_ROOT/
592
608
  bootstrapped-at: <current ISO 8601 UTC — same value as timestamp; distinct field for age-validation probe>
593
609
  LOCK
594
610
  mv "$_LOCK_TMP" "$REPO_ROOT/.orchestrator/bootstrap.lock"
611
+ if [[ "$_LOCK_CREATED" = true ]]; then BOOTSTRAP_FILES+=(.orchestrator/bootstrap.lock); fi
595
612
  ```
596
613
 
597
614
  Set `source` using the same logic as fast-template Step 5.
@@ -604,16 +621,9 @@ Stage all created files and commit:
604
621
 
605
622
  ```bash
606
623
  cd "$REPO_ROOT"
607
- BOOTSTRAP_FILES=(
608
- CLAUDE.md AGENTS.md .gitignore README.md .orchestrator/bootstrap.lock
609
- .orchestrator/policy/quality-gates.json
610
- package.json pyproject.toml tsconfig.json eslint.config.mjs .prettierrc
611
- .editorconfig src/ tests/ CHANGELOG.md CODEOWNERS
612
- .gitlab/ .github/ .claude/
613
- )
614
624
  # Add only the files bootstrap created — no sweeping -u/-A to avoid catching pre-existing files
615
- for _f in "${BOOTSTRAP_FILES[@]}"; do
616
- [[ -e "$_f" ]] && git add -- "$_f"
625
+ for _f in ${BOOTSTRAP_FILES[@]+"${BOOTSTRAP_FILES[@]}"}; do
626
+ [[ -f "$_f" && ! -L "$_f" ]] && git add -- "$_f"
617
627
  done
618
628
  git commit -m "chore: bootstrap (deep)"
619
629
  ```
@@ -14,6 +14,10 @@
14
14
 
15
15
  Intentionally absent: `package.json`, frameworks, tests, CI config. The feature that follows brings its own stack.
16
16
 
17
+ Maintain the inherited `BOOTSTRAP_FILES` array and append every newly created
18
+ relative file at creation. Preserve existing owner files and never reset this
19
+ array when Fast is inherited by Standard or Deep.
20
+
17
21
  ## Step 1: Ensure Git Repo is Initialized
18
22
 
19
23
  ```bash
@@ -38,7 +42,12 @@ After `public-fallback.md` completes CLAUDE.md generation, continue to Step 2b t
38
42
 
39
43
  **If `PATH_TYPE = private`:**
40
44
 
41
- Use the baseline scripts at `$BASELINE_PATH` as directed by the baseline's own documentation. Proceed with baseline-driven CLAUDE.md generation, then continue to Step 2b.
45
+ For Standard/Deep inheritance, `private-contract.md` already rendered the
46
+ instruction file and stack into the repo. Preserve those files and continue
47
+ to Step 2b; use its quality-gate command mapping for missing Session Config
48
+ fields. Preserve the rendered README and `.gitignore` in subsequent Fast steps.
49
+ For a standalone Fast tier, no archetype is selected: use `public-fallback.md`'s
50
+ minimal Fast instruction-file generation and report `source: plugin-template`.
42
51
 
43
52
  **Step 2b: Verify Session Config block.** After writing or updating CLAUDE.md, check for the sentinel string `## Session Config`:
44
53
 
@@ -107,7 +116,8 @@ elif ls *.ts *.js package.json 2>/dev/null | head -1 | grep -q .; then STACK="no
107
116
  else STACK="generic"; fi
108
117
  ```
109
118
 
110
- Write `.gitignore` with the appropriate content:
119
+ If absent, write `.gitignore` with the appropriate content and append `.gitignore`
120
+ to `BOOTSTRAP_FILES`. Preserve an existing file.
111
121
 
112
122
  **Generic (no stack detected):**
113
123
  ```gitignore
@@ -166,6 +176,10 @@ Note: `.orchestrator/` is NOT gitignored — `bootstrap.lock` must be committed.
166
176
 
167
177
  Vendor the canonical always-on rules from the plugin's `rules/` library into `$REPO_ROOT/.claude/rules/`. `rules/` is the single source of truth for every distributable rule — never `cp` a rule file from anywhere else.
168
178
 
179
+ `syncBootstrapRules` calls the canonical `scripts/lib/rules-sync.mjs` writer.
180
+ Standalone Fast uses ordinary plugin rules without private archetype selection;
181
+ inherited Fast passes the confirmed contract ID and records all created paths.
182
+
169
183
  Idempotency is handled by the writer itself:
170
184
  - Missing → create
171
185
  - Exists, plugin-owned (first line is the `<!-- source: session-orchestrator plugin ... -->` header) and byte-identical → skip silently
@@ -175,11 +189,28 @@ Idempotency is handled by the writer itself:
175
189
  Shell:
176
190
  ```bash
177
191
  mkdir -p "$REPO_ROOT/.claude"
178
- node "$PLUGIN_ROOT/scripts/lib/rules-sync.mjs" --repo-root "$REPO_ROOT"
179
- cp "$PLUGIN_ROOT/templates/_shared/loop.md" "$REPO_ROOT/.claude/loop.md"
192
+ export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE
193
+ RULES_RESULT=$(node --input-type=module <<'NODE'
194
+ import { pathToFileURL } from 'node:url';
195
+ const { syncBootstrapRules } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
196
+ const result = await syncBootstrapRules({ repoRoot: process.env.REPO_ROOT,
197
+ archetype: process.env.CONFIRMED_ARCHETYPE || undefined, minimal: !process.env.CONFIRMED_ARCHETYPE });
198
+ process.stdout.write(`${JSON.stringify(result)}\n`);
199
+ if (result.status === 'error') process.exitCode = 2;
200
+ NODE
201
+ ) || exit 2
202
+ printf '%s\n' "$RULES_RESULT"
203
+ while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
204
+ < <(printf '%s\n' "$RULES_RESULT" | jq -r '.created[]')
205
+ if [[ ! -e "$REPO_ROOT/.claude/loop.md" && ! -L "$REPO_ROOT/.claude/loop.md" ]]; then
206
+ cp "$PLUGIN_ROOT/templates/_shared/loop.md" "$REPO_ROOT/.claude/loop.md"
207
+ BOOTSTRAP_FILES+=(.claude/loop.md)
208
+ fi
180
209
  ```
181
210
 
182
- The command prints a JSON report (`written` / `skipped` / `preserved` / `errors` / `warnings` / `sanitizer`) and exits non-zero on any error. At fast tier `.orchestrator/bootstrap.lock` does not exist yet (Step 5 writes it), so archetype-scoped entries report `archetype-unknown` and are skipped — the always-on rules vendor regardless.
211
+ The command prints a JSON report and exits non-zero on any error. At standalone
212
+ Fast tier the lock and selected ID are absent, so scoped rules are skipped.
213
+ Inherited Fast delivers private required targets through the same writer.
183
214
 
184
215
  Surface `errors[]` and `sanitizer[]` to the operator. `sanitizer[]` (issue #1098) carries `{file, line, kind, text}` records for citations that read fine inside the plugin repo and dangle once vendored (`repo-local-path`, `unresolvable-see-also`); the CLI also prints each to stderr as `rules-sync: sanitizer <kind> <file>:<line> — <text>`. **Report it, do not act on it automatically** — it never rewrites content and never changes the exit code, so a human decides whether the citation is a leak.
185
216
 
@@ -189,6 +220,9 @@ Why one writer (issue #1060): a literal `cp` from a second source directory bypa
189
220
 
190
221
  ## Step 4: Generate README.md
191
222
 
223
+ If absent, write the stub below and append `README.md` to `BOOTSTRAP_FILES`.
224
+ Preserve an existing README.
225
+
192
226
  ```markdown
193
227
  # <REPO_NAME>
194
228
 
@@ -207,6 +241,8 @@ Write `.orchestrator/bootstrap.lock` **atomically** (mktemp + mv prevents a corr
207
241
  process is interrupted mid-write):
208
242
 
209
243
  ```bash
244
+ _LOCK_CREATED=false
245
+ [[ -e "$REPO_ROOT/.orchestrator/bootstrap.lock" || -L "$REPO_ROOT/.orchestrator/bootstrap.lock" ]] || _LOCK_CREATED=true
210
246
  _LOCK_TMP=$(mktemp "$REPO_ROOT/.orchestrator/bootstrap.lock.XXXXXX")
211
247
  cat > "$_LOCK_TMP" << LOCK
212
248
  # .orchestrator/bootstrap.lock
@@ -219,6 +255,7 @@ plugin-version: <session-orchestrator plugin version — read from $PLUGIN_ROOT/
219
255
  bootstrapped-at: <current ISO 8601 UTC — same value as timestamp; distinct field for age-validation probe>
220
256
  LOCK
221
257
  mv "$_LOCK_TMP" "$REPO_ROOT/.orchestrator/bootstrap.lock"
258
+ if [[ "$_LOCK_CREATED" = true ]]; then BOOTSTRAP_FILES+=(.orchestrator/bootstrap.lock); fi
222
259
  ```
223
260
 
224
261
  Set `source`:
@@ -231,10 +268,9 @@ Stage all created files and commit:
231
268
 
232
269
  ```bash
233
270
  cd "$REPO_ROOT"
234
- BOOTSTRAP_FILES=(CLAUDE.md AGENTS.md .gitignore README.md .orchestrator/bootstrap.lock .claude/rules/parallel-sessions.md)
235
271
  # Add only the files bootstrap created — no sweeping -u/-A to avoid catching pre-existing files
236
- for _f in "${BOOTSTRAP_FILES[@]}"; do
237
- [[ -e "$_f" ]] && git add -- "$_f"
272
+ for _f in ${BOOTSTRAP_FILES[@]+"${BOOTSTRAP_FILES[@]}"}; do
273
+ [[ -f "$_f" && ! -L "$_f" ]] && git add -- "$_f"
238
274
  done
239
275
  git commit -m "chore: bootstrap (fast)"
240
276
  ```
@@ -8,7 +8,7 @@
8
8
  After executing this algorithm, report:
9
9
 
10
10
  - `RECOMMENDED_TIER`: `fast` | `standard` | `deep`
11
- - `RECOMMENDED_ARCHETYPE`: `static-html` | `node-minimal` | `nextjs-minimal` | `python-uv` | `null`
11
+ - `RECOMMENDED_ARCHETYPE`: a validated private contract ID, one of the public IDs, or `null`
12
12
  - `HEURISTIC_REASON`: one sentence explaining the recommendation (shown to user)
13
13
  - `ARCHETYPE_CONFIDENCE`: `high` | `low` (used to decide whether to ask the optional second question)
14
14
 
@@ -54,7 +54,13 @@ Examples:
54
54
 
55
55
  **Fast tier:** Always `RECOMMENDED_ARCHETYPE = null`, `ARCHETYPE_CONFIDENCE = high`. No stack needed — skip to output.
56
56
 
57
- **Private path (baseline configured):** Always `RECOMMENDED_ARCHETYPE = null` at this stage. The baseline's own archetype selector is used during Standard/Deep scaffolding. Set `ARCHETYPE_CONFIDENCE = high`.
57
+ **Private path (valid configured contract):** Use `BOOTSTRAP_CONTRACT.selected.id`
58
+ from Phase 0.5 and set `ARCHETYPE_CONFIDENCE = high` when markers match. An
59
+ explicit user ID must pass the reader's `--archetype` lookup and takes priority.
60
+ If no markers match, set `RECOMMENDED_ARCHETYPE = null` and
61
+ `ARCHETYPE_CONFIDENCE = low`; select from the returned ordered catalog using
62
+ `private-contract.md` before Standard/Deep scaffolding. Detection follows the
63
+ exported signal predicates and priority; no public default applies here.
58
64
 
59
65
  **Public path + Standard or Deep:** Scan the prompt for these signals:
60
66
 
@@ -66,7 +72,7 @@ Examples:
66
72
  | python, py, data, daten, ml, machine learning, api (python context), django, fastapi, flask, pandas, numpy | `python-uv` | high |
67
73
  | Ambiguous — prompt mentions multiple stacks, no clear frontend/backend split, or is too vague (e.g., "Ich brauche ein Projekt", "neues Repo", "etwas bauen") | `node-minimal` (safe default) | `low` |
68
74
 
69
- When `ARCHETYPE_CONFIDENCE = low`, the bootstrap skill will ask a second `AskUserQuestion` to confirm the archetype. `node-minimal` is the pre-selected default for that question.
75
+ On the public path, when `ARCHETYPE_CONFIDENCE = low`, the bootstrap skill will ask a second `AskUserQuestion` to confirm the archetype. `node-minimal` is the pre-selected default for that question.
70
76
 
71
77
  ## Step 5: Output
72
78
 
@@ -74,7 +80,7 @@ Return all four values to `SKILL.md` Phase 1:
74
80
 
75
81
  ```
76
82
  RECOMMENDED_TIER: fast | standard | deep
77
- RECOMMENDED_ARCHETYPE: static-html | node-minimal | nextjs-minimal | python-uv | null
83
+ RECOMMENDED_ARCHETYPE: <validated private ID> | static-html | node-minimal | nextjs-minimal | python-uv | null
78
84
  HEURISTIC_REASON: <one sentence>
79
85
  ARCHETYPE_CONFIDENCE: high | low
80
86
  ```
@@ -0,0 +1,119 @@
1
+ # Configured Baseline Bootstrap
2
+
3
+ Use this flow only after `public-fallback.md` returned `PATH_TYPE = private`.
4
+ The configured local baseline owns the archetype catalog. The plugin consumes
5
+ its validated, reduced export; it carries no private archetype table.
6
+
7
+ ## Select
8
+
9
+ For Standard/Deep, use the `selected.id` returned by Phase 0.5 when repository
10
+ markers match. An explicit owner-supplied ID takes precedence: validate it with
11
+ `--archetype` before accepting it. A user description can help present choices,
12
+ but cannot invent a catalog ID. When `selected` is null, present the returned
13
+ `archetypes` in `order`, showing their runtime, package manager, UI/API and deploy
14
+ metadata. Ask for the needed selection; paginate if the UI limits option count.
15
+ Do not substitute a public default for missing evidence or an invalid choice.
16
+
17
+ Once selected, set `CONFIRMED_ARCHETYPE` and refresh the contract:
18
+
19
+ ```bash
20
+ BOOTSTRAP_CONTRACT=$(node "$PLUGIN_ROOT/scripts/baseline-archetypes.mjs" \
21
+ --repo "$REPO_ROOT" --archetype "$CONFIRMED_ARCHETYPE") || exit 2
22
+ export BOOTSTRAP_CONTRACT
23
+ ```
24
+
25
+ `status: error` aborts before scaffolding. Its reason is safe to report; do not
26
+ print baseline paths, raw producer diagnostics, or private catalog files.
27
+ `insufficient-evidence` is a selection state, not permission to use `node-minimal`.
28
+ Fast tier has no archetype; use the plugin's minimal instruction-file flow and
29
+ skip this file's scaffold/rules actions until upgrading to Standard/Deep.
30
+
31
+ ## Scaffold
32
+
33
+ Execute this before Standard inherits the Fast steps. It runs only the local
34
+ baseline's `render_archetype_dir`, `render_shared_and_substitute`, and
35
+ `render_archetype_metadata` functions in temporary staging. It excludes all
36
+ staged rules; S99 below and `rules-sync` own rule delivery. It never invokes the
37
+ interactive setup script, package installation, Git, or a remote service.
38
+
39
+ ```bash
40
+ export PLUGIN_ROOT REPO_ROOT CONFIRMED_ARCHETYPE REPO_NAME
41
+ SCAFFOLD_RESULT=$(node --input-type=module <<'NODE'
42
+ import { pathToFileURL } from 'node:url';
43
+ const { scaffoldBaselineArchetype } = await import(pathToFileURL(`${process.env.PLUGIN_ROOT}/scripts/lib/baseline-archetypes.mjs`));
44
+ const result = await scaffoldBaselineArchetype({
45
+ repoRoot: process.env.REPO_ROOT,
46
+ archetype: process.env.CONFIRMED_ARCHETYPE,
47
+ projectName: process.env.REPO_NAME,
48
+ });
49
+ process.stdout.write(`${JSON.stringify(result)}\n`);
50
+ if (result.status === 'error') process.exitCode = 2;
51
+ NODE
52
+ ) || exit 2
53
+ printf '%s\n' "$SCAFFOLD_RESULT"
54
+ while IFS= read -r _file; do BOOTSTRAP_FILES+=("$_file"); done \
55
+ < <(printf '%s\n' "$SCAFFOLD_RESULT" | jq -r '.created[]')
56
+ ```
57
+
58
+ The report lists relative `created` and `preserved` files plus `unavailableGates`. Add only `created`
59
+ files to `BOOTSTRAP_FILES`; an existing file is preserved for owner review.
60
+ All sources and destinations are checked for symlinks before the first copy.
61
+ The renderer's commands are fixed function calls; exported `commands` and
62
+ `qualityGates[].command` remain data throughout lookup and staging.
63
+
64
+ Continue Fast's common steps, preserving the rendered instruction files,
65
+ README, manifests and configuration. Then skip Standard's four public stack
66
+ sections and continue at Step 3a, S99 and the lock/quality-policy steps.
67
+
68
+ ## Expectations
69
+
70
+ Use `selected.runtimes`, `packageManagers`, `ui`, `api`, `deploy`, `commands`,
71
+ `qualityGates`, `ci`, and `browserAutomation` as the scaffold expectations.
72
+ Keep rendered command documentation and CI. Staging normalizes new Session
73
+ Config `test-command`, `typecheck-command`, and `lint-command` from exactly
74
+ matching `qualityGates[].id` values (`test`, `typecheck`, `lint`). An absent gate
75
+ gets the literal failing command `false` and an unavailable explanation, so a
76
+ later generic gate runner cannot report an unsupported check as passing. No
77
+ other ID is silently relabeled. Existing owner instruction files are preserved.
78
+
79
+ For private verification, enumerate the selected `qualityGates` and report each
80
+ declared result. Separately report absent test/typecheck/lint slots as
81
+ unavailable; do not execute their `false` placeholders as if they were declared
82
+ checks, or claim that all three generic checks passed. Command execution is a
83
+ later explicit bootstrap step, separate from lookup and staging. Step 6.5 writes
84
+ the same exact mapping to a new quality policy, whose commands take precedence
85
+ at runtime. Existing owner policy is preserved; report any divergence for review.
86
+ The generic quality runner is unchanged.
87
+
88
+ Deep D1 preserves the baseline CI and its `ci.profile`. If `ci.required` is
89
+ false, do not create a public Node CI pipeline. If true and the baseline did
90
+ not render CI, staging fails. VCS mismatch or a required translation needs an
91
+ explicit owner choice; do not silently replace the canonical CI with a public
92
+ template. The remaining Deep governance steps apply normally.
93
+
94
+ ## Rules
95
+
96
+ S99 re-reads the selected contract after rendering, so dependency-conditional
97
+ targets include the new package manifest. `ruleTargets` is the exported union;
98
+ `pluginRuleTargets` is its intersection with all basenames in `rules/_index.md`.
99
+ Only `baselineRules` may be copied from the local baseline. Every source is a
100
+ validated relative file under `.claude/rules/` or
101
+ `templates/shared/.claude/rules/`, and every target belongs to that union.
102
+ Existing rules are preserved. Plugin rule basenames, including
103
+ `parallel-sessions.md`, are written only by `rules-sync.mjs`. Step 3a invokes
104
+ `syncBootstrapRules`, which reloads the contract and passes `pluginRuleTargets`
105
+ as the writer's validated required basenames. This delivers private requirements
106
+ even when plugin scope tags do not name that archetype. The same action backs
107
+ later `/bootstrap --sync-rules`, resolving the explicit ID, then the lock ID,
108
+ then repository markers. Public/default rule selection remains unchanged.
109
+ Later sync of a valid Fast/null lock without stack markers also uses ordinary
110
+ plugin rules; a configured contract must still validate before that refresh.
111
+
112
+ ## Created files
113
+
114
+ Keep one `BOOTSTRAP_FILES` array throughout inherited Fast/Standard/Deep steps.
115
+ Each writer appends only relative files it actually creates; do not replace the
116
+ array with a stack-specific list. Existing owner files and directories are never
117
+ added merely because they exist. A repeated writer reporting `created: []`
118
+ leaves accumulated paths intact. New governance files are appended individually
119
+ at creation, and commit steps consume this accumulated list without broad globs.