# nobrainer-tech-flow 2.5.0: one set of project instructions for every agent

Release date: 2026-10-20.

The module `nobrainer-codex-context` (`nb-codex-context`) becomes `nobrainer-context`
(`nb-context`). It now looks at the project instructions of every coding agent in use,
not only Codex. The old name keeps no alias. The module set stays at eighteen.

## What changes

- **One inventory for six clients.** `skills/nobrainer-context/scripts/context_inventory.py`
  (Python 3.11+ standard library, read-only) lists, for Codex, Claude Code, Gemini CLI,
  Cursor, GitHub Copilot and OpenCode, the instruction files each one loads in a
  project: at start, on demand, by import or only on some surfaces. It reports bytes,
  lines and words, the Codex `project_doc_max_bytes` budget and truncation, files over
  Claude Code's 200-line or Cursor's 500-line guidance, byte-identical copies, lines
  repeated across files with `file:line` locations, and whether the instructions name
  the current Flow goal file (`NONE`, `POINTED`, `NOT_POINTED`, `STALE_POINTER`).
  `--include-global` adds each client's user-level file. The earlier Codex probe,
  `codex_context.py`, ships unchanged next to it.
- **Rules from the clients' own documentation.** `references/clients.md` lists what
  each client loads, its documented limit and its readback, with the official pages
  checked on 2026-10-20. Points the pages do not document (a Codex command that prints
  the loaded instructions, the `project_root_markers` default, Cursor's `.cursorrules`
  status, a Copilot character limit, Gemini CLI size limits) are marked `UNVERIFIED`
  and reported as unknown, never as limits.
- **One source of truth, applied only after approval.** `references/consolidate.md`
  proposes `AGENTS.md` as the source of truth with short pointers, for example
  `@AGENTS.md` in `CLAUDE.md` or `context.fileName` for Gemini CLI. It covers the
  traps the documentation names: a `CLAUDE.md` or `CLAUDE.local.md` stops Claude Code
  from reading `AGENTS.md` directly, imports still load at start, and a sentence that
  only says "read AGENTS.md" is unreliable. Contradictions are reported with
  `file:line` pairs and never resolved by picking one wording. Edits are project-local,
  follow a full preview and an explicit yes, and are read back by running the
  inventory again. Global files and client settings stay untouched unless the owner
  asks for that separately.
- **Goal pointer only.** When the project keeps a Flow goal file, the module checks
  that instructions name the current one. Goal content and handoff stay with
  `nobrainer-tech-flow` and `nobrainer-sessions`.
- **Clean update from the old name.** `nobrainer-codex-context` joins the retired
  names. `install.sh` and `install.py` read the setup record: when it lists
  the old name and the old link is this checkout's exact link, preview shows
  `REMOVE_RETIRED`. Apply links `nobrainer-context` and writes everything else
  first; the old link goes last, just before the record is saved. It is moved into a
  private folder and checked there, so an entry that replaced it after the check is
  put back untouched, and it comes back if the record cannot be saved. Undo of a
  setup made before 2.5.0 removes the old link too. `install_skills.py` gains
  `--recorded-retired NAME`, which stops that link from blocking and never deletes
  it; without a record an exact old link still needs `--migrate-legacy`. A file,
  folder, copy or link at the old name that is not this checkout's link is reported
  as `PRESERVED_FOREIGN` and left unchanged.
- **TypeSafe key only on request.** `typed_decisions.py` no longer reads
  `TYPESAFE_API_KEY` by itself. `--key-env NAME` names the variable, and the key
  reaches the worker on standard input; the worker's environment carries no
  credential.

## Claude plugin directory findings

The directory scan of the 2.4.1 plugin ZIP reported four kinds of findings without
details. A local scan of the built ZIP matched them as follows:

- *Uses a credential from the user's machine* (3): `typed_decisions.py` read
  `TYPESAFE_API_KEY`, sent it as a bearer token and copied it into the child process.
  Fixed: the key is read only from a variable the user names with `--key-env`.
