audrey 1.0.1 → 1.0.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 (227) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +5 -3
  3. package/benchmarks/adapter-self-test.mjs +6 -2
  4. package/benchmarks/adapters/example-allow.mjs +5 -2
  5. package/benchmarks/adapters/mem0-platform.mjs +19 -12
  6. package/benchmarks/adapters/zep-cloud.mjs +51 -27
  7. package/benchmarks/baselines.js +11 -6
  8. package/benchmarks/build-leaderboard.mjs +36 -23
  9. package/benchmarks/cases.js +24 -12
  10. package/benchmarks/create-conformance-card.mjs +12 -3
  11. package/benchmarks/create-submission-bundle.mjs +22 -8
  12. package/benchmarks/dry-run-external-adapters.mjs +24 -12
  13. package/benchmarks/guardbench.js +263 -123
  14. package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +4 -4
  15. package/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
  16. package/benchmarks/output/external/guardbench-external-evidence.json +1 -1
  17. package/benchmarks/output/guardbench-conformance-card.json +11 -11
  18. package/benchmarks/output/guardbench-raw.json +107 -108
  19. package/benchmarks/output/guardbench-summary.json +170 -172
  20. package/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
  21. package/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
  22. package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +11 -11
  23. package/benchmarks/output/submission-bundle/guardbench-raw.json +107 -108
  24. package/benchmarks/output/submission-bundle/guardbench-summary.json +170 -172
  25. package/benchmarks/output/submission-bundle/submission-manifest.json +11 -11
  26. package/benchmarks/output/submission-bundle/validation-report.json +1 -1
  27. package/benchmarks/output/summary.json +57 -57
  28. package/benchmarks/perf-snapshot.js +12 -9
  29. package/benchmarks/perf.bench.js +14 -6
  30. package/benchmarks/public-paths.mjs +11 -5
  31. package/benchmarks/reference-results.js +10 -5
  32. package/benchmarks/report.js +48 -27
  33. package/benchmarks/run-external-guardbench.mjs +47 -25
  34. package/benchmarks/run.js +112 -59
  35. package/benchmarks/validate-adapter-module.mjs +13 -10
  36. package/benchmarks/validate-adapter-registry.mjs +16 -5
  37. package/benchmarks/validate-guardbench-artifacts.mjs +76 -19
  38. package/benchmarks/verify-external-evidence.mjs +86 -31
  39. package/benchmarks/verify-publication-artifacts.mjs +34 -11
  40. package/benchmarks/verify-submission-bundle.mjs +9 -4
  41. package/dist/mcp-server/config.d.ts +1 -1
  42. package/dist/mcp-server/config.d.ts.map +1 -1
  43. package/dist/mcp-server/config.js +5 -3
  44. package/dist/mcp-server/config.js.map +1 -1
  45. package/dist/mcp-server/index.d.ts +4 -3
  46. package/dist/mcp-server/index.d.ts.map +1 -1
  47. package/dist/mcp-server/index.js +479 -172
  48. package/dist/mcp-server/index.js.map +1 -1
  49. package/dist/src/action-key.d.ts.map +1 -1
  50. package/dist/src/action-key.js +6 -2
  51. package/dist/src/action-key.js.map +1 -1
  52. package/dist/src/adaptive.d.ts.map +1 -1
  53. package/dist/src/adaptive.js +4 -2
  54. package/dist/src/adaptive.js.map +1 -1
  55. package/dist/src/affect.d.ts.map +1 -1
  56. package/dist/src/affect.js +8 -5
  57. package/dist/src/affect.js.map +1 -1
  58. package/dist/src/audrey.d.ts +1 -1
  59. package/dist/src/audrey.d.ts.map +1 -1
  60. package/dist/src/audrey.js +93 -49
  61. package/dist/src/audrey.js.map +1 -1
  62. package/dist/src/capsule.d.ts.map +1 -1
  63. package/dist/src/capsule.js +37 -15
  64. package/dist/src/capsule.js.map +1 -1
  65. package/dist/src/causal.d.ts +1 -1
  66. package/dist/src/causal.d.ts.map +1 -1
  67. package/dist/src/causal.js +4 -2
  68. package/dist/src/causal.js.map +1 -1
  69. package/dist/src/confidence.d.ts.map +1 -1
  70. package/dist/src/confidence.js +5 -5
  71. package/dist/src/confidence.js.map +1 -1
  72. package/dist/src/consolidate.d.ts.map +1 -1
  73. package/dist/src/consolidate.js +17 -9
  74. package/dist/src/consolidate.js.map +1 -1
  75. package/dist/src/context.js +1 -1
  76. package/dist/src/context.js.map +1 -1
  77. package/dist/src/controller.d.ts.map +1 -1
  78. package/dist/src/controller.js +24 -13
  79. package/dist/src/controller.js.map +1 -1
  80. package/dist/src/db.d.ts.map +1 -1
  81. package/dist/src/db.js +78 -27
  82. package/dist/src/db.js.map +1 -1
  83. package/dist/src/decay.d.ts +1 -1
  84. package/dist/src/decay.d.ts.map +1 -1
  85. package/dist/src/decay.js +1 -1
  86. package/dist/src/decay.js.map +1 -1
  87. package/dist/src/embedding.d.ts +12 -4
  88. package/dist/src/embedding.d.ts.map +1 -1
  89. package/dist/src/embedding.js +18 -16
  90. package/dist/src/embedding.js.map +1 -1
  91. package/dist/src/encode.d.ts.map +1 -1
  92. package/dist/src/encode.js +5 -4
  93. package/dist/src/encode.js.map +1 -1
  94. package/dist/src/events.d.ts +3 -2
  95. package/dist/src/events.d.ts.map +1 -1
  96. package/dist/src/events.js +7 -3
  97. package/dist/src/events.js.map +1 -1
  98. package/dist/src/export.d.ts.map +1 -1
  99. package/dist/src/export.js +21 -7
  100. package/dist/src/export.js.map +1 -1
  101. package/dist/src/feedback.d.ts.map +1 -1
  102. package/dist/src/feedback.js +1 -1
  103. package/dist/src/feedback.js.map +1 -1
  104. package/dist/src/forget.d.ts.map +1 -1
  105. package/dist/src/forget.js +12 -6
  106. package/dist/src/forget.js.map +1 -1
  107. package/dist/src/fts.d.ts.map +1 -1
  108. package/dist/src/fts.js +20 -8
  109. package/dist/src/fts.js.map +1 -1
  110. package/dist/src/hybrid-recall.d.ts.map +1 -1
  111. package/dist/src/hybrid-recall.js +12 -6
  112. package/dist/src/hybrid-recall.js.map +1 -1
  113. package/dist/src/impact.d.ts.map +1 -1
  114. package/dist/src/impact.js +26 -10
  115. package/dist/src/impact.js.map +1 -1
  116. package/dist/src/import.d.ts.map +1 -1
  117. package/dist/src/import.js +11 -6
  118. package/dist/src/import.js.map +1 -1
  119. package/dist/src/index.d.ts +3 -3
  120. package/dist/src/index.d.ts.map +1 -1
  121. package/dist/src/index.js +3 -3
  122. package/dist/src/index.js.map +1 -1
  123. package/dist/src/interference.d.ts.map +1 -1
  124. package/dist/src/interference.js +10 -5
  125. package/dist/src/interference.js.map +1 -1
  126. package/dist/src/introspect.d.ts.map +1 -1
  127. package/dist/src/introspect.js +12 -6
  128. package/dist/src/introspect.js.map +1 -1
  129. package/dist/src/llm.d.ts +2 -2
  130. package/dist/src/llm.d.ts.map +1 -1
  131. package/dist/src/llm.js +6 -6
  132. package/dist/src/llm.js.map +1 -1
  133. package/dist/src/migrate.d.ts.map +1 -1
  134. package/dist/src/migrate.js +10 -4
  135. package/dist/src/migrate.js.map +1 -1
  136. package/dist/src/preflight.d.ts.map +1 -1
  137. package/dist/src/preflight.js +6 -8
  138. package/dist/src/preflight.js.map +1 -1
  139. package/dist/src/profile.d.ts.map +1 -1
  140. package/dist/src/profile.js.map +1 -1
  141. package/dist/src/promote.d.ts.map +1 -1
  142. package/dist/src/promote.js +16 -7
  143. package/dist/src/promote.js.map +1 -1
  144. package/dist/src/prompts.d.ts.map +1 -1
  145. package/dist/src/prompts.js +1 -2
  146. package/dist/src/prompts.js.map +1 -1
  147. package/dist/src/recall.d.ts.map +1 -1
  148. package/dist/src/recall.js +85 -18
  149. package/dist/src/recall.js.map +1 -1
  150. package/dist/src/redact.d.ts.map +1 -1
  151. package/dist/src/redact.js +9 -4
  152. package/dist/src/redact.js.map +1 -1
  153. package/dist/src/reflexes.d.ts.map +1 -1
  154. package/dist/src/reflexes.js +1 -7
  155. package/dist/src/reflexes.js.map +1 -1
  156. package/dist/src/rollback.d.ts.map +1 -1
  157. package/dist/src/rollback.js +4 -2
  158. package/dist/src/rollback.js.map +1 -1
  159. package/dist/src/routes.d.ts.map +1 -1
  160. package/dist/src/routes.js +33 -13
  161. package/dist/src/routes.js.map +1 -1
  162. package/dist/src/rules-compiler.d.ts.map +1 -1
  163. package/dist/src/rules-compiler.js +24 -2
  164. package/dist/src/rules-compiler.js.map +1 -1
  165. package/dist/src/server.js +2 -2
  166. package/dist/src/server.js.map +1 -1
  167. package/dist/src/tool-trace.d.ts +2 -2
  168. package/dist/src/tool-trace.d.ts.map +1 -1
  169. package/dist/src/tool-trace.js +12 -4
  170. package/dist/src/tool-trace.js.map +1 -1
  171. package/dist/src/types.d.ts.map +1 -1
  172. package/dist/src/ulid.js +1 -1
  173. package/dist/src/ulid.js.map +1 -1
  174. package/dist/src/utils.d.ts.map +1 -1
  175. package/dist/src/utils.js.map +1 -1
  176. package/dist/src/validate.d.ts.map +1 -1
  177. package/dist/src/validate.js +20 -10
  178. package/dist/src/validate.js.map +1 -1
  179. package/docs/paper/07-evaluation.md +5 -5
  180. package/docs/paper/audrey-paper-v1.md +5 -5
  181. package/docs/paper/evidence-ledger.md +1 -1
  182. package/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  183. package/docs/paper/output/arxiv/main.tex +5 -5
  184. package/docs/paper/output/arxiv-compile-report.json +3 -3
  185. package/docs/paper/output/submission-bundle/README.md +5 -3
  186. package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +4 -4
  187. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
  188. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +1 -1
  189. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +11 -11
  190. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +107 -108
  191. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +170 -172
  192. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
  193. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
  194. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +11 -11
  195. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +1 -1
  196. package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +58 -58
  197. package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +5 -5
  198. package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +5 -5
  199. package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +1 -1
  200. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  201. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +5 -5
  202. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +3 -3
  203. package/docs/paper/output/submission-bundle/package.json +17 -4
  204. package/docs/paper/output/submission-bundle/paper-submission-manifest.json +36 -36
  205. package/examples/fintech-ops-demo.js +12 -5
  206. package/examples/healthcare-ops-demo.js +8 -4
  207. package/examples/ollama-memory-agent.js +41 -13
  208. package/examples/stripe-demo.js +12 -5
  209. package/package.json +17 -4
  210. package/scripts/audit-release-completion.mjs +179 -101
  211. package/scripts/create-arxiv-source.mjs +20 -14
  212. package/scripts/create-paper-submission-bundle.mjs +6 -2
  213. package/scripts/finalize-release.mjs +111 -36
  214. package/scripts/prepare-release-cut.mjs +14 -6
  215. package/scripts/publish-release-bundle.mjs +62 -23
  216. package/scripts/publish-release-github-api.mjs +89 -24
  217. package/scripts/smoke-cli.js +9 -9
  218. package/scripts/sync-paper-artifacts.mjs +5 -1
  219. package/scripts/verify-arxiv-compile.mjs +52 -16
  220. package/scripts/verify-arxiv-source.mjs +45 -15
  221. package/scripts/verify-browser-launch-plan.mjs +28 -11
  222. package/scripts/verify-browser-launch-results.mjs +32 -14
  223. package/scripts/verify-paper-artifacts.mjs +539 -79
  224. package/scripts/verify-paper-claims.mjs +48 -20
  225. package/scripts/verify-paper-submission-bundle.mjs +22 -11
  226. package/scripts/verify-publication-pack.mjs +23 -9
  227. package/scripts/verify-release-readiness.mjs +211 -76
