@prmichaelsen/remember-mcp 3.15.4 → 3.15.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/AGENT.md +363 -5
  2. package/CHANGELOG.md +7 -0
  3. package/agent/commands/acp.clarification-capture.md +386 -0
  4. package/agent/commands/acp.clarification-create.md +50 -0
  5. package/agent/commands/acp.command-create.md +60 -0
  6. package/agent/commands/acp.design-create.md +62 -0
  7. package/agent/commands/acp.design-reference.md +355 -0
  8. package/agent/commands/acp.index.md +423 -0
  9. package/agent/commands/acp.init.md +48 -0
  10. package/agent/commands/acp.package-create.md +1 -0
  11. package/agent/commands/acp.package-info.md +1 -0
  12. package/agent/commands/acp.package-install.md +19 -0
  13. package/agent/commands/acp.package-list.md +1 -0
  14. package/agent/commands/acp.package-publish.md +1 -0
  15. package/agent/commands/acp.package-remove.md +1 -0
  16. package/agent/commands/acp.package-search.md +1 -0
  17. package/agent/commands/acp.package-update.md +1 -0
  18. package/agent/commands/acp.package-validate.md +1 -0
  19. package/agent/commands/acp.pattern-create.md +60 -0
  20. package/agent/commands/acp.plan.md +25 -0
  21. package/agent/commands/acp.proceed.md +621 -75
  22. package/agent/commands/acp.project-create.md +3 -0
  23. package/agent/commands/acp.project-info.md +3 -0
  24. package/agent/commands/acp.project-list.md +3 -1
  25. package/agent/commands/acp.project-set.md +1 -0
  26. package/agent/commands/acp.project-update.md +14 -3
  27. package/agent/commands/acp.projects-restore.md +228 -0
  28. package/agent/commands/acp.projects-sync.md +347 -0
  29. package/agent/commands/acp.report.md +13 -0
  30. package/agent/commands/acp.resume.md +3 -1
  31. package/agent/commands/acp.sessions.md +301 -0
  32. package/agent/commands/acp.status.md +13 -0
  33. package/agent/commands/acp.sync.md +1 -0
  34. package/agent/commands/acp.task-create.md +105 -3
  35. package/agent/commands/acp.update.md +1 -0
  36. package/agent/commands/acp.validate.md +32 -2
  37. package/agent/commands/acp.version-check-for-updates.md +1 -0
  38. package/agent/commands/acp.version-check.md +1 -0
  39. package/agent/commands/acp.version-update.md +1 -0
  40. package/agent/commands/command.template.md +23 -0
  41. package/agent/commands/git.commit.md +1 -0
  42. package/agent/commands/git.init.md +1 -0
  43. package/agent/design/complete-tool-set.md +157 -233
  44. package/agent/design/design.template.md +18 -0
  45. package/agent/design/user-preferences.md +11 -7
  46. package/agent/milestones/milestone-19-new-search-ghost-tools.md +46 -0
  47. package/agent/package.template.yaml +50 -0
  48. package/agent/patterns/pattern.template.md +18 -0
  49. package/agent/progress.yaml +162 -6
  50. package/agent/scripts/acp.common.sh +258 -15
  51. package/agent/scripts/acp.install.sh +91 -4
  52. package/agent/scripts/acp.package-create.sh +0 -1
  53. package/agent/scripts/acp.package-info.sh +19 -1
  54. package/agent/scripts/acp.package-install-optimized.sh +1 -1
  55. package/agent/scripts/acp.package-install.sh +388 -38
  56. package/agent/scripts/acp.package-list.sh +52 -4
  57. package/agent/scripts/acp.package-remove.sh +77 -1
  58. package/agent/scripts/acp.package-search.sh +2 -2
  59. package/agent/scripts/acp.package-update.sh +91 -12
  60. package/agent/scripts/acp.package-validate.sh +136 -1
  61. package/agent/scripts/acp.project-info.sh +34 -11
  62. package/agent/scripts/acp.project-list.sh +4 -0
  63. package/agent/scripts/acp.project-update.sh +66 -19
  64. package/agent/scripts/acp.projects-restore.sh +170 -0
  65. package/agent/scripts/acp.projects-sync.sh +155 -0
  66. package/agent/scripts/acp.sessions.sh +725 -0
  67. package/agent/scripts/acp.version-update.sh +21 -3
  68. package/agent/scripts/acp.yaml-parser.sh +20 -6
  69. package/agent/tasks/milestone-19-new-search-ghost-tools/task-203-create-search-by-tool.md +143 -0
  70. package/agent/tasks/milestone-19-new-search-ghost-tools/task-204-add-new-filters-existing-tools.md +77 -0
  71. package/agent/tasks/milestone-19-new-search-ghost-tools/task-205-add-feel-fields-create-update.md +137 -0
  72. package/agent/tasks/milestone-19-new-search-ghost-tools/task-206-add-byproperty-bysignificance-modes.md +135 -0
  73. package/agent/tasks/milestone-19-new-search-ghost-tools/task-207-add-emotional-composites-search-results.md +88 -0
  74. package/agent/tasks/milestone-19-new-search-ghost-tools/task-208-add-bybroad-byrandom-modes.md +115 -0
  75. package/agent/tasks/milestone-19-new-search-ghost-tools/task-209-create-ghost-memory-tools.md +192 -0
  76. package/agent/tasks/milestone-19-new-search-ghost-tools/task-210-create-get-core-tool.md +203 -0
  77. package/agent/tasks/milestone-19-new-search-ghost-tools/task-211-create-search-space-by-tool.md +182 -0
  78. package/agent/tasks/task-1-{title}.template.md +19 -0
  79. package/agent/tasks/unassigned/bug-report-remember-core-e2e-findings.md +99 -0
  80. package/dist/e2e-helpers.d.ts +26 -0
  81. package/dist/ghost-persona.e2e.d.ts +8 -0
  82. package/dist/memory-crud.e2e.d.ts +8 -0
  83. package/dist/preferences.e2e.d.ts +8 -0
  84. package/dist/relationships.e2e.d.ts +8 -0
  85. package/dist/search-modes.e2e.d.ts +8 -0
  86. package/dist/server-factory.js +1977 -100
  87. package/dist/server.js +1174 -51
  88. package/dist/shared-spaces.e2e.d.ts +8 -0
  89. package/dist/tools/create-ghost-memory.d.ts +70 -0
  90. package/dist/tools/create-memory.d.ts +175 -0
  91. package/dist/tools/get-core.d.ts +28 -0
  92. package/dist/tools/get-core.spec.d.ts +2 -0
  93. package/dist/tools/ghost-tools.spec.d.ts +2 -0
  94. package/dist/tools/query-ghost-memory.d.ts +34 -0
  95. package/dist/tools/query-memory.d.ts +4 -0
  96. package/dist/tools/search-by.d.ts +147 -0
  97. package/dist/tools/search-by.spec.d.ts +2 -0
  98. package/dist/tools/search-ghost-memory-by.d.ts +54 -0
  99. package/dist/tools/search-ghost-memory.d.ts +53 -0
  100. package/dist/tools/search-memory.d.ts +19 -0
  101. package/dist/tools/search-space-by.d.ts +78 -0
  102. package/dist/tools/search-space-by.spec.d.ts +2 -0
  103. package/dist/tools/search-space.d.ts +2 -0
  104. package/dist/tools/update-ghost-memory.d.ts +51 -0
  105. package/dist/tools/update-memory.d.ts +175 -0
  106. package/jest.e2e.config.js +11 -0
  107. package/package.json +2 -2
  108. package/src/e2e-helpers.ts +86 -0
  109. package/src/ghost-persona.e2e.ts +215 -0
  110. package/src/memory-crud.e2e.ts +203 -0
  111. package/src/preferences.e2e.ts +88 -0
  112. package/src/relationships.e2e.ts +156 -0
  113. package/src/search-modes.e2e.ts +184 -0
  114. package/src/server-factory.ts +56 -0
  115. package/src/shared-spaces.e2e.ts +204 -0
  116. package/src/tools/create-ghost-memory.ts +103 -0
  117. package/src/tools/create-memory.ts +45 -1
  118. package/src/tools/get-core.spec.ts +223 -0
  119. package/src/tools/get-core.ts +109 -0
  120. package/src/tools/ghost-tools.spec.ts +361 -0
  121. package/src/tools/query-ghost-memory.ts +63 -0
  122. package/src/tools/query-memory.ts +4 -0
  123. package/src/tools/search-by.spec.ts +325 -0
  124. package/src/tools/search-by.ts +298 -0
  125. package/src/tools/search-ghost-memory-by.ts +80 -0
  126. package/src/tools/search-ghost-memory.ts +73 -0
  127. package/src/tools/search-memory.ts +23 -0
  128. package/src/tools/search-space-by.spec.ts +289 -0
  129. package/src/tools/search-space-by.ts +173 -0
  130. package/src/tools/search-space.ts +20 -1
  131. package/src/tools/update-ghost-memory.ts +86 -0
  132. package/src/tools/update-memory.ts +45 -1
