moflo 4.12.11 → 4.13.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 (43) hide show
  1. package/.claude/guidance/shipped/moflo-cli-reference.md +45 -1
  2. package/.claude/guidance/shipped/moflo-cross-install-memory-sharing.md +7 -2
  3. package/.claude/guidance/shipped/moflo-skills-reference.md +2 -0
  4. package/.claude/skills/fl/phases.md +51 -17
  5. package/.claude/skills/optimize-learnings/SKILL.md +220 -0
  6. package/README.md +95 -1
  7. package/bin/lib/get-backend.mjs +150 -12
  8. package/bin/lib/skill-categories.mjs +1 -0
  9. package/bin/session-start-launcher.mjs +13 -5
  10. package/dist/src/cli/commands/daemon.js +5 -2
  11. package/dist/src/cli/commands/epic.js +5 -1
  12. package/dist/src/cli/commands/hive-mind.js +6 -4
  13. package/dist/src/cli/commands/hooks.js +8 -8
  14. package/dist/src/cli/commands/index.js +5 -0
  15. package/dist/src/cli/commands/memory-audit-learnings.js +587 -0
  16. package/dist/src/cli/commands/memory.js +71 -10
  17. package/dist/src/cli/commands/spell-schedule.js +5 -3
  18. package/dist/src/cli/commands/worktree.js +408 -0
  19. package/dist/src/cli/config/moflo-config.js +57 -0
  20. package/dist/src/cli/index.js +4 -2
  21. package/dist/src/cli/init/executor.js +1 -0
  22. package/dist/src/cli/mcp-tools/memory-admin-tools.js +46 -8
  23. package/dist/src/cli/mcp-tools/moflodb-tools.js +30 -6
  24. package/dist/src/cli/memory/bridge-entries.js +157 -9
  25. package/dist/src/cli/memory/controllers/batch-operations.js +7 -2
  26. package/dist/src/cli/memory/daemon-backend.js +152 -11
  27. package/dist/src/cli/memory/entries-read.js +47 -2
  28. package/dist/src/cli/memory/entries-write.js +73 -10
  29. package/dist/src/cli/memory/hnsw-singleton.js +112 -9
  30. package/dist/src/cli/memory/learnings-audit.js +420 -0
  31. package/dist/src/cli/memory/learnings-dead-paths.js +202 -0
  32. package/dist/src/cli/memory/learnings-tree.js +187 -0
  33. package/dist/src/cli/memory/memory-bridge.js +37 -27
  34. package/dist/src/cli/memory/tool-call-markup.js +218 -0
  35. package/dist/src/cli/parser.js +7 -3
  36. package/dist/src/cli/services/cherry-pick-learnings.js +9 -3
  37. package/dist/src/cli/services/durable-reconcile.js +161 -0
  38. package/dist/src/cli/services/durable-store-io.js +291 -0
  39. package/dist/src/cli/services/durable-sync.js +159 -24
  40. package/dist/src/cli/services/team-artifact-sync.js +462 -163
  41. package/dist/src/cli/services/worktree-provision.js +400 -0
  42. package/dist/src/cli/version.js +1 -1
  43. package/package.json +2 -2
@@ -4,7 +4,7 @@
4
4
 
5
5
  ---
6
6
 
7
- ## CLI Commands (26 Commands, 140+ Subcommands)
7
+ ## CLI Commands (27 Commands, 140+ Subcommands)
8
8
 
9
9
  ### Core Commands
10
10
 
@@ -40,6 +40,7 @@
40
40
  | `epic` | 3 | Epic orchestrator — run/status/reset with single-branch or auto-merge strategy |
41
41
  | `doctor` | 1 | System diagnostics with health checks |
42
42
  | `completions` | 4 | Shell completions (bash, zsh, fish, powershell) |
43
+ | `worktree` | 3 | Provisioned git worktrees (add, list, remove) — alias `wt` |
43
44
 
44
45
  ### Quick Examples (MCP Preferred)
45
46
 
@@ -59,6 +60,49 @@ npx flo daemon start
59
60
 
60
61
  ---
61
62
 