@@ -2,7 +2,7 @@
2
2
  import { z } from 'zod';
3
3
  import { homedir, platform, tmpdir } from 'node:os';
4
4
  import { dirname, join, resolve } from 'node:path';
5
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync, } from 'node:fs';
6
6
  import { execFileSync } from 'node:child_process';
7
7
  import { fileURLToPath } from 'node:url';
8
8
  import { Audrey, MemoryController } from '../src/index.js';
@@ -56,21 +56,46 @@ function isEmbeddingWarmupDisabled(env = process.env) {
56
56
  return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';
57
57
  }
58
58
  export const memoryEncodeToolSchema = {
59
- content: z.string()
59
+ content: z
60
+ .string()
60
61
  .max(MAX_MEMORY_CONTENT_LENGTH)
61
62
  .refine(isNonEmptyText, 'Content must not be empty')
62
63
  .describe('The memory content to encode'),
63
64
  source: z.enum(VALID_SOURCES).describe('Source type of the memory'),
64
65
  tags: z.array(z.string()).optional().describe('Optional tags for categorization'),
65
66
  salience: z.number().min(0).max(1).optional().describe('Importance weight 0-1'),
66
- context: z.record(z.string(), z.string()).optional().describe('Situational context as key-value pairs (e.g., {task: "debugging", domain: "payments"})'),
67
- affect: z.object({
68
- valence: z.number().min(-1).max(1).describe('Emotional valence: -1 (very negative) to 1 (very positive)'),
69
- arousal: z.number().min(0).max(1).optional().describe('Emotional arousal: 0 (calm) to 1 (highly activated)'),
70
- label: z.string().optional().describe('Human-readable emotion label (e.g., "curiosity", "frustration", "relief")'),
71
- }).optional().describe('Emotional affect - how this memory feels'),
72
- private: z.boolean().optional().describe('If true, memory is only visible to the AI and excluded from public recall results'),
73
- wait_for_consolidation: z.boolean().optional().describe('If true, wait for post-encode validation/interference/resonance work before returning. Defaults to false.'),
67
+ context: z
68
+ .record(z.string(), z.string())
69
+ .optional()
70
+ .describe('Situational context as key-value pairs (e.g., {task: "debugging", domain: "payments"})'),
71
+ affect: z
72
+ .object({
73
+ valence: z
74
+ .number()
75
+ .min(-1)
76
+ .max(1)
77
+ .describe('Emotional valence: -1 (very negative) to 1 (very positive)'),
78
+ arousal: z
79
+ .number()
80
+ .min(0)
81
+ .max(1)
82
+ .optional()
83
+ .describe('Emotional arousal: 0 (calm) to 1 (highly activated)'),
84
+ label: z
85
+ .string()
86
+ .optional()
87
+ .describe('Human-readable emotion label (e.g., "curiosity", "frustration", "relief")'),
88
+ })
89
+ .optional()
90
+ .describe('Emotional affect - how this memory feels'),
91
+ private: z
92
+ .boolean()
93
+ .optional()
94
+ .describe('If true, memory is only visible to the AI and excluded from public recall results'),
95
+ wait_for_consolidation: z
96
+ .boolean()
97
+ .optional()
98
+ .describe('If true, wait for post-encode validation/interference/resonance work before returning. Defaults to false.'),
74
99
  };
