audrey 1.0.1 → 1.0.3

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 (235) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +13 -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 +12 -12
  18. package/benchmarks/output/guardbench-raw.json +106 -106
  19. package/benchmarks/output/guardbench-summary.json +168 -168
  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 +12 -12
  23. package/benchmarks/output/submission-bundle/guardbench-raw.json +106 -106
  24. package/benchmarks/output/submission-bundle/guardbench-summary.json +168 -168
  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 +58 -58
  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 +7 -347
  46. package/dist/mcp-server/index.d.ts.map +1 -1
  47. package/dist/mcp-server/index.js +289 -256
  48. package/dist/mcp-server/index.js.map +1 -1
  49. package/dist/mcp-server/tool-schemas.d.ts +341 -0
  50. package/dist/mcp-server/tool-schemas.d.ts.map +1 -0
  51. package/dist/mcp-server/tool-schemas.js +248 -0
  52. package/dist/mcp-server/tool-schemas.js.map +1 -0
  53. package/dist/mcp-server/tool-validation.d.ts +17 -0
  54. package/dist/mcp-server/tool-validation.d.ts.map +1 -0
  55. package/dist/mcp-server/tool-validation.js +41 -0
  56. package/dist/mcp-server/tool-validation.js.map +1 -0
  57. package/dist/src/action-key.d.ts.map +1 -1
  58. package/dist/src/action-key.js +6 -2
  59. package/dist/src/action-key.js.map +1 -1
  60. package/dist/src/adaptive.d.ts.map +1 -1
  61. package/dist/src/adaptive.js +4 -2
  62. package/dist/src/adaptive.js.map +1 -1
  63. package/dist/src/affect.d.ts.map +1 -1
  64. package/dist/src/affect.js +8 -5
  65. package/dist/src/affect.js.map +1 -1
  66. package/dist/src/audrey.d.ts +1 -1
  67. package/dist/src/audrey.d.ts.map +1 -1
  68. package/dist/src/audrey.js +93 -49
  69. package/dist/src/audrey.js.map +1 -1
  70. package/dist/src/capsule.d.ts.map +1 -1
  71. package/dist/src/capsule.js +37 -15
  72. package/dist/src/capsule.js.map +1 -1
  73. package/dist/src/causal.d.ts +1 -1
  74. package/dist/src/causal.d.ts.map +1 -1
  75. package/dist/src/causal.js +4 -2
  76. package/dist/src/causal.js.map +1 -1
  77. package/dist/src/confidence.d.ts.map +1 -1
  78. package/dist/src/confidence.js +5 -5
  79. package/dist/src/confidence.js.map +1 -1
  80. package/dist/src/consolidate.d.ts.map +1 -1
  81. package/dist/src/consolidate.js +17 -9
  82. package/dist/src/consolidate.js.map +1 -1
  83. package/dist/src/context.js +1 -1
  84. package/dist/src/context.js.map +1 -1
  85. package/dist/src/controller.d.ts.map +1 -1
  86. package/dist/src/controller.js +24 -13
  87. package/dist/src/controller.js.map +1 -1
  88. package/dist/src/db.d.ts.map +1 -1
  89. package/dist/src/db.js +78 -27
  90. package/dist/src/db.js.map +1 -1
  91. package/dist/src/decay.d.ts +1 -1
  92. package/dist/src/decay.d.ts.map +1 -1
  93. package/dist/src/decay.js +1 -1
  94. package/dist/src/decay.js.map +1 -1
  95. package/dist/src/embedding.d.ts +12 -4
  96. package/dist/src/embedding.d.ts.map +1 -1
  97. package/dist/src/embedding.js +18 -16
  98. package/dist/src/embedding.js.map +1 -1
  99. package/dist/src/encode.d.ts.map +1 -1
  100. package/dist/src/encode.js +5 -4
  101. package/dist/src/encode.js.map +1 -1
  102. package/dist/src/events.d.ts +3 -2
  103. package/dist/src/events.d.ts.map +1 -1
  104. package/dist/src/events.js +7 -3
  105. package/dist/src/events.js.map +1 -1
  106. package/dist/src/export.d.ts.map +1 -1
  107. package/dist/src/export.js +21 -7
  108. package/dist/src/export.js.map +1 -1
  109. package/dist/src/feedback.d.ts.map +1 -1
  110. package/dist/src/feedback.js +1 -1
  111. package/dist/src/feedback.js.map +1 -1
  112. package/dist/src/forget.d.ts.map +1 -1
  113. package/dist/src/forget.js +12 -6
  114. package/dist/src/forget.js.map +1 -1
  115. package/dist/src/fts.d.ts.map +1 -1
  116. package/dist/src/fts.js +20 -8
  117. package/dist/src/fts.js.map +1 -1
  118. package/dist/src/hybrid-recall.d.ts.map +1 -1
  119. package/dist/src/hybrid-recall.js +12 -6
  120. package/dist/src/hybrid-recall.js.map +1 -1
  121. package/dist/src/impact.d.ts.map +1 -1
  122. package/dist/src/impact.js +26 -10
  123. package/dist/src/impact.js.map +1 -1
  124. package/dist/src/import.d.ts.map +1 -1
  125. package/dist/src/import.js +11 -6
  126. package/dist/src/import.js.map +1 -1
  127. package/dist/src/index.d.ts +3 -3
  128. package/dist/src/index.d.ts.map +1 -1
  129. package/dist/src/index.js +3 -3
  130. package/dist/src/index.js.map +1 -1
  131. package/dist/src/interference.d.ts.map +1 -1
  132. package/dist/src/interference.js +10 -5
  133. package/dist/src/interference.js.map +1 -1
  134. package/dist/src/introspect.d.ts.map +1 -1
  135. package/dist/src/introspect.js +12 -6
  136. package/dist/src/introspect.js.map +1 -1
  137. package/dist/src/llm.d.ts +2 -2
  138. package/dist/src/llm.d.ts.map +1 -1
  139. package/dist/src/llm.js +6 -6
  140. package/dist/src/llm.js.map +1 -1
  141. package/dist/src/migrate.d.ts.map +1 -1
  142. package/dist/src/migrate.js +10 -4
  143. package/dist/src/migrate.js.map +1 -1
  144. package/dist/src/preflight.d.ts.map +1 -1
  145. package/dist/src/preflight.js +6 -8
  146. package/dist/src/preflight.js.map +1 -1
  147. package/dist/src/profile.d.ts.map +1 -1
  148. package/dist/src/profile.js.map +1 -1
  149. package/dist/src/promote.d.ts.map +1 -1
  150. package/dist/src/promote.js +16 -7
  151. package/dist/src/promote.js.map +1 -1
  152. package/dist/src/prompts.d.ts.map +1 -1
  153. package/dist/src/prompts.js +1 -2
  154. package/dist/src/prompts.js.map +1 -1
  155. package/dist/src/recall.d.ts.map +1 -1
  156. package/dist/src/recall.js +85 -18
  157. package/dist/src/recall.js.map +1 -1
  158. package/dist/src/redact.d.ts.map +1 -1
  159. package/dist/src/redact.js +9 -4
  160. package/dist/src/redact.js.map +1 -1
  161. package/dist/src/reflexes.d.ts.map +1 -1
  162. package/dist/src/reflexes.js +1 -7
  163. package/dist/src/reflexes.js.map +1 -1
  164. package/dist/src/rollback.d.ts.map +1 -1
  165. package/dist/src/rollback.js +4 -2
  166. package/dist/src/rollback.js.map +1 -1
  167. package/dist/src/routes.d.ts.map +1 -1
  168. package/dist/src/routes.js +33 -13
  169. package/dist/src/routes.js.map +1 -1
  170. package/dist/src/rules-compiler.d.ts.map +1 -1
  171. package/dist/src/rules-compiler.js +24 -2
  172. package/dist/src/rules-compiler.js.map +1 -1
  173. package/dist/src/server.js +2 -2
  174. package/dist/src/server.js.map +1 -1
  175. package/dist/src/tool-trace.d.ts +2 -2
  176. package/dist/src/tool-trace.d.ts.map +1 -1
  177. package/dist/src/tool-trace.js +12 -4
  178. package/dist/src/tool-trace.js.map +1 -1
  179. package/dist/src/types.d.ts.map +1 -1
  180. package/dist/src/ulid.js +1 -1
  181. package/dist/src/ulid.js.map +1 -1
  182. package/dist/src/utils.d.ts.map +1 -1
  183. package/dist/src/utils.js.map +1 -1
  184. package/dist/src/validate.d.ts.map +1 -1
  185. package/dist/src/validate.js +20 -10
  186. package/dist/src/validate.js.map +1 -1
  187. package/docs/paper/07-evaluation.md +5 -5
  188. package/docs/paper/audrey-paper-v1.md +5 -5
  189. package/docs/paper/evidence-ledger.md +1 -1
  190. package/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  191. package/docs/paper/output/arxiv/main.tex +5 -5
  192. package/docs/paper/output/arxiv-compile-report.json +3 -3
  193. package/docs/paper/output/submission-bundle/README.md +13 -3
  194. package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +4 -4
  195. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
  196. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +1 -1
  197. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +12 -12
  198. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +106 -106
  199. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +168 -168
  200. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
  201. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
  202. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +11 -11
  203. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +1 -1
  204. package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +64 -64
  205. package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +5 -5
  206. package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +5 -5
  207. package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +1 -1
  208. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  209. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +5 -5
  210. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +3 -3
  211. package/docs/paper/output/submission-bundle/package.json +17 -4
  212. package/docs/paper/output/submission-bundle/paper-submission-manifest.json +34 -34
  213. package/examples/fintech-ops-demo.js +12 -5
  214. package/examples/healthcare-ops-demo.js +8 -4
  215. package/examples/ollama-memory-agent.js +41 -13
  216. package/examples/stripe-demo.js +12 -5
  217. package/package.json +17 -4
  218. package/scripts/audit-release-completion.mjs +179 -101
  219. package/scripts/create-arxiv-source.mjs +20 -14
  220. package/scripts/create-paper-submission-bundle.mjs +6 -2
  221. package/scripts/finalize-release.mjs +111 -36
  222. package/scripts/prepare-release-cut.mjs +14 -6
  223. package/scripts/publish-release-bundle.mjs +62 -23
  224. package/scripts/publish-release-github-api.mjs +89 -24
  225. package/scripts/smoke-cli.js +9 -9
  226. package/scripts/sync-paper-artifacts.mjs +5 -1
  227. package/scripts/verify-arxiv-compile.mjs +52 -16
  228. package/scripts/verify-arxiv-source.mjs +45 -15
  229. package/scripts/verify-browser-launch-plan.mjs +28 -11
  230. package/scripts/verify-browser-launch-results.mjs +32 -14
  231. package/scripts/verify-paper-artifacts.mjs +539 -79
  232. package/scripts/verify-paper-claims.mjs +48 -20
  233. package/scripts/verify-paper-submission-bundle.mjs +22 -11
  234. package/scripts/verify-publication-pack.mjs +23 -9
  235. package/scripts/verify-release-readiness.mjs +211 -76
