clean-room-skill 0.1.0 → 0.1.2

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 (95) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.codex-plugin/plugin.json +1 -2
  4. package/README.md +388 -133
  5. package/agents/clean-architect.md +24 -8
  6. package/agents/clean-implementer-verifier-shell.md +36 -0
  7. package/agents/clean-qa-editor.md +31 -8
  8. package/agents/contaminated-handoff-sanitizer.md +37 -0
  9. package/agents/contaminated-manager-verifier.md +28 -9
  10. package/agents/contaminated-source-analyst.md +22 -4
  11. package/assets/clean-room-arch.svg +354 -0
  12. package/bin/install.js +305 -314
  13. package/bin/verify.sh +78 -0
  14. package/docs/ARCHITECTURE.md +274 -0
  15. package/examples/codex/.codex/agents/clean-architect.toml +15 -6
  16. package/examples/codex/.codex/agents/clean-qa-editor.toml +22 -7
  17. package/examples/codex/.codex/agents/contaminated-handoff-sanitizer.toml +18 -0
  18. package/examples/codex/.codex/agents/contaminated-manager-verifier.toml +14 -5
  19. package/examples/codex/.codex/agents/contaminated-source-analyst.toml +11 -4
  20. package/hooks/agent3-verification-runner.py +264 -0
  21. package/hooks/check-artifact-leakage.py +133 -26
  22. package/hooks/clean_room_paths.py +191 -22
  23. package/hooks/deny-clean-room-shell.py +149 -0
  24. package/hooks/deny-clean-source-read.py +93 -36
  25. package/hooks/deny-contaminated-clean-write.py +59 -56
  26. package/hooks/require-clean-room-env.py +161 -6
  27. package/hooks/validate-handoff-package.py +54 -19
  28. package/hooks/validate-json-schema.py +269 -44
  29. package/lib/bootstrap.cjs +247 -0
  30. package/lib/doctor.cjs +312 -0
  31. package/lib/fs-utils.cjs +103 -4
  32. package/lib/hooks.cjs +37 -39
  33. package/lib/install-artifacts.cjs +163 -0
  34. package/lib/install-plan.cjs +252 -0
  35. package/lib/preflight.cjs +425 -0
  36. package/lib/run.cjs +798 -0
  37. package/lib/runtime-layout.cjs +258 -0
  38. package/package.json +7 -3
  39. package/plugin.json +2 -3
  40. package/skills/attended/SKILL.md +10 -6
  41. package/skills/clean-room/SKILL.md +81 -45
  42. package/skills/clean-room/assets/behavior-spec.schema.json +1 -0
  43. package/skills/clean-room/assets/clean-room-result.schema.json +103 -0
  44. package/skills/clean-room/assets/clean-run-context.schema.json +556 -0
  45. package/skills/clean-room/assets/contamination-incident.schema.json +1 -0
  46. package/skills/clean-room/assets/handoff-package.schema.json +3 -7
  47. package/skills/clean-room/assets/implementation-plan.schema.json +297 -0
  48. package/skills/clean-room/assets/implementation-report.schema.json +333 -0
  49. package/skills/clean-room/assets/init-config.schema.json +225 -0
  50. package/skills/clean-room/assets/preflight-goal.schema.json +439 -0
  51. package/skills/clean-room/assets/qc-report.schema.json +3 -0
  52. package/skills/clean-room/assets/task-manifest.schema.json +612 -3
  53. package/skills/clean-room/examples/README.md +22 -5
  54. package/skills/clean-room/examples/contaminated-side/init-config.json +52 -0
  55. package/skills/clean-room/examples/contaminated-side/preflight-goal.json +88 -0
  56. package/skills/clean-room/examples/contaminated-side/task-manifest.json +473 -0
  57. package/skills/clean-room/examples/minimal-spec-package/behavior-spec.json +1 -1
  58. package/skills/clean-room/examples/minimal-spec-package/clean-room-result.json +10 -0
  59. package/skills/clean-room/examples/minimal-spec-package/clean-run-context.json +139 -0
  60. package/skills/clean-room/examples/minimal-spec-package/contamination-incident.json +10 -0
  61. package/skills/clean-room/examples/minimal-spec-package/handoff-package.json +8 -2
  62. package/skills/clean-room/examples/minimal-spec-package/implementation-plan.json +88 -0
  63. package/skills/clean-room/examples/minimal-spec-package/implementation-report.json +30 -0
  64. package/skills/clean-room/examples/valid-handoff-package/behavior-spec.json +61 -0
  65. package/skills/clean-room/examples/valid-handoff-package/handoff-package.json +26 -0
  66. package/skills/clean-room/references/CONTROLLER-LOOP.md +100 -0
  67. package/skills/clean-room/references/LEAKAGE-RULES.md +18 -7
  68. package/skills/clean-room/references/PREFLIGHT.md +71 -0
  69. package/skills/clean-room/references/PROCESS.md +162 -70
  70. package/skills/clean-room/references/SPEC-SCHEMA.md +149 -13
  71. package/skills/clean-room/references/TARGET-LANGUAGE-GUIDE.md +7 -0
  72. package/skills/clean-room/scripts/build_source_index.py +34 -1118
  73. package/skills/clean-room/scripts/clean_room_tool_manager.py +120 -37
  74. package/skills/clean-room/scripts/clean_room_tooling.py +120 -28
  75. package/skills/clean-room/scripts/source_index/__init__.py +2 -0
  76. package/skills/clean-room/scripts/source_index/batching.py +213 -0
  77. package/skills/clean-room/scripts/source_index/discovery.py +331 -0
  78. package/skills/clean-room/scripts/source_index/metrics.py +67 -0
  79. package/skills/clean-room/scripts/source_index/native_scanners.py +245 -0
  80. package/skills/clean-room/scripts/source_index/python_js_scanners.py +124 -0
  81. package/skills/clean-room/scripts/source_index/relationships.py +185 -0
  82. package/skills/clean-room/scripts/source_index/scanner_utils.py +28 -0
  83. package/skills/clean-room/scripts/source_index/scanners.py +110 -0
  84. package/skills/clean-room/scripts/source_index/writer.py +40 -0
  85. package/skills/init/SKILL.md +58 -0
  86. package/skills/preflight/SKILL.md +56 -0
  87. package/skills/refocus/SKILL.md +67 -0
  88. package/skills/resume/SKILL.md +77 -0
  89. package/skills/start-over/SKILL.md +58 -0
  90. package/skills/unattended/SKILL.md +16 -7
  91. package/hooks/hooks.json +0 -44
  92. package/skills/clean-room/examples/minimal-spec-package/task-manifest.json +0 -220
  93. /package/skills/clean-room/examples/{minimal-spec-package → contaminated-side}/coverage-ledger.json +0 -0
  94. /package/skills/clean-room/examples/{minimal-spec-package → contaminated-side}/evidence-ledger.json +0 -0
  95. /package/skills/clean-room/examples/{minimal-spec-package → contaminated-side}/source-index.json +0 -0
package/README.md CHANGED
@@ -1,30 +1,30 @@
1
1
  # Clean Room
2
2
 
3
- Spec-first clean-room workflow for software to spec.
3
+ Clean-room workflow for turning authorized source analysis into clean specs and clean implementation code.
4
4
 
5
5
  This is a POC based on the ideas presented here:
6
6
 
7
7
  https://malus.sh/blog.html
8
8
 
9
- This plugin packages the `clean-room`, `attended`, and `unattended` skills, Claude role agents, Codex role-agent templates, JSON schemas, examples, and hook guardrails for separating contaminated source analysis from clean behavioral specification work.
9
+ This plugin packages the `clean-room`, `preflight`, `attended`, `unattended`, `resume`, `start-over`, and `refocus` skills, Claude role agents, Codex role-agent templates, JSON schemas, examples, and hook guardrails for separating contaminated source analysis from clean behavioral specification and clean implementation work.
10
10
 
11
11
  It is an engineering risk-reduction workflow. It is not legal advice and does not create a legal safe harbor.
12
12
 
13
13
  ## Use This For
14
14
 
15
- - Authorized source-to-spec migration planning.
15
+ - Authorized source-to-implementation migration work.
16
16
  - Clean behavioral specifications for compatibility work.
