freeharness 0.4.1 → 0.4.2

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 (194) hide show
  1. package/README.md +8 -7
  2. package/canonical/HARVEST.yaml +25 -14
  3. package/canonical/PROVENANCE.yaml +1 -1
  4. package/canonical/agents/README.md +77 -36
  5. package/canonical/agents/agentic-architect.md +2 -1
  6. package/canonical/agents/database-reviewer.md +6 -8
  7. package/canonical/agents/explorer-ai-engineer-analyst.md +2 -6
  8. package/canonical/agents/implementer.md +30 -0
  9. package/canonical/agents/pr-reviewer.md +9 -11
  10. package/canonical/agents/python-reviewer.md +7 -9
  11. package/canonical/agents/report-formatter.md +7 -3
  12. package/canonical/agents/security-reviewer.md +7 -8
  13. package/canonical/agents/test-writer.md +5 -2
  14. package/canonical/hooks/cost-prices.json +11 -9
  15. package/canonical/hooks/freeharness-config-guard.mjs +8072 -87
  16. package/canonical/hooks/freeharness-context-monitor.mjs +88 -54
  17. package/canonical/hooks/freeharness-converge.mjs +78 -23
  18. package/canonical/hooks/freeharness-cost-tracker.mjs +1129 -218
  19. package/canonical/hooks/freeharness-memory-guard.mjs +20 -23
  20. package/canonical/hooks/freeharness-precompact.mjs +217 -87
  21. package/canonical/hooks/freeharness-quota-tap.mjs +173 -0
  22. package/canonical/hooks/freeharness-reload-context.mjs +197 -0
  23. package/canonical/hooks/freeharness-repeat-tool.mjs +1 -1
  24. package/canonical/hooks/freeharness-sdd-context.mjs +970 -0
  25. package/canonical/hooks/freeharness-session-start +297 -59
  26. package/canonical/hooks/hooks.claude-code.json +1 -1
  27. package/canonical/hooks/hooks.config-guard.claude-code.json +3 -2
  28. package/canonical/hooks/hooks.context-monitor.claude-code.json +1 -1
  29. package/canonical/hooks/hooks.converge.claude-code.json +1 -1
  30. package/canonical/hooks/hooks.memory-guard.claude-code.json +3 -2
  31. package/canonical/hooks/hooks.reload-context.claude-code.json +15 -0
  32. package/canonical/openspec/schema.spec-driven.yaml +29 -8
  33. package/canonical/openspec/templates/follow-ups.md +3 -2
  34. package/canonical/openspec/templates/proposal.md +1 -1
  35. package/canonical/openspec/templates/tasks.md +8 -0
  36. package/canonical/rules/CLAUDE.md +5 -4
  37. package/canonical/rules/routing.md +10 -9
  38. package/canonical/skills/agent-evaluation/SKILL.md +17 -6
  39. package/canonical/skills/agent-evaluation/evals/cases.yaml +38 -23
  40. package/canonical/skills/agentic-architecture/SKILL.md +4 -0
  41. package/canonical/skills/agentic-architecture/evals/cases.yaml +27 -0
  42. package/canonical/skills/code-review/SKILL.md +9 -2
  43. package/canonical/skills/code-review/evals/cases.yaml +1118 -27
  44. package/canonical/skills/git-workflow/SKILL.md +2 -0
  45. package/canonical/skills/local-code/SKILL.md +2 -2
  46. package/canonical/skills/local-code/evals/cases.yaml +1 -1
  47. package/canonical/skills/report-formatting/SKILL.md +10 -2
  48. package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +3 -3
  49. package/canonical/skills/report-formatting/reference/HELPERS.md +10 -5
  50. package/canonical/skills/report-formatting/reference/RELEASE.md +1 -2
  51. package/canonical/skills/report-formatting/reference/TEMPLATES.md +3 -2
  52. package/canonical/skills/report-formatting/reference/authoring.md +25 -37
  53. package/canonical/skills/report-formatting/scripts/build-architecture.js +1 -1
  54. package/canonical/skills/report-formatting/scripts/build-md-claro.js +5 -8
  55. package/canonical/skills/report-formatting/scripts/check-env.js +0 -4
  56. package/canonical/skills/report-formatting/scripts/docmodel.js +3 -11
  57. package/canonical/skills/report-formatting/scripts/example-build.js +8 -10
  58. package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +8 -10
  59. package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +8 -10
  60. package/canonical/skills/report-formatting/scripts/theme-claro.js +39 -10
  61. package/canonical/skills/subagent-driven-development/SKILL.md +35 -28
  62. package/canonical/skills/subagent-driven-development/evals/cases.yaml +3496 -19
  63. package/canonical/skills/subagent-driven-development/reference/brief.md +185 -35
  64. package/canonical/skills/subagent-driven-development/reference/handoff.md +82 -2
  65. package/canonical/skills/subagent-driven-development/reference/loop.md +57 -0
  66. package/canonical/skills/subagent-driven-development/reference/trees.md +40 -0
  67. package/canonical/skills/subagent-driven-development/reference/workspace.md +31 -0
  68. package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +4771 -326
  69. package/dist/adapters/harness/claude-code.d.ts +19 -3
  70. package/dist/adapters/harness/claude-code.js +204 -39
  71. package/dist/adapters/harness/opencode.js +16 -2
  72. package/dist/adapters/harness/plugin.js +28 -17
  73. package/dist/adapters/memory/doctor.d.ts +174 -29
  74. package/dist/adapters/memory/doctor.js +758 -134
  75. package/dist/adapters/memory/migrate.d.ts +95 -0
  76. package/dist/adapters/memory/migrate.js +497 -0
  77. package/dist/adapters/memory/paths.d.ts +22 -0
  78. package/dist/adapters/memory/paths.js +85 -0
  79. package/dist/adapters/memory/vendored.d.ts +56 -29
  80. package/dist/adapters/memory/vendored.js +191 -154
  81. package/dist/adapters/sync/diff.js +4 -1
  82. package/dist/cli/cleanup-prompt.d.ts +35 -0
  83. package/dist/cli/cleanup-prompt.js +68 -0
  84. package/dist/cli/cleanup.d.ts +22 -24
  85. package/dist/cli/cleanup.js +182 -68
  86. package/dist/cli/cost-quota.d.ts +158 -0
  87. package/dist/cli/cost-quota.js +645 -0
  88. package/dist/cli/cost.d.ts +408 -46
  89. package/dist/cli/cost.js +1731 -57
  90. package/dist/cli/doctor.d.ts +52 -13
  91. package/dist/cli/doctor.js +193 -44
  92. package/dist/cli/hard-cleanup.d.ts +93 -0
  93. package/dist/cli/hard-cleanup.js +552 -0
  94. package/dist/cli/install-facts.d.ts +28 -0
  95. package/dist/cli/install-facts.js +66 -0
  96. package/dist/cli/json-key-edit.d.ts +18 -0
  97. package/dist/cli/json-key-edit.js +118 -0
  98. package/dist/cli/memory-import.d.ts +74 -0
  99. package/dist/cli/memory-import.js +469 -0
  100. package/dist/cli/plugin-validate.d.ts +12 -0
  101. package/dist/cli/plugin-validate.js +43 -0
  102. package/dist/cli/uninstall.d.ts +1 -1
  103. package/dist/cli/uninstall.js +2 -2
  104. package/dist/cli/upstream-launchers.d.ts +49 -0
  105. package/dist/cli/upstream-launchers.js +287 -0
  106. package/dist/index.js +247 -70
  107. package/dist/infra/fsutil.d.ts +31 -3
  108. package/dist/infra/fsutil.js +69 -6
  109. package/dist/infra/manifest.d.ts +2 -1
  110. package/dist/infra/manifest.js +3 -2
  111. package/dist/infra/prices.d.ts +18 -0
  112. package/dist/infra/prices.js +64 -0
  113. package/node_modules/@freeharness/core/dist/tiers.d.ts +10 -1
  114. package/node_modules/@freeharness/core/dist/tiers.js +24 -2
  115. package/node_modules/@freeharness/core/package.json +1 -1
  116. package/node_modules/@freeharness/sdd/PROVENANCE.yaml +279 -2
  117. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +34 -8
  118. package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +7 -6
  119. package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +72 -64
  120. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +48 -16
  121. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +168 -70
  122. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +36 -6
  123. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +110 -49
  124. package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +1 -1
  125. package/node_modules/@freeharness/sdd/dist/src/shim/list.js +57 -14
  126. package/node_modules/@freeharness/sdd/dist/src/shim/nested-change.d.ts +7 -0
  127. package/node_modules/@freeharness/sdd/dist/src/shim/nested-change.js +118 -0
  128. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +3 -1
  129. package/node_modules/@freeharness/sdd/dist/src/shim/proposal-capabilities.d.ts +12 -0
  130. package/node_modules/@freeharness/sdd/dist/src/shim/proposal-capabilities.js +94 -0
  131. package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +17 -0
  132. package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +182 -1
  133. package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +2 -2
  134. package/node_modules/@freeharness/sdd/dist/src/shim/status.js +34 -5
  135. package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +9 -0
  136. package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +49 -41
  137. package/node_modules/@freeharness/sdd/dist/src/shim/warnings.d.ts +21 -0
  138. package/node_modules/@freeharness/sdd/dist/src/shim/warnings.js +66 -0
  139. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/line-endings.d.ts +4 -0
  140. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/line-endings.js +17 -0
  141. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +95 -22
  142. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +6 -0
  143. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +14 -6
  144. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +1 -1
  145. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +1 -1
  146. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +3 -3
  147. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +24 -4
  148. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +4 -7
  149. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +13 -1
  150. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +21 -6
  151. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +80 -19
  152. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +42 -22
  153. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/project-root.d.ts +32 -0
  154. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/project-root.js +39 -0
  155. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +16 -9
  156. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +36 -1
  157. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +65 -30
  158. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +1 -1
  159. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +1 -1
  160. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +8 -13
  161. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +79 -102
  162. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +4 -9
  163. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +50 -10
  164. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +165 -37
  165. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +24 -3
  166. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +55 -8
  167. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +4 -1
  168. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +19 -9
  169. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +10 -0
  170. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +115 -0
  171. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +3 -3
  172. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +20 -20
  173. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +6 -0
  174. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +75 -14
  175. package/node_modules/@freeharness/sdd/package.json +1 -1
  176. package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +47 -7
  177. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +25 -7
  178. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +50 -11
  179. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +48 -10
  180. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +27 -7
  181. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +25 -12
  182. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +17 -5
  183. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +12 -1
  184. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +47 -33
  185. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +17 -5
  186. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +29 -1
  187. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +31 -13
  188. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +75 -27
  189. package/package.json +6 -4
  190. package/provenance/canonical.PROVENANCE.yaml +1 -1
  191. package/provenance/memory.PROVENANCE.yaml +458 -6
  192. package/provenance/sdd.PROVENANCE.yaml +279 -2
  193. package/canonical/hooks/freeharness-auto-memory.mjs +0 -158
  194. package/canonical/hooks/hooks.auto-memory.claude-code.json +0 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freeharness",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Agnostic agentic engineering framework installer (Claude Code, OpenCode, Claude Code plugin emission)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,7 +41,9 @@