- *Contains a download-and-run command* (2): no shipped script downloads and runs
  anything. The likely matches are instructions in `nobrainer-team` (`npx skills
  find/add/use`, a documented, owner-gated capability search) and `nobrainer-browser`
  (installs `@playwright/cli` at the exact version it read back first). Left as they
  are: both are documented steps an agent runs only under the existing approval
  gates, not executed code.
- *Image or font file that the plugin's code could run* (3): the ZIP holds exactly
  three images: `assets/nobrainer-tech-logo.svg`, `assets/nobrainer-workflow.svg` and
  `assets/plugin-logo.png`. Neither SVG has a script, event handler, `foreignObject` or
  external reference; the PNG has only standard chunks. No script reads them; the
  manifests reference the logo. Left as they are.
- *Unrecognized field in plugin.json* (3): `.claude-plugin/plugin.json` passes
  `claude plugin validate --strict`. The fields Claude does not know are in the other
  clients' manifests that the same ZIP carries for the OpenAI upload: `extensions` and
  `$schema` in the root `plugin.json`, `interface` in `.codex-plugin/plugin.json`.
  Left as they are: removing them would break the OpenAI package, and Claude ignores
  unknown fields at load.

## Verification record

Initial implementation checks (macOS, Python 3.14.5), before the later
eleven-finding review:

- `python3 scripts/validate_skills.py` and `python3 scripts/validate_skills.py --suite`:
  both passed.
- `python3 -m unittest discover -s tests`: 531 tests ran, all passed except 5
  platform-specific skips. This includes the exported-source run without Git metadata.
- `tests.test_context_probe`: 14 tests for the inventory and the Codex probe. They
  cover the pointer layout (`CLAUDE.md` with `@AGENTS.md`, `GEMINI.md` with
  `@./AGENTS.md`) reported `CURRENT` without any write; Claude Code reading
  `AGENTS.md` only while no `CLAUDE.md` or `CLAUDE.local.md` exists; byte-identical
  copies, repeated lines with `file:line` locations and the 200-line guidance;
  Cursor `.mdc` modes and an ignored plain `.md`; Copilot path-specific files; the
  Gemini `context.fileName` list and `opencode.json` entries (relative, absolute,
  empty, `~/` and globs, URLs never fetched); imports inside code ignored and import
  loops stopped; `@~/` imports and user-level files; an unreadable file reported as a
  finding; the goal pointer states; Codex truncation; an empty project. 14 of them
  (with `tests.test_typed_decisions`, 22 in all) also passed on Python 3.11.14.
- A new `tests.test_shell_installer` case starts from a 2.4.1-style setup (a record
  and a link for `nobrainer-codex-context`) and runs under `/bin/sh`, dash, bash in
  POSIX mode, zsh emulating sh and with `install.py`: undo removes all 18 links
  including the dangling old one; apply removes the old link, links
  `nobrainer-context` and records the 18 current names; an old link the record does
  not list still stops apply with exit 3. A new `tests.test_installer` case checks
  that a foreign folder at the old name survives `--recorded-retired`, and that the
  exact old link needs `--migrate-legacy` or `--recorded-retired`.
- A new `tests.test_typed_decisions` case checks that `TYPESAFE_API_KEY` is not read
  without `--key-env`, that only the named variable is read, and that the worker's
  environment carries no credential.
- `scripts/build_plugin.py` built a 140-file ZIP with 18 skills, version 2.5.0 and
  `skills/nobrainer-context/` (5 files). `claude plugin validate --strict` (Claude
  Code 2.1.303) passed on the extracted copy, and no file in it reads
  `TYPESAFE_API_KEY` implicitly.
- On this repository the inventory reports `ATTENTION`: `CLAUDE.md` has 205 lines
  (over the 200-line guidance), `AGENTS.md` and `CLAUDE.md` are byte-identical
  (a test requires the copy), and Copilot's agent surfaces load both, so 107 lines
  reach Copilot twice. This is reported, not changed, in this release.