17
- - Skeleton manifests, QC reports, open questions, and test plans.
18
- - Documented separation between source-reading roles and clean artifact roles.
17
+ - Implementation plans, clean code changes, verification reports, QC reports, open questions, and test plans.
18
+ - Documented separation between source-reading roles, clean planning roles, and clean implementation roles.
19
19
 
20
20
  ## Threat Model And Non-Goals
21
21
 
22
22
  This workflow protects against:
23
23
 
24
- - accidental source expression crossing into clean specs
24
+ - accidental source expression crossing into clean specs or clean implementation code
25
25
  - clean agents reading contaminated roots
26
26
  - contaminated agents writing clean artifacts
27
- - clean or contaminated agents writing outside their role artifact roots
27
+ - clean or contaminated agents writing outside their role artifact or implementation roots
28
28
  - unbounded unattended controller loops
29
29
 
30
30
  It does not protect against:
@@ -37,6 +37,16 @@ It does not protect against:
37
37
 
38
38
  ## Install
39
39
 
40
+ ### Installation Model
41
+
42
+ The `clean-room-skill` npm package has two separate layers:
43
+
44
+ * **Agent/runtime install**: installs clean-room skills, agent prompts, and verification hooks *into* your local or global agent runtimes (e.g., Claude Code, Codex, or Cursor). This is the default command behavior.
45
+ * **Run bootstrap**: `clean-room-skill init` creates neutral external output folders and a clean-safe repo stub for a specific clean-room run. It does not install hooks, does not write active run artifacts, and does not replace the runtime skill workflow.
46
+
47
+ * **Global Installation (Recommended)**: Integrates the clean-room workflow globally into your agent configuration directories (e.g., `~/.claude/` or `~/.codex/`).
48
+ * **Local Installation**: Places the plugin directly inside your current repository's workspace (e.g., `.claude/` or `.codex/`).
49
+
40
50
  Preferred direct installer:
41
51
 
42
52
  ```bash
@@ -49,31 +59,178 @@ The installer prompts for runtime and scope when no flags are supplied. For non-
49
59
  npx clean-room-skill@latest --codex --global --yes
50
60
  npx clean-room-skill@latest --claude --global --yes
51
61
  npx clean-room-skill@latest --antigravity --global --yes
62
+ npx clean-room-skill@latest --opencode --global --yes
63
+ npx clean-room-skill@latest --cursor --global --yes
52
64
  npx clean-room-skill@latest --all --global --yes
53
65
  ```
54
66
 
55
- Supported runtime roots:
67
+ Runtime support tiers:
68
+
69
+ - Verified: Codex and Claude Code. These installs have tested skill, agent, hook registration, and hook payload behavior.
70
+ - Layout-only / experimental: Antigravity, Gemini, OpenCode, Kilo, Cursor, GitHub Copilot, Windsurf, Augment, Trae, Qwen Code, Hermes Agent, and CodeBuddy. The installer writes files to expected layout roots, but this repo does not verify that those hosts load the files or enforce clean-room behavior.
71
+
72
+ Runtime install roots:
56
73
 
57
74
  - Codex global: `CODEX_HOME` or `~/.codex`
58
75
  - Claude Code global: `CLAUDE_CONFIG_DIR` or `~/.claude`
59
- - Antigravity global: `ANTIGRAVITY_PLUGIN_DIR` or `~/.gemini/config/plugins/clean-room-skill`
60
-
61
- Local installs are supported for Codex and Claude Code through `--local`. Antigravity local installs are rejected in v1.
76
+ - Antigravity CLI global plugin: `ANTIGRAVITY_PLUGIN_DIR`, `ANTIGRAVITY_CLI_PLUGIN_DIR`, `ANTIGRAVITY_CONFIG_DIR/plugins/clean-room`, or `~/.gemini/antigravity-cli/plugins/clean-room`
77
+ - Gemini global legacy/enterprise: `GEMINI_CONFIG_DIR` or `~/.gemini`
78
+ - OpenCode global: `OPENCODE_CONFIG_DIR`, `OPENCODE_CONFIG`, `XDG_CONFIG_HOME/opencode`, or `~/.config/opencode`
79
+ - Kilo global: `KILO_CONFIG_DIR`, `KILO_CONFIG`, `XDG_CONFIG_HOME/kilo`, or `~/.config/kilo`
80
+ - Cursor global: `CURSOR_CONFIG_DIR` or `~/.cursor`
81
+ - GitHub Copilot global: `COPILOT_CONFIG_DIR` or `~/.copilot`
82
+ - Windsurf global: `WINDSURF_CONFIG_DIR` or `~/.codeium/windsurf`
83
+ - Augment global: `AUGMENT_CONFIG_DIR` or `~/.augment`
84
+ - Trae global: `TRAE_CONFIG_DIR` or `~/.trae`
85
+ - Qwen Code global: `QWEN_CONFIG_DIR` or `~/.qwen`
86
+ - Hermes Agent global: `HERMES_HOME` or `~/.hermes`
87
+ - CodeBuddy global: `CODEBUDDY_CONFIG_DIR` or `~/.codebuddy`
88
+
89
+ Local installs are available through `--local` using each runtime's project config directory. Antigravity local installs write `.agents/plugins/clean-room/`. Claude local, Gemini, **OpenCode, and Kilo** receive generated command wrappers (e.g. `clean-room-clean-room.md`, `clean-room-init.md`); native skill runtimes receive `SKILL.md` directories. Gemini CLI support is legacy/enterprise compatibility because Google is transitioning consumer Gemini CLI users to Antigravity CLI on June 18, 2026. Cline is not included because it has no verified clean-room skill or command layout.
62
90
 
63
91
  Hook modes:
64
92
 
65
- - `--hooks=safe`: default. Copies hooks and registers a wrapper that no-ops unless `CLEAN_ROOM_HOOK_ENFORCE=1` or clean-room environment variables are present.
93
+ - `--hooks=safe`: default. Copies hooks and registers a wrapper that no-ops unless `CLEAN_ROOM_HOOK_ENFORCE=1` or clean-room environment variables are present. This is compatibility-only; use `--hooks=strict` for dedicated Codex or Claude clean-room homes.
66
94
  - `--hooks=copy-only` or `--no-hooks`: copies hook files but does not register Codex or Claude hook config.
67
- - `--hooks=strict`: registers fail-closed hooks for dedicated clean-room homes.
95
+ - `--hooks=strict`: registers fail-closed hooks for dedicated clean-room homes. Strict mode is supported only for Codex and Claude Code because other runtime hook payloads are not verified. Antigravity receives hook scripts in the plugin directory, but the generated plugin manifest does not enable them until an Antigravity-specific hook payload adapter exists.
96
+
97
+ ### Installer CLI Reference
98
+
99
+ Execute the installer via `npx` with the following parameters:
100
+
101
+ ```bash
102
+ npx clean-room-skill@latest [runtimes] [scope] [options]
103
+ ```
104
+
105
+ | Parameter | Type | Description |
106
+ | --- | --- | --- |
107
+ | `--claude` / `--codex` | Runtime | Selects the target agent runtime. (Supports `--all` for all runtimes) |
108
+ | `--global` / `--local` | Scope | Installs to the global user home config or the local project directory. |
109
+ | `--hooks=<mode>` | Option | Sets hook mode: `safe` (default, opt-in), `strict` (fail-closed), or `copy-only`. |
110
+ | `--no-hooks` | Option | Alias for `--hooks=copy-only`. Copies scripts without registering hooks. |
111
+ | `--config-dir <path>` | Option | Overrides the target root directory (only for single-runtime installs). |
112
+ | `--dry-run` | Option | Performs a trial run, logging actions without writing files. |
113
+ | `--uninstall` | Option | Removes all manifest-managed files and hook registrations. |
114
+ | `--yes` | Option | Non-interactive mode. Automatically accepts overwriting known files. |
68
115
 
69
116
  Useful maintenance commands:
70
117
 
