audrey 2.0.0 → 2.1.1

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 (148) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +64 -60
  3. package/SECURITY.md +2 -3
  4. package/dist/mcp-server/config.d.ts +1 -11
  5. package/dist/mcp-server/config.d.ts.map +1 -1
  6. package/dist/mcp-server/config.js +42 -4
  7. package/dist/mcp-server/config.js.map +1 -1
  8. package/dist/mcp-server/index.d.ts +6 -2
  9. package/dist/mcp-server/index.d.ts.map +1 -1
  10. package/dist/mcp-server/index.js +147 -16
  11. package/dist/mcp-server/index.js.map +1 -1
  12. package/dist/mcp-server/tool-schemas.d.ts +46 -0
  13. package/dist/mcp-server/tool-schemas.d.ts.map +1 -1
  14. package/dist/mcp-server/tool-schemas.js +20 -1
  15. package/dist/mcp-server/tool-schemas.js.map +1 -1
  16. package/dist/src/action-key.d.ts.map +1 -1
  17. package/dist/src/action-key.js +7 -7
  18. package/dist/src/action-key.js.map +1 -1
  19. package/dist/src/audrey.d.ts +7 -4
  20. package/dist/src/audrey.d.ts.map +1 -1
  21. package/dist/src/audrey.js +210 -57
  22. package/dist/src/audrey.js.map +1 -1
  23. package/dist/src/autopilot.d.ts +1 -1
  24. package/dist/src/autopilot.d.ts.map +1 -1
  25. package/dist/src/autopilot.js +47 -224
  26. package/dist/src/autopilot.js.map +1 -1
  27. package/dist/src/capsule.d.ts +4 -17
  28. package/dist/src/capsule.d.ts.map +1 -1
  29. package/dist/src/capsule.js +21 -20
  30. package/dist/src/capsule.js.map +1 -1
  31. package/dist/src/chatgpt-auth.d.ts +82 -0
  32. package/dist/src/chatgpt-auth.d.ts.map +1 -0
  33. package/dist/src/chatgpt-auth.js +965 -0
  34. package/dist/src/chatgpt-auth.js.map +1 -0
  35. package/dist/src/chatgpt-llm.d.ts +18 -0
  36. package/dist/src/chatgpt-llm.d.ts.map +1 -0
  37. package/dist/src/chatgpt-llm.js +157 -0
  38. package/dist/src/chatgpt-llm.js.map +1 -0
  39. package/dist/src/consolidate.d.ts.map +1 -1
  40. package/dist/src/consolidate.js +30 -2
  41. package/dist/src/consolidate.js.map +1 -1
  42. package/dist/src/controller.d.ts +7 -1
  43. package/dist/src/controller.d.ts.map +1 -1
  44. package/dist/src/controller.js +88 -14
  45. package/dist/src/controller.js.map +1 -1
  46. package/dist/src/db.d.ts +1 -0
  47. package/dist/src/db.d.ts.map +1 -1
  48. package/dist/src/db.js +126 -45
  49. package/dist/src/db.js.map +1 -1
  50. package/dist/src/embedding.d.ts.map +1 -1
  51. package/dist/src/embedding.js +14 -1
  52. package/dist/src/embedding.js.map +1 -1
  53. package/dist/src/encode.d.ts +14 -0
  54. package/dist/src/encode.d.ts.map +1 -1
  55. package/dist/src/encode.js +56 -17
  56. package/dist/src/encode.js.map +1 -1
  57. package/dist/src/events.d.ts +17 -0
  58. package/dist/src/events.d.ts.map +1 -1
  59. package/dist/src/events.js +130 -3
  60. package/dist/src/events.js.map +1 -1
  61. package/dist/src/export.d.ts +1 -0
  62. package/dist/src/export.d.ts.map +1 -1
  63. package/dist/src/export.js +9 -2
  64. package/dist/src/export.js.map +1 -1
  65. package/dist/src/forget.d.ts.map +1 -1
  66. package/dist/src/forget.js +6 -2
  67. package/dist/src/forget.js.map +1 -1
  68. package/dist/src/fts.d.ts +2 -2
  69. package/dist/src/fts.d.ts.map +1 -1
  70. package/dist/src/fts.js +4 -4
  71. package/dist/src/fts.js.map +1 -1
  72. package/dist/src/grounding.d.ts +1 -1
  73. package/dist/src/grounding.d.ts.map +1 -1
  74. package/dist/src/grounding.js +24 -11
  75. package/dist/src/grounding.js.map +1 -1
  76. package/dist/src/hybrid-recall.d.ts +5 -8
  77. package/dist/src/hybrid-recall.d.ts.map +1 -1
  78. package/dist/src/hybrid-recall.js +25 -57
  79. package/dist/src/hybrid-recall.js.map +1 -1
  80. package/dist/src/import.d.ts +40 -3
  81. package/dist/src/import.d.ts.map +1 -1
  82. package/dist/src/import.js +101 -42
  83. package/dist/src/import.js.map +1 -1
  84. package/dist/src/index.d.ts +3 -0
  85. package/dist/src/index.d.ts.map +1 -1
  86. package/dist/src/index.js +2 -0
  87. package/dist/src/index.js.map +1 -1
  88. package/dist/src/llm-shared.d.ts +10 -0
  89. package/dist/src/llm-shared.d.ts.map +1 -0
  90. package/dist/src/llm-shared.js +20 -0
  91. package/dist/src/llm-shared.js.map +1 -0
  92. package/dist/src/llm.d.ts +2 -1
  93. package/dist/src/llm.d.ts.map +1 -1
  94. package/dist/src/llm.js +13 -22
  95. package/dist/src/llm.js.map +1 -1
  96. package/dist/src/migrate.d.ts.map +1 -1
  97. package/dist/src/migrate.js +34 -40
  98. package/dist/src/migrate.js.map +1 -1
  99. package/dist/src/preflight.d.ts +2 -0
  100. package/dist/src/preflight.d.ts.map +1 -1
  101. package/dist/src/preflight.js +5 -1
  102. package/dist/src/preflight.js.map +1 -1
  103. package/dist/src/project-memory.d.ts +14 -0
  104. package/dist/src/project-memory.d.ts.map +1 -0
  105. package/dist/src/project-memory.js +135 -0
  106. package/dist/src/project-memory.js.map +1 -0
  107. package/dist/src/project.d.ts +2 -0
  108. package/dist/src/project.d.ts.map +1 -1
  109. package/dist/src/project.js +12 -0
  110. package/dist/src/project.js.map +1 -1
  111. package/dist/src/promote.d.ts.map +1 -1
  112. package/dist/src/promote.js +2 -26
  113. package/dist/src/promote.js.map +1 -1
  114. package/dist/src/recall-scoring.d.ts +14 -0
  115. package/dist/src/recall-scoring.d.ts.map +1 -0
  116. package/dist/src/recall-scoring.js +167 -0
  117. package/dist/src/recall-scoring.js.map +1 -0
  118. package/dist/src/recall.d.ts.map +1 -1
  119. package/dist/src/recall.js +31 -168
  120. package/dist/src/recall.js.map +1 -1
  121. package/dist/src/rollback.d.ts +12 -0
  122. package/dist/src/rollback.d.ts.map +1 -1
  123. package/dist/src/rollback.js +118 -25
  124. package/dist/src/rollback.js.map +1 -1
  125. package/dist/src/routes.d.ts.map +1 -1
  126. package/dist/src/routes.js +102 -33
  127. package/dist/src/routes.js.map +1 -1
  128. package/dist/src/rules-compiler.d.ts +4 -0
  129. package/dist/src/rules-compiler.d.ts.map +1 -1
  130. package/dist/src/rules-compiler.js +34 -2
  131. package/dist/src/rules-compiler.js.map +1 -1
  132. package/dist/src/server.d.ts +2 -0
  133. package/dist/src/server.d.ts.map +1 -1
  134. package/dist/src/server.js +96 -38
  135. package/dist/src/server.js.map +1 -1
  136. package/dist/src/shell-command.d.ts.map +1 -1
  137. package/dist/src/shell-command.js +24 -7
  138. package/dist/src/shell-command.js.map +1 -1
  139. package/dist/src/success-checks.d.ts +41 -0
  140. package/dist/src/success-checks.d.ts.map +1 -0
  141. package/dist/src/success-checks.js +164 -0
  142. package/dist/src/success-checks.js.map +1 -0
  143. package/dist/src/types.d.ts +7 -1
  144. package/dist/src/types.d.ts.map +1 -1
  145. package/dist/src/validate.d.ts.map +1 -1
  146. package/dist/src/validate.js +23 -9
  147. package/dist/src/validate.js.map +1 -1
  148. package/package.json +7 -10
