riskrails 3.2.1 → 4.0.1

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 (141) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +40 -83
  5. package/agents/ai-reviewer.md.tmpl +1 -1
  6. package/ai/using-riskrails.md +0 -3
  7. package/bin/riskrails.js +13 -59
  8. package/hooks/ai-path-guard-defaults.json +1 -1
  9. package/hooks/context-guard.py +2 -4
  10. package/hooks/guard/paths.py +3 -6
  11. package/hooks/guard/scope.py +1 -3
  12. package/hooks/runtime-gate.py +18 -58
  13. package/instructions/routing.md +2 -2
  14. package/package.json +1 -1
  15. package/scripts/ai-path +1 -1
  16. package/scripts/resolve-profile.py +0 -3
  17. package/skills/ai-audit/templates/ai-sdlc-adoption-plan.md +1 -1
  18. package/skills/ai-audit/templates/play-scoring-rubric.md +1 -1
  19. package/skills/ai-init/templates/.ai/AGENTS.md +6 -6
  20. package/skills/ai-init/templates/.ai/VERSION +1 -1
  21. package/skills/ai-init/templates/.ai/policies/security.md +1 -2
  22. package/skills/ai-init/templates/.ai/policies/testing.md +5 -12
  23. package/skills/ai-init/templates/.ai/policies/verification.md +18 -0
  24. package/skills/ai-init/templates/.ai/policies/weight.json +0 -1
  25. package/skills/ai-init/templates/.ai/policies/weight.md +1 -2
  26. package/skills/ai-init/templates/.ai/policies/weight.project.json +4 -0
  27. package/skills/ai-init/templates/.ai/project/architecture.md +1 -1
  28. package/skills/ai-init/templates/.ai/project/initial-assessment.md +2 -2
  29. package/skills/ai-init/templates/.ai/project/overview.md +1 -1
  30. package/skills/ai-init/templates/.ai/rules/README.md +2 -2
  31. package/skills/ai-init/templates/.ai/state/README.md +1 -1
  32. package/skills/ai-task/memory_store.py +8 -9
  33. package/skills/ai-task/rr_state/cli.py +1 -1
  34. package/skills/ai-task/rr_state/dialog.py +2 -4
  35. package/skills/ai-task/rr_state/fs.py +5 -13
  36. package/skills/ai-task/rr_state/profile.py +2 -4
  37. package/skills/ai-task/rr_state/questions_cmd.py +1 -1
  38. package/skills/ai-task/rr_state/report.py +3 -4
  39. package/skills/ai-task/rr_state/runtime.py +1 -1
  40. package/skills/ai-task/rr_state/start.py +7 -7
  41. package/skills/ai-task/sensors.py +10 -11
  42. package/skills/ai-task/state.py +4 -24
  43. package/skills/ai-task/weight.py +17 -17
  44. package/skills/ai-task/weight_overlay.py +38 -0
  45. package/skills/project-init/templates/constitution.md +2 -2
  46. package/skills/project-update/history/blobs/00f5e27ce2d66e3a1d8b222b013ae8fa1fed32612d91a551e0c661cee3ef9c2d +34 -0
  47. package/skills/project-update/history/blobs/0a6b1b6dd06a35582b2e9989a1f41c40abc29254b8e482714fcc6f0a7b16c406 +32 -0
  48. package/skills/project-update/history/blobs/0aeb04b04262683cac6513545683486a73dc473b447bba43b5aaab18403957a6 +34 -0
  49. package/skills/project-update/history/blobs/0ce913a28996f546f72d570b0e5a376362e993ce4d805bc4aae57d38caa44212 +41 -0
  50. package/skills/project-update/history/blobs/0ea9e36446b624b73b2a821231b2ee66a357b43d584a5b23da48b3c800855e65 +41 -0
  51. package/skills/project-update/history/blobs/0fb1d68678a1349195b2e79433bb20174d25874e3bfd0b70410bb4e428b4e4b8 +35 -0
  52. package/skills/project-update/history/blobs/119b2b9d0f9c647a243540724edac6b29afa020c69aa205797bcfa9eb06bc021 +35 -0
  53. package/skills/project-update/history/blobs/1d0fe3ee5fb8260ba610942d4bbdfff7410fbe80ed826ac07f32985031dc2b3f +34 -0
  54. package/skills/project-update/history/blobs/1de9a37ed6402893dcab6e61ddbf15ffd35f15a6d84b18e675a0c5bf4e981f85 +42 -0
  55. package/skills/project-update/history/blobs/1f44e1a236233dcbab58064f39b69f798b35d1d9a29f8c615b5b12854ce633cb +15 -0
  56. package/skills/project-update/history/blobs/1f824645299579cbdd8141642ddbb4bca9fd5fe9d3112f036d8221f0811e0abf +40 -0
  57. package/skills/project-update/history/blobs/235fb88393cfe20dd58b35fe9785cc45baf5ffe21a13d926652d76ec68cea8b7 +35 -0
  58. package/skills/project-update/history/blobs/3918b4ee011d9477b9d2779e2893ab599749c406d4b09439a9748b64fbff58f3 +18 -0
  59. package/skills/project-update/history/blobs/449273200dfec2a56885c881ff34d40e8ecc00da53c24c2d09b7fbeb1004d255 +40 -0
  60. package/skills/project-update/history/blobs/4c45aee9b9fc5f6b4e1d9739e434c4094975a5a8dec6b9703fb25f3080680c77 +124 -0
  61. package/skills/project-update/history/blobs/4dd3fa12bc45acc8c836ab65d790248ca7504a021bca6677499d17bb3d798ed9 +64 -0
  62. package/skills/project-update/history/blobs/51e3f15095d7123ea8566b512479ee10a6cb2f336b7352a259a083a887bd7116 +33 -0
  63. package/skills/project-update/history/blobs/5497a204967bea7dab29079a6e1dfa3d8713b2d2cb294c2779378039f03a55fc +36 -0
  64. package/skills/project-update/history/blobs/60c4d7e7fde7049d92d84295fc13ca9a91eb2de423be08f093b3ee5d5e817ff8 +64 -0
  65. package/skills/project-update/history/blobs/6221b7c14cc04634e485e562d464c6860d45666a7f63e293c06bb2944ff556cc +27 -0
  66. package/skills/project-update/history/blobs/637971cfb844ef4285e2886a4b1c834fb2ed5c46e773adb88c2c147fea626ad3 +33 -0
  67. package/skills/project-update/history/blobs/65af2282eea2a51fcc27a4acf2c26c727b0961c30e1be13176369200c460c219 +34 -0
  68. package/skills/project-update/history/blobs/66ecd73e303e7bbc1aa8ee72435d0d10812ff7b2eff0adac59bbf0a303e2cc01 +41 -0
  69. package/skills/project-update/history/blobs/6a43bf32461b22b87fafe2865529dc04fa66cd00182a2a7598aa071667ca255a +35 -0
  70. package/skills/project-update/history/blobs/6d6dee8634abf9ac057bb206828b83a893a2afcf4f86bbe69e839a3b47d0adde +48 -0
  71. package/skills/project-update/history/blobs/7224ede803ea81e65a456e21b6028a0e848e8a880456c6503eebe7534ca4f6aa +74 -0
  72. package/skills/project-update/history/blobs/765a39a202617096c232017822ae738d37e4405430c71700dc7bc14bf1ba794e +33 -0
  73. package/skills/project-update/history/blobs/77577440a933d1cabd8c6f4a6401cf361a784aa09a25500a6f7b44ead8ab5e55 +41 -0
  74. package/skills/project-update/history/blobs/7bae90789625d6fb9071ecb412d14a8d1eb0bc5659d8d284c4eaf213e1b5de56 +67 -0
  75. package/skills/project-update/history/blobs/7bcdf9a0e6b85277b9b60669150224b9414d2e32821ff06f4d148eb1d18785bb +42 -0
  76. package/skills/project-update/history/blobs/7f834103e9d97aea44e76717bcdcbbe349c560e5b81a42ce85a1cec341041281 +4 -0
  77. package/skills/project-update/history/blobs/7fb3acb0211818efebc2234863db0b8c846022a7280a6d2d69f267dbf63db48c +34 -0
  78. package/skills/project-update/history/blobs/87f0855859ff68cc6c988cc0b631ee7f56af7fbba062172bf80e01f4982cc054 +35 -0
  79. package/skills/project-update/history/blobs/8abab74759766d02b5cb7b0c3e59a3d440b25a454216cd8fea325c23fd822d36 +33 -0
  80. package/skills/project-update/history/blobs/a1fb50e6c86fae1679ef3351296fd6713411a08cf8dd1790a4fd05fae8688164 +1 -0
  81. package/skills/project-update/history/blobs/a3df7268feb0780be0d2cf9acced6ed81780a7790f36fe024b6ea0b1bd6eb7a6 +35 -0
  82. package/skills/project-update/history/blobs/b28721136482dafb9fd2801af340364cb97e9f6eaa987908606c786045b8d334 +28 -0
  83. package/skills/project-update/history/blobs/b3726422d767f9219fea633bea77f0c99ad9af843c591e6e928e1ccd2a47f374 +27 -0
  84. package/skills/project-update/history/blobs/b3839425f9d0ab2efa42a6f5e9488ec2d26ca5fb8dcd694b8ab098e10743ca46 +32 -0
  85. package/skills/project-update/history/blobs/ba14a457e83f9dde65e4190fdfab83b912f7398c1442a2a1cb3d89bfac741cf3 +8 -0
  86. package/skills/project-update/history/blobs/bceb7189444bb6291b262ca08e34db01010dda2f6e64d696231ec3c343c95c66 +34 -0
  87. package/skills/project-update/history/blobs/bf82a2bb4fce1bd349ff66118930a01d61a7af8e2bd8d200c721d43afc58c713 +34 -0
  88. package/skills/project-update/history/blobs/c4dbeb180292a6199ad73a3be861ece07c1f8bf6bf0cc7ca204412bc8e1bb1d8 +31 -0
  89. package/skills/project-update/history/blobs/c644838866df2001a42501a988dd7b77aacf862bf09d22b465f3cd8a22c6b6eb +33 -0
  90. package/skills/project-update/history/blobs/c980d74f76a4bdfb38c94b573ac10a54eb50b850b052e15fa6f2442889b36ccb +32 -0
  91. package/skills/project-update/history/blobs/ceed2f3bd937f862d0e6ca59ce1b1e3603e19a0d7f85d90d6dfeb7bf690153be +29 -0
  92. package/skills/project-update/history/blobs/d51ea2e893482a20c5882056cf8043327ca1dc1c957927f6746929a47ee8368e +45 -0
  93. package/skills/project-update/history/blobs/d78f5e0bb1380259fce2cce009785a9a11f6de8b87a160080b9872c059f95060 +34 -0
  94. package/skills/project-update/history/blobs/d97f46a2cca020406252b1f7baa4184617fa71faca3885e2379c44ae4e1d9327 +67 -0
  95. package/skills/project-update/history/blobs/da3ecd4c4c414c93d04488685931df39a56bf959bfeb9c45cb1aea2c13bd991b +38 -0
  96. package/skills/project-update/history/blobs/e129bf71a5a922e24b2c1bc8daa8a5d2b5589b0069770e17ce17e7db5ed4e7a4 +27 -0
  97. package/skills/project-update/history/blobs/e504529519a371892838725f8b89b5d32e3300e345bcbf2643a3a1a48434b3dd +24 -0
  98. package/skills/project-update/history/blobs/e9e62d03ca70b3dffccef8dceeb214173352cfef005145e519f0e037993f1c03 +36 -0
  99. package/skills/project-update/history/blobs/effefbaaf4beb8f1ba55081d6b7e74bf25ebb91045dd10613418f17b95fa7182 +33 -0
  100. package/skills/project-update/history/blobs/f6af4581bafbf62b257d57e06c3ae2c5998aeca608ee7df037fcc3c3e4b563a9 +34 -0
  101. package/skills/project-update/history/blobs/fc35045777d29630303430752a651b3e553580a581036a02cc103eb96a46f4b0 +34 -0
  102. package/skills/project-update/history/blobs/fdc21345c77f92a42d244aa104f393f439a0ff9981a9fd462bd837e8a47931bb +48 -0
  103. package/skills/project-update/history/index.json +32 -13
  104. package/skills/project-update/render_instructions.py +12 -45
  105. package/skills/project-update/update.py +757 -1172
  106. package/skills/rr-setup/SKILL.md +42 -81
  107. package/skills/rr-setup/scaffold_ai.py +7 -7
  108. package/skills/rr-setup/setup.py +96 -164
  109. package/skills/rr-status/status.py +7 -10
  110. package/skills/usage-report/usage-report.py +4 -5
  111. package/skills/ai-audit/SKILL.md +0 -9
  112. package/skills/ai-init/SKILL.md +0 -9
  113. package/skills/ai-status/SKILL.md +0 -9
  114. package/skills/ai-task/SKILL.md +0 -9
  115. package/skills/project-init/SKILL.md +0 -9
  116. package/skills/project-update/SKILL.md +0 -9
  117. package/skills/project-update/adopt-map.json +0 -91
  118. package/skills/project-update/adopt.py +0 -2225
  119. package/skills/project-update/migrations/0001_schema_version.py +0 -13
  120. package/skills/project-update/migrations/0002_task_journal.py +0 -123
  121. package/skills/project-update/migrations/0003_context_diet.py +0 -65
  122. package/skills/project-update/migrations/0004_deterministic_gates.py +0 -57
  123. package/skills/project-update/migrations/0005_runtimes_and_plans.py +0 -35
  124. package/skills/project-update/migrations/0006_shared_files.py +0 -154
  125. package/skills/project-update/migrations/0007_weight_model.py +0 -295
  126. package/skills/project-update/migrations/0008_renames.py +0 -43
  127. package/skills/project-update/migrations/0009_state_file.py +0 -25
  128. package/skills/project-update/migrations/0010_dialog_switch.py +0 -30
  129. package/skills/project-update/migrations/0011_retire_risk_tiers.py +0 -37
  130. package/skills/project-update/migrations/README.md +0 -76
  131. package/skills/project-update/migrations/__init__.py +0 -186
  132. package/skills/sdlc-intent/SKILL.md +0 -9
  133. package/skills/sdlc-plan/SKILL.md +0 -9
  134. package/skills/sdlc-spec/SKILL.md +0 -9
  135. package/skills/usage-report/SKILL.md +0 -10
  136. /package/{ai/workflows/refactoring.md → skills/project-update/history/blobs/36cb593293496fbcf38df828a9b9b2bc0d5a53333f584a5319ebc3d799016e24} +0 -0
  137. /package/{ai/workflows/feature.md → skills/project-update/history/blobs/56e16072c2f3edc6c8897c690d09a11d12fc414c3e3f361f359f7dc609a21282} +0 -0
  138. /package/{ai/workflows/hotfix.md → skills/project-update/history/blobs/8cbefbf1aa412bae3e5019acd40b8fe0598fceba6c781906b3bc6dbd014f6b23} +0 -0
  139. /package/{ai/workflows/bugfix.md → skills/project-update/history/blobs/af56dc16e44ae1d8c3dac4c3ca82e2163b719553c02ea455e77430bab9a14089} +0 -0
  140. /package/{ai/workflows/investigation.md → skills/project-update/history/blobs/b9e09cb24958cd6831589997558974bd6356305306e8f9685e226bcdc30d60ac} +0 -0
  141. /package/{ai/agents/manager.md → skills/project-update/history/blobs/d0cf6388f35a92a0cf607d33909278382f6d7b6a4c32e281b9f9e0ea652c7b91} +0 -0