71
118
  ```bash
72
119
  npx clean-room-skill@latest --dry-run --all --global
73
120
  npx clean-room-skill@latest --codex --global --uninstall --yes
121
+ npx clean-room-skill@latest doctor --runtime codex --hooks=safe
122
+ npx clean-room-skill@latest preflight --template --output ~/Documents/CleanRoom/task-1234abcd/contaminated/preflight-goal.json
123
+ npx clean-room-skill@latest run --task-manifest ~/Documents/CleanRoom/task-1234abcd/contaminated/task-manifest.json --agent-commands ./agent-commands.json --dry-run
124
+ ```
125
+
126
+ The installer serializes install and uninstall per target root with `.clean-room-install.lock`. It writes `clean-room-install-manifest.json` into each target root, records `phase: "installing"` before hook config mutation, and switches to `phase: "complete"` only after hook config succeeds. Reinstalling replaces only manifest-managed files automatically. Before each write or removal, the installer rechecks the file state observed during planning; late managed-file changes are backed up under `clean-room-patches/<timestamp>/` before replacement or removal. Unknown existing files are not overwritten in non-interactive mode.
127
+
128
+ ### Bootstrap CLI Reference
129
+
130
+ Use `init` to prepare a clean implementation repository and external run folder before starting the agent workflow:
131
+
132
+ ```bash
133
+ npx clean-room-skill@latest init
134
+ npx clean-room-skill@latest init --target-dir . --target-profile speckit-feature-folder
135
+ npx clean-room-skill@latest init --artifact-base ~/Documents/CleanRoom --task-id task-1234abcd
136
+ ```
137
+
138
+ By default, `init` writes external run folders under `~/Documents/CleanRoom/<task-id>/` and creates:
139
+
140
+ - `contaminated/`
141
+ - `clean/`
142
+ - `quarantine/`
143
+ - `clean-room-bootstrap.json`
144
+ - `.clean-room/README.md` in the target repository
145
+
146
+ The repo-local `.clean-room/README.md` is clean-safe guidance only. Do not commit source roots, contaminated artifact paths, private identifiers, source-derived names, `preflight-goal.json`, `init-config.json`, `task-manifest.json`, or `clean-run-context.json` into the clean implementation repository.
147
+
148
+ Without `--force`, bootstrap metadata and repo stub writes use atomic no-clobber creation. If another process creates the same task metadata or repo stub between the existence check and write, `init` aborts instead of overwriting it.
149
+
150
+ `init` prints the output folder, repo stub path, safe hook install command, runtime start guidance, and uninstall command. It never registers strict hooks. For normal use, install safe hooks into your agent home:
151
+
152
+ ```bash
153
+ npx clean-room-skill@latest --codex --global --hooks=safe --yes
154
+ npx clean-room-skill@latest --claude --global --hooks=safe --yes
155
+ ```
156
+
157
+ Use `--hooks=strict` only for dedicated clean-room Codex or Claude homes, not a daily agent profile.
158
+
159
+ ### Preflight CLI Reference
160
+
161
+ `clean-room-skill preflight` creates or validates the required Stage 0 goal contract. It is a small helper, not an interactive wizard.
162
+
163
+ ```bash
164
+ npx clean-room-skill@latest preflight --template --output ~/Documents/CleanRoom/task-1234abcd/contaminated/preflight-goal.json
165
+ npx clean-room-skill@latest preflight --input ./preflight-goal.json --output ~/Documents/CleanRoom/task-1234abcd/contaminated/preflight-goal.json
166
+ ```
167
+
168
+ `--template` writes an attended draft with blocking `open_questions`. It rejects `--mode unattended`; unattended runs must use a completed input contract with `unattended_allowed_after_preflight: true`, finite `max_iterations`, and no `open_questions`.
169
+
170
+ Keep `preflight-goal.json` in the contaminated/controller artifact root. Agent 2 and Agent 3 receive only clean-safe `goal_contract` fields and `code_hygiene_policy` through `clean-run-context.json`.
171
+
172
+ ### Inner Loop Runner Reference
173
+
174
+ `clean-room-skill run` executes the bounded inner clean-room loop for one approved spec slice. It is not the outer spec-development loop. The task manifest must already contain:
175
+
176
+ - `preflight_goal_ref` and `preflight_goal_sha256`
177
+ - the required `handoff_sequence`
178
+ - `controller_policy.mode: "unattended"`
179
+ - `controller_policy.max_iterations`
180
+ - `controller_policy.max_units_per_iteration: 1`
181
+ - `loop_context.child_loop_kind: "clean-room"`
182
+ - `loop_context.approved_scope_refs` naming the selected unit or units
183
+
184
+ The runner locks the contaminated artifact root with `.clean-room-run.lock`, reloads durable artifacts each iteration, validates schema/leakage/handoff state, selects at most one pending or gap unit inside `approved_scope_refs`, spawns configured role commands with `shell: false`, and writes:
185
+
186
+ - `controller-run-ledger.json` in the contaminated artifact root
187
+ - `clean-room-result.json` in the contaminated artifact root
188
+
189
+ CLI:
190
+
191
+ ```bash
192
+ npx clean-room-skill@latest run \
193
+ --task-manifest ~/Documents/CleanRoom/task-1234abcd/contaminated/task-manifest.json \
194
+ --agent-commands ./agent-commands.json \
195
+ --max-iterations 3
196
+ ```
197
+
198
+ Options:
199
+
200
+ | Option | Description |
201
+ | --- | --- |
202
+ | `--task-manifest <path>` | Required path to `task-manifest.json`. |
203
+ | `--agent-commands <path>` | Required role command adapter JSON unless `--dry-run` is set. |
204
+ | `--max-iterations <n>` | May only lower the manifest and `loop_context` cap. |
205
+ | `--once` | Runs at most one inner-loop iteration. |
206
+ | `--dry-run` | Validates, selects, and prints the selected unit without writing state or spawning agents. |
207
+ | `--schema-dir <path>` | Overrides bundled schema directory. |
208
+ | `--python <path>` | Python executable for validation hooks. Defaults to `python3`. |
209
+
210
+ Agent command adapter shape:
211
+
212
+ ```json
213
+ {
214
+ "version": 1,
215
+ "stages": [
216
+ {
217
+ "phase": "contaminated-analysis",
218
+ "role": "contaminated-source-analyst",
219
+ "cwd": "/absolute/contaminated/workspace",
220
+ "argv": ["agent-cli", "--fresh-session", "--role", "source-analyst"],
221
+ "timeout_ms": 600000
222
+ },
223
+ {
224
+ "phase": "contaminated-coverage-verify",
225
+ "role": "contaminated-manager-verifier",
226
+ "cwd": "/absolute/contaminated/workspace",
227
+ "argv": ["agent-cli", "--fresh-session", "--role", "manager"]
228
+ }
229
+ ]
230
+ }
74
231
  ```
75
232
 
76
- The installer writes `clean-room-install-manifest.json` into each target root. Reinstalling replaces only manifest-managed files automatically. If a managed file was locally modified, the previous version is backed up under `clean-room-patches/<timestamp>/`. Unknown existing files are not overwritten in non-interactive mode.
233
+ Supported phases are `contaminated-analysis`, `sanitize-handoff`, `clean-plan`, `clean-implement-qc`, and `contaminated-coverage-verify`. The coverage verification phase is required because Agent 3's terminal report is not enough to return to the outer loop. Adapter `env` values may add non-clean-room variables, but must not override `CLEAN_ROOM_*`.
77
234
 
78
235
  Marketplace install remains available.
79
236
 
@@ -114,22 +271,116 @@ In Claude Code, use the plugin skill namespace:
114
271
  ```text
115
272
  /clean-room
116
273
  /clean-room:clean-room
274
+ /clean-room:preflight
275
+ /clean-room:init
117
276
  /clean-room:attended
118
277
  /clean-room:unattended
278
+ /clean-room:resume
279
+ /clean-room:start-over
280
+ /clean-room:refocus
119
281
  ```
120
282
 
121
- `/clean-room` and `/clean-room:clean-room` start the setup wizard. `/clean-room:attended` starts the same wizard with attended review gates. `/clean-room:unattended` starts it with bounded unattended defaults: one unit per iteration, finite max iterations, and the configured safety stop conditions.
283
+ `/clean-room` and `/clean-room:clean-room` start the setup wizard. `/clean-room:preflight` creates or reviews the required goal contract. `/clean-room:init` records reusable setup preferences before a run starts or changes. `/clean-room:attended` starts the same wizard with attended review gates. `/clean-room:unattended` starts it with bounded unattended defaults: one unit per iteration, finite max iterations, and the configured safety stop conditions. `/clean-room:resume`, `/clean-room:start-over`, and `/clean-room:refocus` recover runs from durable artifacts. `clean-room-skill run` executes the bounded inner clean-room loop from a schema-valid `task-manifest.json` and a user-supplied agent command adapter.
122
284
 
