moflo 4.12.4 → 4.12.6

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 (110) hide show
  1. package/.claude/guidance/shipped/moflo-agent-rules.md +1 -0
  2. package/.claude/guidance/shipped/moflo-claude-swarm-cohesion.md +1 -1
  3. package/.claude/guidance/shipped/moflo-cli-reference.md +4 -4
  4. package/.claude/guidance/shipped/moflo-core-guidance.md +4 -4
  5. package/.claude/guidance/shipped/moflo-guidance-rules.md +21 -0
  6. package/.claude/guidance/shipped/moflo-inline-fixes.md +98 -0
  7. package/.claude/guidance/shipped/moflo-root-cause-discipline.md +10 -10
  8. package/.claude/guidance/shipped/moflo-sdd.md +5 -5
  9. package/.claude/guidance/shipped/moflo-spell-engine.md +1 -1
  10. package/.claude/guidance/shipped/moflo-yaml-reference.md +8 -8
  11. package/.claude/helpers/gate.cjs +46 -7
  12. package/.claude/helpers/pr-create-command.cjs +440 -0
  13. package/.claude/skills/eldar/SKILL.md +1 -1
  14. package/.claude/skills/fl/SKILL.md +6 -6
  15. package/.claude/skills/fl/execution-modes.md +3 -3
  16. package/.claude/skills/fl/phases.md +8 -8
  17. package/.claude/skills/fl/sdd.md +6 -6
  18. package/.claude/skills/guidance/SKILL.md +3 -0
  19. package/.claude/skills/verify/SKILL.md +4 -4
  20. package/bin/gate.cjs +46 -7
  21. package/bin/hooks.mjs +4 -1
  22. package/bin/lib/retired-files.mjs +38 -6
  23. package/bin/lib/shipped-scripts.json +2 -1
  24. package/bin/lib/skill-categories.mjs +81 -17
  25. package/bin/pr-create-command.cjs +440 -0
  26. package/bin/session-start-launcher.mjs +11 -6
  27. package/dist/src/cli/aidefence/domain/entities/threat.js +2 -1
  28. package/dist/src/cli/commands/doctor-checks-deep.js +3 -2
  29. package/dist/src/cli/commands/doctor-checks-memory-access.js +3 -2
  30. package/dist/src/cli/commands/doctor-checks-swarm.js +3 -2
  31. package/dist/src/cli/commands/doctor-fixes.js +119 -20
  32. package/dist/src/cli/commands/hooks.js +2 -1
  33. package/dist/src/cli/commands/mcp.js +3 -2
  34. package/dist/src/cli/commands/memory.js +2 -1
  35. package/dist/src/cli/commands/performance.js +2 -1
  36. package/dist/src/cli/commands/retire.js +1 -1
  37. package/dist/src/cli/commands/spell-schedule.js +2 -1
  38. package/dist/src/cli/commands/swarm.js +216 -104
  39. package/dist/src/cli/guidance/headless.js +5 -8
  40. package/dist/src/cli/guidance/retriever.js +27 -6
  41. package/dist/src/cli/guidance/ruvbot-integration.js +2 -1
  42. package/dist/src/cli/guidance/uncertainty.js +2 -1
  43. package/dist/src/cli/hooks/bridge/official-hooks-bridge.js +2 -1
  44. package/dist/src/cli/hooks/mcp/index.js +3 -2
  45. package/dist/src/cli/hooks/reasoningbank/index.js +2 -1
  46. package/dist/src/cli/hooks/registry/index.js +2 -1
  47. package/dist/src/cli/hooks/swarm/index.js +6 -5
  48. package/dist/src/cli/init/claudemd-generator.js +2 -1
  49. package/dist/src/cli/init/helpers-generator.js +1 -1
  50. package/dist/src/cli/init/moflo-yaml-template.js +4 -4
  51. package/dist/src/cli/mcp-client.js +5 -2
  52. package/dist/src/cli/mcp-tools/agent-tools.js +4 -1
  53. package/dist/src/cli/mcp-tools/hive-mind-tools.js +4 -3
  54. package/dist/src/cli/mcp-tools/hooks-tools.js +6 -5
  55. package/dist/src/cli/mcp-tools/json-store.js +3 -2
  56. package/dist/src/cli/mcp-tools/neural-tools.js +2 -1
  57. package/dist/src/cli/mcp-tools/performance-tools.js +2 -1
  58. package/dist/src/cli/mcp-tools/session-tools.js +4 -2
  59. package/dist/src/cli/mcp-tools/spell-tools.js +2 -1
  60. package/dist/src/cli/memory/bridge-core.js +8 -2
  61. package/dist/src/cli/memory/controllers/_shared.js +8 -2
  62. package/dist/src/cli/memory/controllers/nightly-learner.js +2 -1
  63. package/dist/src/cli/memory/domain/services/memory-domain-service.js +2 -1
  64. package/dist/src/cli/memory/entries-write.js +2 -1
  65. package/dist/src/cli/memory/intelligence.js +2 -1
  66. package/dist/src/cli/memory/persistent-sona.js +1 -3
  67. package/dist/src/cli/memory/types.js +2 -3
  68. package/dist/src/cli/memory/verify.js +3 -2
  69. package/dist/src/cli/movector/graph-analyzer.js +14 -3
  70. package/dist/src/cli/neural/pattern-learner.js +4 -2
  71. package/dist/src/cli/neural/reasoning-bank.js +2 -1
  72. package/dist/src/cli/neural/reasoningbank-adapter.js +2 -1
  73. package/dist/src/cli/neural/sona-manager.js +4 -3
  74. package/dist/src/cli/production/monitoring.js +2 -1
  75. package/dist/src/cli/services/daemon-service.js +57 -46
  76. package/dist/src/cli/services/daemon-spell-executor.js +3 -2
  77. package/dist/src/cli/services/headless-worker-executor.js +4 -2
  78. package/dist/src/cli/services/learning-service.js +2 -1
  79. package/dist/src/cli/services/project-root.js +17 -1
  80. package/dist/src/cli/services/worker-daemon.js +2 -1
  81. package/dist/src/cli/shared/hooks/example-usage.js +3 -2
  82. package/dist/src/cli/shared/hooks/safety/git-commit.js +11 -2
  83. package/dist/src/cli/shared/hooks/session-hooks.js +3 -2
  84. package/dist/src/cli/shared/hooks/task-hooks.js +2 -1
  85. package/dist/src/cli/shared/mcp/session-manager.js +2 -1
  86. package/dist/src/cli/shared/plugins/official/hive-mind-plugin.js +2 -1
  87. package/dist/src/cli/shared/plugins/official/maestro-plugin.js +3 -2
  88. package/dist/src/cli/shared/security/index.js +6 -2
  89. package/dist/src/cli/shared/utils/atomic-file-write.js +9 -1
  90. package/dist/src/cli/shared/utils/id.js +54 -0
  91. package/dist/src/cli/shared/utils/platform.js +36 -5
  92. package/dist/src/cli/spells/commands/destructive-pattern-checker.js +6 -1
  93. package/dist/src/cli/spells/core/dry-run-validator.js +2 -1
  94. package/dist/src/cli/spells/core/interpolation.js +8 -3
  95. package/dist/src/cli/spells/core/permission-resolver.js +2 -2
  96. package/dist/src/cli/spells/core/runner.js +2 -1
  97. package/dist/src/cli/spells/core/shell.js +7 -8
  98. package/dist/src/cli/spells/factory/runner-bridge.js +3 -2
  99. package/dist/src/cli/spells/factory/runner-factory.js +3 -2
  100. package/dist/src/cli/spells/scheduler/scheduler.js +2 -1
  101. package/dist/src/cli/swarm/consensus/gossip.js +2 -1
  102. package/dist/src/cli/swarm/federation-hub.js +5 -4
  103. package/dist/src/cli/swarm/queen-coordinator.js +5 -4
  104. package/dist/src/cli/swarm/shared/events.js +2 -1
  105. package/dist/src/cli/swarm/unified-coordinator.js +3 -2
  106. package/dist/src/cli/version.js +1 -1
  107. package/package.json +2 -2
  108. package/retired-files.json +0 -72
  109. package/dist/src/cli/mcp-tools/coordination-tools.js +0 -86
  110. package/dist/src/cli/shared/security/secure-random.js +0 -142