@@ -2,150 +2,24 @@
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';
9
9
  import { readStoredDimensions } from '../src/db.js';
10
- import { importSnapshotSchema } from '../src/import.js';
11
10
  import { isAudreyProfileEnabled } from '../src/profile.js';
12
11
  import { VERSION, SERVER_NAME, MCP_ENTRYPOINT, buildAudreyConfig, buildInstallArgs, formatMcpHostConfig, resolveDataDir, resolveEmbeddingProvider, resolveLLMProvider, } from './config.js';
13
- const VALID_SOURCES = [
14
- 'direct-observation',
15
- 'told-by-user',
16
- 'tool-result',
17
- 'inference',
18
- 'model-generated',
19
- ];
20
- const VALID_TYPES = ['episodic', 'semantic', 'procedural'];
21
- export const MAX_MEMORY_CONTENT_LENGTH = 50_000;
22
- export const ADMIN_TOOLS_ENV = 'AUDREY_ENABLE_ADMIN_TOOLS';
12
+ import { initializeEmbeddingProvider, requireAdminTools, validateForgetSelection, validateMemoryContent, } from './tool-validation.js';
13
+ import { memoryEncodeToolSchema, memoryForgetToolSchema, memoryGuardAfterToolSchema, memoryGuardBeforeToolSchema, memoryImportToolSchema, memoryPreflightToolSchema, memoryRecallToolSchema, memoryReflexesToolSchema, memoryValidateToolSchema, } from './tool-schemas.js';
14
+ // Re-export the tool-validation and tool-schema public surface so existing
15
+ // importers of `mcp-server/index.js` (tests, embedders) keep resolving.
16
+ export { ADMIN_TOOLS_ENV, MAX_MEMORY_CONTENT_LENGTH, initializeEmbeddingProvider, isAdminToolsEnabled, requireAdminTools, validateForgetSelection, validateMemoryContent, } from './tool-validation.js';
17
+ export * from './tool-schemas.js';
23
18
  const subcommand = (process.argv[2] || '').trim() || undefined;