123
285
  In Codex, invoke the `clean-room` plugin or one of its bundled skills explicitly with `@` or the skills UI. Do not rely on Claude-style `/clean-room:...` namespacing in Codex.
124
286
 
287
+ ## Run Workflow
288
+
289
+ Use this sequence for normal runs and recovery:
290
+
291
+ | Situation | Claude command | Codex action | What the skill does |
292
+ | --- | --- | --- | --- |
293
+ | Record goal contract | `/clean-room:preflight` | Invoke `preflight` | Records end goal, target stack, dependency/license policy, exactness policy, feature policy, code hygiene, output policy, mode, and open questions. |
294
+ | Initialize preferences | `/clean-room:init` | Invoke `init` | Records artifact roots, target profile, model preferences, clean-safe rules, and contaminated-only rules. Defaults artifacts to `~/Documents/CleanRoom/<task-id>/`. |
295
+ | New run, default review gates | `/clean-room` or `/clean-room:attended` | Invoke `clean-room` or `attended` | Confirms authorization, separated roots, target profile, and starts the scope gate in attended mode. |
296
+ | New bounded unattended run | `/clean-room:unattended` | Invoke `unattended` | Starts from the same scope gate, then records finite unattended bounds and stop conditions. |
297
+ | Continue an interrupted run | `/clean-room:resume` | Invoke `resume` | Reloads `task-manifest.json`, the initialization snapshot, ledgers, `clean-run-context.json`, `qc-report.json`, handoff artifacts, and abstract delta tickets, then continues from the earliest incomplete gate. |
298
+ | Restart a bad or obsolete run | `/clean-room:start-over` | Invoke `start-over` | Requires explicit confirmation, archives or quarantines current artifacts without deletion, then returns to the scope gate with a fresh `task_id`. |
299
+ | Correct drift without changing scope | `/clean-room:refocus` | Invoke `refocus` | Audits current artifacts against declared scope and routes Agent 0 back to missed gates without expanding scope. |
300
+
301
+ Before starting, prepare separate paths for source, contaminated artifacts, clean artifacts, optional clean reference docs, and quarantine. The default artifact base is `~/Documents/CleanRoom/<task-id>/`; if no explicitly approved neutral task ID is provided, use `task-` plus 8 lowercase hex characters. For recovery, provide the existing `task-manifest.json` or the artifact roots so the skill can reload durable state. Prior chat history is not task state.
302
+
303
+ ## Quick Start: Onboarding your Codebase
304
+
305
+ Once the skill package is installed in your runtime, follow these steps to initialize and execute a clean-room specification task.
306
+
307
+ ### Optional: Bootstrap Run Folders
308
+ Before invoking the runtime skill, you can create the external output folders and a clean-safe repository stub:
309
+
310
+ ```bash
311
+ npx clean-room-skill@latest init
312
+ ```
313
+
314
+ The command prints the output folder path to pass into the runtime skill. It does not write `preflight-goal.json`, `init-config.json`, `task-manifest.json`, or `clean-run-context.json`; those are still created or validated by the runtime workflow.
315
+
316
+ ### Step 1: Record the Goal Contract
317
+
318
+ Create or review `preflight-goal.json` before source discovery:
319
+
320
+ ```text
321
+ /clean-room:preflight
322
+ ```
323
+
324
+ The goal contract records what is being built, which target stack to use, what public behavior may be mirrored exactly, what must not be mirrored, feature add/remove policy, dependency/license policy, code hygiene, output roots, and attended/unattended mode. `preflight-goal.json` stays on the contaminated/controller side.
325
+
326
+ ### Step 2: Initialize Workspace Preferences
327
+ In your agent session (e.g., Claude Code), run the initialization subcommand:
328
+
329
+ ```text
330
+ /clean-room:init
331
+ ```
332
+
333
+ The agent will prompt you for setup choices and write an `init-config.json` file on the contaminated side (defaults to `~/Documents/CleanRoom/<task-id>/`). This file holds:
334
+ * The paths to your **Authorized Source Roots** and **Clean Output Roots**.
335
+ * Your output schema target profile (e.g., `speckit-feature-folder` or `openspec-delta`).
336
+ * Model configurations and `clean_safe` or `contaminated_only` rules.
337
+
338
+ *Note: For security, `init-config.json` should never be written to or committed within your clean workspace.*
339
+
340
+ ### Step 3: Establish the Scope and Task Manifest
341
+ Start the clean-room controller wizard:
342
+
343
+ ```text
344
+ /clean-room
345
+ ```
346
+
347
+ The agent (Agent 0) will:
348
+ 1. Re-verify the path separation of your source, contaminated, and clean workspace roots.
349
+ 2. Capture your authorization details and compile them into `task-manifest.json` with `preflight_goal_ref`, `preflight_goal_sha256`, and the required `handoff_sequence`.
350
+ 3. Create `clean-run-context.json` with only clean-safe `goal_contract` fields and `code_hygiene_policy`.
351
+ 4. If analyzing a complex scope, guide you to run the local source-index preflight to generate a `source-index.json` under your contaminated artifacts directory.
352
+ 5. Decompose the workspace files into neutral, logical task units.
353
+
354
+ ### Step 4: Run the Implementation Pipeline
355
+ Choose either **Attended** (with explicit manual approval checkpoints) or **Unattended** mode to begin work on the logical units:
356
+
357
+ ```text
358
+ /clean-room:attended
359
+ /clean-room:unattended
360
+ ```
361
+
362
+ * **Agent 1** analyzes the source files mapped to the active unit and writes neutral draft specs under `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS`.
363
+ * **Agent 1.5** sanitizes the drafts, ensuring no private symbols, code snippets, or structure are leaked.
364
+ * **Agent 2** reads sanitized specs plus the clean destination foundation and writes `implementation-plan.json`.
365
+ * **Agent 3** implements the selected spec slice under `CLEAN_ROOM_IMPLEMENTATION_ROOTS`, records verification status, and writes `implementation-report.json` plus `qc-report.json`.
366
+
367
+ The outer loop evolves specs and chooses one approved spec slice. The inner clean-room loop completes that slice through sanitized handoff, implementation, QC, and contaminated-side coverage verification, then writes `clean-room-result.json` before returning to the outer loop. Agent 3's terminal report alone is not an inner-loop return.
368
+
125
369
  ## Operating Model
126
370
 
127
371
  Use separate workspaces, worktrees, repositories, or profiles for contaminated and clean work:
128
372
 
129
373
  - Contaminated source workspace: source-readable, read-only where practical.
130
- - Contaminated artifact workspace: source indexes, task manifests, coverage ledgers, evidence ledgers, draft specs, and abstract delta tickets. Configure as `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS`.
131
- - Clean spec workspace: approved behavior specs, handoff packages, skeleton manifests, QC reports, and test plans.
132
- - Clean allowed reference workspace: public documentation or destination constraints explicitly approved for clean-role reads.
374
+ - Contaminated artifact workspace: preflight goals, init configs, source indexes, task manifests, coverage ledgers, evidence ledgers, draft specs, and abstract delta tickets. Configure as `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS`.
375
+ - Clean artifact workspace: clean run contexts, approved behavior specs, handoff packages, skeleton manifests, implementation plans, implementation reports, QC reports, and test plans. Configure as `CLEAN_ROOM_CLEAN_ROOTS`.
376
+ - Clean implementation workspace: clean destination code and tests. Configure as `CLEAN_ROOM_IMPLEMENTATION_ROOTS`.
377
+ - Clean allowed reference workspace: public documentation or destination constraints explicitly approved for clean and source-denied role reads.
378
+
379
+ ### Path Naming Guards
380
+
381
+ Artifact paths must be neutral. Do not name task IDs, clean roots, implementation roots, or contaminated artifact roots after private source folders or private code identifiers.
382
+
383
+ When no explicitly approved neutral task ID is provided, the controller should generate `task-` plus 8 lowercase hex characters under `~/Documents/CleanRoom/`. The initialization wizard and `require-clean-room-env.py` preflight reject clean, implementation, or contaminated artifact paths that contain source root basenames or meaningful non-generic tokens from those basenames. Guard errors avoid printing the private source name.
133
384
 