@@ -176,6 +176,7 @@ npx flo memory store --namespace patterns --key "brief-descriptive-key" --value
176
176
 
177
177
  ## See Also
178
178
 
179
+ - `.claude/guidance/moflo-inline-fixes.md` — Fix-vs-file rule for defects found mid-PR; the default is to fix them in the PR you are already in
179
180
  - `.claude/guidance/moflo-subagents.md` — Spawn protocol that consumes these universal rules
180
181
  - `.claude/guidance/moflo-task-icons.md` — Full ICON + [Role] format and icon map
181
182
  - `.claude/guidance/moflo-claude-swarm-cohesion.md` — How `TaskCreate` and swarm coordination layer on top of these rules
@@ -119,7 +119,7 @@ TaskList() // Shows what's now unblocked
119
119
  TaskUpdate({ taskId: "2", status: "in_progress" }) // Next agent starts
120
120
  ```
121
121
 
122
- Close every task you open. moflo's PR gate reads the session transcript on `gh pr create` and prints `N tasks created this session, M still open` (#1374) — an unclosed list reports as unfinished work on the PR. Mark tasks that no longer apply `status: "deleted"`; that closes the loop exactly like `completed`.
122
+ Close every task you open. moflo's PR gate reads the session transcript on `gh pr create` and prints `N tasks created this session, M still open` — an unclosed list reports as unfinished work on the PR. Mark tasks that no longer apply `status: "deleted"`; that closes the loop exactly like `completed`.
123
123
 
124
124
  ---
125
125
 
@@ -61,7 +61,7 @@ npx flo daemon start
61
61
 
62
62
  ## Available Agents
63
63
 
64
- The shipped agent roster — each is invoked via the `Agent` tool with `subagent_type: <name>`. The canonical handle is the `name:` frontmatter inside `.claude/agents/**/*.md` (filename may differ from agent name). Aspirational agents that never shipped were retired in #932 — `retired-files.json` enforces auto-prune on consumer upgrade.
64
+ The shipped agent roster — each is invoked via the `Agent` tool with `subagent_type: <name>`. The canonical handle is the `name:` frontmatter inside `.claude/agents/**/*.md` (filename may differ from agent name). Aspirational agents that never shipped were retired — `retired-files.json` enforces auto-prune on consumer upgrade.
65
65
 
66
66
  ### Core Development
67
67
  `coder`, `reviewer`, `tester`, `planner`, `researcher`, `analyst`
@@ -119,10 +119,10 @@ The orchestrator is the calling Claude, not a named agent. Pick specialists from
119
119
  ### Background Workers
120
120
 
121
121
  The daemon ships seven workers — two scheduled by default (both local, no
122
- model calls) plus five manual-trigger only. The pre-#970 `audit`, `predict`,
122
+ model calls) plus five manual-trigger only. The earlier `audit`, `predict`,
123
123
  and `document` workers were removed because they ran without a surfacing
124
- layer for findings. The `optimize` and `testgaps` workers were removed in
125
- #1258 — they were the only default-ON workers that spawned billed
124
+ layer for findings. The `optimize` and `testgaps` workers were also
125
+ removed — they were the only default-ON workers that spawned billed
126
126
  `claude --print` agents, on a 15/20-min timer with no change-detection, and
127
127
  their reports were never surfaced. Their capability now lives in the ad-hoc
128
128
  `/quicken` (perf) and `/ward` (test-gap) skills, which scope to the diff and
@@ -16,7 +16,7 @@
16
16
  | Claude Desktop (the macOS/Windows app) | **Out of scope — never** | None — moflo neither reads nor writes Claude Desktop config |
17
17
  | Other MCP-capable clients (Cline, Continue, etc.) | Unsupported, may incidentally work | None — bug reports require Claude Code reproduction |
18
18
 
19
- **Never** introduce a code path, search list, fixture, or doc that reads from or writes to `~/.claude/claude_desktop_config.json`, `~/Library/Application Support/Claude/`, or `%APPDATA%/Claude/`. Those are Claude **Desktop** paths. Including them in moflo's MCP-config search list caused issue #1126: a parseable Claude Desktop preferences file outranked a malformed project `.mcp.json`, masking the real failure and routing the auto-fixer down a no-op branch.
19
+ **Never** introduce a code path, search list, fixture, or doc that reads from or writes to `~/.claude/claude_desktop_config.json`, `~/Library/Application Support/Claude/`, or `%APPDATA%/Claude/`. Those are Claude **Desktop** paths. Including them in moflo's MCP-config search list has already caused one regression: a parseable Claude Desktop preferences file outranked a malformed project `.mcp.json`, masking the real failure and routing the auto-fixer down a no-op branch.
20
20
 
21
21
  The one ambiguous-looking path is Claude Code's user-level config at `~/.claude.json` (where `claude mcp add` writes). MoFlo doesn't author or rewrite that file either; the project-local `.mcp.json` written by `flo init` is the canonical surface moflo owns end-to-end.
22
22
 
@@ -145,7 +145,7 @@ For the full `moflo.yaml` schema, gate toggles, model routing, and sandbox confi
145
145
  | Every 5+ file changes | `map` worker | Update codebase map (local, automatic) |
146
146
  | Complex debugging | `deepdive` worker | Deep code analysis (manual trigger) |
147
147
 
148
- **Performance and test-gap analysis are ad-hoc skills, not background workers.** The old always-on `optimize`/`testgaps` daemon workers were removed in #1258 — they were billed `claude --print` loops with no change-detection whose reports were never surfaced. Run `/quicken` and `/ward` when you want them; they scope to the diff and report in the conversation.
148
+ **Performance and test-gap analysis are ad-hoc skills, not background workers.** The old always-on `optimize`/`testgaps` daemon workers were removed — they were billed `claude --print` loops with no change-detection whose reports were never surfaced. Run `/quicken` and `/ward` when you want them; they scope to the diff and report in the conversation.
149
149
 
150
150
  ### Worker Report Location
151
151
 
@@ -184,7 +184,7 @@ Checks: Node version (20+), Git, config validity, daemon status, memory database
184
184
 
185
185
  ## Monorepo Layout
186
186
 
187
- **Purpose:** prevent the most common moflo misconfig — daemon islands in monorepos (#1174).
187
+ **Purpose:** prevent the most common moflo misconfig — daemon islands in monorepos.
188
188
 
189
189
  | Rule | Why |
190
190
  |------|-----|
@@ -209,7 +209,7 @@ The resolver (`findProjectRoot`) prefers the topmost ancestor with `.moflo/moflo
209
209
  | Embeddings fail offline / air-gapped | `fastembed` model cache missing | Pre-populate `~/.cache/fastembed` or set `FASTEMBED_CACHE` (see `docs/modules/embeddings.md`) |
