nobrainer-tech-flow 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/AGENTS.md +1 -0
  5. package/CLAUDE.md +1 -0
  6. package/README.md +9 -6
  7. package/assets/nobrainer-tech-logo.svg +1 -1
  8. package/assets/plugin-logo.png +0 -0
  9. package/docs/INSTALL.md +9 -6
  10. package/docs/MIGRATION_TO_FLOW.md +14 -0
  11. package/docs/RELEASING.md +24 -0
  12. package/docs/SKILL_CURATION.md +8 -2
  13. package/docs/releases/v2.4.1.md +63 -0
  14. package/docs/releases/v2.5.0.md +190 -0
  15. package/gemini-extension.json +1 -1
  16. package/package.json +1 -1
  17. package/plugin.json +1 -1
  18. package/scripts/install.py +13 -6
  19. package/scripts/install.sh +137 -16
  20. package/scripts/install_skills.py +34 -5
  21. package/scripts/recommend_flow_setup.py +126 -21
  22. package/scripts/validate_skills.py +2 -1
  23. package/skills/nobrainer-context/SKILL.md +113 -0
  24. package/skills/nobrainer-context/references/clients.md +115 -0
  25. package/skills/nobrainer-context/references/consolidate.md +66 -0
  26. package/skills/nobrainer-context/scripts/context_inventory.py +425 -0
  27. package/skills/nobrainer-skill-doctor/SKILL.md +4 -4
  28. package/skills/nobrainer-tech-flow/VERSION +1 -1
  29. package/skills/nobrainer-tech-flow/references/optional-decisions.md +5 -3
  30. package/skills/nobrainer-tech-flow/references/routing.md +1 -1
  31. package/skills/nobrainer-tech-flow/scripts/typed_decisions.py +20 -9
  32. package/skills/nobrainer-codex-context/SKILL.md +0 -111
  33. /package/skills/{nobrainer-codex-context → nobrainer-context}/scripts/codex_context.py +0 -0