134
385
  Prompt instructions alone are not a boundary. Use path separation, role-specific sessions, hook checks, schema validation, and artifact quarantine.
135
386
 
@@ -137,79 +388,15 @@ Prompt instructions alone are not a boundary. Use path separation, role-specific
137
388
 
138
389
  ![Clean Room Architecture](assets/clean-room-arch.svg)
139
390
 
140
- ### Flowchart Representation
141
-
142
- ```mermaid
143
- flowchart LR
144
- subgraph contaminated["Contaminated domain: source-readable"]
145
- source["Authorized source roots<br/>CLEAN_ROOM_SOURCE_ROOTS"]
146
- manager["Agent 0: contaminated-manager-verifier<br/>Scope, decompose, track coverage, verify"]
147
- analyst["Agent 1: contaminated-source-analyst<br/>Read source, write neutral tasks and specs"]
148
- ledgers["Contaminated artifacts<br/>CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS<br/>source-index.json<br/>task-manifest.json<br/>coverage-ledger.json<br/>evidence-ledger.json"]
149
- scrub["Leakage review<br/>Remove source expression"]
150
- end
151
-
152
- subgraph wall["Clean-room wall"]
153
- handoff["Approved handoff only<br/>handoff-package.json<br/>scrubbed behavior-spec.json"]
154
- blocked["Blocked from crossing<br/>source excerpts, raw diffs, copied comments,<br/>private identifiers, source-shaped pseudocode"]
155
- end
156
-
157
- subgraph clean["Clean domain: source-denied"]
158
- cleanroots["Clean artifact roots<br/>CLEAN_ROOM_CLEAN_ROOTS"]
159
- publicrefs["Allowed public refs<br/>CLEAN_ROOM_ALLOWED_READ_ROOTS"]
160
- architect["Agent 2: clean-architect<br/>Manage schema base and skeleton manifest"]
161
- qa["Agent 3: clean-qa-editor<br/>Validate schema, leakage, coverage, testability"]
162
- outputs["Clean outputs<br/>skeleton-manifest.json<br/>qc-report.json<br/>test plan notes"]
163
- end
164
-
165
- subgraph guardrails["Guardrails and audit"]
166
- env["require-clean-room-env.py"]
167
- denyread["deny-clean-source-read.py"]
168
- denywrite["deny-contaminated-clean-write.py<br/>write root policy"]
169
- denyshell["deny-clean-room-shell.py"]
170
- scan["check-artifact-leakage.py<br/>validate-json-schema.py"]
171
- end
172
-
173
- source --> manager
174
- manager --> analyst
175
- manager --> ledgers
176
- analyst --> ledgers
177
- analyst --> scrub
178
- scrub --> handoff
179
- handoff --> cleanroots
180
- cleanroots --> architect
181
- publicrefs --> architect
182
- architect --> outputs
183
- outputs --> qa
184
- qa --> outputs
185
- qa -. abstract delta tickets only .-> manager
186
-
187
- blocked -. quarantine do not hand off .-> ledgers
188
- env -. required for every role session .-> manager
189
- env -. required for every role session .-> architect
190
- denyread -. clean roles cannot read source roots .-> cleanroots
191
- denywrite -. contaminated writes only to contaminated artifact roots .-> ledgers
192
- denywrite -. clean writes only to clean roots .-> cleanroots
193
- denyshell -. no shell-style tools in role sessions .-> manager
194
- denyshell -. no shell-style tools in role sessions .-> architect
195
- scan -. post-write checks .-> outputs
196
-
197
- classDef contaminatedDomain fill:#fff7ed,stroke:#c2410c,color:#111827;
198
- classDef cleanDomain fill:#ecfeff,stroke:#0e7490,color:#111827;
199
- classDef wallClass fill:#f8fafc,stroke:#475569,color:#111827;
200
- classDef guardClass fill:#f0fdf4,stroke:#15803d,color:#111827;
201
- class source,manager,analyst,ledgers,scrub contaminatedDomain;
202
- class cleanroots,publicrefs,architect,qa,outputs cleanDomain;
203
- class handoff,blocked wallClass;
204
- class env,denyread,denywrite,denyshell,scan guardClass;
205
- ```
391
+ For a detailed breakdown of the flowchart representation, agent responsibilities, environment boundaries, and guardrail scripts, see the [Clean Room Architecture Documentation](docs/ARCHITECTURE.md).
206
392
 
207
393
  ## Roles
208
394
 
209
- - Agent 0 / `contaminated-manager-verifier`: consumes contaminated source indexes, decomposes scope into logical batches, tracks coverage, verifies clean specs against source, and receives Agent 3 final QC reports.
210
- - Agent 1 / `contaminated-source-analyst`: reads authorized source and writes neutral task/spec material with evidence references, not code.
211
- - Agent 2 / `clean-architect`: reads approved clean artifacts, manages the selected clean schema base, and organizes artifacts into target-neutral skeleton manifests.
212
- - Agent 3 / `clean-qa-editor`: validates schema conformance, leakage risk, terminology, coverage gaps, and testability, then reports abstract findings back to Agent 0.
395
+ - Agent 0 / `contaminated-manager-verifier`: consumes contaminated source indexes, decomposes scope into logical batches, tracks coverage, verifies clean specs and terminal implementation reports against source, and influences Agent 2/3 only through durable sanitized artifacts.
396
+ - Agent 1 / `contaminated-source-analyst`: reads authorized source and writes neutral draft task/spec material with evidence references, not code.
397
+ - Agent 1.5 / `contaminated-handoff-sanitizer`: reviews Agent 1 drafts from a fresh source-denied contaminated context and approves only sanitized handoff candidates.
398
+ - Agent 2 / `clean-architect`: reads clean artifacts and the clean implementation foundation, then writes `implementation-plan.json` with relative destination paths, tests, constraints, risks, and argv-array verification commands.
399
+ - Agent 3 / `clean-qa-editor`: implements the selected spec-slice work under `CLEAN_ROOM_IMPLEMENTATION_ROOTS`, records verification status, maintains `qc-report.json`, and emits one terminal report for Agent 0 only when the assigned slice is complete, blocked, or quarantined.
213
400
 
214
401
  Claude role agents are in `agents/`. Codex role-agent templates are in `examples/codex/.codex/agents/`.
215
402
 
@@ -222,13 +409,18 @@ CLEAN_ROOM_ROLE
222
409
  CLEAN_ROOM_SOURCE_ROOTS
223
410
  CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS
224
411
  CLEAN_ROOM_CLEAN_ROOTS
412
+ CLEAN_ROOM_IMPLEMENTATION_ROOTS
225
413
  CLEAN_ROOM_SCHEMA_DIR
226
414
  CLEAN_ROOM_ALLOWED_READ_ROOTS
227
415
  ```
228
416
 
229
- For clean roles, reads are deny-by-default. They may read only `CLEAN_ROOM_CLEAN_ROOTS` plus explicit public or destination constraint roots in `CLEAN_ROOM_ALLOWED_READ_ROOTS`. Source roots in `CLEAN_ROOM_SOURCE_ROOTS` stay denied.
417
+ For clean roles, reads are deny-by-default. They may read only `CLEAN_ROOM_CLEAN_ROOTS`, `CLEAN_ROOM_IMPLEMENTATION_ROOTS`, `CLEAN_ROOM_SCHEMA_DIR`, and explicit public or destination constraint roots in `CLEAN_ROOM_ALLOWED_READ_ROOTS`. Agent 2 and Agent 3 receive `clean-run-context.json`, not the full `task-manifest.json` or `preflight-goal.json`. Agent 1.5 is also source-denied: it may read only assigned contaminated artifacts, `CLEAN_ROOM_SCHEMA_DIR`, and explicit public or destination constraint roots. Source roots in `CLEAN_ROOM_SOURCE_ROOTS` stay denied.
418
+
419
+ Agent 0 must not directly steer Agent 2 or Agent 3. Clean roles accept Agent 0 input only as schema-valid durable sanitized artifacts already present in the clean workspace. Direct chat instructions, progress feedback, priority changes, implementation hints, or corrective coaching from Agent 0 are out of bounds. Agent 3 reports back to Agent 0 only at the terminal report gate, never during an active implementation loop.
230
420
 
231
- Writes are also deny-by-default. Clean roles may write only under `CLEAN_ROOM_CLEAN_ROOTS`. Contaminated roles may write only under `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS`. Source roots stay read-only for contaminated roles unless a separate, explicit process outside this plugin changes that policy.
421
+ Writes are also deny-by-default. Agent 2 writes only clean artifacts under `CLEAN_ROOM_CLEAN_ROOTS`. Agent 3 writes reports under `CLEAN_ROOM_CLEAN_ROOTS` and code/tests only under `CLEAN_ROOM_IMPLEMENTATION_ROOTS`. Contaminated roles may write only under `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS`. Source roots stay read-only for contaminated roles unless a separate, explicit process outside this plugin changes that policy.
422
+
423
+ The environment preflight also audits root names. `CLEAN_ROOM_CLEAN_ROOTS`, `CLEAN_ROOM_IMPLEMENTATION_ROOTS`, and `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS` must not contain source-derived project basenames or meaningful non-generic source-name tokens.
232
424
 
233
425
  Optional hook-only guardrail:
234
426
 
@@ -236,11 +428,13 @@ Optional hook-only guardrail:
236
428
  CLEAN_ROOM_PRIVATE_IDENTIFIER_DENYLIST
237
429
  ```
