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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -3
- package/.codex-plugin/plugin.json +1 -2
- package/README.md +388 -133
- package/agents/clean-architect.md +24 -8
- package/agents/clean-implementer-verifier-shell.md +36 -0
- package/agents/clean-qa-editor.md +31 -8
- package/agents/contaminated-handoff-sanitizer.md +37 -0
- package/agents/contaminated-manager-verifier.md +28 -9
- package/agents/contaminated-source-analyst.md +22 -4
- package/assets/clean-room-arch.svg +354 -0
- package/bin/install.js +305 -314
- package/bin/verify.sh +78 -0
- package/docs/ARCHITECTURE.md +274 -0
- package/examples/codex/.codex/agents/clean-architect.toml +15 -6
- package/examples/codex/.codex/agents/clean-qa-editor.toml +22 -7
- package/examples/codex/.codex/agents/contaminated-handoff-sanitizer.toml +18 -0
- package/examples/codex/.codex/agents/contaminated-manager-verifier.toml +14 -5
- package/examples/codex/.codex/agents/contaminated-source-analyst.toml +11 -4
- package/hooks/agent3-verification-runner.py +264 -0
- package/hooks/check-artifact-leakage.py +133 -26
- package/hooks/clean_room_paths.py +191 -22
- package/hooks/deny-clean-room-shell.py +149 -0
- package/hooks/deny-clean-source-read.py +93 -36
- package/hooks/deny-contaminated-clean-write.py +59 -56
- package/hooks/require-clean-room-env.py +161 -6
- package/hooks/validate-handoff-package.py +54 -19
- package/hooks/validate-json-schema.py +269 -44
- package/lib/bootstrap.cjs +247 -0
- package/lib/doctor.cjs +312 -0
- package/lib/fs-utils.cjs +103 -4
- package/lib/hooks.cjs +37 -39
- package/lib/install-artifacts.cjs +163 -0
- package/lib/install-plan.cjs +252 -0
- package/lib/preflight.cjs +425 -0
- package/lib/run.cjs +798 -0
- package/lib/runtime-layout.cjs +258 -0
- package/package.json +7 -3
- package/plugin.json +2 -3
- package/skills/attended/SKILL.md +10 -6
- package/skills/clean-room/SKILL.md +81 -45
- package/skills/clean-room/assets/behavior-spec.schema.json +1 -0
- package/skills/clean-room/assets/clean-room-result.schema.json +103 -0
- package/skills/clean-room/assets/clean-run-context.schema.json +556 -0
- package/skills/clean-room/assets/contamination-incident.schema.json +1 -0
- package/skills/clean-room/assets/handoff-package.schema.json +3 -7
- package/skills/clean-room/assets/implementation-plan.schema.json +297 -0
- package/skills/clean-room/assets/implementation-report.schema.json +333 -0
- package/skills/clean-room/assets/init-config.schema.json +225 -0
- package/skills/clean-room/assets/preflight-goal.schema.json +439 -0
- package/skills/clean-room/assets/qc-report.schema.json +3 -0
- package/skills/clean-room/assets/task-manifest.schema.json +612 -3
- package/skills/clean-room/examples/README.md +22 -5
- package/skills/clean-room/examples/contaminated-side/init-config.json +52 -0
- package/skills/clean-room/examples/contaminated-side/preflight-goal.json +88 -0
- package/skills/clean-room/examples/contaminated-side/task-manifest.json +473 -0
- package/skills/clean-room/examples/minimal-spec-package/behavior-spec.json +1 -1
- package/skills/clean-room/examples/minimal-spec-package/clean-room-result.json +10 -0
- package/skills/clean-room/examples/minimal-spec-package/clean-run-context.json +139 -0
- package/skills/clean-room/examples/minimal-spec-package/contamination-incident.json +10 -0
- package/skills/clean-room/examples/minimal-spec-package/handoff-package.json +8 -2
- package/skills/clean-room/examples/minimal-spec-package/implementation-plan.json +88 -0
- package/skills/clean-room/examples/minimal-spec-package/implementation-report.json +30 -0
- package/skills/clean-room/examples/valid-handoff-package/behavior-spec.json +61 -0
- package/skills/clean-room/examples/valid-handoff-package/handoff-package.json +26 -0
- package/skills/clean-room/references/CONTROLLER-LOOP.md +100 -0
- package/skills/clean-room/references/LEAKAGE-RULES.md +18 -7
- package/skills/clean-room/references/PREFLIGHT.md +71 -0
- package/skills/clean-room/references/PROCESS.md +162 -70
- package/skills/clean-room/references/SPEC-SCHEMA.md +149 -13
- package/skills/clean-room/references/TARGET-LANGUAGE-GUIDE.md +7 -0
- package/skills/clean-room/scripts/build_source_index.py +34 -1118
- package/skills/clean-room/scripts/clean_room_tool_manager.py +120 -37
- package/skills/clean-room/scripts/clean_room_tooling.py +120 -28
- package/skills/clean-room/scripts/source_index/__init__.py +2 -0
- package/skills/clean-room/scripts/source_index/batching.py +213 -0
- package/skills/clean-room/scripts/source_index/discovery.py +331 -0
- package/skills/clean-room/scripts/source_index/metrics.py +67 -0
- package/skills/clean-room/scripts/source_index/native_scanners.py +245 -0
- package/skills/clean-room/scripts/source_index/python_js_scanners.py +124 -0
- package/skills/clean-room/scripts/source_index/relationships.py +185 -0
- package/skills/clean-room/scripts/source_index/scanner_utils.py +28 -0
- package/skills/clean-room/scripts/source_index/scanners.py +110 -0
- package/skills/clean-room/scripts/source_index/writer.py +40 -0
- package/skills/init/SKILL.md +58 -0
- package/skills/preflight/SKILL.md +56 -0
- package/skills/refocus/SKILL.md +67 -0
- package/skills/resume/SKILL.md +77 -0
- package/skills/start-over/SKILL.md +58 -0
- package/skills/unattended/SKILL.md +16 -7
- package/hooks/hooks.json +0 -44
- package/skills/clean-room/examples/minimal-spec-package/task-manifest.json +0 -220
- /package/skills/clean-room/examples/{minimal-spec-package → contaminated-side}/coverage-ledger.json +0 -0
- /package/skills/clean-room/examples/{minimal-spec-package → contaminated-side}/evidence-ledger.json +0 -0
- /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
|
-
|
|
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 `
|
|
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-
|
|
15
|
+
- Authorized source-to-implementation migration work.
|
|
16
16
|
- Clean behavioral specifications for compatibility work.
|
|
17
|
-
-
|
|
18
|
-
- Documented separation between source-reading roles and clean
|
|
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
|
-
|
|
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/
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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
|
|
132
|
-
- Clean
|
|
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
|

|
|
139
390
|
|
|
140
|
-
|
|
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
|
|
210
|
-
- Agent 1 / `contaminated-source-analyst`: reads authorized source and writes neutral task/spec material with evidence references, not code.
|
|
211
|
-
- Agent
|
|
212
|
-
- Agent
|
|
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`
|
|
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.
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
270
|
-
- `unattended`: agent zero runs a bounded
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
293
|
-
2. Record
|
|
294
|
-
3.
|
|
295
|
-
4.
|
|
296
|
-
5.
|
|
297
|
-
6.
|
|
298
|
-
7.
|
|
299
|
-
8.
|
|
300
|
-
9.
|
|
301
|
-
10.
|
|
302
|
-
11.
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
```
|