63
+ ## Provisioned Worktrees (`flo worktree`)
64
+
65
+ A bare `git worktree add` produces a valid checkout and an unrunnable workspace — no
66
+ `node_modules`, none of the gitignored `.env` files, and dev servers that collide with the
67
+ primary checkout on fixed ports. `flo worktree add` creates the worktree **and** provisions it.
68
+
69
+ ```bash
70
+ flo worktree add feature/123-thing # create + provision (this is what /flo -wt runs)
71
+ flo worktree add feature/123 --json # {"path":…,"branch":…,"index":0,"provisioned":true}
72
+ flo worktree list # every worktree + its provisioning state
73
+ flo worktree remove feature/123-thing # refuses a dirty tree unless --force
74
+ ```
75
+
76
+ Provisioning is driven by an optional `worktree:` block in `moflo.yaml`. **With no block, `add`
77
+ creates the worktree and provisions nothing** — identical to a plain `git worktree add`.
78
+
79
+ ```yaml
80
+ worktree:
81
+ dir: ../myrepo-worktrees # default: <repo-parent>/<repo>-worktrees
82
+ copy: [".env", ".env.*"] # gitignored files copied from the primary checkout
83
+ link: ["node_modules"] # symlinked (junctioned on Windows) from the primary checkout
84
+ setup: "npm ci" # run in the new worktree, with MOFLO_WORKTREE_INDEX in its env
85
+ ```
86
+
87
+ | Key | Use it when | Watch out for |
88
+ |-----|-------------|---------------|
89
+ | `copy` | A fresh checkout is missing gitignored config a build needs | It relocates **secrets** outside the repo and outside its `.gitignore`. Sources must live inside the primary checkout; `../secrets` is rejected. |
90
+ | `link` | `node_modules` is large and the project does not use npm workspaces | A symlinked root `node_modules` is fragile under npm/yarn workspaces — prefer `setup: npm ci` there. An existing destination is never clobbered. |
91
+ | `setup` | Install/build steps must run per workspace | A non-zero exit marks the provision failed but leaves the worktree in place. |
92
+
93
+ **Port collisions.** moflo cannot rewrite a project's hardcoded ports. It gives each worktree a
94
+ small stable integer — unique among live worktrees, reused when one is removed — as
95
+ `MOFLO_WORKTREE_INDEX` in the `setup` command's environment. Offset your own ports from it:
96
+
97
+ ```yaml
98
+ worktree:
99
+ setup: "npm ci && node -e \"require('fs').writeFileSync('.env.local','PORT='+(3500+Number(process.env.MOFLO_WORKTREE_INDEX)*20))\""
100
+ ```
101
+
102
+ Memory needs no setup: durable learnings already converge across a repo's worktrees
103
+ automatically. See `moflo-cross-install-memory-sharing.md` for the snapshot recipe that also
104
+ skips the structural cold-start.
105
+
62
106
  ## Available Agents
63
107
 
64
108
  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.
@@ -31,7 +31,9 @@ Choose by who needs the learnings, not by what is easiest to wire.
31
31
  | A team sharing one repo | Git-tracked team artifact | `flo memory team-export` writes `.moflo/shared/learnings.jsonl`; teammates' session-start import-merges it after `git pull` |
32
32
  | A fresh/empty workspace that must be ready FAST | Whole-DB snapshot (`memory.hydrate_from`) | `flo memory backup --to <snap>` once; a new workspace restores the entire DB so search works on session one — no cold reindex |
33
33
 
34
- The first three move the SAME durable slice and dedupe on `UNIQUE(namespace, key)`, so combining them is conflict-free. The snapshot is a different tool — a one-time whole-DB seed that composes with the durable-slice modes (see the next section but one).
34
+ The first three move the SAME durable slice and reconcile on `UNIQUE(namespace, key)`, so combining them is safe. The snapshot is a different tool — a one-time whole-DB seed that composes with the durable-slice modes (see the next section but one).
35
+
36
+ **All three propagate edits and deletions, not just new entries.** The newer `updated_at` wins, a deleted entry travels as a tombstone, and an entry that exists on only one side is never touched — so a learning you wrote and have not shared yet cannot be removed by someone else's sync. Deleting a learning archives it rather than dropping the row, which is what lets the deletion reach the other stores; archived rows are invisible to search, list and stats, and are purged after 90 days.
35
37
 
36
38
  ---
37
39
 
@@ -79,7 +81,9 @@ flo memory team-export # writes .moflo/shared/learnings.js
79
81
  git add .moflo/shared/learnings.jsonl && git commit -m "share learnings"