package/CHANGELOG.md CHANGED
@@ -1,5 +1,84 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.1.1 - 2026-10-28
4
+
5
+ ### ChatGPT sign-in
6
+
7
+ - Every refresh failure OpenAI documents as terminal (`invalid_grant`, `invalid_refresh_token`, `token_expired`, `refresh_token_expired`, `refresh_token_invalidated`, `refresh_token_reused`) now clears the stored tokens and asks for a new sign-in. 2.1.0 did that for `invalid_grant` only, so the other five left a dead grant in place that every later call retried against the authorization server. Any other error code keeps the credentials, as the documentation asks.
8
+ - A token that is still valid is served straight from the credential file without taking the writer lock, so concurrent hook processes no longer queue behind one another to read it. When a refresh is needed, discovery and the signing keys are fetched before the lock is taken, the lock is removed only by the process whose stamp it still carries, and the credential file's rename is followed by a directory fsync.
9
+ - A malformed request to the sign-in callback listener answers 400 instead of crashing the process that is waiting for the browser.
10
+ - `AUDREY_CHATGPT_AUTH_DIR` may start with `~`, and `audrey install` resolves it to an absolute path before writing hook commands, so a relative or home-relative value no longer produces a different credential store for every project directory.
11
+ - An `earliest_refresh_at` later than the token's own expiry is ignored rather than trusted; the field's unit is undocumented, and trusting a far-future value locked the account out until a manual login.
12
+ - `audrey auth logout` reports `revoked: false` when the account held an access token but no refresh token to revoke; it previously reported success while the access token stayed valid until expiry.
13
+ - On Windows, `powershell.exe` is launched by its installed path rather than looked up on `PATH` from a hook running inside the user's repository.
14
+
15
+ ### Release workflow
16
+
17
+ - The MCP Registry publish waits for npm to list the new version before registering it. npm now processes a published package for a few minutes before it is visible, and the 2.1.0 registry publish failed on that window and had to be re-run by hand.
18
+
19
+ ## 2.1.0 - 2026-10-28
20
+
21
+ ### Guard can check what an action returned
22
+
23
+ - `beforeAction` accepts `successChecks`: up to 16 comparisons, each naming a JSON Pointer into the output that `afterAction` will receive and the scalar value found there must equal. The receipt stores the compiled contract with expected values as SHA-256 fingerprints rather than plaintext, so the expectation is fixed before the action runs and a later `afterAction` cannot replace it. A reported success whose checks mismatch is recorded as `failed`; one whose checks cannot be evaluated (value missing, string that is not JSON when `parseJson` is set) is recorded as `unknown`; a reported failure stays failed, and passing checks never promote an unknown execution outcome to success. Blocked and skipped actions do not run the checks. MCP `memory_guard_before` takes `success_checks`, REST `POST /v1/guard/before` takes `success_checks` or `successChecks`, and `GuardOutcome` gains `reported_outcome` and `verification`. The contract and its limits are in `docs/SUCCESS_CHECKS.md`.
24
+ - A failed check stays active for the exact-failure window until a later success passes the same contract. A retry that omits the checks, or declares different ones, does not clear it or hide it; the failure stands until a success passes the original contract or the exact-failure window ends. The older `MemoryController.beforeAction(AgentAction)` interface rejects `successChecks`; use `Audrey.beforeAction` and `Audrey.afterAction`.
25
+ - `afterAction` records the outcome, the post-event, and any evidence feedback inside one immediate transaction and emits its events after the commit. Two hook processes closing the same receipt at once could previously both read "no outcome yet" and both write one, applying the same evidence feedback twice. It also rejects an outcome outside `succeeded`, `failed`, `blocked`, `skipped`, and `unknown` instead of storing it, and it sets `read_only` on the recorded outcome from the receipt rather than from caller metadata, so a failure cannot be kept out of failure learning by labelling it read-only.
26
+ - Autopilot passes an explicit `unknown` outcome through instead of treating a zero exit code as success, learns a failure from the persisted outcome's error summary so a verification failure behind a clean exit still produces a failure memory, and the legacy controller path no longer writes a failure memory for a read-only command's non-zero exit.
27
+ - The exact-action fingerprint keeps the command's case and whitespace. Folding both meant `rm -rf build` and `rm -rf BUILD` shared one failure history on a case-sensitive filesystem, and quoted arguments lost their spacing. Autopilot keys, which fingerprint the host's tool-input digest, are unchanged. Non-digest keys recorded through the SDK, MCP, or REST before this release do not match the exact-repeat check after upgrading; those failures still surface through the recent-failure path, which matches by what a command runs.
28
+
29
+ ### Reflection and consolidation on a ChatGPT subscription
30
+
31
+ - `AUDREY_LLM_PROVIDER=chatgpt` runs reflection and consolidation through OpenAI's Responses API with a signed-in ChatGPT plan instead of an API key. `audrey auth login` completes the browser sign-in (`--no-browser` prints the URL instead of opening it; `--consent` asks for plan usage when it was not granted the first time), and `audrey auth status`, `accounts`, `select --account <ID>`, and `logout` manage saved registrations. ID tokens are verified against OpenAI's published keys (new dependency: `jose`). Credentials live in `AUDREY_CHATGPT_AUTH_DIR` (default `~/.audrey/auth`, created `0700` with `0600` files), outside the memory database, and `status` and `accounts` report connection state without printing tokens. The provider confirms the selected model is available to the account before using a new token, never substitutes a different model, and never falls back to API billing. Requests are sent with `store: false`, and the first request in a process prints the same one-line stderr notice the API providers print before memory content leaves the machine. On Windows the owner-only ACL is applied through the .NET access-control API rather than `Set-Acl`, so it needs neither an elevated shell nor a loadable PowerShell module.
32
+ - `AUDREY_LLM_REASONING_EFFORT` (`low`, `medium`, `high`, `xhigh`, or `max`) sets the reasoning effort for the `chatgpt` provider, which defaults to `medium`, and for the `openai` provider, which sends no `reasoning_effort` unless the variable is set, since chat-tuned and older reasoning models reject the parameter. The `openai` provider's default model moves from `gpt-4o` to `gpt-6.1-sol`, and its `max_completion_tokens` handling now covers `gpt-6` models.
33
+ - Autopilot hook commands accept `--llm-reasoning-effort`, `--chatgpt-auth-dir`, and `--chatgpt-account`, and `audrey install` writes them from the matching environment variables.
34
+
35
+ ### Promote
36
+
37
+ - Promoted rule files are named by memory identity (`.claude/rules/audrey-sem-<hash>.md` and `audrey-proc-<hash>.md`) rather than by a slug of the title. Two memories whose titles slugified the same, or that differed only in case on a case-insensitive filesystem, could previously land in one file, and a memory id from an imported snapshot never becomes part of a path.
38
+ - An existing rule file is preserved, not overwritten. Promotion reads the generated provenance header at the new name and at the older slug name, including the numbered variants the old renderer wrote; a file carrying this memory's provenance is recorded as already promoted and left as it is, so a rule someone edited survives a re-run. A file at the destination with different provenance is an error instead of an overwrite. New files are published by hard-linking a private temporary file into place, which fails rather than replaces when something else wrote the path first, so two promotions racing cannot clobber each other. On a filesystem without hard links (exFAT, some network and container mounts) the file is created with an exclusive open instead, which keeps the same no-overwrite guarantee. `overwritten` in the result is always `false` now.
39
+ - Promotions are recorded in a ledger inside the store (`audrey_config` keys prefixed `promotion_ledger:`) as well as in the activity log. The event retention sweep deletes old `Promotion` events, which made the candidate search forget what had been promoted and offer it again; the sweep now copies each promotion into the ledger before deleting its event, and `memory_export` and `memory_import` round-trip the ledger.
40
+ - The footer of a generated rule no longer points at an `audrey forget` command that does not exist. It names the `memory_forget` tool and the SDK call, and says that retracting the memory does not delete the file.
41
+
42
+ ### Recall
43
+
44
+ - Keyword candidates are scored the same way as vector candidates. A semantic or procedural memory that only full-text search found used to get a reduced confidence (its support ratio alone, with no age, interference, or salience), so hybrid ranking fused two different scales; both paths now run the same confidence and provenance computation, and `min_confidence` applies uniformly during fusion.
45
+ - Full-text search includes `context_dependent` semantic and procedural memories, and `dormant` ones when `include_dormant` is set. It previously matched only `active` rows, so a memory the vector path would return could be invisible to a keyword query for the same words.
46
+ - The post-encode contradiction check finds the nearest semantic memory with a bounded nearest-neighbour query instead of computing a distance to every one of the agent's semantic rows and sorting them. When the nearest vector belongs to a retired memory it runs one more indexed query restricted to live rows.
47
+ - `greeting` excludes superseded episodes from its recent, identity, unresolved, and affect summaries, and `encode` with `supersedes` and `resolveTruth` drop or restore the affected row's vector immediately rather than at the next sweep.
48
+ - `recall` requires an integer `limit` of at least 1 (the MCP schema now rejects fractions), and the local embedding provider rejects a `batchSize` that is not a positive integer.
49
+
50
+ ### Encode, import, and consolidation
51
+
52
+ - `encodeBatch` validates every item before writing any of them. The context, causal, and supersedes checks lived only in the single-item path, so a batch with a bad later item committed its earlier items, queued their post-encode work, and then threw without returning their ids.
53
+ - `encode` validates what it is given: `context` must be an object of string values and is redacted as one document, `causal` must carry string `trigger` and `consequence` values, and `supersedes` must name an episode owned by the acting agent. An agent could previously supersede another agent's episode by id.
54
+ - Import no longer caps snapshot size (50,000 characters per content field, 25,000 rows per section, 25 MB of content in total). Those caps blocked restoring a store that was simply larger than an interactive request; shape validation stays, and embedding runs in batches of 256 with each returned vector checked for the right dimension and finite values. Imported semantic and procedural memories inherit `private` from any private evidence episode in the snapshot, matching what consolidation does.
55
+ - Each consolidation run records a commit sequence in its undo journal, assigned under the write lock, because run ids and timestamps record when preparation started rather than the order merges committed. Rollback refuses a run that is not `completed`, and refuses to undo a merge that a later completed run built on until that later run is rolled back first; two journals without sequences whose completion times tie are refused rather than guessed.
56
+
57
+ ### REST sidecar
58
+
59
+ - Startup and shutdown are deliberate. `startServer` resolves only after the listener is bound and rejects, closing the store and any sockets, if binding fails. `close()` stops accepting connections, waits for in-flight requests up to `shutdownTimeoutMs` (default 10 seconds), then drains queued post-encode work and reports any that did not finish. `audrey serve` handles `SIGINT` and `SIGTERM` the same way and forces exit one second past the grace period.
60
+ - The API key comparison refuses an `Authorization` header longer than its fixed 4 KiB compare buffer instead of silently comparing only the first 1 KiB, and the configured key must fit that buffer; the compare itself stays constant-time over the whole buffer.
61
+ - Routes with optional bodies (`consolidate`, `dream`, `decay`, `greeting`) answer 400 to a body that is not a JSON object instead of treating it as empty. `validate` answers 400 to an unknown `outcome` instead of recording it as `used`. `encode` accepts `causal`, requires string context values, and accepts `supersedes` only when admin tools are enabled, because retiring a memory is the same class of operation as `forget` and the acting agent on this transport is whatever the caller named. `capsule` accepts `cwd`. `forget` by query and `reflect` act as the request's agent rather than the server's default agent.
62
+
63
+ ### Hosts and CLI
64
+
65
+ - `audrey --help` and `-h` work after a subcommand, and `audrey auth` joins the command list.
66
+ - `server.json` (the MCP Registry listing) is a release version surface: the release cut bumps it with the other four, readiness checks it for alignment, and it now lists the embedding, LLM, and admin-tools variables alongside the data directory and agent name. It had declared 1.1.3 since that release.
67
+ - The shell classifier no longer treats `git remote -v add …` or `git remote --verbose set-url …` as read-only, since the verbose flag is a global option that can precede a mutating subcommand, and a redirect to `nul` or `NUL:` counts as a write, because under Bash on Windows those names can be ordinary files.
68
+
69
+ ### Python SDK
70
+
71
+ - `StatusResponse` matches what `/v1/status` returns: `episodes`, `semantics`, `procedures`, `healthy`, the vector and searchable counts, dimensions, schema version, warm-up, and recall-health fields. The previous model's fields were never populated. `episodic`, `semantic`, and `procedural` remain as read-only aliases. `context` on encode and recall is typed `dict[str, str]` and rejected client-side otherwise, and the README states that snapshot export and restore need `AUDREY_ENABLE_ADMIN_TOOLS=1` on the sidecar.
72
+
73
+ ### Dependencies
74
+
75
+ - The production dependency audit is clean again. `@modelcontextprotocol/sdk` moves to 1.32 (six advisories against the HTTP transports, OAuth client, and bearer-token checks, none of which the stdio server uses but all of which ship in the package), `zod` to 4.6.7 (memory exhaustion while validating oversized constrained collections), `hono` to 4.13.14 and `@hono/node-server` to 2.1 (`serveStatic` double-decoding, unused here; the node-server major drops Node 18 and the Vercel adapter and changes nothing Audrey calls), and the transitive `sharp`, `body-parser`, `proxy-addr`, `qs`, `ip-address`, and `fast-uri` pins to their patched releases.
76
+
77
+ ### Documentation
78
+
79
+ - The README describes each feature by what it checks and what it does not: Guard verifies action fingerprints and declared result checks, not whether a prose prerequisite was satisfied; grounding checks that paths and scripts still exist, not that they are correct; `impact` reports explicit feedback, not time saved; and hook latency includes process startup even with a warm model cache. `.env.example` says that Audrey does not load `.env` files itself.
80
+ - Removes non-reference material from `docs/paper` (a copy bank, a submission plan, and a posting log), the pre-writing outline and submission notes, and the three scripts and the readiness check that existed only to validate them. The arXiv title and abstract, the two entries the paper build needs, now live in `docs/paper/arxiv-metadata.json`, which `paper:arxiv` reads. The paper pipeline itself is unchanged: claims, arXiv source and compile, the submission bundle, and the evidence ledger all still build and verify, and the paper and ledger no longer describe the removed tooling.
81
+
3
82
  ## 2.0.0 - 2026-09-16