24
- function isNonEmptyText(value) {
25
- return typeof value === 'string' && value.trim().length > 0;
26
- }
27
- export function validateMemoryContent(content) {
28
- if (!isNonEmptyText(content)) {
29
- throw new Error('content must be a non-empty string');
30
- }
31
- if (content.length > MAX_MEMORY_CONTENT_LENGTH) {
32
- throw new Error(`content exceeds maximum length of ${MAX_MEMORY_CONTENT_LENGTH} characters`);
33
- }
34
- }
35
- export function validateForgetSelection(id, query) {
36
- if ((id && query) || (!id && !query)) {
37
- throw new Error('Provide exactly one of id or query');
38
- }
39
- }
40
- export function isAdminToolsEnabled(env = process.env) {
41
- const value = env[ADMIN_TOOLS_ENV]?.toLowerCase();
42
- return value === '1' || value === 'true' || value === 'yes';
43
- }
44
- export function requireAdminTools(env = process.env) {
45
- if (!isAdminToolsEnabled(env)) {
46
- throw new Error(`Admin memory tools are disabled. Set ${ADMIN_TOOLS_ENV}=1 to enable export, import, and forget operations.`);
47
- }
48
- }
49
- export async function initializeEmbeddingProvider(provider) {
50
- if (provider && typeof provider.ready === 'function') {
51
- await provider.ready();
52
- }
53
- }
54
19
  function isEmbeddingWarmupDisabled(env = process.env) {
55
20
  const value = env['AUDREY_DISABLE_WARMUP'];
56
21
  return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';
57
22
  }
58
- export const memoryEncodeToolSchema = {
59
- content: z.string()
60
- .max(MAX_MEMORY_CONTENT_LENGTH)
61
- .refine(isNonEmptyText, 'Content must not be empty')
62
- .describe('The memory content to encode'),
63
- source: z.enum(VALID_SOURCES).describe('Source type of the memory'),
64
- tags: z.array(z.string()).optional().describe('Optional tags for categorization'),
65
- 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.'),
74
- };
75
- export const memoryRecallToolSchema = {
76
- query: z.string().describe('Search query to match against memories'),
77
- limit: z.number().min(1).max(50).optional().describe('Max results (default 10)'),
78
- types: z.array(z.enum(VALID_TYPES)).optional().describe('Memory types to search'),
79
- min_confidence: z.number().min(0).max(1).optional().describe('Minimum confidence threshold'),
80
- 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'),
82
- after: z.string().optional().describe('Only return memories created after this ISO date'),
83
- 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.'),
91
- };
92
- export const memoryImportToolSchema = {
93
- snapshot: importSnapshotSchema.describe('A validated snapshot from memory_export'),
94
- };
95
- export const memoryForgetToolSchema = {
96
- 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)'),
100
- };
101
- export const memoryValidateToolSchema = {
102
- 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).'),
104
- };
105
- export const memoryPreflightToolSchema = {
106
- action: z.string()
107
- .refine(isNonEmptyText, 'Action must not be empty')
108
- .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.'),
111
- 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.'),
122
- };
123
- const { record_event: _preflightRecordEvent, ...memoryGuardBeforeFields } = memoryPreflightToolSchema;
124
- export const memoryGuardBeforeToolSchema = {
125
- ...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.'),
128
- };
129
- export const memoryGuardAfterToolSchema = {
130
- receipt_id: z.string()
131
- .refine(isNonEmptyText, 'Receipt id must not be empty')
132
- .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.'),
139
- 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.'),
144
- };
145
- export const memoryReflexesToolSchema = {
146
- ...memoryPreflightToolSchema,
147
- include_preflight: z.boolean().optional().describe('If true, include the full underlying preflight report.'),
148
- };
149
23
  // ---------------------------------------------------------------------------
150
24
  // CLI subcommands
151
25
  // ---------------------------------------------------------------------------