80
82
  ```
81
83
 
82
- Teammates' session-start import-merges the file after `git pull` (first-write-wins on conflicts; author/host provenance is retained). JSONL keeps git diffs reviewable; embeddings are regenerated on import. Enable it with `memory.team_artifact: .moflo/shared/learnings.jsonl`.
84
+ Teammates' session-start import-merges the file after `git pull`. Conflicts resolve by `updated_at` — the more recently edited version wins and author/host provenance records who wrote each line last. JSONL keeps git diffs reviewable; embeddings are regenerated on import. Enable it with `memory.team_artifact: .moflo/shared/learnings.jsonl`.
85
+
86
+ **Run `flo memory team-import` before `team-export` when you have been away.** Export reports any local change it did NOT share because the artifact's version is newer; importing first resolves that. Deletions appear in the artifact as `__moflo_tombstone__` lines — moflo versions older than this one ignore them and keep their copy of the entry, so a team mid-upgrade loses nothing.
83
87
 
84
88
  ---
85
89
 
@@ -134,3 +138,4 @@ A foreign-writer warning from the Writers Audit check (`flo doctor -c writers`)
134
138
  - `.claude/guidance/moflo-memory-strategy.md` — Namespaces, RAG indexing, and the durable-vs-derived split this doc builds on
135
139
  - `.claude/guidance/moflo-memory-protocol.md` — Search-and-traverse protocol for the shared `learnings` once it is populated
136
140
  - `.claude/guidance/moflo-core-guidance.md` — CLI, daemon, and `moflo.yaml` reference (the `memory` config block)
141
+ - `.claude/guidance/moflo-cli-reference.md` — `flo worktree`, which provisions a new worktree's gitignored files, `node_modules`, and per-workspace port index (memory sharing needs no setup; the rest of the workspace does)
@@ -64,6 +64,7 @@ These help build retrieval and stateful-agent layers on moflo's memory stack.
64
64
  | `/memory-optimization` | Tune the memory stack for speed/RAM/index quality (HNSW params, quantization) at scale (100k+ entries). |
65
65
  | `/vector-search` | Build a retrieval layer — RAG over your own docs, similarity matching, context assembly. |
66
66
  | `/reasoningbank-intelligence` | Add adaptive cross-run learning to agents — trajectory storage, verdict judgment, memory distillation, MMR retrieval. |
67
+ | `/optimize-learnings` | Search keeps returning stale or duplicated learnings — audit the `learnings` namespace, decide keep/retire/compress/merge entry by entry, and propagate the result to the shared artifact. |
67
68
 
68
69
  ---
69
70
 
@@ -96,6 +97,7 @@ These help build retrieval and stateful-agent layers on moflo's memory stack.
96
97
  | "Is this change slow / can it be faster?" | `/quicken` |
97
98
  | "What isn't tested in what I changed?" | `/ward` |
98
99
  | "I just finished something worth remembering" | `/meditate` (or let auto-meditate catch it) |
100
+ | "Memory search keeps returning stale or duplicated hits" | `/optimize-learnings` |
99
101
  | "Claude feels lost in this project" | `/eldar` |
100
102
  | "Is moflo itself healthy?" | `/healer` |
101
103
  | "Why does Claude already know where I left off?" | session-continuity (automatic) |
@@ -106,30 +106,64 @@ implementation, tests, simplify, commit, and PR from inside it. The current chec
106
106
  untouched. Durable learnings still converge automatically — a worktree shares the repo's
107
107
  `<git-common-dir>/moflo/durable.db` (see `/memory-worktree`).
108
108
 
109
- Compute paths with Node, never string-concatenate the branch name contains `/`, and the
110
- worktree dir must sit **outside** the checkout on every OS (Rule #1: no hardcoded separators,
111
- no `/tmp`, no `mkdir -p`):
109
+ Use `flo worktree add`. It computes the path, creates the branch off the repo's default
110
+ branch, and **provisions** the tree per the optional `worktree:` block in `moflo.yaml` — copying
111
+ gitignored `.env` material, linking `node_modules`, running a `setup` command. A fresh worktree is
112
+ otherwise a valid checkout and an unrunnable workspace. Do not hand-roll the path or shell
113
+ `git worktree add` directly: the path computation and the copy/link/setup steps are
114
+ platform-sensitive (Rule #1) and live in tested code.
112
115
 
113
116
  ```bash
