@danielmarbach/mnemonic-mcp 0.20.0 → 0.21.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.
package/build/index.js CHANGED
@@ -19,7 +19,7 @@ import { getRelationshipPreview } from "./relationships.js";
19
19
  import { cleanMarkdown } from "./markdown.js";
20
20
  import { MnemonicConfigStore, readVaultSchemaVersion } from "./config.js";
21
21
  import { CONSOLIDATION_MODES, PROTECTED_BRANCH_BEHAVIORS, PROJECT_POLICY_SCOPES, WRITE_SCOPES, isProtectedBranch, resolveProtectedBranchBehavior, resolveProtectedBranchPatterns, resolveConsolidationMode, resolveWriteScope, } from "./project-memory-policy.js";
22
- import { classifyTheme, classifyThemeWithGraduation, computeThemesWithGraduation, summarizePreview, titleCaseTheme, withinThemeScore, anchorScore, computeConnectionDiversity, } from "./project-introspection.js";
22
+ import { classifyTheme, classifyThemeWithGraduation, computeThemesWithGraduation, summarizePreview, titleCaseTheme, daysSinceUpdate, withinThemeScore, anchorScore, computeConnectionDiversity, workingStateScore, extractNextAction, } from "./project-introspection.js";
23
23
  import { getEffectiveMetadata } from "./role-suggestions.js";
24
24
  import { detectProject, getCurrentGitBranch, resolveProjectIdentity } from "./project.js";
25
25
  import { VaultManager } from "./vault.js";
@@ -321,6 +321,18 @@ async function resolveProject(cwd) {
321
321
  getProjectIdentityOverride: async (projectId) => configStore.getProjectIdentityOverride(projectId),
322
322
  });
323
323
  }