41
41
  "verify": "npm run build",
42
42
  "clean": "rm -rf dist canonical NOTICE LICENSE README.md provenance node_modules/@freeharness",
43
43
  "prepare": "npm run bundle:canonical",
44
- "test": "node --import tsx --test test/*.test.ts",
44
+ "test": "npm run test:parallel && npm run test:integration",
45
+ "test:parallel": "node -e \"const t=['guard.test.ts','memory-tags.test.ts','quota-tap.test.ts','sdd-context.test.ts'];const all=require('node:fs').readdirSync('test').filter((n)=>n.endsWith('.test.ts')&&n!=='integration.test.ts').sort();const run=(o,l)=>l.length===0?0:require('node:child_process').spawnSync(process.execPath,['--import','tsx','--test',...o,...l.map((n)=>'test/'+n)],{stdio:'inherit'}).status??1;const p=run([],all.filter((n)=>!t.includes(n)));const s=run(['--test-concurrency=1'],all.filter((n)=>t.includes(n)));process.exit(p||s)\"",
46
+ "test:integration": "node --import tsx --test test/integration.test.ts",
45
47
  "pack:stage": "node scripts/prepack.mjs",
46
48
  "pack:unstage": "node scripts/postpack.mjs",
47
49
  "pack": "node scripts/prepack.mjs && npm pack --ignore-scripts && node scripts/postpack.mjs"
@@ -52,8 +54,8 @@
52
54
  "license": "MIT",
53
55
  "author": "André Negrelli",