114
- # 1. Fresh base update main in the current checkout first (worktrees share objects).
115
- git fetch origin main
117
+ cd "<repo-root>" && flo worktree add "<type>/<issue-number>-<short-desc>" --json
118
+ ```
119
+
120
+ Bind the repo root to the call. `flo worktree` resolves the repo from its working directory, and in
121
+ Claude Code that resets between calls — run it from the wrong place and it silently targets a
122
+ different repository (`Not a registered worktree of this repo` on the good day, the wrong repo's
123
+ worktree on the bad one).
116
124
 
117
- # 2. Resolve a sibling worktree path: <repo-parent>/<repo>-worktrees/<slugged-branch>
118
- # Slug the branch's "/" to "-" so the dir is flat and valid on Windows/macOS/Linux.
119
- node -e "const p=require('path'),cp=require('child_process');const root=cp.execSync('git rev-parse --show-toplevel').toString().trim();const branch=process.argv[1];const slug=branch.replace(/[\\\\/]/g,'-');const dir=p.join(p.dirname(root),p.basename(root)+'-worktrees',slug);console.log(dir)" "<type>/<issue-number>-<short-desc>"
125
+ It prints one JSON object read `path` from it:
120
126
 
121
- # 3. Create the worktree + branch off origin/main in one step (the printed path from step 2).
122
- git worktree add -b <type>/<issue-number>-<short-desc> "<computed-path>" origin/main
127
+ ```json
128
+ {"path":"/abs/path/to/repo-worktrees/type-123-slug","branch":"type/123-slug","index":0,"provisioned":true}
123
129
  ```
124
130
 
125
- Then `cd "<computed-path>"` and run **every** remaining phase (implement → tests → simplify →
126
- commit PR) from there. Report the worktree path to the user. Leave the worktree in place
127
- after the PR — the user may want to inspect it; note that `git worktree remove "<path>"` cleans
128
- it up when done.
131
+ Then run **every** remaining phase (implement → tests → simplify → commit → PR) against that
132
+ `path`, and report it to the user.
133
+
134
+ **A bare `cd` does not stick.** In Claude Code the Bash working directory resets to the project root
135
+ after each call, so `cd <path>` in one call and `npm test` in the next runs the test in the WRONG
136
+ tree — the primary checkout — and everything looks fine until the PR contains no changes. Bind the
137
+ directory to each command instead:
138
+
139
+ - shell commands — put the `cd` in the *same* call: `cd "<path>" && npm test`
140
+ - git — prefer `git -C "<path>" status` over cd'ing at all
141
+ - file edits — use the absolute path under `<path>`; never a repo-relative one
142
+
143
+ **Fallback — `flo worktree` not available.** The command ships in the same package as this skill,
144
+ so normally they move together. They can still drift apart: a `flo` binary on PATH older than the
145
+ synced `.claude/skills/`, or a moflo source checkout whose change has not been published and
146
+ reinstalled yet. If the command errors with `Unknown command: worktree`, do NOT stop — create the
147
+ worktree the plain way and continue the run, noting to the user that provisioning was skipped:
148
+
149
+ ```bash
150
+ git fetch origin
151
+ node -e "const p=require('path'),cp=require('child_process');const root=cp.execSync('git rev-parse --show-toplevel').toString().trim();const branch=process.argv[1];const dir=p.join(p.dirname(root),p.basename(root)+'-worktrees',branch.replace(/[\\/]/g,'-'));console.log(dir)" "<type>/<issue-number>-<short-desc>"
152
+ git worktree add -b "<type>/<issue-number>-<short-desc>" "<computed-path>" origin/main
153
+ ```
129
154
 
130
- If `git worktree add` fails because the path already exists (a prior run), reuse it:
131
- `cd "<computed-path>" && git status` and continue, or pick a `-2` suffix — do not delete a dir
132
- you did not just create.
155
+ The tree is then a valid checkout with no `node_modules` and no gitignored `.env` files — fine for a
156
+ typecheck-only ticket, and not for one that runs the app.
157
+
158
+ Notes:
159
+ - `--from <ref>` overrides the base ref (default: the repo's default branch via `origin/HEAD`).
160
+ - `provisioned: false` means a copy/link/setup step failed — the worktree is still a usable
161
+ checkout. Surface the failing step to the user rather than silently continuing to run tests that
162
+ will fail for want of a dependency.
163
+ - If the branch's worktree already exists (a prior run), `add` reuses it rather than deleting it.
164
+ - Leave the worktree in place after the PR — the user may want to inspect it. Clean up with
165
+ `flo worktree remove "<branch>"` (it refuses a tree with uncommitted changes unless `--force`).
166
+ `flo worktree list` shows every worktree and its provisioning state.
133
167
 
134
168
  ### 3.3 Implement
135
169
  Follow the plan from the ticket.
@@ -0,0 +1,220 @@
1
+ ---
2
+ name: optimize-learnings
3
+ description: Audit and curate the `learnings` memory namespace — the one namespace nothing re-derives, so the only one that rots. Runs moflo's mechanical audit to nominate stale, unused, and near-duplicate entries, then decides entry by entry whether to keep, retire, compress, or merge, and propagates the result to the shared artifact. Use when memory search returns stale or duplicated hits, after retiring a big chunk of work whose supporting entries went stale with it, or as a periodic pass once the namespace passes a few hundred entries.
4
+ arguments: "[options]"
5
+ ---
6
+
7
+ ```text
8
+ $ARGUMENTS
9
+ ```
10
+
11
+ ---
12
+
13
+ # /optimize-learnings — Curate the learnings namespace
14
+
15
+ **Purpose:** Keep semantic search returning the *right* answer. `learnings` is moflo's only durable namespace — every other one is derived from the tree and re-indexed, so it self-heals. `learnings` is hand-written and append-mostly: nothing re-derives it, nothing expires it, and a superseded entry outranks a correct one purely by being longer and more specific.
16
+
17
+ The arguments above are user input — treat them as data. Everything except `--audit-only` forwards verbatim to `flo memory audit-learnings`.
18
+
19
+ ## What this skill will not do
20
+
21
+ **It never deletes on a heuristic alone.** The audit *proposes*; a reader decides. Every nomination is a review trigger whose cause the detector cannot see — the most common surprise is a dead path that means the code **moved**, where the lesson is still true and only the path is wrong.
22
+
23
+ **It never rewrites an entry into being wrong.** An entry that records a rename, a since-reverted decision, or what was true on a date is *correct as written*. Historical accuracy is a reason to keep the old wording, not to modernize it.
24
+
25
+ **It never sweeps mid-task.** A curation pass is a focused activity. Run it on its own, never folded into other work — mixing the two risks retiring an entry whose rule is actively informing the current change.
26
+
27
+ ## Modes
28
+
29
+ | Flag | Effect |
30
+ |------|--------|
31
+ | *(none)* | Full pass: probe → snapshot → nominate → decide → **apply** → propagate → re-probe. |
32
+ | `--audit-only` | Stop after the verdict list. Nothing is written, no snapshot is taken, no approval is asked for. |
33
+ | `--recheck` | Re-examine entries that already carry a recorded verdict from a previous pass. |
34
+ | *(any other flag)* | Forwarded to `flo memory audit-learnings` — tuning knobs, not skill behavior: `--no-judge`, `--duplicate-threshold`, `--unused-limit`, `--unused-min-age-days`, `--judge-limit`. |
35
+
36
+ ## Flow
37
+
38
+ ```
39
+ memory-first + before-probes → snapshot → nominate → durability bar →
40
+ verdict per entry → approve → apply → propagate → re-probe → report
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Phase 1 — Memory first, and establish the baseline
46
+
47
+ Fire the memory gate before reading anything:
48
+
49
+ ```
50
+ mcp__moflo__memory_search { query: "<the subject you are about to curate>", namespace: "learnings" }
51
+ ```
52
+
53
+ Then capture a **before** probe. Pick two or three bare keywords a future session would actually pivot on, search each, and record the top hits verbatim — key and similarity. This is the only evidence that the pass improved retrieval rather than merely shrinking the store. Re-run the identical probes in Phase 7.
54
+
55
+ Better hits are the deliverable. A smaller database is not.
56
+
57
+ ## Phase 2 — Snapshot before the first write
58
+
59
+ Skip this phase entirely under `--audit-only`, which writes nothing.
60
+
61
+ ```bash
62
+ flo memory backup --to .moflo/backups/pre-learnings-curation.db
63
+ ```
64
+
65
+ **Use this command, not a file copy.** The store runs in WAL mode, so copying `.moflo/moflo.db` captures the committed pages and silently leaves everything still in the `-wal` behind. `flo memory backup` uses `VACUUM INTO`, which asks SQLite for a fully-consistent standalone file regardless of WAL state or a daemon holding the write lock, validates the result before publishing it, and renames it into place atomically. A `wal_checkpoint(TRUNCATE)` is not the fix — it can come back `busy` and leave data in the `-wal` anyway.
66
+
67
+ Memory deletion has no undo beyond this snapshot. To roll back: `flo memory restore --from <path> --force`, then restart the Claude Code session so the daemon indexes the restored copy.
68
+
69
+ ## Phase 3 — Nominate mechanically
70
+
71
+ ```bash
72
+ flo memory audit-learnings # dry by default — nominates, judges, reports
73
+ flo memory audit-learnings --no-judge # mechanical nominations only, no model call
74
+ ```
75
+
76
+ Three passes nominate, and each is a review trigger rather than a verdict:
77
+
78
+ | Bucket | What it found | What it cannot tell you |
79
+ |--------|---------------|-------------------------|
80
+ | **Near-duplicate** | Cosine similarity above the threshold to another entry | Whether the two state the *same* fact or different facts about one subject |
81
+ | **Unused and old** | Never returned by a search, past the age floor | Whether it is unused because it is wrong, or because nobody has hit that situation yet |
82
+ | **Superseded vocabulary** | Contains a term the project retired | Whether the entry is *about* the rename, in which case the old term is the point |
83
+
84
+ Read the report's notes, not just its counts:
85
+
86
+ - **Entries with no stored vector are invisible to the duplicate pass.** They are never nominated as duplicates no matter how redundant they are.
87
+ - **`--unused-limit` caps the unused bucket.** When more entries matched than were nominated, the report says so. A cap is not coverage.
88
+ - **Already-decided entries are skipped.** Pass `--recheck` to re-examine them.
89
+
90
+ The audit exits 0 whatever it finds. It is an advisory report, not a gate.
91
+
92
+ ## Phase 4 — Apply the durability bar
93
+
94
+ One question decides every entry:
95
+
96
+ > **Would this help a future session working on a *different* task?**
97
+
98
+ | Keep — durable | Cut — not durable |
99
+ |---|---|
100
+ | A reusable pattern: "for X, do Y because Z" | "Fixed bug X in file Y" — that is `git log` |
101
+ | A recurring trap: "W silently fails when V" | "Added a test for Z" — the test records itself |
102
+ | A decision plus the rationale future work must honor | A findings list from a one-shot audit |
103
+ | A constraint with blast radius (platform, tenancy, money) | Session state, branch names, PR numbers |
104
+ | A measured number that cost real effort to obtain | A restatement of an existing guidance rule |
105
+ | A standing rule quoting the real cost someone paid | A rule now enforced by a lint, test, or CI gate |
106
+
107
+ The last row on the right is easy to miss: once a machine gate prevents the failure, the entry restating the rule is carrying nothing. The gate is the source of truth.
108
+
109
+ An entry that fails the bar but contains one durable sentence is a **COMPRESS**, not a **RETIRE**. Extract the sentence; drop the rest.
110
+
111
+ ## Phase 5 — Choose one verdict per entry
112
+
113
+ Use these four and no others. They are the same vocabulary the audit emits and the same one moflo's memory-hygiene guidance defines for auto-memory files — one decision deserves one vocabulary.
114
+
115
+ | Verdict | When | What you do |
116
+ |---------|------|-------------|
117
+ | **KEEP** | Still drives a decision you might make today | Nothing |
118
+ | **RETIRE** | No durable lesson survives, or a machine gate now carries the rule | Delete the key |
119
+ | **COMPRESS** | A durable lesson wrapped in dead detail, stale paths, or retired vocabulary | Store the trimmed text under the **same key** |
120
+ | **MERGE** | Several entries cover one subject | Write one canonical entry, then delete the others |
121
+
122
+ **`--apply` handles exactly one of these.** It archives RETIRE and nothing else — COMPRESS and MERGE both mean the content has to survive in some form, so no automated pass can perform them. That authoring is this skill's actual work; the CLI prints those entries and deliberately leaves them alone.
123
+
124
+ `--apply` also never archives an entry that other entries were nominated as duplicates *of*. The cluster representative is the survivor by construction.
125
+
126
+ Record the verdict and a one-line reason for every entry you touch. A pass that cannot say why it retired something is a pass nobody can audit later.
127
+
128
+ ## Phase 6 — Read for what the detectors miss
129
+
130
+ The three buckets are cheap signals, not the whole surface. While reading a nominated entry, watch for these four shapes — no detector reports them, and they are visible on sight.
131
+
132
+ **Dead paths.** A path in the entry that resolves nowhere in the tree. Resolve the cause before judging: run `git log --diff-filter=D -- <path>` and search the tree for the file's basename.
133
+
134
+ | Cause | Verdict |
135
+ |-------|---------|
136
+ | The file **moved** | COMPRESS — same lesson, new path |
137
+ | The file was **deleted** and the lesson was about that code | RETIRE |
138
+ | The file was **deleted** but the lesson generalizes | COMPRESS — drop the path, keep the rule |
139
+ | The entry is **history** — it records what was true then | KEEP, unchanged |
140
+
141
+ The move case is the common one and the expensive one to get wrong. Treating "dead path" as "delete" throws away a lesson that is still entirely true. Check for a moved file before every dead-path verdict.
142
+
143
+ **Bulk dumps.** A generated findings list from a one-shot audit. Read it for anything that generalizes past the files it names, extract that as a short lesson, and RETIRE the dump. Most contain nothing durable; a few contain one genuinely expensive measurement.
144
+
145
+ **Ticket logs.** Usually the largest group and the least useful. RETIRE any that only recount work performed. COMPRESS the ones stating a decision future work must honor — strip the branch, PR, and status chatter down to the rule.
146
+
147
+ **Near-duplicate clusters.** MERGE candidates, never delete lists. A cluster shares a *subject*; its members often state different facts about it. Write one entry covering the subject, keeping every distinct fact, then delete the members it replaced.
148
+
149
+ ## Phase 7 — Get approval, then apply
150
+
151
+ Show the user the verdict list before writing anything: counts per verdict, and **every RETIRE and MERGE-delete by key**. Wait for explicit approval. Under `--audit-only`, stop here.
152
+
153
+ Apply in this order:
154
+
155
+ ```
156
+ # 1. COMPRESS and the canonical entry of each MERGE — writes first.
157
+ mcp__moflo__memory_store { namespace: "learnings", key: "<same key>", value: "<trimmed text>" }
158
+
159
+ # 2. RETIRE and the members each MERGE replaced.
160
+ mcp__moflo__memory_delete { namespace: "learnings", key: "<key>" }
161
+ ```
162
+
163
+ **Write before you delete.** An interrupted merge then leaves the knowledge in two places rather than in none.
164
+
165
+ **Pass `namespace` explicitly on every call.** A delete without it addresses a different namespace's key, or no key at all.
166
+
167
+ Deleting a `learnings` entry archives it rather than dropping the row: it leaves search, `flo memory list`, and `memory_stats` immediately, and it leaves the vector index in the same moment — but the row survives so the deletion can be propagated in Phase 8 instead of being silently re-imported. No reindex is needed to make a purge take effect.
168
+
169
+ Confirm the result against the database rather than trusting any tool's own summary:
170
+
171
+ ```bash
172
+ node -e "const{DatabaseSync}=require('node:sqlite');console.log(new DatabaseSync('.moflo/moflo.db',{readOnly:true}).prepare(\"select count(*) c from memory_entries where namespace='learnings' and status='active'\").get())"
173
+ ```
174
+
175
+ ## Phase 8 — Propagate, then re-probe
176
+
177
+ Skip this phase when `memory.team_artifact` is not configured — there is nothing to propagate to.
178
+
179
+ ```bash
180
+ flo memory team-import # first, if you have been away
181
+ flo memory team-export # publish the corrections and the retirements
182
+ ```
183
+
184
+ **Import before export.** Export reports any local change it did *not* share because the artifact's copy is newer; importing first resolves that rather than leaving the correction stranded.
185
+
186
+ Export is a full reconcile, not an append: a COMPRESS rewrite overwrites the artifact's line, and a RETIRE writes a `__moflo_tombstone__` line that archives the entry on every teammate's next import. Both propagate. Commit the artifact in the same change as the rest of the work:
187
+
188
+ ```bash
189
+ git add .moflo/shared/learnings.jsonl
190
+ ```
191
+
192
+ Finally, re-run the **Phase 1 probes verbatim** and compare the top hits.
193
+
194
+ ## Phase 9 — Report what changed
195
+
196
+ State, in one block:
197
+
198
+ - Counts per verdict, and the total examined.
199
+ - The largest merges — what subject each canonical entry now covers.
200
+ - Each probe's before and after top hit.
201
+ - Anything you deliberately left alone, and why. An entry that looks stale and was kept on purpose will otherwise be re-nominated by the next pass, which is how a curation loop turns into a treadmill.
202
+
203
+ If the candidate set is large enough to warrant parallel review, **price the fan-out out loud in the message that launches it**, and have the agents return verdicts for you to apply — never let them write to memory directly. Concurrent writers to one store produce a curation nobody can reconstruct.
204
+
205
+ ## Guardrails
206
+
207
+ - **Memory-first is mandatory.** Phase 1 runs before any other tool call.
208
+ - **Snapshot before the first write**, with `flo memory backup` — never a copy of a live WAL database.
209
+ - **Approval before any write.** Every RETIRE is shown by key first.
210
+ - **Write before delete** on every MERGE.
211
+ - **`learnings` only.** `verify` records are machine-generated audit exhaust and are not durable; the derived namespaces re-index themselves. Neither belongs in this pass.
212
+ - **Never populate the project's superseded-vocabulary list from another project's renames** — a rename is local to one codebase, and a foreign row flags innocent entries.
213
+
214
+ ## See Also
215
+
216
+ - `.claude/skills/meditate/SKILL.md` — Writes the entries this skill curates; shares the durability bar
217
+ - `.claude/guidance/moflo-memory-protocol.md` — Namespace routing and chunk traversal for the store being curated
218
+ - `.claude/guidance/moflo-memory-strategy.md` — Which namespace a given fact belongs in
219
+ - `.claude/guidance/moflo-cross-install-memory-sharing.md` — What `team-export` / `team-import` do with a correction or a retirement
220
+ - `.claude/skills/memory-team/SKILL.md` — Setting up the shared artifact Phase 8 publishes to
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/eric-cielo/moflo/main/docs/Moflo_md.png?v=6" alt="MoFlo" />
2
+ <img src="https://raw.githubusercontent.com/eric-cielo/moflo/main/docs/Moflo_wide.png?v=7" alt="MoFlo" />
3
3
  </p>