238
430
 
239
- Set it to path-separated, line-oriented files containing private source package, module, class, function, method, variable, constant, field, or other internal identifiers to reject from clean artifacts. Blank lines and `#` comments are ignored. Files are bounded to 1,000,000 bytes each, 20,000 total terms, and 512 characters per term. Keep those files outside clean-role readable roots and do not paste their contents into model-visible artifacts.
431
+ Set it to path-separated, line-oriented files containing private source package, module, class, function, method, variable, constant, field, or other internal identifiers to reject from clean artifacts. Blank lines and `#` comments are ignored. Files are bounded to 1,000,000 bytes each, 20,000 total terms, and 512 characters per term. Keep those files outside clean/source-denied readable roots and do not paste their contents into model-visible artifacts.
432
+
433
+ Do not grant shell-style tools to Agent 0, Agent 1, Agent 1.5, Agent 2, or the default Agent 3 profile. If Agent 3 verification needs a terminal, use an isolated verification home with strict hooks and `CLEAN_ROOM_ALLOW_AGENT3_SHELL=1`, then invoke only the installed `agent3-verification-runner.py` from an implementation-root cwd. The runner reads argv-array verification commands from `implementation-plan.json`, applies a small allowlist, strips clean-room root env values, and executes with `shell=False`. Shell access still does not replace OS/profile isolation for untrusted test code.
240
434
 
241
- Do not grant shell-style tools to clean-room role sessions. Shell access can bypass path-aware read and write hooks.
435
+ For multi-file scopes, run `skills/clean-room/scripts/build_source_index.py` as source-index controller preflight before clean-room role sessions. Store `source-index.json` under `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS`, or pass `--contaminated-artifact-root` explicitly. The script refuses `--output` outside those roots. It is contaminated-only and must not be included in clean handoff packages or shown to Agent 1.5.
242
436
 
243
- For multi-file scopes, run `skills/clean-room/scripts/build_source_index.py` as controller preflight before clean-room role sessions. Store `source-index.json` under `CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS`, or pass `--contaminated-artifact-root` explicitly. The script refuses `--output` outside those roots. It is contaminated-only and must not be included in clean handoff packages.
437
+ `source-index.json` includes bounded `skipped_entries` when the indexer intentionally or unavoidably omits input. Expected reasons include ignored directories, file count and byte caps, total byte caps, binary files, file stat/read errors, post-read size changes, files that changed during read, symlinks that resolve outside the source root, and directory traversal errors. After a global file or byte cap is reached, traversal is pruned and represented by an aggregate `remaining-files-skipped-after-limit:*` entry instead of enumerating the rest of a large tree. Treat skipped entries as coverage metadata: inspect them before deciding that a source index fully represents the authorized root.
244
438
 
245
439
  Optional AST/indexing helpers are checked before the controller loop, not from clean-room role sessions:
246
440
 
@@ -248,13 +442,15 @@ Optional AST/indexing helpers are checked before the controller loop, not from c
248
442
  python3 skills/clean-room/scripts/clean_room_tool_manager.py --status
249
443
  ```
250
444
 
251
- `--status` is stat-only by default. Use `--probe-tools` only when you want it to execute discovered tools with version commands:
445
+ `--status` is stat-only by default. Use `--probe-tools` only when you want it to execute version commands for explicitly configured, cache-local, skill-local, system-path, or explicitly allowed project tools:
252
446
 
253
447
  ```bash
254
448
  python3 skills/clean-room/scripts/clean_room_tool_manager.py --status --probe-tools
255
449
  ```
256
450
 
257
- Local helper installs are explicit and version-pinned, and they write to `~/.cache/re-skills/clean-room-tools/`:
451
+ Tools discovered under `/opt/homebrew` or `/usr/local` remain stat-only during `--probe-tools` unless you also pass `--allow-user-toolchain-probes`.
452
+
453
+ Local helper installs are explicit and strict SemVer version-pinned, and they write to `~/.cache/re-skills/clean-room-tools/`. Local npm-backed installs are serialized with a cache-local lock so concurrent setup processes do not mutate the shared npm prefix at the same time. Prefix creation failures, subprocess timeouts, and subprocess launch errors are reported as structured JSON error facts:
258
454
 
259
455
  ```bash
260
456
  python3 skills/clean-room/scripts/clean_room_tool_manager.py --install-local ast-grep --version <exact-version>
@@ -266,65 +462,117 @@ Target-project `.local/bin`, `.bin`, and `node_modules/.bin` are ignored unless
266
462
 
267
463
  Missing `controller_policy` means `attended`.
268
464
 
269
- - `attended`: agent zero pauses for human review at scope gate, clean handoff, QC deltas, blocked units, and final coverage.
270
- - `unattended`: agent zero runs a bounded controller loop. It reloads durable artifacts each iteration, selects at most one pending or gap unit, starts each role from fresh context with the required environment block, validates before advancing state, and stops on any configured safety or ambiguity condition.
465
+ - `attended`: agent zero pauses for human review at scope gate, clean handoff, terminal implementation deltas, blocked units, and final coverage.
466
+ - `unattended`: agent zero runs a bounded inner clean-room loop only after preflight allows unattended mode with no open questions. It reloads durable artifacts each iteration, selects at most one pending or gap unit inside the approved spec slice, starts each role from fresh context with the required environment block, validates before advancing state, and stops on any configured safety or ambiguity condition.
271
467
 
272
- Agent zero generates the durable tasklist as neutral `task-manifest.json` `units`. For larger scopes, it may use `source-index.json` recommended batches and record `source_index_ref` plus per-unit `source_index_refs`. Progress is tracked in `coverage-ledger.json`, `evidence-ledger.json`, `qc-report.json`, and abstract delta tickets, not in prior chat history.
468
+ `task-manifest.json` may include `run_state` with the generation, start timestamp, previous generation reference, and restart reason. It may also include `initialization_snapshot`, which is the per-run copy of `init-config.json` preferences. Use durable artifacts to recover or start over without relying on chat history.
469
+
470
+ Agent zero generates the durable tasklist as neutral `task-manifest.json` `units`. For larger scopes, it may use `source-index.json` recommended batches and record `source_index_ref` plus per-unit `source_index_refs`. Progress is tracked in `coverage-ledger.json`, `evidence-ledger.json`, terminal `implementation-report.json`, `qc-report.json`, and abstract delta tickets, not in prior chat history or live clean-role feedback.
471
+
472
+ ## Recovery Entry Points
473
+
474
+ - `resume`: reload durable artifacts, including referenced preflight goal and implementation plan/report when present, validate schema and leakage state, compare reusable init config against the manifest snapshot when present, and continue from the earliest incomplete gate using the recorded `controller_policy`.
475
+ - `start-over`: require explicit confirmation, archive or quarantine the current artifact set without deletion, and restart from the preflight gate with a fresh `task_id`.
476
+ - `refocus`: audit current artifacts against declared scope and preflight goal, then steer Agent 0 back to missed gates without expanding scope.
273
477
 
274
478
  ## Artifacts