75
100
  export const memoryRecallToolSchema = {
76
101
  query: z.string().describe('Search query to match against memories'),
@@ -78,73 +103,196 @@ export const memoryRecallToolSchema = {
78
103
  types: z.array(z.enum(VALID_TYPES)).optional().describe('Memory types to search'),
79
104
  min_confidence: z.number().min(0).max(1).optional().describe('Minimum confidence threshold'),
80
105
  tags: z.array(z.string()).optional().describe('Only return episodic memories with these tags'),
81
- sources: z.array(z.enum(VALID_SOURCES)).optional().describe('Only return episodic memories from these sources'),
106
+ sources: z
107
+ .array(z.enum(VALID_SOURCES))
108
+ .optional()
109
+ .describe('Only return episodic memories from these sources'),
82
110
  after: z.string().optional().describe('Only return memories created after this ISO date'),
83
111
  before: z.string().optional().describe('Only return memories created before this ISO date'),
84
- context: z.record(z.string(), z.string()).optional().describe('Retrieval context - memories encoded in matching context get boosted'),
85
- mood: z.object({
86
- valence: z.number().min(-1).max(1).describe('Current emotional valence: -1 (negative) to 1 (positive)'),
87
- arousal: z.number().min(0).max(1).optional().describe('Current arousal: 0 (calm) to 1 (activated)'),
88
- }).optional().describe('Current mood - boosts recall of memories encoded in similar emotional state'),
89
- retrieval: z.enum(['hybrid', 'vector']).optional().describe('Retrieval strategy. hybrid is the default (vector + FTS/BM25 fusion); vector bypasses FTS for lower latency but loses lexical exact-match signal.'),
90
- scope: z.enum(['agent', 'shared']).optional().describe('agent restricts recall to this MCP server agent identity. shared searches the whole store. Defaults to shared for backward compatibility.'),
112
+ context: z
113
+ .record(z.string(), z.string())
114
+ .optional()
115
+ .describe('Retrieval context - memories encoded in matching context get boosted'),
116
+ mood: z
117
+ .object({
118
+ valence: z
119
+ .number()
120
+ .min(-1)
121
+ .max(1)
122
+ .describe('Current emotional valence: -1 (negative) to 1 (positive)'),
123
+ arousal: z
124
+ .number()
125
+ .min(0)
126
+ .max(1)
127
+ .optional()
128
+ .describe('Current arousal: 0 (calm) to 1 (activated)'),
129
+ })
130
+ .optional()
131
+ .describe('Current mood - boosts recall of memories encoded in similar emotional state'),
132
+ retrieval: z
133
+ .enum(['hybrid', 'vector'])
134
+ .optional()
135
+ .describe('Retrieval strategy. hybrid is the default (vector + FTS/BM25 fusion); vector bypasses FTS for lower latency but loses lexical exact-match signal.'),
136
+ scope: z
137
+ .enum(['agent', 'shared'])
138
+ .optional()
139
+ .describe('agent restricts recall to this MCP server agent identity. shared searches the whole store. Defaults to shared for backward compatibility.'),
91
140
  };
92
141
  export const memoryImportToolSchema = {
93
142
  snapshot: importSnapshotSchema.describe('A validated snapshot from memory_export'),
94
143
  };
95
144
  export const memoryForgetToolSchema = {
96
145
  id: z.string().optional().describe('ID of the memory to forget'),
97
- query: z.string().optional().describe('Semantic query to find and forget the closest matching memory'),
98
- min_similarity: z.number().min(0).max(1).optional().describe('Minimum similarity for query-based forget (default 0.9)'),
99
- purge: z.boolean().optional().describe('Hard-delete the memory permanently (default false, soft-delete)'),
146
+ query: z
147
+ .string()
148
+ .optional()
149
+ .describe('Semantic query to find and forget the closest matching memory'),
150
+ min_similarity: z
151
+ .number()
152
+ .min(0)
153
+ .max(1)
154
+ .optional()
155
+ .describe('Minimum similarity for query-based forget (default 0.9)'),
156
+ purge: z
157
+ .boolean()
158
+ .optional()
159
+ .describe('Hard-delete the memory permanently (default false, soft-delete)'),
100
160
  };
101
161
  export const memoryValidateToolSchema = {
102
162
  id: z.string().describe('ID of the memory to validate'),
103
- outcome: z.enum(['used', 'helpful', 'wrong']).describe('How the memory played out: "used" (referenced without obvious value), "helpful" (drove a correct action — reinforces salience and retrieval), "wrong" (memory was misleading — bumps challenge_count and decreases salience).'),
163
+ outcome: z
164
+ .enum(['used', 'helpful', 'wrong'])
165
+ .describe('How the memory played out: "used" (referenced without obvious value), "helpful" (drove a correct action — reinforces salience and retrieval), "wrong" (memory was misleading — bumps challenge_count and decreases salience).'),
104
166
  };
105
167
  export const memoryPreflightToolSchema = {
106
- action: z.string()
168
+ action: z
169
+ .string()
107
170
  .refine(isNonEmptyText, 'Action must not be empty')
108
171
  .describe('Natural-language description of the action the agent is about to take.'),
109
- tool: z.string().optional().describe('Tool or command family about to be used, e.g. Bash, npm test, Edit, deploy.'),
110
- session_id: z.string().optional().describe('Session identifier for grouping the optional preflight event.'),
172
+ tool: z
173
+ .string()
174
+ .optional()
175
+ .describe('Tool or command family about to be used, e.g. Bash, npm test, Edit, deploy.'),
176
+ session_id: z
177
+ .string()
178
+ .optional()
179
+ .describe('Session identifier for grouping the optional preflight event.'),
111
180
  cwd: z.string().optional().describe('Working directory for the action.'),
112
- files: z.array(z.string()).optional().describe('File paths to fingerprint if record_event is true.'),
113
- strict: z.boolean().optional().describe('If true, high-severity memory warnings produce decision=block instead of caution.'),
114
- limit: z.number().int().min(1).max(50).optional().describe('Max recall results to consider before preflight categorization.'),
115
- budget_chars: z.number().int().min(200).max(32000).optional().describe('Capsule budget in characters.'),
116
- mode: z.enum(['balanced', 'conservative', 'aggressive']).optional().describe('Underlying capsule mode. Defaults to conservative.'),
117
- failure_window_hours: z.number().int().min(1).max(8760).optional().describe('How far back to check failed tool events. Defaults to 168 hours.'),
118
- include_status: z.boolean().optional().describe('Include memory health in the response and warning calculation. Defaults to true.'),
119
- record_event: z.boolean().optional().describe('Record a redacted PreToolUse event for this preflight. Defaults to false.'),
120
- include_capsule: z.boolean().optional().describe('If false, omit the embedded Memory Capsule from the response.'),
121
- scope: z.enum(['agent', 'shared']).optional().describe('agent restricts memory recall to this server agent identity. shared searches the whole store. Defaults to agent.'),
181
+ files: z
182
+ .array(z.string())
183
+ .optional()
184
+ .describe('File paths to fingerprint if record_event is true.'),
185
+ strict: z
186
+ .boolean()
187
+ .optional()
188
+ .describe('If true, high-severity memory warnings produce decision=block instead of caution.'),
189
+ limit: z
190
+ .number()
191
+ .int()
192
+ .min(1)
193
+ .max(50)
194
+ .optional()
195
+ .describe('Max recall results to consider before preflight categorization.'),
196
+ budget_chars: z
197
+ .number()
198
+ .int()
199
+ .min(200)
200
+ .max(32000)
201
+ .optional()
202
+ .describe('Capsule budget in characters.'),
203
+ mode: z
204
+ .enum(['balanced', 'conservative', 'aggressive'])
205
+ .optional()
206
+ .describe('Underlying capsule mode. Defaults to conservative.'),
207
+ failure_window_hours: z
208
+ .number()
209
+ .int()
210
+ .min(1)
211
+ .max(8760)
212
+ .optional()
213
+ .describe('How far back to check failed tool events. Defaults to 168 hours.'),
214
+ include_status: z
215
+ .boolean()
216
+ .optional()
217
+ .describe('Include memory health in the response and warning calculation. Defaults to true.'),
218
+ record_event: z
219
+ .boolean()
220
+ .optional()
221
+ .describe('Record a redacted PreToolUse event for this preflight. Defaults to false.'),
222
+ include_capsule: z
223
+ .boolean()
224
+ .optional()
225
+ .describe('If false, omit the embedded Memory Capsule from the response.'),
226
+ scope: z
227
+ .enum(['agent', 'shared'])
228
+ .optional()
229
+ .describe('agent restricts memory recall to this server agent identity. shared searches the whole store. Defaults to agent.'),
122
230
  };
123
231
  const { record_event: _preflightRecordEvent, ...memoryGuardBeforeFields } = memoryPreflightToolSchema;
124
232
  export const memoryGuardBeforeToolSchema = {
125
233
  ...memoryGuardBeforeFields,
126
- session_id: z.string().optional().describe('Session identifier for grouping the required guard receipt event.'),
127
- files: z.array(z.string()).optional().describe('File paths to fingerprint in the required guard receipt.'),
234
+ session_id: z
235
+ .string()
236
+ .optional()
237
+ .describe('Session identifier for grouping the required guard receipt event.'),
238
+ files: z
239
+ .array(z.string())
240
+ .optional()
241
+ .describe('File paths to fingerprint in the required guard receipt.'),
128
242
  };
129
243
  export const memoryGuardAfterToolSchema = {
130
- receipt_id: z.string()
244
+ receipt_id: z
245
+ .string()
131
246
  .refine(isNonEmptyText, 'Receipt id must not be empty')
132
247
  .describe('Receipt id returned by memory_guard_before.'),
133
- tool: z.string().optional().describe('Tool or command family that completed, e.g. Bash, npm test, Edit, deploy.'),
134
- session_id: z.string().optional().describe('Session identifier for grouping related guard events.'),
135
- input: z.unknown().optional().describe('Tool input. Hashed and never stored raw; redacted metadata is only stored when retain_details is true.'),
136
- output: z.unknown().optional().describe('Tool output. Same redaction and storage policy as input.'),
137
- outcome: z.enum(['succeeded', 'failed', 'blocked', 'skipped', 'unknown']).optional().describe('Outcome classification'),
138
- error_summary: z.string().optional().describe('Short error description if the action failed. Redacted and truncated to 2 KB.'),
248
+ tool: z
249
+ .string()
250
+ .optional()
251
+ .describe('Tool or command family that completed, e.g. Bash, npm test, Edit, deploy.'),
252
+ session_id: z
253
+ .string()
254
+ .optional()
255
+ .describe('Session identifier for grouping related guard events.'),
256
+ input: z
257
+ .unknown()
258
+ .optional()
259
+ .describe('Tool input. Hashed and never stored raw; redacted metadata is only stored when retain_details is true.'),
260
+ output: z
261
+ .unknown()
262
+ .optional()
263
+ .describe('Tool output. Same redaction and storage policy as input.'),
264
+ outcome: z
265
+ .enum(['succeeded', 'failed', 'blocked', 'skipped', 'unknown'])
266
+ .optional()
267
+ .describe('Outcome classification'),
268
+ error_summary: z
269
+ .string()
270
+ .optional()
271
+ .describe('Short error description if the action failed. Redacted and truncated to 2 KB.'),
139
272
  cwd: z.string().optional().describe('Working directory at the time of the action.'),
140
- files: z.array(z.string()).optional().describe('File paths to fingerprint (size + mtime + content hash).'),
141
- metadata: z.record(z.string(), z.unknown()).optional().describe('Arbitrary structured metadata (redacted before storage).'),
142
- retain_details: z.boolean().optional().describe('If true, redacted input and output payloads are stored alongside hashes. Defaults to false.'),
143
- evidence_feedback: z.record(z.string(), z.enum(['used', 'helpful', 'wrong'])).optional().describe('Map of evidence ids from the guard receipt to memory validation outcomes.'),
273
+ files: z
274
+ .array(z.string())
275
+ .optional()
276
+ .describe('File paths to fingerprint (size + mtime + content hash).'),
277
+ metadata: z
278
+ .record(z.string(), z.unknown())
279
+ .optional()
280
+ .describe('Arbitrary structured metadata (redacted before storage).'),
281
+ retain_details: z
282
+ .boolean()
283
+ .optional()
284
+ .describe('If true, redacted input and output payloads are stored alongside hashes. Defaults to false.'),
285
+ evidence_feedback: z
286
+ .record(z.string(), z.enum(['used', 'helpful', 'wrong']))
287
+ .optional()
288
+ .describe('Map of evidence ids from the guard receipt to memory validation outcomes.'),
144
289
  };
145
290
  export const memoryReflexesToolSchema = {
146
291
  ...memoryPreflightToolSchema,
147
- include_preflight: z.boolean().optional().describe('If true, include the full underlying preflight report.'),
292
+ include_preflight: z
293
+ .boolean()
294
+ .optional()
295
+ .describe('If true, include the full underlying preflight report.'),
148
296
  };
149
297
  // ---------------------------------------------------------------------------
150
298
  // CLI subcommands
@@ -160,7 +308,9 @@ async function serveHttp() {
160
308
  if (apiKey) {
161
309
  console.error('[audrey-http] API key authentication enabled');
162
310
  }
163
- else if (server.hostname === '127.0.0.1' || server.hostname === '::1' || server.hostname === 'localhost') {
311
+ else if (server.hostname === '127.0.0.1' ||
312
+ server.hostname === '::1' ||
313
+ server.hostname === 'localhost') {
164
314
  console.error('[audrey-http] no API key set (loopback only — set AUDREY_API_KEY to enable network access)');
165
315
  }
166
316
  }
@@ -178,7 +328,9 @@ async function reembed() {
178
328
  try {
179
329
  await initializeEmbeddingProvider(audrey.embeddingProvider);
180
330
  const { reembedAll } = await import('../src/migrate.js');
181
- const counts = await reembedAll(audrey.db, audrey.embeddingProvider, { dropAndRecreate: dimensionsChanged });
331
+ const counts = await reembedAll(audrey.db, audrey.embeddingProvider, {
332
+ dropAndRecreate: dimensionsChanged,
333
+ });
182
334
  console.log(`Done. Re-embedded: ${counts.episodes} episodes, ${counts.semantics} semantics, ${counts.procedures} procedures`);
183
335
  }
184
336
  finally {
@@ -208,13 +360,13 @@ async function dream() {
208
360
  console.log(`[audrey] Embedding: ${embeddingLabel}`);
209
361
  const result = await audrey.dream();
210
362
  const health = audrey.memoryStatus();
211
- console.log(`[audrey] Consolidation: evaluated ${result.consolidation.episodesEvaluated} episodes, `
212
- + `found ${result.consolidation.clustersFound} clusters, extracted ${result.consolidation.principlesExtracted} principles `
213
- + `(${result.consolidation.semanticsCreated ?? 0} semantic, ${result.consolidation.proceduresCreated ?? 0} procedural)`);
214
- console.log(`[audrey] Decay: evaluated ${result.decay.totalEvaluated} memories, `
215
- + `${result.decay.transitionedToDormant} transitioned to dormant`);
216
- console.log(`[audrey] Final: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ${result.stats.procedural} procedural `
217
- + `| ${health.healthy ? 'healthy' : 'unhealthy'}`);
363
+ console.log(`[audrey] Consolidation: evaluated ${result.consolidation.episodesEvaluated} episodes, ` +
364
+ `found ${result.consolidation.clustersFound} clusters, extracted ${result.consolidation.principlesExtracted} principles ` +
365
+ `(${result.consolidation.semanticsCreated ?? 0} semantic, ${result.consolidation.proceduresCreated ?? 0} procedural)`);
366
+ console.log(`[audrey] Decay: evaluated ${result.decay.totalEvaluated} memories, ` +
367
+ `${result.decay.transitionedToDormant} transitioned to dormant`);
368
+ console.log(`[audrey] Final: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ${result.stats.procedural} procedural ` +
369
+ `| ${health.healthy ? 'healthy' : 'unhealthy'}`);
218
370
  console.log('[audrey] Dream complete.');
219
371
  }
220
372
  finally {
@@ -257,9 +409,9 @@ async function greeting() {
257
409
  }
258
410
  const storedDimensions = readStoredDimensions(dataDir);
259
411
  const resolvedEmbedding = resolveEmbeddingProvider(process.env, process.env['AUDREY_EMBEDDING_PROVIDER']);
260
- const canUseResolvedEmbedding = Boolean(contextArg)
261
- && storedDimensions !== null
262
- && storedDimensions === resolvedEmbedding.dimensions;
412
+ const canUseResolvedEmbedding = Boolean(contextArg) &&
413
+ storedDimensions !== null &&
414
+ storedDimensions === resolvedEmbedding.dimensions;
263
415
  const dimensions = storedDimensions || resolvedEmbedding.dimensions || 8;
264
416
  const audrey = new Audrey({
265
417
  dataDir,
@@ -272,28 +424,30 @@ async function greeting() {
272
424
  if (canUseResolvedEmbedding) {
273
425
  await initializeEmbeddingProvider(audrey.embeddingProvider);
274
426
  }
275
- const result = await audrey.greeting({ context: canUseResolvedEmbedding ? contextArg : undefined });
427
+ const result = await audrey.greeting({
428
+ context: canUseResolvedEmbedding ? contextArg : undefined,
429
+ });
276
430
  const health = audrey.memoryStatus();
277
431
  const lines = [];
278
432
  lines.push(`[Audrey v${VERSION}] Memory briefing`);
279
433
  lines.push('');
280
434
  if (contextArg && !canUseResolvedEmbedding) {
281
- lines.push(`Context recall skipped: stored index is ${storedDimensions ?? 'unknown'}d `
282
- + `but current embedding config resolves to ${resolvedEmbedding.dimensions}d.`);
435
+ lines.push(`Context recall skipped: stored index is ${storedDimensions ?? 'unknown'}d ` +
436
+ `but current embedding config resolves to ${resolvedEmbedding.dimensions}d.`);
283
437
  lines.push('');
284
438
  }
285
439
  // Mood
286
440
  if (result.mood && result.mood.samples > 0) {
287
441
  const v = result.mood.valence;
288
442
  const moodWord = v > 0.3 ? 'positive' : v < -0.3 ? 'negative' : 'neutral';
289
- lines.push(`Mood: ${moodWord} (valence=${v.toFixed(2)}, `
290
- + `arousal=${result.mood.arousal.toFixed(2)}, `
291
- + `from ${result.mood.samples} recent memories)`);
443
+ lines.push(`Mood: ${moodWord} (valence=${v.toFixed(2)}, ` +
444
+ `arousal=${result.mood.arousal.toFixed(2)}, ` +
445
+ `from ${result.mood.samples} recent memories)`);
292
446
  }
293
447
  // Health
294
448
  const stats = audrey.introspect();
295
- lines.push(`Memory: ${stats.episodic} episodic, ${stats.semantic} semantic, `
296
- + `${stats.procedural} procedural | ${health.healthy ? 'healthy' : 'needs attention'}`);
449
+ lines.push(`Memory: ${stats.episodic} episodic, ${stats.semantic} semantic, ` +
450
+ `${stats.procedural} procedural | ${health.healthy ? 'healthy' : 'needs attention'}`);
297
451
  lines.push('');
298
452
  // Principles (semantic memories)
299
453
  if (result.principles?.length > 0) {
@@ -398,12 +552,12 @@ async function reflect() {
398
552
  // Always run dream cycle after reflect
399
553
  console.log('[audrey] Starting dream cycle...');
400
554
  const result = await audrey.dream();
401
- console.log(`[audrey] Consolidation: ${result.consolidation.episodesEvaluated} episodes evaluated, `
402
- + `${result.consolidation.clustersFound} clusters, ${result.consolidation.principlesExtracted} principles`);
403
- console.log(`[audrey] Decay: ${result.decay.totalEvaluated} evaluated, `
404
- + `${result.decay.transitionedToDormant} dormant`);
405
- console.log(`[audrey] Status: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, `
406
- + `${result.stats.procedural} procedural`);
555
+ console.log(`[audrey] Consolidation: ${result.consolidation.episodesEvaluated} episodes evaluated, ` +
556
+ `${result.consolidation.clustersFound} clusters, ${result.consolidation.principlesExtracted} principles`);
557
+ console.log(`[audrey] Decay: ${result.decay.totalEvaluated} evaluated, ` +
558
+ `${result.decay.transitionedToDormant} dormant`);
559
+ console.log(`[audrey] Status: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ` +
560
+ `${result.stats.procedural} procedural`);
407
561
  console.log('[audrey] Dream complete.');
408
562
  }
409
563
  finally {
@@ -449,11 +603,7 @@ export function formatInstallGuide(host, env = process.env, dryRun = false) {
449
603
  formatMcpHostConfig(normalizedHost, env),
450
604
  '',
451
605
  ...(normalizedHost === 'claude-code'
452
- ? [
453
- 'Generated Claude Code hook config:',
454
- formatClaudeCodeHookConfig(),
455
- '',
456
- ]
606
+ ? ['Generated Claude Code hook config:', formatClaudeCodeHookConfig(), '']
457
607
  : []),
458
608
  'Next steps:',
459
609
  ];
@@ -643,8 +793,12 @@ function printHookConfig() {
643
793
  dryRun: options.dryRun,
644
794
  });
645
795
  const action = result.dryRun
646
- ? result.changed ? 'would update' : 'would leave unchanged'
647
- : result.changed ? 'updated' : 'already up to date';
796
+ ? result.changed
797
+ ? 'would update'
798
+ : 'would leave unchanged'
799
+ : result.changed
800
+ ? 'updated'
801
+ : 'already up to date';
648
802
  console.log(`[audrey] Claude Code hook settings ${action}: ${result.settingsPath}`);
649
803
  if (result.backupPath)
650
804
  console.log(`[audrey] backup written: ${result.backupPath}`);
@@ -826,7 +980,9 @@ export function applyClaudeCodeHookConfig(options) {
826
980
  }
827
981
  catch (err) {
828
982
  const message = err instanceof Error ? err.message : String(err);
829
- throw new Error(`Cannot merge Audrey hooks into invalid JSON at ${settingsPath}: ${message}`);
983
+ throw new Error(`Cannot merge Audrey hooks into invalid JSON at ${settingsPath}: ${message}`, {
984
+ cause: err,
985
+ });
830
986
  }
831
987
  }
832
988
  const settings = mergeClaudeCodeHookSettings(existing);
@@ -875,11 +1031,7 @@ function demoScenario(argv = process.argv) {
875
1031
  return cliValue('--scenario', argv);
876
1032
  }
877
1033
  function formatControllerGuardResult(result) {
878
- const label = result.decision === 'block'
879
- ? 'BLOCKED'
880
- : result.decision === 'warn'
881
- ? 'WARN'
882
- : 'ALLOW';
1034
+ const label = result.decision === 'block' ? 'BLOCKED' : result.decision === 'warn' ? 'WARN' : 'ALLOW';
883
1035
  const lines = [];
884
1036
  lines.push(`Audrey Guard: ${label}`);
885
1037
  lines.push('');
@@ -992,8 +1144,8 @@ export async function runDemoCommand({ out = console.log, keep = process.argv.in
992
1144
  tags: ['procedure', 'memory-capsule', 'agent-loop'],
993
1145
  }));
994
1146
  ids.push(await audrey.encode({
995
- content: 'If a host cannot auto-install Audrey, run npx audrey mcp-config codex '
996
- + 'or npx audrey mcp-config generic and paste the generated config.',
1147
+ content: 'If a host cannot auto-install Audrey, run npx audrey mcp-config codex ' +
1148
+ 'or npx audrey mcp-config generic and paste the generated config.',
997
1149
  source: 'direct-observation',
998
1150
  tags: ['procedure', 'mcp', 'first-contact'],
999
1151
  }));
@@ -1011,8 +1163,8 @@ export async function runDemoCommand({ out = console.log, keep = process.argv.in
1011
1163
  event: 'PostToolUse',
1012
1164
  tool: 'npm test',
1013
1165
  outcome: 'failed',
1014
- errorSummary: 'Vitest can fail with spawn EPERM on locked-down Windows hosts; '
1015
- + 'use build, typecheck, benchmarks, and direct dist smokes as the fallback evidence path.',
1166
+ errorSummary: 'Vitest can fail with spawn EPERM on locked-down Windows hosts; ' +
1167
+ 'use build, typecheck, benchmarks, and direct dist smokes as the fallback evidence path.',
1016
1168
  cwd: process.cwd(),
1017
1169
  metadata: { demo: true, source: 'audrey demo' },
1018
1170
  });
@@ -1118,12 +1270,15 @@ export function buildStatusReport({ dataDir = resolveDataDir(process.env), claud
1118
1270
  });
1119
1271
  report.stats = audrey.introspect();
1120
1272
  report.health = audrey.memoryStatus();
1121
- report.lastConsolidation = audrey.db.prepare(`
1273
+ report.lastConsolidation =
1274
+ audrey.db
1275
+ .prepare(`
1122
1276
  SELECT completed_at FROM consolidation_runs
1123
1277
  WHERE status = 'completed'
1124
1278
  ORDER BY completed_at DESC
1125
1279
  LIMIT 1
1126
- `).get()?.completed_at ?? 'never';
1280
+ `)
1281
+ .get()?.completed_at ?? 'never';
1127
1282
  audrey.close();
1128
1283
  }
1129
1284
  catch (err) {
@@ -1145,11 +1300,11 @@ export function formatStatusReport(report) {
1145
1300
  lines.push(`Data directory: ${report.dataDir}`);
1146
1301
  lines.push(`Stored dimensions: ${report.storedDimensions ?? 'unknown'}`);
1147
1302
  lines.push(`Memories: ${report.stats.episodic} episodic, ${report.stats.semantic} semantic, ${report.stats.procedural} procedural`);
1148
- lines.push(`Index sync: ${report.health.vec_episodes}/${report.health.searchable_episodes} episodic, `
1149
- + `${report.health.vec_semantics}/${report.health.searchable_semantics} semantic, `
1150
- + `${report.health.vec_procedures}/${report.health.searchable_procedures} procedural`);
1151
- lines.push(`Health: ${report.health.healthy ? 'healthy' : 'unhealthy'}`
1152
- + `${report.health.reembed_recommended ? ' (re-embed recommended)' : ''}`);
1303
+ lines.push(`Index sync: ${report.health.vec_episodes}/${report.health.searchable_episodes} episodic, ` +
1304
+ `${report.health.vec_semantics}/${report.health.searchable_semantics} semantic, ` +
1305
+ `${report.health.vec_procedures}/${report.health.searchable_procedures} procedural`);
1306
+ lines.push(`Health: ${report.health.healthy ? 'healthy' : 'unhealthy'}` +
1307
+ `${report.health.reembed_recommended ? ' (re-embed recommended)' : ''}`);
1153
1308
  lines.push(`Dormant: ${report.stats.dormant}`);
1154
1309
  lines.push(`Causal links: ${report.stats.causalLinks}`);
1155
1310
  lines.push(`Contradictions: ${report.stats.contradictions.open} open, ${report.stats.contradictions.resolved} resolved`);
@@ -1165,8 +1320,11 @@ export function runStatusCommand({ argv = process.argv, dataDir = resolveDataDir
1165
1320
  else {
1166
1321
  out(formatStatusReport(report));
1167
1322
  }
1168
- const exitCode = report.error
1169
- || (cliHasFlag('--fail-on-unhealthy', argv) && report.exists && report.health && !report.health.healthy)
1323
+ const exitCode = report.error ||
1324
+ (cliHasFlag('--fail-on-unhealthy', argv) &&
1325
+ report.exists &&
1326
+ report.health &&
1327
+ !report.health.healthy)
1170
1328
  ? 1
1171
1329
  : 0;
1172
1330
  return { report, exitCode };
@@ -1319,23 +1477,30 @@ function toolResult(data, diagnostics) {
1319
1477
  return result;
1320
1478
  }
1321
1479
  function toolError(err) {
1322
- return { isError: true, content: [{ type: 'text', text: `Error: ${err.message || String(err)}` }] };
1480
+ return {
1481
+ isError: true,
1482
+ content: [{ type: 'text', text: `Error: ${err.message || String(err)}` }],
1483
+ };
1323
1484
  }
1324
1485
  function jsonResource(uri, data) {
1325
1486
  return {
1326
- contents: [{
1487
+ contents: [
1488
+ {
1327
1489
  uri: uri.toString(),
1328
1490
  mimeType: 'application/json',
1329
1491
  text: JSON.stringify(data, null, 2),
1330
- }],
1492
+ },
1493
+ ],
1331
1494
  };
1332
1495
  }
1333
1496
  function promptText(text) {
1334
1497
  return {
1335
- messages: [{
1498
+ messages: [
1499
+ {
1336
1500
  role: 'user',
1337
1501
  content: { type: 'text', text },
1338
- }],
1502
+ },
1503
+ ],
1339
1504
  };
1340
1505
  }
1341
1506
  export function registerShutdownHandlers(processRef, audrey, logger = console.error) {
@@ -1350,8 +1515,8 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
1350
1515
  if (typeof audrey.drainPostEncodeQueue === 'function') {
1351
1516
  const drain = await audrey.drainPostEncodeQueue(5000);
1352
1517
  if (!drain.drained && drain.pendingIds.length > 0) {
1353
- logger(`[audrey-mcp] post-encode queue did not drain within 5000ms; `
1354
- + `pending ids: ${drain.pendingIds.join(', ')}`);
1518
+ logger(`[audrey-mcp] post-encode queue did not drain within 5000ms; ` +
1519
+ `pending ids: ${drain.pendingIds.join(', ')}`);
1355
1520
  }
1356
1521
  }
1357
1522
  audrey.close();
@@ -1365,9 +1530,15 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
1365
1530
  processRef.exit(exitCode);
1366
1531
  }
1367
1532
  };
1368
- processRef.once('SIGINT', () => { void shutdown('[audrey-mcp] received SIGINT, shutting down'); });
1369
- processRef.once('SIGTERM', () => { void shutdown('[audrey-mcp] received SIGTERM, shutting down'); });
1370
- processRef.once('SIGHUP', () => { void shutdown('[audrey-mcp] received SIGHUP, shutting down'); });
1533
+ processRef.once('SIGINT', () => {
1534
+ void shutdown('[audrey-mcp] received SIGINT, shutting down');
1535
+ });
1536
+ processRef.once('SIGTERM', () => {
1537
+ void shutdown('[audrey-mcp] received SIGTERM, shutting down');
1538
+ });
1539
+ processRef.once('SIGHUP', () => {
1540
+ void shutdown('[audrey-mcp] received SIGHUP, shutting down');
1541
+ });
1371
1542
  processRef.once('uncaughtException', (err) => {
1372
1543
  logger('[audrey-mcp] uncaught exception:', err);
1373
1544
  void shutdown(undefined, 1);
@@ -1381,13 +1552,20 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
1381
1552
  });
1382
1553
  return (message, exitCode = 0) => shutdown(message, exitCode);
1383
1554
  }
1384
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1385
1555
  export function registerDreamTool(server, audrey) {
1386
1556
  server.tool('memory_dream', {
1387
1557
  min_cluster_size: z.number().optional().describe('Minimum episodes per cluster (default 3)'),
1388
- similarity_threshold: z.number().optional().describe('Similarity threshold for clustering (default 0.85)'),
1389
- dormant_threshold: z.number().min(0).max(1).optional().describe('Confidence below which memories go dormant (default 0.1)'),
1390
- }, async ({ min_cluster_size, similarity_threshold, dormant_threshold }) => {
1558
+ similarity_threshold: z
1559
+ .number()
1560
+ .optional()
1561
+ .describe('Similarity threshold for clustering (default 0.85)'),
1562
+ dormant_threshold: z
1563
+ .number()
1564
+ .min(0)
1565
+ .max(1)
1566
+ .optional()
1567
+ .describe('Confidence below which memories go dormant (default 0.1)'),
1568
+ }, async ({ min_cluster_size, similarity_threshold, dormant_threshold, }) => {
1391
1569
  try {
1392
1570
  const result = await audrey.dream({
1393
1571
  minClusterSize: min_cluster_size,
@@ -1401,7 +1579,6 @@ export function registerDreamTool(server, audrey) {
1401
1579
  }
1402
1580
  });
1403
1581
  }
1404
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1405
1582
  export function registerHostResources(server, audrey) {
1406
1583
  server.registerResource('audrey-status', 'audrey://status', {
1407
1584
  title: 'Audrey Status',
@@ -1448,7 +1625,6 @@ export function registerHostResources(server, audrey) {
1448
1625
  });
1449
1626
  });
1450
1627
  }
1451
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1452
1628
  export function registerHostPrompts(server) {
1453
1629
  server.registerPrompt('audrey-session-briefing', {
1454
1630
  title: 'Audrey Session Briefing',
@@ -1476,13 +1652,18 @@ export function registerHostPrompts(server) {
1476
1652
  title: 'Audrey Memory Reflection',
1477
1653
  description: 'Reflect at the end of a meaningful session and encode durable lessons.',
1478
1654
  argsSchema: {
1479
- summary: z.string().optional().describe('Optional compact summary of the session to reflect on.'),
1655
+ summary: z
1656
+ .string()
1657
+ .optional()
1658
+ .describe('Optional compact summary of the session to reflect on.'),
1480
1659
  },
1481
1660
  }, ({ summary }) => promptText([
1482
1661
  'Call memory_reflect with the important user and assistant turns from this session.',
1483
1662
  'Encode only durable preferences, decisions, fixes, failures, and project facts that should affect future work.',
1484
1663
  summary ? `Session summary hint: ${summary}` : undefined,
1485
- ].filter(Boolean).join('\n')));
1664
+ ]
1665
+ .filter(Boolean)
1666
+ .join('\n')));
1486
1667
  }
1487
1668
  async function main() {
1488
1669
  const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
@@ -1626,7 +1807,10 @@ async function main() {
1626
1807
  purge: purge ?? false,
1627
1808
  });
1628
1809
  if (!result) {
1629
- return toolResult({ forgotten: false, reason: 'No memory found above similarity threshold' });
1810
+ return toolResult({
1811
+ forgotten: false,
1812
+ reason: 'No memory found above similarity threshold',
1813
+ });
1630
1814
  }
1631
1815
  }
1632
1816
  return toolResult({ forgotten: true, ...result });
@@ -1647,7 +1831,12 @@ async function main() {
1647
1831
  }
1648
1832
  });
1649
1833
  server.tool('memory_decay', {
1650
- dormant_threshold: z.number().min(0).max(1).optional().describe('Confidence below which memories go dormant (default 0.1)'),
1834
+ dormant_threshold: z
1835
+ .number()
1836
+ .min(0)
1837
+ .max(1)
1838
+ .optional()
1839
+ .describe('Confidence below which memories go dormant (default 0.1)'),
1651
1840
  }, async ({ dormant_threshold }) => {
1652
1841
  try {
1653
1842
  return toolResult(audrey.decay({ dormantThreshold: dormant_threshold }));
@@ -1665,10 +1854,12 @@ async function main() {
1665
1854
  }
1666
1855
  });
1667
1856
  server.tool('memory_reflect', {
1668
- turns: z.array(z.object({
1857
+ turns: z
1858
+ .array(z.object({
1669
1859
  role: z.string().describe('Message role: user or assistant'),
1670
1860
  content: z.string().describe('Message content'),
1671
- })).describe('Conversation turns to reflect on. Call at end of meaningful conversations to form lasting memories.'),
1861
+ }))
1862
+ .describe('Conversation turns to reflect on. Call at end of meaningful conversations to form lasting memories.'),
1672
1863
  }, async ({ turns }) => {
1673
1864
  try {
1674
1865
  return toolResult(await audrey.reflect(turns));
@@ -1679,8 +1870,14 @@ async function main() {
1679
1870
  });
1680
1871
  registerDreamTool(server, audrey);
1681
1872
  server.tool('memory_greeting', {
1682
- context: z.string().optional().describe('Optional hint about this session. When provided, Audrey also returns semantically relevant memories.'),
1683
- scope: z.enum(['agent', 'shared']).optional().describe('agent keeps greeting scoped to this server agent identity. shared includes the whole store. Defaults to agent.'),
1873
+ context: z
1874
+ .string()
1875
+ .optional()
1876
+ .describe('Optional hint about this session. When provided, Audrey also returns semantically relevant memories.'),
1877
+ scope: z
1878
+ .enum(['agent', 'shared'])
1879
+ .optional()
1880
+ .describe('agent keeps greeting scoped to this server agent identity. shared includes the whole store. Defaults to agent.'),
1684
1881
  }, async ({ context, scope }) => {
1685
1882
  try {
1686
1883
  return toolResult(await audrey.greeting({ context, scope: scope ?? 'agent' }));
@@ -1690,17 +1887,40 @@ async function main() {
1690
1887
  }
1691
1888
  });
1692
1889
  server.tool('memory_observe_tool', {
1693
- event: z.string().describe('Hook event name (PreToolUse, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, etc.)'),
1890
+ event: z
1891
+ .string()
1892
+ .describe('Hook event name (PreToolUse, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, etc.)'),
1694
1893
  tool: z.string().describe('Tool name being observed (Bash, Edit, Write, etc.)'),
1695
1894
  session_id: z.string().optional().describe('Session identifier for grouping related events'),
1696
- input: z.unknown().optional().describe('Tool input. Hashed and never stored raw; redacted metadata is only stored when retain_details is true.'),
1697
- output: z.unknown().optional().describe('Tool output. Same redaction and storage policy as input.'),
1698
- outcome: z.enum(['succeeded', 'failed', 'blocked', 'skipped', 'unknown']).optional().describe('Outcome classification'),
1699
- error_summary: z.string().optional().describe('Short error description if the tool failed. Redacted and truncated to 2 KB.'),
1895
+ input: z
1896
+ .unknown()
1897
+ .optional()
1898
+ .describe('Tool input. Hashed and never stored raw; redacted metadata is only stored when retain_details is true.'),
1899
+ output: z
1900
+ .unknown()
1901
+ .optional()
1902
+ .describe('Tool output. Same redaction and storage policy as input.'),
1903
+ outcome: z
1904
+ .enum(['succeeded', 'failed', 'blocked', 'skipped', 'unknown'])
1905
+ .optional()
1906
+ .describe('Outcome classification'),
1907
+ error_summary: z
1908
+ .string()
1909
+ .optional()
1910
+ .describe('Short error description if the tool failed. Redacted and truncated to 2 KB.'),
1700
1911
  cwd: z.string().optional().describe('Working directory at the time of the tool call'),
1701
- files: z.array(z.string()).optional().describe('File paths to fingerprint (size + mtime + content hash)'),
1702
- metadata: z.record(z.string(), z.unknown()).optional().describe('Arbitrary structured metadata (redacted before storage)'),
1703
- retain_details: z.boolean().optional().describe('If true, redacted input and output payloads are stored alongside hashes. Defaults to false.'),
1912
+ files: z
1913
+ .array(z.string())
1914
+ .optional()
1915
+ .describe('File paths to fingerprint (size + mtime + content hash)'),
1916
+ metadata: z
1917
+ .record(z.string(), z.unknown())
1918
+ .optional()
1919
+ .describe('Arbitrary structured metadata (redacted before storage)'),
1920
+ retain_details: z
1921
+ .boolean()
1922
+ .optional()
1923
+ .describe('If true, redacted input and output payloads are stored alongside hashes. Defaults to false.'),
1704
1924
  }, async ({ event, tool, session_id, input, output, outcome, error_summary, cwd, files, metadata, retain_details, }) => {
1705
1925
  try {
1706
1926
  const result = audrey.observeTool({
@@ -1732,7 +1952,13 @@ async function main() {
1732
1952
  });
1733
1953
  server.tool('memory_recent_failures', {
1734
1954
  since: z.string().optional().describe('ISO timestamp lower bound (defaults to 7 days ago)'),
1735
- limit: z.number().int().min(1).max(200).optional().describe('Max rows to return (defaults to 20)'),
1955
+ limit: z
1956
+ .number()
1957
+ .int()
1958
+ .min(1)
1959
+ .max(200)
1960
+ .optional()
1961
+ .describe('Max rows to return (defaults to 20)'),
1736
1962
  }, async ({ since, limit }) => {
1737
1963
  try {
1738
1964
  return toolResult(audrey.recentFailures({ since, limit }));
@@ -1743,13 +1969,43 @@ async function main() {
1743
1969
  });
1744
1970
  server.tool('memory_capsule', {
1745
1971
  query: z.string().describe('Natural-language query for the turn. Drives what gets surfaced.'),
1746
- limit: z.number().int().min(1).max(50).optional().describe('Max recall results to consider before categorization.'),
1747
- budget_chars: z.number().int().min(200).max(32000).optional().describe('Token budget in characters (defaults to AUDREY_CONTEXT_BUDGET_CHARS or 4000).'),
1748
- mode: z.enum(['balanced', 'conservative', 'aggressive']).optional().describe('Capsule mode: conservative = fewer, higher-confidence entries; aggressive = broader sweep.'),
1749
- recent_change_window_hours: z.number().int().min(1).max(720).optional().describe('How far back "recent_changes" looks (default 24h).'),
1750
- include_risks: z.boolean().optional().describe('Include recent tool failures as risks (default true).'),
1751
- include_contradictions: z.boolean().optional().describe('Include open contradictions (default true).'),
1752
- scope: z.enum(['agent', 'shared']).optional().describe('agent restricts memory recall to this MCP server agent identity. shared searches the whole store. Defaults to agent.'),
1972
+ limit: z
1973
+ .number()
1974
+ .int()
1975
+ .min(1)
1976
+ .max(50)
1977
+ .optional()
1978
+ .describe('Max recall results to consider before categorization.'),
1979
+ budget_chars: z
1980
+ .number()
1981
+ .int()
1982
+ .min(200)
1983
+ .max(32000)
1984
+ .optional()
1985
+ .describe('Token budget in characters (defaults to AUDREY_CONTEXT_BUDGET_CHARS or 4000).'),
1986
+ mode: z
1987
+ .enum(['balanced', 'conservative', 'aggressive'])
1988
+ .optional()
1989
+ .describe('Capsule mode: conservative = fewer, higher-confidence entries; aggressive = broader sweep.'),
1990
+ recent_change_window_hours: z
1991
+ .number()
1992
+ .int()
1993
+ .min(1)
1994
+ .max(720)
1995
+ .optional()
1996
+ .describe('How far back "recent_changes" looks (default 24h).'),
1997
+ include_risks: z
1998
+ .boolean()
1999
+ .optional()
2000
+ .describe('Include recent tool failures as risks (default true).'),
2001
+ include_contradictions: z
2002
+ .boolean()
2003
+ .optional()
2004
+ .describe('Include open contradictions (default true).'),
2005
+ scope: z
2006
+ .enum(['agent', 'shared'])
2007
+ .optional()
2008
+ .describe('agent restricts memory recall to this MCP server agent identity. shared searches the whole store. Defaults to agent.'),
1753
2009
  }, async ({ query, limit, budget_chars, mode, recent_change_window_hours, include_risks, include_contradictions, scope, }) => {
1754
2010
  try {
1755
2011
  const capsule = await audrey.capsule(query, {
@@ -1860,14 +2116,42 @@ async function main() {
1860
2116
  }
1861
2117
  });
1862
2118
  server.tool('memory_promote', {
1863
- target: z.enum(['claude-rules']).optional().describe('Promotion target. Only claude-rules is implemented in PR 4 v1.'),
1864
- min_confidence: z.number().min(0).max(1).optional().describe('Minimum memory confidence for promotion (default 0.7 for procedural, 0.8 for semantic).'),
1865
- min_evidence: z.number().int().min(1).optional().describe('Minimum supporting episode count (default 2).'),
1866
- limit: z.number().int().min(1).max(50).optional().describe('Max candidates to return/apply (default 20).'),
1867
- dry_run: z.boolean().optional().describe('If true (default), return candidates without writing. Pair with yes=true to actually write.'),
1868
- yes: z.boolean().optional().describe('Confirm write. Without this or dry_run=false the command stays in dry-run mode.'),
1869
- project_dir: z.string().optional().describe('Absolute path to the project root where .claude/rules/ should be created. Defaults to process.cwd().'),
1870
- }, async ({ target, min_confidence, min_evidence, limit, dry_run, yes, project_dir, }) => {
2119
+ target: z
2120
+ .enum(['claude-rules'])
2121
+ .optional()
2122
+ .describe('Promotion target. Only claude-rules is implemented in PR 4 v1.'),
2123
+ min_confidence: z
2124
+ .number()
2125
+ .min(0)
2126
+ .max(1)
2127
+ .optional()
2128
+ .describe('Minimum memory confidence for promotion (default 0.7 for procedural, 0.8 for semantic).'),
2129
+ min_evidence: z
2130
+ .number()
2131
+ .int()
2132
+ .min(1)
2133
+ .optional()
2134
+ .describe('Minimum supporting episode count (default 2).'),
2135
+ limit: z
2136
+ .number()
2137
+ .int()
2138
+ .min(1)
2139
+ .max(50)
2140
+ .optional()
2141
+ .describe('Max candidates to return/apply (default 20).'),
2142
+ dry_run: z
2143
+ .boolean()
2144
+ .optional()
2145
+ .describe('If true (default), return candidates without writing. Pair with yes=true to actually write.'),
2146
+ yes: z
2147
+ .boolean()
2148
+ .optional()
2149
+ .describe('Confirm write. Without this or dry_run=false the command stays in dry-run mode.'),
2150
+ project_dir: z
2151
+ .string()
2152
+ .optional()
2153
+ .describe('Absolute path to the project root where .claude/rules/ should be created. Defaults to process.cwd().'),
2154
+ }, async ({ target, min_confidence, min_evidence, limit, dry_run, yes, project_dir }) => {
1871
2155
  try {
1872
2156
  const result = await audrey.promote({
1873
2157
  target,
@@ -1890,7 +2174,8 @@ async function main() {
1890
2174
  console.error('[audrey-mcp] connected via stdio');
1891
2175
  }
1892
2176
  if (!isEmbeddingWarmupDisabled(process.env)) {
1893
- void audrey.startEmbeddingWarmup()
2177
+ void audrey
2178
+ .startEmbeddingWarmup()
1894
2179
  .then(() => {
1895
2180
  if (process.env.AUDREY_DEBUG === '1') {
1896
2181
  const status = audrey.memoryStatus();
@@ -1925,7 +2210,10 @@ function parseObserveToolArgs(argv) {
1925
2210
  else if (token === '--files') {
1926
2211
  const list = next();
1927
2212
  if (list)
1928
- out.files = list.split(',').map(s => s.trim()).filter(Boolean);
2213
+ out.files = list
2214
+ .split(',')
2215
+ .map(s => s.trim())
2216
+ .filter(Boolean);
1929
2217
  }
1930
2218
  else if (token === '--input-json')
1931
2219
  out.inputJson = next();
@@ -1980,13 +2268,11 @@ async function observeToolCli() {
1980
2268
  };
1981
2269
  const inputPayload = args.inputJson !== undefined
1982
2270
  ? parseMaybeJson(args.inputJson)
1983
- : stdinPayload?.tool_input ?? stdinPayload?.input;
2271
+ : (stdinPayload?.tool_input ?? stdinPayload?.input);
1984
2272
  const outputPayload = args.outputJson !== undefined
1985
2273
  ? parseMaybeJson(args.outputJson)
1986
- : stdinPayload?.tool_response ?? stdinPayload?.tool_output ?? stdinPayload?.output;
1987
- const metadataPayload = args.metadataJson !== undefined
1988
- ? parseMaybeJson(args.metadataJson)
1989
- : stdinPayload?.metadata;
2274
+ : (stdinPayload?.tool_response ?? stdinPayload?.tool_output ?? stdinPayload?.output);
2275
+ const metadataPayload = args.metadataJson !== undefined ? parseMaybeJson(args.metadataJson) : stdinPayload?.metadata;
1990
2276
  const sessionId = args.sessionId ?? stdinPayload?.session_id;
1991
2277
  const cwd = args.cwd ?? stdinPayload?.cwd;
1992
2278
  // Detect failure from Claude Code hook payload shape: tool_response often
@@ -2124,7 +2410,7 @@ function guardDisplayDecision(result) {
2124
2410
  return 'allow';
2125
2411
  }
2126
2412
  function summarizeToolInput(payload, tool) {
2127
- const input = (payload.tool_input && typeof payload.tool_input === 'object')
2413
+ const input = payload.tool_input && typeof payload.tool_input === 'object'
2128
2414
  ? payload.tool_input
2129
2415
  : {};
2130
2416
  const command = typeof input.command === 'string' ? input.command : undefined;
@@ -2139,9 +2425,7 @@ function summarizeToolInput(payload, tool) {
2139
2425
  return { action: `${tool}: ${description}`, files };
2140
2426
  const compactInput = JSON.stringify(input);
2141
2427
  return {
2142
- action: compactInput && compactInput !== '{}'
2143
- ? `${tool} ${compactInput}`
2144
- : `Use ${tool}`,
2428
+ action: compactInput && compactInput !== '{}' ? `${tool} ${compactInput}` : `Use ${tool}`,
2145
2429
  files,
2146
2430
  };
2147
2431
  }
@@ -2160,7 +2444,9 @@ function formatHookReason(result) {
2160
2444
  result.summary,
2161
2445
  recommendations.length > 0 ? `Recommended: ${recommendations.join(' ')}` : '',
2162
2446
  result.evidence_ids.length > 0 ? `Evidence: ${result.evidence_ids.slice(0, 5).join(', ')}` : '',
2163
- ].filter(Boolean).join('\n');
2447
+ ]
2448
+ .filter(Boolean)
2449
+ .join('\n');
2164
2450
  }
2165
2451
  function formatPreToolUseHookOutput(result, failOnWarn) {
2166
2452
  const decision = guardDisplayDecision(result);
@@ -2253,7 +2539,11 @@ async function guardCli() {
2253
2539
  tool: hookTool ?? args.tool,
2254
2540
  sessionId: args.sessionId ?? hookSessionId,
2255
2541
  cwd: args.cwd ?? hookCwd ?? process.cwd(),
2256
- files: args.files.length > 0 ? args.files : hookSummary?.files?.length ? hookSummary.files : undefined,
2542
+ files: args.files.length > 0
2543
+ ? args.files
2544
+ : hookSummary?.files?.length
2545
+ ? hookSummary.files
2546
+ : undefined,
2257
2547
  strict: args.strict || args.failOnWarn || args.hook,
2258
2548
  recordEvent: true,
2259
2549
  includeCapsule: args.includeCapsule || args.explain,
@@ -2268,7 +2558,9 @@ async function guardCli() {
2268
2558
  console.log(formatGuardDecision(result, { explain: args.explain }));
2269
2559
  }
2270
2560
  const display = guardDisplayDecision(result);
2271
- if (!args.hook && (display === 'block' || (args.failOnWarn && display === 'warn')) && !args.override) {
2561
+ if (!args.hook &&
2562
+ (display === 'block' || (args.failOnWarn && display === 'warn')) &&
2563
+ !args.override) {
2272
2564
  process.exitCode = 2;
2273
2565
  }
2274
2566
  }
@@ -2314,9 +2606,9 @@ async function readOptionalJsonFromStdin(command) {
2314
2606
  }
2315
2607
  }
2316
2608
  function inferGuardAfterOutcome(stdinPayload) {
2317
- const response = stdinPayload?.tool_response
2318
- ?? stdinPayload?.tool_output
2319
- ?? stdinPayload?.output;
2609
+ const response = stdinPayload?.tool_response ??
2610
+ stdinPayload?.tool_output ??
2611
+ stdinPayload?.output;
2320
2612
  const success = response?.success;
2321
2613
  if (typeof success === 'boolean')
2322
2614
  return success ? 'succeeded' : 'failed';
@@ -2433,8 +2725,8 @@ async function promoteCli() {
2433
2725
  const snippet = c.content.length > 120 ? c.content.slice(0, 117) + '...' : c.content;
2434
2726
  console.log(` memory: ${snippet}`);
2435
2727
  console.log(` why: ${c.reason}`);
2436
- console.log(` confidence=${(c.confidence * 100).toFixed(1)}% `
2437
- + `evidence=${c.evidence_count} prevented_failures=${c.failure_prevented}`);
2728
+ console.log(` confidence=${(c.confidence * 100).toFixed(1)}% ` +
2729
+ `evidence=${c.evidence_count} prevented_failures=${c.failure_prevented}`);
2438
2730
  }
2439
2731
  if (result.dry_run) {
2440
2732
  console.log('');
@@ -2454,11 +2746,26 @@ function canonicalEntryPath(path) {
2454
2746
  return resolved.toLowerCase();
2455
2747
  }
2456
2748
  }
2457
- const isDirectRun = Boolean(process.argv[1])
2458
- && canonicalEntryPath(process.argv[1]) === canonicalEntryPath(fileURLToPath(import.meta.url));
2749
+ const isDirectRun = Boolean(process.argv[1]) &&
2750
+ canonicalEntryPath(process.argv[1]) === canonicalEntryPath(fileURLToPath(import.meta.url));
2459
2751
  const KNOWN_SUBCOMMANDS = [
2460
- 'install', 'uninstall', 'mcp-config', 'hook-config', 'demo', 'reembed', 'dream',
2461
- 'greeting', 'reflect', 'serve', 'status', 'doctor', 'observe-tool', 'guard', 'guard-after', 'promote', 'impact',
2752
+ 'install',
2753
+ 'uninstall',
2754
+ 'mcp-config',
2755
+ 'hook-config',
2756
+ 'demo',
2757
+ 'reembed',
2758
+ 'dream',
2759
+ 'greeting',
2760
+ 'reflect',
2761
+ 'serve',
2762
+ 'status',
2763
+ 'doctor',
2764
+ 'observe-tool',
2765
+ 'guard',
2766
+ 'guard-after',
2767
+ 'promote',
2768
+ 'impact',
2462
2769
  ];
2463
2770
  function printHelp() {
2464
2771
  process.stdout.write(`audrey ${VERSION} — local-first memory runtime for AI agents