nobrainer-tech-flow 2.5.0 → 2.7.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 (36) 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 +8 -8
  5. package/CLAUDE.md +8 -8
  6. package/README.md +78 -36
  7. package/adapters/bootstrap.md +2 -2
  8. package/assets/nobrainer-workflow.svg +2 -2
  9. package/docs/CHAT_PLUGINS.md +4 -2
  10. package/docs/INSTALL.md +51 -30
  11. package/docs/SKILL_CURATION.md +6 -6
  12. package/docs/releases/v2.6.0.md +73 -0
  13. package/docs/releases/v2.7.0.md +145 -0
  14. package/gemini-extension.json +1 -1
  15. package/package.json +1 -1
  16. package/plugin.json +1 -1
  17. package/scripts/install.py +3 -1
  18. package/scripts/install.sh +25 -6
  19. package/scripts/install_guards.py +29 -13
  20. package/scripts/install_personalization.py +52 -17
  21. package/skills/nobrainer-auto-fine-tune/SKILL.md +1 -1
  22. package/skills/nobrainer-build/SKILL.md +17 -2
  23. package/skills/nobrainer-security/SKILL.md +10 -0
  24. package/skills/nobrainer-team/SKILL.md +43 -64
  25. package/skills/nobrainer-team/references/team-plan.md +7 -6
  26. package/skills/nobrainer-tech-flow/SKILL.md +13 -13
  27. package/skills/nobrainer-tech-flow/VERSION +1 -1
  28. package/skills/nobrainer-tech-flow/references/correction-hooks.md +11 -5
  29. package/skills/nobrainer-tech-flow/references/daily-update.md +5 -2
  30. package/skills/nobrainer-tech-flow/references/delivery.md +50 -20
  31. package/skills/nobrainer-tech-flow/references/long-run-state.md +31 -5
  32. package/skills/nobrainer-tech-flow/references/model-routing.md +13 -11
  33. package/skills/nobrainer-tech-flow/references/project-start.md +2 -2
  34. package/skills/nobrainer-tech-flow/references/routing.md +6 -8
  35. package/skills/nobrainer-tech-flow/references/setup.md +6 -7
  36. package/skills/nobrainer-tech-flow/scripts/flow_guard.py +179 -2