@@ -8,7 +8,7 @@
8
8
  {
9
9
  "name": "nobrainer-tech-flow",
10
10
  "description": "From task to done. nobrainer-tech-flow is one workflow of 18 modules for AI coding agents: it scopes the task, delegates ready work, checks the result and hands over the evidence, including what was not checked.",
11
- "version": "2.4.0",
11
+ "version": "2.5.0",
12
12
  "source": "./",
13
13
  "author": {
14
14
  "name": "NoBrainer Tech"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nobrainer-tech-flow",
3
3
  "description": "From task to done. nobrainer-tech-flow is one workflow of 18 modules for AI coding agents: it scopes the task, delegates ready work, checks the result and hands over the evidence, including what was not checked.",
4
- "version": "2.4.0",
4
+ "version": "2.5.0",
5
5
  "author": {
6
6
  "name": "NoBrainer Tech"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nobrainer-tech-flow",
3
3
  "description": "From task to done. nobrainer-tech-flow is one workflow of 18 modules for AI coding agents: it scopes the task, delegates ready work, checks the result and hands over the evidence, including what was not checked.",
4
- "version": "2.4.0",
4
+ "version": "2.5.0",
5
5
  "author": {
6
6
  "name": "NoBrainer Tech",
7
7
  "url": "https://nobrainer.tech"
package/AGENTS.md CHANGED
@@ -23,6 +23,7 @@ Respect host hierarchy; user instructions override skill guidelines. Apply [deli
23
23
  - `tests/` — deterministic and behavioral regression gates.
24
24
  - `docs/COMPATIBILITY.md` and `docs/TESTING.md` — proof boundaries.
25
25
  - `docs/SKILL_CURATION.md` — admission, ownership and retirement decisions.
26
+ - `docs/RELEASING.md`: releases.
26
27
 
27
28
  ## Portable skill contract
28
29
 
package/CLAUDE.md CHANGED
@@ -23,6 +23,7 @@ Respect host hierarchy; user instructions override skill guidelines. Apply [deli
23
23
  - `tests/` — deterministic and behavioral regression gates.
24
24
  - `docs/COMPATIBILITY.md` and `docs/TESTING.md` — proof boundaries.
25
25
  - `docs/SKILL_CURATION.md` — admission, ownership and retirement decisions.
26
+ - `docs/RELEASING.md`: releases.
26
27
 
27
28
  ## Portable skill contract
28
29
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center">
2
2
  <a href="https://nobrainer.tech">
3
- <img src="assets/nobrainer-tech-logo.svg" width="96" alt="nobrainer-tech-flow monogram">
3
+ <img src="assets/nobrainer-tech-logo.svg" width="96" alt="NoBrainer Tech logo">
4
4
  </a>
5
5
  </p>
6
6
 
@@ -423,7 +423,7 @@ recurring boundary:
423
423
  |---|---|---|
424
424
  | [`nobrainer-tech-flow`](skills/nobrainer-tech-flow/) | `NBFlow`, `NBF` | Technical entrypoint for end-to-end setup and delivery: one requirements gate, concise progress, bounded execution, recovery, audit and learning |
425
425
  | [`nobrainer-auto-fine-tune`](skills/nobrainer-auto-fine-tune/) | `nb-auto-fine-tune` | Read-only capability audit and route calibration: verified host models, effort, context and useful parallelism while MAIN keeps the owner's model |
426
- | [`nobrainer-codex-context`](skills/nobrainer-codex-context/) | `nb-codex-context` | Project-local Codex context setup: instruction discovery, fallback and byte-budget audit, safe context block reconciliation and runtime readback |
426
+ | [`nobrainer-context`](skills/nobrainer-context/) | `nb-context` | One set of project instructions for every coding agent: what Codex, Claude Code, Gemini CLI, Cursor, Copilot and OpenCode load, size limits, duplicates and contradictions, one source of truth with pointers after approval, and readback |
427
427
  | [`nobrainer-skill-doctor`](skills/nobrainer-skill-doctor/) | `nb-skill-doctor` | Cross-project audit of skills, project instructions and task prompts: trigger overlap, excessive process, coverage and minimal portfolio repair planning |
428
428
  | [`nobrainer-team`](skills/nobrainer-team/) | `nb-team` | Capability selection and bounded native assignments, installed-skill inventory and safe temporary specialist discovery |
429
429
  | [`nobrainer-dispatcher`](skills/nobrainer-dispatcher/) | `nb-dispatcher` | Dependency-aware ready-set scheduling, bounded dispatch, backpressure and audited result routing |
@@ -531,12 +531,15 @@ prove production. See [Compatibility](docs/COMPATIBILITY.md) for current proof
531
531
  and [Testing](docs/TESTING.md) for acceptance evidence.
532
532
 
533
533
 
534
- **What's new in 2.4.0:** nobrainer-tech-flow can ask before risky commands and
535
- shows whether its proof still matches your files. See [RELEASE-NOTES.md](RELEASE-NOTES.md).
534
+ **What's new in 2.5.0:** `nobrainer-context` (`nb-context`) keeps one set of project
535
+ instructions for every coding agent: it shows what Codex, Claude Code, Gemini CLI,
536
+ Cursor, Copilot and OpenCode load, and proposes one source of truth with pointers.
537
+ See [RELEASE-NOTES.md](RELEASE-NOTES.md).
536
538
 
537
- Current source version: **2.4.0**. Check the
539
+ Current source version: **2.5.0**. Check the
538
540
  [latest published GitHub release](https://github.com/nobrainer-tech/nobrainer-tech-flow/releases/latest)
539
- for distribution and the [2.4.0 verification record](docs/releases/v2.4.0.md) for
541
+ for distribution and the [2.5.0](docs/releases/v2.5.0.md) and
542
+ [2.4.0 verification records](docs/releases/v2.4.0.md) for
540
543
  the current scope, reproducible checks and client-runtime limits. The unchanged command runner keeps its
541
544
  [v1.7.0 verification scope](docs/releases/v1.7.0.md). Source publication does not
542
545
  imply client marketplace discovery or improved model reasoning. The earlier
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" role="img" aria-label="NBTF"><rect x="2" y="2" width="92" height="92" rx="22" fill="#2948B8"/><text x="18" y="43" fill="#fff" font-family="Arial,Helvetica,sans-serif" font-weight="800" font-size="31" letter-spacing="-2">NB</text><text x="18" y="76" fill="#fff" font-family="Arial,Helvetica,sans-serif" font-weight="800" font-size="31" letter-spacing="-2">TF</text><rect x="70" y="63" width="8" height="8" rx="1" fill="#FF9875"/></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M126 0H476A36 36 0 0 1 512 36V386A126 126 0 0 1 386 512H36A36 36 0 0 1 0 476V126A126 126 0 0 1 126 0Z" fill="#3B65F0"/><path d="M384 384H121A24 24 0 0 1 97 358A288 288 0 0 1 358 97A24 24 0 0 1 384 121Z" fill="#FFF7EC"/><rect x="240" y="240" width="104" height="104" fill="#F04A14"/></svg>
Binary file
package/docs/INSTALL.md CHANGED
@@ -14,9 +14,9 @@ upgraded merely because the new source is installed nearby.
14
14
  Node 18+ and Python 3.11+ are prerequisites. Preview the setup first:
15
15
 
16
16
  ```sh
17
- npx nobrainer-tech-flow@2.4.0 --client codex
18
- npx nobrainer-tech-flow@2.4.0 --client codex --apply
19
- npx nobrainer-tech-flow@2.4.0 --client codex --undo --apply
17
+ npx nobrainer-tech-flow@2.5.0 --client codex
18
+ npx nobrainer-tech-flow@2.5.0 --client codex --apply
19
+ npx nobrainer-tech-flow@2.5.0 --client codex --undo --apply
20
20
  ```
21
21
 
22
22
  Use claude for Claude Code, opencode or copilot for those clients. Add --home PATH
@@ -24,7 +24,7 @@ for an isolated profile. These commands become available once this version is
24
24
  published on npm; a source candidate is not registry availability.
25
25
 
26
26
  Application copies the release files into the chosen home directory's
27
- .nobrainer-tech-flow-npm/2.4.0 and verifies the copy. That folder sits beside
27
+ .nobrainer-tech-flow-npm/2.5.0 and verifies the copy. That folder sits beside
28
28
  ~/.nobrainer-tech-flow, where the Git installation suggests a clone, so cleaning
29
29
  the clone cannot delete the files the skill links point to. Releases before 2.3.2
30
30
  kept their copy in .nobrainer-tech-flow/npm; undo such a setup with the command of
@@ -213,8 +213,11 @@ shared folder.
213
213
  ## Conflict and migration behavior
214
214
 
215
215
  `install_skills.py` and `install.sh` never overwrite an unknown directory, file
216
- or symlink. A foreign target at the retired name `nobrainer-reddit` is reported as
217
- `PRESERVED_FOREIGN` and left unchanged without blocking installation. A foreign
216
+ or symlink. A foreign target at a retired name such as `nobrainer-reddit` is
217
+ reported as `PRESERVED_FOREIGN` and left unchanged without blocking installation.
218
+ An exact old link into this checkout at a retired name that a setup record lists
219
+ is removed by the next `install.sh` or `install.py` apply (see the
220
+ [migration guide](MIGRATION_TO_FLOW.md) for the 2.5.0 rename). A foreign
218
221
  target at a renamed alias such as `nb-flow`, a canonical name or an unresolved
219
222
  legacy name such as `nobrainer-fast-audit` still stops installation.
220
223
 
@@ -98,6 +98,20 @@ until migrated with `install_skills.py --migrate-legacy`. Foreign renamed aliase
98
98
  such as `nb-flow` and unresolved legacy names still block installation to prevent
99
99
  trigger conflicts.
100
100
 
101
+ In 2.5.0 the module `nobrainer-codex-context` (trigger `nb-codex-context`) became
102
+ `nobrainer-context` (trigger `nb-context`) and covers every coding agent's project
103
+ instructions, not only Codex. The old name and trigger no longer work. When the
104
+ setup record of a Git checkout (`install.sh` or `install.py`) lists the old link,
105
+ the next apply removes that exact link into this checkout and links
106
+ `nobrainer-context`; undo also removes it. The npm setup keeps each release in its
107
+ own folder, so undo an npm setup with the earlier release's command before
108
+ applying 2.5.0, as [INSTALL.md](INSTALL.md) describes. An old link without a record, for example one made by
109
+ `install_skills.py` directly, still blocks until migrated with
110
+ `install_skills.py --migrate-legacy`. A file, folder, copy or link at the old name
111
+ that is not this checkout's link is left unchanged (`PRESERVED_FOREIGN`); remove a
112
+ copy you made of the old module yourself. Plugin installs pick up the new name on
113
+ update.
114
+
101
115
  After an update, read back the source commit and package identity, restart the
102
116
  client and confirm that `nobrainer-tech-flow` loads once. A version change or an
103
117
  installed file alone does not establish runtime compatibility.
@@ -0,0 +1,24 @@
1
+ # Releasing nobrainer-tech-flow
2
+
3
+ This repository is the one product to promote: stars, issues and links point here.
4
+ Every channel below carries the same version from the same tag, and its links
5
+ (homepage, repository, support) lead back here. A stable release is finished only
6
+ when each channel reads back that version, or the gap is reported:
7
+
8
+ 1. GitHub release from the annotated `vX.Y.Z` tag, with
9
+ `nobrainer-tech-flow-X.Y.Z-plugin.zip` (`scripts/build_plugin.py`) and the
10
+ `npm pack` tarball built from the merge commit; download each asset and compare its
11
+ SHA-256 with the digest of that same file before upload.
12
+ 2. npm: run the `Publish npm` workflow from the tag, then read back
13
+ `npm view nobrainer-tech-flow version`.
14
+ 3. Claude Code and Codex marketplaces in this repository: they follow the default
15
+ branch, so install `nobrainer-tech-flow@nobrainer-tech` in a throwaway profile while
16
+ `main` still equals the tag, and read back the version and the installed commit.
17
+ 4. `nobrainer-tech/nobrainer-tech-flow-plugin`: export the release ZIP there
18
+ through a PR, update `SOURCE.json`, run its unmodified
19
+ `_maintainers/verify_release.py`, then release it. It is the hook-free copy that
20
+ the Claude directory tracks, not a second project to promote.
21
+ 5. Claude directory (claude.ai/directory/manage) picks up that repository's
22
+ default branch; OpenAI plugin directory (platform.openai.com/plugins) takes the
23
+ native ZIP upload. Both submissions and publication clicks are owner-gated.
24
+ 6. Changelog on https://nobrainer.tech/flow/changelog/ after owner preview.
@@ -41,14 +41,14 @@ Popularity, file size and prior existence are not admission criteria.
41
41
  | `nobrainer-decide` | One consequential decision after alternatives, scoring and adversarial attack. |
42
42
  | `nobrainer-rca` | Read-only causal diagnosis of an observed failure. |
43
43
  | `nobrainer-review` | Final acceptance/bug/release evidence gate and verified actionable findings. |
44
- | `nobrainer-codex-context` | Project-local Codex instruction discovery, byte-budget audit, safe context-block setup and runtime readback. |
44
+ | `nobrainer-context` | One project's instruction files for every coding agent: what each client loads, size limits, duplicates and contradictions, one approved source of truth with pointers, and readback. |
45
45
  | `nobrainer-skill-doctor` | Cross-project audit of skills, project instructions and task prompts, with coverage, overlap and minimal portfolio repair planning. |
46
46
 
47
47
  ## Boundaries that stay embedded
48
48
 
49
49
  Do not create separate permanent skills for:
50
50
 
51
- - planning, autopilot, general NoBrainer setup or correction capture: the Flow entry skill owns the lifecycle; Codex-specific project-context setup belongs to `nobrainer-codex-context`;
51
+ - planning, autopilot, general NoBrainer setup or correction capture: the Flow entry skill owns the lifecycle; one project's instruction files belong to `nobrainer-context`;
52
52
  - visible goal/TODO progress: Flow owns one canonical plan and its compact view;
53
53
  do not add a separate goal, todo or progress skill;
54
54
  - KISS, DRY, SOLID, YAGNI, simplification or test safety: Build owns them;
@@ -109,6 +109,12 @@ targets at that name with `PRESERVED_FOREIGN`. Only exact old links from this
109
109
  checkout remain migration candidates. Renamed/absorbed aliases retain blocking
110
110
  conflict checks.
111
111
 
112
+ `nobrainer-codex-context` is `RETIRED` in 2.5.0 by owner decision (2026-10-20): its
113
+ boundary grew into `nobrainer-context`, which covers every coding agent's project
114
+ instructions, and the old name keeps no alias or trigger. Foreign targets at the
115
+ old name are preserved like `nobrainer-reddit`; an exact old link that a setup
116
+ record lists is removed by the next setup apply or undo.
117
+
112
118
  ## Change control
113
119
 
114
120
  Any addition, merge or retirement updates together:
@@ -0,0 +1,63 @@
1
+ # nobrainer-tech-flow 2.4.1: undo after a rearranged profile
2
+
3
+ Release date: 2026-10-19.
4
+
5
+ Two fixes to the setup record from an independent review of the 2.3.2 installer
6
+ (issue #82). In both cases the undo used to stop with exit 3 and change nothing, so no
7
+ data was lost, but the skill links stayed installed until the record was fixed by hand.
8
+
9
+ ## What changes
10
+
11
+ - **Undo works after a link joins two folders the setup made.** After a Codex setup on
12
+ a fresh profile, moving `~/.agents/skills` to `~/.codex/skills` and replacing
13
+ `~/.agents` with a link to `~/.codex` makes two entries of `created_dirs` lead to
14
+ one folder. `install.sh`, `install.py` and the guided `--rollback` refused that record
15
+ as listing a folder twice. They now look for a repeated entry by its spelling in the
16
+ record, so a link added after the setup no longer counts as a repeat. The undo
17
+ removes the links, leaves the `~/.agents` link and everything in `~/.codex` as they
18
+ are, and prints a `PRESERVED` line for the folder that now lies behind the link. A
19
+ record that lists the same path twice is still refused with exit 3. When two
20
+ different entries lead to one folder, the record cannot show which of them the setup
21
+ made, so the undo removes neither: each one stays with a `PRESERVED` line, while the
22
+ links and the other recorded folders are still removed.
23
+ - **A folder whose real path holds a line break stops the setup before it writes.**
24
+ The record lists each folder the setup makes with the links on the way resolved.
25
+ When a link on the way leads to a folder whose name holds a line break or another
26
+ control character (for example `~/.claude` linked to such a folder), `install.sh`
27
+ wrote that path into the record split over two lines, so apply exited 0 and the
28
+ undo later refused the record. The Python installer wrote such a path for a folder
29
+ behind a link that is not on the skills path (for example `CODEX_HOME` set to a
30
+ folder still to be made behind such a link). Both installers now refuse the apply
31
+ with exit 2 and an error that names the folder, before anything is written, as they
32
+ already did for a path written with such a character. `install.sh` also keeps a
33
+ line break at the end of a folder name when it resolves links; it used to drop it.
34
+
35
+ ## Verification record
36
+
37
+ Local checks (macOS, Python 3.14.5):
38
+
39
+ - Two new tests in `tests.test_shell_installer` run each case with `install.sh` under
40
+ `/bin/sh`, dash, bash in POSIX mode and zsh emulating sh, and with `install.py`.
41
+ Against the 2.4.0 scripts they failed in 23 subtests: every `install.sh` run of both
42
+ cases, the `install.py` undo of the rearranged profile, and the `install.py` apply
43
+ with `CODEX_HOME` behind a link. The `install.py` apply with `~/.claude` linked to
44
+ such a folder was already refused. Without the trailing line break fix, 8 `install.sh`
45
+ subtests for a folder name that ends in a line break still failed.
46
+ - The case "a folder listed under two spellings" was removed from the test of damaged
47
+ records, because such a record is now accepted; the case of a folder listed twice
48
+ stays.
49
+ - A third test, from a review of this fix, lists an existing empty home under its real
50
+ path and through a link to it. The undo exits 0 and the home stays in all 5 runs; with
51
+ the first version of this fix, the undo removed the home in all 5.
52
+ - `python3 -m unittest tests.test_shell_installer tests.test_one_command_installer
53
+ tests.test_guided_onboarding tests.test_installer tests.test_install_guards`: 205
54
+ tests passed, 2 skipped.
55
+ - `sh -n` and `dash -n` on `scripts/install.sh`, `shellcheck -S error` and
56
+ `git diff --check` passed.
57
+
58
+ The line break case is not tested on Windows, which does not allow such a file name.
59
+
60
+ ## Scope
61
+
62
+ This is an installer fix. The record format, the module set and the instruction
63
+ block do not change.
@@ -0,0 +1,190 @@
1
+ # nobrainer-tech-flow 2.5.0: one set of project instructions for every agent
2
+
3
+ Release date: 2026-10-20.
4
+
5
+ The module `nobrainer-codex-context` (`nb-codex-context`) becomes `nobrainer-context`
6
+ (`nb-context`). It now looks at the project instructions of every coding agent in use,
7
+ not only Codex. The old name keeps no alias. The module set stays at eighteen.
8
+
9
+ ## What changes
10
+
11
+ - **One inventory for six clients.** `skills/nobrainer-context/scripts/context_inventory.py`
12
+ (Python 3.11+ standard library, read-only) lists, for Codex, Claude Code, Gemini CLI,
13
+ Cursor, GitHub Copilot and OpenCode, the instruction files each one loads in a
14
+ project: at start, on demand, by import or only on some surfaces. It reports bytes,
15
+ lines and words, the Codex `project_doc_max_bytes` budget and truncation, files over
16
+ Claude Code's 200-line or Cursor's 500-line guidance, byte-identical copies, lines
17
+ repeated across files with `file:line` locations, and whether the instructions name
18
+ the current Flow goal file (`NONE`, `POINTED`, `NOT_POINTED`, `STALE_POINTER`).
19
+ `--include-global` adds each client's user-level file. The earlier Codex probe,
20
+ `codex_context.py`, ships unchanged next to it.
21
+ - **Rules from the clients' own documentation.** `references/clients.md` lists what
22
+ each client loads, its documented limit and its readback, with the official pages
23
+ checked on 2026-10-20. Points the pages do not document (a Codex command that prints
24
+ the loaded instructions, the `project_root_markers` default, Cursor's `.cursorrules`
25
+ status, a Copilot character limit, Gemini CLI size limits) are marked `UNVERIFIED`
26
+ and reported as unknown, never as limits.
27
+ - **One source of truth, applied only after approval.** `references/consolidate.md`
28
+ proposes `AGENTS.md` as the source of truth with short pointers, for example
29
+ `@AGENTS.md` in `CLAUDE.md` or `context.fileName` for Gemini CLI. It covers the
30
+ traps the documentation names: a `CLAUDE.md` or `CLAUDE.local.md` stops Claude Code
31
+ from reading `AGENTS.md` directly, imports still load at start, and a sentence that
32
+ only says "read AGENTS.md" is unreliable. Contradictions are reported with
33
+ `file:line` pairs and never resolved by picking one wording. Edits are project-local,
34
+ follow a full preview and an explicit yes, and are read back by running the
35
+ inventory again. Global files and client settings stay untouched unless the owner
36
+ asks for that separately.
37
+ - **Goal pointer only.** When the project keeps a Flow goal file, the module checks
38
+ that instructions name the current one. Goal content and handoff stay with
39
+ `nobrainer-tech-flow` and `nobrainer-sessions`.
40
+ - **Clean update from the old name.** `nobrainer-codex-context` joins the retired
41
+ names. `install.sh` and `install.py` read the setup record: when it lists
42
+ the old name and the old link is this checkout's exact link, preview shows
43
+ `REMOVE_RETIRED`. Apply links `nobrainer-context` and writes everything else
44
+ first; the old link goes last, just before the record is saved. It is moved into a
45
+ private folder and checked there, so an entry that replaced it after the check is
46
+ put back untouched, and it comes back if the record cannot be saved. Undo of a
47
+ setup made before 2.5.0 removes the old link too. `install_skills.py` gains
48
+ `--recorded-retired NAME`, which stops that link from blocking and never deletes
49
+ it; without a record an exact old link still needs `--migrate-legacy`. A file,
50
+ folder, copy or link at the old name that is not this checkout's link is reported
51
+ as `PRESERVED_FOREIGN` and left unchanged.
52
+ - **TypeSafe key only on request.** `typed_decisions.py` no longer reads
53
+ `TYPESAFE_API_KEY` by itself. `--key-env NAME` names the variable, and the key
54
+ reaches the worker on standard input; the worker's environment carries no
55
+ credential.
56
+
57
+ ## Claude plugin directory findings
58
+
59
+ The directory scan of the 2.4.1 plugin ZIP reported four kinds of findings without
60
+ details. A local scan of the built ZIP matched them as follows:
61
+
62
+ - *Uses a credential from the user's machine* (3): `typed_decisions.py` read
63
+ `TYPESAFE_API_KEY`, sent it as a bearer token and copied it into the child process.
64
+ Fixed: the key is read only from a variable the user names with `--key-env`.
65
+ - *Contains a download-and-run command* (2): no shipped script downloads and runs
66
+ anything. The likely matches are instructions in `nobrainer-team` (`npx skills
67
+ find/add/use`, a documented, owner-gated capability search) and `nobrainer-browser`
68
+ (installs `@playwright/cli` at the exact version it read back first). Left as they
69
+ are: both are documented steps an agent runs only under the existing approval
70
+ gates, not executed code.
71
+ - *Image or font file that the plugin's code could run* (3): the ZIP holds exactly
72
+ three images: `assets/nobrainer-tech-logo.svg`, `assets/nobrainer-workflow.svg` and
73
+ `assets/plugin-logo.png`. Neither SVG has a script, event handler, `foreignObject` or
74
+ external reference; the PNG has only standard chunks. No script reads them; the
75
+ manifests reference the logo. Left as they are.
76
+ - *Unrecognized field in plugin.json* (3): `.claude-plugin/plugin.json` passes
77
+ `claude plugin validate --strict`. The fields Claude does not know are in the other
78
+ clients' manifests that the same ZIP carries for the OpenAI upload: `extensions` and
79
+ `$schema` in the root `plugin.json`, `interface` in `.codex-plugin/plugin.json`.
80
+ Left as they are: removing them would break the OpenAI package, and Claude ignores
81
+ unknown fields at load.
82
+
83
+ ## Verification record
84
+
85
+ Initial implementation checks (macOS, Python 3.14.5), before the later
86
+ eleven-finding review:
87
+
88
+ - `python3 scripts/validate_skills.py` and `python3 scripts/validate_skills.py --suite`:
89
+ both passed.
90
+ - `python3 -m unittest discover -s tests`: 531 tests ran, all passed except 5
91
+ platform-specific skips. This includes the exported-source run without Git metadata.
92
+ - `tests.test_context_probe`: 14 tests for the inventory and the Codex probe. They
93
+ cover the pointer layout (`CLAUDE.md` with `@AGENTS.md`, `GEMINI.md` with
94
+ `@./AGENTS.md`) reported `CURRENT` without any write; Claude Code reading
95
+ `AGENTS.md` only while no `CLAUDE.md` or `CLAUDE.local.md` exists; byte-identical
96
+ copies, repeated lines with `file:line` locations and the 200-line guidance;
97
+ Cursor `.mdc` modes and an ignored plain `.md`; Copilot path-specific files; the
98
+ Gemini `context.fileName` list and `opencode.json` entries (relative, absolute,
99
+ empty, `~/` and globs, URLs never fetched); imports inside code ignored and import
100
+ loops stopped; `@~/` imports and user-level files; an unreadable file reported as a
101
+ finding; the goal pointer states; Codex truncation; an empty project. 14 of them
102
+ (with `tests.test_typed_decisions`, 22 in all) also passed on Python 3.11.14.
103
+ - A new `tests.test_shell_installer` case starts from a 2.4.1-style setup (a record
104
+ and a link for `nobrainer-codex-context`) and runs under `/bin/sh`, dash, bash in
105
+ POSIX mode, zsh emulating sh and with `install.py`: undo removes all 18 links
106
+ including the dangling old one; apply removes the old link, links
107
+ `nobrainer-context` and records the 18 current names; an old link the record does
108
+ not list still stops apply with exit 3. A new `tests.test_installer` case checks
109
+ that a foreign folder at the old name survives `--recorded-retired`, and that the
110
+ exact old link needs `--migrate-legacy` or `--recorded-retired`.
111
+ - A new `tests.test_typed_decisions` case checks that `TYPESAFE_API_KEY` is not read
112
+ without `--key-env`, that only the named variable is read, and that the worker's
113
+ environment carries no credential.
114
+ - `scripts/build_plugin.py` built a 140-file ZIP with 18 skills, version 2.5.0 and
115
+ `skills/nobrainer-context/` (5 files). `claude plugin validate --strict` (Claude
116
+ Code 2.1.303) passed on the extracted copy, and no file in it reads
117
+ `TYPESAFE_API_KEY` implicitly.
118
+ - On this repository the inventory reports `ATTENTION`: `CLAUDE.md` has 205 lines
119
+ (over the 200-line guidance), `AGENTS.md` and `CLAUDE.md` are byte-identical
120
+ (a test requires the copy), and Copilot's agent surfaces load both, so 107 lines
121
+ reach Copilot twice. This is reported, not changed, in this release.
122
+ - `sh -n` and `dash -n` on `scripts/install.sh`, `shellcheck -S error`,
123
+ `python3 -m py_compile` on every script and test, `git diff --check` and a gitleaks
124
+ scan of the staged changes passed.
125
+ - The initial implementation review found no critical or safety finding; its two
126
+ probe crashes (an unreadable file, an absolute `opencode.json` entry), the missed
127
+ `@~/` imports and user-level locations, the changed `install.sh` error order and a
128
+ record not rewritten after a retire-only run were fixed and tested.
129
+
130
+ ### Corrections after the eleven-finding review
131
+
132
+ The later review requested changes for installer races and rollback, hidden
133
+ retirement previews, incorrect or incomplete instruction discovery, JSONC parsing,
134
+ Codex configuration errors, a named credential remaining in the worker environment
135
+ and shifted duplicate-line locations. The corrections keep retirement claims until
136
+ the record is saved, restore them on failure, report broken discovery as attention,
137
+ and preserve the actual source locations. The migration regression also covers a
138
+ home path containing spaces and a run that only retires a recorded link. If claiming
139
+ a later retired link fails, earlier claims are restored before setup rollback.
140
+ JSONC parsing preserves string contents and rejects unterminated comments.
141
+ A follow-up review found two remaining defects, reproduced before correction:
142
+ shell restore could overwrite a concurrent destination, and imports from on-demand
143
+ instructions were counted at startup. Shell recovery now calls the existing native
144
+ no-replace rename helper; when Python or the native operation is unavailable, it
145
+ preserves the recovery claim and reports incomplete rollback instead of falling
146
+ back to an overwriting move. Normal installation still works without Python.
147
+ Imports retain their conditional scope recursively; a startup use takes precedence
148
+ when a file is also imported conditionally.
149
+
150
+ Fresh local verification of the corrections:
151
+
152
+ - 93 tests passed: `tests.test_context_probe` (22),
153
+ `tests.test_typed_decisions` (9), `tests.test_installer` (59), and three focused
154
+ shell cases for the restore race, spaced-home migration and no-Python install.
155
+ - The spaced-home migration case first failed in sh, dash, bash in POSIX mode
156
+ and zsh emulating sh, then passed in all four plus `install.py` after correction.
157
+ - Both structure validators, shell syntax/lint and a redacted scan of the candidate
158
+ diff passed. The 140-file plugin ZIP still has 18 modules, five context-module
159
+ files and no retired module; strict Claude plugin validation passed.
160
+ - The final full run executed 544 tests in 1081.229 seconds and returned exit 1
161
+ (two failures, five skips). Both failures came from an old extracted plugin in
162
+ the ignored backup directory: the curated-tree test found a second set of
163
+ modules, and archive acceptance copied it and failed the same check. The archive
164
+ child executed 544 tests in 521.629 seconds (one failure, six skips).
165
+ - The generated package was moved outside the checkout, preserving all 141 files;
166
+ SHA-256 manifests before and after matched. Only the two failed tests were rerun:
167
+ both passed, exit 0, in 396.922 seconds. This includes the archive acceptance
168
+ test's complete discovery run on the same 544-test source, with its recursion
169
+ guard enabled. No source changed between the failed run and this rerun.
170
+ - The final independent delta review returned `CLEAN` after both follow-up
171
+ corrections. The initial 531-test result above predates these corrections;
172
+ earlier process-control failures do not establish acceptance for them.
173
+
174
+ These checks prove the module's probe, the installer migration and the package
175
+ metadata locally. They do not prove that a live client follows the consolidated
176
+ instructions, a fresh marketplace import, publication or a performance gain.
177
+
178
+ ### Further PR review corrections
179
+
180
+ The inventory now returns `NONE` when every discovered goal is complete, while
181
+ still reporting a pointer to a missing goal. With `--include-global`, Claude and
182
+ Gemini user-level imports enter the same recursive discovery, byte totals,
183
+ duplicate detection and goal-pointer scan as project imports. Claude's line
184
+ guidance applies only to directly discovered `CLAUDE.md` files, excluding
185
+ `AGENTS.md` fallbacks and `.claude/rules/*.md` rules.
186
+
187
+ The installer audit also reproduced a blocked recovery: a changed retired entry
188
+ was claimed, then another entry occupied its original path before restore.
189
+ Both installers now fail the run, restore earlier retirement claims and preserve
190
+ the blocked claim for recovery, rather than saving a record and reporting success.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nobrainer-tech-flow",
3
3
  "description": "From task to done. nobrainer-tech-flow is one workflow of 18 modules for AI coding agents: it scopes the task, delegates ready work, checks the result and hands over the evidence, including what was not checked.",
4
- "version": "2.4.0",
4
+ "version": "2.5.0",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nobrainer-tech-flow",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "From task to done. nobrainer-tech-flow is one workflow of 18 modules for AI coding agents: it scopes the task, delegates ready work, checks the result and hands over the evidence, including what was not checked.",
5
5
  "type": "module",
6
6
  "main": ".opencode/plugins/nobrainer-tech-skills.js",
package/plugin.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "nobrainer-tech-flow",
4
4
  "description": "From task to done. nobrainer-tech-flow is one workflow of 18 modules for AI coding agents: it scopes the task, delegates ready work, checks the result and hands over the evidence, including what was not checked.",
5
- "version": "2.4.0",
5
+ "version": "2.5.0",
6
6
  "author": {
7
7
  "name": "NoBrainer Tech",
8
8
  "url": "https://nobrainer.tech"
@@ -248,11 +248,12 @@ def symlink_help(where: Path | None = None) -> str:
248
248
  )
249
249
 
250
250
 
251
- def plan_skills(ctx: Context) -> tuple[int, int]:
252
- """Dry-run the skill install: (skills to link, skills already linked)."""
251
+ def plan_skills(ctx: Context) -> tuple[int, int, list[str]]:
252
+ """Dry-run the skill install: (skills to link, skills already linked, retired links due to go)."""
253
253
 
254
254
  code, out, err = run(
255
- [sys.executable, str(INSTALL_SKILLS), "--client", ctx.client, "--dest", str(ctx.skills)]
255
+ [sys.executable, str(INSTALL_SKILLS), "--client", ctx.client, "--dest", str(ctx.skills),
256
+ *ctx.guided.recorded_retired_args(read_record(ctx))]
256
257
  )
257
258
  if code:
258
259
  hint = None
@@ -271,7 +272,8 @@ def plan_skills(ctx: Context) -> tuple[int, int]:
271
272
  if to_link and not symlinks_available():
272
273
  print(symlink_help(), file=sys.stderr)
273
274
  raise Refused(2)
274
- return to_link, actions.count("KEEP")
275
+ retired = [line.split(": ", 1)[1] for line in out.splitlines() if line.startswith("RETIRED_RECORDED: ")]
276
+ return to_link, actions.count("KEEP"), retired
275
277
 
276
278
 
277
279
  def plan_instructions(ctx: Context) -> list[str]:
@@ -361,7 +363,7 @@ def unrecorded_path(ctx: Context) -> Path | None:
361
363
 
362
364
 
363
365
  def install(ctx: Context) -> int:
364
- to_link, kept = plan_skills(ctx)
366
+ to_link, kept, retired = plan_skills(ctx)
365
367
  instructions = plan_instructions(ctx)
366
368
  # The guided setup's own dry run checks the recorded setup, the paths and the
367
369
  # target, so the preview refuses whatever --apply would refuse.
@@ -371,6 +373,8 @@ def install(ctx: Context) -> int:
371
373
  if not ctx.apply:
372
374
  print(f"{source_line()} for {ctx.label}")
373
375
  print(f"SKILLS: {to_link} to link into {ctx.skills} ({kept} already linked)")
376
+ for line in retired:
377
+ print(f"REMOVE_RETIRED: {line}")
374
378
  for line in unique(instructions):
375
379
  print(line)
376
380
  note = ctx.variable_note()
@@ -394,12 +398,15 @@ def install(ctx: Context) -> int:
394
398
  # New links and a written instruction file are what a client has to be restarted for.
395
399
  # The personalization helper prints APPLIED only for a file it wrote.
396
400
  written = re.search(r"^APPLIED: ", out, re.MULTILINE) is not None
397
- changed = bool(to_link) or written
401
+ removed_retired = re.findall(r"^REMOVED_RETIRED: (.+)$", out, re.MULTILINE)
402
+ changed = bool(to_link) or written or bool(removed_retired)
398
403
  if changed:
399
404
  print(f"INSTALLED: {source_line()} for {ctx.label}")
400
405
  else:
401
406
  print(f"UP TO DATE: {source_line()} is already installed for {ctx.label}; nothing changed")
402
407
  print(f"SKILLS: {linked} linked in {ctx.skills} ({to_link} new)")
408
+ for target in removed_retired:
409
+ print(f"REMOVED_RETIRED: {target}")
403
410
  if profile.get("target"):
404
411
  backup = profile.get("backup")
405
412
  if written and re.search(r"^UPDATE: ", out, re.MULTILINE):