54
56
  "dependencies": {
55
- "@freeharness/core": "^0.4.1",
56
- "@freeharness/sdd": "^0.4.1",
57
+ "@freeharness/core": "^0.4.2",
58
+ "@freeharness/sdd": "^0.4.2",
57
59
  "commander": "^12.1.0",
58
60
  "yaml": "^2",
59
61
  "zod": "^4"
@@ -566,7 +566,7 @@ files:
566
566
  commit: "e04ea0b9"
567
567
  license: MIT
568
568
  rewritten: true
569
- note: "Matcher and deny shape only; the 30-minute TTL flag is ours (P2.3)."
569
+ note: "Matcher and deny shape only; the --ttl flag (240 minutes by default) is ours (P2.3)."
570
570
 
571
571
  - path: hooks/freeharness-context-monitor.mjs
572
572
  source: ecc
@@ -4,26 +4,26 @@ upstream:
4
4
  name: "claude-mem"
5
5
  repo: https://github.com/thedotmack/claude-mem
6
6
  fork: https://github.com/anegrelli/claude-mem
7
- baseline_version: "13.25.1"
8
- baseline_commit: "dcfc4422"
7
+ baseline_version: "13.25.3+main"
8
+ baseline_commit: "c4bfa459"
9
9
 
10
10
  runtime_prerequisites:
11
11
  - "Bun >= 1.0 (plugin bundles are `bun build` CJS; hooks run worker-service.cjs through bun-runner.js)"
12
12
  - "uv / Python (Chroma vector store)"
13
13
  - "Claude Agent SDK (worker generation)"
14
14
 
15
- status: "V3-P0 memory-runtime DONE + recall verified on the dev machine (2026-08-15). V3-P0b memory-slim DONE (2026-09-04): engine trimmed to the single capture->store->recall path (216 -> 141 .ts, deps 8 -> 4, plugin dir 70 MB -> 3.1 MB), hooks.json/.mcp.json rewritten to deterministic ${CLAUDE_PLUGIN_ROOT} commands, skill dir aligned to upstream layout. Audit: vendor/claude-mem/SLIM-AUDIT.md; trim record: FIXUP.md section 7. Recall re-verified on the dev machine after the trim (2026-09-04); FreeHarness viewer added (FIXUP §8). V4-P3 memory-quality (2026-09-06): engine hunks ported from claude-mem 13.24.0 (be44b6c8) — bounded observer generations (#3800), field-optimizer, quota guard (#3838), observer-health + quota-cooldown ledgers, uvx-env, kill-process-tree + process-identity, silent observer role + FreeHarness verbatim/English rule, skip_summary noise, single-read transcript parser; port list, ignored set and settings in FIXUP.md section 9; plugin version 13.24.0. Recall re-verify after the port = task 3.6 [machine]. v4.1 memory-local-provider (2026-09-17): FreeHarness-authored opt-in local provider (CLAUDE_MEM_PROVIDER=local) serving the simple tier over a local OpenAI-compatible endpoint, with Claude as the per-batch fallback on local failure; provider interface, session runner, batch routing and health reporting; per-file record in FIXUP.md section 12 and freeharness_local_provider below."
15
+ status: "V3-P0 memory-runtime DONE + recall verified on the dev machine (2026-08-15). V3-P0b memory-slim DONE (2026-09-04): engine trimmed to the single capture->store->recall path (216 -> 141 .ts, deps 8 -> 4, plugin dir 70 MB -> 3.1 MB), hooks.json/.mcp.json rewritten to deterministic ${CLAUDE_PLUGIN_ROOT} commands, skill dir aligned to upstream layout. Audit: vendor/claude-mem/SLIM-AUDIT.md; trim record: FIXUP.md section 7. Recall re-verified on the dev machine after the trim (2026-09-04); FreeHarness viewer added (FIXUP §8). V4-P3 memory-quality (2026-09-06): engine hunks ported from claude-mem 13.24.0 (be44b6c8) — bounded observer generations (#3800), field-optimizer, quota guard (#3838), observer-health + quota-cooldown ledgers, uvx-env, kill-process-tree + process-identity, silent observer role + FreeHarness verbatim/English rule, skip_summary noise, single-read transcript parser; port list, ignored set and settings in FIXUP.md section 9; plugin version 13.24.0. Recall re-verify after the port = task 3.6 [machine]. v4.1 memory-local-provider (2026-09-17): FreeHarness-authored opt-in local provider (CLAUDE_MEM_PROVIDER=local) serving the simple tier over a local OpenAI-compatible endpoint, with Claude as the per-batch fallback on local failure; provider interface, session runner, batch routing and health reporting; per-file record in FIXUP.md section 12 and freeharness_local_provider below. memory-observer-pause (2026-09-23): degraded-mode routing serves every batch of a session locally, of any tier, while a quota cooldown withholds Claude admission; each batch reaches a stored, skipped or dropped terminal outcome, with a second local failure while degraded dropping the batch as degraded_local_failed; the worker's log file switches to the day's file at the first write after the UTC date changes. Per-file record in FIXUP.md section 12. vendor-sync-2026-10 (2026-09-24): 13.25.3+main port landed (ports_13_25_3 above, FIXUP.md section 13); `sync adopt memory` preview reported only the two DIVERGENT tracked files (plugin/hooks/hooks.json, plugin/.mcp.json), skipped by design and never adopted, so nothing was adoptable; the baseline was bumped by hand here and in sources.yaml to c4bfa459 / 13.25.3+main, and the plugin manifests (plugin.json, plugin/package.json, .claude-plugin/marketplace.json) carry 13.25.3, the semver part of baseline_version 13.25.3+main (semver has no room for the +main suffix). memory-quota-freshness: FreeHarness-authored quota freshness fixup, where the local quota guard ignores a window snapshot observed more than 60 minutes ago and every rate_limit_event refreshes the other windows named in its unifiedWindows map; per-file record in FIXUP.md section 12 and freeharness_quota_freshness below. radar-w43-fixes: the upstream privacy and tag-stripping fixes (481bcff76, e04dba2c3, 983d6b258, 8ac62b3e6) are hand ports recorded in ports_radar_w43 below and FIXUP.md section 15; the baseline is unchanged at c4bfa459 / 13.25.3+main because the rest of the upstream 14.x/15.x delta is held."
16
16
 
17
17
  vendored:
18
18
  control_plane:
19
19
  - path: vendor/claude-mem/plugin/hooks/hooks.json
20
- note: "lifecycle hooks (Setup/SessionStart/UserPromptSubmit/PostToolUse/PreToolUse:Read/Stop). DIVERGENT since memory-slim: same events/matchers/timeouts/async as upstream, commands rewritten to `node ${CLAUDE_PLUGIN_ROOT}/scripts/bun-runner.js ... <cmd>` with a static PATH prefix (no login shell, no plugin-cache enumeration). On upstream changes compare the event set and command verbs by hand; never copy the upstream blobs back."
20
+ note: "lifecycle hooks (Setup/SessionStart/UserPromptSubmit/PostToolUse/PostToolUseFailure/PreToolUse:Read/Stop). DIVERGENT since memory-slim: same events/matchers/timeouts/async as upstream except PostToolUseFailure, a FreeHarness addition (memory-deterministic-tier) that runs the PostToolUse observation command with the same matcher, timeout and async so a failing tool call is captured; commands rewritten to `node ${CLAUDE_PLUGIN_ROOT}/scripts/bun-runner.js ... <cmd>` with a static PATH prefix (no login shell, no plugin-cache enumeration). On upstream changes compare the event set and command verbs by hand; never copy the upstream blobs back."
21
21
  - path: vendor/claude-mem/plugin/.mcp.json
22
22
  note: "recall MCP registration (stdio). DIVERGENT: spawns ${CLAUDE_PLUGIN_ROOT}/scripts/mcp-server.cjs directly"
23
23
  - path: vendor/claude-mem/plugin/.claude-plugin/plugin.json
24
24
  note: "plugin manifest shape"
25
25
  - path: vendor/claude-mem/plugin/skills/mem-search
26
- note: "the mem-search skill (the recall entry point FreeHarness calls); the only kept plugin skill; upstream layout"
26
+ note: "the mem-search skill (the recall entry point FreeHarness calls); the only kept plugin skill; upstream layout. SKILL.md is DIVERGENT since radar-w43-fixes: it names only the tools the slim MCP server registers (search, timeline, get_observations, important_workflow, session_start_context), so the upstream get_tool_uses and /knowledge-agent passages are dropped (the slim server serves neither). On upstream changes compare the workflow by hand; never copy the upstream SKILL.md back."
27
27
  - path: vendor/claude-mem/plugin/modes
28
28
  note: "code.json (+ pt-br, chill variants) — the worker's ModeManager fails init without code.json"
29
29
  - path: vendor/claude-mem/.claude-plugin/marketplace.json
@@ -36,7 +36,7 @@ vendored:
36
36
  increment_2:
37
37
  engine_vendored:
38
38
  - path: vendor/claude-mem/engine
39
- note: "141 .ts after memory-slim (+8 with the 13.24 port, FIXUP.md section 9): services (worker [ClaudeProvider only] + context/transcripts/infrastructure/sqlite/sync[Chroma]/server[worker-local HTTP]) + cli (claude-code hook runtime only) + supervisor + utils + types + sdk + servers/mcp-server. Removed set recorded in FIXUP.md section 7 (providers, cloud sync, corpus, smart-file-read, SaaS /v1, other-IDE adapters, viewer/SSE, CLAUDE.md writer, npx-cli). Type gate: `tsc -p engine/tsconfig.check.json` (bun build does not type-check)."
39
+ note: "141 .ts after memory-slim (+8 with the 13.24 port, FIXUP.md section 9): services (worker [ClaudeProvider only] + context/transcripts/infrastructure/sqlite/sync[CanonicalContent]/server[worker-local HTTP]) + cli (claude-code hook runtime only) + supervisor + utils + types + sdk + servers/mcp-server. Removed set recorded in FIXUP.md section 7 (providers, cloud sync, corpus, smart-file-read, SaaS /v1, other-IDE adapters, viewer/SSE, CLAUDE.md writer, npx-cli). Type gate: `tsc -p engine/tsconfig.check.json` (bun build does not type-check). Vector store removed 2026-10-31 (memory-retrieval-redesign, owner ruling; FIXUP.md section 25): sync/ChromaMcpManager.ts, sync/ChromaSync.ts, sync/ChromaSyncState.ts, shared/uvx-bin-dirs.ts, shared/uvx-env.ts, worker/search/SearchOrchestrator.ts, worker/search/errors.ts and worker/search/ResultFormatter.ts are gone, their rows below dropped; sync/ keeps CanonicalContent.ts (the sync_outbox content); the CLAUDE_MEM_CHROMA_* settings are gone and ignored when present. Observation vectors are back as SQLite rows (FIXUP.md section 26): the services inventory gains the vector store (sqlite/VectorStore.ts), the embeddings client (embeddings/EmbeddingsClient.ts, over the shared loopback helper http/local-http.ts) and the idle backfill (worker/EmbedBackfill.ts), with vector search feeding the fused search; there is no external vector store and no subprocess."
40
40
  - path: vendor/claude-mem/SLIM-AUDIT.md
41
41
  note: "memory-slim audit: baseline metrics, keep set, trim set with reachability evidence"
42
42
  plugin_build:
@@ -51,6 +51,7 @@ increment_2:
51
51
  - { name: context-generator, source: services/context-generator.ts, out: plugin/scripts/context-generator.cjs, target: bun }
52
52
  - { name: transcript-watcher, source: services/transcripts/transcript-watcher-entry.ts, out: plugin/scripts/transcript-watcher.cjs, target: bun }
53
53
  generated: "plugin/package.json (type: module; dep zod only)"
54
+ version_source: "cli-hygiene patch (FIXUP.md section 14): every bundle's __DEFAULT_PACKAGE_VERSION__ define, and so the MCP server's serverInfo.version, comes from plugin/.claude-plugin/plugin.json through the exported readPluginVersion(); engine/package.json is never read by the build and may lag a baseline bump. build-plugin.ts builds only when run directly (import.meta.main), so packages/cli/test/memory-build-version.test.ts imports the reader and buildBundles(pluginDir, only?), the bundle step main() runs. No engine runtime file changed."
54
55
  install_mechanism:
55
56
  adapter: packages/cli/src/adapters/memory/vendored.ts (VendoredMemory implements MemoryPort)
56
57
  identity: "thedotmack/claude-mem, key claude-mem@thedotmack (kept so hooks.json/.mcp.json resolvers work unmodified)"
@@ -394,6 +395,457 @@ freeharness_local_provider:
394
395
  status: freeharness
395
396
  note: "spawnSdkProcess and createSdkSpawnFactory take an optional label (default session-<id>) used in the SDK_SPAWN log lines, so a completion's negative spawn id renders as [completion-<n>] instead of the unlabeled [session--1]; the registry key and duplicate scan keep the numeric id"
396
397
 
398
+ # memory-quota-freshness: FreeHarness-authored freshness bound and unified-window refresh
399
+ # for the quota guard. Same row shape as freeharness_13_25; status is always freeharness.
400
+ # Restated for the vendor tree in FIXUP.md section 12.
401
+ freeharness_quota_freshness:
402
+ - commit: "memory-quota-freshness 1.1"
403
+ upstream: "(none — FreeHarness authored)"
404
+ target: engine/services/worker/RateLimitStore.ts
405
+ status: freeharness
406
+ note: "every rate_limit_event refreshes the other windows in its unifiedWindows map (skipping a past or zero reset time, a negative or non-finite utilization and the overage window; a utilization above 1 counts as 1), shouldAbortForQuota ignores a snapshot observed more than 60 minutes ago, and rejection dedup is kept apart from the guard snapshot; an event without a numeric utilization takes it from its own valid unified entry, and the stored own snapshot drops the unifiedWindows map"
407
+ - commit: "memory-quota-freshness 1.1"
408
+ upstream: "(none — FreeHarness authored)"
409
+ target: engine/services/worker/http/routes/SessionRoutes.ts
410
+ status: freeharness
411
+ note: "the quota-guard pause message names the observation time of the snapshot that triggered it"
412
+
413
+ # vendor-sync-2026-10 ports from upstream c4bfa459 (13.25.3 + four untagged main fixes),
414
+ # pre-port baseline dcfc4422 (13.25.1, ports_13_25 above). Same row shape as ports_13_25.
415
+ # `sync adopt memory` never touches this list. Restated for the vendor tree in FIXUP.md
416
+ # section 13.
417
+ ports_13_25_3:
418
+ - commit: "81ea0a932 (#4124)"
419
+ upstream: services/context/ContextConfigLoader.ts
420
+ target: engine/services/context/ContextConfigLoader.ts
421
+ status: adapted
422
+ note: "resolveIdSet() (added under 1ce59d48 hardening, ports_13_25 above) now filters a partial match down to only the ids the active mode carries, discarding the rest, instead of keeping the full configured set; a warning still names the discarded ids and a total mismatch still falls back to the full mode list"
423
+ - commit: "c4bfa4595 (#4202)"
424
+ upstream: services/worker/RateLimitStore.ts
425
+ target: engine/services/worker/RateLimitStore.ts
426
+ status: port
427
+ note: "normalizeResetTimeMs() extracted from minutesUntilReset; shouldAbortForQuota's per-window loop skips a snapshot whose normalized reset time has already elapsed, without removing it from the store, so a stale rejection cannot repeatedly wedge the observer after its window actually reset, and still dedups as not-new against set()'s telemetry"
428
+ - commit: "b1b5cd9a0 (#4190)"
429
+ upstream: supervisor/process-registry.ts
430
+ target: engine/supervisor/process-registry.ts
431
+ status: port
432
+ note: "retainSupersededEntry() re-keys a still-alive process displaced from a fixed registry id (chroma-mcp and similar) to <id>#superseded:<pid> instead of dropping the record on register(); the existing reapers (getAll(), pruneDeadEntries(), isSameProcess-gated shutdown) reach it under its own id and remove it once it exits"
433
+ - commit: "f9f6dfc7b (#4205)"
434
+ upstream: services/worker/session/response-pacer.ts
435
+ target: engine/services/worker/session/response-pacer.ts
436
+ status: port
437
+ note: "new module: ObserverResponsePacer (mark/answer/close/activity/waitForAnswer, hasStalled fence), planResponseStallResume(), RESPONSE_STALL_RESUME_DELAY_MS (30 s), MAX_CONSECUTIVE_STALL_RESUMES (3), plus the FreeHarness transportFailureMessage() (observer-health message for a transport:* exit); upstream behavior unchanged, comments condensed to the 20% budget; planResponseStallResume takes Pick<ActiveSession, 'consecutiveResponseStalls'> so the pure module loads under Node"
438
+ - commit: "f9f6dfc7b (#4205)"
439
+ upstream: services/worker/ClaudeProvider.ts
440
+ target: engine/services/worker/ClaudeProvider.ts
441
+ status: adapted
442
+ note: "the Claude feed yields at most one unanswered prompt per generation: stale claims reset before the init prompt, awaitObserverAnswer() after every yield, frames fenced after a stall, the stall window re-armed per frame (plus an announced api_retry delay), the gate opened per result frame and closed in finally; an unanswered prompt past IDLE_TIMEOUT_MS aborts with transport:response_stall and returns the batch to pending. Merged with freeharness_13_25 and freeharness_local_provider: no worker parameter (memory-slim) and no compressField signal (e6e4d738f not ported), so the pacer follows the optional compressField (CLAUDE_MEM_FIELD_OPTIMIZER); the gate opens at the end of the existing result branch (the upstream failed-turn re-queue is not vendored); the quota guard, the Provider contract and complete() are untouched"
443
+ - commit: "f9f6dfc7b (#4205)"
444
+ upstream: services/worker/agents/ResponseProcessor.ts
445
+ target: engine/services/worker/agents/ResponseProcessor.ts
446
+ status: adapted
447
+ note: "clearDebtForAnsweredWork() resets consecutiveContextOverflows and consecutiveResponseStalls only for a reply to queued work, never an init reply; merged with freeharness_local_provider: a local reply (isLocalReply) always clears, since it answers a batch and has no init prompt; the observation-mode filter (freeharness_13_25) is untouched"
448
+ - commit: "f9f6dfc7b (#4205)"
449
+ upstream: services/worker/http/routes/SessionRoutes.ts
450
+ target: engine/services/worker/http/routes/SessionRoutes.ts
451
+ status: adapted
452
+ note: "a starting generator clears a pending stallResumeTimer; a transport:response_stall exit resumes after 30 s, at most 3 times in a row. Merged after the FreeHarness exit accounting: a Claude-run stall also records the existing transport observer-health entry, with a stall-specific message from transportFailureMessage() instead of the transport-failure one, and localRunPause still skips a local run's own pauses; runLocalGenerator and the quota_guard accounting are untouched"
453
+ - commit: "f9f6dfc7b (#4205)"
454
+ upstream: services/worker/session/recycle-conversation.ts
455
+ target: engine/services/worker/session/recycle-conversation.ts
456
+ status: adapted
457
+ note: "MAX_CONSECUTIVE_RECYCLES docstring states a fresh generation fits because the feed is paced; condensed to keep the file's comment share at its base"
458
+ - commit: "f9f6dfc7b (#4205)"
459
+ upstream: services/worker-types.ts
460
+ target: engine/services/worker-types.ts
461
+ status: port
462
+ note: "ActiveSession.consecutiveResponseStalls? and stallResumeTimer?"
463
+ - commit: "f9f6dfc7b (#4205)"
464
+ upstream: services/worker/SessionMessageBuffer.ts
465
+ target: engine/services/worker/SessionMessageBuffer.ts
466
+ status: port
467
+ note: "IDLE_TIMEOUT_MS exported as the response-stall window; the cached-view drain() (freeharness_local_provider) is untouched"
468
+ - commit: "609da9f94 (#4189)"
469
+ upstream: sdk/prompts.ts
470
+ target: engine/sdk/prompts.ts
471
+ status: port
472
+ note: "stripImagePayloadsFromField() parses a field stored as JSON text before stripping and hands back the original text when nothing was stripped; buildObservationPrompt uses it; the Read-tool { type: 'image', file: { base64 } } block is elided; elided blocks survive a second pass with their byte count; an untouched value keeps its identity"
473
+ - commit: "609da9f94 (#4189)"
474
+ upstream: services/worker/field-optimizer.ts
475
+ target: engine/services/worker/field-optimizer.ts
476
+ status: adapted
477
+ note: "optimizeObservationFields strips both fields before the oversize check and the compressor; the vendored optimizer has no compactEditOutput (e6e4d738f not ported), so the stripped fields feed optimizeField directly; with CLAUDE_MEM_FIELD_OPTIMIZER=false the strip inside buildObservationPrompt still applies"
478
+ - commit: "4d323afe7 (#4125)"
479
+ upstream: "retry.ts, services/worker/OpenAICompatibleProvider.ts, shared/SettingsDefaultsManager.ts"
480
+ target: "(none)"
481
+ status: ignored
482
+ note: "the alt-provider retry path; the upstream retry loop (retry.ts) is absent from the slim engine, which ships a single-provider Claude implementation (ports_13_25 above, 4e966e15 row), and the FreeHarness LocalProvider (FIXUP.md section 12) bounds its calls with its own timeout setting, CLAUDE_MEM_LOCAL_TIMEOUT_MS"
483
+ - commit: "0e7b03f19 (#4166)"
484
+ upstream: "http/routes/SettingsRoutes.ts, viewer (ContextSettingsModal.tsx, useSettings.ts, types.ts), services/telemetry/error-scrub.ts, services/telemetry/scrub.ts"
485
+ target: "(none)"
486
+ status: ignored
487
+ note: "SettingsRoutes.ts and the React viewer are removed in memory-slim (skipped list below); FreeHarness's own read-only viewer (freeharness_own above) has no settings write route. error-scrub.ts and scrub.ts (the redaction-order hardening and PostHog query/userinfo/assignment-secret scrubbing this commit also carries) are absent from the slim engine's telemetry shim, which is no-op stubs with no redaction code to harden"
488
+ - commit: "b3f0d7cfa, eb88c1670, 4e98d977c (sync-hub + merge)"
489
+ upstream: "sync-hub poll-mode projection"
490
+ target: "(none)"
491
+ status: ignored
492
+ note: "the cloud sync-hub is not vendored (memory-slim dropped CloudSync/SyncClient/SyncApply, skipped list below)"
493
+ - commit: "d8bc9755e"
494
+ upstream: README.md
495
+ target: "(none)"
496
+ status: ignored
497
+ note: "docs/marketing"
498
+ - commit: "adce0fdfa, 4520de9e0"
499
+ upstream: "package.json version bumps"
500
+ target: "(none)"
501
+ status: ignored
502
+ note: "the FreeHarness plugin manifests (plugin/.claude-plugin/plugin.json, plugin/package.json, .claude-plugin/marketplace.json) carry the semver part (13.25.3) of baseline_version 13.25.3+main above, bumped with the rest of this range's baseline move, not per commit"
503
+
504
+ # Hand ports of the upstream privacy and tag-stripping fixes landed after the
505
+ # 13.25.3+main baseline. The baseline stays c4bfa459: the rest of the upstream 14.x/15.x
506
+ # delta is held. Restated for the vendor tree in FIXUP.md section 15.
507
+ ports_radar_w43:
508
+ - commit: "481bcff76 (#4761)"
509
+ upstream: utils/tag-stripping.ts
510
+ target: "engine/utils/memory-tag-scanner.ts, engine/utils/tag-stripping.ts"
511
+ status: adapted
512
+ note: "stripTags pairs nested and overlapping memory tags with a balanced scanner instead of a lazy back-referenced regex; the scanner lives in the import-free module memory-tag-scanner.ts so Node tests load it without the logger, and tag-stripping.ts delegates to it (no STRIP_REGEX exists)"
513
+ - commit: "e04dba2c3 (#4897)"
514
+ upstream: utils/tag-stripping.ts
515
+ target: engine/utils/memory-tag-scanner.ts
516
+ status: port
517
+ note: "a closing tag may carry whitespace before the > (</private >); the scanner's close matcher is </name\\s*>"
518
+ - commit: "e04dba2c3 (#4897)"
519
+ upstream: "utils/tag-stripping.ts (JSON-node sanitizer probe)"
520
+ target: "(none)"
521
+ status: ignored
522
+ note: "the slim engine has no JSON-node sanitizer, so the hunk has nothing to apply to"
523
+ - commit: "983d6b258 (#4801)"
524
+ upstream: utils/tag-stripping.ts, shared/transcript-parser.ts, services/context/ObservationCompiler.ts
525
+ target: "engine/utils/memory-tag-scanner.ts, engine/utils/tag-stripping.ts, engine/shared/transcript-parser.ts, engine/services/context/ObservationCompiler.ts"
526
+ status: port
527
+ note: "system-reminder blocks are stripped by a linear indexOf scan (stripSystemReminderBlocks) instead of a lazy regex that goes quadratic on unclosed openers; the transcript parser and the observation compiler call it, and tag-stripping.ts exports no reminder regex. shared/advisor-transcript.ts is not vendored, so that hunk has no target"
528
+ - commit: "8ac62b3e6 (#4899)"
529
+ upstream: services/sqlite/prompt-storage.ts
530
+ target: engine/services/sqlite/prompt-storage.ts
531
+ status: port
532
+ note: "the prompt normalizer returns the stripped, trimmed text (empty string when the prompt is fully private) so a fully private prompt is never stored raw as the session's user_prompt"
533
+
534
+ # radar-w43-fixes: FreeHarness-authored privacy import paths (no upstream commit).
535
+ # Same row shape as freeharness_13_25; status is always freeharness. Restated for the
536
+ # vendor tree in FIXUP.md section 15.
537
+ freeharness_radar_w43:
538
+ - commit: "radar-w43-fixes 1.2"
539
+ upstream: "(none — FreeHarness authored)"
540
+ target: engine/services/sqlite/SessionStore.ts
541
+ status: freeharness
542
+ note: "importSdkSession and importUserPrompt, which upstream leaves unreachable from the normalizer, bind a normalized user_prompt and prompt_text; importSdkSession keeps a null user_prompt as null"
543
+
544
+ # memory-recall-everywhere: FreeHarness-authored subagent recall (no upstream commit). Same
545
+ # row shape as freeharness_radar_w43; status is always freeharness. Restated for the vendor
546
+ # tree in FIXUP.md section 18. The additive agent_tags table is migration 9001.
547
+ freeharness_recall:
548
+ - commit: "memory-recall-everywhere 2.1"
549
+ upstream: "(none — FreeHarness authored)"
550
+ target: engine/services/sqlite/agent-filters.ts
551
+ status: freeharness
552
+ note: "new, import-free: AGENT_ID_PATTERN, TAG_PATTERN, AgentFilters, hasAgentFilters and agentFilterClause, which ANDs exact agent_type, exact agent_id and an EXISTS over agent_tags joined to sdk_sessions"
553
+ - commit: "memory-recall-everywhere 2.1"
554
+ upstream: "(none — FreeHarness authored)"
555
+ target: engine/services/sqlite/SessionStore.ts
556
+ status: freeharness
557
+ note: "ensureAgentTagsTable (agent_tags, idx_agent_tags_tag, migration 9001) ends the constructor chain; addAgentTags validates before the first insert and counts newly stored tags; agentTags lists them; getObservationsByIds and the timeline readers take agent filters, drop the project under a tag and return no summaries or prompts under any filter"
558
+ - commit: "memory-recall-everywhere 2.1"
559
+ upstream: "(none — FreeHarness authored)"
560
+ target: engine/services/sqlite/SessionSearch.ts
561
+ status: freeharness
562
+ note: "buildFilterClause appends agentFilterClause for the observation alias and drops the project under a tag; searchSessions and searchUserPrompts return empty under any agent filter"
563
+ - commit: "memory-recall-everywhere 2.1"
564
+ upstream: "(none — FreeHarness authored)"
565
+ target: engine/services/sqlite/types.ts
566
+ status: freeharness
567
+ note: "SearchFilters extends AgentFilters"
568
+ - commit: "memory-recall-everywhere 2.1"
569
+ upstream: "(none — FreeHarness authored)"
570
+ target: engine/services/worker/search/strategies/SQLiteSearchStrategy.ts
571
+ status: freeharness
572
+ note: "search passes agentType, agentId and tag to the observation search and skips session and prompt searches when any is set"
573
+ - commit: "memory-recall-everywhere 2.2"
574
+ upstream: "(none — FreeHarness authored)"
575
+ target: engine/services/worker/SearchManager.ts
576
+ status: freeharness
577
+ note: "normalizeParams accepts only snake_case agent filters; search skips sessions and prompts and uses FTS5 instead of Chroma under a filter; timeline passes the filters to the anchor search, the anchor lookup and every getTimelineAround call"
578
+ - commit: "memory-recall-everywhere 2.2"
579
+ upstream: "(none — FreeHarness authored)"
580
+ target: engine/servers/mcp-server.ts
581
+ status: freeharness
582
+ note: "search and timeline tool descriptions and schemas list agent_type, agent_id and tag"
583
+ - commit: "memory-recall-everywhere 2.2"
584
+ upstream: "(none — FreeHarness authored)"
585
+ target: engine/services/worker/http/routes/SearchRoutes.ts
586
+ status: freeharness
587
+ note: "invalidAgentFilter validates agent_type, agent_id and tag (a repeated parameter is invalid); search and timeline answer 400 before any query"
588
+ - commit: "memory-recall-everywhere 2.2"
589
+ upstream: "(none — FreeHarness authored)"
590
+ target: engine/services/worker/http/routes/DataRoutes.ts
591
+ status: freeharness
592
+ note: "observationsBatchSchema accepts agent_type, agent_id and tag and handleGetObservationsByIds forwards them to getObservationsByIds"
593
+ - commit: "memory-recall-everywhere 2.3"
594
+ upstream: "(none — FreeHarness authored)"
595
+ target: engine/services/worker/http/shared.ts
596
+ status: freeharness
597
+ note: "ingestObservation sends a payload with an agentId to storeSubagentRule unless CLAUDE_MEM_SUBAGENT_CAPTURE is observer; storeSubagentRule keeps only the changed path of a Write, Edit, MultiEdit or NotebookEdit call as one rules observation and skips other tools with reason subagent_rules; first drift candidate at the next sync"
598
+ - commit: "memory-recall-everywhere 2.3"
599
+ upstream: "(none — FreeHarness authored)"
600
+ target: engine/shared/SettingsDefaultsManager.ts, shared/SettingsDefaultsManager.ts
601
+ status: freeharness
602
+ note: "CLAUDE_MEM_SUBAGENT_CAPTURE field and default rules, the same in the engine copy and the vendor copy"
603
+ - commit: "memory-recall-everywhere 2.4"
604
+ upstream: "(none — FreeHarness authored)"
605
+ target: engine/services/worker/http/routes/SubagentRoutes.ts
606
+ status: freeharness
607
+ note: "new: POST /api/subagents/start stores tags and answers a deterministic capped brief built from stored rows; POST /api/subagents/stop stores the final report as one rules observation (stripped, cut, fenced, privacy-checked, repeat told apart by content hash); excluded projects answer empty"
608
+ - commit: "memory-recall-everywhere 2.4"
609
+ upstream: "(none — FreeHarness authored)"
610
+ target: engine/services/worker/http/routes/ImportRoutes.ts
611
+ status: freeharness
612
+ note: "exports StoredObservation and syncStoredObservation (fire-and-log Chroma sync); importObservations syncs each freshly stored row; ImportRoutes takes getChromaSync"
613
+ - commit: "memory-recall-everywhere 2.4"
614
+ upstream: "(none — FreeHarness authored)"
615
+ target: engine/services/worker-service.ts
616
+ status: freeharness
617
+ note: "registerRoutes registers SubagentRoutes right after ImportRoutes"
618
+
619
+ # subagent-input-sanitize: FreeHarness-authored folding of untrusted subagent text (no upstream
620
+ # commit). Same row shape as freeharness_recall; status is always freeharness. Restated for the
621
+ # vendor tree in FIXUP.md section 19.
622
+ freeharness_sanitize:
623
+ - commit: "subagent-input-sanitize 1.1"
624
+ upstream: "(none — FreeHarness authored)"
625
+ target: engine/utils/untrusted-text.ts
626
+ status: freeharness
627
+ note: "new, import-free: UNSAFE_RANGES (C0 controls, DEL and C1 controls, bidi and invisible marks), hasUnsafeChar, foldUntrusted (collapse whitespace, trim, swap each unsafe code unit for one replacement character), TASK_BRIEF_CAP and PROJECT_BRIEF_CAP; callers strip memory tags first"
628
+ - commit: "subagent-input-sanitize 1.2"
629
+ upstream: "(none — FreeHarness authored)"
630
+ target: engine/services/worker/http/shared.ts
631
+ status: freeharness
632
+ note: "storeSubagentRule requires AGENT_ID_PATTERN and folds the changed path and agent type before any column or repeat key; the upstream session-memory gate in ingestObservation reads file_path or notebook_path only when a non-empty string, so a non-string path is absent instead of throwing; re-apply the gate guard after an adopt"
633
+ - commit: "subagent-input-sanitize 1.3"
634
+ upstream: "(none — FreeHarness authored)"
635
+ target: engine/services/worker/http/routes/SubagentRoutes.ts
636
+ status: freeharness
637
+ note: "agentType holding an unsafe character is refused with a fixed message; foldLine strips memory tags then folds with foldUntrusted; the brief caps, 4000 for a task tag and 2000 otherwise, are imported from untrusted-text.ts"
638
+
639
+ # memory-hard-fork: FreeHarness-authored free-mem identity for the engine (data directory,
640
+ # database, log, MCP server name, FREE_MEM_ names) with CLAUDE_MEM_ fallbacks (no upstream
641
+ # commit). Same row shape as freeharness_sanitize; status is freeharness, except the two
642
+ # tracked shared/ contract copies, which are DIVERGENT and never adopted. Restated for the
643
+ # vendor tree in FIXUP.md section 20.
644
+ freeharness_hard_fork:
645
+ - commit: "memory-hard-fork 1.1"
646
+ upstream: "(none — FreeHarness authored)"
647
+ target: engine/shared/data-dir.ts
648
+ status: freeharness
649
+ note: "new leaf module: expandHome, publicSettingName, envGet (FREE_MEM_ then CLAUDE_MEM_, empty as unset), toPublicSettings, resolveDataDir (FREE_MEM_DATA_DIR, CLAUDE_MEM_DATA_DIR, settings redirect, ~/.free-mem, legacy ~/.claude-mem while it alone exists)"
650
+ - commit: "memory-hard-fork 1.1"
651
+ upstream: "(none — FreeHarness authored)"
652
+ target: engine/shared/paths.ts
653
+ status: freeharness
654
+ note: "re-exports expandHome and resolveDataDir from data-dir.ts; DB_FILENAME free-mem.db, LEGACY_DB_FILENAME claude-mem.db, resolveDbPath picks the legacy file only while it alone exists; DB_PATH and paths.database() use it"
655
+ - commit: "memory-hard-fork 1.2"
656
+ upstream: "(none — FreeHarness authored)"
657
+ target: engine/shared/SettingsDefaultsManager.ts
658
+ status: freeharness
659
+ note: "data dir defaults from resolveDataDir; get() and applyEnvOverrides read through envGet; loadFromFile reads both name families and every rewrite writes FREE_MEM_ keys and drops the CLAUDE_MEM_ twin; internal keys stay CLAUDE_MEM_*"
660
+ - commit: "memory-hard-fork 1.1"
661
+ upstream: "(none — FreeHarness authored)"
662
+ target: engine/utils/logger.ts
663
+ status: freeharness
664
+ note: "log file is free-mem-<date>.log"
665
+ - commit: "memory-hard-fork 1.1"
666
+ upstream: "(none — FreeHarness authored)"
667
+ target: engine/services/infrastructure/ProcessManager.ts
668
+ status: freeharness
669
+ note: "runOneTimeCwdRemap opens the database through resolveDbPath"
670
+ - commit: "memory-hard-fork 1.4"
671
+ upstream: "(none — FreeHarness authored)"
672
+ target: engine/servers/mcp-server.ts
673
+ status: freeharness
674
+ note: "MCP server name is free-mem"
675
+ - commit: "memory-hard-fork 1.4"
676
+ upstream: "(none — FreeHarness authored)"
677
+ target: engine/scripts/plain/bun-runner.js
678
+ status: freeharness
679
+ note: "crash-log data directory resolved inline, mirroring resolveDataDir (env, settings redirect, ~/.free-mem, legacy directory while it alone exists)"
680
+ - commit: "memory-hard-fork 1.3"
681
+ upstream: "(none — FreeHarness authored)"
682
+ target: engine/scripts/plain/version-check.js
683
+ status: freeharness
684
+ note: "Codex hook flag reads FREE_MEM_CODEX_HOOK then CLAUDE_MEM_CODEX_HOOK inline"
685
+ - commit: "memory-hard-fork 3.1"
686
+ upstream: "(none — FreeHarness authored)"
687
+ target: engine/utils/untrusted-text.ts
688
+ status: freeharness
689
+ note: "unsafe set by code point: adds U+00AD, U+180E, variation selectors U+FE00 to U+FE0E (U+FE0F stays), tag characters U+E0000 to U+E007F, variation selectors supplement U+E0100 to U+E01EF; unpaired surrogates are unsafe; one U+FFFD per unsafe code point"
690
+ - commit: "memory-hard-fork 1.4"
691
+ upstream: "(none — FreeHarness authored)"
692
+ target: engine/services/worker/ClaudeProvider.ts
693
+ status: freeharness
694
+ note: "messages name USER_SETTINGS_PATH and the resolved .env path instead of ~/.claude-mem"
695
+ - commit: "memory-hard-fork 1.3"
696
+ upstream: "(none — FreeHarness authored)"
697
+ target: engine/services/worker/http/routes/SearchRoutes.ts
698
+ status: freeharness
699
+ note: "welcome-hint switch reads through envGet"
700
+ - commit: "memory-hard-fork 1.3"
701
+ upstream: "(none — FreeHarness authored)"
702
+ target: engine/services/worker-service.ts
703
+ status: freeharness
704
+ note: "Codex hook flag and managed-mode check read through envGet"
705
+ - commit: "memory-hard-fork 1.3"
706
+ upstream: "(none — FreeHarness authored)"
707
+ target: engine/services/server/Server.ts
708
+ status: freeharness
709
+ note: "the three CLAUDE_MEM_MANAGED checks read through envGet"
710
+ - commit: "memory-hard-fork 1.3"
711
+ upstream: "(none — FreeHarness authored)"
712
+ target: engine/services/domain/ModeManager.ts
713
+ status: freeharness
714
+ note: "modes directory override reads through envGet"
715
+ - commit: "memory-hard-fork 1.4"
716
+ upstream: "(none — FreeHarness authored)"
717
+ target: engine/shared/dependency-health.ts
718
+ status: freeharness
719
+ note: "Claude CLI setup remediation names USER_SETTINGS_PATH"
720
+ - commit: "memory-hard-fork 1.4"
721
+ upstream: "(none — FreeHarness authored)"
722
+ target: engine/shared/find-claude-executable.ts
723
+ status: freeharness
724
+ note: "CLAUDE_CODE_PATH hints name USER_SETTINGS_PATH"
725
+ - commit: "memory-hard-fork 1.3"
726
+ upstream: "(none — FreeHarness authored)"
727
+ target: engine/shared/mcp-client.ts
728
+ status: freeharness
729
+ note: "resolveNodeCommand reads CLAUDE_MEM_NODE_PATH through envGet"
730
+ - commit: "memory-hard-fork 1.4"
731
+ upstream: "(none — FreeHarness authored)"
732
+ target: engine/shared/observer-health.ts
733
+ status: freeharness
734
+ note: "observer-health warning names USER_SETTINGS_PATH"
735
+ - commit: "memory-hard-fork 1.3"
736
+ upstream: "(none — FreeHarness authored)"
737
+ target: engine/shared/should-track-project.ts
738
+ status: freeharness
739
+ note: "CLAUDE_MEM_INTERNAL reads through envGet"
740
+ - commit: "memory-hard-fork 1.3"
741
+ upstream: "(none — FreeHarness authored)"
742
+ target: engine/shared/worker-utils.ts
743
+ status: freeharness
744
+ note: "CLAUDE_MEM_WORKER_SCRIPT_PATH reads through envGet"
745
+ - commit: "memory-hard-fork 1.1"
746
+ upstream: "(none — FreeHarness authored)"
747
+ target: shared/paths.ts
748
+ status: DIVERGENT
749
+ note: "tracked contract copy, not edited; differs from engine/shared/paths.ts by the marketplace directory, the resolver, the database name and the re-exports"
750
+ - commit: "memory-hard-fork 1.2"
751
+ upstream: "(none — FreeHarness authored)"
752
+ target: shared/SettingsDefaultsManager.ts
753
+ status: DIVERGENT
754
+ note: "tracked contract copy, not edited; lacks the FREE_MEM_ boundary and the two context-observation keys the engine copy adds"
755
+
756
+ # recall-privacy-fixes: FreeHarness-authored privacy fixes in the engine (no upstream commit).
757
+ # The tag-name rule diverges from upstream, which matches names case-sensitively and exactly;
758
+ # an adopt re-applies it. Same row shape as freeharness_hard_fork; status is freeharness.
759
+ # Restated for the vendor tree in FIXUP.md section 21.
760
+ freeharness_recall_privacy:
761
+ - commit: "recall-privacy-fixes 2.1"
762
+ upstream: "(none — FreeHarness authored)"
763
+ target: engine/utils/memory-tag-scanner.ts
764
+ status: freeharness
765
+ note: "tag names match a listed name case-insensitively or by the listed-name- prefix, longest first; diverges from upstream's exact, case-sensitive match"
766
+ - commit: "recall-privacy-fixes 2.2"
767
+ upstream: "(none — FreeHarness authored)"
768
+ target: engine/services/worker/http/routes/SessionRoutes.ts
769
+ status: freeharness
770
+ note: "prompt tags stripped until unchanged, at most 8 passes, before the cap, log, rows and observer; a prompt still changing at the limit is withheld; an empty stripped prompt saves an empty prompt row"
771
+ - commit: "recall-privacy-fixes 1.1, 2.3"
772
+ upstream: "(none — FreeHarness authored)"
773
+ target: engine/services/worker/http/routes/SubagentRoutes.ts
774
+ status: freeharness
775
+ note: "stop route accepts optional tags and records them before the report; exclusion goes through isCwdExcluded"
776
+ - commit: "recall-privacy-fixes 2.3"
777
+ upstream: "(none — FreeHarness authored)"
778
+ target: engine/utils/project-filter.ts
779
+ status: freeharness
780
+ note: "isCwdExcluded matches the cwd and the parent path of a git worktree; git is consulted only when a pattern is set"
781
+ - commit: "recall-privacy-fixes 2.3"
782
+ upstream: "(none — FreeHarness authored)"
783
+ target: engine/services/worker/http/shared.ts
784
+ status: freeharness
785
+ note: "ingestObservation checks the project exclusion through isCwdExcluded"
786
+ - commit: "recall-privacy-fixes 2.3"
787
+ upstream: "(none — FreeHarness authored)"
788
+ target: engine/shared/should-track-project.ts
789
+ status: freeharness
790
+ note: "shouldTrackProject uses isCwdExcluded"
791
+
792
+ # memory-worker-identity: FreeHarness-authored worker identity in the engine (no upstream commit).
793
+ # /api/health carries product "free-mem"; one classifier tells our worker from another program on
794
+ # the port, and a foreign responder is never waited on, spawned over or recycled. Search paging
795
+ # values are coerced by a shared reader. Same row shape as freeharness_recall_privacy.
796
+ # Restated for the vendor tree in FIXUP.md section 27.
797
+ freeharness_worker_identity:
798
+ - commit: "memory-worker-identity 1.1"
799
+ upstream: "(none — FreeHarness authored)"
800
+ target: engine/shared/worker-identity.ts
801
+ status: freeharness
802
+ note: "new; classifyWorker (ours, ours-stale, foreign), filterForeignText and foreignWorkerLine"
803
+ - commit: "memory-worker-identity 1.1"
804
+ upstream: "(none — FreeHarness authored)"
805
+ target: engine/services/server/Server.ts
806
+ status: freeharness
807
+ note: "/api/health adds product: free-mem"
808
+ - commit: "memory-worker-identity 1.2.1, 1.5"
809
+ upstream: "(none — FreeHarness authored)"
810
+ target: engine/shared/worker-utils.ts
811
+ status: freeharness
812
+ note: "ensureWorker returns a WorkerCheck; the health body is classified before the PID-file check; a foreign responder is never recycled or spawned over; WorkerFallback gains foreign facts and reason worker_foreign"
813
+ - commit: "memory-worker-identity 1.2.1"
814
+ upstream: "(none — FreeHarness authored)"
815
+ target: engine/cli/handlers/context.ts
816
+ status: freeharness
817
+ note: "worker_foreign returns an empty context plus the foreign-worker line as a user-only system message"
818
+ - commit: "memory-worker-identity 1.2.2, 1.5"
819
+ upstream: "(none — FreeHarness authored)"
820
+ target: engine/services/worker-spawner.ts
821
+ status: freeharness
822
+ note: "WorkerStartResult gains foreign; a responder on the configured worker host is classified before each readiness wait, with no wait, spawn or lock for a foreign one"
823
+ - commit: "memory-worker-identity 1.2.2"
824
+ upstream: "(none — FreeHarness authored)"
825
+ target: engine/services/worker-service.ts
826
+ status: freeharness
827
+ note: "start command and hook command handle foreign with a fixed message"
828
+ - commit: "memory-worker-identity 1.3, 1.5"
829
+ upstream: "(none — FreeHarness authored)"
830
+ target: engine/servers/mcp-server.ts
831
+ status: freeharness
832
+ note: "per-call health check replaces verifyWorkerConnection; a foreign responder gets a fixed tool refusal naming only our port and skips the auto-start"
833
+ - commit: "memory-worker-identity 5.1"
834
+ upstream: "(none — FreeHarness authored)"
835
+ target: engine/shared/numbers.ts
836
+ status: freeharness
837
+ note: "new; wholeNumber, the one reader of route values that arrive as text"
838
+ - commit: "memory-worker-identity 5.1"
839
+ upstream: "(none — FreeHarness authored)"
840
+ target: engine/services/search/fused-request.ts
841
+ status: freeharness
842
+ note: "wholeNumber moved to numbers.ts and re-exported"
843
+ - commit: "memory-worker-identity 5.1"
844
+ upstream: "(none — FreeHarness authored)"
845
+ target: engine/services/sqlite/SessionSearch.ts
846
+ status: freeharness
847
+ note: "searchSessions and searchUserPrompts read limit and offset through wholeNumber"
848
+
397
849
  roadmap:
398
850
  - "P4 inc.2 / V3-P0: DONE (engine + plugin build + MemoryPort install/register). Machine-only: observation generation + Chroma recall (Agent-SDK creds, uvx network)."
399
851
  - "vendor-sync-2026-09: DONE — 13.25.1 port (ports_13_25 above); FIXUP.md section 10 (the same port list, restated for the vendor tree) blocked by the memory-guard hook's path exception (task 1.1); plugin manifests + engine/package.json at 13.25.1 (task 1.5); sync adopt memory bumped baseline_commit/baseline_version above."