memorix 1.1.13 → 1.2.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 (88) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +3 -2
  3. package/README.zh-CN.md +3 -2
  4. package/dist/cli/index.js +36313 -31189
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/dashboard/static/app.js +50 -30
  7. package/dist/index.js +5348 -674
  8. package/dist/index.js.map +1 -1
  9. package/dist/maintenance-runner.d.ts +1 -1
  10. package/dist/maintenance-runner.js +3661 -293
  11. package/dist/maintenance-runner.js.map +1 -1
  12. package/dist/memcode-runtime/CHANGELOG.md +19 -0
  13. package/dist/sdk.d.ts +1 -1
  14. package/dist/sdk.js +5346 -672
  15. package/dist/sdk.js.map +1 -1
  16. package/docs/1.2.0-CLAIM-LEDGER.md +72 -0
  17. package/docs/1.2.0-CODE-STATE.md +61 -0
  18. package/docs/1.2.0-DEVELOPMENT-CHARTER.md +255 -0
  19. package/docs/1.2.0-DYNAMIC-LIFECYCLE.md +71 -0
  20. package/docs/1.2.0-EVALUATION-HARNESS.md +51 -0
  21. package/docs/1.2.0-IMPLEMENTATION-PLAN.md +554 -0
  22. package/docs/1.2.0-KNOWLEDGE-WORKFLOW-RESEARCH.md +205 -0
  23. package/docs/1.2.0-KNOWLEDGE-WORKSPACE.md +68 -0
  24. package/docs/1.2.0-PRODUCT-STORY.md +234 -0
  25. package/docs/1.2.0-PROVIDER-QUALITY.md +189 -0
  26. package/docs/1.2.0-WORKFLOW-INHERITANCE.md +101 -0
  27. package/docs/1.2.0-WORKSET-RETRIEVAL.md +80 -0
  28. package/docs/AGENT_OPERATOR_PLAYBOOK.md +6 -3
  29. package/docs/API_REFERENCE.md +25 -6
  30. package/docs/CONFIGURATION.md +21 -3
  31. package/docs/README.md +17 -2
  32. package/docs/dev-log/progress.txt +120 -40
  33. package/llms-full.txt +16 -2
  34. package/llms.txt +9 -4
  35. package/package.json +3 -2
  36. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  37. package/src/cli/capability-map.ts +1 -0
  38. package/src/cli/commands/codegraph.ts +112 -9
  39. package/src/cli/commands/context.ts +2 -0
  40. package/src/cli/commands/doctor.ts +73 -4
  41. package/src/cli/commands/knowledge.ts +282 -0
  42. package/src/cli/commands/serve-http.ts +12 -1
  43. package/src/cli/index.ts +3 -1
  44. package/src/cli/tui/App.tsx +1 -1
  45. package/src/cli/tui/Panels.tsx +8 -8
  46. package/src/cli/tui/theme.ts +1 -1
  47. package/src/cli/tui/views/GraphView.tsx +8 -7
  48. package/src/cli/tui/views/KnowledgeView.tsx +9 -9
  49. package/src/codegraph/auto-context.ts +171 -9
  50. package/src/codegraph/code-state.ts +95 -0
  51. package/src/codegraph/context-pack.ts +82 -1
  52. package/src/codegraph/external-provider.ts +581 -0
  53. package/src/codegraph/lite-provider.ts +64 -19
  54. package/src/codegraph/project-context.ts +9 -1
  55. package/src/codegraph/store.ts +154 -6
  56. package/src/codegraph/types.ts +117 -0
  57. package/src/config/resolved-config.ts +28 -0
  58. package/src/config/toml-loader.ts +3 -0
  59. package/src/config/yaml-loader.ts +6 -0
  60. package/src/dashboard/server.ts +15 -1
  61. package/src/evaluation/workset-evaluation.ts +120 -0
  62. package/src/hooks/handler.ts +48 -6
  63. package/src/knowledge/claim-store.ts +267 -0
  64. package/src/knowledge/claims.ts +537 -0
  65. package/src/knowledge/markdown.ts +129 -0
  66. package/src/knowledge/types.ts +157 -0
  67. package/src/knowledge/wiki.ts +524 -0
  68. package/src/knowledge/workflow-store.ts +168 -0
  69. package/src/knowledge/workflow-types.ts +95 -0
  70. package/src/knowledge/workflows.ts +743 -0
  71. package/src/knowledge/workset.ts +515 -0
  72. package/src/knowledge/workspace-store.ts +220 -0
  73. package/src/knowledge/workspace-types.ts +106 -0
  74. package/src/knowledge/workspace.ts +220 -0
  75. package/src/memory/observations.ts +19 -0
  76. package/src/runtime/control-plane-maintenance.ts +5 -0
  77. package/src/runtime/isolated-maintenance.ts +5 -0
  78. package/src/runtime/lifecycle-status.ts +102 -0
  79. package/src/runtime/lifecycle.ts +107 -0
  80. package/src/runtime/maintenance-jobs.ts +5 -0
  81. package/src/runtime/project-maintenance.ts +190 -0
  82. package/src/server/tool-profile.ts +3 -2
  83. package/src/server.ts +354 -14
  84. package/src/store/file-lock.ts +24 -4
  85. package/src/store/sqlite-db.ts +307 -0
  86. package/src/wiki/generator.ts +4 -2
  87. package/src/wiki/knowledge-graph.ts +7 -4
  88. package/src/wiki/types.ts +16 -4