@@ -160,7 +34,9 @@ async function serveHttp() {
160
34
  if (apiKey) {
161
35
  console.error('[audrey-http] API key authentication enabled');
162
36
  }
163
- else if (server.hostname === '127.0.0.1' || server.hostname === '::1' || server.hostname === 'localhost') {
37
+ else if (server.hostname === '127.0.0.1' ||
38
+ server.hostname === '::1' ||
39
+ server.hostname === 'localhost') {
164
40
  console.error('[audrey-http] no API key set (loopback only — set AUDREY_API_KEY to enable network access)');
165
41
  }
166
42
  }
@@ -178,7 +54,9 @@ async function reembed() {
178
54
  try {
179
55
  await initializeEmbeddingProvider(audrey.embeddingProvider);
180
56
  const { reembedAll } = await import('../src/migrate.js');
181
- const counts = await reembedAll(audrey.db, audrey.embeddingProvider, { dropAndRecreate: dimensionsChanged });
57
+ const counts = await reembedAll(audrey.db, audrey.embeddingProvider, {
58
+ dropAndRecreate: dimensionsChanged,
59
+ });
182
60
  console.log(`Done. Re-embedded: ${counts.episodes} episodes, ${counts.semantics} semantics, ${counts.procedures} procedures`);
183
61
  }
184
62
  finally {
@@ -208,13 +86,13 @@ async function dream() {
208
86
  console.log(`[audrey] Embedding: ${embeddingLabel}`);
209
87
  const result = await audrey.dream();
210
88
  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'}`);
89
+ console.log(`[audrey] Consolidation: evaluated ${result.consolidation.episodesEvaluated} episodes, ` +
90
+ `found ${result.consolidation.clustersFound} clusters, extracted ${result.consolidation.principlesExtracted} principles ` +
91
+ `(${result.consolidation.semanticsCreated ?? 0} semantic, ${result.consolidation.proceduresCreated ?? 0} procedural)`);
92
+ console.log(`[audrey] Decay: evaluated ${result.decay.totalEvaluated} memories, ` +
93
+ `${result.decay.transitionedToDormant} transitioned to dormant`);
94
+ console.log(`[audrey] Final: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ${result.stats.procedural} procedural ` +
95
+ `| ${health.healthy ? 'healthy' : 'unhealthy'}`);
218
96
  console.log('[audrey] Dream complete.');
219
97
  }
220
98
  finally {
@@ -257,9 +135,9 @@ async function greeting() {
257
135
  }
258
136
  const storedDimensions = readStoredDimensions(dataDir);
259
137
  const resolvedEmbedding = resolveEmbeddingProvider(process.env, process.env['AUDREY_EMBEDDING_PROVIDER']);
260
- const canUseResolvedEmbedding = Boolean(contextArg)
261
- && storedDimensions !== null
262
- && storedDimensions === resolvedEmbedding.dimensions;
138
+ const canUseResolvedEmbedding = Boolean(contextArg) &&
139
+ storedDimensions !== null &&
140
+ storedDimensions === resolvedEmbedding.dimensions;
263
141
  const dimensions = storedDimensions || resolvedEmbedding.dimensions || 8;
264
142
  const audrey = new Audrey({
265
143
  dataDir,
@@ -272,28 +150,30 @@ async function greeting() {
272
150
  if (canUseResolvedEmbedding) {
273
151
  await initializeEmbeddingProvider(audrey.embeddingProvider);
274
152
  }
275
- const result = await audrey.greeting({ context: canUseResolvedEmbedding ? contextArg : undefined });
153
+ const result = await audrey.greeting({
154
+ context: canUseResolvedEmbedding ? contextArg : undefined,
155
+ });
276
156
  const health = audrey.memoryStatus();
277
157
  const lines = [];
278
158
  lines.push(`[Audrey v${VERSION}] Memory briefing`);
279
159
  lines.push('');
280
160
  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.`);
161
+ lines.push(`Context recall skipped: stored index is ${storedDimensions ?? 'unknown'}d ` +
162
+ `but current embedding config resolves to ${resolvedEmbedding.dimensions}d.`);
283
163
  lines.push('');
284
164
  }
285
165
  // Mood
286
166
  if (result.mood && result.mood.samples > 0) {
287
167
  const v = result.mood.valence;
288
168
  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)`);
169
+ lines.push(`Mood: ${moodWord} (valence=${v.toFixed(2)}, ` +
170
+ `arousal=${result.mood.arousal.toFixed(2)}, ` +
171
+ `from ${result.mood.samples} recent memories)`);
292
172
  }
293
173
  // Health
294
174
  const stats = audrey.introspect();
295
- lines.push(`Memory: ${stats.episodic} episodic, ${stats.semantic} semantic, `
296
- + `${stats.procedural} procedural | ${health.healthy ? 'healthy' : 'needs attention'}`);
175
+ lines.push(`Memory: ${stats.episodic} episodic, ${stats.semantic} semantic, ` +
176
+ `${stats.procedural} procedural | ${health.healthy ? 'healthy' : 'needs attention'}`);
297
177
  lines.push('');
298
178
  // Principles (semantic memories)
299
179
  if (result.principles?.length > 0) {
@@ -398,12 +278,12 @@ async function reflect() {
398
278
  // Always run dream cycle after reflect
399
279
  console.log('[audrey] Starting dream cycle...');
400
280
  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`);
281
+ console.log(`[audrey] Consolidation: ${result.consolidation.episodesEvaluated} episodes evaluated, ` +
282
+ `${result.consolidation.clustersFound} clusters, ${result.consolidation.principlesExtracted} principles`);
283
+ console.log(`[audrey] Decay: ${result.decay.totalEvaluated} evaluated, ` +
284
+ `${result.decay.transitionedToDormant} dormant`);
285
+ console.log(`[audrey] Status: ${result.stats.episodic} episodic, ${result.stats.semantic} semantic, ` +
286
+ `${result.stats.procedural} procedural`);
407
287
  console.log('[audrey] Dream complete.');
408
288
  }
409
289
  finally {
@@ -449,11 +329,7 @@ export function formatInstallGuide(host, env = process.env, dryRun = false) {
449
329
  formatMcpHostConfig(normalizedHost, env),
450
330
  '',
451
331
  ...(normalizedHost === 'claude-code'
452
- ? [
453
- 'Generated Claude Code hook config:',
454
- formatClaudeCodeHookConfig(),
455
- '',
456
- ]
332
+ ? ['Generated Claude Code hook config:', formatClaudeCodeHookConfig(), '']
457
333
  : []),
458
334
  'Next steps:',
459
335
  ];
@@ -643,8 +519,12 @@ function printHookConfig() {
643
519
  dryRun: options.dryRun,
644
520
  });
645
521
  const action = result.dryRun
646
- ? result.changed ? 'would update' : 'would leave unchanged'
647
- : result.changed ? 'updated' : 'already up to date';
522
+ ? result.changed
523
+ ? 'would update'
524
+ : 'would leave unchanged'
525
+ : result.changed
526
+ ? 'updated'
527
+ : 'already up to date';
648
528
  console.log(`[audrey] Claude Code hook settings ${action}: ${result.settingsPath}`);
649
529
  if (result.backupPath)
650
530
  console.log(`[audrey] backup written: ${result.backupPath}`);
@@ -826,7 +706,9 @@ export function applyClaudeCodeHookConfig(options) {
826
706
  }
827
707
  catch (err) {
828
708
  const message = err instanceof Error ? err.message : String(err);
829
- throw new Error(`Cannot merge Audrey hooks into invalid JSON at ${settingsPath}: ${message}`);
709
+ throw new Error(`Cannot merge Audrey hooks into invalid JSON at ${settingsPath}: ${message}`, {
710
+ cause: err,
711
+ });
830
712
  }
831
713
  }
832
714
  const settings = mergeClaudeCodeHookSettings(existing);
@@ -875,11 +757,7 @@ function demoScenario(argv = process.argv) {
875
757
  return cliValue('--scenario', argv);
876
758
  }
877
759
  function formatControllerGuardResult(result) {
878
- const label = result.decision === 'block'
879
- ? 'BLOCKED'
880
- : result.decision === 'warn'
881
- ? 'WARN'
882
- : 'ALLOW';
760
+ const label = result.decision === 'block' ? 'BLOCKED' : result.decision === 'warn' ? 'WARN' : 'ALLOW';
883
761
  const lines = [];
884
762
  lines.push(`Audrey Guard: ${label}`);
885
763
  lines.push('');
@@ -992,8 +870,8 @@ export async function runDemoCommand({ out = console.log, keep = process.argv.in
992
870
  tags: ['procedure', 'memory-capsule', 'agent-loop'],
993
871
  }));
994
872
  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.',
873
+ content: 'If a host cannot auto-install Audrey, run npx audrey mcp-config codex ' +
874
+ 'or npx audrey mcp-config generic and paste the generated config.',
997
875
  source: 'direct-observation',
998
876
  tags: ['procedure', 'mcp', 'first-contact'],
999
877
  }));
@@ -1011,8 +889,8 @@ export async function runDemoCommand({ out = console.log, keep = process.argv.in
1011
889
  event: 'PostToolUse',
1012
890
  tool: 'npm test',
1013
891
  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.',
892
+ errorSummary: 'Vitest can fail with spawn EPERM on locked-down Windows hosts; ' +
893
+ 'use build, typecheck, benchmarks, and direct dist smokes as the fallback evidence path.',
1016
894
  cwd: process.cwd(),
1017
895
  metadata: { demo: true, source: 'audrey demo' },
1018
896
  });
@@ -1118,12 +996,15 @@ export function buildStatusReport({ dataDir = resolveDataDir(process.env), claud
1118
996
  });
1119
997
  report.stats = audrey.introspect();
1120
998
  report.health = audrey.memoryStatus();
1121
- report.lastConsolidation = audrey.db.prepare(`
999
+ report.lastConsolidation =
1000
+ audrey.db
1001
+ .prepare(`
1122
1002
  SELECT completed_at FROM consolidation_runs
1123
1003
  WHERE status = 'completed'
1124
1004
  ORDER BY completed_at DESC
1125
1005
  LIMIT 1
1126
- `).get()?.completed_at ?? 'never';
1006
+ `)
1007
+ .get()?.completed_at ?? 'never';
1127
1008
  audrey.close();
1128
1009
  }
1129
1010
  catch (err) {
@@ -1145,11 +1026,11 @@ export function formatStatusReport(report) {
1145
1026
  lines.push(`Data directory: ${report.dataDir}`);
1146
1027
  lines.push(`Stored dimensions: ${report.storedDimensions ?? 'unknown'}`);
1147
1028
  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)' : ''}`);
1029
+ lines.push(`Index sync: ${report.health.vec_episodes}/${report.health.searchable_episodes} episodic, ` +
1030
+ `${report.health.vec_semantics}/${report.health.searchable_semantics} semantic, ` +
1031
+ `${report.health.vec_procedures}/${report.health.searchable_procedures} procedural`);
1032
+ lines.push(`Health: ${report.health.healthy ? 'healthy' : 'unhealthy'}` +
1033
+ `${report.health.reembed_recommended ? ' (re-embed recommended)' : ''}`);
1153
1034
  lines.push(`Dormant: ${report.stats.dormant}`);
1154
1035
  lines.push(`Causal links: ${report.stats.causalLinks}`);
1155
1036
  lines.push(`Contradictions: ${report.stats.contradictions.open} open, ${report.stats.contradictions.resolved} resolved`);
@@ -1165,8 +1046,11 @@ export function runStatusCommand({ argv = process.argv, dataDir = resolveDataDir
1165
1046
  else {
1166
1047
  out(formatStatusReport(report));
1167
1048
  }
1168
- const exitCode = report.error
1169
- || (cliHasFlag('--fail-on-unhealthy', argv) && report.exists && report.health && !report.health.healthy)
1049
+ const exitCode = report.error ||
1050
+ (cliHasFlag('--fail-on-unhealthy', argv) &&
1051
+ report.exists &&
1052
+ report.health &&
1053
+ !report.health.healthy)
1170
1054
  ? 1
1171
1055
  : 0;
1172
1056
  return { report, exitCode };
@@ -1319,23 +1203,30 @@ function toolResult(data, diagnostics) {
1319
1203
  return result;
1320
1204
  }
1321
1205
  function toolError(err) {
1322
- return { isError: true, content: [{ type: 'text', text: `Error: ${err.message || String(err)}` }] };
1206
+ return {
1207
+ isError: true,
1208
+ content: [{ type: 'text', text: `Error: ${err.message || String(err)}` }],
1209
+ };
1323
1210
  }
1324
1211
  function jsonResource(uri, data) {
1325
1212
  return {
1326
- contents: [{
1213
+ contents: [
1214
+ {
1327
1215
  uri: uri.toString(),
1328
1216
  mimeType: 'application/json',
1329
1217
  text: JSON.stringify(data, null, 2),
1330
- }],
1218
+ },
1219
+ ],
1331
1220
  };
1332
1221
  }
1333
1222
  function promptText(text) {
1334
1223
  return {
1335
- messages: [{
1224
+ messages: [
1225
+ {
1336
1226
  role: 'user',
1337
1227
  content: { type: 'text', text },
1338
- }],
1228
+ },
1229
+ ],
1339
1230
  };
1340
1231
  }
1341
1232
  export function registerShutdownHandlers(processRef, audrey, logger = console.error) {
@@ -1350,8 +1241,8 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
1350
1241
  if (typeof audrey.drainPostEncodeQueue === 'function') {
1351
1242
  const drain = await audrey.drainPostEncodeQueue(5000);
1352
1243
  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(', ')}`);
1244
+ logger(`[audrey-mcp] post-encode queue did not drain within 5000ms; ` +
1245
+ `pending ids: ${drain.pendingIds.join(', ')}`);
1355
1246
  }
1356
1247
  }
1357
1248
  audrey.close();
@@ -1365,9 +1256,15 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
1365
1256
  processRef.exit(exitCode);
1366
1257
  }
1367
1258
  };
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'); });
1259
+ processRef.once('SIGINT', () => {
1260
+ void shutdown('[audrey-mcp] received SIGINT, shutting down');
1261
+ });
1262
+ processRef.once('SIGTERM', () => {
1263
+ void shutdown('[audrey-mcp] received SIGTERM, shutting down');
1264
+ });
1265
+ processRef.once('SIGHUP', () => {
1266
+ void shutdown('[audrey-mcp] received SIGHUP, shutting down');
1267
+ });
1371
1268
  processRef.once('uncaughtException', (err) => {
1372
1269
  logger('[audrey-mcp] uncaught exception:', err);
1373
1270
  void shutdown(undefined, 1);
@@ -1381,13 +1278,20 @@ export function registerShutdownHandlers(processRef, audrey, logger = console.er
1381
1278
  });
1382
1279
  return (message, exitCode = 0) => shutdown(message, exitCode);
1383
1280
  }
1384
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1385
1281
  export function registerDreamTool(server, audrey) {
1386
1282
  server.tool('memory_dream', {
1387
1283
  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 }) => {
1284
+ similarity_threshold: z
1285
+ .number()
1286
+ .optional()
1287
+ .describe('Similarity threshold for clustering (default 0.85)'),
1288
+ dormant_threshold: z
1289
+ .number()
1290
+ .min(0)
1291
+ .max(1)
1292
+ .optional()
1293
+ .describe('Confidence below which memories go dormant (default 0.1)'),
1294
+ }, async ({ min_cluster_size, similarity_threshold, dormant_threshold, }) => {
1391
1295
  try {
1392
1296
  const result = await audrey.dream({
1393
1297
  minClusterSize: min_cluster_size,
@@ -1401,7 +1305,6 @@ export function registerDreamTool(server, audrey) {
1401
1305
  }
1402
1306
  });
1403
1307
  }
1404
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1405
1308
  export function registerHostResources(server, audrey) {
1406
1309
  server.registerResource('audrey-status', 'audrey://status', {
1407
1310
  title: 'Audrey Status',
@@ -1448,7 +1351,6 @@ export function registerHostResources(server, audrey) {
1448
1351
  });
1449
1352
  });
1450
1353
  }
1451
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1452
1354
  export function registerHostPrompts(server) {
1453
1355
  server.registerPrompt('audrey-session-briefing', {
1454
1356
  title: 'Audrey Session Briefing',
@@ -1476,13 +1378,18 @@ export function registerHostPrompts(server) {
1476
1378
  title: 'Audrey Memory Reflection',
1477
1379
  description: 'Reflect at the end of a meaningful session and encode durable lessons.',
1478
1380
  argsSchema: {
1479
- summary: z.string().optional().describe('Optional compact summary of the session to reflect on.'),
1381
+ summary: z
1382
+ .string()
1383
+ .optional()
1384
+ .describe('Optional compact summary of the session to reflect on.'),
1480
1385
  },
1481
1386
  }, ({ summary }) => promptText([
1482
1387
  'Call memory_reflect with the important user and assistant turns from this session.',
1483
1388
  'Encode only durable preferences, decisions, fixes, failures, and project facts that should affect future work.',
1484
1389
  summary ? `Session summary hint: ${summary}` : undefined,
1485
- ].filter(Boolean).join('\n')));
1390
+ ]
1391
+ .filter(Boolean)
1392
+ .join('\n')));
1486
1393
  }
1487
1394
  async function main() {
1488
1395
  const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
@@ -1626,7 +1533,10 @@ async function main() {
1626
1533
  purge: purge ?? false,
1627
1534
  });
1628
1535
  if (!result) {
1629
- return toolResult({ forgotten: false, reason: 'No memory found above similarity threshold' });
1536
+ return toolResult({
1537
+ forgotten: false,
1538
+ reason: 'No memory found above similarity threshold',
1539
+ });
1630
1540
  }
1631
1541
  }
1632
1542
  return toolResult({ forgotten: true, ...result });
@@ -1647,7 +1557,12 @@ async function main() {
1647
1557
  }
1648
1558
  });
1649
1559
  server.tool('memory_decay', {
1650
- dormant_threshold: z.number().min(0).max(1).optional().describe('Confidence below which memories go dormant (default 0.1)'),
1560
+ dormant_threshold: z
1561
+ .number()
1562
+ .min(0)
1563
+ .max(1)
1564
+ .optional()
1565
+ .describe('Confidence below which memories go dormant (default 0.1)'),
1651
1566
  }, async ({ dormant_threshold }) => {
1652
1567
  try {
1653
1568
  return toolResult(audrey.decay({ dormantThreshold: dormant_threshold }));
@@ -1665,10 +1580,12 @@ async function main() {
1665
1580
  }
1666
1581
  });
1667
1582
  server.tool('memory_reflect', {
1668
- turns: z.array(z.object({
1583
+ turns: z
1584
+ .array(z.object({
1669
1585
  role: z.string().describe('Message role: user or assistant'),
1670
1586
  content: z.string().describe('Message content'),
1671
- })).describe('Conversation turns to reflect on. Call at end of meaningful conversations to form lasting memories.'),
1587
+ }))
1588
+ .describe('Conversation turns to reflect on. Call at end of meaningful conversations to form lasting memories.'),
1672
1589
  }, async ({ turns }) => {
1673
1590
  try {
1674
1591
  return toolResult(await audrey.reflect(turns));
@@ -1679,8 +1596,14 @@ async function main() {
1679
1596
  });
1680
1597
  registerDreamTool(server, audrey);
1681
1598
  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.'),
1599
+ context: z
1600
+ .string()
1601
+ .optional()
1602
+ .describe('Optional hint about this session. When provided, Audrey also returns semantically relevant memories.'),
1603
+ scope: z
1604
+ .enum(['agent', 'shared'])
1605
+ .optional()
1606
+ .describe('agent keeps greeting scoped to this server agent identity. shared includes the whole store. Defaults to agent.'),
1684
1607
  }, async ({ context, scope }) => {
1685
1608
  try {
1686
1609
  return toolResult(await audrey.greeting({ context, scope: scope ?? 'agent' }));
@@ -1690,17 +1613,40 @@ async function main() {
1690
1613
  }
1691
1614
  });
1692
1615
  server.tool('memory_observe_tool', {
1693
- event: z.string().describe('Hook event name (PreToolUse, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, etc.)'),
1616
+ event: z
1617
+ .string()
1618
+ .describe('Hook event name (PreToolUse, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, etc.)'),
1694
1619
  tool: z.string().describe('Tool name being observed (Bash, Edit, Write, etc.)'),
1695
1620
  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.'),
1621
+ input: z
1622
+ .unknown()
1623
+ .optional()
1624
+ .describe('Tool input. Hashed and never stored raw; redacted metadata is only stored when retain_details is true.'),
1625
+ output: z
1626
+ .unknown()
1627
+ .optional()
1628
+ .describe('Tool output. Same redaction and storage policy as input.'),
1629
+ outcome: z
1630
+ .enum(['succeeded', 'failed', 'blocked', 'skipped', 'unknown'])
1631
+ .optional()
1632
+ .describe('Outcome classification'),
1633
+ error_summary: z
1634
+ .string()
1635
+ .optional()
1636
+ .describe('Short error description if the tool failed. Redacted and truncated to 2 KB.'),
1700
1637
  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.'),
1638
+ files: z
1639
+ .array(z.string())
1640
+ .optional()
1641
+ .describe('File paths to fingerprint (size + mtime + content hash)'),
1642
+ metadata: z
1643
+ .record(z.string(), z.unknown())
1644
+ .optional()
1645
+ .describe('Arbitrary structured metadata (redacted before storage)'),
1646
+ retain_details: z
1647
+ .boolean()
1648
+ .optional()
1649
+ .describe('If true, redacted input and output payloads are stored alongside hashes. Defaults to false.'),
1704
1650
  }, async ({ event, tool, session_id, input, output, outcome, error_summary, cwd, files, metadata, retain_details, }) => {
1705
1651
  try {
1706
1652
  const result = audrey.observeTool({
@@ -1732,7 +1678,13 @@ async function main() {
1732
1678
  });
1733
1679
  server.tool('memory_recent_failures', {
1734
1680
  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)'),
1681
+ limit: z
1682
+ .number()
1683
+ .int()
1684
+ .min(1)
1685
+ .max(200)
1686
+ .optional()
1687
+ .describe('Max rows to return (defaults to 20)'),
1736
1688
  }, async ({ since, limit }) => {
1737
1689
  try {
1738
1690
  return toolResult(audrey.recentFailures({ since, limit }));
@@ -1743,13 +1695,43 @@ async function main() {
1743
1695
  });
1744
1696
  server.tool('memory_capsule', {
1745
1697
  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.'),
1698
+ limit: z
1699
+ .number()
1700
+ .int()
1701
+ .min(1)
1702
+ .max(50)
1703
+ .optional()
1704
+ .describe('Max recall results to consider before categorization.'),
1705
+ budget_chars: z
1706
+ .number()
1707
+ .int()
1708
+ .min(200)
1709
+ .max(32000)
1710
+ .optional()
1711
+ .describe('Token budget in characters (defaults to AUDREY_CONTEXT_BUDGET_CHARS or 4000).'),
1712
+ mode: z
1713
+ .enum(['balanced', 'conservative', 'aggressive'])
1714
+ .optional()
1715
+ .describe('Capsule mode: conservative = fewer, higher-confidence entries; aggressive = broader sweep.'),
1716
+ recent_change_window_hours: z
1717
+ .number()
1718
+ .int()
1719
+ .min(1)
1720
+ .max(720)
1721
+ .optional()
1722
+ .describe('How far back "recent_changes" looks (default 24h).'),
1723
+ include_risks: z
1724
+ .boolean()
1725
+ .optional()
1726
+ .describe('Include recent tool failures as risks (default true).'),
1727
+ include_contradictions: z
1728
+ .boolean()
1729
+ .optional()
1730
+ .describe('Include open contradictions (default true).'),
1731
+ scope: z
1732
+ .enum(['agent', 'shared'])
1733
+ .optional()
1734
+ .describe('agent restricts memory recall to this MCP server agent identity. shared searches the whole store. Defaults to agent.'),
1753
1735
  }, async ({ query, limit, budget_chars, mode, recent_change_window_hours, include_risks, include_contradictions, scope, }) => {
1754
1736
  try {
1755
1737
  const capsule = await audrey.capsule(query, {
@@ -1860,14 +1842,42 @@ async function main() {
1860
1842
  }
1861
1843
  });
1862
1844
  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, }) => {
1845
+ target: z
1846
+ .enum(['claude-rules'])
1847
+ .optional()
1848
+ .describe('Promotion target. Only claude-rules is implemented in PR 4 v1.'),
1849
+ min_confidence: z
1850
+ .number()
1851
+ .min(0)
1852
+ .max(1)
1853
+ .optional()
1854
+ .describe('Minimum memory confidence for promotion (default 0.7 for procedural, 0.8 for semantic).'),
1855
+ min_evidence: z
1856
+ .number()
1857
+ .int()
1858
+ .min(1)
1859
+ .optional()
1860
+ .describe('Minimum supporting episode count (default 2).'),
1861
+ limit: z
1862
+ .number()
1863
+ .int()
1864
+ .min(1)
1865
+ .max(50)
1866
+ .optional()
1867
+ .describe('Max candidates to return/apply (default 20).'),
1868
+ dry_run: z
1869
+ .boolean()
1870
+ .optional()
1871
+ .describe('If true (default), return candidates without writing. Pair with yes=true to actually write.'),
1872
+ yes: z
1873
+ .boolean()
1874
+ .optional()
1875
+ .describe('Confirm write. Without this or dry_run=false the command stays in dry-run mode.'),
1876
+ project_dir: z
1877
+ .string()
1878
+ .optional()
1879
+ .describe('Absolute path to the project root where .claude/rules/ should be created. Defaults to process.cwd().'),
1880
+ }, async ({ target, min_confidence, min_evidence, limit, dry_run, yes, project_dir }) => {
1871
1881
  try {
1872
1882
  const result = await audrey.promote({
1873
1883
  target,
@@ -1890,7 +1900,8 @@ async function main() {
1890
1900
  console.error('[audrey-mcp] connected via stdio');
1891
1901
  }
1892
1902
  if (!isEmbeddingWarmupDisabled(process.env)) {
1893
- void audrey.startEmbeddingWarmup()
1903
+ void audrey
1904
+ .startEmbeddingWarmup()
1894
1905
  .then(() => {
1895
1906
  if (process.env.AUDREY_DEBUG === '1') {
1896
1907
  const status = audrey.memoryStatus();
@@ -1925,7 +1936,10 @@ function parseObserveToolArgs(argv) {
1925
1936
  else if (token === '--files') {
1926
1937
  const list = next();
1927
1938
  if (list)
1928
- out.files = list.split(',').map(s => s.trim()).filter(Boolean);
1939
+ out.files = list
1940
+ .split(',')
1941
+ .map(s => s.trim())
1942
+ .filter(Boolean);
1929
1943
  }
1930
1944
  else if (token === '--input-json')
1931
1945
  out.inputJson = next();
@@ -1980,13 +1994,11 @@ async function observeToolCli() {
1980
1994
  };
1981
1995
  const inputPayload = args.inputJson !== undefined
1982
1996
  ? parseMaybeJson(args.inputJson)
1983
- : stdinPayload?.tool_input ?? stdinPayload?.input;
1997
+ : (stdinPayload?.tool_input ?? stdinPayload?.input);
1984
1998
  const outputPayload = args.outputJson !== undefined
1985
1999
  ? 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;
2000
+ : (stdinPayload?.tool_response ?? stdinPayload?.tool_output ?? stdinPayload?.output);
2001
+ const metadataPayload = args.metadataJson !== undefined ? parseMaybeJson(args.metadataJson) : stdinPayload?.metadata;
1990
2002
  const sessionId = args.sessionId ?? stdinPayload?.session_id;
1991
2003
  const cwd = args.cwd ?? stdinPayload?.cwd;
1992
2004
  // Detect failure from Claude Code hook payload shape: tool_response often
@@ -2124,7 +2136,7 @@ function guardDisplayDecision(result) {
2124
2136
  return 'allow';
2125
2137
  }
2126
2138
  function summarizeToolInput(payload, tool) {
2127
- const input = (payload.tool_input && typeof payload.tool_input === 'object')
2139
+ const input = payload.tool_input && typeof payload.tool_input === 'object'
2128
2140
  ? payload.tool_input
2129
2141
  : {};
2130
2142
  const command = typeof input.command === 'string' ? input.command : undefined;
@@ -2139,9 +2151,7 @@ function summarizeToolInput(payload, tool) {
2139
2151
  return { action: `${tool}: ${description}`, files };
2140
2152
  const compactInput = JSON.stringify(input);
2141
2153
  return {
2142
- action: compactInput && compactInput !== '{}'
2143
- ? `${tool} ${compactInput}`
2144
- : `Use ${tool}`,
2154
+ action: compactInput && compactInput !== '{}' ? `${tool} ${compactInput}` : `Use ${tool}`,
2145
2155
  files,
2146
2156
  };
2147
2157
  }
@@ -2160,7 +2170,9 @@ function formatHookReason(result) {
2160
2170
  result.summary,
2161
2171
  recommendations.length > 0 ? `Recommended: ${recommendations.join(' ')}` : '',
2162
2172
  result.evidence_ids.length > 0 ? `Evidence: ${result.evidence_ids.slice(0, 5).join(', ')}` : '',
2163
- ].filter(Boolean).join('\n');
2173
+ ]
2174
+ .filter(Boolean)
2175
+ .join('\n');
2164
2176
  }
2165
2177
  function formatPreToolUseHookOutput(result, failOnWarn) {
2166
2178
  const decision = guardDisplayDecision(result);
@@ -2253,7 +2265,11 @@ async function guardCli() {
2253
2265
  tool: hookTool ?? args.tool,
2254
2266
  sessionId: args.sessionId ?? hookSessionId,
2255
2267
  cwd: args.cwd ?? hookCwd ?? process.cwd(),
2256
- files: args.files.length > 0 ? args.files : hookSummary?.files?.length ? hookSummary.files : undefined,
2268
+ files: args.files.length > 0
2269
+ ? args.files
2270
+ : hookSummary?.files?.length
2271
+ ? hookSummary.files
2272
+ : undefined,
2257
2273
  strict: args.strict || args.failOnWarn || args.hook,
2258
2274
  recordEvent: true,
2259
2275
  includeCapsule: args.includeCapsule || args.explain,
@@ -2268,7 +2284,9 @@ async function guardCli() {
2268
2284
  console.log(formatGuardDecision(result, { explain: args.explain }));
2269
2285
  }
2270
2286
  const display = guardDisplayDecision(result);
2271
- if (!args.hook && (display === 'block' || (args.failOnWarn && display === 'warn')) && !args.override) {
2287
+ if (!args.hook &&
2288
+ (display === 'block' || (args.failOnWarn && display === 'warn')) &&
2289
+ !args.override) {
2272
2290
  process.exitCode = 2;
2273
2291
  }
2274
2292
  }
@@ -2314,9 +2332,9 @@ async function readOptionalJsonFromStdin(command) {
2314
2332
  }
2315
2333
  }
2316
2334
  function inferGuardAfterOutcome(stdinPayload) {
2317
- const response = stdinPayload?.tool_response
2318
- ?? stdinPayload?.tool_output
2319
- ?? stdinPayload?.output;
2335
+ const response = stdinPayload?.tool_response ??
2336
+ stdinPayload?.tool_output ??
2337
+ stdinPayload?.output;
2320
2338
  const success = response?.success;
2321
2339
  if (typeof success === 'boolean')
2322
2340
  return success ? 'succeeded' : 'failed';
@@ -2433,8 +2451,8 @@ async function promoteCli() {
2433
2451
  const snippet = c.content.length > 120 ? c.content.slice(0, 117) + '...' : c.content;
2434
2452
  console.log(` memory: ${snippet}`);
2435
2453
  console.log(` why: ${c.reason}`);
2436
- console.log(` confidence=${(c.confidence * 100).toFixed(1)}% `
2437
- + `evidence=${c.evidence_count} prevented_failures=${c.failure_prevented}`);
2454
+ console.log(` confidence=${(c.confidence * 100).toFixed(1)}% ` +
2455
+ `evidence=${c.evidence_count} prevented_failures=${c.failure_prevented}`);
2438
2456
  }
2439
2457
  if (result.dry_run) {
2440
2458
  console.log('');
@@ -2454,11 +2472,26 @@ function canonicalEntryPath(path) {
2454
2472
  return resolved.toLowerCase();
2455
2473
  }
2456
2474
  }
2457
- const isDirectRun = Boolean(process.argv[1])
2458
- && canonicalEntryPath(process.argv[1]) === canonicalEntryPath(fileURLToPath(import.meta.url));
2475
+ const isDirectRun = Boolean(process.argv[1]) &&
2476
+ canonicalEntryPath(process.argv[1]) === canonicalEntryPath(fileURLToPath(import.meta.url));
2459
2477
  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',
2478
+ 'install',
2479
+ 'uninstall',
2480
+ 'mcp-config',
2481
+ 'hook-config',
2482
+ 'demo',
2483
+ 'reembed',
2484
+ 'dream',
2485
+ 'greeting',
2486
+ 'reflect',
2487
+ 'serve',
2488
+ 'status',
2489
+ 'doctor',
2490
+ 'observe-tool',
2491
+ 'guard',
2492
+ 'guard-after',
2493
+ 'promote',
2494
+ 'impact',
2462
2495
  ];
2463
2496
  function printHelp() {
2464
2497
  process.stdout.write(`audrey ${VERSION} — local-first memory runtime for AI agents