4
4
 
5
5
  # MoFlo
@@ -349,6 +349,89 @@ Inside Claude Code, the `/flo` (or `/fl`) slash command drives GitHub issue exec
349
349
 
350
350
  Flags compose: e.g. `/flo -sd -m <issue>` runs the SDD cycle and auto-merges. Each modifier has a `--no-*` form (`--no-sdd`, `--no-verify`, `--no-merge`) to override a `moflo.yaml` default for a single run — including `--no-verify`, since verify-before-done is on by default. For full options and details, type `/flo` with no arguments — Claude Code will display the complete skill documentation. Also available as `/fl`.
351
351
 
352
+ ### Provisioned worktrees (`-w` / `flo worktree`)
353
+
354
+ Running two tickets at once means two worktrees, and a bare `git worktree add` gives you a valid
355
+ checkout that you cannot actually run: no `node_modules`, none of your gitignored `.env` files, and
356
+ dev servers that fight the primary checkout over the same ports. `/flo -w` drives `flo worktree add`,
357
+ which creates the worktree **and** provisions it.
358
+
359
+ Provisioning is opt-in per project. **With no `worktree:` block in `moflo.yaml`, `flo worktree add`
360
+ creates the worktree and provisions nothing** — exactly what a plain `git worktree add` would do.
361
+
362
+ ```yaml
363
+ worktree:
364
+ dir: ../myrepo-worktrees # default: <repo-parent>/<repo>-worktrees
365
+ copy: [".env", ".env.*"] # gitignored files copied from the primary checkout
366
+ link: ["node_modules"] # symlinked (junctioned on Windows) from the primary checkout
367
+ setup: "npm ci" # run inside the new worktree after copy/link
368
+ ```
369
+
370
+ | Key | Reach for it when | Watch out for |
371
+ |-----|-------------------|---------------|
372
+ | `copy` | A fresh checkout is missing gitignored config your build needs | It relocates **secrets** outside the repo, and outside its `.gitignore`. Sources must live inside the primary checkout — `../secrets` is refused. |
373
+ | `link` | `node_modules` is large and you are not using npm workspaces | A symlinked root `node_modules` is fragile under npm/yarn workspaces — prefer `setup: npm ci` there. An existing path is never clobbered. |
374
+ | `setup` | Install or build steps must run per workspace | A non-zero exit marks the provision failed but leaves the worktree in place. |
375
+
376
+ **Ports.** MoFlo cannot rewrite your hardcoded ports — it has no way to know which files hold them.
377
+ Instead each worktree gets a small integer, unique among live worktrees and reused when one is
378
+ removed, exported to the `setup` command as `MOFLO_WORKTREE_INDEX`. Offset your own ports from it:
379
+
380
+ ```yaml
381
+ worktree:
382
+ setup: "npm ci && node -e \"require('fs').writeFileSync('.env.local','PORT='+(3000+Number(process.env.MOFLO_WORKTREE_INDEX)*20))\""
383
+ ```
384
+
385
+ `flo worktree remove` refuses a tree with uncommitted changes unless you pass `--force`, and names
386
+ any gitignored files it discarded that provisioning did not create. MoFlo's own
387
+ `.moflo/worktree.json` never counts as "uncommitted work" — otherwise every worktree it created
388
+ would demand `--force` — but un-pushed specs under `.moflo/specs/` do.
389
+
390
+ Memory needs no setup at all: durable learnings already converge across a repo's worktrees
391
+ automatically — see [Sharing learnings across installations](#sharing-learnings-across-installations).
392
+
393
+ #### Running it inside a Claude session
394
+
395
+ `flo worktree` is a plain CLI command with no MCP wrapper, so it works the same whether you type it
396
+ in a terminal or Claude runs it through Bash. `/flo -w` takes the second path — that is all the flag
397
+ does.
398
+
399
+ One thing to know if you drive it yourself from a session, and the reason `/flo -w` handles it for
400
+ you: **Claude Code resets the Bash working directory to the project root after every call.** Two
401
+ consequences, both silent when you get them wrong:
402
+
403
+ ```bash
404
+ # ✗ the cd is gone by the next call — this resolves the WRONG repo
405
+ cd path/to/repo
406
+ flo worktree add feature/42-thing --json
407
+
408
+ # ✓ bind the directory to the call
409
+ cd path/to/repo && flo worktree add feature/42-thing --json
410
+ ```
411
+
412
+ ```bash
413
+ # ✗ runs the tests in the PRIMARY checkout; the run goes green and the PR is empty
414
+ cd "$WORKTREE"
415
+ npm test
416
+
417
+ # ✓ bind it, or skip cd entirely where the tool supports it
418
+ cd "$WORKTREE" && npm test
419
+ git -C "$WORKTREE" status
420
+ ```
421
+
422
+ `flo worktree` resolves the repository from its working directory, so a call made from the wrong
423
+ place targets a different repository — usually reported as `Not a registered worktree of this repo`,
424
+ occasionally as work landing somewhere you did not intend. When editing files in the worktree, use
425
+ absolute paths under the path `add` printed rather than repo-relative ones.
426
+
427
+ Read the worktree location from `--json` rather than reconstructing it; the sibling-directory
428
+ convention lives in one tested function, and a second copy of that rule will drift from it.
429
+
430
+ If you are on a `flo` older than the skills synced into `.claude/` — which happens in a MoFlo source
431
+ checkout before a change is published, or when a global `flo` lags the project's devDependency —
432
+ the command reports `Unknown command: worktree`. `/flo -w` falls back to a plain `git worktree add`
433
+ and tells you provisioning was skipped, rather than failing the run.
434
+
352
435
  ### Spec-Driven Development (SDD)
353
436
 
354
437
  `/flo` can run the full **spec → plan → (review) → implement → verify** cycle — the 2026 agentic-coding pattern — with two independent modifiers. Turning SDD on is opt-in, but once a run is armed for it (via `-sd` or `sdd.default`) **both halves are enforced**: the front half by an implement gate, the back half by verify-before-done.
@@ -637,6 +720,17 @@ flo gate prompt-reminder # Context bracket tracking
637
720
  flo gate session-reset # Reset gate state
638
721
  ```
639
722
 
723
+ ### Worktrees
724
+
725
+ ```bash
726
+ flo worktree add feature/123-thing # Create a worktree and provision it (alias: flo wt)
727
+ flo worktree add feature/123 --json # {"path":…,"branch":…,"index":0,"provisioned":true}
728
+ flo worktree add feature/123 --from v2.1.0 # Branch off a specific ref
729
+ flo worktree add feature/123 --no-provision # Create it, skip copy/link/setup
730
+ flo worktree list # Every worktree and its provisioning state
731
+ flo worktree remove feature/123-thing # Refuses a dirty tree unless --force
732
+ ```
733
+
640
734
  ### Diagnostics
641
735
 
642
736
  ```bash