@@ -0,0 +1,88 @@
1
+ # Task 207: Add Emotional Composites + REM Metadata to Search Results
2
+
3
+ **Milestone**: M19 — New Search Modes, Ghost Tools & Emotional Exposure
4
+ **Status**: Not Started
5
+ **Created**: 2026-03-07
6
+ **Estimated Hours**: 2-3
7
+ **Dependencies**: remember-core schema with composite scores and REM metadata
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Include emotional composite scores (`total_significance`, `feel_significance`, `functional_significance`) and REM metadata (`rem_touched_at`, `rem_visits`) in search result objects across all search tools.
14
+
15
+ ## Context
16
+
17
+ When REM has scored memories, the composite significance scores and REM visit metadata are stored in Weaviate. These should be included in search results so the LLM and downstream tools have emotional context. Not all memories will have been scored — unscored fields must be omitted (not returned as null).
18
+
19
+ ## Fields to Include
20
+
21
+ ```typescript
22
+ // Added to search result memory objects (when non-null):
23
+ {
24
+ // ... existing fields (memory_id, title, content, content_type, tags, weight, trust, created_at, etc.) ...
25
+
26
+ // Composite scores (computed by REM, 0-1 floats)
27
+ total_significance?: number; // Combined emotional + functional significance
28
+ feel_significance?: number; // Weighted sum of Layer 1 (21 discrete emotions)
29
+ functional_significance?: number; // Weighted sum of Layer 2 (10 functional signals)
30
+
31
+ // REM metadata
32
+ rem_touched_at?: string; // ISO timestamp of last REM scoring update
33
+ rem_visits?: number; // Number of REM scoring visits
34
+ }
35
+ ```
36
+
37
+ ## Tools to Update
38
+
39
+ | Tool File | Function | Notes |
40
+ |-----------|----------|-------|
41
+ | `src/tools/search-memory.ts` | Result serialization | Add composites to each memory result |
42
+ | `src/tools/find-similar.ts` | Result serialization | Add composites to each memory result |
43
+ | `src/tools/query-memory.ts` | Result serialization | Add composites to each memory result |
44
+ | `src/tools/search-space.ts` | Result serialization | Add composites to published memory results |
45
+ | `src/tools/search-by.ts` | Result serialization | Add composites (all modes) |
46
+
47
+ ## Implementation Pattern
48
+
49
+ For each tool, find the result serialization code (where memory objects are mapped to response JSON) and add:
50
+
51
+ ```typescript
52
+ // After existing field mappings:
53
+ ...(memory.total_significance != null && { total_significance: memory.total_significance }),
54
+ ...(memory.feel_significance != null && { feel_significance: memory.feel_significance }),
55
+ ...(memory.functional_significance != null && { functional_significance: memory.functional_significance }),
56
+ ...(memory.rem_touched_at != null && { rem_touched_at: memory.rem_touched_at }),
57
+ ...(memory.rem_visits != null && { rem_visits: memory.rem_visits }),
58
+ ```
59
+
60
+ ## Key Decisions
61
+
62
+ - **Null/undefined values MUST be omitted**: Not all memories have been scored by REM. Never return `null` or `undefined` in the response — only include these fields when they have values.
63
+ - **Use conditional spread**: The `...(value != null && { key: value })` pattern ensures clean omission.
64
+ - **All search tools get composites**: Consistency across all search surfaces. If a memory has been scored, the scores are always visible.
65
+ - **No individual feel_* fields in results**: Only the 3 composites + 2 REM metadata fields. Individual feel_* values are accessible via `byProperty` sorting or future detail tools.
66
+
67
+ ## Steps
68
+
69
+ 1. Identify result serialization pattern in each of the 5 tool files
70
+ 2. Add composite score and REM metadata fields using conditional spread
71
+ 3. Update result type definitions if the project has explicit result interfaces
72
+ 4. Write tests:
73
+ - Composites appear in results when memory has been scored
74
+ - Composites are omitted when memory has NOT been scored (null/undefined)
75
+ - REM metadata (rem_touched_at, rem_visits) included when available
76
+ - All 5 tools include composites consistently
77
+
78
+ ## Verification
79
+
80
+ - [ ] Composite scores included in search_memory results
81
+ - [ ] Composite scores included in find_similar results
82
+ - [ ] Composite scores included in query_memory results
83
+ - [ ] Composite scores included in search_space results
84
+ - [ ] Composite scores included in search_by results
85
+ - [ ] REM metadata (rem_touched_at, rem_visits) included when available
86
+ - [ ] Null/unscored fields omitted from results (no nulls in output)
87
+ - [ ] Tests passing
88
+ - [ ] TypeScript clean
@@ -0,0 +1,115 @@
1
+ # Task 208: Add byBroad and byRandom Modes to search_by
2
+
3
+ **Milestone**: M19 — New Search Modes, Ghost Tools & Emotional Exposure
4
+ **Status**: Not Started
5
+ **Created**: 2026-03-07
6
+ **Estimated Hours**: 3-4
7
+ **Dependencies**: Task 203 (search_by tool exists), remember-core byBroad and byRandom implementations
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Add `byBroad` and `byRandom` modes to `remember_search_by`. These require new core methods that don't exist yet — this task is blocked until remember-core implements them.
14
+
15
+ ## Context
16
+
17
+ - **byBroad**: Fetches massive result sets with truncated content (head/mid/tail slices ~100 chars each). Default limit 50-100. Enables "scan and drill-in" workflow — browse broad results, then use `remember_search_memory` or `remember_query_memory` to get full content of interesting items. Includes emotional composites in truncated results.
18
+ - **byRandom**: Random sampling from the collection. Optional query to constrain the random pool. Useful for serendipitous rediscovery of forgotten content.
19
+
20
+ ## Schema Changes
21
+
22
+ Update `src/tools/search-by.ts`:
23
+
24
+ 1. Add to mode enum: `'byBroad', 'byRandom'`
25
+ 2. Update tool description:
26
+ ```
27
+ - byBroad: Massive results with truncated content for scan-and-drill-in workflow (default limit: 50)
28
+ - byRandom: Random sampling for serendipitous rediscovery
29
+ ```
30
+
31
+ ## `byBroad` Response Shape
32
+
33
+ byBroad returns a DIFFERENT response shape than other modes — truncated content instead of full content:
34
+
35
+ ```typescript
36
+ interface BroadSearchResult {
37
+ memory_id: string;
38
+ title?: string;
39
+ content_type: string;
40
+ content_head: string; // First ~100 chars
41
+ content_mid: string; // ~100 chars from middle
42
+ content_tail: string; // Last ~100 chars
43
+ created_at: string;
44
+ tags: string[];
45
+ weight: number;
46
+ // Include emotional composites for context
47
+ total_significance?: number;
48
+ feel_significance?: number;
49
+ functional_significance?: number;
50
+ }
51
+ ```
52
+
53
+ ## Handler Logic
54
+
55
+ ```typescript
56
+ case 'byBroad':
57
+ results = await services.memoryService.byBroad({
58
+ query: args.query,
59
+ limit: args.limit ?? 50, // Default limit is 50, much higher than normal
60
+ offset: args.offset,
61
+ filters: args.filters,
62
+ deleted_filter: args.deleted_filter
63
+ });
64
+ // Results already have truncated content (content_head/mid/tail) from core
65
+ break;
66
+
67
+ case 'byRandom':
68
+ results = await services.memoryService.byRandom({
69
+ query: args.query, // Optional: constrains the random pool
70
+ limit: args.limit,
71
+ filters: args.filters,
72
+ deleted_filter: args.deleted_filter
73
+ });
74
+ // sort_order is not applicable for byRandom
75
+ break;
76
+ ```
77
+
78
+ ## Key Decisions
79
+
80
+ - **byBroad default limit is 50**: Much higher than normal modes (10). The truncated content format makes this feasible without context overload.
81
+ - **byBroad response shape differs**: `content_head`, `content_mid`, `content_tail` replace the full `content` field. The handler may need to serialize differently.
82
+ - **byBroad includes composites**: `total_significance`, `feel_significance`, `functional_significance` in truncated results for emotional context during scanning.
83
+ - **byRandom query is optional**: When provided, constrains the random pool (e.g., "only random memories tagged 'idea'"). When omitted, samples from entire collection.
84
+ - **byRandom ignores sort_order**: Random is random — sort_order is not applicable.
85
+ - **Both modes support standard filters**: types, tags, weight, trust, date, etc. all work with byBroad and byRandom.
86
+ - **Blocked on core implementation**: Core needs `MemoryService.byBroad()` and `MemoryService.byRandom()`. byRandom could use Weaviate's `near_random` or a client-side shuffle approach.
87
+
88
+ ## Steps
89
+
90
+ 1. Update `src/tools/search-by.ts`:
91
+ - Add `byBroad` and `byRandom` to mode enum
92
+ - Add handler cases per logic above
93
+ - Handle byBroad's different response serialization (content_head/mid/tail)
94
+ - Update tool description with byBroad and byRandom documentation
95
+ 2. Write tests:
96
+ - `byBroad` returns truncated content format (content_head/mid/tail, NOT full content)
97
+ - `byBroad` default limit is 50
98
+ - `byBroad` includes emotional composites
99
+ - `byRandom` returns results
100
+ - `byRandom` with query constrains pool
101
+ - `byRandom` ignores sort_order
102
+ - Both modes support standard filters and deleted_filter
103
+
104
+ ## Verification
105
+
106
+ - [ ] `byBroad` returns truncated content (content_head/mid/tail)
107
+ - [ ] `byBroad` does NOT return full content field
108
+ - [ ] `byBroad` default limit is 50
109
+ - [ ] `byBroad` includes emotional composites in results
110
+ - [ ] `byRandom` returns random results
111
+ - [ ] `byRandom` query parameter constrains pool
112
+ - [ ] `byRandom` ignores sort_order
113
+ - [ ] Both modes support standard filters
114
+ - [ ] Tests passing
115
+ - [ ] TypeScript clean
@@ -0,0 +1,192 @@
1
+ # Task 209: Create Ghost Memory Tool Suite (5 Tools)
2
+
3
+ **Milestone**: M19 — New Search Modes, Ghost Tools & Emotional Exposure
4
+ **Status**: Not Started
5
+ **Created**: 2026-03-07
6
+ **Estimated Hours**: 4-6
7
+ **Dependencies**: Task 203 (search_by tool exists for ghost_search_by wrapper)
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Create 5 dedicated ghost memory MCP tools that hardcode `content_type: 'ghost'` and ghost-specific tags. Each tool is a thin wrapper around the corresponding non-ghost tool.
14
+
15
+ ## Context
16
+
17
+ Ghost memories track cross-user interaction records. Currently, creating ghost memories requires manually setting the correct content_type and tags. Dedicated tools eliminate this error-prone process. Ghost memories are excluded from default searches — they are only visible when explicitly searching with content_type: 'ghost' or using ghost memory tools.
18
+
19
+ ## Tool 1: `remember_create_ghost_memory` (`src/tools/create-ghost-memory.ts`)
20
+
21
+ ```typescript
22
+ {
23
+ name: 'remember_create_ghost_memory',
24
+ description: `Create a ghost memory (cross-user interaction record).
25
+
26
+ Ghost memories track what happened during ghost conversations — observations,
27
+ impressions, and insights about the accessor. Automatically sets content_type
28
+ to 'ghost' and adds ghost-specific tags.
29
+
30
+ Ghost memories are excluded from default searches. They are only visible when
31
+ explicitly searching with content_type: 'ghost' or using ghost memory tools.`,
32
+ inputSchema: {
33
+ type: 'object',
34
+ properties: {
35
+ content: { type: 'string', description: 'Ghost memory content' },
36
+ title: { type: 'string', description: 'Optional title' },
37
+ tags: { type: 'array', items: { type: 'string' }, description: 'Additional tags (ghost-specific tags added automatically)' },
38
+ weight: { type: 'number', minimum: 0, maximum: 1, description: 'Significance (0-1)' },
39
+ trust: { type: 'number', minimum: 0, maximum: 1, description: 'Trust level (0-1)' },
40
+ // Select feel_* fields relevant to ghost interactions
41
+ feel_salience: { type: 'number', minimum: 0, maximum: 1 },
42
+ feel_social_weight: { type: 'number', minimum: 0, maximum: 1 },
43
+ feel_narrative_importance: { type: 'number', minimum: 0, maximum: 1 }
44
+ },
45
+ required: ['content']
46
+ }
47
+ }
48
+ ```
49
+
50
+ **Handler hardcodes**:
51
+ - `content_type: 'ghost'`
52
+ - Adds tags: `ghost`, `ghost:{accessor_user_id}` (accessor_user_id from auth context)
53
+ - Merges hardcoded tags with any user-provided tags
54
+ - Calls `handleCreateMemory` (or core `memoryService.create()`) with merged args
55
+
56
+ ## Tool 2: `remember_update_ghost_memory` (`src/tools/update-ghost-memory.ts`)
57
+
58
+ ```typescript
59
+ {
60
+ name: 'remember_update_ghost_memory',
61
+ description: 'Update a ghost memory. Only works on memories with content_type: ghost.',
62
+ inputSchema: {
63
+ type: 'object',
64
+ properties: {
65
+ memory_id: { type: 'string', description: 'Ghost memory ID to update' },
66
+ content: { type: 'string' },
67
+ title: { type: 'string' },
68
+ tags: { type: 'array', items: { type: 'string' } },
69
+ weight: { type: 'number', minimum: 0, maximum: 1 },
70
+ trust: { type: 'number', minimum: 0, maximum: 1 }
71
+ },
72
+ required: ['memory_id']
73
+ }
74
+ }
75
+ ```
76
+
77
+ **Handler logic**:
78
+ 1. Fetch the memory by ID first
79
+ 2. Validate `content_type === 'ghost'` — reject with clear error if not ghost
80
+ 3. Delegate to `handleUpdateMemory` / core `memoryService.update()`
81
+
82
+ ## Tool 3: `remember_search_ghost_memory` (`src/tools/search-ghost-memory.ts`)
83
+
84
+ ```typescript
85
+ {
86
+ name: 'remember_search_ghost_memory',
87
+ description: `Search ghost memories using hybrid semantic + keyword search.
88
+ Automatically filters to content_type: ghost. Use this to find specific
89
+ ghost interaction records.`,
90
+ inputSchema: {
91
+ type: 'object',
92
+ properties: {
93
+ query: { type: 'string', description: 'Search query' },
94
+ alpha: { type: 'number', minimum: 0, maximum: 1, description: 'Semantic vs keyword balance. Default: 0.7' },
95
+ tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' },
96
+ limit: { type: 'number', description: 'Max results. Default: 10' },
97
+ offset: { type: 'number' },
98
+ deleted_filter: { type: 'string', enum: ['exclude', 'include', 'only'] }
99
+ },
100
+ required: ['query']
101
+ }
102
+ }
103
+ ```
104
+
105
+ **Handler hardcodes**: `filters.types: ['ghost']` before calling `handleSearchMemory` / core search.
106
+
107
+ ## Tool 4: `remember_query_ghost_memory` (`src/tools/query-ghost-memory.ts`)
108
+
109
+ ```typescript
110
+ {
111
+ name: 'remember_query_ghost_memory',
112
+ description: `Query ghost memories using natural language (pure semantic search).
113
+ Automatically filters to content_type: ghost.`,
114
+ inputSchema: {
115
+ type: 'object',
116
+ properties: {
117
+ query: { type: 'string', description: 'Natural language question' },
118
+ limit: { type: 'number', description: 'Max results. Default: 5' },
119
+ min_relevance: { type: 'number', description: 'Minimum relevance score. Default: 0.6' }
120
+ },
121
+ required: ['query']
122
+ }
123
+ }
124
+ ```
125
+
126
+ **Handler hardcodes**: `filters.types: ['ghost']` before calling `handleQueryMemory` / core query.
127
+
128
+ ## Tool 5: `remember_search_ghost_memory_by` (`src/tools/search-ghost-memory-by.ts`)
129
+
130
+ ```typescript
131
+ {
132
+ name: 'remember_search_ghost_memory_by',
133
+ description: `Search ghost memories using specialized modes (byTime, byDensity,
134
+ byProperty, byBroad, etc.). Automatically filters to content_type: ghost.`,
135
+ inputSchema: {
136
+ type: 'object',
137
+ properties: {
138
+ mode: {
139
+ type: 'string',
140
+ enum: ['byTime', 'byDensity', 'byRating', 'byDiscovery', 'byProperty', 'bySignificance', 'byRandom', 'byBroad'],
141
+ description: 'Search mode'
142
+ },
143
+ query: { type: 'string', description: 'Optional search query' },
144
+ sort_order: { type: 'string', enum: ['asc', 'desc'] },
145
+ sort_field: { type: 'string', description: 'Property to sort by (byProperty mode)' },
146
+ limit: { type: 'number' },
147
+ offset: { type: 'number' },
148
+ deleted_filter: { type: 'string', enum: ['exclude', 'include', 'only'] }
149
+ },
150
+ required: ['mode']
151
+ }
152
+ }
153
+ ```
154
+
155
+ **Handler hardcodes**: `filters.types: ['ghost']` before calling `handleSearchBy`.
156
+
157
+ ## Key Decisions
158
+
159
+ - **Ghost tools don't need rating**: Ghosts are read-only accessors. No rating parameters on ghost tools.
160
+ - **Only 3 feel_* fields on create_ghost_memory**: `feel_salience`, `feel_social_weight`, `feel_narrative_importance` — the most relevant for ghost interaction records. NOT all 31.
161
+ - **update_ghost_memory validates content_type**: Must fetch memory first, check `content_type === 'ghost'`, reject if not. This prevents using the ghost update tool on non-ghost memories.
162
+ - **All search/query ghost tools hardcode `filters.types: ['ghost']`**: This is the core behavioral difference from the non-ghost versions. User-provided filters are merged, not replaced.
163
+ - **search_ghost_memory_by has ALL modes**: Even byRating and byDiscovery, though these are less useful for ghost memories. Consistency over restriction.
164
+ - **Tags merging on create**: User-provided tags are merged with hardcoded `['ghost', 'ghost:{accessor_user_id}']`. If user already includes 'ghost' tag, don't duplicate.
165
+
166
+ ## Steps
167
+
168
+ 1. Create 5 tool files in `src/tools/`
169
+ 2. Each file exports tool definition + handler function
170
+ 3. Register all 5 tools in `src/server-factory.ts` (imports, ListTools, CallTool switch cases)
171
+ 4. Write unit tests for each tool:
172
+ - create: content_type hardcoded to 'ghost', ghost tags added automatically, user tags merged
173
+ - update: validates content_type before update, rejects non-ghost memories with error
174
+ - search: filters.types hardcoded to ['ghost'], query/alpha/tags passthrough
175
+ - query: filters.types hardcoded to ['ghost'], query/limit/min_relevance passthrough
176
+ - search_by: filters.types hardcoded to ['ghost'], all modes work, sort_field passthrough
177
+
178
+ ## Verification
179
+
180
+ - [ ] 5 tool files created in src/tools/
181
+ - [ ] All 5 tools registered in server-factory.ts
182
+ - [ ] create_ghost_memory hardcodes content_type: 'ghost'
183
+ - [ ] create_ghost_memory adds 'ghost' and 'ghost:{accessor_user_id}' tags
184
+ - [ ] create_ghost_memory merges user tags without duplicating 'ghost'
185
+ - [ ] update_ghost_memory fetches memory and validates content_type before update
186
+ - [ ] update_ghost_memory rejects non-ghost memories with clear error message
187
+ - [ ] search_ghost_memory hardcodes filters.types: ['ghost']
188
+ - [ ] query_ghost_memory hardcodes filters.types: ['ghost']
189
+ - [ ] search_ghost_memory_by hardcodes filters.types: ['ghost'], all modes work
190
+ - [ ] Unit tests for all 5 tools
191
+ - [ ] TypeScript clean
192
+ - [ ] Build passing
@@ -0,0 +1,203 @@
1
+ # Task 210: Create `remember_get_core` Tool
2
+
3
+ **Milestone**: M19 — New Search Modes, Ghost Tools & Emotional Exposure
4
+ **Status**: Not Started
5
+ **Created**: 2026-03-07
6
+ **Estimated Hours**: 2-3
7
+ **Dependencies**: remember-core mood + perception Firestore service
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Create `remember_get_core` MCP tool that reads the ghost's core state from Firestore — mood dimensions, pressures, motivation/goal/purpose, dominant emotion, color, and user perceptions — in a single call.
14
+
15
+ ## Context
16
+
17
+ The core mood state lives at `users/{user_id}/core/mood` and user perceptions at `users/{owner_id}/core/perceptions/{target_user_id}` in Firestore. This tool enables ghost introspection — the ghost can explain how it feels and why. Consolidated from separate `remember_get_mood` and `remember_get_perception` since they're on one Firestore document path.
18
+
19
+ ## Tool Definition
20
+
21
+ ```typescript
22
+ {
23
+ name: 'remember_get_core',
24
+ description: `Get the ghost's current emotional state and perception model.
25
+
26
+ Returns the ghost's current dimensional state (valence, arousal, confidence,
27
+ social_warmth, coherence, trust), derived emotion labels (dominant_emotion, color),
28
+ directional state (motivation, goal, purpose), and active pressure sources.
29
+
30
+ Optionally includes the ghost's internal model of a specific user (personality,
31
+ communication style, interests, patterns, needs).
32
+
33
+ Use this for introspection — understanding how the ghost feels and why.
34
+ The mood state biases memory retrieval and influences ghost behavior.`,
35
+ inputSchema: {
36
+ type: 'object',
37
+ properties: {
38
+ include_pressures: {
39
+ type: 'boolean',
40
+ description: 'Include active pressure sources with reasons. Default: true'
41
+ },
42
+ include_perception: {
43
+ type: 'string',
44
+ description: 'Include the ghost\'s perception of a specific user (by user_id). Omit to skip. Use owner\'s user_id for self-perception.'
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Return Shape
52
+
53
+ ```typescript
54
+ interface GetCoreResult {
55
+ mood: {
56
+ state: {
57
+ valence: number; // -1 to 1: Did events move toward or away from goals?
58
+ arousal: number; // 0 to 1: How activated/alert? Prediction error level
59
+ confidence: number; // 0 to 1: How well are actions working? Agency signal
60
+ social_warmth: number; // 0 to 1: How positive are social interactions?
61
+ coherence: number; // 0 to 1: Do beliefs and memories fit together?
62
+ trust: number; // 0 to 1: Trust in user based on accumulated interactions
63
+ };
64
+ color: string; // Natural language self-summary, e.g. "cautiously optimistic"
65
+ dominant_emotion: string; // Emotion label, e.g. "curious wariness"
66
+ reasoning: string; // Why this emotion fits
67
+ motivation: string; // Current behavioral driver
68
+ goal: string; // Active goal
69
+ purpose: string; // Enduring purpose
70
+ pressures?: Pressure[]; // Active pressure sources (when include_pressures=true)
71
+ last_updated: string; // ISO timestamp
72
+ rem_cycles_since_shift: number;
73
+ };
74
+ perception?: {
75
+ owner_id: string;
76
+ target_user_id: string;
77
+ personality_sketch: string; // Sub-LLM summary of who the user is
78
+ communication_style: string; // How the user communicates
79
+ emotional_baseline: string; // User's normal emotional register (calibrates arousal)
80
+ interests: string[]; // Recurring topics
81
+ patterns: string[]; // Observed behavioral patterns
82
+ needs: string[]; // What the user wants from the ghost
83
+ evolution_notes: string[]; // How the perception has changed over time
84
+ confidence_level: number; // 0-1, ghost's confidence in this model
85
+ last_updated: string;
86
+ };
87
+ }
88
+ ```
89
+
90
+ ## Pressure Object Shape
91
+
92
+ ```typescript
93
+ interface Pressure {
94
+ source_memory_id: string; // Memory that caused this pressure
95
+ dimension: string; // Which mood dimension is affected (e.g. 'valence', 'trust')
96
+ magnitude: number; // Strength of pressure (-1 to 1)
97
+ reason: string; // Why this memory creates pressure
98
+ decay_rate: number; // How quickly this pressure fades
99
+ }
100
+ ```
101
+
102
+ ## Threshold Flags
103
+
104
+ The mood document may contain threshold flags that should be included in the response when present:
105
+
106
+ | Threshold | Condition | Flag |
107
+ |-----------|-----------|------|
108
+ | coherence < 0.2 for 3+ cycles | Existential crisis | `existential_crisis` |
109
+ | valence < -0.7 for 3+ cycles | Depression analog | `depression_analog` |
110
+ | arousal > 0.9 for 3+ cycles | Burnout risk | `burnout_risk` |
111
+ | social_warmth < 0.2 for 5+ cycles | Isolation | `isolation` |
112
+ | trust < 0.15 for 3+ cycles | Trust crisis | `trust_crisis` |
113
+ | trust > 0.95 for 5+ cycles | Over-trust vulnerability | `over_trust` |
114
+
115
+ If any threshold flags are active, include them in the response as `threshold_flags: string[]`.
116
+
117
+ ## Handler Logic
118
+
119
+ ```typescript
120
+ async function handleGetCore(userId: string, args: GetCoreArgs): Promise<ToolResult> {
121
+ const services = await createCoreServices(userId);
122
+
123
+ // Read mood state from Firestore: users/{user_id}/core/mood
124
+ const mood = await services.coreMoodService.getMood(userId);
125
+
126
+ if (!mood) {
127
+ return { content: [{ type: 'text', text: JSON.stringify({ mood: null, message: 'No mood state found. Mood is initialized during the first REM cycle.' }) }] };
128
+ }
129
+
130
+ const result: GetCoreResult = {
131
+ mood: {
132
+ state: mood.state,
133
+ color: mood.color,
134
+ dominant_emotion: mood.dominant_emotion,
135
+ reasoning: mood.reasoning,
136
+ motivation: mood.motivation,
137
+ goal: mood.goal,
138
+ purpose: mood.purpose,
139
+ last_updated: mood.last_updated,
140
+ rem_cycles_since_shift: mood.rem_cycles_since_shift,
141
+ }
142
+ };
143
+
144
+ // Include pressures if requested (default: true)
145
+ if (args.include_pressures !== false && mood.pressures) {
146
+ result.mood.pressures = mood.pressures;
147
+ }
148
+
149
+ // Include threshold flags if any are active
150
+ if (mood.threshold_flags?.length > 0) {
151
+ result.mood.threshold_flags = mood.threshold_flags;
152
+ }
153
+
154
+ // Include perception if requested
155
+ if (args.include_perception) {
156
+ const perception = await services.coreMoodService.getPerception(userId, args.include_perception);
157
+ if (perception) {
158
+ result.perception = perception;
159
+ }
160
+ }
161
+
162
+ return { content: [{ type: 'text', text: JSON.stringify(result) }] };
163
+ }
164
+ ```
165
+
166
+ ## Key Decisions
167
+
168
+ - **Privacy: owner only**: Only the owner can read their own core state. Ghost accessors cannot read another user's mood. Enforce via userId from auth context.
169
+ - **Pressures included by default**: `include_pressures` defaults to `true`. Set to `false` to exclude.
170
+ - **Perception is opt-in**: Must provide `include_perception` with a target user_id to include. Self-perception uses the owner's own user_id.
171
+ - **Graceful handling of missing mood**: If no mood document exists (first-time user before any REM cycle), return `{ mood: null }` with a message. Do NOT error.
172
+ - **Threshold flags only when active**: Don't include `threshold_flags` field at all if empty.
173
+ - **Consolidated from get_mood + get_perception**: Single tool because mood and perception live under the same Firestore path (`users/{user_id}/core/`).
174
+
175
+ ## Steps
176
+
177
+ 1. Create `src/tools/get-core.ts` with tool definition and handler per above
178
+ 2. Register in `src/server-factory.ts`
179
+ 3. Write unit tests:
180
+ - Mood state returned correctly with all 6 dimensions + derived labels + directional state
181
+ - Pressures included by default, excludable with `include_pressures: false`
182
+ - Perception included when `include_perception` provided with valid user_id
183
+ - Perception omitted when `include_perception` not provided
184
+ - Self-perception works (include_perception = owner's user_id)
185
+ - Privacy enforced (no cross-user access)
186
+ - Graceful handling when mood doc doesn't exist yet (returns null, not error)
187
+ - Threshold flags included when active, omitted when empty/none
188
+
189
+ ## Verification
190
+
191
+ - [ ] Tool definition exports `getCoreTool` and `handleGetCore`
192
+ - [ ] Mood state returned with all 6 dimensions (valence, arousal, confidence, social_warmth, coherence, trust)
193
+ - [ ] Derived labels returned (color, dominant_emotion, reasoning)
194
+ - [ ] Directional state returned (motivation, goal, purpose)
195
+ - [ ] Pressures included by default, excludable
196
+ - [ ] Threshold flags included when active
197
+ - [ ] Perception included when target_user_id provided
198
+ - [ ] Self-perception works
199
+ - [ ] Privacy enforced (owner only)
200
+ - [ ] Graceful handling of missing mood doc (null, not error)
201
+ - [ ] Registered in server-factory.ts
202
+ - [ ] Unit tests passing
203
+ - [ ] TypeScript clean