@@ -0,0 +1,73 @@
1
+ # nobrainer-tech-flow 2.6.0: delegate aggressively, verify by risk
2
+
3
+ Release date: 2026-10-23.
4
+
5
+ This release changes workflow guidance and the update line of the instruction block.
6
+ The setup record and the module set (eighteen) do not change.
7
+
8
+ ## What changes
9
+
10
+ - **Aggressive delegation as the default.** `skills/nobrainer-tech-flow/SKILL.md` now opens
11
+ substantial work with "Delegate aggressively": independent units run on parallel native
12
+ subagents through team execution, and MAIN integrates, verifies and refills slots.
13
+ `references/delivery.md` adds the reason (delegation is the default route to a faster
14
+ done), keeps only tiny, tightly coupled, gated or shared-state steps in MAIN, and sets a
15
+ cost rule: delegate a unit when parallel work shortens the time to done more than a
16
+ worker's start-up costs, send a short task packet rather than the whole conversation,
17
+ ask for a concise report, and give narrow, mechanical work to a cheaper model under the
18
+ host's policy. No model is named.
19
+ - **Resend only failed units.** When part of a batch fails, only the failed units go out
20
+ again with their new evidence; accepted units are not rerun.
21
+ - **Verification by blast radius.** `references/delivery.md` scales verification to how
22
+ risky and reversible a change is. Reversible, low-risk changes may proceed on green
23
+ automated tests, review and security checks. CI configuration, credentials,
24
+ security-sensitive paths, data migrations and irreversible effects need an independent
25
+ review and remain owner-gated. An agent's approval never counts as the owner's.
26
+ - **Two build rules.** `skills/nobrainer-build/SKILL.md`: before adding complexity for a
27
+ speculative race or security edge case, name the concrete failure, its likelihood and
28
+ the cost; and in user interfaces, taglines, helper text and secondary labels added to
29
+ explain a screen count as slop, so the layout gets fixed instead.
30
+
31
+ ## Daily updates by default, in one line
32
+
33
+ The managed instruction block now carries one short update line, on by default for new
34
+ setups: "Once a day on first use, update nobrainer-tech-flow to its latest verified stable
35
+ release from the canonical source, with a backup; change nothing else and ask if unsure."
36
+ `install_personalization.py --no-auto-update` writes the one-line opt-out instead ("tell
37
+ the owner when a newer stable nobrainer-tech-flow release exists; do not update it
38
+ yourself"); `--auto-update` stays accepted and means the default. With `--keep-options`
39
+ (which `install.py` and the guided setup always pass) the longer lines written before 2.6.0
40
+ become the matching short line: an old update grant stays a grant and the old notify-only
41
+ default stays notify-only, so no existing setup starts updating itself without a choice.
42
+ An update line that is neither recognized grant, for example one edited by hand, becomes
43
+ the notify-only line. `install.sh` follows the same rule when it refreshes an earlier block:
44
+ it rewrites the block in this version's text but keeps notifying unless the block held the
45
+ update line as its own line.
46
+
47
+ ## Sources
48
+
49
+ The delegation rule is an owner decision (2026-10-23). The other rules were drawn from the
50
+ owner's recent X bookmarks and checked against the replies under each post; ideas that the
51
+ replies credibly disputed (a "canary" line to detect context decay, a viral prompt with a
52
+ false attribution) were left out.
53
+
54
+ ## Verification record
55
+
56
+ Local checks (macOS, Python 3.14.5):
57
+
58
+ - `python3 scripts/validate_skills.py` and `python3 scripts/validate_skills.py --suite`: OK.
59
+ - `skills/nobrainer-tech-flow/SKILL.md` stays within the suite budget (239 lines, 1,749
60
+ words; limits 240 and 1,750).
61
+ - `python3 -m unittest tests.test_suite tests.test_delegation_contract
62
+ tests.test_visible_session_rule`: 81 tests OK.
63
+ - `python3 -m unittest tests.test_shell_installer tests.test_personalization
64
+ tests.test_one_command_installer tests.test_guided_onboarding`: OK, including the new
65
+ cases for the default update line, the opt-out, pre-2.6 blocks, edited or unknown update
66
+ lines and preferences that quote the update wording.
67
+ - `sh -n`, `dash -n` and `shellcheck -S error` on `scripts/install.sh`: clean.
68
+ - `git diff --check`: clean.
69
+ - An independent read-only review found four issues in the update-line handling and its
70
+ documentation (an unrecognized notify-only line could turn into an update grant); all
71
+ were fixed and a second review pass confirmed the fixes.
72
+
73
+ The full suite runs in the Validate workflow for the tagged commit.
@@ -0,0 +1,145 @@
1
+ # nobrainer-tech-flow 2.7.0: delegation where it pays, owner requests in the goal file
2
+
3
+ Release date: 2026-10-25.
4
+
5
+ This release changes workflow guidance and delegation, the optional Claude Code guards,
6
+ `nobrainer-team`, `nobrainer-security` and `nobrainer-build`. The setup record and the module set (eighteen) do not change.
7
+
8
+ ## What changes
9
+
10
+ - **Done is defined and visible.** `skills/nobrainer-tech-flow/SKILL.md` now has the
11
+ agent show the owner what done means before substantial work and set it as the
12
+ host-native goal where supported; `references/delivery.md`, `references/project-start.md`
13
+ and `references/long-run-state.md` replace "create a native goal only when explicitly
14
+ requested" with "set the outcome and DoD as the native goal when the host offers one",
15
+ so the owner can see whether the goal is running, paused or stopped. The Markdown goal
16
+ stays the canonical, portable record. The TODO stays visible: the canonical TODO is
17
+ mirrored in the host's plan or todo tool when it has one, otherwise shown as the
18
+ Progress checklist (`SKILL.md`, `references/delivery.md`, `references/setup.md`).
19
+ - **Delegation only where it pays.** `references/delivery.md` "Coordinated team
20
+ execution" now makes one MAIN loop that loads skills on demand the default. A unit
21
+ goes to a native worker only when parallel work, context isolation, independent
22
+ verification or specialization outweighs the cost, and the plan names that condition;
23
+ without one, the unit stays in MAIN. Work is split by context, not by type of work, so
24
+ the worker that changes a feature also writes and runs its tests. The 2.6.0 rules that
25
+ made delegation the default and said a missing measured speedup was no reason to keep
26
+ work in MAIN are removed. An owner or host rule that asks for more delegation still
27
+ controls. `SKILL.md`, `AGENTS.md`, `CLAUDE.md`, `nobrainer-team`,
28
+ `nobrainer-auto-fine-tune`, `references/model-routing.md` (`STANDARD` is now the
29
+ default and `ROUTED` applies only to qualifying units), `references/long-run-state.md`,
30
+ the shared bootstrap, the Copilot instructions, the
31
+ personalization block written by the installers, the README and the workflow diagram
32
+ say the same. The change follows Anthropic's published guidance:
33
+ [when to fold subagents into the main agent loop](https://claude.com/resources/articles/building-agents-when-to-fold-subagents-into-your-main-agent-loop)
34
+ and [when multi-agent systems help](https://www.claude.com/blog/building-multi-agent-systems-when-and-how-to-use-them),
35
+ which reports that multi-agent implementations typically use three to ten times more
36
+ tokens than a single agent for equivalent tasks.
37
+ - **Owner requests go into the goal file as they arrive.** In
38
+ `skills/nobrainer-tech-flow/SKILL.md` the detailed-ledger gate has a new condition: the
39
+ owner keeps adding requests mid-run in one long conversation. A new section of
40
+ `references/long-run-state.md`, "New owner requests", sets the rule. While the ledger is
41
+ active, the agent records each new request or idea before it continues any work, even
42
+ when the request is deferred. The row quotes the owner's words (minus any secret) and
43
+ carries the date and the status `PENDING`, or `READY` when nothing blocks it. When the
44
+ gate first passes mid-conversation, earlier unfinished requests are backfilled. Rows are
45
+ reconciled at every checkpoint, after compaction and at closeout, and none is silently
46
+ dropped. At closeout each row is `ACCEPTED`, `STOPPED` with the owner decision that
47
+ stopped it, or visibly open with its next step. In `references/correction-hooks.md`,
48
+ `OWNER_DECISION_CHANGED` now acts as soon as the change arrives, before other work,
49
+ updates the goal-file row when a ledger is active, and keeps other project instruction
50
+ files from carrying the old rule: under `AUTO_SCOPED` it edits the contradicting line,
51
+ under `ASK` it prepares the exact diff and asks once, and under `OFF` it names the stale
52
+ line in the final report. The goal-file block gains `CURRENT_MILESTONE`: one short-term
53
+ goal derived from `OUTCOME` and the open request rows, small enough to finish and verify
54
+ in the current session. The agent works toward it without waiting, sets the next
55
+ milestone from the open rows when it is accepted, and re-derives it at once when the
56
+ owner changes a decision or a new request changes what matters most; accepting a
57
+ milestone never closes `OUTCOME`. `OWNER_DECISION_CHANGED` resumes on that re-derived
58
+ milestone. The default task-local goal file is
59
+ `.nobrainer/goal.md`, which the context inventory already searches; it should not be
60
+ committed to a public repository. The short restatements of the gate in
61
+ `references/routing.md`, `references/setup.md`, `AGENTS.md`, `CLAUDE.md` and the
62
+ README say the same.
63
+ - **The guards point back to the goal file after compaction.** The optional Claude Code
64
+ guards gain a fourth hook, SessionStart with the matcher `compact|resume|clear`. It
65
+ tells the agent to re-read up to three active Flow goal files: files with a `GOAL_ID:`
66
+ line and a `STATUS` other than `COMPLETE` in the project root, `tasks/`, `docs/` or
67
+ `.nobrainer/`. It prints only each path and a known `STATUS` word, never other
68
+ goal-file text. It follows no symlink, skips unusual file names, stops after 5,000
69
+ folder entries or 200 files, and prints nothing on any error.
70
+ `scripts/install_guards.py` now reports an install from an earlier version as an
71
+ update. If you already use the guards, update your Git checkout to 2.7.0 first, so the
72
+ hooks' `flow_guard.py` knows the new mode, then preview the change with
73
+ `python3 scripts/install.py --client claude --guards`, apply it with `--apply` and
74
+ restart Claude Code. Until then the three earlier hooks keep working unchanged. The hook
75
+ only finds goal files that already exist; it does not write one.
76
+ - **Team uses task-local specialists, not third-party skills.** `nobrainer-team` no
77
+ longer searches for, downloads, installs or runs external skills, and it writes into no
78
+ client's skill folder. When a capability gap remains after curated skills, installed
79
+ skills, project tools and bounded research, MAIN writes a specialist brief (role,
80
+ method from project docs or verified primary sources, allowed actions, write scope,
81
+ acceptance and report) for a native worker. The brief stays in the task plan and is
82
+ discarded afterwards. The module's description now says "task-local specialist briefs".
83
+ - **A clean security result needs more than one pass.** In
84
+ `skills/nobrainer-security/SKILL.md` one model pass counts as a sample of the scope, not
85
+ as coverage. Before `CLEAN`, at least one more independent pass starts from a different
86
+ entry point, trust boundary or data-flow direction; the review stops when a pass adds no
87
+ new verified finding and reports how many passes ran. After a fix, when the defect was
88
+ public or reachable before it, the agent checks the available logs or other evidence for
89
+ exploitation during that exposure window, or lists the window under
90
+ `UNTESTED_OR_INACCESSIBLE_SURFACE`. In `references/delivery.md` the security-sensitive
91
+ paths that need an independent review and stay owner-gated, however small the diff, now
92
+ name authentication, permissions, payments and personal data. Work from an untrusted or
93
+ unknown author never takes the low-risk path, and a user-interface change needs rendered
94
+ evidence, a screenshot or recording, before and after where possible; unit tests alone
95
+ do not prove it.
96
+ - **Stale conventions are reported, not followed silently.** In
97
+ `skills/nobrainer-build/SKILL.md`, when instruction files or docs describe a coding
98
+ convention that the existing code does not follow, the agent follows the convention the
99
+ code uses, unless the instruction is an explicit owner rule or names a deliberate
100
+ migration, and lists each disagreement in its final report. When the code wins, the
101
+ report includes the exact edit that fixes the stale instruction file, applied only as
102
+ the project's `LEARNING_WRITE_POLICY` allows, so the next run does not inherit the stale
103
+ rule; when an owner rule or migration wins, it names the code change required. Owner
104
+ rules on safety, authority and workflow always apply.
105
+ - **Accurate install documentation.** The README lists the free remote MCP server
106
+ (`https://mcp.nobrainer.tech/mcp`, no sign-in, stateless, six read-only tools) as a
107
+ sixth channel and says it does not install the eighteen modules. `docs/CHAT_PLUGINS.md`
108
+ and `docs/INSTALL.md` now say the npm package is published.
109
+ - **Test fixes.** The bounded-runner interrupt test waits until the child's pid file
110
+ holds a number, not only until it exists, which removes an intermittent CI failure.
111
+ A duplicate GitHub transport test that shadowed another one was removed.
112
+
113
+ ## The remote MCP server
114
+
115
+ The MCP server in `mcp/` is deployed separately and is not part of the npm package.
116
+ Since 2.6.0 it returns a goal-file block with a renewed contract token when
117
+ `get_flow_step` is called with a contract token and `event: "resume"`, and a scheduled, read-only workflow
118
+ warns three days before the bundled model-advisor benchmark snapshot expires. Its
119
+ guidance cards are still pinned to 2.6.0 and move to this release in a separate change
120
+ after the tag.
121
+
122
+ ## Verification record
123
+
124
+ Local checks (macOS, Python 3.14):
125
+
126
+ - `python3 scripts/validate_skills.py` and `python3 scripts/validate_skills.py --suite`: OK.
127
+ - `skills/nobrainer-tech-flow/SKILL.md` stays within the suite budget (239 lines, 1,748
128
+ words; limits 240 and 1,750); `AGENTS.md` and `CLAUDE.md` stay byte-identical within
129
+ theirs (205 lines, 1,615 words; limits 205 and 1,620).
130
+ - `python3 -m unittest tests.test_suite`: 74 tests OK. Every other test module, run
131
+ separately: OK.
132
+ - `git diff --check`: clean.
133
+ - An independent read-only review of this release preparation found three issues: the
134
+ always-loaded instructions went over their word budget, the guard upgrade steps were
135
+ incomplete, and the release text overstated what the request rule guarantees. All three
136
+ were fixed. Two further independent read-only reviews of the delegation, security and
137
+ conventions changes found four low and two medium issues: README summaries that dropped
138
+ conditions, tests that did not protect the exceptions or the cost gate, and the
139
+ delegation-first default still present in `nobrainer-auto-fine-tune` and
140
+ `references/model-routing.md`. All were fixed, and a test now checks that the retired
141
+ delegation defaults do not return on the active surfaces.
142
+
143
+ The changes it ships were each reviewed and passed CI in their own pull requests (#98,
144
+ #101, #109, #110, #111, #112, #113, #115). The full suite runs in the Validate workflow for the
145
+ tagged commit.
@@ -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.5.0",
4
+ "version": "2.7.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.5.0",
3
+ "version": "2.7.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.5.0",
5
+ "version": "2.7.0",
6
6
  "author": {
7
7
  "name": "NoBrainer Tech",
8
8
  "url": "https://nobrainer.tech"
@@ -4,7 +4,9 @@
4
4
  Every run is a dry run until --apply. The skills are linked and the managed
5
5
  instruction block is written by the same helpers as the manual and guided setups,
6
6
  and --undo uses the guided setup's rollback state (as scripts/install.sh does), so
7
- every path reverses the same way. This command never grants a standing authorization.
7
+ every path reverses the same way. The only standing authorization it writes is the
8
+ default daily update of Flow itself, and an existing block keeps notifying unless it
9
+ already held that update line.
8
10
  """
9
11
 
10
12
  from __future__ import annotations
@@ -4,7 +4,8 @@
4
4
  # Same flags, locations, conflict rule and setup record as scripts/install.py, so
5
5
  # either one can undo what the other did. Every run previews until --apply. The
6
6
  # skills are linked to this checkout (never copied), one managed instruction block
7
- # is added, and no standing authorization is ever granted. A managed block that is
7
+ # is added. Its only standing authorization is the default daily update of Flow itself;
8
+ # an existing block keeps notifying unless it already held that line. A managed block that is
8
9
  # already there is replaced by this version's text when it differs, and everything
9
10
  # outside the two markers stays byte for byte, as install.py does. One difference: a
10
11
  # block that carries options (a standing authorization, a wiki root or a preference)
@@ -47,6 +48,12 @@ SEPARATORS=$(printf '\342\200[\250\251]')
47
48
  TAB=$(printf '\t')
48
49
  CR=$(printf '\r')
49
50
 
51
+ # The update line of the block: on by default; an existing block that only notifies
52
+ # (written with --no-auto-update, or the default before 2.6.0) keeps notifying.
53
+ AUTO_UPDATE_LINE='- Once a day on first use, update nobrainer-tech-flow to its latest verified stable release from the canonical source, with a backup; change nothing else and ask if unsure.'
54
+ NOTIFY_UPDATE_LINE='- Once a day on first use, tell the owner when a newer stable nobrainer-tech-flow release exists; do not update it yourself.'
55
+ update_line=$AUTO_UPDATE_LINE
56
+
50
57
  # The block scripts/install_personalization.py writes without options, byte for byte
51
58
  # (a test compares them).
52
59
  block() {
@@ -56,12 +63,14 @@ block() {
56
63
 
57
64
  - Use the `nobrainer-tech-flow` module as the task entrypoint when this client supports skill invocation, by the exact name this client lists for it. In Codex that is `$nobrainer-tech-flow:nobrainer-tech-flow` when modules are listed under the plugin name, or `$nobrainer-tech-flow` when they are listed plainly. If unavailable, check the documented installation path and report that limitation honestly.
58
65
  - On first setup, load `nobrainer-auto-fine-tune` for a read-only capability audit; preserve MAIN model and effort, and mark unverified runtime values `UNKNOWN`.
59
- - Preserve the user's selected MAIN model and effort. Inspect the host's actual subagent models, capabilities, concurrency and quota; delegate every independent ready unit promptly and refill slots after audited completion. Keep coordination in MAIN. Never assume a model is available or silently substitute one.
66
+ - Preserve the user's selected MAIN model and effort. Inspect the host's actual subagent models, capabilities, concurrency and quota; work in one MAIN loop and delegate only units that gain from parallel work, context isolation, independent review or specialization. Keep coordination in MAIN. Never assume a model is available or silently substitute one.
60
67
  - Split substantial work into bounded tasks with clear outputs, exclusive write scope, dependencies, and verification. Keep integration and acceptance in MAIN; avoid duplicate or filler tasks.
61
68
  - Derive short-term goals from the user's long-term direction (LDD) and define observable completion criteria. At project start, inspect the existing structure and layers, then recommend a fitting approach.
62
69
  - At project start, discover whether a relevant wiki exists. If one exists, read its `WIKI.md`, locate relevant `index.md` entries with a targeted search, then read only the relevant pages. Ask before creating a wiki unless project rules or prior authorization already settle it.
63
70
  - Assess context and checkpoint at appropriate milestones. Recommend session rotation when it would help; do not restart or archive automatically. When rotation is authorized, use the supported lifecycle, verify exact successor takeover by ID/readback, and archive the old session only after that readback. Do not create recursive visible workers or claim a restart when unsupported.
64
- - On the first `nobrainer-tech-flow` use each calendar day, check for available updates when this client exposes a supported check and notify the owner; do not apply them automatically. If the client is inactive or cannot check, do not claim a check occurred.
71
+ EOF
72
+ printf '%s\n' "$update_line"
73
+ cat <<'EOF'
65
74
  - Use `nobrainer-writing` for material writing when available; make technical documentation concrete, source-backed, and technically verified. Preserve facts, use the user's language, and verify at the actual delivery layer.
66
75
  <!-- NOBRAINER-TECH-FLOW:END -->
67
76
  EOF
@@ -806,6 +815,12 @@ plan_instructions() {
806
815
  die 3 "malformed or duplicated nobrainer-tech-flow managed markers in $target"
807
816
  fi
808
817
  file_status=present
818
+ # An existing block keeps updating only when it holds the update line as its own line;
819
+ # a notify-only, edited or unknown line keeps notifying, so no grant is ever inferred.
820
+ if block_lines "$target" && ! head -n "$block_to" "$target" | tail -n "+$block_from" |
821
+ LC_ALL=C sed 's/[[:space:]]*$//' | grep -a -q -x -F -e "$AUTO_UPDATE_LINE"; then
822
+ update_line=$NOTIFY_UPDATE_LINE
823
+ fi
809
824
  # A block of an earlier version is brought up to date, but only one that can be replaced
810
825
  # without losing anything: its markers stand on lines of their own, and it holds no option.
811
826
  if ! block_is_default && block_lines "$target" && ! block_has_options; then
@@ -827,6 +842,10 @@ block_lines() {
827
842
  [ "$block_from" -lt "$block_to" ]
828
843
  }
829
844
 
845
+ update_status() {
846
+ if [ "$update_line" = "$NOTIFY_UPDATE_LINE" ]; then echo CHECK_AND_NOTIFY; else echo AUTHORIZED_SAFE_VERIFIED_ONLY; fi
847
+ }
848
+
830
849
  block_is_default() {
831
850
  block_lines "$target" || return 1
832
851
  _b_text=$(head -n "$block_to" "$target" | tail -n "+$block_from")
@@ -836,7 +855,7 @@ block_is_default() {
836
855
  }
837
856
 
838
857
  # block_has_options: the block block_lines found in $target carries something the owner
839
- # chose: a standing authorization, a wiki root or a preference. Only install.py and
858
+ # chose: a pre-2.6 standing authorization, a wiki root or a preference. Only install.py and
840
859
  # scripts/install_personalization.py --keep-options carry those over to a new block.
841
860
  block_has_options() {
842
861
  head -n "$block_to" "$target" | tail -n "+$block_from" |
@@ -873,7 +892,7 @@ preview() {
873
892
  elif [ "$file_status" = refresh ]; then
874
893
  block_lines "$target"
875
894
  say "UPDATE: nobrainer-tech-flow personalization block"
876
- say "AUTO_UPDATE: CHECK_AND_NOTIFY"
895
+ say "AUTO_UPDATE: $(update_status)"
877
896
  say "AUTO_SESSION_RESTART: ASSESS_CHECKPOINT_RECOMMEND"
878
897
  say "PRESERVED: content outside the managed block"
879
898
  say "DIFF:"
@@ -881,7 +900,7 @@ preview() {
881
900
  block | sed 's/^/+/'
882
901
  else
883
902
  say "MISSING: nobrainer-tech-flow personalization block"
884
- say "AUTO_UPDATE: CHECK_AND_NOTIFY"
903
+ say "AUTO_UPDATE: $(update_status)"
885
904
  say "AUTO_SESSION_RESTART: ASSESS_CHECKPOINT_RECOMMEND"
886
905
  say "DIFF:"
887
906
  block | sed 's/^/+/'
@@ -1,14 +1,16 @@
1
1
  #!/usr/bin/env python3
2
2
  """Preview, add or remove the optional nobrainer-tech-flow guards for Claude Code.
3
3
 
4
- The guards are three hooks in the Claude Code user settings.json: a PreToolUse hook
5
- that asks before common risky shell commands, and Stop and SubagentStop hooks that
6
- ask for a proof line once. Every run is a preview until --apply. The hooks point at
7
- flow_guard.py through the skill link that scripts/install.py created, so they keep
8
- working when the checkout is updated. Our entries are the hooks whose command is
9
- exactly one this script generates; --undo --apply removes those and nothing else.
10
- The preview names only those hooks and the settings path, never other settings,
11
- which can hold tokens.
4
+ The guards are four hooks in the Claude Code user settings.json: a PreToolUse hook
5
+ that asks before common risky shell commands, Stop and SubagentStop hooks that ask
6
+ for a proof line once, and a SessionStart hook that, after compaction, resume or
7
+ clear, names the active Flow goal files to re-read. Every run is a preview until
8
+ --apply, and an install from an earlier version is reported as an update. The hooks
9
+ point at flow_guard.py through the skill link that scripts/install.py created, so
10
+ they keep working when the checkout is updated. Our entries are the hooks whose
11
+ command is exactly one this script generates; --undo --apply removes those and
12
+ nothing else. The preview names only those hooks and the settings path, never other
13
+ settings, which can hold tokens.
12
14
  """
13
15
 
14
16
  from __future__ import annotations
@@ -28,8 +30,14 @@ from pathlib import Path
28
30
  ROOT = Path(__file__).resolve().parents[1]
29
31
  INSTALL_SKILLS = ROOT / "scripts" / "install_skills.py"
30
32
  GUARD = Path("nobrainer-tech-flow") / "scripts" / "flow_guard.py"
31
- EVENTS = (("PreToolUse", "Bash", "pre-tool"), ("Stop", None, "stop"), ("SubagentStop", None, "stop"))
33
+ EVENTS = (
34
+ ("PreToolUse", "Bash", "pre-tool"),
35
+ ("Stop", None, "stop"),
36
+ ("SubagentStop", None, "stop"),
37
+ ("SessionStart", "compact|resume|clear", "session"),
38
+ )
32
39
  TIMEOUT = 10
40
+ DONE = {"add": "INSTALLED", "update": "UPDATED", "remove": "REMOVED"}
33
41
  DISCLAIMER = (
34
42
  "NOTE: a seatbelt: it asks before common risky commands; it is not a security "
35
43
  "boundary, and sh -c or variables bypass it."
@@ -223,18 +231,26 @@ def run(apply: bool, undo: bool, home: Path | None, rerun: str = "python3 script
223
231
  print(f"UP TO DATE: the Flow guards are already in {settings_path}; nothing changed")
224
232
  return 0
225
233
  after = render(updated)
234
+ # Some of our hooks but not exactly the current set, as an install from an earlier
235
+ # version leaves them: an update, never reported as current.
236
+ present = len(listed(settings, guard))
237
+ action = "remove" if undo else "update" if present else "add"
226
238
  if not apply:
227
239
  hooks = listed(settings if undo else updated, guard)
228
- verb = f"remove {len(hooks)} hooks from" if undo else f"add {len(hooks)} hooks to"
229
- print(f"PREVIEW: would {verb} {settings_path}; other settings keep their values:")
240
+ target = {
241
+ "remove": f"remove {len(hooks)} hooks from {settings_path}",
242
+ "update": f"update the Flow guards in {settings_path} ({present} hooks now, {len(hooks)} after)",
243
+ "add": f"add {len(hooks)} hooks to {settings_path}",
244
+ }[action]
245
+ print(f"PREVIEW: would {target}; other settings keep their values:")
230
246
  print("\n".join(hooks))
231
247
  if not undo:
232
248
  print(DISCLAIMER)
233
249
  flags = "--undo --apply" if undo else "--apply"
234
- print(f"NO_CHANGES: preview only; {'remove' if undo else 'add'} them with: {rerun.replace('{flags}', flags)}")
250
+ print(f"NO_CHANGES: preview only; {action} them with: {rerun.replace('{flags}', flags)}")
235
251
  return 0
236
252
  backup = write(settings_path, before, after)
237
- print(f"{'REMOVED' if undo else 'INSTALLED'}: Flow guards in {settings_path}")
253
+ print(f"{DONE[action]}: Flow guards in {settings_path}")
238
254
  if backup:
239
255
  print(f"BACKUP: {backup}")
240
256
  if not undo:
@@ -27,10 +27,17 @@ LEGACY_FLOW_INSTRUCTIONS = re.compile(
27
27
  r"\bnobrainer-ultra\b|^\s*#{1,6}\s+NoBrainer(?:[ .]?Tech)?\s+Flow\b",
28
28
  re.IGNORECASE | re.MULTILINE,
29
29
  )
30
- # The two lines that carry a standing authorization. --keep-options recognises a grant
30
+ # The lines that carry a standing authorization. --keep-options recognises a grant
31
31
  # only as one of these exact lines, never as a phrase somewhere in the block, so free
32
32
  # text in a preference cannot forge one.
33
- AUTO_UPDATE_RULE = "- On the first `nobrainer-tech-flow` use each calendar day, check for a safe verified update when this client exposes a supported check. This setting grants standing authorization to apply a `nobrainer-tech-flow`-only update after verifying the canonical source/version, reviewing the exact changes, and making a recoverable backup. Never apply destructive, unrelated, or uncertain changes; ask the owner first. If the client is inactive or cannot check, do not claim a check occurred."
33
+ AUTO_UPDATE_RULE = "- Once a day on first use, update nobrainer-tech-flow to its latest verified stable release from the canonical source, with a backup; change nothing else and ask if unsure."
34
+ # The opt-out written by --no-auto-update.
35
+ NOTIFY_UPDATE_RULE = "- Once a day on first use, tell the owner when a newer stable nobrainer-tech-flow release exists; do not update it yourself."
36
+ # Lines written before 2.6.0. --keep-options maps them to the short rules above and
37
+ # keeps the owner's choice: the old grant stays a grant, the old notify-only default
38
+ # stays notify-only.
39
+ LEGACY_AUTO_UPDATE_RULE = "- On the first `nobrainer-tech-flow` use each calendar day, check for a safe verified update when this client exposes a supported check. This setting grants standing authorization to apply a `nobrainer-tech-flow`-only update after verifying the canonical source/version, reviewing the exact changes, and making a recoverable backup. Never apply destructive, unrelated, or uncertain changes; ask the owner first. If the client is inactive or cannot check, do not claim a check occurred."
40
+ LEGACY_NOTIFY_UPDATE_RULE = "- On the first `nobrainer-tech-flow` use each calendar day, check for available updates when this client exposes a supported check and notify the owner; do not apply them automatically. If the client is inactive or cannot check, do not claim a check occurred."
34
41
  AUTO_SESSION_RULE = "- This setting grants standing authorization for session rotation only when the host supports creating a fresh successor, context or checkpoint evidence warrants rotation, and no write is in flight. Create the successor, verify exact takeover by ID/readback, and archive the old session only after that readback. Do not create recursive visible workers or claim a restart when unsupported."
35
42
 
36
43
 
@@ -57,6 +64,28 @@ def earlier_grant(existing: str, rule: str, phrase: str, label: str, flag: str)
57
64
  return False
58
65
 
59
66
 
67
+ # Wording of an update grant, current or pre-2.6, used only to warn that an edited one
68
+ # was not kept.
69
+ UPDATE_GRANT_PHRASES = (
70
+ "update nobrainer-tech-flow to its latest verified stable release",
71
+ "grants standing authorization to apply a `nobrainer-tech-flow`-only update",
72
+ )
73
+
74
+
75
+ def saved_update_choice(existing: str) -> bool:
76
+ """True only when an existing block holds an update grant as its own line.
77
+
78
+ Anything else, a notify-only line, an edited or unknown one, keeps notifying:
79
+ an update grant is never inferred. Trailing spaces on the line are ignored, and
80
+ a preference that quotes the wording is not a line of its own.
81
+ """
82
+
83
+ return any(
84
+ re.search(r"(?m)^" + re.escape(rule) + r"[ \t]*\r?$", existing) is not None
85
+ for rule in (AUTO_UPDATE_RULE, LEGACY_AUTO_UPDATE_RULE)
86
+ )
87
+
88
+
60
89
  def unsafe_line(value: str) -> bool:
61
90
  """True when ``value`` cannot be one plain Markdown line (or could split into two)."""
62
91
 
@@ -85,11 +114,7 @@ def build_block(
85
114
  if wiki_root is not None
86
115
  else "- At project start, discover whether a relevant wiki exists. If one exists, read its `WIKI.md`, locate relevant `index.md` entries with a targeted search, then read only the relevant pages. Ask before creating a wiki unless project rules or prior authorization already settle it."
87
116
  )
88
- update_rule = (
89
- AUTO_UPDATE_RULE
90
- if auto_update
91
- else "- On the first `nobrainer-tech-flow` use each calendar day, check for available updates when this client exposes a supported check and notify the owner; do not apply them automatically. If the client is inactive or cannot check, do not claim a check occurred."
92
- )
117
+ update_rule = AUTO_UPDATE_RULE if auto_update else NOTIFY_UPDATE_RULE
93
118
  session_rule = (
94
119
  AUTO_SESSION_RULE
95
120
  if auto_session_restart
@@ -105,7 +130,7 @@ def build_block(
105
130
 
106
131
  - Use the `nobrainer-tech-flow` module as the task entrypoint when this client supports skill invocation, by the exact name this client lists for it. In Codex that is `$nobrainer-tech-flow:nobrainer-tech-flow` when modules are listed under the plugin name, or `$nobrainer-tech-flow` when they are listed plainly. If unavailable, check the documented installation path and report that limitation honestly.
107
132
  - On first setup, load `nobrainer-auto-fine-tune` for a read-only capability audit; preserve MAIN model and effort, and mark unverified runtime values `UNKNOWN`.
108
- - Preserve the user's selected MAIN model and effort. Inspect the host's actual subagent models, capabilities, concurrency and quota; delegate every independent ready unit promptly and refill slots after audited completion. Keep coordination in MAIN. Never assume a model is available or silently substitute one.
133
+ - Preserve the user's selected MAIN model and effort. Inspect the host's actual subagent models, capabilities, concurrency and quota; work in one MAIN loop and delegate only units that gain from parallel work, context isolation, independent review or specialization. Keep coordination in MAIN. Never assume a model is available or silently substitute one.
109
134
  - Split substantial work into bounded tasks with clear outputs, exclusive write scope, dependencies, and verification. Keep integration and acceptance in MAIN; avoid duplicate or filler tasks.
110
135
  - Derive short-term goals from the user's long-term direction (LDD) and define observable completion criteria. At project start, inspect the existing structure and layers, then recommend a fitting approach.
111
136
  {wiki_rule}
@@ -356,10 +381,16 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
356
381
  type=Path,
357
382
  help="project wiki root containing WIKI.md; its resolved path is added to the managed instructions",
358
383
  )
359
- parser.add_argument(
384
+ updates = parser.add_mutually_exclusive_group()
385
+ updates.add_argument(
360
386
  "--auto-update",
361
387
  action="store_true",
362
- help="authorize safe, verified nobrainer-tech-flow-only updates; default is check and notify",
388
+ help="update nobrainer-tech-flow once a day from its verified stable releases (the default)",
389
+ )
390
+ updates.add_argument(
391
+ "--no-auto-update",
392
+ action="store_true",
393
+ help="only tell the owner about a newer stable release; never update automatically",
363
394
  )
364
395
  parser.add_argument(
365
396
  "--auto-session-restart",
@@ -374,7 +405,7 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
374
405
  "--keep-options",
375
406
  action="store_true",
376
407
  help=(
377
- "keep the auto-update, session-restart and wiki-root settings already in the "
408
+ "keep the update, session-restart and wiki-root settings already in the "
378
409
  "managed block; flags given on this run are added to them, never removed"
379
410
  ),
380
411
  )
@@ -429,15 +460,19 @@ def main(argv: list[str] | None = None) -> int:
429
460
  saved = SAVED_PREFERENCE.search(existing)
430
461
  if saved:
431
462
  preferences = saved.group(1)
432
- auto_update = args.auto_update
463
+ auto_update = not args.no_auto_update
433
464
  auto_session_restart = args.auto_session_restart
434
465
  if args.keep_options and existing:
435
466
  kept: list[str] = []
436
- if not auto_update and earlier_grant(
437
- existing, AUTO_UPDATE_RULE, "grants standing authorization to apply", "auto-update", "--auto-update"
438
- ):
439
- auto_update = True
440
- kept.append("auto-update")
467
+ saved_update = saved_update_choice(existing)
468
+ if not (args.auto_update or args.no_auto_update) and not saved_update:
469
+ auto_update = False
470
+ kept.append("notify-only updates")
471
+ if any(phrase in existing for phrase in UPDATE_GRANT_PHRASES):
472
+ print(
473
+ "NOTE: an earlier update authorization was not kept because its line no longer "
474
+ "matches what this installer writes; pass --auto-update to grant it again"
475
+ )
441
476
  if not auto_session_restart and earlier_grant(
442
477
  existing,
443
478
  AUTO_SESSION_RULE,
@@ -27,7 +27,7 @@ Keep advertised, configured, callable, and successfully invoked capabilities dis
27
27
 
28
28
  For a one-off, low-risk task, use the owner's selected MAIN and current known tools; skip benchmarking and state that routing is uncalibrated. For a recurring workflow, material model choice, or task with meaningful quality/latency/cost tradeoffs, define a small bounded comparison before spending resources.
29
29
 
30
- Classify the work by required expertise, context, accuracy, latency, cost sensitivity, confidentiality, dependence between units, and integration effort. Calibration follows the delegation-first default for independent units with measurable acceptance and disjoint write scope. A missing benchmark or measured speed gain does not block eligible dispatch. When comparing routes, measure the critical path and observed concurrency, including setup, review and integration; worker count alone proves no benefit.
30
+ Classify the work by required expertise, context, accuracy, latency, cost sensitivity, confidentiality, dependence between units, and integration effort. MAIN is the default; calibration compares worker routes only for units that qualify under [team execution](../nobrainer-tech-flow/references/delivery.md#coordinated-team-execution) and have measurable acceptance and disjoint write scope. A missing benchmark does not block a qualifying unit's dispatch. When comparing routes, measure the critical path and observed concurrency, including setup, review and integration; worker count alone proves no benefit.
31
31
 
32
32
  ## Run a bounded, comparable calibration
33
33
 
@@ -26,6 +26,17 @@ Before the first write, resolve:
26
26
  - cheapest useful failing proof, target tests, broader verifier/build/runtime;
27
27
  - side effects, owner gates, rollback and the `Done clean` condition.
28
28
 
29
+ When instruction files or docs describe a coding convention the existing code
30
+ does not follow, do not pick one silently. Follow the convention the code uses,
31
+ unless the instruction is an explicit owner rule or names a deliberate migration,
32
+ and list each disagreement in the final report. When the code's convention wins,
33
+ include the exact edit that would bring the stale instruction file in line, and
34
+ apply it only as the project's `LEARNING_WRITE_POLICY` allows
35
+ ([correction hooks](../nobrainer-tech-flow/references/correction-hooks.md)), so the
36
+ next run does not inherit the stale rule. When an owner rule or migration wins,
37
+ name the code change it requires instead. Owner rules on safety, authority and
38
+ workflow always apply.
39
+
29
40
  Preserve unrelated changes. Use an isolated worktree or disjoint write scope
30
41
  when another writer is active. If a missing requirement changes architecture,
31
42
  scope, public behavior or safety, stop at `SPEC_CHANGE_PROPOSED`; do not invent it
@@ -37,7 +48,9 @@ Apply these principles as decision rules, not slogans:
37
48
 
38
49
  - `KISS`: choose the simplest complete design that satisfies acceptance.
39
50
  - `YAGNI`: do not add extension points, compatibility layers or options for an
40
- unproven future requirement.
51
+ unproven future requirement. Before adding complexity for a speculative race
52
+ or security edge case, name the concrete failure, its likelihood and the cost;
53
+ add it only when that case is accepted.
41
54
  - `DRY`: keep each rule and mutable fact under one owner, but do not abstract
42
55
  incidental similarity. Duplication can be cheaper than the wrong coupling.
43
56
  - `SOLID`: preserve cohesive responsibilities and stable dependency boundaries;
@@ -80,7 +93,9 @@ Reject a patch that contains any of the following without explicit acceptance:
80
93
  - duplicate state owners, speculative abstractions or fallback stacks that make
81
94
  failure ambiguous;
82
95
  - tests that only assert a mock/fixture while the real contract remains
83
- unexercised.
96
+ unexercised;
97
+ - in user interfaces, taglines, helper text and secondary labels added to explain
98
+ a screen; if the screen needs them, fix the layout.
84
99
 
85
100
  Names should explain intent. Comments should explain only non-obvious why,
86
101
  constraints, risk or tradeoffs. Do not create a new README, framework or process
@@ -137,6 +137,11 @@ constraint, deployment setting, parser behavior or version fact that would make
137
137
  the path unreachable. Reject generic hardening, style preferences, stale
138
138
  advisories for another version and speculative chains missing a necessary step.
139
139
 
140
+ One model pass samples the scope; it does not prove coverage. Before `CLEAN`,
141
+ run at least one more independent pass that starts from a different entry point,
142
+ trust boundary or data-flow direction. Stop when a pass adds no new verified
143
+ finding, and report how many passes ran.
144
+
140
145
  ## Handoff and remediation
141
146
 
142
147
  Security review ends with evidence and a fix contract. If remediation is in
@@ -146,6 +151,11 @@ security trace with fresh evidence. Consequential fixes still require an
146
151
  independent `nobrainer-review` or release gate; self-authored code is not
147
152
  self-approved.
148
153
 
154
+ A fix closes the path; it does not show the path was never used. When the
155
+ defect was public or reachable before the fix, check the available logs or
156
+ other evidence for exploitation during that exposure window. If that evidence
157
+ is unavailable, list the window under `UNTESTED_OR_INACCESSIBLE_SURFACE`.
158
+
149
159
  ## Final report
150
160
 
151
161
  ```text