@@ -0,0 +1,282 @@
1
+ import { defineCommand } from 'citty';
2
+ import { CodeGraphStore } from '../../codegraph/store.js';
3
+ import { ClaimStore } from '../../knowledge/claim-store.js';
4
+ import { applyKnowledgeProposal, compileKnowledgeWorkspace, lintKnowledgeWorkspace } from '../../knowledge/wiki.js';
5
+ import { initializeKnowledgeWorkspace, loadKnowledgeWorkspace } from '../../knowledge/workspace.js';
6
+ import { KnowledgeWorkspaceStore } from '../../knowledge/workspace-store.js';
7
+ import { WorkflowStore } from '../../knowledge/workflow-store.js';
8
+ import {
9
+ applyWorkflowAdapter,
10
+ importWindsurfWorkflows,
11
+ previewWorkflowAdapter,
12
+ recordWorkflowRun,
13
+ selectWorkspaceWorkflows,
14
+ syncCanonicalWorkflows,
15
+ } from '../../knowledge/workflows.js';
16
+ import { emitError, emitResult, getCliProjectContext } from './operator-shared.js';
17
+
18
+ function modeFrom(value: unknown): 'local' | 'versioned' {
19
+ if (!value || value === 'local') return 'local';
20
+ if (value === 'versioned') return 'versioned';
21
+ throw new Error('knowledge mode must be local or versioned');
22
+ }
23
+
24
+ function usage(): string {
25
+ return [
26
+ 'Memorix Knowledge Commands',
27
+ '',
28
+ ' memorix knowledge init [--mode local]',
29
+ ' memorix knowledge init --mode versioned --path C:\\project\\docs\\knowledge',
30
+ ' memorix knowledge status',
31
+ ' memorix knowledge compile',
32
+ ' memorix knowledge lint',
33
+ ' memorix knowledge apply --proposal <id> [--force]',
34
+ ' memorix knowledge workflow import',
35
+ ' memorix knowledge workflow list',
36
+ ' memorix knowledge workflow select --task "prepare a release"',
37
+ ' memorix knowledge workflow preview --id <workflow-id> --agent codex',
38
+ ' memorix knowledge workflow apply --id <workflow-id> --agent codex',
39
+ ' memorix knowledge workflow run --id <workflow-id> --task "..." --outcome passed',
40
+ ].join('\n');
41
+ }
42
+
43
+ function requiredText(value: unknown, field: string): string {
44
+ const text = typeof value === 'string' ? value.trim() : '';
45
+ if (!text) throw new Error(field + ' is required');
46
+ return text;
47
+ }
48
+
49
+ function workflowOutcome(value: unknown): 'passed' | 'failed' | 'cancelled' | 'in-progress' {
50
+ if (value === 'passed' || value === 'failed' || value === 'cancelled' || value === 'in-progress') return value;
51
+ throw new Error('workflow outcome must be passed, failed, cancelled, or in-progress');
52
+ }
53
+
54
+ function workflowVerdict(value: unknown): 'passed' | 'failed' | 'not-run' | undefined {
55
+ if (value === undefined || value === null || value === '') return undefined;
56
+ if (value === 'passed' || value === 'failed' || value === 'not-run') return value;
57
+ throw new Error('workflow verdict must be passed, failed, or not-run');
58
+ }
59
+
60
+ function evidenceList(value: unknown): string[] {
61
+ if (typeof value !== 'string' || !value.trim()) return [];
62
+ return [...new Set(value.split(',').map(item => item.trim()).filter(Boolean))];
63
+ }
64
+
65
+ export default defineCommand({
66
+ meta: {
67
+ name: 'knowledge',
68
+ description: 'Initialize, review, and lint the Memorix Knowledge Workspace',
69
+ },
70
+ args: {
71
+ action: { type: 'string', description: 'Action: init, status, compile, lint, or apply' },
72
+ mode: { type: 'string', description: 'Workspace mode: local or versioned' },
73
+ path: { type: 'string', description: 'Explicit versioned workspace path for init' },
74
+ proposal: { type: 'string', description: 'Proposal id for apply' },
75
+ force: { type: 'boolean', description: 'Explicitly allow an approved proposal to replace manual page edits' },
76
+ id: { type: 'string', description: 'Canonical workflow id' },
77
+ agent: { type: 'string', description: 'Target agent for a workflow adapter' },
78
+ task: { type: 'string', description: 'Task wording for workflow selection or a workflow run' },
79
+ outcome: { type: 'string', description: 'Workflow run outcome: passed, failed, cancelled, or in-progress' },
80
+ verdict: { type: 'string', description: 'Workflow verification verdict: passed, failed, or not-run' },
81
+ failure: { type: 'string', description: 'Sanitized failure reason for a workflow run' },
82
+ snapshot: { type: 'string', description: 'Starting code snapshot id for a workflow run' },
83
+ evidence: { type: 'string', description: 'Comma-separated evidence ids selected for a workflow run' },
84
+ json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
85
+ },
86
+ run: async ({ args }) => {
87
+ const positional = (args._ as string[]) ?? [];
88
+ const action = (positional[0] || (args.action as string | undefined) || 'status').toLowerCase();
89
+ const asJson = !!args.json;
90
+ try {
91
+ const { project, dataDir } = await getCliProjectContext();
92
+ const mode = modeFrom(args.mode);
93
+ if (action === 'init') {
94
+ const workspace = await initializeKnowledgeWorkspace({
95
+ projectId: project.id,
96
+ dataDir,
97
+ mode,
98
+ ...(mode === 'versioned'
99
+ ? {
100
+ projectRoot: project.rootPath,
101
+ rootPath: (args.path as string | undefined) ?? '',
102
+ }
103
+ : {}),
104
+ });
105
+ emitResult(
106
+ { project, workspace },
107
+ 'Knowledge workspace initialized at ' + workspace.rootPath,
108
+ asJson,
109
+ );
110
+ return;
111
+ }
112
+
113
+ const workspace = await loadKnowledgeWorkspace({ projectId: project.id, dataDir, mode });
114
+ if (!workspace) {
115
+ emitError('Knowledge workspace is not initialized. Run "memorix knowledge init" first.', asJson);
116
+ return;
117
+ }
118
+ const claimStore = new ClaimStore();
119
+ await claimStore.init(dataDir);
120
+ const workspaceStore = new KnowledgeWorkspaceStore();
121
+ await workspaceStore.init(dataDir);
122
+
123
+ if (action === 'workflow') {
124
+ const workflowAction = (positional[1] || 'list').toLowerCase();
125
+ const workflowStore = new WorkflowStore();
126
+ await workflowStore.init(dataDir);
127
+ const projectRoot = workspace.projectRoot ?? project.rootPath;
128
+
129
+ if (workflowAction === 'import') {
130
+ const result = await importWindsurfWorkflows({ workspace, projectRoot });
131
+ emitResult(
132
+ { project, workspace, result },
133
+ 'Imported ' + result.imported.length + ' Windsurf workflow(s); preserved ' + result.skipped.length + ' existing source or canonical file(s).',
134
+ asJson,
135
+ );
136
+ return;
137
+ }
138
+
139
+ const synced = await syncCanonicalWorkflows(workspace);
140
+ if (workflowAction === 'list') {
141
+ emitResult(
142
+ {
143
+ project,
144
+ workspace,
145
+ workflows: workflowStore.listWorkflows(workspace.id),
146
+ parseErrors: synced.errors,
147
+ },
148
+ [
149
+ 'Canonical workflows: ' + workflowStore.listWorkflows(workspace.id).length,
150
+ 'Parse errors: ' + synced.errors.length,
151
+ ].join('\n'),
152
+ asJson,
153
+ );
154
+ return;
155
+ }
156
+
157
+ if (workflowAction === 'select') {
158
+ const task = requiredText(args.task, 'task');
159
+ const result = await selectWorkspaceWorkflows({ workspace, task });
160
+ emitResult(
161
+ { project, workspace, task, ...result },
162
+ result.selections.length
163
+ ? 'Selected ' + result.selections.length + ' workflow(s) for this task.'
164
+ : 'No project workflow matches this task.',
165
+ asJson,
166
+ );
167
+ return;
168
+ }
169
+
170
+ const workflowId = requiredText(args.id, 'workflow id');
171
+ const workflow = workflowStore.getWorkflow(workflowId);
172
+ if (!workflow || workflow.workspaceId !== workspace.id) {
173
+ emitError('Workflow was not found for this knowledge workspace.', asJson);
174
+ return;
175
+ }
176
+
177
+ if (workflowAction === 'preview' || workflowAction === 'apply') {
178
+ const agent = requiredText(args.agent, 'agent');
179
+ const result = workflowAction === 'preview'
180
+ ? await previewWorkflowAdapter({ workflow, projectRoot, agent: agent as any })
181
+ : await applyWorkflowAdapter({ workflow, projectRoot, agent: agent as any });
182
+ emitResult(
183
+ { project, workspace, result },
184
+ 'Workflow adapter ' + result.status + ': ' + result.reason,
185
+ asJson,
186
+ );
187
+ return;
188
+ }
189
+
190
+ if (workflowAction === 'run') {
191
+ const task = requiredText(args.task, 'task');
192
+ const outcome = workflowOutcome(args.outcome);
193
+ const result = await recordWorkflowRun({
194
+ workspace,
195
+ run: {
196
+ workflowId,
197
+ projectId: project.id,
198
+ task,
199
+ outcome,
200
+ ...(workflowVerdict(args.verdict) ? { verificationVerdict: workflowVerdict(args.verdict) } : {}),
201
+ ...(typeof args.failure === 'string' && args.failure.trim() ? { failureReason: args.failure.trim() } : {}),
202
+ ...(typeof args.snapshot === 'string' && args.snapshot.trim() ? { startingSnapshotId: args.snapshot.trim() } : {}),
203
+ selectedEvidence: evidenceList(args.evidence),
204
+ },
205
+ });
206
+ emitResult(
207
+ { project, workspace, result },
208
+ 'Recorded workflow run ' + result.id + ' (' + result.outcome + ').',
209
+ asJson,
210
+ );
211
+ return;
212
+ }
213
+
214
+ emitResult({ usage: usage() }, usage(), asJson);
215
+ return;
216
+ }
217
+
218
+ switch (action) {
219
+ case 'status': {
220
+ const pages = workspaceStore.listPages(workspace.id);
221
+ const pending = workspaceStore.listProposals(workspace.id, 'pending');
222
+ emitResult(
223
+ { project, workspace, pages, pendingProposals: pending },
224
+ [
225
+ 'Knowledge workspace: ' + workspace.rootPath,
226
+ '- Mode: ' + workspace.mode,
227
+ '- Published pages: ' + pages.filter(page => page.status === 'active').length,
228
+ '- Pending proposals: ' + pending.length,
229
+ '- Status: ' + workspace.status,
230
+ ].join('\n'),
231
+ asJson,
232
+ );
233
+ return;
234
+ }
235
+ case 'compile': {
236
+ const result = await compileKnowledgeWorkspace({ workspace, claims: claimStore });
237
+ emitResult(
238
+ { project, workspace, result },
239
+ 'Knowledge compilation completed: ' + result.proposals.length + ' proposal(s), ' + result.published.length + ' unchanged published page(s).',
240
+ asJson,
241
+ );
242
+ return;
243
+ }
244
+ case 'lint': {
245
+ const codeStore = new CodeGraphStore();
246
+ await codeStore.init(dataDir);
247
+ const result = await lintKnowledgeWorkspace({ workspace, claims: claimStore, codeStore });
248
+ emitResult(
249
+ { project, workspace, result },
250
+ result.valid
251
+ ? 'Knowledge workspace lint passed.'
252
+ : 'Knowledge workspace lint found ' + result.issues.length + ' issue(s).',
253
+ asJson,
254
+ );
255
+ return;
256
+ }
257
+ case 'apply': {
258
+ const proposalId = (args.proposal as string | undefined)?.trim();
259
+ if (!proposalId) {
260
+ emitError('proposal is required for "memorix knowledge apply"', asJson);
261
+ return;
262
+ }
263
+ const result = await applyKnowledgeProposal({
264
+ workspace,
265
+ proposalId,
266
+ allowManualOverwrite: !!args.force,
267
+ });
268
+ emitResult(
269
+ { project, workspace, result },
270
+ 'Knowledge proposal applied to ' + result.targetPath,
271
+ asJson,
272
+ );
273
+ return;
274
+ }
275
+ default:
276
+ emitResult({ usage: usage() }, usage(), asJson);
277
+ }
278
+ } catch (error) {
279
+ emitError(error instanceof Error ? error.message : String(error), asJson);
280
+ }
281
+ },
282
+ });
@@ -868,9 +868,12 @@ export default defineCommand({
868
868
  const projectRelations = graph.relations.filter((r: any) => projectEntitySet.has(r.from) && projectEntitySet.has(r.to));
869
869
 
870
870
  let maintenance = { total: 0, pending: 0, running: 0, retrying: 0, completed: 0, failed: 0 };
871
+ let lifecycle: unknown;
871
872
  try {
872
873
  const { MaintenanceJobStore } = await import('../../runtime/maintenance-jobs.js');
873
874
  maintenance = new MaintenanceJobStore(statsDataDir).summary(statsProjectId);
875
+ const { collectLifecycleDiagnostics } = await import('../../runtime/lifecycle-status.js');
876
+ lifecycle = await collectLifecycleDiagnostics({ dataDir: statsDataDir, projectId: statsProjectId });
874
877
  } catch { /* optional maintenance diagnostics */ }
875
878
 
876
879
  sendJson({
@@ -892,17 +895,25 @@ export default defineCommand({
892
895
  },
893
896
  retentionSummary,
894
897
  maintenance,
898
+ ...(lifecycle ? { lifecycle } : {}),
895
899
  });
896
900
  return;
897
901
  }
898
902
 
899
903
  if (apiPath === '/maintenance') {
900
904
  const { projectId: maintenanceProjectId, dataDir: maintenanceDataDir } = await resolveRequestProject(url);
901
- const { MaintenanceJobStore } = await import('../../runtime/maintenance-jobs.js');
905
+ const [{ MaintenanceJobStore }, { collectLifecycleDiagnostics }] = await Promise.all([
906
+ import('../../runtime/maintenance-jobs.js'),
907
+ import('../../runtime/lifecycle-status.js'),
908
+ ]);
902
909
  const queue = new MaintenanceJobStore(maintenanceDataDir);
903
910
  sendJson({
904
911
  summary: queue.summary(maintenanceProjectId),
905
912
  jobs: queue.list({ projectId: maintenanceProjectId, limit: 50 }),
913
+ lifecycle: await collectLifecycleDiagnostics({
914
+ dataDir: maintenanceDataDir,
915
+ projectId: maintenanceProjectId,
916
+ }),
906
917
  });
907
918
  return;
908
919
  }
package/src/cli/index.ts CHANGED
@@ -989,6 +989,7 @@ const main = defineCommand({
989
989
  context: () => import('./commands/context.js').then(m => m.default),
990
990
  explain: () => import('./commands/explain.js').then(m => m.default),
991
991
  codegraph: () => import('./commands/codegraph.js').then(m => m.default),
992
+ knowledge: () => import('./commands/knowledge.js').then(m => m.default),
992
993
  reasoning: () => import('./commands/reasoning.js').then(m => m.default),
993
994
  retention: () => import('./commands/retention.js').then(m => m.default),
994
995
  formation: () => import('./commands/formation.js').then(m => m.default),
@@ -1048,7 +1049,7 @@ const main = defineCommand({
1048
1049
  // Detect by checking if the first CLI arg matches a registered subcommand name.
1049
1050
  const firstArg = process.argv[2];
1050
1051
  const knownSubs = ['ask', 'search', 'remember', 'recent', 'memcode', 'config',
1051
- 'init', 'setup', 'integrate', 'memory', 'context', 'explain', 'codegraph', 'reasoning', 'retention', 'formation', 'audit', 'transfer', 'skills',
1052
+ 'init', 'setup', 'integrate', 'memory', 'context', 'explain', 'codegraph', 'knowledge', 'reasoning', 'retention', 'formation', 'audit', 'transfer', 'skills',
1052
1053
  'session', 'team', 'task', 'message', 'lock', 'handoff', 'poll',
1053
1054
  'receipt',
1054
1055
  'serve', 'serve-http', 'status', 'sync',
@@ -1088,6 +1089,7 @@ const main = defineCommand({
1088
1089
  console.error(' context Show the Memory Autopilot brief for this project');
1089
1090
  console.error(' explain Explain where Memorix project context comes from');
1090
1091
  console.error(' codegraph Refresh/status/context-pack for CodeGraph Memory');
1092
+ console.error(' knowledge Review source-backed knowledge pages and project workflows');
1091
1093
  console.error(' reasoning Store/search decision rationale');
1092
1094
  console.error(' retention Inspect stale/archive status');
1093
1095
  console.error(' formation Inspect Memory Formation metrics');
@@ -598,7 +598,7 @@ export function WorkbenchApp({ version, onExitForInteractive }: AppProps): React
598
598
  setKnowledgeSelectedIdx(0);
599
599
  setLoading(false);
600
600
  navigateTo('knowledge');
601
- setStatusMsg({ text: kb ? `Knowledge Base: ${kb.stats.observationsUsed} obs, ${kb.stats.miniSkillsUsed} skills` : 'No knowledge available', type: 'info' });
601
+ setStatusMsg({ text: kb ? `Memory Overview: ${kb.stats.observationsUsed} obs, ${kb.stats.miniSkillsUsed} skills` : 'No memory overview available', type: 'info' });
602
602
  break;
603
603
  }
604
604
  case 'memory': {
@@ -553,8 +553,8 @@ export function WikiView({ knowledge, loading }: WikiViewProps): React.ReactElem
553
553
  if (loading) {
554
554
  return (
555
555
  <Box flexDirection="column" paddingX={1}>
556
- <Text color={COLORS.brand} bold>Knowledge Base</Text>
557
- <Text color={COLORS.muted}> LLM Wiki</Text>
556
+ <Text color={COLORS.brand} bold>Memory Overview</Text>
557
+ <Text color={COLORS.muted}> Generated from durable memory</Text>
558
558
  <Text color={COLORS.border}>{separator()}</Text>
559
559
  <Text color={COLORS.muted}>Loading...</Text>
560
560
  </Box>
@@ -564,19 +564,19 @@ export function WikiView({ knowledge, loading }: WikiViewProps): React.ReactElem
564
564
  if (!knowledge) {
565
565
  return (
566
566
  <Box flexDirection="column" paddingX={1}>
567
- <Text color={COLORS.brand} bold>Knowledge Base</Text>
568
- <Text color={COLORS.muted}> LLM Wiki</Text>
567
+ <Text color={COLORS.brand} bold>Memory Overview</Text>
568
+ <Text color={COLORS.muted}> Generated from durable memory</Text>
569
569
  <Text color={COLORS.border}>{separator()}</Text>
570
- <Text color={COLORS.warning}>No knowledge available for this project.</Text>
571
- <Text color={COLORS.textDim}>Store memories with /remember or /chat to build your Knowledge Base.</Text>
570
+ <Text color={COLORS.warning}>No memory overview is available for this project.</Text>
571
+ <Text color={COLORS.textDim}>Store durable memories with /remember or /chat to build your overview.</Text>
572
572
  </Box>
573
573
  );
574
574
  }
575
575
 
576
576
  return (
577
577
  <Box flexDirection="column" paddingX={1}>
578
- <Text color={COLORS.brand} bold>Knowledge Base</Text>
579
- <Text color={COLORS.muted}> LLM Wiki</Text>
578
+ <Text color={COLORS.brand} bold>Memory Overview</Text>
579
+ <Text color={COLORS.muted}> Generated from durable memory</Text>
580
580
  <Box>
581
581
  <Text color={COLORS.textDim}> Project: {knowledge.projectId}</Text>
582
582
  <Text color={COLORS.muted}> │ {knowledge.stats.observationsUsed} obs, {knowledge.stats.miniSkillsUsed} skills</Text>
@@ -31,7 +31,7 @@ export const SLASH_COMMANDS: SlashCommand[] = [
31
31
  { name: '/integrate', description: 'Set up an IDE', alias: '/setup' },
32
32
  { name: '/cleanup', description: 'Cleanup and purge' },
33
33
  { name: '/ingest', description: 'Git to Memory' },
34
- { name: '/wiki', description: 'Knowledge Base', alias: '/knowledge' },
34
+ { name: '/wiki', description: 'Memory overview', alias: '/knowledge' },
35
35
  { name: '/exit', description: 'Exit workbench', alias: '/q' },
36
36
  ];
37
37
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * GraphView — Knowledge graph text browser.
2
+ * GraphView — deterministic memory-map text browser.
3
3
  *
4
4
  * Modes: browse (clusters + nodes), detail (single node with edge summary).
5
5
  * Keyboard: f filter, up/down navigate, enter detail, k -> Knowledge, esc back.
@@ -168,7 +168,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
168
168
  return (
169
169
  <Box flexDirection="column" paddingX={1}>
170
170
  <Box>
171
- <Text color={COLORS.brand} bold>Graph Node Detail</Text>
171
+ <Text color={COLORS.brand} bold>Memory Map Item</Text>
172
172
  </Box>
173
173
  <Text color={COLORS.border}>{separator()}</Text>
174
174
  <Box marginY={1} flexDirection="column">
@@ -190,7 +190,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
190
190
  )}
191
191
  {/* Edge summary */}
192
192
  <Box marginY={1} flexDirection="column">
193
- <Text color={COLORS.brandDim} bold>Edges</Text>
193
+ <Text color={COLORS.brandDim} bold>Links</Text>
194
194
  <Text color={COLORS.muted}>Outgoing ({outgoing.length}): </Text>
195
195
  {outgoing.slice(0, 6).map((e) => {
196
196
  const targetNode = graph?.nodes.find((n) => n.id === e.target);
@@ -213,7 +213,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
213
213
  {incoming.length > 6 && <Text color={COLORS.muted}> ... +{incoming.length - 6} more</Text>}
214
214
  </Box>
215
215
  <Box marginTop={1}>
216
- <Text color={COLORS.muted}>esc back | k {'>'} Knowledge</Text>
216
+ <Text color={COLORS.muted}>esc back | k {'>'} Memory Overview</Text>
217
217
  </Box>
218
218
  </Box>
219
219
  );
@@ -230,11 +230,12 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
230
230
  <Box flexDirection="column" paddingX={1}>
231
231
  <Box flexDirection="column">
232
232
  <Box>
233
- <Text color={COLORS.brand} bold>Knowledge Graph</Text>
233
+ <Text color={COLORS.brand} bold>Memory Map</Text>
234
234
  {!loading && graph && (
235
235
  <Text color={COLORS.muted}> | {graph.stats.totalNodes} nodes, {graph.stats.totalEdges} edges, {graph.stats.clusterCount} clusters</Text>
236
236
  )}
237
237
  </Box>
238
+ <Text color={COLORS.textDim}>Deterministic links from shared entities, skill sources, and explicit relations</Text>
238
239
  {/* Filter bar */}
239
240
  {!loading && graph && (
240
241
  <Box marginTop={0}>
@@ -248,7 +249,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
248
249
  {loading ? (
249
250
  <Text color={COLORS.muted}>Loading...</Text>
250
251
  ) : !graph ? (
251
- <Text color={COLORS.muted}>No graph data available. Store observations to build the knowledge graph.</Text>
252
+ <Text color={COLORS.muted}>No memory map data is available. Store durable observations to build deterministic links.</Text>
252
253
  ) : flatItems.length === 0 ? (
253
254
  <Text color={COLORS.muted}>
254
255
  {filterMode !== 'all' ? 'No nodes match this filter.' : 'No nodes in graph.'}
@@ -290,7 +291,7 @@ export function GraphView({ projectId, inputFocused, onNavigateKnowledge }: Grap
290
291
 
291
292
  <Box marginTop={1} flexDirection="column">
292
293
  <Text color={COLORS.textDim}>
293
- f filter | up/down navigate | enter detail | k {'>'} Knowledge
294
+ f filter | up/down navigate | enter detail | k {'>'} Memory Overview
294
295
  </Text>
295
296
  </Box>
296
297
  </Box>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * KnowledgeView — Wiki browser for the shared knowledge layer.
2
+ * KnowledgeView — read-only memory overview browser.
3
3
  *
4
4
  * Displays ProjectKnowledgeOverview sections and items.
5
5
  * Each item shows its provenance refs; pressing 'm' on an item
@@ -36,8 +36,8 @@ export function KnowledgeView({ knowledge, loading, selectedItemIdx, itemCount }
36
36
  if (loading) {
37
37
  return (
38
38
  <Box flexDirection="column" paddingX={1}>
39
- <Text color={COLORS.brand} bold>Knowledge Base</Text>
40
- <Text color={COLORS.muted}> LLM Wiki</Text>
39
+ <Text color={COLORS.brand} bold>Memory Overview</Text>
40
+ <Text color={COLORS.muted}> Generated from durable memory</Text>
41
41
  <Text color={COLORS.border}>{separator()}</Text>
42
42
  <Text color={COLORS.muted}>Loading…</Text>
43
43
  </Box>
@@ -47,11 +47,11 @@ export function KnowledgeView({ knowledge, loading, selectedItemIdx, itemCount }
47
47
  if (!knowledge) {
48
48
  return (
49
49
  <Box flexDirection="column" paddingX={1}>
50
- <Text color={COLORS.brand} bold>Knowledge Base</Text>
51
- <Text color={COLORS.muted}> LLM Wiki</Text>
50
+ <Text color={COLORS.brand} bold>Memory Overview</Text>
51
+ <Text color={COLORS.muted}> Generated from durable memory</Text>
52
52
  <Text color={COLORS.border}>{separator()}</Text>
53
- <Text color={COLORS.warning}>No knowledge available for this project.</Text>
54
- <Text color={COLORS.textDim}>Store memories with /remember or use Workbench to build context.</Text>
53
+ <Text color={COLORS.warning}>No memory overview is available for this project.</Text>
54
+ <Text color={COLORS.textDim}>Store durable memories with /remember or use Workbench to build context.</Text>
55
55
  </Box>
56
56
  );
57
57
  }
@@ -68,8 +68,8 @@ export function KnowledgeView({ knowledge, loading, selectedItemIdx, itemCount }
68
68
  return (
69
69
  <Box flexDirection="column" paddingX={1}>
70
70
  <Box>
71
- <Text color={COLORS.brand} bold>Knowledge Base</Text>
72
- <Text color={COLORS.muted}> LLM Wiki</Text>
71
+ <Text color={COLORS.brand} bold>Memory Overview</Text>
72
+ <Text color={COLORS.muted}> Generated from durable memory</Text>
73
73
  </Box>
74
74
  <Box>
75
75
  <Text color={COLORS.textDim}> {knowledge.projectId}</Text>