210
210
  | `flo` command not found | Not in PATH | Use `npx flo` or `node node_modules/moflo/bin/index-guidance.mjs` |
211
211
  | Bundled guidance not indexed | Running inside the moflo repo | Bundled guidance only indexes when installed as a dependency in a different project |
212
- | `mcp__moflo__*` tools missing in monorepo session | Nested `.moflo/` directories spawned separate daemons (#1174) | Run `flo doctor -c nested-moflo`; if any are found, `flo doctor --fix -c nested-moflo` archives them. Restart Claude Code to reconnect. |
212
+ | `mcp__moflo__*` tools missing in monorepo session | Nested `.moflo/` directories spawned separate daemons | Run `flo doctor -c nested-moflo`; if any are found, `flo doctor --fix -c nested-moflo` archives them. Restart Claude Code to reconnect. |
213
213
 
214
214
  See `.claude/guidance/moflo-memory-strategy.md` for memory-specific troubleshooting and `.claude/guidance/moflo-spell-troubleshooting.md` for spell sandbox/network failures.
215
215
 
@@ -145,6 +145,27 @@ Use relative names (not absolute paths) so the links work across project context
145
145
 
146
146
  ---
147
147
 
148
+ ## 10. Never Cite Issue or PR Numbers
149
+
150
+ **Write the rule, not where it came from.** Strip every `(#NNNN)`, `issue #NNNN`, `Epic #NNNN`, and `per PR #NNNN` from guidance. A reader who hits a bare issue number cannot resolve it without leaving the document, and in guidance that ships between projects the number points at the *reader's* issue tracker, not the author's — so it is worse than useless there. Provenance belongs in `git log` and `git blame`, which is where it stays accurate.
151
+
152
+ The cost is not just confusion. Guidance is loaded, chunked, and RAG-retrieved on nearly every task, so an unresolvable citation is a permanent context tax that dilutes the rule it is attached to.
153
+
154
+ Below, `#NNNN` stands in for a real issue number — written that way so these examples do not themselves violate the rule.
155
+
156
+ | Instead of | Write |
157
+ |---|---|
158
+ | `verify_before_done` is on by default (#NNNN) | `verify_before_done` is on by default |
159
+ | Never run `flo init` in a sub-workspace (issue #NNNN) | Never run `flo init` in a sub-workspace |
160
+ | The `optimize` worker was removed in #NNNN — it was a billed loop | The `optimize` worker was removed — it was a billed loop |
161
+ | `### Case Study: #NNNN Hive-Mind Shutdown` | `### Case Study: Hive-Mind Shutdown Flake` |
162
+
163
+ **When the number is load-bearing, relabel — don't just delete.** A case-study heading or a table keyed by `#NNNN layer 1` / `#NNNN attempt 4` uses the numbers to carry a *sequence*. Replace them with descriptive ordinals (`Attempt 1`, `Attempt 2`) so the progression survives.
164
+
165
+ **This applies to every reader-facing surface, not just `.md` guidance** — skills, agent definitions, slash commands, and any template your tooling writes into a project (a generated `CLAUDE.md` block, a scaffolded config file). Source-code comments in your own repo are exempt: they are read where the number resolves.
166
+
167
+ ---
168
+
148
169
  ## See Also
149
170
 
150
171
  - `.claude/guidance/moflo-memory-strategy.md` — Companion rules on namespaces, RAG indexing, and search patterns the data feeds
@@ -0,0 +1,98 @@
1
+ # Inline Fixes — Resolve Small Defects in the PR You Are Already In
2
+
3
+ **Purpose:** Decide between "fix it here" and "file a follow-up" when a defect surfaces while you are working on something else. The default is **fix it here**. Opening a separate ticket for a small problem spends a full issue → branch → research → tests → review → PR → merge cycle on a change that a reviewer confirms in thirty seconds, and it is the single most common way agent work becomes slower than doing it by hand.
4
+
5
+ ---
6
+
7
+ ## 1. The Default Is Fix, Not File
8
+
9
+ **Fix a small defect in the PR you are already in.** Do not open a ticket, do not branch a new cycle, do not defer it to "follow-up".
10
+
11
+ Filing is the exception and must be earned. Before you file, name which threshold in the table below the defect crosses. If you cannot name one, fix it.
12
+
13
+ **Never file a ticket to record work you could have finished in the time it took to write the ticket.** A ticket that says "rename this variable" costs more to triage than the rename costs to do.
14
+
15
+ ---
16
+
17
+ ## 2. Trivial vs. Non-Trivial Decision Table
18
+
19
+ The split is about review burden and blast radius, not line count alone.
20
+
21
+ | Signal | Fix inline | File separately |
22
+ |--------|-----------|-----------------|
23
+ | Net production LOC | ≤ ~10 | > ~10 or spans multiple subsystems |
24
+ | New tests required | 0–1 small assertion | dedicated test file or several new tests |
25
+ | Public API surface | unchanged | adds, removes, or renames an export |
26
+ | Behaviour change | matches intent already documented | could surprise a consumer |
27
+ | Reviewer friction | confirmable in under 30 seconds | needs context this PR does not carry |
28
+ | Relationship to the main fix | same file or same subsystem | different subsystem entirely |
29
+ | Risk if shipped wrong | reverts cleanly in one commit | needs a coordinated migration |
30
+
31
+ **Any single row in the right column flips it to non-trivial.** A three-line fix in an unrelated subsystem is non-trivial, because the reviewer of your PR has no context for it.
32
+
33
+ ---
34
+
35
+ ## 3. Defects Your Own Work Surfaces Are Never Follow-Ups
36
+
37
+ A defect that your change **caused, unmasked, or invalidated** is part of the change. It is not a discovery to be logged.
38
+
39
+ | Situation | Action |
40
+ |-----------|--------|
41
+ | A test you just made red | Fix it now, in this PR |
42
+ | A lint, type, or build error your edit introduced | Fix it now |
43
+ | A stale bound, count, or snapshot your change invalidated | Update it now |
44
+ | A test that pinned the exact bug you are fixing | Update the test in the same commit |
45
+ | A reviewer comment on this PR | Address it in this PR |
46
+ | A neighbouring function with the same defect you just fixed | Fix it here if it clears the table above |
47
+
48
+ Treating any of these as a separate ticket ships a knowingly broken tree and asks a human to re-triage work that was already in your hands.
49
+
50
+ ---
51
+
52
+ ## 4. Batch Fixes; Do Not Serialise CI Rounds
53
+
54
+ **Group related fixes into one push.** Every push burns a full CI round, and reviewers re-read the diff each time.
55
+
56
+ - Fix everything you have found, then run the suite once, then push once.
57
+ - Do not push a one-line fix, wait for CI, then push the next one-line fix.
58
+ - When several small defects share a root cause, fix the cause and say so, rather than patching each symptom in its own commit.
59
+
60
+ Serialised single-fix rounds are slower than one careful pass, and they make the change history harder to read for no gain.
61
+
62
+ ---
63
+
64
+ ## 5. How to Surface Inline Fixes
65
+
66
+ Bundling is not hiding. Make every drive-by visible:
67
+
68
+ - **In the commit body** — one bullet under `Also fixed:`.
69
+ - **In the PR description** — the same bullets under a `## Drive-by fixes` heading.
70
+ - **Do not retitle the PR.** The main subject stays the original fix; drive-bys are footnotes.
71
+
72
+ ```
73
+ fix(cli): drain stdout/stderr before exit to avoid a Windows async-pipe race
74
+
75
+ [main fix description]
76
+
77
+ Also fixed:
78
+ - Removed a redundant `stream.destroyed` check already covered by `!stream.writable`.
79
+ - Corrected the module-count lower bound this change invalidated.
80
+ ```
81
+
82
+ ---
83
+
84
+ ## 6. When an Inline Fix Grows
85
+
86
+ If a fix expands past the trivial threshold mid-flight — the "one-line check" turns out to need three new tests and a migration — **stop and back out**. File it, and stay focused on the original PR.
87
+
88
+ The decision point is the moment you realise the fix is not trivial. Catching it there keeps the discipline without bloating the PR. An over-scoped PR is expensive; a deferred trivial fix is more expensive still.
89
+
90
+ **When you do file, finish the rest first.** Deliver every part of the current work that is not blocked, then state plainly what you left out and why. Never stop the whole task to file a ticket.
91
+
92
+ ---
93
+
94
+ ## See Also
95
+
96
+ - `.claude/guidance/moflo-agent-rules.md` — Git, branch, and PR conventions these fixes land through
97
+ - `.claude/guidance/moflo-root-cause-discipline.md` — Fixing the cause rather than the symptom, which is what makes a batch of small fixes collapse into one
98
+ - `.claude/guidance/moflo-guidance-rules.md` — Universal writing rules this doc follows
@@ -52,7 +52,7 @@ When fix N didn't work, do these in order — not in parallel, not skipping step
52
52
  1. **Read every prior fix on this surface in full.** Not the commit message — the code. Note what each one was trying to prevent and what it actually does.
53
53
  2. **Reproduce the failure deterministically** before touching code. If you can't reproduce it, you don't understand it.
54
54
  3. **Trace the data flow.** Where does the bad state originate? What writes it? What reads it? What invariant got violated?
55
- 4. **Question the test, not just the code.** What invariant does the failing test actually encode? Does that invariant match the runtime contract, or is the test stricter? A test stricter than the contract will produce flakes that look like bugs but aren't. (See #1017 case study.)
55
+ 4. **Question the test, not just the code.** What invariant does the failing test actually encode? Does that invariant match the runtime contract, or is the test stricter? A test stricter than the contract will produce flakes that look like bugs but aren't. (See the hive-mind shutdown case study below.)
56
56
  5. **Identify the structural cause** — the place where the bug becomes possible, not the place where it becomes visible.
57
57
  6. **Now consider fixes.** The cheapest fix at the structural cause beats the cleverest fix at the symptom every time. If the cause is "test asserts X, runtime contract is Y, X is stricter," the fix is in the test.
58
58
 
@@ -105,9 +105,9 @@ When you find that the test is the actual problem: change the test, document why
105
105
 
106
106
  **Smell test:** read the test setup as a description of production behavior. If steps appear that production code does not perform, the test is mocking around a real bug.
107
107
 
108
- ### Case Study: #1053 Memory Traversal
108
+ ### Case Study: Memory Traversal Healer Probe
109
109
 
110
- > "Healer: probeMemoryGetNeighbors() runs first in checkMemoryAccessFunctional so the bridge instantiates after the seed lands (sql.js whole-DB writeback clobbers external file writes once the in-memory snapshot warms)." — PR #1053 commit
110
+ > "Healer: probeMemoryGetNeighbors() runs first in checkMemoryAccessFunctional so the bridge instantiates after the seed lands (sql.js whole-DB writeback clobbers external file writes once the in-memory snapshot warms)." — the fix commit
111
111
 
112
112
  Diagnosis correct; fix wrong. The clobber stayed in production. `moflo@4.9.37` shipped two regressions to every consumer (migration-induced embedding loss + `memory_store` silent drop) because the suite was engineered around the failure it had just detected.
113
113
 
@@ -120,18 +120,18 @@ Diagnosis correct; fix wrong. The clobber stayed in production. `moflo@4.9.37` s
120
120
 
121
121
  ---
122
122
 
123
- ## Concrete Example: #1017 Hive-Mind Shutdown
123
+ ## Concrete Example: Hive-Mind Shutdown Flake
124
124
 
125
125
  This is the canonical case study for this guidance — and it has a second-order lesson that makes it even more useful.
126
126
 
127
127
  | Attempt | Approach | Outcome |
128
128
  |---------|----------|---------|
129
- | #1017 first try | Loop list+delete in `clearNamespace` | Race window remained — broadcasts landed mid-loop |
130
- | #1024 layer 1 | Detach adapter BEFORE `clearNamespace` (after `terminateAgent`) | Race narrowed but not eliminated |
131
- | #1024 layer 2 | Add `purgeHiveNamespacesDirect` raw sql.js DELETE | Looked bulletproof; actually clobber-prone vs daemon's stale snapshot (#981 single-writer) |
132
- | #1024 declared green | All 6 CI checks pass once | Same flake reappeared on next PR's CI |
133
- | #1027 attempt 4 | Move `adapter.detach()` BEFORE `terminateAgent`; delete `purgeHiveNamespacesDirect` | Code simplified by -73 LOC. **Same flake on macos-latest CI.** |
134
- | #1027 — actual fix | Run launcher a SECOND time after doctor in the populated harness | Test passes. Race is intrinsic to multi-process sql.js + daemon kill timing; the harness assertion was over-strict. |
129
+ | 1 | Loop list+delete in `clearNamespace` | Race window remained — broadcasts landed mid-loop |
130
+ | 2 | Detach adapter BEFORE `clearNamespace` (after `terminateAgent`) | Race narrowed but not eliminated |
131
+ | 3 | Add `purgeHiveNamespacesDirect` raw sql.js DELETE | Looked bulletproof; actually clobber-prone vs daemon's stale snapshot it violates the single-writer contract |
132
+ | declared green | All 6 CI checks pass once | Same flake reappeared on next PR's CI |
133
+ | 4 | Move `adapter.detach()` BEFORE `terminateAgent`; delete `purgeHiveNamespacesDirect` | Code simplified by -73 LOC. **Same flake on macos-latest CI.** |
134
+ | 5 — actual fix | Run launcher a SECOND time after doctor in the populated harness | Test passes. Race is intrinsic to multi-process sql.js + daemon kill timing; the harness assertion was over-strict. |
135
135
 
136
136
  The first three attempts kept asking "how do we delete this row harder?" The fourth attempt was a structural simplification that was correct on its own merits (-73 LOC, removed dead code, simpler shutdown ordering) but **did not fix the flake**.
137
137
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## When to Use `-sd` vs `-v` vs Neither
8
8
 
9
- Two independent modifiers on `/flo`, orthogonal to execution mode (`-n`/`-s`/`-h`) and `--worktree`. The **spec/plan ceremony (`-sd`) is opt-in**; **verify-before-done (`-v`) runs by default** (#1294) — separable from SDD by design.
9
+ Two independent modifiers on `/flo`, orthogonal to execution mode (`-n`/`-s`/`-h`) and `--worktree`. The **spec/plan ceremony (`-sd`) is opt-in**; **verify-before-done (`-v`) runs by default** — separable from SDD by design.
10
10
 
11
11
  | Situation | Flag | Effect |
12
12
  |-----------|------|--------|
@@ -44,7 +44,7 @@ A spec is pre-implementation intent for **one** unit of work, not a project rule
44
44
 
45
45
  Existing spec rows are removed by the `purge-spec-chunks` migration on the next session start.
46
46
 
47
- **Where specs live is configurable (`sdd.specs_dir`, #1294).** The default `.moflo/specs` is **gitignored** by `flo init`. To make specs reviewable in the PR, point `sdd.specs_dir` at a **tracked** path and commit them:
47
+ **Where specs live is configurable (`sdd.specs_dir`).** The default `.moflo/specs` is **gitignored** by `flo init`. To make specs reviewable in the PR, point `sdd.specs_dir` at a **tracked** path and commit them:
48
48
 
49
49
  | `sdd.specs_dir` | Committed? | Use when |
50
50
  |-----------------|------------|----------|
@@ -78,7 +78,7 @@ The two review checkpoints are the point: **a spec must be reviewed before its p
78
78
 
79
79
  When enforced, `gh pr create` is blocked until the change has been verified end-to-end since the last code edit.
80
80
 
81
- - **On by default (#1294).** Enforced for every `/flo` run; disable per-project with `gates.verify_before_done: false` or per-run with `--no-verify`. On upgrade, consumers with no `verify_before_done` key start enforcing; an explicit value is preserved. Docs-only diffs are exempt, so a pure-docs PR is never blocked.
81
+ - **On by default.** Enforced for every `/flo` run; disable per-project with `gates.verify_before_done: false` or per-run with `--no-verify`. On upgrade, consumers with no `verify_before_done` key start enforcing; an explicit value is preserved. Docs-only diffs are exempt, so a pure-docs PR is never blocked.
82
82
  - **Satisfy it by running the `/verify` skill** — `/flo` delegates to it. It exercises the change against the plan's (or ticket's) acceptance criteria and records its own outcome to memory (`namespace: verify, key: verify:<slug>`). It reuses the Tests-phase run rather than repeating it (no double verify).
83
83
  - **A source edit invalidates a prior verification** — re-run `/verify` after editing. `/ward` and `/quicken` are targeted audits, not the completion gate.
84
84
 
@@ -86,13 +86,13 @@ When enforced, `gh pr create` is blocked until the change has been verified end-
86
86
 
87
87
  ## SDD & Verify moflo.yaml Defaults
88
88
 
89
- `sdd.default` is off (opt-in); `verify_before_done` is **on** (#1294). Override per run with the flags.
89
+ `sdd.default` is off (opt-in); `verify_before_done` is **on**. Override per run with the flags.
90
90
 
91
91
  ```yaml
92
92
  sdd:
93
93
  default: false # true → every /flo run uses the SDD cycle unless --no-sdd
94
94
  gates:
95
- verify_before_done: true # on by default (#1294); false → skip /verify unless -v. Per-run: --no-verify
95
+ verify_before_done: true # on by default; false → skip /verify unless -v. Per-run: --no-verify
96
96
  ```
97
97
 
98
98
  Check wiring status with `/healer` (or `/eldar`) — the `SDD + Verify Wiring` check reports whether the gate cases and hooks are present and which toggles are on.
@@ -124,7 +124,7 @@ steps:
124
124
 
125
125
  ### agent — NOT EXECUTABLE
126
126
 
127
- **Do not use this step type.** It has never spawned a subagent — moflo has no agent spawner in the spell runner. It is still registered so existing spell YAML keeps parsing, but casting it now always fails with an explanatory error (#1334). Earlier versions returned `success: true` and a `result` string for work that never happened.
127
+ **Do not use this step type.** It has never spawned a subagent — moflo has no agent spawner in the spell runner. It is still registered so existing spell YAML keeps parsing, but casting it now always fails with an explanatory error. Earlier versions returned `success: true` and a `result` string for work that never happened.
128
128
 
129
129
  **To run a Claude subagent from a spell, use a `bash` step:**
130
130
 
@@ -57,13 +57,13 @@ session_continuity:
57
57
 
58
58
  # Memory backend
59
59
  memory:
60
- backend: node-sqlite # node-sqlite (default) | rvf (pure-TS fallback) | json (last resort). Passed to createDatabase() as the preferred provider (#1144).
60
+ backend: node-sqlite # node-sqlite (default) | rvf (pure-TS fallback) | json (last resort). Passed to createDatabase() as the preferred provider.
61
61
  embedding_model: Xenova/all-MiniLM-L6-v2 # 384-dim neural embeddings
62
62
  namespace: default # Default namespace for memory operations
63
- # worktree_sharing: false # opt-OUT (#1231): automatic durable-learning sharing across git worktrees is ON by default (derived at <git-common-dir>/moflo/durable.db, active only when worktrees exist; a single checkout is untouched). Set false to disable.
64
- # durable_path: ~/.moflo-shared/team-learnings.db # opt-in (#1232): OVERRIDE the auto worktree store — a custom durable-only path for learnings/knowledge, or to converge separate clones. Point at a DEDICATED store, never a full moflo.db. Env override: MOFLO_DURABLE_PATH.
65
- # team_artifact: .moflo/shared/learnings.jsonl # opt-in (#1234): git-tracked JSONL the team commits; session-start import-merges it. Env override: MOFLO_TEAM_ARTIFACT. See moflo-cross-install-memory-sharing.md.
66
- # hydrate_from: /abs/path/to/moflo-snapshot.db # opt-in (#1244): whole-DB snapshot to seed a fresh/empty workspace on session-start (skips the cold reindex). No-op once the local DB has content. Take one with "flo memory backup --to <path>". Env override: MOFLO_HYDRATE_FROM.
63
+ # worktree_sharing: false # opt-OUT: automatic durable-learning sharing across git worktrees is ON by default (derived at <git-common-dir>/moflo/durable.db, active only when worktrees exist; a single checkout is untouched). Set false to disable.
64
+ # durable_path: ~/.moflo-shared/team-learnings.db # opt-in: OVERRIDE the auto worktree store — a custom durable-only path for learnings/knowledge, or to converge separate clones. Point at a DEDICATED store, never a full moflo.db. Env override: MOFLO_DURABLE_PATH.
65
+ # team_artifact: .moflo/shared/learnings.jsonl # opt-in: git-tracked JSONL the team commits; session-start import-merges it. Env override: MOFLO_TEAM_ARTIFACT. See moflo-cross-install-memory-sharing.md.
66
+ # hydrate_from: /abs/path/to/moflo-snapshot.db # opt-in: whole-DB snapshot to seed a fresh/empty workspace on session-start (skips the cold reindex). No-op once the local DB has content. Take one with "flo memory backup --to <path>". Env override: MOFLO_HYDRATE_FROM.
67
67
 
68
68
  # Hook toggles (all on by default — disable to slim down)
69
69
  hooks:
@@ -132,7 +132,7 @@ auto_update:
132
132
  enabled: true # Master toggle for version-change auto-sync
133
133
  scripts: true # Sync .claude/scripts/ from moflo bin/
134
134
  helpers: true # Sync .claude/helpers/ from moflo source
135
- hook_block_drift: regenerate # warn | regenerate | off (default: regenerate since #1227)
135
+ hook_block_drift: regenerate # warn | regenerate | off (default: regenerate)
136
136
  claudemd_injection_drift: regenerate # warn | regenerate | off
137
137
 
138
138
  # Which skill categories to install (OPTIONAL — omit to get every skill)
@@ -245,10 +245,10 @@ skills:
245
245
  | `sandbox.tier: full` | Require OS sandbox; throw at runtime if the platform tool is unavailable |
246
246
  | `sandbox.tier: denylist-only` | Keep Layer 1 denylist only; skip OS isolation even when enabled |
247
247
  | `auto_update.enabled: false` | Disable all on-session auto-sync (scripts, helpers, drift checks) |
248
- | `auto_update.hook_block_drift: regenerate` | Auto-repair drift in `.claude/settings.json` hook block on session start (#881, default since #1227 — basename guard from #1180 keeps user-owned hooks safe). |
248
+ | `auto_update.hook_block_drift: regenerate` | Auto-repair drift in `.claude/settings.json` hook block on session start (default; a basename guard keeps user-owned hooks safe). |
249
249
  | `auto_update.hook_block_drift: warn` | Print drift notice but leave settings.json unchanged. Opt-out from auto-regen. |
250
250
  | `auto_update.hook_block_drift: off` | Skip hook-block drift detection entirely |
251
- | `auto_update.claudemd_injection_drift: regenerate` | Auto-refresh the MoFlo block in `CLAUDE.md` when it drifts from the current generator (#1142, default) |
251
+ | `auto_update.claudemd_injection_drift: regenerate` | Auto-refresh the MoFlo block in `CLAUDE.md` when it drifts from the current generator (default) |
252
252
  | `auto_update.claudemd_injection_drift: warn` | Print a drift notice on session start but leave `CLAUDE.md` unchanged |
253
253
  | `auto_update.claudemd_injection_drift: off` | Skip CLAUDE.md injection drift detection entirely |
254
254
 
@@ -963,6 +963,45 @@ function creditIsLive(flag, stored, scope) {
963
963
  return stored === now;
964
964
  }
965
965
 
966
+ // #1410 — is this Bash command actually a `gh pr create` invocation? Delegates
967
+ // to pr-create-command.cjs, which sanitises data regions (quotes, heredoc
968
+ // bodies, comments) before looking for the command, so the gate neither misses
969
+ // real invocations (newline-separated, piped, parenthesised) nor fires on
970
+ // commands that merely quote the literal (`git commit -m "...gh pr create..."`).
971
+ //
972
+ // Fail-safe, in BOTH directions, because this runs on every Bash call in every
973
+ // consumer. gate-hook.mjs maps a non-zero exit from this script to exit 2, so an
974
+ // uncaught throw here does not degrade one gate — it blocks every Bash call the
975
+ // consumer makes. So a load failure (partial `.claude/helpers` sync mid-upgrade,
976
+ // hand-pruned install) AND a throw from the matcher itself both fall back to the
977
+ // pre-#1410 regex: previous behaviour, not a wedged session.
978
+ //
979
+ // Not silent (#854, hook-authoring §4): the fallback path advises on stderr and
980
+ // continues. If this ever fires it means the matcher crashed, which is worth
981
+ // being loud about — and it cannot spam a healthy session, because a healthy
982
+ // session never reaches it.
983
+ var LEGACY_PR_CREATE_RE = /(?:^|&&\s*|\|\|\s*|;\s*)\s*(?:[A-Z_][A-Z0-9_]*=\S+\s+)*gh\s+pr\s+create\b/;
984
+ var prCreateMatcher = null;
985
+ function isPrCreateCommand(cmd) {
986
+ if (prCreateMatcher === null) {
987
+ try {
988
+ prCreateMatcher = require('./pr-create-command.cjs').isPrCreateCommand;
989
+ } catch (e) {
990
+ prCreateMatcher = false;
991
+ process.stderr.write('moflo: pr-create-command.cjs unavailable (' + (e && e.message) + ') — PR gates fall back to the legacy matcher. Run `npx flo doctor --fix`.\n');
992
+ }
993
+ if (typeof prCreateMatcher !== 'function') prCreateMatcher = false;
994
+ }
995
+ if (prCreateMatcher) {
996
+ try {
997
+ return prCreateMatcher(cmd);
998
+ } catch (e) {
999
+ process.stderr.write('moflo: pr-create matcher threw (' + (e && e.message) + ') — falling back to the legacy matcher. Please report with the command that triggered it.\n');
1000
+ }
1001
+ }
1002
+ return LEGACY_PR_CREATE_RE.test(cmd);
1003
+ }
1004
+
966
1005
  // Classifier-aware simplify gate skip. Returns a string reason if the gate
967
1006
  // can be auto-passed, or null if /simplify must run. Uses simplify-classify.cjs
968
1007
  // so the gate's "trivial" definition matches the skill's exactly.
@@ -1600,12 +1639,12 @@ switch (command) {
1600
1639
  break;
1601
1640
  }
1602
1641
  case 'check-before-pr': {
1603
- // Anchored to command-start (or chained via && / || / ;) so heredoc bodies
1604
- // and quoted strings that contain the literal "gh pr create" don't trip
1605
- // the gate during regular `git commit -m "...gh pr create..."` flows. The
1606
- // optional ENV=val prefix segment catches `GH_TOKEN=x gh pr create`.
1642
+ // Anchored to command-start so heredoc bodies and quoted strings that
1643
+ // contain the literal "gh pr create" don't trip the gate during regular
1644
+ // `git commit -m "...gh pr create..."` flows, while still catching the
1645
+ // chained, piped, parenthesised, and multi-line shapes (#1410).
1607
1646
  var cmd = process.env.TOOL_INPUT_command || '';
1608
- if (!/(?:^|&&\s*|\|\|\s*|;\s*)\s*(?:[A-Z_][A-Z0-9_]*=\S+\s+)*gh\s+pr\s+create\b/.test(cmd)) break;
1647
+ if (!isPrCreateCommand(cmd)) break;
1609
1648
  // #1374 — close the loop the TaskCreate reminder opens. Advisory: stdout,
1610
1649
  // no exit, and worded as a reminder, because a message may only claim to
1611
1650
  // block when it blocks (#1326). An open task list is a reporting failure,
@@ -1680,7 +1719,7 @@ switch (command) {
1680
1719
  }
1681
1720
  }
1682
1721
  var missing = [];
1683
- if (config.testing_gate && !s.testsRun) missing.push('tests have not run green since the last code edit (run npm test, vitest, jest, pytest, or similar — a run whose output reports failures does not count, #1322)');
1722
+ if (config.testing_gate && !s.testsRun) missing.push('tests have not run green since the last code edit (run npm test, vitest, jest, pytest, or similar — a run whose output reports failures does not count)');
1684
1723
  if (config.simplify_gate && !s.simplifyRun) missing.push('/flo-simplify (or /distill) has not run since the last code edit');
1685
1724
  if (config.learnings_gate && !s.learningsStored) missing.push('learnings have not been stored (call mcp__moflo__memory_store)');
1686
1725
  if (missing.length === 0) break;
@@ -1716,7 +1755,7 @@ switch (command) {
1716
1755
  // command (docs-only diffs are exempt, so this never blocks a docs PR).
1717
1756
  if (!config.verify_before_done) break;
1718
1757
  var cmd = process.env.TOOL_INPUT_command || '';
1719
- if (!/(?:^|&&\s*|\|\|\s*|;\s*)\s*(?:[A-Z_][A-Z0-9_]*=\S+\s+)*gh\s+pr\s+create\b/.test(cmd)) break;
1758
+ if (!isPrCreateCommand(cmd)) break;
1720
1759
  // No-source-files exemption — a docs-only / path-inert diff needs no verify.
1721
1760
  var changedD = getChangedFilesVsBase();
1722
1761
  if (changedD && changedD.length > 0) {