@@ -5,7 +5,7 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "A weight-based engineering pipeline for Claude Code and Codex: each change is weighed on six axes, runs light, guarded or full, edits only the files its plan names, and ends at human approval — enforced by hooks, reviewed adversarially, routed to the cheap model tier by default.",
8
- "version": "3.2.1"
8
+ "version": "4.0.1"
9
9
  },
10
10
  "plugins": [
11
11
  {
@@ -14,7 +14,7 @@
14
14
  "source": "url",
15
15
  "url": "https://github.com/vanssata/claude-agentic-sdlc-module.git"
16
16
  },
17
- "version": "3.2.1",
17
+ "version": "4.0.1",
18
18
  "strict": true
19
19
  }
20
20
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "riskrails",
3
- "version": "3.2.1",
3
+ "version": "4.0.1",
4
4
  "description": "A weight-based engineering pipeline for Claude Code and Codex: each change is weighed on six axes, runs light, guarded or full, edits only the files its plan names, and ends at human approval — enforced by hooks, reviewed adversarially, routed to the cheap model tier by default.",
5
5
  "author": {
6
6
  "name": "Ivan Kakurov"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "riskrails",
3
- "version": "3.2.1",
3
+ "version": "4.0.1",
4
4
  "description": "A weight-based engineering pipeline for Claude Code and Codex: each change is weighed on six axes, runs light, guarded or full, edits only the files its plan names, and ends at human approval — enforced by hooks, reviewed adversarially, routed to the cheap model tier by default.",
5
5
  "author": {
6
6
  "name": "Ivan Kakurov"
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RiskRails
2
2
 
3
- [![Version](https://img.shields.io/badge/version-3.2.1-d2f878?labelColor=101210)](https://github.com/vanssata/claude-agentic-sdlc-module/releases/tag/v3.2.1)
3
+ [![Version](https://img.shields.io/badge/version-4.0.1-d2f878?labelColor=101210)](https://github.com/vanssata/claude-agentic-sdlc-module/releases/tag/v4.0.1)
4
4
  [![Runtimes](https://img.shields.io/badge/runtimes-Claude%20Code%20%7C%20Codex-d2f878?labelColor=101210)](docs/routing.md)
5
5
  [![Known risks](https://img.shields.io/badge/known%20risks-documented-d2f878?labelColor=101210)](docs/known-risks.md)
6
6
  [![License: MIT](https://img.shields.io/badge/license-MIT-d2f878?labelColor=101210)](LICENSE)
@@ -18,7 +18,7 @@ approval. Risky actions are stopped by a hook, not by a polite request in a
18
18
  prompt.
19
19
 
20
20
  ```bash
21
- npx riskrails@3.2.1 # detects Claude Code, Codex or both (Node 18+, Python 3.11+)
21
+ npx riskrails@4.0.1 # detects Claude Code, Codex or both (Node 18+, Python 3.11+)
22
22
  ```
23
23
 
24
24
  Then, in any project: `/rr-setup` once, and `/rr-build <what you want>` for
@@ -50,83 +50,47 @@ Tuned for **one developer who knows the codebase**, on a Claude Pro, Max or
50
50
  Team plan, or a ChatGPT Plus or Pro plan, following the
51
51
  [AI-native SDLC playbook](https://claude.com/blog/the-ai-native-sdlc-playbook).
52
52
 
53
- **Version 3.2.1.** The guards have limits: read [Known risks](docs/known-risks.md)
53
+ **Version 4.0.1.** The guards have limits: read [Known risks](docs/known-risks.md)
54
54
  before relying on them. What is decided but not built is in [ROADMAP.md](ROADMAP.md).
55
55
 
56
- ## Upgrade to 3.1
57
-
58
- From 3.0.x: update the home (`npx riskrails@3.2.1`, restart the runtime), then
59
- in each project `/rr-setup --update` (dry run first, then `--apply`). Schema 10
60
- becomes **11**: migration `0011` proposes deleting `.ai/policies/risk-tiers.json`
61
- and `risk-tiers.md`, which `weight.json` and `weight.md` replaced; confirm with
62
- `--apply --confirm-delete <name>` in a terminal of your own. The update now
63
- renders `weight.md` from `weight.json` instead of merging it, reads the
64
- `docs/sdlc/*/TEMPLATE.md` files from the plugin (an unedited project copy is
65
- offered for deletion), and proposes cleanup of old run logs and stale tasks.
66
- See [CHANGELOG.md](CHANGELOG.md).
67
-
68
- ## Upgrade to 3.0
69
-
70
- 3.0 renames the plugin from `claude-agentic` to `riskrails`, replaces the risk
71
- tiers with the weight and the three modes, replaces the `/ai-*` and `/sdlc-*`
72
- commands with `/rr-*`, ports the guards to one Python process, and moves the
73
- task state to `.ai/state/state.json`. The old names stay as aliases for this
74
- version. Step by step, in this order:
75
-
76
- 1. **Commit every project's `.ai/`** before anything else; the update tells you
77
- when the tree is dirty, and `git restore` is the rollback.
78
- 2. **Close or abandon tasks in flight.** A task started by 2.x is refused by
79
- the new commands as `old surface`; finish it with the version that started
80
- it, or drop it with `python3 ~/.claude/skills/ai-task/state.py close
81
- --abandon`. Check with `/rr-status`.
82
- 3. **Update the home** on every machine, for every runtime:
83
-
84
- ```bash
85
- npx riskrails@3.2.1 # or: npx -y riskrails@latest --yes
86
- ```
87
-
88
- It moves `<home>/claude-agentic/` to `<home>/riskrails/` and leaves a
89
- symlink at the old path for one version, replaces the old hook entries with
90
- `ai-guard.py` and `runtime-gate.py`, retires the old agents and shim files
91
- to `backups/<date>/`, and rewrites the managed block. Restart the runtime.
92
- In Codex, open `/hooks` and **trust the changed entries** — until you do,
93
- nothing is enforced. `--dry-run` shows all of it first.
94
- 4. **Update each project:**
95
-
96
- ```
97
- /rr-setup --update # dry run first; read it; then --apply
98
- ```
99
-
100
- Migrations `0007` to `0010` (and `0011`, see Upgrade to 3.1) run inside the dry run, in order, before the merge:
101
- `0007` creates `.ai/policies/weight.json`, carrying over the project's
102
- edits to its risk-tier table; `0008` renames the managed-block markers and
103
- the router's routes; `0009` moves `current.json` to `state.json`; `0010`
104
- creates `.ai/policies/dialog.json` with the dialog on. Edited markdown is
105
- three-way merged, JSON policies key by key with a confirmation per key;
106
- `delete?` proposals are left for you to confirm. The schema becomes 10 with a 3.0 plugin, 11 with 3.1.
107
- 5. **Decide two things the migrations cannot.** Keep the dialog (then amend
108
- constitution C5 as `0010` hints) or set `"enabled": false`; and tune the
109
- weight table — `domain.modules`, `customer_visible`, `hot_paths`,
110
- `needs_step`, `irreversible` — then `state.py weight --mirror`.
111
- 6. **Verify**: `/rr-status` shows schema 11 and no task in flight; a
112
- `/rr-build` on a small change runs light and closes on the two facts.
113
- Commit `.ai/`.
114
-
115
- Every machine of a team upgrades the plugin before a project at schema 11 is
116
- committed; an older plugin refuses such a project. Rollback and the full
117
- migration table are in [docs/project-update.md](docs/project-update.md); the
118
- home-side details in [docs/installation.md](docs/installation.md).
56
+ ## Upgrade to 4.0
57
+
58
+ 4.0 converts nothing any more: the one-version fallbacks, the migrations and
59
+ the adopt command are gone, and `/rr-setup --update` regenerates a project's files from
60
+ the plugin. Step by step, in this order:
61
+
62
+ 1. **Come from 3.1.0 or later.** 4.0 refuses a tree that still holds an old
63
+ shape it detects, naming the file, and regenerates any other older tree
64
+ without the conversions it missed. So a project last updated by an older
65
+ riskrails goes through the version that still converts it: install it
66
+ (`npx riskrails@3.1.0`), run `/rr-setup --update` with it, then install 4.0.
67
+ 2. **Commit every project's `.ai/`** first; `git restore` is the rollback.
68
+ 3. **Update the home** on every machine, for every runtime: `npx riskrails@4.0.1`
69
+ (the plugin route and the npm route are separate installs: reinstall both
70
+ if you use both). Restart the runtime. In Codex, open `/hooks` and trust the
71
+ changed entries.
72
+ 4. **Run `/rr-setup --update` in each project right away.** Until you do, the
73
+ project's old shapes are not read: the weight lacks its `domain.modules`, no
74
+ `verify_command` is found, and a task in the old state file is not scope-guarded.
75
+ Dry run first, then `--apply`; a `regenerate?` or `delete?` row is confirmed
76
+ by you in a terminal of your own.
77
+ 5. **Check**: `/rr-status` shows schema 12 and no task in flight.
78
+
79
+ The alias commands (the `/ai-*`, `/sdlc-*`, `/project-*` and usage-report names)
80
+ are removed; use the `/rr-*` commands. Details are in
81
+ [docs/project-update.md](docs/project-update.md), the home-side ones in
82
+ [docs/installation.md](docs/installation.md).
119
83
 
120
84
  ## Install
121
85
 
122
86
  ```bash
123
- npx riskrails@3.2.1 # detects Claude Code, Codex, or both; proposes the detected plan
124
- npx riskrails@3.2.1 --target codex # auto | claude | codex | both
125
- npx riskrails@3.2.1 --plan max --fable no # pro | team-pro | team-max | max | max20 | balanced-max
126
- npx riskrails@3.2.1 --codex-plan plus # plus | pro | balanced-max
127
- npx riskrails@3.2.1 --context economy # the plan's compaction window; the context guard also blocks
128
- npx riskrails@3.2.1 --statusline own # keep your own statusline command (from 3.2.1; default: the plugin's two-line statusline)
129
- npx riskrails@3.2.1 --dry-run # print what would be written, write nothing
87
+ npx riskrails@4.0.1 # detects Claude Code, Codex, or both; proposes the detected plan
88
+ npx riskrails@4.0.1 --target codex # auto | claude | codex | both
89
+ npx riskrails@4.0.1 --plan max --fable no # pro | team-pro | team-max | max | max20 | balanced-max
90
+ npx riskrails@4.0.1 --codex-plan plus # plus | pro | balanced-max
91
+ npx riskrails@4.0.1 --context economy # the plan's compaction window; the context guard also blocks
92
+ npx riskrails@4.0.1 --statusline own # keep your own statusline command (from 3.2.1; default: the plugin's two-line statusline)
93
+ npx riskrails@4.0.1 --dry-run # print what would be written, write nothing
130
94
  npx -y riskrails@latest --yes # update in place, keeping the recorded plan
131
95
  ```
132
96
 
@@ -145,7 +109,6 @@ The same commands in both runtimes:
145
109
  | You want to | Run |
146
110
  |---|---|
147
111
  | set up `.ai/` in a project, or bring it up to the installed plugin | `/rr-setup`, `/rr-setup --update` |
148
- | move another AI tool's files, or the project's own toolbox, into this layout | `/rr-setup --adopt` |
149
112
  | score the repository against the twelve plays | `/rr-setup --audit` |
150
113
  | turn an idea into intent, requirements and design | `/rr-spec <idea>` |
151
114
  | plan a spec into tasks, or one task into a mode and a start | `/rr-plan <spec or task>` |
@@ -155,10 +118,6 @@ The same commands in both runtimes:
155
118
  | close the task, get the human's approval | `/rr-ship` |
156
119
  | see where the task stands, or what it cost | `/rr-status`, `/rr-status --cost` |
157
120
 
158
- The old names — `/ai-init`, `/ai-task`, `/ai-status`, `/ai-audit`,
159
- `/project-init`, `/project-update`, `/sdlc-intent`, `/sdlc-spec`,
160
- `/sdlc-plan`, `/usage-report` — are aliases for one version.
161
-
162
121
  ### Three modes
163
122
 
164
123
  `state.py weight` scores six axes 0–2 — scope, behaviour, reversibility,
@@ -265,7 +224,6 @@ to do: [docs/known-risks.md](docs/known-risks.md).
265
224
  | Codex facts are observed, not guaranteed | grep the journals for `missed_reroute` after a Codex upgrade |
266
225
  | The dialog switch is read in two places | when the dialog and the terminal disagree, use the terminal |
267
226
  | Budgets and quota are advice, not limits | read the quota with its `stale` field |
268
- | `--adopt` edge cases fail safe, not smoothly | adopt on a committed tree, keep `original/` |
269
227
  | The usage report's parse cache trusts mtime and size | `--no-cache` when a number surprises you |
270
228
 
271
229
  ## Tests
@@ -276,15 +234,14 @@ python3 -I -m unittest discover -s tests -p 'test_*.py' # CI's serial oracl
276
234
  AI_E2E=1 python3 -I -m unittest discover -s tests -p test_end_to_end.py
277
235
  ```
278
236
 
279
- Fifty-nine suites, 1045 tests, about 75 seconds in parallel. The guards against JSON fixtures for both runtimes and a
237
+ Fifty-eight suites, 1133 tests, about 75 seconds in parallel. The guards against JSON fixtures for both runtimes and a
280
238
  golden of 1 341 recorded decisions, byte for byte, with timed cases that hold
281
239
  the hot path under its budget; the state machine, the weight, the batch loop,
282
240
  the dialog contract and the documents rule; the compact record and its
283
241
  pre-push validator; the installer for every plan and `--target`, the Codex
284
242
  agent renderer and the `config.toml` merge against a fixture full of
285
243
  third-party settings; `/rr-setup --update` against projects scaffolded from
286
- the oldest shipped templates and edited by hand; `--adopt` against Spec Kit,
287
- Kiro and Cursor fixtures; and an end-to-end run that installs both runtimes
244
+ the oldest shipped templates and edited by hand; and an end-to-end run that installs both runtimes
288
245
  into scratch directories, drives one task through the guards from Claude and
289
246
  then from Codex, and proves both see the same state. No suite reads or writes
290
247
  the developer's real `~/.claude` or `~/.codex`.
@@ -295,7 +252,7 @@ the developer's real `~/.claude` or `~/.codex`.
295
252
  |---|---|
296
253
  | [docs/getting-started.md](docs/getting-started.md) | the first hour: install, `/rr-setup`, a light and a full task, a batch build, the update, the bill |
297
254
  | [docs/installation.md](docs/installation.md) | every installer option, what it installs per runtime, what loads on every turn, the limits it sets, the 2.x home-side upgrade |
298
- | [docs/project-update.md](docs/project-update.md) | shared versus project-owned files, how a file is updated, the migrations and their rollback, `--adopt` |
255
+ | [docs/project-update.md](docs/project-update.md) | shared versus project-owned files, how a file is regenerated, what is kept, the rollback |
299
256
  | [docs/architecture.md](docs/architecture.md) | how the pieces fit: the installed home, `.ai/`, the pipeline, the state, the hooks, the two adapters |
300
257
  | [docs/weight.md](docs/weight.md) | the six axes, the three modes, what is measured and what is declared, tuning the table |
301
258
  | [docs/workflows.md](docs/workflows.md) | feature, bugfix, refactoring, hotfix, investigation |
@@ -54,7 +54,7 @@ in light and guarded, about 80 in full, then FINDINGS and VERDICT, with
54
54
 
55
55
  ## Boundary
56
56
 
57
- The brief names the task's mode; `.ai/state/state.json` (or the legacy `current.json`) has it otherwise. In
57
+ The brief names the task's mode; `.ai/state/state.json` has it otherwise. In
58
58
  light and guarded mode your inputs are the task goal, the diff, the tests the
59
59
  step names, and the project's own fixture corpus and threat model:
60
60
  `.ai/policies/safety.md`, the guards' `*-defaults.json`, the test fixtures.
@@ -8,7 +8,6 @@ the steps; `policies/` holds the rules; this says which to open.
8
8
  | You want to | Run |
9
9
  |---|---|
10
10
  | set up `.ai/` in a project, or bring it up to the installed plugin | `/rr-setup`, `/rr-setup --update` |
11
- | move another AI tool's files into this layout | `/rr-setup --adopt` |
12
11
  | score the repository against the twelve plays | `/rr-setup --audit` |
13
12
  | turn an idea into intent, requirements and design | `/rr-spec <idea>` |
14
13
  | plan a spec into tasks, or one task into a mode and a start | `/rr-plan <spec or task>` |
@@ -18,8 +17,6 @@ the steps; `policies/` holds the rules; this says which to open.
18
17
  | close the task, get the human's approval | `/rr-ship` |
19
18
  | see where the task stands, or what it cost | `/rr-status`, `/rr-status --cost` |
20
19
 
21
- The old names (`/ai-task`, `/ai-init`, `/sdlc-spec` …) stay one version as aliases.
22
-
23
20
  ## Three modes
24
21
 
25
22
  `state.py weight` scores six axes 0–2 — scope, behaviour, reversibility, domain,
package/bin/riskrails.js CHANGED
@@ -152,7 +152,6 @@ const exists = (p) => fs.existsSync(p); // follows symlink
152
152
  const isDir = (p) => { try { return fs.statSync(p).isDirectory(); } catch (e) { return false; } };
153
153
  const isFile = (p) => { try { return fs.statSync(p).isFile(); } catch (e) { return false; } };
154
154
  const isLink = (p) => { try { return fs.lstatSync(p).isSymbolicLink(); } catch (e) { return false; } };
155
- const lexists = (p) => { try { fs.lstatSync(p); return true; } catch (e) { return false; } };
156
155
  const read = (p) => fs.readFileSync(p, 'utf8');
157
156
  const readJSON = (p) => JSON.parse(read(p));
158
157
  const pretty = (v) => JSON.stringify(v, null, 2);
@@ -311,7 +310,7 @@ function renderStub(scope, runtime, dst, vars, kind = 'block') {
311
310
  // block_size — what the always-loaded block costs, and how much of the file is the user's own.
312
311
  function blockSize(file, budget) {
313
312
  const text = read(file);
314
- const m = text.match(/<!-- (riskrails|claude-agentic|[Cc]odex-agentic):start -->[\s\S]*?<!-- \1:end -->/);
313
+ const m = text.match(/<!-- riskrails:start -->[\s\S]*?<!-- riskrails:end -->/);
315
314
  const block = m ? Buffer.byteLength(m[0]) : 0;
316
315
  out(`${path.basename(file)}: managed block ${spaced(block)} B (budget ${spaced(budget)}), file ${spaced(Buffer.byteLength(text))} B — the rest is yours`);
317
316
  }
@@ -358,12 +357,10 @@ function writeProfile(home, profile) {
358
357
  }
359
358
 
360
359
  function prevPlan(home) {
361
- for (const name of ['riskrails', 'claude-agentic']) { // before 3.4b it lived under claude-agentic/ (R35)
362
- try {
363
- const plan = readJSON(path.join(home, name, 'profile.json')).plan;
364
- return plan === null || plan === undefined || plan === false ? '' : String(plan);
365
- } catch (e) { /* next */ }
366
- }
360
+ try {
361
+ const plan = readJSON(path.join(home, 'riskrails', 'profile.json')).plan;
362
+ return plan === null || plan === undefined || plan === false ? '' : String(plan);
363
+ } catch (e) { /* none */ }
367
364
  return '';
368
365
  }
369
366
 
@@ -748,15 +745,13 @@ function claudeDryRun() {
748
745
  if (C.TIER === 'max') out(` bin: claude-1m (opus[1m]${FABLE === 'yes' ? ' / fable[1m]' : ''}, pins the model at launch; compacts near ${C.ONE_M_AT})`);
749
746
  const plugin = claudePlugin(CLAUDE_DIR);
750
747
  skillsLine(plugin);
751
- out(' retire: skills/status (now skills/rr-status), into backups/<date>/ if present');
748
+ out(' retire: skills/{status,ai-status,sdlc-intent,sdlc-plan,sdlc-spec}, into backups/<date>/ if present');
752
749
  shimLine('settings.json');
753
750
  pluginLine(plugin, true);
754
- homeLine(CLAUDE_DIR);
755
751
  sharedLine();
756
752
  out(' config: ai-git-guard.json (only if absent)');
757
753
  out(' routing: riskrails/routing.md');
758
754
  out(' profile: riskrails/profile.json');
759
- out('== would migrate: the claude-routing managed block, if present, into this one');
760
755
  }
761
756
 
762
757
  // Every backup goes to one dated directory, <root>/backups/<date>/<path>: a backup beside
@@ -780,18 +775,6 @@ function retire(root, rel) { // move what nothing installs
780
775
  out(`retired: ${rel} -> backups/${BACKUP_DATE}/${rel}`);
781
776
  }
782
777
 
783
- // move_home — R35: the install home was <root>/claude-agentic/ before 3.4b. It moves to
784
- // <root>/riskrails/ and the old path becomes a symlink to it for one version. A real old
785
- // home beside an existing new one (or a link there, dangling or not) is retired.
786
- function moveHome(root) {
787
- const old = path.join(root, 'claude-agentic'), nw = path.join(root, 'riskrails');
788
- if (!isDir(old) || isLink(old)) return;
789
- if (lexists(nw)) retire(root, 'claude-agentic');
790
- else { fs.renameSync(old, nw); out('moved: claude-agentic/ -> riskrails/'); }
791
- fs.symlinkSync('riskrails', old);
792
- out('linked: claude-agentic -> riskrails (for one version)');
793
- }
794
-
795
778
  // sweep_bak — every *.bak an older installer left beside a live file moves into
796
779
  // backups/<date>/, keeping its path. Only the directories and root files this installer writes.
797
780
  function sweepBak(root, ...names) {
@@ -808,6 +791,8 @@ function sweepBak(root, ...names) {
808
791
  }
809
792
  }
810
793
 
794
+ const RETIRED_SKILLS = ['status', 'ai-status', 'sdlc-intent', 'sdlc-plan', 'sdlc-spec'];
795
+
811
796
  // The seven agents the 2026-09-02 install shipped, and the nine redesign 2.4 removed (with
812
797
  // the Codex -strong/-balanced twins). Moved, not deleted: one mv out of backups/ restores one.
813
798
  const STALE_AGENTS = ['code-implementer', 'qa-runner', 'qa-fixer', 'db-migrator', 'doc-lookup', 'log-inspector',
@@ -831,8 +816,8 @@ function installFile(src, dst, root = CLAUDE_DIR) { // back up on a real change
831
816
  // their scripts (state.py, ai-path, ...) through $AI_HOME/skills/ as on the npx route.
832
817
  function installSkills(root, plugin) {
833
818
  const backups = path.join(root, 'backups', BACKUP_DATE, 'skills');
834
- // /status became /rr-status (redesign 2.3); a leftover would load as a second status command.
835
- retire(root, 'skills/status');
819
+ // /status became /rr-status (2.3) and the ai-status and sdlc-* aliases ended in 4.0: a leftover would load as a second command.
820
+ for (const n of RETIRED_SKILLS) retire(root, `skills/${n}`);
836
821
  for (const name of ls(path.join(SRC, 'skills')).filter((n) => isDir(path.join(SRC, 'skills', n)))) {
837
822
  const d = path.join(SRC, 'skills', name), dst = path.join(root, 'skills', name);
838
823
  // A developer who ran the scripts in place leaves __pycache__ behind; it is not copied.
@@ -879,43 +864,15 @@ function installShared(root) {
879
864
  installFile(path.join(SRC, 'scripts/resolve-profile.py'), path.join(home, 'scripts/resolve-profile.py'), root);
880
865
  }
881
866
 
882
- function homeLine(root) {
883
- const old = path.join(root, 'claude-agentic');
884
- if (isDir(old) && !isLink(old)) out(' home: claude-agentic/ -> riskrails/, the old path a symlink for one version');
885
- }
886
867
  const sharedLine = () => out(` shared: riskrails/ai (${countFiles(path.join(SRC, 'ai'))} files), riskrails/ai-path`);
887
868
 
888
- // managed_block — replace the one managed block, or append it; migrates the predecessor
889
- // plugin's block and an unmarked legacy section on the way. Backs up a non-empty target first.
869
+ // managed_block — replace the one managed block, or append it. Backs up a non-empty target first.
890
870
  function managedBlock(target, blockFile, label) {
891
871
  if (!exists(target)) fs.writeFileSync(target, '');
892
872
  if (fs.statSync(target).size > 0) backupFile(target, path.dirname(target));
893
873
  const block = read(blockFile).replace(/^\n+|\n+$/g, '');
894
874
  let text = read(target);
895
875
  const start = '<!-- riskrails:start -->', end = '<!-- riskrails:end -->';
896
- const notes = [];
897
- const routing = text.match(/<!-- claude-routing:start -->[\s\S]*?<!-- claude-routing:end -->\n?/);
898
- if (routing) {
899
- text = text.slice(0, routing.index) + text.slice(routing.index + routing[0].length);
900
- notes.push('migrated the claude-routing block');
901
- }
902
- const legacy = text.match(/^# Model allocation by task and scope[\s\S]*?(?=^# |(?![\s\S]))/m);
903
- if (legacy && !text.slice(0, legacy.index).includes(start)) {
904
- text = text.slice(0, legacy.index) + text.slice(legacy.index + legacy[0].length);
905
- notes.push("migrated an unmarked 'Model allocation' section");
906
- }
907
- // A legacy claude-agentic (before 3.4b) or Codex-agentic pair is the managed block under its
908
- // old name: rename it, never append beside it.
909
- if (!text.includes(start) && !text.includes(end)) {
910
- const pair = text.match(/<!-- (claude-agentic|[Cc]odex-agentic):start -->[\s\S]*?<!-- \1:end -->/);
911
- if (pair) {
912
- const name = pair[1];
913
- text = text.slice(0, pair.index)
914
- + pair[0].replace(`<!-- ${name}:start -->`, start).replace(`<!-- ${name}:end -->`, end)
915
- + text.slice(pair.index + pair[0].length);
916
- notes.push(`renamed the legacy ${name} markers`);
917
- }
918
- }
919
876
  let nw, action;
920
877
  if (text.includes(start) && text.includes(end)) {
921
878
  const esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -928,7 +885,7 @@ function managedBlock(target, blockFile, label) {
928
885
  }
929
886
  nw = nw.replace(/\n{4,}/g, '\n\n\n');
930
887
  fs.writeFileSync(target, nw);
931
- out(`${label}: ${action}${notes.length ? ' + ' + notes.join(' + ') : ''}`);
888
+ out(`${label}: ${action}`);
932
889
  }
933
890
 
934
891
  // The three shell guards 3.5 retired: ai-guard.py runs all of them in one process. Their
@@ -1114,7 +1071,6 @@ const loadJSONFile = (file) => JSON.parse(read(file));
1114
1071
  const writeJSONFile = (file, doc) => { fs.writeFileSync(file + '.tmp', pretty(doc) + '\n'); fs.renameSync(file + '.tmp', file); };
1115
1072
 
1116
1073
  function claudeApply() {
1117
- moveHome(CLAUDE_DIR);
1118
1074
  for (const d of ['agents', 'hooks/lib', 'hooks/guard', 'skills']) mkdirp(path.join(CLAUDE_DIR, d));
1119
1075
  sweepBak(CLAUDE_DIR, 'settings.json', 'CLAUDE.md');
1120
1076
 
@@ -1390,10 +1346,9 @@ function codexDryRun() {
1390
1346
  out(` hooks: ${codexHookFiles().map((f) => path.basename(f)).join(',')}`);
1391
1347
  const plugin = codexPlugin(CODEX_DIR);
1392
1348
  skillsLine(plugin);
1393
- out(' retire: skills/status (now skills/rr-status), into backups/<date>/ if present');
1349
+ out(' retire: skills/{status,ai-status,sdlc-intent,sdlc-plan,sdlc-spec}, into backups/<date>/ if present');
1394
1350
  shimLine('hooks.json');
1395
1351
  pluginLine(plugin, true);
1396
- homeLine(CODEX_DIR);
1397
1352
  sharedLine();
1398
1353
  out(' config: ai-git-guard.json (only if absent)');
1399
1354
  out(' routing: riskrails/routing.md');
@@ -1404,7 +1359,6 @@ function codexDryRun() {
1404
1359
  }
1405
1360
 
1406
1361
  function codexApply() {
1407
- moveHome(CODEX_DIR);
1408
1362
  for (const d of ['agents', 'hooks/lib', 'hooks/guard', 'skills']) mkdirp(path.join(CODEX_DIR, d));
1409
1363
  sweepBak(CODEX_DIR, 'hooks.json', 'config.toml', 'AGENTS.md');
1410
1364
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "_comment": "Shipped defaults for ai-path-guard. Do not edit this file; a project overrides it in .ai/policies/path-guard.json (patterns are unioned, allow wins over every other list). Patterns are POSIX extended regular expressions matched against the absolute path. deny_patterns are secrets: refused for read and write. protected_config_patterns are always on and refuse writes: the task's state and journal, task.md, the compact record (.ai/memory/, .ai/local/memory/), and the guards' own configuration, engine and state.py under .claude/ or .codex/, in a project or in the user's home, and the riskrails plugin's cache folder, which carries the same code on the plugin route. Also the installer's statusline record (.claude/riskrails/statusline.json), which keeps the statusline command it replaced. A project's dependency_instruction_patterns, from before 3.4, are read as deny_patterns. task_protected_patterns are on only while a task is in flight (.ai/state/state.json, or else current.json, exists and has not reached \"done\"): the runtime's settings, Claude's record of installed plugins and the pipeline's policies, so a run cannot change the rules it is being judged by. Reading anything but a secret is allowed.",
2
+ "_comment": "Shipped defaults for ai-path-guard. Do not edit this file; a project overrides it in .ai/policies/path-guard.json (patterns are unioned, allow wins over every other list). Patterns are POSIX extended regular expressions matched against the absolute path. deny_patterns are secrets: refused for read and write. protected_config_patterns are always on and refuse writes: the task's state and journal, task.md, the compact record (.ai/memory/, .ai/local/memory/), and the guards' own configuration, engine and state.py under .claude/ or .codex/, in a project or in the user's home, and the riskrails plugin's cache folder, which carries the same code on the plugin route. Also the installer's statusline record (.claude/riskrails/statusline.json), which keeps the statusline command it replaced. task_protected_patterns are on only while a task is in flight (.ai/state/state.json, or else current.json, exists and has not reached \"done\"): the runtime's settings, Claude's record of installed plugins and the pipeline's policies, so a run cannot change the rules it is being judged by. Reading anything but a secret is allowed.",
3
3
  "deny_patterns": [
4
4
  "(^|/)\\.env$",
5
5
  "(^|/)\\.env\\.(local|prod|production|staging|live)$",
@@ -284,7 +284,7 @@ def prompt_text(message):
284
284
  text = REMINDER.sub("", content).strip()
285
285
  # only a wrapper at the very start is a slash command: a prompt may quote these tags
286
286
  command = COMMAND.search(text) if text.startswith(("<command-name>", "<command-message>")) else None
287
- if command: # "/ai-task fix the export" is an instruction; a bare "/model" is not
287
+ if command: # "/rr-build fix the export" is an instruction; a bare "/model" is not
288
288
  name, args = command.group(1).strip(), (COMMAND_ARGS.search(text) or [None, ""])[1].strip()
289
289
  return f"{name} {args}" if args else None
290
290
  # local command output, caveats, interruptions
@@ -360,7 +360,7 @@ def ai_root(cwd):
360
360
  """The project the session is in, or None.
361
361
 
362
362
  The walk stops at the repository it starts in, and never leaves $HOME. An
363
- unbounded walk would let one `/ai-init` in a home directory adopt every
363
+ unbounded walk would let one `/rr-setup` in a home directory adopt every
364
364
  session on the machine: a nested, unrelated checkout would have its prompts
365
365
  recorded into the ancestor's session.json and be handed the ancestor's
366
366
  handoff at startup. cwd falls back to the process's own, which is where the
@@ -390,8 +390,6 @@ def task_in_flight(root):
390
390
  if not root:
391
391
  return False
392
392
  state = os.path.join(root, ".ai", "state", "state.json")
393
- if not os.path.isfile(state):
394
- state = os.path.join(root, ".ai", "state", "current.json") # R34: legacy name, one version
395
393
  try:
396
394
  with open(state, encoding="utf-8") as fh:
397
395
  return (json.load(fh) or {}).get("current_stage") != "done"
@@ -672,9 +672,8 @@ class PathGuard: # pylint: disable=too-many-instance-
672
672
  # -------------------------------------------------------------- the task
673
673
 
674
674
  def _state_file(self):
675
- """R34: state.json, or the legacy current.json for one version."""
676
- new = self.root + "/.ai/state/state.json"
677
- return new if is_file(new) else self.root + "/.ai/state/current.json"
675
+ """The task's state file."""
676
+ return self.root + "/.ai/state/state.json"
678
677
 
679
678
  def _task_line(self):
680
679
  loaded = load_json_file(self._state_file())
@@ -720,9 +719,7 @@ class PathGuard: # pylint: disable=too-many-instance-
720
719
  if doc is not None and not isinstance(doc, dict):
721
720
  continue
722
721
  for tag, key in (("d", "deny_patterns"), ("a", "allow_patterns"),
723
- ("p", "protected_config_patterns"), ("k", "task_protected_patterns"),
724
- # A project's list from before 3.4 keeps its read and write deny.
725
- ("d", "dependency_instruction_patterns")):
722
+ ("p", "protected_config_patterns"), ("k", "task_protected_patterns")):
726
723
  v = doc.get(key) if doc else None
727
724
  for item in jq_iter(v if v is not None and v is not False else []):
728
725
  if is_jq_string(item) and item != "":
@@ -3,7 +3,7 @@ MultiEdit, NotebookEdit and Codex's apply_patch.
3
3
 
4
4
  During the implementation stage the approved plan names the files a step may
5
5
  touch; an edit outside them is refused with SCOPE_CHANGE_REQUIRED. Inert unless
6
- .ai/state/state.json (or, for one version, the legacy current.json) exists and
6
+ .ai/state/state.json exists and
7
7
  its stage is "implementation".
8
8
 
9
9
  Bash semantics kept: a plan glob is matched as `[[ $rel == $pattern ]]` — "*"
@@ -334,8 +334,6 @@ def check(ctx):
334
334
  if root is None:
335
335
  return
336
336
  state = root + "/.ai/state/state.json"
337
- if not is_file(state):
338
- state = root + "/.ai/state/current.json"
339
337
  if not is_file(state):
340
338
  return
341
339
  step_id, task_id, allowed, forbidden, reason = read_state(state)