codex-workspace-bootstrap 0.4.0__tar.gz → 0.5.1__tar.gz

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 (29) hide show
  1. {codex_workspace_bootstrap-0.4.0/src/codex_workspace_bootstrap.egg-info → codex_workspace_bootstrap-0.5.1}/PKG-INFO +80 -5
  2. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/README.md +79 -4
  3. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/pyproject.toml +1 -1
  4. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap/__init__.py +1 -1
  5. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap/cli.py +95 -4
  6. codex_workspace_bootstrap-0.5.1/src/codex_workspace_bootstrap/fixes.py +72 -0
  7. codex_workspace_bootstrap-0.5.1/src/codex_workspace_bootstrap/instructions.py +654 -0
  8. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap/preflight.py +61 -53
  9. codex_workspace_bootstrap-0.5.1/src/codex_workspace_bootstrap/sarif.py +205 -0
  10. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1/src/codex_workspace_bootstrap.egg-info}/PKG-INFO +80 -5
  11. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap.egg-info/SOURCES.txt +4 -0
  12. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/tests/test_cli.py +33 -1
  13. codex_workspace_bootstrap-0.5.1/tests/test_instruction_integrity.py +381 -0
  14. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/tests/test_preflight.py +60 -0
  15. codex_workspace_bootstrap-0.5.1/tests/test_public_repo_patterns.py +72 -0
  16. codex_workspace_bootstrap-0.5.1/tests/test_sarif.py +96 -0
  17. codex_workspace_bootstrap-0.4.0/src/codex_workspace_bootstrap/sarif.py +0 -83
  18. codex_workspace_bootstrap-0.4.0/tests/test_sarif.py +0 -44
  19. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/LICENSE +0 -0
  20. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/setup.cfg +0 -0
  21. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap/__main__.py +0 -0
  22. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap/agents.py +0 -0
  23. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap/audit.py +0 -0
  24. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap/doctor.py +0 -0
  25. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap.egg-info/dependency_links.txt +0 -0
  26. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap.egg-info/entry_points.txt +0 -0
  27. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/src/codex_workspace_bootstrap.egg-info/top_level.txt +0 -0
  28. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/tests/test_audit.py +0 -0
  29. {codex_workspace_bootstrap-0.4.0 → codex_workspace_bootstrap-0.5.1}/tests/test_doctor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-workspace-bootstrap
3
- Version: 0.4.0
3
+ Version: 0.5.1
4
4
  Summary: Preflight AI coding repositories before Codex, Copilot, Cline, Claude, Gemini, Continue, or Cursor touches them.
5
5
  Author: kohli217
6
6
  License: MIT
@@ -30,12 +30,13 @@ Dynamic: license-file
30
30
 
31
31
  [![CI](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/ci.yml/badge.svg)](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/ci.yml)
32
32
  [![CodeQL](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/codeql.yml/badge.svg)](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/codeql.yml)