4
83
 
5
84
  Breaking changes: Node 20 and Node 23 are no longer supported. The SDK's `audrey.db` now exposes Audrey's SQLite adapter instead of a `better-sqlite3` instance; code using driver-specific methods must be updated. Existing memory stores need no conversion.
package/README.md CHANGED
@@ -15,19 +15,19 @@
15
15
  </p>
16
16
  </div>
17
17
 
18
- ## Your agent should remember the work, not just the chat
18
+ ## Memory before action
19
19
 
20
20
  You fix the deploy command on Monday. On Thursday, a fresh session tries the broken version again.
21
21
 
22
- You explain that this repository never commits generated files. The next agent helpfully commits them.
22
+ Audrey brings relevant project memory into the next session, checks supported tool calls before they run, and links their reported outcomes to the check that preceded them. A Guard decision carries evidence IDs you can inspect. Grounding can flag memories that reference deleted files or package scripts.
23
23
 
24
- You discover a subtle migration rule, write it down somewhere, and still have to remember to paste it into every new conversation.
24
+ Try the SQLite-backed demo before configuring a host:
25
25
 
26
- That is the gap Audrey closes.
27
-
28
- Audrey sits beside the agent and participates in the work automatically. At the start of a session it brings back a small, relevant memory packet. When you submit a prompt, it recalls project facts, preferences, procedures, and recent risks. Before a side-effectful tool runs, Audrey checks the proposed action against prior evidence. Afterward, it links the outcome back to the exact check that preceded it.
26
+ ```bash
27
+ npm exec --yes --package=audrey -- audrey demo --scenario repeated-failure
28
+ ```
29
29
 