324
+ function toProjectRef(project) {
325
+ return project ? { id: project.id, name: project.name } : undefined;
326
+ }
327
+ function noteProjectRef(note) {
328
+ if (!note.project || !note.projectName) {
329
+ return undefined;
330
+ }
331
+ return {
332
+ id: note.project,
333
+ name: note.projectName,
334
+ };
335
+ }
324
336
  async function resolveProjectIdentityForCwd(cwd) {
325
337
  if (!cwd)
326
338
  return undefined;
@@ -1815,9 +1827,10 @@ server.registerTool("recall", {
1815
1827
  .describe("'project' = only this project's memories (project-scoped storage), " +
1816
1828
  "'global' = only unscoped memories (main/global storage), " +
1817
1829
  "'all' = both, with project notes boosted (default)"),
1830
+ lifecycle: z.enum(["temporary", "permanent"]).optional().describe("Filter results by lifecycle. Useful for recovering working-state with `lifecycle: temporary` after `project_memory_summary` orientation."),
1818
1831
  }),
1819
1832
  outputSchema: RecallResultSchema,
1820
- }, async ({ query, cwd, limit, minSimilarity, mode, verbose, tags, scope }) => {
1833
+ }, async ({ query, cwd, limit, minSimilarity, mode, verbose, tags, scope, lifecycle }) => {
1821
1834
  const t0Recall = performance.now();
1822
1835
  await ensureBranchSynced(cwd);
1823
1836
  const project = await resolveProject(cwd);
@@ -1863,6 +1876,9 @@ server.registerTool("recall", {
1863
1876
  if (!tags.every((t) => noteTags.has(t)))
1864
1877
  continue;
1865
1878
  }
1879
+ if (lifecycle && note.lifecycle !== lifecycle) {
1880
+ continue;
1881
+ }
1866
1882
  const isProjectNote = note.project !== undefined;
1867
1883
  const isCurrentProject = project && note.project === project.id;
1868
1884
  if (scope === "project") {
@@ -1967,8 +1983,7 @@ server.registerTool("recall", {
1967
1983
  title: note.title,
1968
1984
  score,
1969
1985
  boosted,
1970
- project: note.project,
1971
- projectName: note.projectName,
1986
+ project: noteProjectRef(note),
1972
1987
  vault: storageLabel(vault),
1973
1988
  tags: note.tags,
1974
1989
  lifecycle: note.lifecycle,
@@ -2142,8 +2157,7 @@ server.registerTool("update", {
2142
2157
  title: updated.title,
2143
2158
  fieldsModified: changes,
2144
2159
  timestamp: now,
2145
- project: updated.project,
2146
- projectName: updated.projectName,
2160
+ project: noteProjectRef(updated),
2147
2161
  lifecycle: updated.lifecycle,
2148
2162
  persistence,
2149
2163
  };
@@ -2247,8 +2261,7 @@ server.registerTool("forget", {
2247
2261
  action: "forgotten",
2248
2262
  id,
2249
2263
  title: note.title,
2250
- project: note.project,
2251
- projectName: note.projectName,
2264
+ project: noteProjectRef(note),
2252
2265
  relationshipsCleaned: vaultChanges.size > 0 ? Array.from(vaultChanges.values()).reduce((sum, files) => sum + files.length - 1, 0) : 0,
2253
2266
  vaultsModified: Array.from(vaultChanges.keys()).map(v => storageLabel(v)),
2254
2267
  retry,
@@ -2326,10 +2339,10 @@ server.registerTool("get", {
2326
2339
  id: note.id,
2327
2340
  title: note.title,
2328
2341
  content: note.content,
2329
- project: note.project,
2330
- projectName: note.projectName,
2342
+ project: noteProjectRef(note),
2331
2343
  tags: note.tags,
2332
2344
  lifecycle: note.lifecycle,
2345
+ alwaysLoad: note.alwaysLoad,
2333
2346
  relatedTo: note.relatedTo,
2334
2347
  createdAt: note.createdAt,
2335
2348
  updatedAt: note.updatedAt,
@@ -2340,7 +2353,7 @@ server.registerTool("get", {
2340
2353
  const lines = [];
2341
2354
  for (const note of found) {
2342
2355
  lines.push(`## ${note.title} (${note.id})`);
2343
- lines.push(`project: ${note.projectName ?? note.project ?? "global"} | stored: ${note.vault} | lifecycle: ${note.lifecycle}`);
2356
+ lines.push(`project: ${note.project?.name ?? "global"} | stored: ${note.vault} | lifecycle: ${note.lifecycle}`);
2344
2357
  if (note.tags.length > 0)
2345
2358
  lines.push(`tags: ${note.tags.join(", ")}`);
2346
2359
  lines.push("");
@@ -2405,8 +2418,7 @@ server.registerTool("where_is_memory", {
2405
2418
  action: "located",
2406
2419
  id: note.id,
2407
2420
  title: note.title,
2408
- project: note.project,
2409
- projectName: note.projectName,
2421
+ project: noteProjectRef(note),
2410
2422
  vault: vaultLabel,
2411
2423
  updatedAt: note.updatedAt,
2412
2424
  relatedCount,
@@ -2484,8 +2496,7 @@ server.registerTool("list", {
2484
2496
  const structuredNotes = entries.map(({ note, vault }) => ({
2485
2497
  id: note.id,
2486
2498
  title: note.title,
2487
- project: note.project,
2488
- projectName: note.projectName,
2499
+ project: noteProjectRef(note),
2489
2500
  tags: note.tags,
2490
2501
  lifecycle: note.lifecycle,
2491
2502
  vault: storageLabel(vault),
@@ -2786,16 +2797,21 @@ server.registerTool("recent_memories", {
2786
2797
  limit: z.number().int().min(1).max(20).optional().default(5),
2787
2798
  includePreview: z.boolean().optional().default(true),
2788
2799
  includeStorage: z.boolean().optional().default(true),
2800
+ lifecycle: z.enum(["temporary", "permanent"]).optional().describe("Filter results by lifecycle. Useful for recovering working-state with `lifecycle: temporary` after `project_memory_summary` orientation."),
2789
2801
  }),
2790
2802
  outputSchema: RecentResultSchema,
2791
- }, async ({ cwd, scope, storedIn, limit, includePreview, includeStorage }) => {
2803
+ }, async ({ cwd, scope, storedIn, limit, includePreview, includeStorage, lifecycle }) => {
2792
2804
  await ensureBranchSynced(cwd);
2793
2805
  const { project, entries } = await collectVisibleNotes(cwd, scope, undefined, storedIn);
2794
- const recent = [...entries]
2806
+ let filteredEntries = entries;
2807
+ if (lifecycle) {
2808
+ filteredEntries = entries.filter(({ note }) => note.lifecycle === lifecycle);
2809
+ }
2810
+ const recent = [...filteredEntries]
2795
2811
  .sort((a, b) => b.note.updatedAt.localeCompare(a.note.updatedAt))
2796
2812
  .slice(0, limit);
2797
2813
  if (recent.length === 0) {
2798
- const structuredContent = { action: "recent_shown", project: project?.id, projectName: project?.name, count: 0, limit: limit || 5, notes: [] };
2814
+ const structuredContent = { action: "recent_shown", project: toProjectRef(project), count: 0, limit: limit || 5, notes: [] };
2799
2815
  return { content: [{ type: "text", text: "No memories found." }], structuredContent };
2800
2816
  }
2801
2817
  const header = project && scope !== "global"
@@ -2810,8 +2826,7 @@ server.registerTool("recent_memories", {
2810
2826
  const structuredNotes = recent.map(({ note, vault }) => ({
2811
2827
  id: note.id,
2812
2828
  title: note.title,
2813
- project: note.project,
2814
- projectName: note.projectName,
2829
+ project: noteProjectRef(note),
2815
2830
  tags: note.tags,
2816
2831
  lifecycle: note.lifecycle,
2817
2832
  vault: storageLabel(vault),
@@ -2820,8 +2835,7 @@ server.registerTool("recent_memories", {
2820
2835
  }));
2821
2836
  const structuredContent = {
2822
2837
  action: "recent_shown",
2823
- project: project?.id,
2824
- projectName: project?.name,
2838
+ project: toProjectRef(project),
2825
2839
  count: recent.length,
2826
2840
  limit: limit || 5,
2827
2841
  notes: structuredNotes,
@@ -2860,7 +2874,7 @@ server.registerTool("memory_graph", {
2860
2874
  await ensureBranchSynced(cwd);
2861
2875
  const { project, entries } = await collectVisibleNotes(cwd, scope, undefined, storedIn);
2862
2876
  if (entries.length === 0) {
2863
- const structuredContent = { action: "graph_shown", project: project?.id, projectName: project?.name, nodes: [], limit, truncated: false };
2877
+ const structuredContent = { action: "graph_shown", project: toProjectRef(project), nodes: [], limit, truncated: false };
2864
2878
  return { content: [{ type: "text", text: "No memories found." }], structuredContent };
2865
2879
  }
2866
2880
  const visibleIds = new Set(entries.map((entry) => entry.note.id));
@@ -2875,7 +2889,7 @@ server.registerTool("memory_graph", {
2875
2889
  })
2876
2890
  .filter(Boolean);
2877
2891
  if (lines.length === 0) {
2878
- const structuredContent = { action: "graph_shown", project: project?.id, projectName: project?.name, nodes: [], limit, truncated: false };
2892
+ const structuredContent = { action: "graph_shown", project: toProjectRef(project), nodes: [], limit, truncated: false };
2879
2893
  return { content: [{ type: "text", text: "No relationships found for that scope." }], structuredContent };
2880
2894
  }
2881
2895
  const header = project && scope !== "global"
@@ -2899,8 +2913,7 @@ server.registerTool("memory_graph", {
2899
2913
  .filter((node) => node.edges.length > 0);
2900
2914
  const structuredContent = {
2901
2915
  action: "graph_shown",
2902
- project: project?.id,
2903
- projectName: project?.name,
2916
+ project: toProjectRef(project),
2904
2917
  nodes: structuredNodes,
2905
2918
  limit,
2906
2919
  truncated: structuredNodes.length < entries.filter(e => (e.note.relatedTo?.length ?? 0) > 0).length,
@@ -2920,6 +2933,7 @@ server.registerTool("project_memory_summary", {
2920
2933
  "Returns:\n" +
2921
2934
  "- A synthesized project-level summary based on stored memories\n" +
2922
2935
  "- Bounded 1-hop relationship previews on orientation entry points (primaryEntry and suggestedNext)\n\n" +
2936
+ "- Optional compact working-state recovery hints when relevant temporary notes exist\n\n" +
2923
2937
  "Read-only.\n\n" +
2924
2938
  "Typical next step:\n" +
2925
2939
  "- Use `recall` or `list` to drill down into specific areas.",
@@ -3060,6 +3074,48 @@ server.registerTool("project_memory_summary", {
3060
3074
  .slice(0, recentLimit);
3061
3075
  sections.push(`\nRecent activity (start here):`);
3062
3076
  sections.push(...recent.map(e => `- ${e.note.updatedAt} — ${e.note.title}`));
3077
+ const temporaryEntries = projectEntries
3078
+ .filter((entry) => entry.note.lifecycle === "temporary")
3079
+ .map((entry) => {
3080
+ const metadata = effectiveMetadataById.get(entry.note.id)?.metadata;
3081
+ const score = workingStateScore(entry.note, metadata);
3082
+ const nextAction = extractNextAction(entry.note);
3083
+ const relatedCount = entry.note.relatedTo?.length ?? 0;
3084
+ const days = daysSinceUpdate(entry.note.updatedAt);
3085
+ const rationaleParts = [`updated ${days < 1 ? "today" : `${Math.round(days)}d ago`}`];
3086
+ if (relatedCount > 0)
3087
+ rationaleParts.push(`${relatedCount} linked note${relatedCount === 1 ? "" : "s"}`);
3088
+ if (nextAction)
3089
+ rationaleParts.push("explicit next action");
3090
+ if (metadata?.role === "plan" || metadata?.role === "context")
3091
+ rationaleParts.push(`${metadata.role} note`);
3092
+ return {
3093
+ entry,
3094
+ score,
3095
+ rationale: rationaleParts.join(", "),
3096
+ preview: summarizePreview(entry.note.content, 120),
3097
+ nextAction,
3098
+ };
3099
+ })
3100
+ .filter((candidate) => candidate.score > -Infinity)
3101
+ .sort((a, b) => b.score - a.score || b.entry.note.updatedAt.localeCompare(a.entry.note.updatedAt))
3102
+ .slice(0, 3);
3103
+ const workingState = temporaryEntries.length > 0
3104
+ ? {
3105
+ summary: temporaryEntries.length === 1
3106
+ ? `1 temporary note may help resume active work.`
3107
+ : `${temporaryEntries.length} temporary notes may help resume active work.`,
3108
+ recoveryHint: "Orient with project_memory_summary first, then inspect these temporary notes if you need to continue in-progress work.",
3109
+ notes: temporaryEntries.map(({ entry, rationale, preview, nextAction }) => ({
3110
+ id: entry.note.id,
3111
+ title: entry.note.title,
3112
+ updatedAt: entry.note.updatedAt,
3113
+ rationale,
3114
+ preview,
3115
+ nextAction,
3116
+ })),
3117
+ }
3118
+ : undefined;
3063
3119
  // Anchor notes with diversity constraint (project-scoped only)
3064
3120
  const scoredAnchorCandidates = projectEntries
3065
3121
  .map(e => {
@@ -3209,11 +3265,14 @@ server.registerTool("project_memory_summary", {
3209
3265
  }
3210
3266
  const suggestedEnriched = await Promise.all(suggestedCandidates.map(enrichOrientationNote));
3211
3267
  const suggestedRelationships = await Promise.all(suggestedCandidates.map(enrichOrientationNoteWithRelationships));
3268
+ const recentPermanent = recent.find((entry) => entry.note.lifecycle === "permanent");
3269
+ const fallbackEntry = recentPermanent ?? recent[0];
3270
+ const permanentOverrideUsed = Boolean(recentPermanent && recent[0] && recentPermanent.note.id !== recent[0].note.id);
3212
3271
  // Enrich fallback primaryEntry when no anchors exist
3213
3272
  let fallbackEnriched = {};
3214
3273
  let fallbackRelationships = {};
3215
- if (!primaryAnchor && recent[0]) {
3216
- const fallbackNote = recent[0].note;
3274
+ if (!primaryAnchor && fallbackEntry) {
3275
+ const fallbackNote = fallbackEntry.note;
3217
3276
  const vault = noteVaultMap.get(fallbackNote.id);
3218
3277
  if (vault) {
3219
3278
  const filePath = `${vault.notesRelDir}/${fallbackNote.id}.md`;
@@ -3235,11 +3294,13 @@ server.registerTool("project_memory_summary", {
3235
3294
  ...primaryRelationships,
3236
3295
  }
3237
3296
  : {
3238
- id: recent[0]?.note.id ?? projectEntries[0]?.note.id ?? "",
3239
- title: recent[0]?.note.title ?? projectEntries[0]?.note.title ?? "No notes",
3240
- rationale: recent[0]
3241
- ? "Most recent note — no high-centrality anchors found"
3242
- : "Only note available",
3297
+ id: fallbackEntry?.note.id ?? projectEntries[0]?.note.id ?? "",
3298
+ title: fallbackEntry?.note.title ?? projectEntries[0]?.note.title ?? "No notes",
3299
+ rationale: permanentOverrideUsed
3300
+ ? "Most recent permanent note — no high-centrality anchors found"
3301
+ : fallbackEntry
3302
+ ? "Most recent note — no high-centrality anchors found"
3303
+ : "Only note available",
3243
3304
  ...fallbackEnriched,
3244
3305
  ...fallbackRelationships,
3245
3306
  },
@@ -3285,6 +3346,18 @@ server.registerTool("project_memory_summary", {
3285
3346
  sections.push(` - ${w}`);
3286
3347
  }
3287
3348
  }
3349
+ if (workingState) {
3350
+ sections.push(`\nWorking state:`);
3351
+ sections.push(workingState.summary);
3352
+ sections.push(`Recovery hint: ${workingState.recoveryHint}`);
3353
+ for (const note of workingState.notes) {
3354
+ sections.push(`- ${note.title} (\`${note.id}\`) — ${note.rationale}`);
3355
+ sections.push(` Preview: ${note.preview}`);
3356
+ if (note.nextAction) {
3357
+ sections.push(` Next action: ${note.nextAction}`);
3358
+ }
3359
+ }
3360
+ }
3288
3361
  // Related global notes (optional, anchor-based similarity)
3289
3362
  const structuredContent = {
3290
3363
  action: "project_summary_shown",
@@ -3304,6 +3377,7 @@ server.registerTool("project_memory_summary", {
3304
3377
  })),
3305
3378
  anchors,
3306
3379
  orientation,
3380
+ workingState,
3307
3381
  relatedGlobal,
3308
3382
  };
3309
3383
  console.error(`[summary:timing] ${(performance.now() - t0Summary).toFixed(1)}ms`);
@@ -4059,8 +4133,7 @@ async function detectDuplicates(entries, threshold, project) {
4059
4133
  const structuredContent = {
4060
4134
  action: "consolidated",
4061
4135
  strategy: "detect-duplicates",
4062
- project: project?.id,
4063
- projectName: project?.name,
4136
+ project: toProjectRef(project),
4064
4137
  notesProcessed: entries.length,
4065
4138
  notesModified: 0,
4066
4139
  };
@@ -4147,8 +4220,7 @@ function findClusters(entries, project) {
4147
4220
  const structuredContent = {
4148
4221
  action: "consolidated",
4149
4222
  strategy: "find-clusters",
4150
- project: project?.id,
4151
- projectName: project?.name,
4223
+ project: toProjectRef(project),
4152
4224
  notesProcessed: entries.length,
4153
4225
  notesModified: 0,
4154
4226
  themeGroups,
@@ -4235,8 +4307,7 @@ async function suggestMerges(entries, threshold, defaultConsolidationMode, proje
4235
4307
  const structuredContent = {
4236
4308
  action: "consolidated",
4237
4309
  strategy: "suggest-merges",
4238
- project: project?.id,
4239
- projectName: project?.name,
4310
+ project: toProjectRef(project),
4240
4311
  notesProcessed: entries.length,
4241
4312
  notesModified: 0,
4242
4313
  };
@@ -4260,8 +4331,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
4260
4331
  const structuredContent = {
4261
4332
  action: "consolidated",
4262
4333
  strategy: "execute-merge",
4263
- project: project?.id,
4264
- projectName: project?.name,
4334
+ project: toProjectRef(project),
4265
4335
  notesProcessed: entries.length,
4266
4336
  notesModified: 0,
4267
4337
  warnings: ["execute-merge requires at least two distinct sourceIds."],
@@ -4272,8 +4342,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
4272
4342
  const structuredContent = {
4273
4343
  action: "consolidated",
4274
4344
  strategy: "execute-merge",
4275
- project: project?.id,
4276
- projectName: project?.name,
4345
+ project: toProjectRef(project),
4277
4346
  notesProcessed: entries.length,
4278
4347
  notesModified: 0,
4279
4348
  warnings: ["execute-merge requires a non-empty targetTitle."],
@@ -4288,8 +4357,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
4288
4357
  const structuredContent = {
4289
4358
  action: "consolidated",
4290
4359
  strategy: "execute-merge",
4291
- project: project?.id,
4292
- projectName: project?.name,
4360
+ project: toProjectRef(project),
4293
4361
  notesProcessed: entries.length,
4294
4362
  notesModified: 0,
4295
4363
  warnings: [`Source note '${id}' not found.`],
@@ -4324,8 +4392,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
4324
4392
  const structuredContent = {
4325
4393
  action: "consolidated",
4326
4394
  strategy: "execute-merge",
4327
- project: project?.id,
4328
- projectName: project?.name,
4395
+ project: toProjectRef(project),
4329
4396
  notesProcessed: entries.length,
4330
4397
  notesModified: 0,
4331
4398
  warnings: [message],
@@ -4537,8 +4604,7 @@ async function executeMerge(entries, mergePlan, defaultConsolidationMode, projec
4537
4604
  const structuredContent = {
4538
4605
  action: "consolidated",
4539
4606
  strategy: "execute-merge",
4540
- project: project?.id,
4541
- projectName: project?.name,
4607
+ project: toProjectRef(project),
4542
4608
  notesProcessed: entries.length,
4543
4609
  notesModified: vaultChanges.size,
4544
4610
  persistence,
@@ -4578,8 +4644,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
4578
4644
  const structuredContent = {
4579
4645
  action: "consolidated",
4580
4646
  strategy: "prune-superseded",
4581
- project: project?.id,
4582
- projectName: project?.name,
4647
+ project: toProjectRef(project),
4583
4648
  notesProcessed: entries.length,
4584
4649
  notesModified: 0,
4585
4650
  warnings: [`prune-superseded requires consolidationMode="delete". Current mode: ${consolidationMode}.`],
@@ -4611,8 +4676,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
4611
4676
  const structuredContent = {
4612
4677
  action: "consolidated",
4613
4678
  strategy: "prune-superseded",
4614
- project: project?.id,
4615
- projectName: project?.name,
4679
+ project: toProjectRef(project),
4616
4680
  notesProcessed: entries.length,
4617
4681
  notesModified: 0,
4618
4682
  };
@@ -4641,8 +4705,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
4641
4705
  const structuredContent = {
4642
4706
  action: "consolidated",
4643
4707
  strategy: "prune-superseded",
4644
- project: project?.id,
4645
- projectName: project?.name,
4708
+ project: toProjectRef(project),
4646
4709
  notesProcessed: entries.length,
4647
4710
  notesModified: 0,
4648
4711
  warnings: [message],
@@ -4697,8 +4760,7 @@ async function pruneSuperseded(entries, consolidationMode, project, cwd, policy,
4697
4760
  const structuredContent = {
4698
4761
  action: "consolidated",
4699
4762
  strategy: "prune-superseded",
4700
- project: project?.id,
4701
- projectName: project?.name,
4763
+ project: toProjectRef(project),
4702
4764
  notesProcessed: entries.length,
4703
4765
  notesModified: vaultChanges.size,
4704
4766
  retry,
@@ -4726,8 +4788,7 @@ async function dryRunAll(entries, threshold, defaultConsolidationMode, project,
4726
4788
  const structuredContent = {
4727
4789
  action: "consolidated",
4728
4790
  strategy: "dry-run",
4729
- project: project?.id,
4730
- projectName: project?.name,
4791
+ project: toProjectRef(project),
4731
4792
  notesProcessed: entries.length,
4732
4793
  notesModified: 0,
4733
4794
  };
@@ -4773,11 +4834,32 @@ server.registerPrompt("mnemonic-workflow-hint", {
4773
4834
  "- For repo-related tasks, pass `cwd` so mnemonic can route project memories correctly.\n\n" +
4774
4835
  "Workflow: `recall`/`list` -> `get` -> `update` or `remember` -> `relate`/`consolidate`/`move_memory`. Use `discover_tags` only when tag choice is ambiguous.\n\n" +
4775
4836
  "Roles are optional prioritization hints, not schema. Lifecycle still governs durability. `role: plan` does not imply `temporary`. Inferred roles are internal hints only. Prioritization is language-independent by default.\n\n" +
4837
+ "### Working-state continuity\n\n" +
4838
+ "Preserve in-progress work as temporary notes when continuation value is high. Recovery happens after project orientation.\n\n" +
4839
+ "**Checkpoint note structure (temporary notes):**\n" +
4840
+ "- Title pattern: 'WIP: <topic>' or 'Checkpoint: <description>'\n" +
4841
+ "- Opening paragraph: current status and next immediate step\n" +
4842
+ "- Body: what was attempted, what worked, blockers, alternatives considered\n" +
4843
+ "- End with explicit next action and confidence level\n\n" +
4844
+ "**Checkpoint note guidance:**\n" +
4845
+ "- One checkpoint per active task or investigation thread\n" +
4846
+ "- Update the same checkpoint note as work progresses (don't create new ones)\n" +
4847
+ "- Link to related decisions: use `relate` to connect temporary checkpoints to permanent decisions\n" +
4848
+ "- Consolidate into a durable note when complete; let lifecycle defaults delete temporary scaffolding unless you intentionally need preserved history\n\n" +
4849
+ "**Recovery workflow:**\n" +
4850
+ "- Call `project_memory_summary` first for orientation (do not skip to recovery)\n" +
4851
+ "- Use `lifecycle: temporary` for active plans, WIP checkpoints, draft investigations, and unvalidated options\n" +
4852
+ "- Use `lifecycle: permanent` for decisions, discovered constraints, bug causes, and reusable lessons\n" +
4853
+ "- After orientation, recover working-state from temporary notes via `recall` with lifecycle filter\n" +
4854
+ "- Consolidate temporary notes into durable ones once knowledge stabilizes\n" +
4855
+ "- Recovery is a follow-on step, not a replacement for orientation\n\n" +
4776
4856
  "### Anti-patterns\n\n" +
4777
4857
  "- Bad: call `remember` immediately because the user said 'remember'.\n" +
4778
4858
  "- Good: `recall` or `list` first, then `get`, then `update` or `remember`.\n" +
4779
4859
  "- Bad: create another note when `recall` or `list` already found the same decision.\n" +
4780
- "- Good: `update` the existing memory and relate it if needed.\n\n" +
4860
+ "- Good: `update` the existing memory and relate it if needed.\n" +
4861
+ "- Bad: skip orientation and jump straight to working-state recovery.\n" +
4862
+ "- Good: `project_memory_summary` first, then recover temporary notes.\n\n" +
4781
4863
  "### Storage model\n\n" +
4782
4864
  "Memories can live in:\n" +
4783
4865
  "- `main-vault` for global knowledge\n" +
@@ -4790,7 +4872,8 @@ server.registerPrompt("mnemonic-workflow-hint", {
4790
4872
  "### Tiny examples\n\n" +
4791
4873
  "- Existing bug note found by `recall` -> inspect with `get` -> refine with `update`.\n" +
4792
4874
  "- No matching note found by `recall` -> optional `discover_tags` with note context -> create with `remember`.\n" +
4793
- "- Two notes overlap heavily -> inspect -> clean up with `consolidate`.",
4875
+ "- Two notes overlap heavily -> inspect -> clean up with `consolidate`.\n" +
4876
+ "- Resume work: `project_memory_summary` -> `recall` (lifecycle: temporary) -> continue from temporary notes.",
4794
4877
  },
4795
4878
  },
4796
4879
  ],