- `sh -n` and `dash -n` on `scripts/install.sh`, `shellcheck -S error`,
  `python3 -m py_compile` on every script and test, `git diff --check` and a gitleaks
  scan of the staged changes passed.
- The initial implementation review found no critical or safety finding; its two
  probe crashes (an unreadable file, an absolute `opencode.json` entry), the missed
  `@~/` imports and user-level locations, the changed `install.sh` error order and a
  record not rewritten after a retire-only run were fixed and tested.

### Corrections after the eleven-finding review

The later review requested changes for installer races and rollback, hidden
retirement previews, incorrect or incomplete instruction discovery, JSONC parsing,
Codex configuration errors, a named credential remaining in the worker environment
and shifted duplicate-line locations. The corrections keep retirement claims until
the record is saved, restore them on failure, report broken discovery as attention,
and preserve the actual source locations. The migration regression also covers a
home path containing spaces and a run that only retires a recorded link. If claiming
a later retired link fails, earlier claims are restored before setup rollback.
JSONC parsing preserves string contents and rejects unterminated comments.
A follow-up review found two remaining defects, reproduced before correction:
shell restore could overwrite a concurrent destination, and imports from on-demand
instructions were counted at startup. Shell recovery now calls the existing native
no-replace rename helper; when Python or the native operation is unavailable, it
preserves the recovery claim and reports incomplete rollback instead of falling
back to an overwriting move. Normal installation still works without Python.
Imports retain their conditional scope recursively; a startup use takes precedence
when a file is also imported conditionally.

Fresh local verification of the corrections:

- 93 tests passed: `tests.test_context_probe` (22),
  `tests.test_typed_decisions` (9), `tests.test_installer` (59), and three focused
  shell cases for the restore race, spaced-home migration and no-Python install.
- The spaced-home migration case first failed in sh, dash, bash in POSIX mode
  and zsh emulating sh, then passed in all four plus `install.py` after correction.
- Both structure validators, shell syntax/lint and a redacted scan of the candidate
  diff passed. The 140-file plugin ZIP still has 18 modules, five context-module
  files and no retired module; strict Claude plugin validation passed.
- The final full run executed 544 tests in 1081.229 seconds and returned exit 1
  (two failures, five skips). Both failures came from an old extracted plugin in
  the ignored backup directory: the curated-tree test found a second set of
  modules, and archive acceptance copied it and failed the same check. The archive
  child executed 544 tests in 521.629 seconds (one failure, six skips).
- The generated package was moved outside the checkout, preserving all 141 files;
  SHA-256 manifests before and after matched. Only the two failed tests were rerun:
  both passed, exit 0, in 396.922 seconds. This includes the archive acceptance
  test's complete discovery run on the same 544-test source, with its recursion
  guard enabled. No source changed between the failed run and this rerun.
- The final independent delta review returned `CLEAN` after both follow-up
  corrections. The initial 531-test result above predates these corrections;
  earlier process-control failures do not establish acceptance for them.

These checks prove the module's probe, the installer migration and the package
metadata locally. They do not prove that a live client follows the consolidated
instructions, a fresh marketplace import, publication or a performance gain.

### Further PR review corrections

The inventory now returns `NONE` when every discovered goal is complete, while
still reporting a pointer to a missing goal. With `--include-global`, Claude and
Gemini user-level imports enter the same recursive discovery, byte totals,
duplicate detection and goal-pointer scan as project imports. Claude's line
guidance applies only to directly discovered `CLAUDE.md` files, excluding
`AGENTS.md` fallbacks and `.claude/rules/*.md` rules.

The installer audit also reproduced a blocked recovery: a changed retired entry
was claimed, then another entry occupied its original path before restore.
Both installers now fail the run, restore earlier retirement claims and preserve
the blocked claim for recovery, rather than saving a record and reporting success.