33
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/kohli217/codex-workspace-bootstrap/badge)](https://scorecard.dev/viewer/?uri=github.com/kohli217/codex-workspace-bootstrap)
33
34
  [![Release](https://img.shields.io/github/v/release/kohli217/codex-workspace-bootstrap)](https://github.com/kohli217/codex-workspace-bootstrap/releases/latest)
34
35
  [![PyPI](https://img.shields.io/pypi/v/codex-workspace-bootstrap)](https://pypi.org/project/codex-workspace-bootstrap/)
35
36
  [![License](https://img.shields.io/github/license/kohli217/codex-workspace-bootstrap)](LICENSE)
36
37
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](pyproject.toml)
37
38
 
38
- **Preflight your repository before an AI coding agent touches it.**
39
+ **Preflight your repository before an AI coding agent touches it — and catch instruction drift before different agents follow different rules.**
39
40
 
40
41
  Windows-first. Local by default. CI-friendly. Designed for repositories used with Codex, Copilot, Cline, Claude Code, Gemini CLI, Continue, Cursor, and similar coding agents.
41
42
 
@@ -58,6 +59,7 @@ State: NEEDS ATTENTION
58
59
  Project: Python
59
60
  AI instructions: none detected
60
61
  Audit: 10 passed, 4 warnings, 0 blocking
62
+ Instruction integrity: 0 findings, 0 drift, 0 invalid commands, 0 metadata
61
63
  Next actions:
62
64
  [P1] Add repository instructions for AI coding agents -> cwb init-agents .
63
65
  [P2] Make the Codex CLI available when local Codex workflows are intended -> codex --version
@@ -70,6 +72,43 @@ cwb init-agents .
70
72
  cwb preflight .
71
73
  ```
72
74
 
75
+ ### See it catch real mistakes
76
+
77
+ A reproducible demo creates a temporary repository where the project uses **pnpm** but `AGENTS.md` tells the agent to use **npm** and references a nonexistent `lint` script.
78
+
79
+ ```powershell
80
+ py examples/first-run-demo/run_demo.py
81
+ ```
82
+
83
+ Expected outcome:
84
+
85
+ ```text
86
+ === BEFORE ===
87
+ State: NEEDS ATTENTION
88
+ Findings:
89
+ - package-manager-mismatch
90
+ - missing-package-script
91
+
92
+ === AFTER ===
93
+ State: READY
94
+ Findings: none
95
+
96
+ Demo verification: PASS
97
+ ```
98
+
99
+ See [examples/first-run-demo](examples/first-run-demo) for the full reproducible demo. It uses disposable temporary Git repositories and is verified in CI.
100
+
101
+ ### Try it on your repository
102
+
103
+ ```powershell
104
+ py -m pip install codex-workspace-bootstrap
105
+ cwb preflight .
106
+ ```
107
+
108
+ If the result is useful, noisy, or surprising, open a [Usage report](https://github.com/kohli217/codex-workspace-bootstrap/issues/new?template=usage_report.yml). Public references are optional; do not include private repository contents, credentials, or secret values.
109
+
110
+ Useful feedback includes false positives, missing repository layouts, monorepo behavior, and which check saved you time.
111
+
73
112
  The goal is not a vanity score. The result is one of:
74
113
 
75
114
  - **READY** — core repository signals and AI instructions are present, with no blocking finding;
@@ -101,6 +140,17 @@ The preflight detects repository instruction/config signals for:
101
140
 
102
141
  It does not claim these files are correct merely because they exist. It tells you what was detected so a maintainer can review the actual instructions.
103
142
 
143
+ ### Cross-agent instruction integrity
144
+
145
+ When multiple AI instruction files exist, `cwb` reads executable-looking commands and checks them against repository evidence. It understands nested `AGENTS.md` / `AGENTS.override.md`, nested Cursor `.cursor/rules`, and common path-specific frontmatter such as Copilot `applyTo` and rule `globs`. It can flag:
146
+
147
+ - package-manager mismatches against `packageManager` and lockfiles;
148
+ - cross-agent package-manager drift;
149
+ - missing `package.json` scripts referenced by instructions;
150
+ - conflicting test/lint/build validation commands when instruction files have no shared command for the same validation family.
151
+
152
+ The lint is intentionally conservative: different files may contain additional commands without being treated as conflicts when they share a compatible validation baseline. Commands from different scopes are not compared as if they were global rules. Path-specific rules are validated individually against repository evidence but are not cross-compared for drift unless their full selector semantics can be represented safely. A repository is not marked READY when it only has nested/path-specific instructions and no repository-wide instruction baseline.
153
+
104
154
  ### Risk signals
105
155
 
106
156
  The audit warns about common secret-bearing filenames without printing their contents. When Git is available, it distinguishes **tracked**, **ignored**, and **untracked/unknown** candidates. Tracked risky filenames can become blocking findings in strict mode.
@@ -146,6 +196,7 @@ Write reports for automation or review:
146
196
  ```powershell
147
197
  cwb preflight . --json preflight.json
148
198
  cwb preflight . --markdown preflight.md
199
+ cwb preflight . --sarif preflight.sarif
149
200
  ```
150
201
 
151
202
  Use strict mode when blocking findings should return a non-zero exit code:
@@ -154,6 +205,12 @@ Use strict mode when blocking findings should return a non-zero exit code:
154
205
  cwb preflight . --strict
155
206
  ```
156
207
 
208
+ Fail CI on any instruction-integrity finding:
209
+
210
+ ```powershell
211
+ cwb preflight . --fail-on-integrity
212
+ ```
213
+
157
214
  ### Detailed audit
158
215
 
159
216
  ```powershell
@@ -163,6 +220,20 @@ cwb audit . --sarif audit.sarif
163
220
  cwb audit . --strict
164
221
  ```
165
222
 
223
+ ### Safe fix preview
224
+
225
+ ```powershell
226
+ cwb fix .
227
+ ```
228
+
229
+ This is preview-only by default. To apply only low-risk supported fixes:
230
+
231
+ ```powershell
232
+ cwb fix . --apply
233
+ ```
234
+
235
+ Existing conflicting instruction files are never auto-rewritten. They remain human-review findings.
236
+
166
237
  ### Non-destructive doctor
167
238
 
168
239
  ```powershell
@@ -188,16 +259,19 @@ The reusable Action is published on GitHub Marketplace.
188
259
  - uses: actions/setup-python@v7
189
260
  with:
190
261
  python-version: "3.13"
191
- - uses: kohli217/codex-workspace-bootstrap@v0.4.0
262
+ - uses: kohli217/codex-workspace-bootstrap@v0.5.1
192
263
  with:
193
264
  path: .
194
265
  strict: "true"
266
+ fail_on_integrity: "true"
195
267
  ```
196
268
 
197
- The Action adds the preflight Markdown report to the **GitHub Actions job summary**, so maintainers get a readable readiness snapshot without digging through raw logs. Optional SARIF output can be uploaded to GitHub Code Scanning.
269
+ The Action adds the preflight Markdown report to the **GitHub Actions job summary**, so maintainers get a readable readiness snapshot without digging through raw logs. Optional SARIF output contains both repository-audit and instruction-integrity findings and can be uploaded to GitHub Code Scanning.
198
270
 
199
271
  See [docs/GITHUB_ACTION.md](docs/GITHUB_ACTION.md).
200
272
 
273
+ Read-only evaluations against real public repositories are documented in [docs/PUBLIC_REPO_EVALUATIONS.md](docs/PUBLIC_REPO_EVALUATIONS.md). They are reproducible technical evaluations, not claims of third-party adoption.
274
+
201
275
  ## Where it fits
202
276
 
203
277
  This project is a **preflight layer**, not an AI coding agent and not a deep security scanner.
@@ -216,6 +290,7 @@ The intent is to complement those tools, not replace them.
216
290
  - Core checks run locally.
217
291
  - Suspected secret files are not opened or printed by the filename-risk check.
218
292
  - Repository contents are not sent to a remote AI service by the core audit.
293
+ - Instruction files are read locally for deterministic linting; extracted commands are never executed by the integrity lint.
219
294
  - Existing `AGENTS.md` files are protected unless overwrite is explicit.
220
295
  - A passing preflight is evidence about the checks performed, **not a security guarantee**.
221
296
 
@@ -248,7 +323,7 @@ py -m pip install codex-workspace-bootstrap
248
323
  Pinned GitHub release artifact:
249
324
 
250
325
  ```powershell
251
- py -m pip install "https://github.com/kohli217/codex-workspace-bootstrap/releases/download/v0.4.0/codex_workspace_bootstrap-0.4.0-py3-none-any.whl"
326
+ py -m pip install "https://github.com/kohli217/codex-workspace-bootstrap/releases/download/v0.5.1/codex_workspace_bootstrap-0.5.1-py3-none-any.whl"
252
327
  ```
253
328
 
254
329
  ## Development
@@ -2,12 +2,13 @@
2
2
 
3
3
  [![CI](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/ci.yml/badge.svg)](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/ci.yml)
4
4
  [![CodeQL](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/codeql.yml/badge.svg)](https://github.com/kohli217/codex-workspace-bootstrap/actions/workflows/codeql.yml)
5
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/kohli217/codex-workspace-bootstrap/badge)](https://scorecard.dev/viewer/?uri=github.com/kohli217/codex-workspace-bootstrap)
5
6
  [![Release](https://img.shields.io/github/v/release/kohli217/codex-workspace-bootstrap)](https://github.com/kohli217/codex-workspace-bootstrap/releases/latest)
6
7
  [![PyPI](https://img.shields.io/pypi/v/codex-workspace-bootstrap)](https://pypi.org/project/codex-workspace-bootstrap/)
7
8
  [![License](https://img.shields.io/github/license/kohli217/codex-workspace-bootstrap)](LICENSE)
8
9
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](pyproject.toml)
9
10
 
10
- **Preflight your repository before an AI coding agent touches it.**
11
+ **Preflight your repository before an AI coding agent touches it — and catch instruction drift before different agents follow different rules.**
11
12
 
12
13
  Windows-first. Local by default. CI-friendly. Designed for repositories used with Codex, Copilot, Cline, Claude Code, Gemini CLI, Continue, Cursor, and similar coding agents.
13
14
 
@@ -30,6 +31,7 @@ State: NEEDS ATTENTION
30
31
  Project: Python
31
32
  AI instructions: none detected
32
33
  Audit: 10 passed, 4 warnings, 0 blocking
34
+ Instruction integrity: 0 findings, 0 drift, 0 invalid commands, 0 metadata
33
35
  Next actions:
34
36
  [P1] Add repository instructions for AI coding agents -> cwb init-agents .
35
37
  [P2] Make the Codex CLI available when local Codex workflows are intended -> codex --version
@@ -42,6 +44,43 @@ cwb init-agents .
42
44
  cwb preflight .
43
45
  ```
44
46
 
47
+ ### See it catch real mistakes
48
+
49
+ A reproducible demo creates a temporary repository where the project uses **pnpm** but `AGENTS.md` tells the agent to use **npm** and references a nonexistent `lint` script.
50
+
51
+ ```powershell
52
+ py examples/first-run-demo/run_demo.py
53
+ ```
54
+
55
+ Expected outcome:
56
+
57
+ ```text
58
+ === BEFORE ===
59
+ State: NEEDS ATTENTION
60
+ Findings:
61
+ - package-manager-mismatch
62
+ - missing-package-script
63
+
64
+ === AFTER ===
65
+ State: READY
66
+ Findings: none
67
+
68
+ Demo verification: PASS
69
+ ```
70
+
71
+ See [examples/first-run-demo](examples/first-run-demo) for the full reproducible demo. It uses disposable temporary Git repositories and is verified in CI.
72
+
73
+ ### Try it on your repository
74
+
75
+ ```powershell
76
+ py -m pip install codex-workspace-bootstrap
77
+ cwb preflight .
78
+ ```
79
+
80
+ If the result is useful, noisy, or surprising, open a [Usage report](https://github.com/kohli217/codex-workspace-bootstrap/issues/new?template=usage_report.yml). Public references are optional; do not include private repository contents, credentials, or secret values.
81
+
82
+ Useful feedback includes false positives, missing repository layouts, monorepo behavior, and which check saved you time.
83
+
45
84
  The goal is not a vanity score. The result is one of:
46
85
 
47
86
  - **READY** — core repository signals and AI instructions are present, with no blocking finding;
@@ -73,6 +112,17 @@ The preflight detects repository instruction/config signals for:
73
112
 
74
113
  It does not claim these files are correct merely because they exist. It tells you what was detected so a maintainer can review the actual instructions.
75
114
 
115
+ ### Cross-agent instruction integrity
116
+
117
+ When multiple AI instruction files exist, `cwb` reads executable-looking commands and checks them against repository evidence. It understands nested `AGENTS.md` / `AGENTS.override.md`, nested Cursor `.cursor/rules`, and common path-specific frontmatter such as Copilot `applyTo` and rule `globs`. It can flag:
118
+
119
+ - package-manager mismatches against `packageManager` and lockfiles;
120
+ - cross-agent package-manager drift;
121
+ - missing `package.json` scripts referenced by instructions;
122
+ - conflicting test/lint/build validation commands when instruction files have no shared command for the same validation family.
123
+
124
+ The lint is intentionally conservative: different files may contain additional commands without being treated as conflicts when they share a compatible validation baseline. Commands from different scopes are not compared as if they were global rules. Path-specific rules are validated individually against repository evidence but are not cross-compared for drift unless their full selector semantics can be represented safely. A repository is not marked READY when it only has nested/path-specific instructions and no repository-wide instruction baseline.
125
+
76
126
  ### Risk signals
77
127
 
78
128
  The audit warns about common secret-bearing filenames without printing their contents. When Git is available, it distinguishes **tracked**, **ignored**, and **untracked/unknown** candidates. Tracked risky filenames can become blocking findings in strict mode.
@@ -118,6 +168,7 @@ Write reports for automation or review:
118
168
  ```powershell
119
169
  cwb preflight . --json preflight.json
120
170
  cwb preflight . --markdown preflight.md
171
+ cwb preflight . --sarif preflight.sarif
121
172
  ```
122
173
 
123
174
  Use strict mode when blocking findings should return a non-zero exit code:
@@ -126,6 +177,12 @@ Use strict mode when blocking findings should return a non-zero exit code:
126
177
  cwb preflight . --strict
127
178
  ```
128
179
 
180
+ Fail CI on any instruction-integrity finding:
181
+
182
+ ```powershell
183
+ cwb preflight . --fail-on-integrity
184
+ ```
185
+
129
186
  ### Detailed audit
130
187
 
131
188
  ```powershell
@@ -135,6 +192,20 @@ cwb audit . --sarif audit.sarif
135
192
  cwb audit . --strict
136
193
  ```
137
194
 
195
+ ### Safe fix preview
196
+
197
+ ```powershell
198
+ cwb fix .
199
+ ```
200
+
201
+ This is preview-only by default. To apply only low-risk supported fixes:
202
+
203
+ ```powershell
204
+ cwb fix . --apply
205
+ ```
206
+
207
+ Existing conflicting instruction files are never auto-rewritten. They remain human-review findings.
208
+
138
209
  ### Non-destructive doctor
139
210
 
140
211
  ```powershell
@@ -160,16 +231,19 @@ The reusable Action is published on GitHub Marketplace.
160
231
  - uses: actions/setup-python@v7
161
232
  with:
162
233
  python-version: "3.13"
163
- - uses: kohli217/codex-workspace-bootstrap@v0.4.0
234
+ - uses: kohli217/codex-workspace-bootstrap@v0.5.1
164
235
  with:
165
236
  path: .
166
237
  strict: "true"
238
+ fail_on_integrity: "true"
167
239
  ```
168
240
 
169
- The Action adds the preflight Markdown report to the **GitHub Actions job summary**, so maintainers get a readable readiness snapshot without digging through raw logs. Optional SARIF output can be uploaded to GitHub Code Scanning.
241
+ The Action adds the preflight Markdown report to the **GitHub Actions job summary**, so maintainers get a readable readiness snapshot without digging through raw logs. Optional SARIF output contains both repository-audit and instruction-integrity findings and can be uploaded to GitHub Code Scanning.
170
242
 
171
243
  See [docs/GITHUB_ACTION.md](docs/GITHUB_ACTION.md).
172
244
 
245
+ Read-only evaluations against real public repositories are documented in [docs/PUBLIC_REPO_EVALUATIONS.md](docs/PUBLIC_REPO_EVALUATIONS.md). They are reproducible technical evaluations, not claims of third-party adoption.
246
+
173
247
  ## Where it fits
174
248
 
175
249
  This project is a **preflight layer**, not an AI coding agent and not a deep security scanner.
@@ -188,6 +262,7 @@ The intent is to complement those tools, not replace them.
188
262
  - Core checks run locally.
189
263
  - Suspected secret files are not opened or printed by the filename-risk check.
190
264
  - Repository contents are not sent to a remote AI service by the core audit.
265
+ - Instruction files are read locally for deterministic linting; extracted commands are never executed by the integrity lint.
191
266
  - Existing `AGENTS.md` files are protected unless overwrite is explicit.
192
267
  - A passing preflight is evidence about the checks performed, **not a security guarantee**.
193
268
 
@@ -220,7 +295,7 @@ py -m pip install codex-workspace-bootstrap
220
295
  Pinned GitHub release artifact:
221
296
 
222
297
  ```powershell
223
- py -m pip install "https://github.com/kohli217/codex-workspace-bootstrap/releases/download/v0.4.0/codex_workspace_bootstrap-0.4.0-py3-none-any.whl"
298
+ py -m pip install "https://github.com/kohli217/codex-workspace-bootstrap/releases/download/v0.5.1/codex_workspace_bootstrap-0.5.1-py3-none-any.whl"
224
299
  ```
225
300
 
226
301
  ## Development
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codex-workspace-bootstrap"
7
- version = "0.4.0"
7
+ version = "0.5.1"
8
8
  description = "Preflight AI coding repositories before Codex, Copilot, Cline, Claude, Gemini, Continue, or Cursor touches them."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """codex-workspace-bootstrap package."""
2
2
 
3
- __version__ = "0.4.0"
3
+ __version__ = "0.5.0"
@@ -9,14 +9,15 @@ from . import __version__
9
9
  from .agents import generate_agents
10
10
  from .audit import audit_repository, summary
11
11
  from .doctor import doctor_findings
12
+ from .fixes import apply_fix_plan, build_fix_plan
12
13
  from .preflight import build_preflight, render_markdown
13
- from .sarif import checks_to_sarif
14
+ from .sarif import checks_to_sarif, preflight_report_to_sarif
14
15
 
15
16
 
16
17
  def _parser() -> argparse.ArgumentParser:
17
18
  parser = argparse.ArgumentParser(
18
19
  prog="codex-workspace-bootstrap",
19
- description="Audit and bootstrap repositories for reliable Codex workflows.",
20
+ description="Preflight AI coding repositories for readiness, instruction integrity, and CI enforcement.",
20
21
  )
21
22
  parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
22
23
  sub = parser.add_subparsers(dest="command", required=True)
@@ -25,11 +26,29 @@ def _parser() -> argparse.ArgumentParser:
25
26
  preflight.add_argument("path", nargs="?", default=".")
26
27
  preflight.add_argument("--json", dest="json_path", help="Write the complete preflight report to JSON")
27
28
  preflight.add_argument("--markdown", dest="markdown_path", help="Write a concise Markdown preflight report")
29
+ preflight.add_argument(
30
+ "--sarif",
31
+ dest="sarif_path",
32
+ help="Write audit and instruction-integrity findings as SARIF 2.1.0",
33
+ )
28
34
  preflight.add_argument(
29
35
  "--strict",
30
36
  action="store_true",
31
37
  help="Return a non-zero exit code when blocking findings are present",
32
38
  )
39
+ preflight.add_argument(
40
+ "--fail-on-integrity",
41
+ action="store_true",
42
+ help="Return a non-zero exit code when AI instruction integrity findings are present",
43
+ )
44
+
45
+ fix = sub.add_parser("fix", help="Preview safe repository-readiness fixes")
46
+ fix.add_argument("path", nargs="?", default=".")
47
+ fix.add_argument(
48
+ "--apply",
49
+ action="store_true",
50
+ help="Apply only low-risk supported fixes; conflicting instructions are never auto-rewritten",
51
+ )
33
52
 
34
53
  audit = sub.add_parser("audit", help="Audit a repository and local toolchain")
35
54
  audit.add_argument("path", nargs="?", default=".")
@@ -63,7 +82,9 @@ def _run_preflight(
63
82
  path: str,
64
83
  json_path: str | None,
65
84
  markdown_path: str | None,
85
+ sarif_path: str | None,
66
86
  strict: bool,
87
+ fail_on_integrity: bool,
67
88
  ) -> int:
68
89
  root = Path(path).expanduser().resolve()
69
90
  if not root.exists() or not root.is_dir():
@@ -84,7 +105,7 @@ def _run_preflight(
84
105
  if instructions:
85
106
  print("AI instructions:")
86
107
  for item in instructions:
87
- print(f" - {item['tool']}: {item['path']}")
108
+ print(f" - {item['tool']}: {item['path']} [scope={item.get('scope', '.')}]")
88
109
  else:
89
110
  print("AI instructions: none detected")
90
111
 
@@ -94,6 +115,23 @@ def _run_preflight(
94
115
  f"{totals['warnings']} warnings, {totals['blocking']} blocking"
95
116
  )
96
117
 
118
+ instruction_totals = report["instruction_summary"]
119
+ print(
120
+ f"Instruction integrity: {instruction_totals['findings']} findings, "
121
+ f"{instruction_totals['drift']} drift, "
122
+ f"{instruction_totals['invalid_commands']} invalid commands, "
123
+ f"{instruction_totals['metadata']} metadata"
124
+ )
125
+
126
+ findings = report["instruction_findings"]
127
+ if findings:
128
+ print("Instruction findings:")
129
+ for item in findings:
130
+ print(
131
+ f" [{item['severity'].upper()}] {item['kind']}: {item['message']} "
132
+ f"[scope={item.get('scope', '.')}]"
133
+ )
134
+
97
135
  actions = report["next_actions"]
98
136
  if actions:
99
137
  print("Next actions:")
@@ -112,8 +150,52 @@ def _run_preflight(
112
150
  output.write_text(render_markdown(report), encoding="utf-8")
113
151
  print(f"Preflight Markdown report written to: {output}")
114
152
 
153
+ if sarif_path:
154
+ _write_json(
155
+ sarif_path,
156
+ preflight_report_to_sarif(report),
157
+ "Preflight SARIF report",
158
+ )
159
+
115
160
  if strict and report["state"] == "BLOCKED":
116
161
  return 1
162
+ if fail_on_integrity and report["instruction_summary"]["findings"]:
163
+ return 1
164
+ return 0
165
+
166
+
167
+ def _run_fix(path: str, apply: bool) -> int:
168
+ root = Path(path).expanduser().resolve()
169
+ if not root.exists() or not root.is_dir():
170
+ print(f"error: repository path does not exist or is not a directory: {root}", file=sys.stderr)
171
+ return 2
172
+
173
+ plan = build_fix_plan(root)
174
+ print(f"Repository: {root}")
175
+ if not plan:
176
+ print("Fix plan: no supported fixes or instruction-integrity findings.")
177
+ return 0
178
+
179
+ print("Fix plan:")
180
+ for item in plan:
181
+ mode = "AUTO" if item.apply_supported else "REVIEW"
182
+ target = f" -> {item.target}" if item.target else ""
183
+ print(f" [{mode}] {item.description}{target}")
184
+
185
+ if not apply:
186
+ print("Preview only. Re-run with --apply to apply low-risk supported fixes.")
187
+ return 0
188
+
189
+ applied = apply_fix_plan(root, plan)
190
+ if applied:
191
+ print("Applied:")
192
+ for path_item in applied:
193
+ print(f" - {path_item}")
194
+ else:
195
+ print("No automatic changes were applied.")
196
+ manual = sum(not item.apply_supported for item in plan)
197
+ if manual:
198
+ print(f"{manual} finding(s) require human review and were left unchanged.")
117
199
  return 0
118
200
 
119
201
  def _run_audit(
@@ -200,7 +282,16 @@ def _run_init_agents(path: str, force: bool) -> int:
200
282
  def main(argv: list[str] | None = None) -> int:
201
283
  args = _parser().parse_args(argv)
202
284
  if args.command == "preflight":
203
- return _run_preflight(args.path, args.json_path, args.markdown_path, args.strict)
285
+ return _run_preflight(
286
+ args.path,
287
+ args.json_path,
288
+ args.markdown_path,
289
+ args.sarif_path,
290
+ args.strict,
291
+ args.fail_on_integrity,
292
+ )
293
+ if args.command == "fix":
294
+ return _run_fix(args.path, args.apply)
204
295
  if args.command == "audit":
205
296
  return _run_audit(args.path, args.json_path, args.sarif_path, args.strict)
206
297
  if args.command == "doctor":
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, dataclass
4
+ from pathlib import Path
5
+
6
+ from .agents import generate_agents
7
+ from .instructions import detect_instruction_signals, lint_instructions
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class FixPlanItem:
12
+ kind: str
13
+ description: str
14
+ apply_supported: bool
15
+ target: str | None = None
16
+
17
+ def to_dict(self) -> dict[str, object]:
18
+ return asdict(self)
19
+
20
+
21
+ def build_fix_plan(root: Path) -> list[FixPlanItem]:
22
+ root = root.resolve()
23
+ plan: list[FixPlanItem] = []
24
+
25
+ signals = detect_instruction_signals(root)
26
+ findings = lint_instructions(root, signals)
27
+
28
+ has_repository_wide = any(
29
+ signal.scope == "." and signal.kind in {"repository", "override"}
30
+ for signal in signals
31
+ )
32
+ if not has_repository_wide:
33
+ plan.append(
34
+ FixPlanItem(
35
+ "create-agents",
36
+ (
37
+ "Create an evidence-based AGENTS.md because no supported repository-wide "
38
+ "AI instruction baseline was detected."
39
+ ),
40
+ True,
41
+ "AGENTS.md",
42
+ )
43
+ )
44
+
45
+ for finding in findings:
46
+ plan.append(
47
+ FixPlanItem(
48
+ f"manual-{finding.kind}",
49
+ finding.message,
50
+ False,
51
+ ", ".join(finding.files) if finding.files else None,
52
+ )
53
+ )
54
+
55
+ return plan
56
+
57
+
58
+ def apply_fix_plan(root: Path, plan: list[FixPlanItem]) -> list[str]:
59
+ root = root.resolve()
60
+ applied: list[str] = []
61
+
62
+ for item in plan:
63
+ if not item.apply_supported:
64
+ continue
65
+ if item.kind == "create-agents":
66
+ target = root / "AGENTS.md"
67
+ if target.exists():
68
+ continue
69
+ target.write_text(generate_agents(root), encoding="utf-8")
70
+ applied.append(str(target))
71
+
72
+ return applied