275
479
 
276
480
  The schema contract lives in `skills/clean-room/assets/`:
277
481
 
278
482
  - `task-manifest.schema.json`
483
+ - `preflight-goal.schema.json`
484
+ - `init-config.schema.json`
485
+ - `clean-run-context.schema.json`
279
486
  - `source-index.schema.json`
280
487
  - `coverage-ledger.schema.json`
281
488
  - `evidence-ledger.schema.json`
282
489
  - `handoff-package.schema.json`
283
490
  - `behavior-spec.schema.json`
284
491
  - `skeleton-manifest.schema.json`
492
+ - `implementation-plan.schema.json`
493
+ - `implementation-report.schema.json`
494
+ - `clean-room-result.schema.json`
285
495
  - `qc-report.schema.json`
286
496
  - `contamination-incident.schema.json`
287
497
 
288
- Example artifact shapes are in `skills/clean-room/examples/minimal-spec-package/`. They are examples only, not outputs from a real source review.
498
+ Clean-side example artifact shapes are in `skills/clean-room/examples/minimal-spec-package/`. Verification commands in clean plans and reports are argv arrays, not shell strings. Contaminated-side controller examples, including `source-index.json`, are in `skills/clean-room/examples/contaminated-side/`. They are examples only, not outputs from a real source review.
289
499
 
290
500
  ## Workflow
291
501
 
292
- 1. Record authorization, scope, prohibited actions, evidence handling, and role root paths in `task-manifest.json`.
293
- 2. Record the user's selected target profile and Agent 0-3 pipeline in `task-manifest.json`.
294
- 3. Run source index preflight when the source scope needs relationship-aware batching.
295
- 4. Decompose the source scope into bounded, neutral `task-manifest.json` units. One unit may map to one source-index batch or, for large files, one preflight segment.
296
- 5. Write contaminated-side behavior specs from observed behavior, public contracts, states, errors, invariants, and test scenarios.
297
- 6. Scrub specs using `skills/clean-room/references/LEAKAGE-RULES.md`.
298
- 7. Move only approved structured artifacts into the clean workspace through `handoff-package.json`. Do not include `source-index.json`.
299
- 8. Build or merge the clean schema base and `skeleton-manifest.json` from clean specs, target profile, and target constraints.
300
- 9. Produce `qc-report.json` with schema status, leakage status, gaps, and testability notes.
301
- 10. Verify coverage from the contaminated side and repeat only with abstract delta tickets.
302
- 11. Stop at the spec package. Do not implement replacement code in this plugin workflow.
502
+ 1. Create or validate `preflight-goal.json`.
503
+ 2. Record reusable setup preferences in `init-config.json` when requested, then snapshot effective choices into `task-manifest.json`.
504
+ 3. Record authorization, scope, prohibited actions, evidence handling, preflight goal ref/hash, role root paths, and the required `handoff_sequence` in `task-manifest.json`.
505
+ 4. Record the user's selected target profile, model policy, `run_state`, Agent 0-3 pipeline, and required Agent 1.5 sanitizer role in `task-manifest.json`.
506
+ 5. Create `clean-run-context.json` for Agent 2 and Agent 3. It must record artifact-only coordination, clean-safe `goal_contract` fields, and `code_hygiene_policy`, and must not contain source roots, contaminated roots, source index refs, ledger paths, or full preflight/task manifests.
507
+ 6. Run source index preflight when the source scope needs relationship-aware batching.
508
+ 7. Decompose the source scope into bounded, neutral `task-manifest.json` units. One unit may map to one source-index batch or, for large files, one preflight segment.
509
+ 8. Write contaminated-side draft behavior specs from observed behavior, public contracts, states, errors, invariants, and test scenarios.
510
+ 9. Sanitize specs through Agent 1.5 using `skills/clean-room/references/LEAKAGE-RULES.md`; Agent 1.5 gets only a neutral brief and assigned draft paths.
511
+ 10. Move only Agent 1.5-approved structured artifacts and `clean-run-context.json` into the clean workspace through `handoff-package.json`. Do not include `task-manifest.json`, `preflight-goal.json`, or `source-index.json`.
512
+ 11. Agent 2 writes `implementation-plan.json` from clean specs, clean run context, target constraints, preflight code hygiene policy, and the clean implementation foundation.
513
+ 12. Agent 3 implements work items under `CLEAN_ROOM_IMPLEMENTATION_ROOTS`, records verification status, and writes `implementation-report.json` without Agent 0 guidance. Run terminal verification only through the installed Agent 3 verification runner.
514
+ 13. Produce or update `qc-report.json` with schema status, leakage status, gaps, code hygiene findings, and testability notes.
515
+ 14. After Agent 3 reaches complete, blocked, or quarantined, Agent 0 verifies coverage from the contaminated side.
516
+ 15. Write `clean-room-result.json` with `spec-slice-complete`, `spec-slice-blocked`, `spec-delta-required`, `contamination-suspected`, `iteration-limit-reached`, or `no-progress-detected`.
517
+ 16. Repeat only through updated durable clean artifacts and abstract delta tickets. Do not steer an in-progress Agent 2 or Agent 3 session.
303
518
 
304
519
  ## Hook Guardrails
305
520
 
306
- Hook scaffolding lives in `hooks/` and is declared by `hooks/hooks.json`.
521
+ Agent/tool hook scaffolding lives in `hooks/`. Security enforcement uses installer-generated Codex or Claude hook configs with absolute wrapper paths. Runtime plugin manifests do not declare static package hooks because cwd-relative hook commands are fragile.
522
+
523
+ The generated hook configs route through `hooks/clean-room-hook.py`. In safe mode, the wrapper exits successfully unless `CLEAN_ROOM_HOOK_ENFORCE=1` or clean-room environment variables are present. Safe mode is compatibility-only until enforcement is enabled. In strict mode, it runs the configured checks immediately and fails closed when required role or path configuration is missing. Prefer strict mode for dedicated Codex or Claude clean-room homes.
524
+
525
+ After install, run a smoke check:
526
+
527
+ ```bash
528
+ clean-room-skill doctor --runtime codex --hooks=strict
529
+ ```
530
+
531
+ Use `--runtime claude` for Claude Code, and add `--config-dir <path>` when testing an alternate config root.
532
+
533
+ Expanded matcher coverage applies only to tool events the host runtime actually emits; do not treat matcher names as proof that an unsupported host tool is guarded.
534
+
535
+ ### What Doctor Verifies
307
536
 
308
- `hooks/hooks.json` routes through `hooks/clean-room-hook.py`. In safe mode, the wrapper exits successfully unless `CLEAN_ROOM_HOOK_ENFORCE=1` or clean-room environment variables are present. In strict mode, it runs the configured checks immediately and fails closed when required role or path configuration is missing.
537
+ `doctor` verifies that Codex or Claude hook config exists, contains four generated clean-room hooks, uses absolute wrapper paths, uses the requested safe or strict mode, and that smoke payloads fail for missing environment, source reads, source writes, shell use, and malformed post-write JSON. It also verifies that safe hooks no-op without clean-room env.
309
538
 
310
- `hooks/hooks.json` uses commands relative to the plugin package root, such as `python3 hooks/clean-room-hook.py --mode safe ...`. Confirm the host executes plugin hooks from that directory during install smoke tests.
539
+ It does not verify every runtime tool event, every matcher name emitted by the host, host-side hook enablement outside the config file, legal clean-room sufficiency, or full JSON Schema conformance. Treat it as an install smoke test, not a complete enforcement proof.
311
540
 
312
541
  - `clean-room-hook.py`: safe/strict dispatch wrapper for the policy checks below.
542
+ - `agent3-verification-runner.py`: runs Agent 3 argv-array verification commands with `shell=False`, a small allowlist, sanitized env, bounded output, timeout, and root traversal checks.
313
543
  - `require-clean-room-env.py`: fails closed when required role and root environment is missing.