30
- The model does not have to remember that a memory tool exists. That is the point.
30
+ The demo simulates a failed deploy, passes read-only inspection commands through the hook, and checks a proposed retry. It does not execute a deployment or change host configuration. After npm fetches the package, the demo needs no API key, model download, or network call.
31
31
 
32
32
  ## Meet Audrey Autopilot
33
33
 
@@ -60,7 +60,9 @@ Autopilot then closes the loop:
60
60
  | A tool failure is reported | Forms a durable, sanitized failure memory for the next attempt |
61
61
  | The turn stops or context compacts | Runs lightweight, due-only consolidation without holding the conversation open |
62
62
 
63
- Each hook event carries a host-declared timeout (30 seconds for the `PreToolUse` Guard check); Audrey races its own internal embedding/LLM timeout a few seconds ahead of that deadline so it can exit cleanly instead of losing the race to the host's kill. Infrastructure failures are fail-open by default: if Audrey itself errors or runs out of time, the tool call proceeds unguarded rather than freezing the session. Set `AUDREY_HOOK_FAIL_CLOSED=1` to deny the action instead when the `PreToolUse` check fails this way; other lifecycle hooks (session start, prompt recall, post-tool bookkeeping) have no "deny" to fall back to and always degrade open regardless of this setting.
63
+ An outcome reflects the tool's reported status. A zero exit code can still produce stale or incorrect output. Custom integrations can declare [required result checks](docs/SUCCESS_CHECKS.md) in `beforeAction` and supply the actual output to `afterAction`. Guard then records a mismatch as failed and an unverifiable reported success as unknown. Audrey does not generate application-specific checks or infer the expected values.
64
+
65
+ Each hook event carries a host-declared timeout (30 seconds for the `PreToolUse` Guard check). Audrey caps individual hosted embedding/LLM requests below that deadline; this is not a deadline for the entire hook, and local model initialization has no equivalent internal timeout. Errors caught by Audrey fail open by default: the hook emits no decision. Set `AUDREY_HOOK_FAIL_CLOSED=1` to deny a `PreToolUse` action on a caught error. If the host terminates the process first, the host determines what happens. Other lifecycle hooks have no deny path and always degrade open on caught errors.
64
66
 
65
67
  ## A small story about a failed deploy
66
68
 
@@ -71,21 +73,17 @@ $ npm run deploy
71
73
  Error: deployment target is missing
72
74
  ```
73
75
 
74
- Audrey keeps a redacted trace and the exact action fingerprint. If another session proposes the same action before the problem is fixed, Guard returns a denial with evidence. Change the command or fix the target and Audrey lets the work continue. Once that exact action succeeds, the old failure no longer blocks it.
76
+ Audrey keeps a redacted trace and an action fingerprint. If another session under the same agent identity proposes that action, Guard can deny the retry with evidence. A later recorded success for that fingerprint clears the exact-failure block. If the failed action declared result checks, recovery must pass the same checks. The default exact-failure window is seven days; other memory warnings are evaluated separately.
75
77
 
76
- This is more useful than “the vector search found a vaguely similar error.” Audrey creates a receipt before the action, records what happened after it, and preserves the lineage between the two.
78
+ Fixing a file or deployment target does not itself clear the block. For a deliberate retry, the Guard API accepts `acknowledgePriorFailure: true` (MCP/REST: `acknowledge_prior_failure`; CLI: `--acknowledge-prior-failure`). Autopilot also recognizes retry language in the current user prompt. Acknowledgement lowers the exact-failure block to a warning and preserves its evidence; it does not bypass separate policy warnings.
77
79
 
78
- Try the complete loop without an API key or network call:
79
-
80
- ```bash
81
- audrey demo --scenario repeated-failure
82
- ```
80
+ Guard does not yet evaluate whether a natural-language prerequisite has been satisfied. A trusted must-follow memory can keep blocking even after its suggested repair succeeds. Review the cited rule when that happens; changing a command's spelling is not proof that its underlying problem is fixed.
83
81
 
84
82
  ## Looking is not doing
85
83
 
86
- Between the failed deploy and the retry, an agent runs a lot of commands that cannot change anything: `grep` for the error, `git status`, `cat` on a config file, `ls` on a directory that turns out not to exist. A memory system that treats every one of those as a risk, or remembers `grep` finding nothing as a "failure", becomes a smoke alarm that goes off when you make toast. People stop listening, and then it is worth nothing on the day the toaster is on fire.
84
+ Inspection commands such as `grep`, `git status`, and `cat` normally need no memory check. A non-zero exit from `grep` can simply mean there was no match.
87
85
 
88
- Audrey reads the command the way an engineer would. A command whose every part is positively recognised as read-only (`grep`, `git log`, `npm view`, `docker ps`, `sed -n '1,40p'`, and their kind, with no command substitution, no redirect except to `/dev/null`, no `sudo` or `xargs`, no environment assignment that could change what the verb resolves to) never reaches the Guard at all. Its exit code is recorded but never counted as a lesson. Everything else is guarded exactly as before, and anything Audrey cannot positively recognise is treated as doing.
86
+ A command whose every part is positively recognised as read-only skips Guard. The classifier rejects command substitution, redirects other than `/dev/null`, `sudo`, `xargs`, and environment assignments that could change command resolution. Inspection outcomes can be recorded, but are excluded from failure learning. Unrecognised commands remain guarded.
89
87
 
90
88
  ```text
91
89
  $ grep -rn "prisma" src/ Guard: silent
@@ -97,11 +95,11 @@ Audrey Guard: BLOCKED
97
95
  - must_follow (high): Before running npm run deploy, run npm run db:generate because Prisma client must be generated first.