314
- - `deny-clean-room-shell.py`: denies shell-style tools for clean-room role sessions.
315
- - `deny-clean-source-read.py`: denies clean-role reads from source roots and unapproved paths.
316
- - `deny-contaminated-clean-write.py`: enforces role write roots. Clean roles write only under clean roots; contaminated roles write only under contaminated artifact roots.
317
- - `check-artifact-leakage.py`: scans clean artifacts for high-risk leakage markers, source-like identifiers, and optional private identifier denylist matches.
544
+ - `deny-clean-room-shell.py`: denies shell-style tools for clean-room role sessions except installed Agent 3 verification-runner invocations explicitly allowed under implementation roots.
545
+ - `deny-clean-source-read.py`: denies clean and source-denied role reads from source roots and unapproved paths.
546
+ - `deny-contaminated-clean-write.py`: enforces role write roots. Agent 2 writes clean artifacts only, Agent 3 may write clean reports and implementation-root files, and contaminated roles write only under contaminated artifact roots.
547
+ - `check-artifact-leakage.py`: scans clean artifacts, plus Agent 1.5 staged contaminated artifacts, for high-risk leakage markers, source-like identifiers, and optional private identifier denylist matches.
318
548
  - `validate-json-schema.py`: checks JSON syntax and common bundled clean-room schema constraints, including the conditional and bounded fields used by these schemas. Under clean roots, unknown JSON artifacts are rejected unless explicitly allowlisted through `CLEAN_ROOM_AUXILIARY_JSON_ALLOWLIST`. It is a lightweight guardrail, not a full JSON Schema 2020-12 validator.
319
- - `validate-handoff-package.py`: verifies handoff artifact paths stay under clean roots, do not point into source or contaminated roots, do not include `source-index.json`, and match declared `sha256` values.
549
+ - `validate-handoff-package.py`: verifies handoff artifact paths stay under clean roots, do not point into source or contaminated roots, do not include `task-manifest.json`, `preflight-goal.json`, or `source-index.json`, and match declared `sha256` values.
320
550
 
321
551
  These scripts are guardrail and audit support. They are not a substitute for separate workspaces and role isolation.
322
552
 
323
553
  For release-quality schema assurance, run a full JSON Schema validator in addition to the bundled lightweight hook.
324
554
 
555
+ ## Troubleshooting
556
+
557
+ | Symptom | Likely cause | Recovery |
558
+ | --- | --- | --- |
559
+ | `python3 is required to install clean-room hooks` | Python missing or not on `PATH` | Install Python 3 or use `--hooks=copy-only` |
560
+ | `safe hooks are installed but not enforcing` | Safe mode default | Set `CLEAN_ROOM_HOOK_ENFORCE=1`, set clean-room env vars, or reinstall with `--hooks=strict` in a dedicated profile |
561
+ | `install lock is held` | Another install or uninstall is mutating the same target root, or a prior process died while holding `.clean-room-install.lock` | Wait for the other process to finish; inspect and remove the lock only after confirming no installer is active |
562
+ | Hook config write failed after files copied | Partial installer state; manifest records `hook_registration.status: "failed"` when possible | Fix the filesystem error, then re-run the same installer command to repair hook registration |
563
+ | Install manifest write failed after files copied | Manifest may be absent or left at `phase: "installing"` | Re-run the same installer command before relying on uninstall tracking |
564
+ | `phase` remains `installing` in `clean-room-install-manifest.json` | The previous install did not complete hook config or manifest finalization | Re-run the same installer command for that runtime and target root |
565
+ | `clean-room run` rejects the manifest | The manifest is not unattended, lacks `loop_context`, raises `--max-iterations`, or has no approved unit | Fix `controller_policy`, `loop_context`, and `approved_scope_refs`, then retry `--dry-run` |
566
+ | `clean-room run` reports no progress | The configured stages exited successfully but no tracked durable JSON artifact changed | Check role command cwd/argv, selected unit, and artifact write roots |
567
+ | `clean-room run` reports repeated unit selection | The same unit was selected after a prior no-progress iteration | Resolve the blocker or update durable artifacts before retrying |
568
+ | Hook reports `could not read` or `could not stat` | Artifact disappeared, permissions changed, or path was replaced during post-write validation | Restore readable artifact state and retry; hooks fail closed without printing private paths |
569
+ | `source-index.json` is missing files | Limits, unreadable directories, ignored directories, binary files, changed-during-read files, or symlinks outside the source root | Inspect `skipped_entries` and adjust limits or permissions if the omissions matter |
570
+
325
571
  ## References
326
572
 
327
573
  - `skills/clean-room/SKILL.md`: main skill instructions.
574
+ - `skills/clean-room/references/CONTROLLER-LOOP.md`: nested outer/inner loop contract.
575
+ - `skills/clean-room/references/PREFLIGHT.md`: Stage 0 goal contract.
328
576
  - `skills/clean-room/references/PROCESS.md`: detailed process.
329
577
  - `skills/clean-room/references/LEAKAGE-RULES.md`: clean handoff rules.
330
578
  - `skills/clean-room/references/SPEC-SCHEMA.md`: artifact schema guidance.
@@ -339,6 +587,7 @@ export CLEAN_ROOM_ROLE=clean-qa-editor
339
587
  export CLEAN_ROOM_SOURCE_ROOTS="$PWD/source"
340
588
  export CLEAN_ROOM_CONTAMINATED_ARTIFACT_ROOTS="$PWD/contaminated-artifacts"
341
589
  export CLEAN_ROOM_CLEAN_ROOTS="$PWD/skills/clean-room/examples/minimal-spec-package"
590
+ export CLEAN_ROOM_IMPLEMENTATION_ROOTS="$PWD/implementation"
342
591
  export CLEAN_ROOM_ALLOWED_READ_ROOTS=""
343
592
  export CLEAN_ROOM_SCHEMA_DIR="$PWD/skills/clean-room/assets"
344
593
 
@@ -353,24 +602,30 @@ python3 hooks/clean-room-hook.py --mode safe --check require-clean-room-env.py <
353
602
 
354
603
  ## Local Verification
355
604
 
356
- After changing plugin metadata, hooks, schemas, or skill instructions, run the relevant checks from the plugin package root:
605
+ After changing plugin metadata, hooks, schemas, or skill instructions, run the same local checks used for pull request CI:
606
+
607
+ ```bash
608
+ npm run verify
609
+ ```
610
+
611
+ Note: The unit test suite (`npm test`) utilizes the native Node.js test runner and requires Node.js >= 22 to execute successfully.
612
+
613
+ The full JSON Schema validation requires Python `jsonschema` with format extras. On macOS with Homebrew Python, use a repo-local venv:
614
+
615
+ ```bash
616
+ python3 -m venv .venv
617
+ .venv/bin/python -m pip install "jsonschema[format]>=4.18,<5"
618
+ npm run verify
619
+ ```
620
+
621
+ Optional, if an external skill-creator `quick_validate` command is installed on your machine:
357
622
 
358
623
  ```bash
359
- python3 -m json.tool plugin.json >/dev/null
360
- python3 -m json.tool .codex-plugin/plugin.json >/dev/null
361
- python3 -m json.tool .claude-plugin/plugin.json >/dev/null
362
- python3 -m json.tool hooks/hooks.json >/dev/null
363
- python3 -m py_compile hooks/*.py
364
- python3 -m py_compile skills/clean-room/scripts/*.py
365
- node --test
366
- npm pack --dry-run
367
- node bin/install.js --dry-run --all --global
368
- python3 skills/clean-room/scripts/build_source_index.py --help
369
- # Optional, if skill-creator quick_validate is installed:
370
624
  quick_validate skills/attended
371
625
  quick_validate skills/clean-room
626
+ quick_validate skills/init
627
+ quick_validate skills/refocus
628
+ quick_validate skills/resume
629
+ quick_validate skills/start-over
372
630
  quick_validate skills/unattended
373
- for f in skills/clean-room/examples/minimal-spec-package/*.json; do printf '{"tool_input":{"file_path":"%s"}}' "$PWD/$f" | CLEAN_ROOM_SCHEMA_DIR="$PWD/skills/clean-room/assets" python3 hooks/validate-json-schema.py || exit 1; done
374
- for f in skills/clean-room/examples/minimal-spec-package/*.json; do if [ "$(basename "$f")" = source-index.json ]; then continue; fi; printf '{"tool_input":{"file_path":"%s"}}' "$PWD/$f" | CLEAN_ROOM_CLEAN_ROOTS="$PWD/skills/clean-room/examples/minimal-spec-package" python3 hooks/check-artifact-leakage.py || exit 1; done
375
- find . -maxdepth 4 -type d -name bin -print
376
631
  ```