98
96
  ```
99
97
 
100
- That is the output of `audrey demo --scenario repeated-failure`, which runs the whole sequence with no API key and no network.
98
+ This excerpt illustrates the output of `audrey demo --scenario repeated-failure`.
101
99
 
102
100
  When Guard does speak, it names the memory it is speaking from, and a remembered failure is matched to the proposed command by what it runs (`npm run deploy` against `npm run deploy`), not by how similar two strings look to an embedding.
103
101
 
104
- The line between looking and doing is drawn fail-closed and was tested adversarially before release: five independent review passes ran the classifier's "read-only" verdicts against real tools and found thirteen ways to hide a write inside a command that looked harmless (`node --check -r ./x.js`, `GIT_EXTERNAL_DIFF=./x git diff`, `sort -ofile`, a backslash-newline hiding `$(`, `jobs -x`). Every one is closed and is a test case, and the fifth pass found none left. Two limits remain by design: a git configuration that already names an external program runs on any read, and a file whose name is a flag can change what a pure reader does with a glob. Both require a prior write that Guard did see.
102
+ Commands with execution-capable options or lifecycle scripts are guarded, including `git ls-remote --upload-pack=...`, `npm pack --dry-run`, and `ss -K`. The classifier is a convenience for ordinary inspection commands, not an operating-system sandbox. Repository configuration, shell expansion, and programs invoked by a reader can change what a command does. Use host permissions or a sandbox when enforcement is required.
105
103
 
106
104
  ## What Audrey remembers
107
105
 
@@ -116,11 +114,13 @@ Audrey treats memory as more than a pile of text chunks.
116
114
 
117
115
  Every context packet includes memory IDs, confidence, provenance where available, and a reason for inclusion. Uncertain or disputed memories are labeled as such. Retrieved content is wrapped with a simple rule: memory is evidence, not authority; current system and user instructions always win.
118
116
 
119
- ## When a memory stops being true
117
+ ## Checking memories against the repository
120
118
 
121
119
  Age is not the only way a memory goes wrong. A note saying "ship with `npm run deploy:prod`" is perfectly recent, well sourced, and completely wrong the day that script is deleted. Worse, every recall reinforces it, because retrieval counts as evidence that a memory is useful. A confidently stated, well-supported, false instruction is more damaging than no memory at all.
122
120
 
123
- So Audrey checks. When a memory is written, it records the claims inside it that can be verified against the project — repository-relative paths and package script names — and keeps only the ones that resolve at that moment. That last part is what makes the signal worth anything: a claim that never resolved is a guess about a typo, while a claim that resolved once and no longer does is the world moving out from under a memory that still asserts it.
121
+ Audrey checks a narrow, useful part of this problem: whether referenced repository paths and package script names still exist. When a memory is written with project context, it records only anchors that resolve at that moment. A missing anchor can then distinguish a later repository change from a reference that never resolved.
122
+
123
+ Existence does not establish correctness. A script can keep its name while changing behavior, and an intact file can contain obsolete instructions. Grounding does not execute scripts, prove a fix, or verify arbitrary claims in prose.
124
124
 
125
125
  ```bash
126
126
  audrey ground
@@ -139,25 +139,25 @@ Repair is symmetric. Restore the file or the script and the next check clears th
139
139
 
140
140
  Memories with no checkable claims are left unlabeled. Silence is not a clean bill of health, and presenting it as one would be the same mistake pointed the other way.
141
141
 
142
- ## Everything it does, and when you'd actually use it
142
+ ## Daily use
143
143
 
144
144
  Most of this runs on its own once Autopilot is installed. You do not invoke recall, and you do not invoke Guard. The table is here for the parts you would reach for deliberately, and so the automatic parts are legible rather than magic.
145
145
 
146
146
  | What | When you want it | Why it helps | How |
147
147
  |---|---|---|---|
148
148
  | **Autopilot** | Always, after one install | The whole point. Memory arrives before the agent acts instead of after you notice it went wrong. | `audrey install --host auto`, restart the host, approve hooks once |
149
- | **Guard** | Automatic, before any edit, write, or shell command that can have side effects | Checks the exact action fingerprint against prior failures. Not "something like this broke once" — this exact command, still broken. Read-only commands (`grep`, `ls`, `git status`) are not guarded, and their non-zero exits are not remembered as failures. | Runs at `PreToolUse`. Manually: `audrey guard --tool Bash --strict` |
150
- | **Grounding** | After deleting or renaming things a memory might mention | Confidence tells you a memory is well-sourced. Grounding tells you it is still true. A note about a script you deleted is confident and wrong. | `audrey ground`, or let the maintenance sweep do it |
151
- | **Session briefing** | Automatic at session start | Small, scoped packet instead of pasting context every time. Each memory injects once per session, not every prompt. | `SessionStart` hook. Preview with `audrey greeting` |
149
+ | **Guard** | Automatic, before supported edit, write, or shell tool calls | Checks action fingerprints against recorded failures and surfaces memory warnings. Recognised read-only commands skip the check. Repairing the repository alone does not clear a prior failure. | Runs at `PreToolUse`. Manually: `audrey guard --tool Bash --strict` |
150
+ | **Grounding** | After deleting or renaming things a memory might mention | Flags previously observed paths or package script names that no longer exist. | `audrey ground`, or let the maintenance sweep do it |
151
+ | **Session briefing** | Automatic at session start | Small, scoped packet instead of pasting context every time. Unchanged memories inject once per session; changes to content or standing are sent again. | `SessionStart` hook. Preview with `audrey greeting` |
152
152
  | **Explicit capture** | When you say "remember that…" or "I prefer…" | Deliberate memories are worth more than inferred ones, and phrasing it that way is enough. | Just type it. Autopilot picks up those sentence shapes |
153
153
  | **Consolidation** | Automatic when idle; manually before a long break | Repeated episodes become one principle. Otherwise the store is a pile of near-duplicates and recall gets noisy. | `audrey dream` |
154
154
  | **Contradictions** | When two memories disagree | Neither one silently wins. Both stay visible and labeled until something resolves them. | Surfaced in packets; `memory_resolve_truth` to settle one |
155
- | **Decay** | Automatic | Low-value memories fade. Reinforced ones stick around. Runs in the same sweep as consolidation. | Part of `audrey dream` |
155
+ | **Decay** | Confidence ages during recall; run maintenance to mark dormant memories | Age lowers confidence. Explicit decay can move weak memories out of active retrieval. Autopilot consolidation does not run this dormancy pass. | `audrey dream` or `memory_decay` |
156
156
  | **Promote** | When a pattern deserves to be a repo rule | Moves a learned habit out of memory and into a file your team can read and review. | `audrey promote --dry-run` first |
157
- | **Impact** | When you want to know whether any of this is working | Shows which memories were used and whether they helped. Answers "is this earning its keep". | `audrey impact --window 30` |
157
+ | **Impact** | When reviewing memory feedback | Reports explicit used/helpful/wrong feedback and frequently validated memories. It does not measure time saved or independently establish that a blocked action would have failed. | `audrey impact --window 30` |
158
158
  | **Snapshot** | Backups, or moving to a new machine | Full store in one JSON file. Import treats it as untrusted: redacted and stripped of trust markers on the way in. | `AUDREY_ENABLE_ADMIN_TOOLS=1`, then `memory_export` / `memory_import` |
159
159
  | **Doctor** | Packets stopped arriving | The two real causes are a drifted hook entrypoint and starved consolidation. Doctor names which one. | `audrey doctor` |
160
- | **Demo** | Before trusting any of this | Runs the whole loop with no API key and no network. Nothing to configure to see it work. | `audrey demo --scenario repeated-failure` |
160
+ | **Demo** | Before configuring a host | Exercises a simulated failure and blocked retry in temporary SQLite storage, with no API key or network call. | `audrey demo --scenario repeated-failure` |
161
161
  | **REST sidecar** | Custom agents that are not Codex or Claude Code | Same memory runtime, same evidence contract, over HTTP. Python and JS clients included. | `audrey serve` with `AUDREY_API_KEY` set |
162
162
 
163
163
  ## What Audrey deliberately does not do
@@ -176,7 +176,7 @@ Guard checks memory at the point where it can change an action, not after the da
176
176
 
177
177
  ### Continuity across agent sessions
178
178
 
179
- Audrey is not tied to one model vendor. Codex and Claude Code use the same memory runtime and the same evidence contract. MCP, REST, JavaScript, and Python clients make the core usable in custom agents too.
179
+ Codex and Claude Code use the same memory runtime and evidence contract. Generated configurations use separate `codex` and `claude-code` agent identities, so they do not automatically recall each other's memories. Cross-agent Autopilot recall requires the explicit `AUDREY_AUTOPILOT_SCOPE=shared` setting in the host runtime environment; this broadens recall across the store. MCP, REST, JavaScript, and Python clients make the core usable in custom agents too.
180
180
 
181
181
  ### Evidence a human can inspect
182
182
 
@@ -188,30 +188,14 @@ The default store is SQLite, FTS5, and `sqlite-vec`. Local embeddings are the de
188
188
 
189
189
  ### A safer shared store
190
190
 
191
- Agent-scoped recall now continues through validation, contradiction detection, interference, affect, failure lookup, capsules, greetings, Guard, and REST request routing. Hidden retrieval candidates do not reinforce themselves; only memories actually surfaced to the caller receive retrieval bookkeeping (usage count and last-reinforced timestamp for semantic and procedural memories). Explicit validation feedback (`memory_validate` / `/v1/validate`) separately adjusts salience based on how a memory actually performed, not merely on being recalled.
191
+ Agent-scoped recall continues through validation, contradiction detection, interference, affect, failure lookup, capsules, greetings, Guard, and REST request routing. Recall updates retrieval count and last-reinforced timestamp for returned semantic and procedural memories. Capsule and Guard filtering may further narrow those results. Explicit validation feedback (`memory_validate` / `/v1/validate`) separately updates usage and salience from a caller's used/helpful/wrong assessment.
192
192
 
193
193
  Vector candidates are partitioned by agent before nearest-neighbor ranking, so one busy agent cannot crowd another out of a bounded search. For hard tenant boundaries, still use a distinct `AUDREY_DATA_DIR` per tenant or security domain.
194
194
 
195
- ## See it before installing anything
196
-
197
- ```bash
198
- npm exec --yes --package=audrey -- audrey demo --scenario repeated-failure
199
- ```
200
-
201
- That command runs from the npm cache, exercises the full SQLite-backed Guard loop, and leaves host configuration unchanged.
202
-
203
195
  <div align="center">
204
196
  <img src="docs/assets/audrey-feature-grid.jpg" alt="Audrey memory continuity, recall, evidence, local storage, and memory-before-action" width="760">
205
197
  </div>
206
198
 
207
- ## Where we want to take it
208
-
209
- The ambition is a temporal evidence graph for agents: immutable observations, explicit validity windows, source trust, evolving claims, scoped procedures, and outcome-calibrated policy. The defensible part is not storing more text. It is knowing what was believed, why, in which context, for how long, and whether acting on it helped.
210
-
211
- Near-term work includes durable background cognition jobs, tenant namespaces bound to credentials, memory quarantine and taint propagation, public long-horizon evaluations, encrypted backup options, and a persistent local daemon that removes per-hook model startup entirely.
212
-
213
- If that is the kind of agent infrastructure you want to build, open an issue or start with the demo. Audrey is MIT licensed, and the product boundary is intentionally inspectable.
214
-
215
199
  ---
216
200
 
217
201
  ## Technical reference
@@ -258,7 +242,7 @@ Claude Code scope mapping follows the host’s terminology:
258
242
 
259
243
  Codex supports project `.codex/hooks.json` and user `~/.codex/hooks.json`; it has no local hook scope. Audrey preserves unrelated hooks, replaces older Audrey-owned handlers, writes a private timestamped backup, and is idempotent on repeat installation. Project-adjacent backup names match `*.audrey-*.bak`; keep that pattern ignored because a host config can contain unrelated credentials.
260
244
 
261
- Audrey respects `CLAUDE_CONFIG_DIR` and `CODEX_HOME`. Generated hooks pin the stable Node executable, Audrey entrypoint, data directory, agent identity, and non-secret provider choices used at install time. With local embeddings, an Autopilot install performs one warmup so the first real hook is not also the first model load; set `AUDREY_DISABLE_WARMUP=1` to skip it.
245
+ Audrey respects `CLAUDE_CONFIG_DIR` and `CODEX_HOME`. Generated hooks pin the stable Node executable, Audrey entrypoint, data directory, agent identity, and non-secret provider choices used at install time. With local embeddings, an Autopilot install warms the model cache; set `AUDREY_DISABLE_WARMUP=1` to skip it. Each hook still runs in a new process and initializes an embedding pipeline when needed, so cached model files do not eliminate startup latency.
262
246
 
263
247
  Generate MCP configuration without applying it:
264
248
 
@@ -297,7 +281,7 @@ Codex hook interception is a guardrail, not a complete shell-policy boundary. Th
297
281
  ### JavaScript API
298
282
 
299
283
  ```js
300
- import { Audrey, MemoryController } from 'audrey';
284
+ import { Audrey } from 'audrey';
301
285
 
302
286
  const memory = new Audrey({
303
287
  dataDir: './audrey-data',
@@ -317,15 +301,19 @@ const capsule = await memory.capsule('increase Stripe throughput', {
317
301
  budgetChars: 3000,
318
302
  });
319
303
 
320
- const guard = new MemoryController(memory);
321
- const before = await guard.beforeAction({
322
- action: 'deploy the billing worker',
304
+ const before = await memory.beforeAction('npm run deploy:billing', {
323
305
  tool: 'Bash',
324
- command: 'npm run deploy:billing',
325
306
  cwd: process.cwd(),
307
+ strict: true,
326
308
  });
327
309
 
328
- console.log(before.decision, before.evidenceIds);
310
+ console.log(before.decision, before.evidence_ids, before.receipt_id);
311
+ // Only execute an authorized action when before.ok_to_proceed is true.
312
+ // After execution, close this receipt with memory.afterAction({
313
+ // receiptId: before.receipt_id, outcome: 'succeeded' | 'failed' | 'unknown',
314
+ // errorSummary: '...' // when available
315
+ // });
316
+ // Report the observed outcome; creating a receipt does not execute the action.
329
317
  await memory.closeAsync();
330
318
  ```
331
319
 
@@ -376,7 +364,7 @@ episode
376
364
  ├─ agent-scoped interference / resonance / validation
377
365
  ├─ reinforcement or contradiction evidence
378
366
  ├─ sleep-time consolidation into semantic or procedural memory
379
- └─ grounding checks that stored claims still hold in the project
367
+ └─ grounding rechecks recorded paths and package-script names
380
368
 
381
369
  query
382
370
  ├─ bounded vector candidates
@@ -404,18 +392,24 @@ The server also sends host instructions explaining the Guard receipt loop when l
404
392
 
405
393
  | Variable | Default | Purpose |
406
394
  |---|---|---|
395
+ | `AUDREY_MODEL_CACHE_DIR` | `$XDG_CACHE_HOME/audrey/models` or `~/.cache/audrey/models` | Writable per-user cache for local model files |
396
+ | `AUDREY_SHARED_STORE` | `0` | Set `1` to retain operator-managed permissions for an intentionally shared store |
407
397
  | `AUDREY_DATA_DIR` | `~/.audrey/data` | SQLite store; use a distinct directory per tenant/security boundary |
408
398
  | `AUDREY_AGENT` | host-specific | Logical memory owner used for scoped operations |
409
399
  | `AUDREY_EMBEDDING_PROVIDER` | `local` | `local`, `gemini`, `openai`, or `mock` |
410
- | `AUDREY_LLM_PROVIDER` | unset | `anthropic`, `openai`, or `mock` for reflection/consolidation; unset (or `auto`) uses local heuristics only, never an ambient `ANTHROPIC_API_KEY`/`OPENAI_API_KEY` |
400
+ | `AUDREY_LLM_PROVIDER` | unset | `anthropic`, `openai` (API billing), `chatgpt` (subscription), or `mock` for reflection/consolidation; unset (or `auto`) uses local heuristics only, never an ambient API key |
411
401
  | `AUDREY_LLM_MODEL` | provider default | Explicit LLM model override |
402
+ | `AUDREY_LLM_REASONING_EFFORT` | `medium` | OpenAI reasoning effort: `low`, `medium`, `high`, `xhigh`, or `max` |
403
+ | `AUDREY_CHATGPT_AUTH_DIR` | `~/.audrey/auth` | Protected local subscription credential directory |
404
+ | `AUDREY_CHATGPT_ACCOUNT` | active account | Saved subscription registration to use |
412
405
  | `AUDREY_DEVICE` | `gpu` | Local embedding device; falls back to CPU |
413
406
  | `AUDREY_CONTEXT_BUDGET_CHARS` | `4000` | Maximum default capsule size |
414
407
  | `AUDREY_AUTOPILOT_SCOPE` | `agent` | `agent` or explicit cross-agent `shared` recall for hooks |
415
408
  | `AUDREY_PACKET_FORMAT` | `compact` | Injected packet style: `compact` line format or `verbose` key=value |
416
- | `AUDREY_PACKET_DELTA` | `1` | Inject each memory once per session; `0` resends full packets every prompt |
409
+ | `AUDREY_PACKET_DELTA` | `1` | Inject each unchanged memory version once per session; `0` resends full packets every prompt |
417
410
  | `AUDREY_HOOK_FAIL_CLOSED` | `0` | Deny guarded actions when Audrey itself fails |
418
411
  | `AUDREY_API_KEY` | unset | Bearer token for REST access |
412
+ | `AUDREY_ALLOW_NO_AUTH` | `0` | Set `1` to permit unauthenticated non-loopback REST access |
419
413
  | `AUDREY_HOST` | `127.0.0.1` | REST bind address |
420
414
  | `AUDREY_PORT` | `7437` | REST port |
421
415
  | `AUDREY_ENABLE_ADMIN_TOOLS` | `0` | Enable export, import, forget, and promote operations |
@@ -426,6 +420,18 @@ The server also sends host instructions explaining the Guard receipt loop when l
426
420
 
427
421
  Provider secrets are never embedded in generated hook commands. `--include-secrets` applies only to MCP registration; prefer host environment injection or a secret manager.
428
422
 
423
+ OpenAI API billing uses `AUDREY_LLM_PROVIDER=openai` and `OPENAI_API_KEY`. To use a ChatGPT subscription for reflection and consolidation, run `audrey auth login`, then set `AUDREY_LLM_PROVIDER=chatgpt`, `AUDREY_LLM_MODEL=gpt-6.1-sol`, and `AUDREY_LLM_REASONING_EFFORT=medium`. Reinstall the host configuration after changing provider settings. Subscription requests require account permission and an available model; failures never switch to API billing. Embeddings remain a separate provider and default to local execution. See [OpenAI's subscription documentation](https://developers.openai.com/siwc/token-sharing-open-source).
424
+
425
+ Use `audrey auth accounts` to list saved registrations, `audrey auth select --account <ID>` to switch, and `audrey auth logout` to sign out. Tokens stay in protected local storage outside the memory database. `audrey auth status` reports connection state without exposing tokens.
426
+
427
+ New local stores use private directory and database permissions on filesystems that support POSIX modes. Existing database and WAL files are restricted on open. Windows and mounted volumes need appropriate operating-system ACLs. Set `AUDREY_SHARED_STORE=1` (SDK: `sharedStore: true`) only when you manage shared access yourself.
428
+
429
+ Local models download into the per-user cache on first use. Allow that first run to finish before relying on hooks offline. A failed initialization can be retried in the same process. For a system package installed by root, run the initial model load as the desktop user so the cache remains writable.
430
+
431
+ Snapshot format 2 preserves grounding anchors, their last known state, and consolidation undo journals; older snapshots remain importable. Worktrees share a repository identity for recall, while grounding checks the checkout where an anchor was recorded. Rollback preserves earlier knowledge when undoing a merge. Legacy merges without an undo journal are refused when they cannot be reversed safely.
432
+
433
+ The REST API requires JSON request bodies and rejects cross-origin browser requests. Unauthenticated requests require a loopback host unless `AUDREY_ALLOW_NO_AUTH=1` is explicitly set. Configure `AUDREY_API_KEY` for network deployments.
434
+
429
435
  ### Production checklist
430
436
 
431
437
  - Give every tenant or hard isolation domain its own `AUDREY_DATA_DIR`.
@@ -460,7 +466,7 @@ GuardBench currently contains ten local, deterministic pre-action scenarios cove
460
466
  Latest local result in this checkout: 10/10 scenarios passed, 100% prevention rate, 0% false-block rate, 0 raw secret leaks, 0 published artifact leaks, and 3.805ms / 13.445ms p50/p95 Guard latency under the mock-provider methodology.
461
467
  <!-- guardbench-summary:end -->
462
468
 
463
- `benchmarks/perf-snapshot.js` measures encode and hybrid-recall p50/p95/p99 at configurable corpus sizes with machine and provider provenance. Run it on the hardware and embedding provider you plan to operate; hosted-provider latency is dominated by its network round trip.
469
+ `benchmarks/perf-snapshot.js` measures encode and hybrid-recall p50/p95/p99 at configurable corpus sizes with machine provenance. It currently uses mock 64-dimensional embeddings; it has no provider-selection flag and does not measure hook process startup. Measure complete hook invocations separately with your intended provider, cache state, corpus, and hardware before using these numbers to estimate interactive latency.
464
470
 
465
471
  The longer-term public evaluation target includes [LongMemEval](https://arxiv.org/abs/2410.10813), [MemoryAgentBench](https://arxiv.org/abs/2507.05257), and adversarial memory-poisoning cases. Relevant design directions include bitemporal knowledge graphs in [Zep/Graphiti](https://arxiv.org/abs/2501.13956), evolving memory organization in [A-MEM](https://arxiv.org/abs/2502.12110), and sleep-time agent compute in [Sleep-time Compute](https://arxiv.org/abs/2504.13171).
466
472
 
@@ -490,8 +496,6 @@ npm run bench:guard:external:evidence:strict
490
496
 
491
497
  npm run paper:arxiv:compile
492
498
  npm run paper:arxiv:compile:strict
493
- npm run paper:launch-results
494
- npm run paper:launch-results:strict
495
499
 
496
500
  npm run release:cut:plan
497
501
  npm run release:cut:apply
@@ -502,6 +506,6 @@ npm run python:release:check
502
506
 
503
507
  Live Zep runs require `ZEP_API_KEY`; `ZEP_GUARDBENCH_INGEST_DELAY_MS` tunes ingestion settling time. The external dry-run matrix proves adapter shape without credentials, while external evidence verification distinguishes pending runs from verified live evidence.
504
508
 
505
- Publication packaging performs an absolute-path sweep, reserves an X URL reserve in social copy, and checks submitted artifact-url targets. Release readiness separately reports source-control state, live remote-head verification, npm registry/auth readiness, and PyPI publish readiness.
509
+ Publication packaging verifies artifact hashes, source bundles, and path redaction. Release readiness separately reports source-control state, live remote-head verification, npm registry/auth readiness, and PyPI publish readiness. Pass `-- --target-version <version>` to the readiness commands when checking a release; the script's legacy default is `1.1.1`.
506
510
 
507
511
  MIT licensed. Built for agents that should get better at the work without becoming less accountable.
package/SECURITY.md CHANGED
@@ -6,9 +6,8 @@ Security fixes are best-effort for the current published release line and the cu
6
6
 
7
7
  | Version | Supported |
8
8
  |---|---|
9
- | `1.1.x` | Yes |
10
- | `1.0.x` | Best effort |
11
- | `< 1.0.0` | No |
9
+ | `2.0.x` and `master` | Yes |
10
+ | `< 2.0.0` | No |
12
11
 
13
12
  ## Reporting a Vulnerability
14
13
 
@@ -1,5 +1,5 @@
1
1
  import type { AudreyConfig, EmbeddingConfig, LLMConfig } from '../src/types.js';
2
- export declare const VERSION = "2.0.0";
2
+ export declare const VERSION = "2.1.1";
3
3
  export declare const SERVER_NAME = "audrey-memory";
4
4
  export declare const DEFAULT_AGENT = "local-agent";
5
5
  export declare const DEFAULT_DATA_DIR: string;
@@ -29,16 +29,6 @@ export declare function resolveDataDir(env?: Record<string, string | undefined>)
29
29
  export declare function resolveEmbeddingProvider(env: Record<string, string | undefined>, explicit?: string | undefined): EmbeddingConfig & {
30
30
  dimensions: number;
31
31
  };
32
- /**
33
- * Resolves which LLM provider to use for principle extraction / reflection.
34
- * Priority: explicit config -> none (local heuristics only).
35
- * Cloud providers are never auto-selected from ambient API keys: memory
36
- * content is sent to the provider verbatim (buildPrincipleExtractionPrompt),
37
- * so leaving AUDREY_LLM_PROVIDER unset (or 'auto') must never cause content
38
- * to leave the machine just because ANTHROPIC_API_KEY/OPENAI_API_KEY happens
39
- * to be set for some unrelated tool. Choose a cloud provider explicitly with
40
- * AUDREY_LLM_PROVIDER=anthropic|openai.
41
- */
42
32
  export declare function resolveLLMProvider(env: Record<string, string | undefined>, explicit?: string | undefined, options?: {
43
33
  requireApiKey?: boolean;
44
34
  }): (LLMConfig & {
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../mcp-server/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../mcp-server/config.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { homedir } from 'node:os';
2
- import { join } from 'node:path';
2
+ import { isAbsolute, join, resolve } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
- export const VERSION = '2.0.0';
4
+ export const VERSION = '2.1.1';
5
5
  export const SERVER_NAME = 'audrey-memory';
6
6
  export const DEFAULT_AGENT = 'local-agent';
7
7
  export const DEFAULT_DATA_DIR = join(homedir(), '.audrey', 'data');
@@ -17,7 +17,7 @@ export const HOST_AGENT_NAMES = {
17
17
  jetbrains: 'jetbrains',
18
18
  };
19
19
  const VALID_EMBEDDING_PROVIDERS = new Set(['mock', 'local', 'gemini', 'openai']);
20
- const VALID_LLM_PROVIDERS = new Set(['mock', 'anthropic', 'openai']);
20
+ const VALID_LLM_PROVIDERS = new Set(['mock', 'anthropic', 'openai', 'chatgpt']);
21
21
  function assertValidProvider(provider, validProviders, envVar) {
22
22
  if (!validProviders.has(provider)) {
23
23
  throw new Error(`Unsupported ${envVar} value: ${provider}`);
@@ -72,6 +72,12 @@ export function resolveEmbeddingProvider(env, explicit = env['AUDREY_EMBEDDING_P
72
72
  * to be set for some unrelated tool. Choose a cloud provider explicitly with
73
73
  * AUDREY_LLM_PROVIDER=anthropic|openai.
74
74
  */
75
+ /** A ~ prefix expands to the home directory; a relative path resolves now, not per hook. */
76
+ function absoluteAuthDir(value) {
77
+ const expanded = value.replace(/^~(?=$|[\\/])/, homedir());
78
+ // A Windows drive path is absolute even when this runs on another platform.
79
+ return isAbsolute(expanded) || /^[A-Za-z]:[\\/]/.test(expanded) ? expanded : resolve(expanded);
80
+ }
75
81
  export function resolveLLMProvider(env, explicit = env['AUDREY_LLM_PROVIDER'], options = {}) {
76
82
  const { requireApiKey = true } = options;
77
83
  const model = env['AUDREY_LLM_MODEL']?.trim() || undefined;
@@ -81,6 +87,24 @@ export function resolveLLMProvider(env, explicit = env['AUDREY_LLM_PROVIDER'], o
81
87
  }
82
88
  assertValidProvider(explicit, VALID_LLM_PROVIDERS, 'AUDREY_LLM_PROVIDER');
83
89
  const provider = explicit;
90
+ const effort = env['AUDREY_LLM_REASONING_EFFORT']?.trim() || 'medium';
91
+ if (!['low', 'medium', 'high', 'xhigh', 'max'].includes(effort)) {
92
+ throw new Error(`Unsupported AUDREY_LLM_REASONING_EFFORT value: ${effort}`);
93
+ }
94
+ const reasoningEffort = effort;
95
+ if (provider === 'chatgpt') {
96
+ return {
97
+ provider,
98
+ model: model || 'gpt-6.1-sol',
99
+ reasoningEffort,
100
+ // Resolved here so hook commands carry an absolute path: each hook runs
101
+ // in its own working directory, and JSON host configs expand no ~.
102
+ ...(env['AUDREY_CHATGPT_AUTH_DIR']
103
+ ? { authDir: absoluteAuthDir(env['AUDREY_CHATGPT_AUTH_DIR']) }
104
+ : {}),
105
+ ...(env['AUDREY_CHATGPT_ACCOUNT'] ? { chatgptAccount: env['AUDREY_CHATGPT_ACCOUNT'] } : {}),
106
+ };
107
+ }
84
108
  if (provider === 'anthropic') {
85
109
  const apiKey = env['ANTHROPIC_API_KEY'];
86
110
  if (requireApiKey && !apiKey) {
@@ -93,7 +117,12 @@ export function resolveLLMProvider(env, explicit = env['AUDREY_LLM_PROVIDER'], o
93
117
  if (requireApiKey && !apiKey) {
94
118
  throw new Error('AUDREY_LLM_PROVIDER=openai requires OPENAI_API_KEY to be set.');
95
119
  }
96
- return { provider: 'openai', apiKey, ...withModel };
120
+ return {
121
+ provider: 'openai',
122
+ apiKey,
123
+ ...(env['AUDREY_LLM_REASONING_EFFORT'] ? { reasoningEffort } : {}),
124
+ ...withModel,
125
+ };
97
126
  }
98
127
  return { provider: 'mock' };
99
128
  }
@@ -157,6 +186,12 @@ export function buildAudreyMcpEnv(env = process.env, agent = env['AUDREY_AGENT']
157
186
  addEnv('AUDREY_LLM_PROVIDER', llm.provider);
158
187
  if (llm.model)
159
188
  addEnv('AUDREY_LLM_MODEL', llm.model);
189
+ if (llm.reasoningEffort)
190
+ addEnv('AUDREY_LLM_REASONING_EFFORT', llm.reasoningEffort);
191
+ if (llm.provider === 'chatgpt') {
192
+ addEnv('AUDREY_CHATGPT_AUTH_DIR', llm.authDir);
193
+ addEnv('AUDREY_CHATGPT_ACCOUNT', llm.chatgptAccount);
194
+ }
160
195
  if (llm.provider === 'anthropic') {
161
196
  if (includeSecrets)
162
197
  addEnv('ANTHROPIC_API_KEY', llm.apiKey);
@@ -175,6 +210,9 @@ const AUTOPILOT_RUNTIME_FLAGS = {
175
210
  AUDREY_DEVICE: '--device',
176
211
  AUDREY_LLM_PROVIDER: '--llm-provider',
177
212
  AUDREY_LLM_MODEL: '--llm-model',
213
+ AUDREY_LLM_REASONING_EFFORT: '--llm-reasoning-effort',
214
+ AUDREY_CHATGPT_AUTH_DIR: '--chatgpt-auth-dir',
215
+ AUDREY_CHATGPT_ACCOUNT: '--chatgpt-account',
178
216
  };
179
217
  export function buildAutopilotRuntimeArgs(env = process.env, agent = env['AUDREY_AGENT'] || DEFAULT_AGENT) {
180
218
  const runtime = buildAudreyMcpEnv(env, agent, { includeSecrets: false });