{"id":51682216,"url":"https://github.com/hjqcan/GoodMemory","last_synced_at":"2026-07-23T02:00:57.656Z","repository":{"id":349829815,"uuid":"1189746863","full_name":"hjqcan/GoodMemory","owner":"hjqcan","description":"Local-first, auditable memory layer for AI apps and coding agents — Codex, Claude Code, MCP, HTTP, TypeScript, and Python.","archived":false,"fork":false,"pushed_at":"2026-07-22T02:22:40.000Z","size":16420,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-22T03:26:28.973Z","etag":null,"topics":["agent-memory","ai-agents","claude-code","codex","coding-agents","developer-tools","hooks","llm-memory","local-first","long-term-memory","mcp","mcp-server","memory","open-source","postgres","sqlite","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/goodmemory","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hjqcan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-23T16:18:00.000Z","updated_at":"2026-07-22T02:22:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hjqcan/GoodMemory","commit_stats":null,"previous_names":["hjqcan/goodmemory"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/hjqcan/GoodMemory","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjqcan%2FGoodMemory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjqcan%2FGoodMemory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjqcan%2FGoodMemory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjqcan%2FGoodMemory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hjqcan","download_url":"https://codeload.github.com/hjqcan/GoodMemory/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjqcan%2FGoodMemory/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35784494,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-23T02:00:06.683Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-memory","ai-agents","claude-code","codex","coding-agents","developer-tools","hooks","llm-memory","local-first","long-term-memory","mcp","mcp-server","memory","open-source","postgres","sqlite","typescript"],"created_at":"2026-07-15T15:00:23.498Z","updated_at":"2026-07-23T02:00:57.580Z","avatar_url":"https://github.com/hjqcan.png","language":"TypeScript","funding_links":[],"categories":["CLIs","💿 Products"],"sub_categories":["Usage","Open-Source"],"readme":"# GoodMemory\n\nLanguage: English | [简体中文](./README.zh-CN.md)\n\nGoodMemory is a memory layer for AI products and coding agents.\n\n\u003e **Release source:** this is the immutable `0.7.0` stable release source.\n\u003e Registry commands require `goodmemory@0.7.0` to be published. The release\n\u003e workflow verifies npm `latest` and artifact integrity before creating the\n\u003e GitHub Release.\n\nIt gives chat apps, copilots, and agent hosts a durable user/project memory loop:\nwrite selected facts, retrieve the right context, inject it into the next turn,\naudit what happened, and delete it when it is wrong.\n\nGoodMemory is not an LLM, agent framework, vector database, or generic RAG\nsystem. It is the product memory layer between your app or installed agent host\nand the model runtime.\n\n## What You Get\n\n- Durable memory API: `remember`, `recall`, `buildContext`, `feedback`, `forget`,\n  `exportMemory`, and `deleteAllMemory`.\n- Installed agent memory for Codex and Claude Code through `goodmemory setup`,\n  managed hooks, installed Codex pre-action, `goodmemory status`, read-only\n  MCP, and opt-in writeback.\n- Public write customization with `GoodMemoryConfig.remember`,\n  `RememberProfile`, `rememberRules`, `RememberInput.annotations`, and named\n  extractor ids.\n- Package exports for `goodmemory`, `goodmemory/ai-sdk`, `goodmemory/host`,\n  and `goodmemory/http` through compiled `dist` artifacts and TypeScript\n  declarations.\n- Local-first storage: Bun gets durable SQLite by default; explicit Postgres,\n  injected adapters, and embedding providers can be added when needed.\n- Evaluation and release evidence paths for deterministic tests, live evals,\n  provider-backed evals, package smoke tests, and quality gates.\n\n## OpenAI Build Week 2026\n\n**Pre-existing foundation.** GoodMemory existed before OpenAI Build Week. The\npre-event foundation already included the core memory API, local\nSQLite/Postgres storage, installed-host integration, and the local Inspector.\nThe hackathon entry is the work added after the submission period opened on\nJuly 13, 2026, not the entire repository.\n\n**Added during Build Week.** Dated commits completed and published `v0.6.0`,\nstrengthened generalized retrieval and iterative-recall verification, added\nclaim-source provenance coverage, hardened installed-host canaries and leakage\naudits, and expanded the controlled Codex coding-effect evaluation path. Review\nthe [pre-event-to-Build-Week diff](https://github.com/hjqcan/GoodMemory/compare/373e1f9a...5d7639a8)\nand its dated commit history for the exact boundary.\n\n**How Codex and GPT-5.6 were used.** Codex with GPT-5.6 was the primary\nimplementation and verification environment: exploring the repository,\nimplementing and reviewing changes, writing regression tests, reproducing\ninstalled-host behavior, and exercising the release and coding-effect evidence\npaths. GPT-5.6 also powers disclosed non-judge model calls in current evaluation\nprofiles; public-claim paths either use deterministic scoring or keep the judge\nindependent from the answer model.\n\n**Run and verify.** Install the submitted release and inspect its local memory\nsurface:\n\n```bash\nnpm install -g goodmemory@0.7.0\ngoodmemory setup --host codex\ngoodmemory status codex --workspace-root .\ngoodmemory inspector serve\n```\n\nVerify the repository from source with `bun install --frozen-lockfile`,\n`bun test`, and `bun run typecheck`. See the\n[Devpost submission](https://devpost.com/software/goodmemory) and\n[public demo video](https://youtu.be/xK663ultN5o).\n\n**Claim boundary:** the submission demonstrates durable cross-session memory,\ngoverned writeback, recall evidence, and inspection/deletion infrastructure. It\ndoes not claim that GoodMemory has already proven an improvement in Codex\ncoding outcomes; that paired hidden-test evaluation remains an active,\nfail-closed evidence track.\n\n## Start Here: Codex Or Claude Code\n\n```bash\nnpm install -g goodmemory@0.7.0\ngoodmemory setup\n```\n\nNo account or hosted service is required. GoodMemory stores memory locally in\nSQLite by default, wires lifecycle hooks plus read-only MCP inspection, and\nkeeps durable writeback opt-in. Verify the installation with\n`goodmemory status`.\n\nUsing another MCP client or integrating an application? [Choose an integration\npath](#choose-your-integration-path).\n\n## Benchmark Results\n\nGoodMemory separates current-production claims, versioned historical evidence,\nand internal research. A number may enter the current-claims table only after\n`gate:public-benchmark-claim --strict` validates a committed declaration for\nthe current package version: complete coverage, `executionFailures: 0`, a\nno-memory baseline, deterministic scoring or an independent judge, verified\ndataset source and license, and a reproducible run (commit + command + package\nversion). Historical rows remain under separate markers and cannot satisfy the\ncurrent-version gate.\n\nThe Phase 72 benchmark and versioned release gates remain closed evidence for\n`v0.6.0`. The rows below preserve those version-pinned public-opt-in results for\nthe disclosed provider-backed or evidence-pack profiles. Because `v0.7.0`\nchanges LanguagePack and recall semantics, they remain historical 0.6 evidence,\nnot 0.7 performance claims or claims about the zero-provider default; no row is\npromoted as a current `v0.7.0` claim until a fresh run passes the same gate.\nLongMemEval's newer label-free verifier result and ImplicitMemBench's retry-merged\nresult remain internal evidence because their current paths are eval-only or do\nnot replace a monolithic fresh run. HaluMem, MemGym, and MINTEval remain release\nevidence rather than public benchmark claims.\n\n\u003c!-- current-claims-table:start --\u003e\n| Benchmark | Primary metric | GoodMemory result | Baseline / reference | Claim declaration |\n|---|---|---:|---:|---|\n\u003c!-- current-claims-table:end --\u003e\n\n### Versioned internal evidence\n\nThese rows are versioned attestations with tracked source fingerprints for the\ndisclosed package version and runtime profile. Reproduction also requires the\nreferenced raw artifacts, which are not all stored in the Git tree. They are\nnot current-production claims for `v0.7.0`.\n\n\u003c!-- historical-evidence-table:start --\u003e\n| Benchmark | Primary metric | GoodMemory result | Baseline / reference | Claim declaration |\n|---|---|---:|---:|---|\n| LoCoMo v0.6.0 (full 10 conversations) | independent official judge protocol; strict deterministic token-F1 | official **0.8708** · strict **0.6299** · open-domain **0.6146** (59/96) | historical no-memory 0.0045 | [locomo.json](./benchmark-claims/locomo.json) |\n| BEAM 100K v0.6.0 (400 questions, 1051 rubric items) | independent official unified rubric; strict binary disclosed separately | unified **0.7651** · strict **0.620** (248/400) · generalized recall **0.8276** | public full-400 same-protocol reference 0.49 | [beam.json](./benchmark-claims/beam.json) |\n| MemoryAgentBench v0.6.0 (CR, TTL) | deterministic upstream match-mode scoring, judge-free | **CR 0.959, TTL 0.933** | no-memory 0.000 for both | [memoryagentbench.json](./benchmark-claims/memoryagentbench.json) |\n| LongMemEval full 500 | strict: judge-free deterministic subset · diagnostic: official-prompt-compatible LongMemEval judge | strict **0.720** (360/500) · prompt-compatible **0.888** (444/500), `goodmemory-rules-only` | no-memory 0.068; current Mem0 harness: 94.4 Top200 / 94.8 Top50 (different stack and budget) | [longmemeval.json](./benchmark-claims/longmemeval.json) |\n| ImplicitMemBench Full-300 | stored-answer cross-version judge rescore | **0.691** (207.35/300), gpt-5.4 judge over gpt-5.5 answers, sourceAnswersUnchanged | upstream-chat baseline **0.400** (120/300); reference line 0.66 | [implicitmembench.json](./benchmark-claims/implicitmembench.json) |\n\u003c!-- historical-evidence-table:end --\u003e\n\nWhere both are available, a row reports two tracks. The\n**strict** track is deterministic or judge-free — a hard lower bound no LLM\njudge can inflate. The second track re-judges the *same stored answers* (not\nregenerated) under a benchmark-source or industry-standard prompt. Numerical\ncomparability is claimed only when the pinned evaluator model and remaining\nbenchmark configuration also match. LongMemEval's gpt-5.4/gpt-5.5 diagnostics\nare outside the pinned evaluator model zoo and are therefore\nprompt-compatible, not directly comparable to published official scores.\nEvery per-protocol detail is recorded in the linked declarations.\n\nThe historical LongMemEval strict result is judge-free, replacing an earlier\ninternal with-judge number (0.908) that is superseded and not claimable. A case counts as correct\nonly when a deterministic method scores it (abstention / exact / contains /\nexpected_alternative / numeric_count); the eval pipeline's same-model semantic\njudge (gpt-5.5 judging gpt-5.5) is excluded by construction — with it, the\ndiagnostic overall accuracy is 0.896, reported for transparency but not\nclaimed. The recorded 0.720 (360/500, `executionFailures: 0`, v0.3.5) uses the\nembedding-free `goodmemory-rules-only` profile; abstention contributes only 28\nof the 360 correct answers, while the no-memory baseline's 0.068 is mostly bare\nabstention (30 of its 34 correct), so the +65.2-point lift is the memory\nsystem's contribution. Judge-free refers to scoring — answers are still\ngenerated by gpt-5.5. Full provenance is in the\n[claim declaration](./benchmark-claims/longmemeval.json).\nThe historical v0.6.0 MemoryAgentBench evidence is deliberately scoped. It uses\n`gpt-5.6-terra` answers and deterministic, judge-free upstream match-mode\nscoring. Conflict Resolution scores CR 0.959 (70/73) and Test-Time Learning\nscores TTL 0.933 (28/30), while the no-memory arm scores `0.000` on both.\nAccurate Retrieval (AR) and Long-Range Understanding (LRU) are excluded because\nprior controls did not establish a memory lift; the claim does not average in\nmultiple-choice wins that can be answered without memory.\n\nThe historical v0.6.0 LoCoMo evidence covers all 1540 non-adversarial questions with\n`executionFailures: 0`. It uses `gpt-5.6-terra` for answers, conversational\nextraction, and provider reranking, then uses an independent `gpt-5.5` judge\nfor the official-protocol track. Official accuracy is 0.8708, strict\ndeterministic token-F1 is 0.6299, and open-domain is 59/96 = 0.6146 versus the\nhistorical no-memory 0.0045. This is the public-opt-in recommended\nprovider-embedding profile, not the embedding-free default. The LoCoMo dataset\nis CC BY-NC 4.0 (non-commercial scope), fetched at eval time, and never\nvendored.\n\nThe historical v0.6.0 BEAM evidence uses `gpt-5.6-terra` answers and an independent\n`gpt-5.5` judge. The generalized path disables all 148 legacy narrow gates and\nlegacy fitted answer postprocessing. It reaches 0.8276 evidence recall and\n0.7651 over all 400 questions and 1051 official rubric items, versus the public\nsame-protocol reference 0.49, with zero execution and judge failures. The\nstrict binary score remains disclosed at 0.620 (248/400), and the upstream\npaper-protocol score remains disclosed at 0.7510. The frozen `event_ordering`\naudit found 7/40 cases with non-chronological official evidence order and one\nrequested-item/rubric mismatch, so 0.72 strict and 0.80 unified remain stretch\ndiagnostics rather than hidden failures. Dataset CC BY-SA 4.0, fetched at eval\ntime, and never vendored.\n\nThe historical ImplicitMemBench Full-300 declaration uses the canonical zero-failure\n`run-phase61-full300-rerun-20260706-codex-current` answers, then re-scores the\nsame stored answers with gpt-5.4 (`sourceAnswersUnchanged: true`). The judge is\ncross-version but the same GPT family as the gpt-5.5 answer model, not a\ncross-family judge. The recorded score is **0.691** (207.35/300) versus an\nupstream-chat baseline of **0.400** (120/300), with 530 judge-required row\ndecisions across the baseline and GoodMemory arms; deterministic\n`structured_first_action` rows are carried forward rather than judged. The\nolder same-model diagnostic score was 0.708 and is not the recorded result. The\nfreshest clean answer-regeneration drift check after recent code changes scored\n0.6895 with `executionFailures: 0`; it shows current checkout drift, not a\nreplacement for the stored-answer comparability artifact. Dataset CC BY 4.0,\nfetched at eval time, never vendored.\n\n### Internal diagnostics (not public claims)\n\nLongMemEval's Phase 72 eval-only verifier chain reaches 0.720 judge-free and\n0.924 under an independent gpt-5.5 official-prompt-compatible judge. That model\nis outside the pinned LongMemEval evaluator model zoo, so the result is not\ndirectly comparable to published official scores; it is also not a production\nruntime profile. ImplicitMemBench's explicit retry-merged check reaches\n0.6923666667 with zero failures, but it is not a replacement monolithic fresh\nFull-300 run. Both therefore remain outside the current-claims table. The\nunderlying reports live under gitignored `reports/` and are reproducible from\nthe recorded commands.\n\nUse [task-board/00-README.txt](./task-board/00-README.txt) for execution order\nand\n[docs/GoodMemory-Current-Status-and-Evidence.md](./docs/GoodMemory-Current-Status-and-Evidence.md)\nfor claim boundaries.\n\n## Choose Your Integration Path\n\nGoodMemory has three primary product entry points. They are not the only APIs:\nlower-level surfaces such as `goodmemory/host`, custom stores, eval tooling, and\nruntime helpers support these paths. They are the README-level ways to decide\nhow to start.\n\n### Autonomous agent? Start here\n\nIf you are an agent that wants to give *yourself* durable memory, match one path\nand run it. Machine-readable versions of this tree live in\n[llms.txt](./llms.txt) and\n[.well-known/goodmemory.json](./.well-known/goodmemory.json) (a deployed bridge\nalso serves the descriptor at `/.well-known/goodmemory.json`).\n\n- **You are, or run inside, Claude Code or Codex** →\n  `npm install -g goodmemory@0.7.0 \u0026\u0026 goodmemory setup`. Unsure what is already\n  wired? Run `goodmemory adopt` (add `--json` for a machine-readable plan): it\n  inspects `.claude/`, `.codex/`, and existing MCP config, then prints the exact\n  next command for your environment.\n- **You speak MCP** (Cursor, Windsurf, Cline, Claude Desktop, Gemini CLI,\n  OpenCode, or a custom client) → add the\n  [standalone MCP server](#standalone-mcp-for-any-client); the two tools you need\n  are `goodmemory_get_context` (recall) and `goodmemory_remember` (opt-in write).\n- **You are a framework agent or a backend** → call the\n  [HTTP bridge](#pythonfastapi-http-bridge): hosted at `goodmemory.vibenest.net`\n  or self-hosted with `goodmemory-http-bridge --recommended` (or\n  `GOODMEMORY_PROFILE=agent-recommended goodmemory-http-bridge`); Python callers\n  use `pip install goodmemory-client`.\n\nThe prose paths below expand each option.\n\n### 1. Build Memory Into An Agent, Chatbox, Or Copilot\n\nUse this when you own the product server and the model call. Install\n`goodmemory` in your Node/Bun service, create one `memory` instance, and pass a\nstable `scope` such as `userId`, `workspaceId`, `sessionId`, and optionally\n`agentId`.\n\nThe request flow is:\n\n1. Before the model call, run `recall()` for the current scope and query.\n2. Run `buildContext()` to turn recall hits into a prompt fragment.\n3. Call your model with that memory context.\n4. After the response, write selected signals with `memory.jobs.enqueueRemember()`\n   or `remember()`.\n5. Use `feedback()`, targeted `reviseMemory()`, `forget()`, and `exportMemory()`\n   for correction, deletion, and user audit.\n\nIf your server already uses Vercel AI SDK, use `goodmemory/ai-sdk` to wrap\n`generateText()` or `streamText()` instead of hand-wiring the whole loop. Start\nwith [App Quickstart](#app-quickstart), then read\n[AI SDK Adapter](#ai-sdk-adapter) if you use AI SDK.\n\n### 2. Add Memory To Codex Or Claude Code\n\nUse this when you want an installed coding agent to remember project and user\ncontext without changing the agent itself. Install the global CLI and run\n`goodmemory setup`.\n\nThe installed-host flow is:\n\n1. `session-start` injects a session brief; `user-prompt-submit` injects\n   per-prompt context (relevance-gated on fresh installs so low-signal prompts\n   stay clean).\n2. The Claude Code `Stop` hook captures each turn from the session transcript\n   (`transcript_path`) into governed writeback candidates — bounded, redacted,\n   never raw transcripts; for Codex, `goodmemory codex writeback --from-rollout`\n   feeds the newest session rollout through the same pipeline.\n3. Codex `pre-tool-use` can deny or redirect risky Bash through\n   `goodmemory codex action` on the same installed config and storage path.\n4. MCP gives trace, context, stats, and artifact inspection; the\n   `goodmemory_remember` write tool is opt-in via `mcp.allowWrite` (or\n   `goodmemory enable \u003chost\u003e --mcp-allow-write`).\n5. Writeback stays `off` for scripted installs; interactive install and\n   `goodmemory setup --recommended` (one consent prompt) enable `selective`\n   durable writes — auditable via `writeback inspect`, reversible via\n   `writeback forget --event-id`.\n6. Fresh installs start on the measured BM25 hybrid retrieval tier with a\n   1024-token session brief and 512-token gated prompt injection; `goodmemory\n   status` shows the retrieval tier, capture proof-of-life, and injection\n   telemetry. Optional `sharedAgents` config lets one host read the other\n   host's records (writes stay attributed).\n\nStart with [Quickstart: Codex Or Claude Code Memory](#quickstart-codex-or-claude-code-memory).\nUse [Installed Host Writeback](#installed-host-writeback) when you are ready to\nreview or enable writes.\n\n### 3. Deploy GoodMemory As A Backend Memory-Layer Service\n\nUse this when another backend should call GoodMemory as a service, especially\nwhen the product backend is Python/FastAPI or when a product such as OneLife\nshould keep memory server-side instead of bundling GoodMemory into a mobile or\nbrowser client.\n\nDeploy the packaged `goodmemory-http-bridge` in a Node/Bun sidecar. Your backend\nthen calls:\n\n- `/memory/recall-context` before its own model call\n- `/memory/remember` after a user-confirmed or product-approved signal\n- `/memory/feedback` for procedural corrections\n- `/memory/export` and `/memory/forget` for audit and deletion\n- `/memory/revise` for targeted correction by explicit memory id\n\nYour service still owns auth, product policy, UI, and model orchestration.\nGoodMemory owns memory storage, recall, context assembly, write governance, and\naudit/export/delete behavior. Start with\n[Python/FastAPI HTTP Bridge](#pythonfastapi-http-bridge) — the official Python\nclient (`pip install goodmemory-client`) and a hosted bridge instance at\n`goodmemory.vibenest.net` are documented there — then check\n[Runtime And Storage](#runtime-and-storage) for SQLite/Postgres choices.\n\nDuring a model turn, GoodMemory does four jobs:\n\n1. Resolve memory for the current `scope`.\n2. Build a prompt-ready context fragment.\n3. Record selected post-response signals when your app or host allows it.\n4. Provide audit, correction, export, and deletion paths for user control.\n\nYour app or installed agent still owns auth, UI, model calls, and product\npolicy. GoodMemory owns the memory loop and storage boundary.\n\n## Install\n\nAfter GoodMemory `0.7.0` is published, it has two normal registry install paths.\nBefore publication, use the tarball verification path below.\n\nUse the global CLI when you want memory enhancement inside installed coding\nagents:\n\n```bash\nnpm install -g goodmemory@0.7.0\ngoodmemory setup\ngoodmemory status\n```\n\nUse the package dependency when you are building an application:\n\n```bash\nnpm install goodmemory@0.7.0\n```\n\nIf you want to type `goodmemory` directly, install the global CLI.\nA project-local `npm install goodmemory@0.7.0` does not put `goodmemory` on your shell `PATH`.\nUse `npx goodmemory`, `npm exec -- goodmemory`, or `./node_modules/.bin/goodmemory`\nfrom that project instead.\n\n```bash\nnpx goodmemory -V\n```\n\nBun consumers can install it directly:\n\n```bash\nbun add goodmemory@0.7.0\n```\n\nTarball verification for release rehearsal:\n\n```bash\nnpm install ./goodmemory-0.7.0.tgz\n```\n\nThe installed CLI is Bun-backed for non-version commands. The package bin is\nNode-safe for `goodmemory -V` and `goodmemory --version`; other commands\ndelegate to Bun.\n\n## Quickstart: Codex Or Claude Code Memory\n\nFor most users, the first useful path is installed-host memory.\n\n```bash\nnpm install -g goodmemory@0.7.0\ngoodmemory setup\ngoodmemory status\n```\n\n`goodmemory setup` detects Codex and Claude Code, installs managed host wiring,\nand asks for:\n\n- host: `codex`, `claude`, or both detected hosts\n- activation: global, current workspace, or manual opt-in\n- GoodMemory user id\n- optional Postgres storage\n- optional embedding provider\n- optional LLM extraction provider\n- writeback mode: `off`, `observe`, `review`, or `selective`\n\nInteractive setup defaults to global activation with workspace-derived\nisolation and recommends `selective` for new host configs so high-signal writes\nstart working immediately with audit and undo. Choose `review` when you want\nInspector approval before durable writes. Existing host configs keep their\ncurrent writeback mode when the interactive prompt default is accepted.\nScripted installs stay safe with `--json` or `--no-interactive`.\nSkipping provider setup is valid: GoodMemory still works with local SQLite and\nrules-only extraction.\n\nUseful commands:\n\n```bash\ngoodmemory setup --host codex\ngoodmemory status codex --workspace-root .\ngoodmemory enable codex --workspace-root . --writeback observe\ngoodmemory enable codex --workspace-root . --writeback selective\ngoodmemory disable codex --workspace-root .\ngoodmemory uninstall codex\n```\n\nThe installed host path has four pieces:\n\n- Managed pre-action for Codex: `pre-tool-use` can deny or redirect risky Bash\n  and `goodmemory codex action` executes the vetted first step on the same\n  installed config, storage, provider, and scope path used by recall and\n  writeback.\n- Recall injection: `session-start` and `user-prompt-submit` hooks call\n  `recall()` plus `buildContext()` and fail open if config, parsing, or storage\n  is unavailable.\n- Deep inspection: `goodmemory mcp serve --host codex` and `goodmemory-mcp\n  --host codex` expose read-only context, trace, stats, and artifact tools.\n- Optional writeback: `session-stop` and explicit writeback commands can turn\n  selected after-response signals into durable memory.\n\n## Standalone MCP For Any Client\n\nHosts without a managed install path (Cursor, Windsurf, Cline, Claude Desktop,\nGemini CLI, OpenCode, or your own MCP client) can run the same MCP server in\nstandalone mode — no `goodmemory setup`, no host config files. Scope and\nstorage come from flags/env; the served surface is the same 8 read-only tools,\nplus an opt-in governed write tool:\n\n```json\n{\n  \"mcpServers\": {\n    \"goodmemory\": {\n      \"command\": \"goodmemory-mcp\",\n      \"args\": [\"--standalone\", \"--user-id\", \"YOUR_USER_ID\"]\n    }\n  }\n}\n```\n\nEquivalent invocation: `goodmemory-mcp --standalone --user-id \u003cid\u003e` (requires\nBun on PATH; `GOODMEMORY_USER_ID` works as the flag's env fallback).\n`--allow-write` (or `GOODMEMORY_MCP_ALLOW_WRITE=1`) registers\n`goodmemory_remember`, which writes through the normal governed remember\npipeline. Agent-tagged memories written by installed hosts stay private to\ntheir agent; add `--agent-id codex` plus the shared `--storage-url` to opt into\nreading an installed host's store. Full flag/env matrix, scope notes, and\nper-host recipes:\n[docs/GoodMemory-Standalone-MCP-Setup-Guide.md](./docs/GoodMemory-Standalone-MCP-Setup-Guide.md)\n([Cursor](./docs/GoodMemory-Cursor-Setup-Guide.md) ·\n[Gemini CLI](./docs/GoodMemory-Gemini-CLI-Setup-Guide.md) ·\n[OpenCode](./docs/GoodMemory-OpenCode-Setup-Guide.md)).\n\n## Installed Host Writeback\n\nInstalled Host Writeback is opt-in. Runtime config defaults and new scripted\ninstalls remain `off` unless the user explicitly chooses a writeback mode.\nExisting configs keep their current writeback mode when no explicit override is\nprovided. New interactive installs recommend `selective` so high-signal writes\nstart working immediately with audit and undo; choose `review` when you want\nInspector approval before durable writes.\n\nUse `observe` before `selective`:\n\n```bash\ngoodmemory enable codex --writeback observe\ngoodmemory codex writeback --json\n\ngoodmemory enable codex --writeback review\ngoodmemory inspector serve\n\ngoodmemory enable codex --writeback selective\ngoodmemory codex writeback --json\n```\n\n`goodmemory inspector serve` opens the built-in local React console for users\nand scopes, categorized memory and supersession history, candidate decisions,\nrecall evidence traces, and audit events. The startup token is passed in a URL\nfragment, cleared immediately into session storage, and sent only as a Bearer\nheader. Revision and destructive actions require confirmation, ETags, and\nidempotency keys. See\n[Inspector And Admin API](./docs/GoodMemory-Inspector-and-Admin-API.md).\n\nWriteback rules:\n\n- `off`: no after-response memory extraction.\n- `observe`: store local bounded/redacted candidate previews for review without\n  raw transcripts or durable memory writes.\n- `review`: queue bounded/redacted candidates for Inspector approval; no durable\n  memory is written until an operator approves a candidate.\n- `selective`: write selected candidates through the public `remember` surface.\n- Raw transcripts are not persisted as memory.\n- Assistant-originated durable memory is blocked unless the host confirms or\n  verifies it and the active profile allows it.\n- `remember: \"never\"` masks annotated content before deterministic, custom, or\n  assisted extraction.\n\nAudit and undo:\n\n```bash\ngoodmemory codex writeback inspect --json\ngoodmemory codex writeback forget --event-id \u003cevent-id\u003e --review-outcome false_write\n```\n\nThe audit ledger stores bounded redacted candidate previews, candidate keys,\ntyped linked record ids, status, reasons, host, mode, timestamps,\nscope/session digests, and optional manual review metadata. It does not store\nraw host payloads. `forget --event-id` deletes linked memory/evidence records\nthrough public `forget()` before marking durable audit events forgotten; for\nobserve-only events it marks the candidate dismissed without calling\n`forget()`.\n\nClaude Code has deterministic CLI parity for hook and writeback commands;\nCodex is the canonical live-evidence path.\n\n## Scripted Host Install\n\nUse `goodmemory install \u003chost\u003e` when you want a fully non-interactive setup:\n\n```bash\ngoodmemory install codex \\\n  --user-id \u003cuser-id\u003e \\\n  --activation-mode global \\\n  --writeback observe \\\n  --storage-provider postgres \\\n  --storage-url \"postgres://user:pass@host:5432/goodmemory\" \\\n  --embedding-provider openai \\\n  --embedding-model text-embedding-3-small \\\n  --embedding-api-key \u003ckey\u003e \\\n  --llm-provider openai \\\n  --llm-model gpt-4o-mini \\\n  --llm-api-key \u003ckey\u003e \\\n  --no-interactive\n```\n\nManaged config lives under `~/.goodmemory/\u003chost\u003e.json`. Re-running install with\nprovider flags updates the same config and keeps MCP/hook registration\nidempotent. Package uninstall does not delete `~/.goodmemory`, repo-local\n`.goodmemory`, local SQLite files, or remote Postgres data. Use\n`goodmemory uninstall \u003chost\u003e` to remove managed host wiring, and use\n`goodmemory forget ...` or explicit storage deletion to remove memory data.\n\n## App Quickstart\n\nUse the root package when you are building a chatbox, copilot, or product agent.\nThe recommended Node service path is the same thin loop used by the Express and\nFastify examples. A longer walkthrough lives in\n[docs/GoodMemory-15-Minute-App-Integration.md](./docs/GoodMemory-15-Minute-App-Integration.md).\n\n```ts\nimport type { GoodMemoryTraceSpan } from \"goodmemory\";\nimport { createGoodMemory } from \"goodmemory\";\n\nconst traceSpans: GoodMemoryTraceSpan[] = [];\n\nconst memory = createGoodMemory({\n  observability: {\n    traceSink: {\n      emit(span) {\n        traceSpans.push(span);\n      },\n    },\n  },\n});\n\nconst scope = {\n  userId: \"u-1\",\n  workspaceId: \"workspace-a\",\n  sessionId: \"s-1\",\n};\nconst userMessage = \"Remember that the migration rollout is blocked on QA signoff.\";\n\n// Call startSession once when the product opens a new session. For later turns\n// with the same sessionId, append to the existing runtime state instead.\nawait memory.runtime.startSession({ scope });\nawait memory.runtime.appendMessage({\n  scope,\n  message: {\n    role: \"user\",\n    content: userMessage,\n  },\n});\n\nconst recall = await memory.recall({\n  scope,\n  query: \"What should the assistant know before replying?\",\n  retrievalProfile: \"general_chat\",\n});\nconst context = await memory.buildContext({\n  recall,\n  output: \"system_prompt_fragment\",\n});\n\nconst assistantText = await callYourModel({\n  memoryContext: context.content,\n  userMessage,\n});\n\nawait memory.runtime.appendMessage({\n  scope,\n  message: {\n    role: \"assistant\",\n    content: assistantText,\n  },\n});\n\nconst writeJob = await memory.jobs.enqueueRemember({\n  scope,\n  messages: [\n    {\n      role: \"user\",\n      content: userMessage,\n    },\n    {\n      role: \"assistant\",\n      content: assistantText,\n    },\n  ],\n  idempotencyKey: \"turn-1\",\n  reason: \"post_response_memory_write\",\n});\nconst drained = await memory.jobs.drain({ maxJobs: 1 });\nconst committedJob =\n  drained.jobs.find((job) =\u003e job.jobId === writeJob.jobId) ?? writeJob;\n\nconsole.log({\n  traceCount: traceSpans.length,\n  writeJobId: writeJob.jobId,\n  writeJobStatus: committedJob.status,\n});\n\nasync function callYourModel(input: {\n  memoryContext: string;\n  userMessage: string;\n}): Promise\u003cstring\u003e {\n  void input.memoryContext;\n  return `Got it. I will keep that in mind: ${input.userMessage}`;\n}\n```\n\nThe core memory loop is intentionally small:\n\n- `remember()` writes selected user, app, or host signals.\n- `recall()` retrieves scoped memory for a query.\n- `buildContext()` turns recall hits into a prompt fragment or JSON payload.\n- `feedback()` records explicit corrections and procedural preferences.\n- `forget()` deletes wrong or obsolete memory.\n\n### Locale and LanguagePack\n\nBuilt-in packs cover English, Simplified Chinese, Traditional Chinese\n(`zh-TW`/`zh-HK`/`zh-MO`), Japanese, Korean, French, and Spanish. Set a\nhost-known locale explicitly; otherwise auto-detection falls back to\n`defaultLocale` for inherently ambiguous Han-only or unmarked Latin text.\n\n```ts\nconst multilingualMemory = createGoodMemory({\n  language: {\n    defaultLocale: \"zh-TW\",\n    detection: \"auto\",\n  },\n});\n\nawait multilingualMemory.remember({\n  locale: \"ko-KR\",\n  scope,\n  messages: [{ role: \"user\", content: \"현재 역할은 릴리스 책임자입니다.\" }],\n});\n```\n\nAdding a language means implementing one complete `LanguagePack`, not adding\nmodule-local regex branches. See the\n[LanguagePack extension guide](./docs/GoodMemory-LanguagePack-Extension-Guide.md)\nfor the contract, custom registration, analyzer versioning, and projection\nmigration rules.\n\nUpgrading from the previous adapter/projection contract is intentionally\nbreaking; follow the\n[0.6 to 0.7 migration guide](./docs/GoodMemory-0.6-to-0.7-Migration-Guide.md).\n\nFor production app integrations, the recommended turn loop adds the governed\nruntime layer around that core:\n\n- `memory.runtime.startSession()` and `memory.runtime.appendMessage()` track\n  current-session state without making raw transcripts durable memory.\n- `memory.jobs.enqueueRemember()` schedules after-response memory writes with\n  idempotency and visible job status.\n- `memory.jobs.drain()` commits queued writes in this in-memory scheduler. In a\n  production service, run draining in your worker or request-adjacent job loop.\n- `GoodMemoryConfig.observability.traceSink` receives redaction-safe traces for\n  remember, recall, context, revise, forget, export, and job events.\n- `memory.reviseMemory({ target: { memoryId } })` corrects a known memory by\n  explicit id, not by fuzzy text selection.\n- `exportMemory()` gives the user an audit/export path.\n\nRuntime archive persistence is off by default. If you call\n`memory.runtime.endSession({ scope, archive: \"off\" })`, session state is\ncleared without writing an archive. If you opt into archive persistence, keep it\nsummary-only and never treat raw transcripts as the default memory source.\n\nFor server integrations, start with the thin examples:\n[examples/express-chat-server.ts](./examples/express-chat-server.ts) or\n[examples/fastify-chat-server.ts](./examples/fastify-chat-server.ts).\nFor Python/FastAPI backends, use the packaged `goodmemory-http-bridge` path\ndescribed below.\n\n## Opt-In Recall Tuning: Generalized Fusion, Multi-Hop, Optional Embeddings, And Conversational Extraction\n\nThe knobs below are optional and conservative by design. Default recall is\nsingle-pass and rules-only, and default extraction is unchanged; nothing happens\nunless you opt in. The recommended preset has a provider-free local path;\nembedding and extraction providers add optional channels but are not required.\n\n### One-flag recommended retrieval preset\n\n`retrieval.preset: \"recommended\"` enables generalized retrieval and conditional\nconversational extraction with one flag:\n\n```ts\nconst memory = createGoodMemory({\n  retrieval: { preset: \"recommended\" },\n});\n```\n\nWhen active it (a) indexes memory-, field-, and sentence-granularity recall\ndocuments, (b) fuses BM25, direct entity adjacency, and any available neural\ndense candidates with RRF, (c) applies a bounded dynamic candidate budget, and\n(d) biases `auto` recall routing to hybrid. An explicit per-call strategy still\nwins, including `strategy: \"rules-only\"`, which bypasses generalized fusion.\nWhen a neural embedding resolves, it contributes a dense `topK: 16` channel;\nwithout one, retrieval stays local, deterministic, and zero-network. The preset\nalso flips assisted extraction to `mode: \"conversational\"` only when an\nextraction model already resolves and no explicit mode was set. It never\ninjects a provider. Leaving `preset` unset preserves the existing rules-only\ndefault.\n\nRequirements and boundaries:\n\n- No provider is required. A neural embedding endpoint\n  (`GOODMEMORY_EMBEDDING_*`, `providers.embedding`, or\n  `adapters.embeddingAdapter`) adds the optional dense channel. The zero-egress\n  neural path is the Ollama recipe below.\n- `createLocalEmbeddingAdapter()` is rejected when paired with the preset:\n  hashed-lexical vectors would duplicate lexical evidence while pretending to\n  be a dense semantic channel.\n- Check `inspectGoodMemoryRuntime(memory).retrievalPreset` — its `extraction`\n  field reports whether the write-time half engaged (`\"conversational\"`) or an\n  extractor was unavailable/kept as-is.\n- The preset covers memory retrieval and conditional extraction only.\n  Answer-side prompting and abstention policy remain application concerns.\n- Do not pair it with `bm25Ranking: true` unless you intentionally want the\n  separate legacy additive BM25 slot; generalized fusion already has a BM25\n  channel.\n- If you use env-resolved extraction and adopt the preset, write-time output\n  becomes conversational atomic claims; the escape hatch is an explicit\n  `providers.extraction` object with `mode: \"default\"`.\n\n### Optional pointwise reranker\n\nAdd a first-party OpenAI-compatible pointwise reranker when the fused candidate\nset is useful but its final order is noisy:\n\n```ts\nconst memory = createGoodMemory({\n  retrieval: { preset: \"recommended\" },\n  providers: {\n    reranking: {\n      provider: \"openai\",\n      model: process.env.RERANKING_MODEL!,\n      apiKey: process.env.RERANKING_API_KEY!,\n      baseURL: process.env.RERANKING_BASE_URL,\n    },\n  },\n});\n\nconst result = await memory.recall({ scope, query });\nconsole.log(result.metadata.retrievalTrace?.reranker);\n```\n\nEach selected fact is scored in an independent query-document call; sibling\ncandidates are never placed in the same reranker prompt. The reranker only\nreorders facts already admitted by deterministic recall, so it cannot widen\nmembership or relax grounded abstention. Provider timeout, schema, or gateway\nfailure returns the original deterministic order and records\n`status: \"fallback\"` plus a stable reason in `retrievalTrace`. Set\n`rerank: false` on one recall to skip it. An explicit `adapters.reranker` remains\nauthoritative over `providers.reranking`. Provider-backed reranking defaults to\na 15-second request timeout; set the optional positive-integer\n`requestTimeoutMs` in `providers.reranking` when the chosen gateway needs a\ndifferent latency budget.\n\nThe trace includes bounded channel/RRF attribution, model role, sanitized\ngateway, latency, scores, and before/after ranks. It does not include API keys,\nquery text, or memory content. This is opt-in and adds one model call per fact in\nthe bounded rerank window; the provider-free recommended path remains unchanged.\n\n### Optional local embedding endpoint (Ollama)\n\nThe recommended preset works without embeddings. To add a zero-egress neural\ndense channel, `GOODMEMORY_EMBEDDING_BASE_URL` accepts any OpenAI-compatible\n`/v1/embeddings` endpoint, including a local Ollama server.\n\n```bash\nollama pull nomic-embed-text        # or bge-m3 for stronger multilingual recall\n\nexport GOODMEMORY_EMBEDDING_PROVIDER=openai\nexport GOODMEMORY_EMBEDDING_BASE_URL=http://localhost:11434/v1\nexport GOODMEMORY_EMBEDDING_MODEL=nomic-embed-text\nexport GOODMEMORY_EMBEDDING_API_KEY=ollama   # any placeholder; Ollama ignores it, the variable stays required\n\n# smoke-check the endpoint before starting your app\ncurl http://localhost:11434/v1/embeddings \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"model\": \"nomic-embed-text\", \"input\": \"hello\"}'\n```\n\n- `provider` stays `openai`: it selects the OpenAI-compatible wire protocol,\n  not the vendor.\n- Keep one embedding model per store: vectors from different models or\n  dimensions are not comparable, and switching models means re-remembering\n  (re-embedding) the corpus.\n- Local embedding quality differs from `text-embedding-3-small`; the public\n  LoCoMo numbers were measured with the OpenAI endpoint. This recipe\n  reproduces the mechanism with zero egress, not the exact number.\n- This is not `createLocalEmbeddingAdapter()` (below), which is\n  hashed-lexical, not semantic, and is rejected by the recommended preset.\n\n### Opt-in multi-hop recall\n\n`recall()` is single-pass by default. Pass `multiHop: true` for an opt-in\ntwo-pass retrieval: GoodMemory runs the query, extracts bridge entities named in\nthe first-pass evidence, expands the query with them, and runs a second pass.\n\n```ts\nconst recall = await memory.recall({\n  scope,\n  query: \"Who manages the project Alice started?\",\n  multiHop: true,\n});\n```\n\nUse it when the answer needs an entity that only the first hop names (hop 1 finds\n\"Alice started Project Atlas\"; hop 2 needs \"who manages Project Atlas\").\n\n- It is opt-in. Default recall stays single-pass; leaving `multiHop` unset\n  changes nothing.\n- It is **not** a general semantic retriever. It bridges named entities\n  lexically; it does not rank by meaning.\n- It can **add noise when first-pass recall is weak**: if hop 1 surfaces the\n  wrong evidence, the extracted bridge entities are wrong and the expanded query\n  dilutes recall. Measured on LoCoMo (where base retrieval is very low) `multiHop`\n  *hurt* recall, so do not reach for it to fix conversational / phrasing-gap\n  retrieval — that needs real semantic retrieval, not multi-hop bridging.\n\n### Offline local embedding adapter\n\n`createLocalEmbeddingAdapter()` is a deterministic, offline, dependency-free\nembedding adapter (hashed character-n-gram vectors). Inject it for\nlexical/morphological tie-breaking without configuring an embedding provider:\n\n```ts\nimport { createGoodMemory, createLocalEmbeddingAdapter } from \"goodmemory\";\n\nconst memory = createGoodMemory({\n  adapters: { embeddingAdapter: createLocalEmbeddingAdapter() },\n});\n```\n\n- It is **not** neural semantic retrieval. The vectors are hashed lexical\n  features, so they break ties between lexically similar candidates; they do not\n  understand meaning.\n- Do **not** use it to claim a semantic benchmark improvement. It cannot bridge a\n  question-to-text phrasing gap that surface lexical overlap already misses.\n- For real semantic ranking, configure a neural embedding provider via\n  `GOODMEMORY_EMBEDDING_*` instead.\n\n### Opt-in conversational fact extraction\n\nBy default, assisted extraction (when a `providers.extraction` model is\nconfigured) pulls durable product memory — profiles, preferences, references,\nand facts. Set `providers.extraction.mode: \"conversational\"` to instead\ndecompose dialogue into self-contained, coreference-resolved, entity- and\ndate-normalized atomic claims at write time, so later retrieval matches a\nnormalized fact instead of a raw conversational turn.\n\n```ts\nconst memory = createGoodMemory({\n  providers: {\n    extraction: {\n      provider: \"openai\",\n      model: \"gpt-5.6-terra\",\n      apiKey: process.env.GOODMEMORY_ASSISTED_EXTRACTOR_API_KEY!,\n      baseURL: process.env.GOODMEMORY_ASSISTED_EXTRACTOR_BASE_URL,\n      mode: \"conversational\",\n    },\n  },\n});\n```\n\nUse it for chat/agent products where memory comes from multi-turn conversation\nand questions are phrased differently from how things were said (\"Who is the\nuser's manager?\" vs. \"yeah my boss Dana signed off\").\n\n- It is opt-in. Leaving `mode` unset (or omitting `providers.extraction`) keeps\n  the default extraction behavior; the recall ranking path is untouched.\n- It is a **write-time LLM pass**: it uses your configured chat model, so it adds\n  extraction latency and token cost, and like any LLM step it can drop or\n  misphrase a claim. Raw turns remain the ground truth.\n- It is **not** semantic retrieval. It normalizes the stored text so lexical\n  retrieval has a better surface to match; it does not rank by meaning. It is the\n  embedding-free lever for the conversational phrasing gap, not a replacement for\n  a neural embedding provider.\n- Do **not** quote a benchmark number from it without held-out validation, and\n  do not tune the extraction prompt to a specific benchmark's phrasing.\n\n## Runtime And Storage\n\n`createGoodMemory({})` follows a local-first auto-storage contract:\n\n- Explicit `storage.provider` wins when supplied.\n- Without explicit storage, GoodMemory uses Postgres only when a configured\n  target can bootstrap the GoodMemory backend.\n- On Bun, zero-config durable storage is local SQLite at\n  `./.goodmemory/memory.sqlite`.\n- On Node runtimes without the built-in local SQLite adapter, zero-config\n  storage falls back to in-memory.\n- Unsupported explicit built-in `sqlite` or `postgres` selections are reported\n  as unavailable rather than mislabeled durable.\n- Injected `documentStore`, `sessionStore`, or `vectorStore` adapters are\n  reported as adapter-defined storage.\n- Without a retrieval preset, runtime behavior remains `rules-only` regardless\n  of embedding configuration. The `recommended` preset routes `auto` to its\n  provider-free hybrid fusion path and adds dense evidence when configured.\n- Supported local runtimes can use `sqlite-vss` for SQLite semantic indexing;\n  unsupported runtimes keep durable non-accelerated fallback behavior.\n\nCustom `DocumentStore` adapters keep the original set/get/update/query/delete\ncontract. Projection-backed features such as the `recommended` generalized\nfusion preset additionally require `ProjectionCapableDocumentStore`, whose\n`projectionBatchSemantics` must equal the exported\n`PROJECTION_BATCH_SEMANTICS` version and whose\n`writeBatchIfUnchanged()` must atomically validate `expected`/`unchanged` rows\nand apply every `set` and `delete` in the batch. Existing adapters can continue\nto run without projections; a legacy same-named method is deliberately not\ntreated as the current atomic contract. Add the version marker only after the\nadapter implements the full semantics. The built-in memory, SQLite, and\nPostgres stores already implement it.\n\nInspect the resolved runtime instead of guessing:\n\n```ts\nimport { createGoodMemory, inspectGoodMemoryRuntime } from \"goodmemory\";\n\nconst memory = createGoodMemory({});\nconst runtime = inspectGoodMemoryRuntime(memory);\n\nconsole.log(runtime.storage);\n```\n\nSQLite vector controls:\n\n- `GOODMEMORY_SQLITE_VECTOR_MODE=off|prefer|require`\n- `GOODMEMORY_SQLITE_CUSTOM_LIBRARY_PATH`\n- `GOODMEMORY_SQLITE_VECTOR_EXTENSION_PATH`\n- `GOODMEMORY_SQLITE_VECTOR_EXTENSION_ENTRYPOINT`\n- `GOODMEMORY_SQLITE_VECTOR_SEARCH_FUNCTION`\n\n## Public Remember Customization\n\nProduct integrations should customize writes through the public `remember`\nsurface. Do not use test-only extractor seams for product behavior.\n\n```ts\nimport { createGoodMemory, rememberRules } from \"goodmemory\";\n\nconst memory = createGoodMemory({\n  remember: {\n    preset: \"default\",\n    profiles: [\n      {\n        id: \"life-coach\",\n        when: { agentId: \"life-coach\" },\n        rules: [\n          rememberRules.fact(/my top priority this quarter is (.+)/i, {\n            id: \"life-goal-priority\",\n            category: \"goal\",\n            tags: [\"life_coach\", \"long_term_goal\"],\n            attributes: { horizon: \"quarter\" },\n            content: ({ match }) =\u003e match[1] ?? \"\",\n          }),\n          rememberRules.preference(/please coach me with (.+)/i, {\n            id: \"life-coaching-style\",\n            category: \"coaching_style\",\n            value: ({ match }) =\u003e match[1] ?? \"\",\n          }),\n        ],\n        assistantOutputs: { mode: \"confirmed_or_verified_only\" },\n      },\n    ],\n  },\n});\n\nawait memory.remember({\n  scope: { userId: \"u-1\", agentId: \"life-coach\" },\n  messages: [\n    {\n      role: \"user\",\n      content: \"My top priority this quarter is rebuilding my sleep routine.\",\n    },\n  ],\n  annotations: [\n    {\n      messageIndex: 0,\n      remember: \"always\",\n      metadataPatch: { tags: [\"confirmed_by_host\"] },\n    },\n  ],\n});\n```\n\nProfile `extractors` can be raw `MemoryExtractor` objects or named\n`{ id, extractor }` entries. Use named extractors for real integrations so\nremember events and eval reports carry stable `extractorIds` even if profile\ncomposition changes. Remember events also carry resolved `profileId` and\n`presetId` metadata.\n\n## AI SDK Adapter\n\nGoodMemory's Node-compatible AI SDK path is a plain `Request -\u003e Response`\nserver handler built from `createGoodMemory()` and `createGoodMemoryAISDK()`.\n\n```ts\nimport { createGoodMemory } from \"goodmemory\";\nimport type { GoodMemoryStreamTextInput } from \"goodmemory/ai-sdk\";\nimport { createGoodMemoryAISDK } from \"goodmemory/ai-sdk\";\n\nconst memory = createGoodMemory({});\n\nconst aiSDK = createGoodMemoryAISDK({\n  memory,\n});\n\ntype MemoryChatRequest = Pick\u003c\n  GoodMemoryStreamTextInput,\n  \"messages\" | \"query\" | \"scope\" | \"system\"\n\u003e;\n\nfunction isMemoryChatRequest(value: unknown): value is MemoryChatRequest {\n  if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n    return false;\n  }\n\n  const candidate = value as Record\u003cstring, unknown\u003e;\n  const scope = candidate.scope;\n  return Array.isArray(candidate.messages)\n    \u0026\u0026 !!scope\n    \u0026\u0026 typeof scope === \"object\"\n    \u0026\u0026 !Array.isArray(scope)\n    \u0026\u0026 typeof (scope as { userId?: unknown }).userId === \"string\"\n    \u0026\u0026 (scope as { userId: string }).userId.trim().length \u003e 0;\n}\n\nexport async function handleMemoryChat(request: Request): Promise\u003cResponse\u003e {\n  const body: unknown = await request.json();\n  if (!isMemoryChatRequest(body)) {\n    return new Response(\n      JSON.stringify({\n        error: \"Expected a request body with a messages array and scope.userId.\",\n      }),\n      {\n        headers: { \"content-type\": \"application/json; charset=utf-8\" },\n        status: 400,\n      },\n    );\n  }\n\n  const result = aiSDK.streamText({\n    messages: body.messages,\n    query: body.query,\n    scope: body.scope,\n    system: body.system,\n    model: {} as never,\n  });\n\n  return result.toTextStreamResponse();\n}\n```\n\nNotes:\n\n- The canonical server example is\n  [examples/plain-ai-sdk-server.ts](./examples/plain-ai-sdk-server.ts).\n- Thin Express and Fastify examples are\n  [examples/express-chat-server.ts](./examples/express-chat-server.ts) and\n  [examples/fastify-chat-server.ts](./examples/fastify-chat-server.ts).\n- `examples/vercel-ai-chat.ts` remains a lower-level wrapper/API example.\n- Next.js App Router can map `export async function POST(request: Request)`\n  to the same handler body.\n- The first public server path is `ModelMessage`-first.\n- The wrapper augments `system` through `recall()` and `buildContext()` and\n  soft-fails if the memory layer errors.\n\n## Python/FastAPI HTTP Bridge\n\nUse the packaged HTTP bridge when a Python backend should call GoodMemory as a\nserver-side memory service.\n\n```bash\nGOODMEMORY_HTTP_BRIDGE_TOKEN=\"replace-with-service-token\" \\\nGOODMEMORY_STORAGE_PROVIDER=postgres \\\nGOODMEMORY_STORAGE_URL=\"postgres://user:pass@host:5432/goodmemory\" \\\n./node_modules/.bin/goodmemory-http-bridge --profile life-coach\n```\n\nPython callers send `Authorization: Bearer \u003ctoken\u003e` plus the `x-goodmemory-*`\nscope headers to `POST /memory/recall-context`, `/memory/remember`,\n`/memory/feedback`, `/memory/export`, `/memory/forget`, and targeted\n`/memory/revise`. The TypeScript bridge API is available from `goodmemory/http`.\n\nTo serve the recommended retrieval preset (multi-granular BM25 + entity + RRF,\nwith an optional dense channel)\nover the bridge, start it with the one switch `--recommended` (or\n`GOODMEMORY_PROFILE=agent-recommended` or\n`GOODMEMORY_HTTP_BRIDGE_RECOMMENDED=1`). No embedding endpoint is required;\n`GOODMEMORY_EMBEDDING_*` adds the dense channel when configured. `GET /healthz`\nreports `retrievalTier` and `embeddingEnabled`, and recall requests default to\n`strategy: \"auto\"`, which the preset routes to `hybrid`. An explicit\n`strategy: \"rules-only\"` request still selects the strict floor.\n\nOr deploy it with Docker in one command (SQLite volume included; add the\ncompose `postgres` profile for pgvector):\n\n```bash\nGOODMEMORY_HTTP_BRIDGE_TOKEN=\"replace-with-service-token\" docker compose up -d\ncurl -fsS http://127.0.0.1:8739/healthz\n```\n\n`GET /healthz` is the auth-free liveness endpoint for containers, load\nbalancers, and client ready-waits. Python backends should use the official\nclient — `pip install goodmemory-client` ([PyPI](https://pypi.org/project/goodmemory-client/)) —\nwhich derives the caller headers from one `Scope` object, mirrors the\nper-endpoint idempotency rules, and surfaces recall `routing` (so silent\nstrategy downgrades are visible). Details:\n[docs/GoodMemory-Python-HTTP-Integration-Bridge.md](./docs/GoodMemory-Python-HTTP-Integration-Bridge.md).\n\n**Hosted instance.** A live GoodMemory bridge runs at\n`https://goodmemory.vibenest.net` (liveness:\n[`/healthz`](https://goodmemory.vibenest.net/healthz)). Point any client at it\nvia `GOODMEMORY_BRIDGE_HOST` / `--goodmemory-host` (or the `GoodMemoryClient`\nhost argument) instead of a local URL; it enforces bearer-token auth, so bring\nyour own service token. It is a single-process, write-capable API — before\nexposing one publicly, add rate limiting and disposable-scope data, and never\npublish a shared write token.\n\n## Host Adapter API\n\nUse `goodmemory/host` when an external host wants artifacts or host-specific\ncontracts without importing internals.\n\n```ts\nimport { createGoodMemory } from \"goodmemory\";\nimport { createHostAdapter } from \"goodmemory/host\";\n\nconst memory = createGoodMemory({});\n\nconst adapter = createHostAdapter({\n  id: \"codex-handoff\",\n  hostKind: \"codex\",\n  memory,\n  readableArtifactTypes: [\"session_memory\"],\n});\n\nconst result = await adapter.readArtifacts({\n  scope: {\n    userId: \"u-1\",\n    workspaceId: \"workspace-a\",\n    sessionId: \"s-1\",\n  },\n  includeRuntime: true,\n});\n```\n\nModes:\n\n- `file-assisted`: read compiled artifacts such as `MEMORY.md`, `user.md`,\n  `session-memory/\u003csessionId\u003e.md`, and `playbooks/*.md` without treating files\n  as canonical storage.\n- `file-authoritative`: available for the minimal writable subset. Today that\n  subset is the canonical `playbooks/*.md` file shape, writing structured\n  deltas back into active validated-pattern feedback records.\n\nWritable guardrails:\n\n- Prompt and skill snippet files remain derived read-only outputs.\n- Risky guidance edits require explicit `verifyWrite` approval.\n- Low-risk metadata edits such as `appliesTo` and `Why` can write back without\n  the extra approval step.\n- Failed writable operations return diagnostics with rollback guidance.\n\nCurrent Claude/Codex examples stay in `file-assisted` mode by default.\n\n## CLI Reference\n\nThe `goodmemory` command on your shell `PATH` is the global CLI installed with\n`npm install -g goodmemory@0.7.0`. In a local dependency install, invoke the\npackage bin as `npx goodmemory`, `npm exec -- goodmemory`, or\n`./node_modules/.bin/goodmemory`. The repo-local `bun run goodmemory` script is\nfor development only.\n\nMemory-first commands:\n\n```bash\n./node_modules/.bin/goodmemory inspect --user-id \u003cuser-id\u003e --workspace-id \u003cworkspace-id\u003e\n./node_modules/.bin/goodmemory trace --user-id \u003cuser-id\u003e --workspace-id \u003cworkspace-id\u003e --query \"Which runbook is the source of truth?\"\n./node_modules/.bin/goodmemory export-memory --user-id \u003cuser-id\u003e --workspace-id \u003cworkspace-id\u003e --output ./tmp/export\n./node_modules/.bin/goodmemory stats --user-id \u003cuser-id\u003e --workspace-id \u003cworkspace-id\u003e\n./node_modules/.bin/goodmemory remember --user-id \u003cuser-id\u003e --workspace-id \u003cworkspace-id\u003e --session-id \u003csession-id\u003e --message \"Remember that the deploy is blocked on smoke verification.\"\n./node_modules/.bin/goodmemory feedback --host codex --workspace-root . --session-id \u003csession-id\u003e --signal \"Keep coding summaries short and list explicit next steps.\"\n./node_modules/.bin/goodmemory forget --host codex --workspace-root . --session-id \u003csession-id\u003e --memory-id \u003cmemory-id\u003e\n```\n\nInstalled-host commands:\n\n```bash\ngoodmemory -V\ngoodmemory --version\ngoodmemory setup --host codex\ngoodmemory status codex --workspace-root .\ngoodmemory install codex --activation-mode global --writeback observe --user-id \u003cuser-id\u003e\ngoodmemory enable codex --workspace-root . --writeback selective\ngoodmemory mcp serve --host codex\ngoodmemory-mcp --host codex\ngoodmemory codex bootstrap --user-id \u003cuser-id\u003e --workspace-id \u003cworkspace-id\u003e\ngoodmemory claude bootstrap --user-id \u003cuser-id\u003e --workspace-id \u003cworkspace-id\u003e\n```\n\nHook and writeback examples:\n\n```bash\nprintf '%s' '{\"cwd\":\".\",\"session_id\":\"s-1\",\"hook_event_name\":\"SessionStart\",\"source\":\"startup\"}' \\\n  | goodmemory codex hook session-start\n\nprintf '%s' '{\"cwd\":\".\",\"session_id\":\"s-1\",\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"./tools/DeepAnalyzer --detailed\"}}' \\\n  | goodmemory codex hook pre-tool-use\n\ngoodmemory codex action -- ./tools/DeepAnalyzer --detailed\n\nprintf '%s' '{\"cwd\":\".\",\"session_id\":\"s-1\",\"messages\":[{\"role\":\"user\",\"content\":\"Next step is to finish the release smoke.\"}]}' \\\n  | goodmemory codex writeback --json\n\nprintf '%s' '{\"cwd\":\".\",\"session_id\":\"s-1\",\"event_id\":\"stop-1\",\"summary\":\"Keep coding summaries short.\"}' \\\n  | goodmemory codex hook session-stop\n```\n\nEval artifact inspection:\n\n```bash\n./node_modules/.bin/goodmemory eval inspect --run-dir reports/eval/live/\u003crun-id\u003e --case-id \u003ccase-id\u003e\n./node_modules/.bin/goodmemory eval trace --run-dir reports/eval/live/\u003crun-id\u003e --case-id \u003ccase-id\u003e\n./node_modules/.bin/goodmemory eval export-case --run-dir reports/eval/live/\u003crun-id\u003e --case-id \u003ccase-id\u003e --output /tmp/case.json\n```\n\nCLI surface:\n\n- `goodmemory -V`\n- `goodmemory --version`\n- `goodmemory setup`\n- `goodmemory status`\n- `goodmemory install`\n- `goodmemory uninstall`\n- `goodmemory enable`\n- `goodmemory disable`\n- `goodmemory inspect`\n- `goodmemory trace`\n- `goodmemory export-memory`\n- `goodmemory stats`\n- `goodmemory remember`\n- `goodmemory feedback`\n- `goodmemory forget`\n- `goodmemory mcp serve`\n- `goodmemory-mcp`\n- `goodmemory codex hook`\n- `goodmemory codex writeback`\n- `goodmemory claude hook`\n- `goodmemory claude writeback`\n- `goodmemory codex bootstrap`\n- `goodmemory claude bootstrap`\n- `goodmemory eval inspect`\n- `goodmemory eval trace`\n- `goodmemory eval export-case`\n\n## Examples\n\nInstalled-package guides:\n\n- 15-minute app integration guide:\n  [docs/GoodMemory-15-Minute-App-Integration.md](./docs/GoodMemory-15-Minute-App-Integration.md)\n- Reference integration guide:\n  [docs/GoodMemory-Reference-Integration-Guide.md](./docs/GoodMemory-Reference-Integration-Guide.md)\n- LanguagePack extension guide:\n  [docs/GoodMemory-LanguagePack-Extension-Guide.md](./docs/GoodMemory-LanguagePack-Extension-Guide.md)\n- Codex handoff setup guide:\n  [docs/GoodMemory-Codex-Handoff-Setup-Guide.md](./docs/GoodMemory-Codex-Handoff-Setup-Guide.md)\n- Claude Code setup guide:\n  [docs/GoodMemory-Claude-Code-Setup-Guide.md](./docs/GoodMemory-Claude-Code-Setup-Guide.md)\n\nRepo-local examples:\n\n- Basic chat integration: [examples/basic-chat.ts](./examples/basic-chat.ts)\n- Coding-agent flavored integration:\n  [examples/coding-agent.ts](./examples/coding-agent.ts)\n- Plain AI SDK server integration:\n  [examples/plain-ai-sdk-server.ts](./examples/plain-ai-sdk-server.ts)\n- Express chat server integration:\n  [examples/express-chat-server.ts](./examples/express-chat-server.ts)\n- Fastify chat server integration:\n  [examples/fastify-chat-server.ts](./examples/fastify-chat-server.ts)\n- AI SDK wrapper integration:\n  [examples/vercel-ai-chat.ts](./examples/vercel-ai-chat.ts)\n- Life-coach public remember profile:\n  [examples/life-coach-remember-profile.ts](./examples/life-coach-remember-profile.ts)\n- Claude-style host artifact consumption:\n  [examples/host-claude-artifacts.ts](./examples/host-claude-artifacts.ts)\n- Codex-style session handoff consumption:\n  [examples/host-codex-handoff.ts](./examples/host-codex-handoff.ts)\n\nRun examples from this repo:\n\n```bash\nbun run example:chat\nbun run example:coding-agent\nbun run example:ai-sdk-server\nbun run example:express-chat\nbun run example:fastify-chat\nbun run example:vercel-ai\nbun run example:life-coach-profile\nbun run example:host-claude\nbun run example:host-codex\n```\n\n## Testing And Eval\n\nDefault local gates:\n\n```bash\nbun test\nbun run typecheck\nbun run test:coverage\n```\n\nFor the complete 0.7 package, coverage, runtime-consumer, size, and provenance\ngate, run `bun run gate:v0.7 --strict`.\n\nUse `bun run test:all` only when you intentionally want the broader sweep\nthrough vendored or third-party test trees.\n\nEval commands:\n\n```bash\nbun run eval:smoke\nbun run eval:fallback\nbun run eval:live\nbun run eval:live-memory\nbun run eval:live-auto-memory\nbun run eval:live-provider-memory\nbun run eval:summary\n```\n\nMeanings:\n\n- `eval:smoke`: harness self-check.\n- `eval:fallback`: deterministic validation without live model calls.\n- `eval:live`: live generator plus live judge with an in-memory backend.\n- `eval:live-memory`: live generator plus live judge using auto-storage\n  semantics; default storage is local SQLite unless provider storage resolves.\n- `eval:live-auto-memory`: alias for `eval:live-memory` when scripts need to\n  make auto-storage explicit.\n- `eval:live-provider-memory`: provider-backed evidence path requiring\n  Postgres, embeddings, and assisted extraction; it does not silently fall back\n  to SQLite.\n- `eval:summary`: summarize existing eval output directories.\n\nLive eval environment:\n\n- `GOODMEMORY_EVAL_PROVIDER`\n- `GOODMEMORY_EVAL_BASE_URL` for OpenAI-compatible gateways\n- `GOODMEMORY_EVAL_MODEL`\n- `GOODMEMORY_EVAL_API_KEY`\n- `GOODMEMORY_EVAL_MAX_CONCURRENCY` optional parallelism cap\n- `GOODMEMORY_JUDGE_PROVIDER`\n- `GOODMEMORY_JUDGE_BASE_URL` for OpenAI-compatible gateways\n- `GOODMEMORY_JUDGE_MODEL`\n- `GOODMEMORY_JUDGE_API_KEY`\n\n`eval:live-memory` and `eval:live-auto-memory` also need embedding and\nassisted extractor configuration:\n\n- `GOODMEMORY_EMBEDDING_PROVIDER`\n- `GOODMEMORY_EMBEDDING_BASE_URL` for OpenAI-compatible gateways\n- `GOODMEMORY_EMBEDDING_MODEL`\n- `GOODMEMORY_EMBEDDING_API_KEY`\n- `GOODMEMORY_ASSISTED_EXTRACTOR_PROVIDER`\n- `GOODMEMORY_ASSISTED_EXTRACTOR_BASE_URL` for OpenAI-compatible gateways\n- `GOODMEMORY_ASSISTED_EXTRACTOR_MODEL`\n- `GOODMEMORY_ASSISTED_EXTRACTOR_API_KEY`\n\n`eval:live-provider-memory` additionally requires:\n\n- `GOODMEMORY_TEST_POSTGRES_URL`\n\nOutput directories:\n\n- live runs: `reports/eval/live/run-*`\n- auto-storage live memory runs: `reports/eval/live-memory/run-*`\n- provider-backed live memory runs: `reports/eval/live-provider-memory/run-*`\n- fallback runs: `reports/eval/fallback/run-*`\n\n## Strategy Rollout\n\nGoodMemory keeps `rules-only` as the supported baseline. New retrieval behavior\nmoves through `observe -\u003e assist -\u003e promote`.\n\nOperator guidance:\n\n- `observe`: collect isolated shadow evidence without changing the executed path.\n- `assist`: allow candidate execution in controlled eval runs.\n- `promote`: require `strategy-promotion-gate.json`, a clean\n  `regression-dashboard.json`, and\n  `strategy-promotion-authorization.json`.\n- Stay `rules-only` when eval evidence is incomplete, provider-backed\n  dependencies are unavailable, or rollback conditions are present.\n\n## Current Status\n\nCurrent stable public surface:\n\n- root memory API through `goodmemory`\n- AI SDK adapter through `goodmemory/ai-sdk`\n- host adapter and host contracts through `goodmemory/host`\n- HTTP bridge API through `goodmemory/http` and packaged\n  `goodmemory-http-bridge`\n- installed CLI and managed host setup through `goodmemory setup`\n- Codex and Claude Code hooks for recall\n- read-only MCP for inspection and debugging\n- opt-in installed-host writeback with audit and undo\n- local SQLite durable fallback on Bun\n- Postgres, embeddings, assisted extraction, and provider-backed evals when\n  configured\n\nStill outside the accepted public claim:\n\n- default-on automatic writeback\n- raw transcript archive\n- dashboard or managed cloud\n- treating exported artifact files as canonical storage\n- broadening root exports with internal proposal or promotion internals\n\nFor the detailed current-state and evidence map, use\n[docs/GoodMemory-Current-Status-and-Evidence.md](./docs/GoodMemory-Current-Status-and-Evidence.md).\n\n## Documentation\n\n- Documentation map and archive policy:\n  [docs/README.md](./docs/README.md)\n- Current status and evidence:\n  [docs/GoodMemory-Current-Status-and-Evidence.md](./docs/GoodMemory-Current-Status-and-Evidence.md)\n- Product comparison:\n  [docs/GoodMemory-Product-Comparison.md](./docs/GoodMemory-Product-Comparison.md)\n- Canonical design:\n  [docs/GoodMemory-First-Principles-and-Reference-Architecture.md](./docs/GoodMemory-First-Principles-and-Reference-Architecture.md)\n- v1 implementation architecture:\n  [docs/GoodMemory-OSS-Architecture-v1.md](./docs/GoodMemory-OSS-Architecture-v1.md)\n- PRD:\n  [docs/GoodMemory-PRD.md](./docs/GoodMemory-PRD.md)\n- TDD and evaluation strategy:\n  [docs/GoodMemory-TDD-and-Evaluation-Strategy.md](./docs/GoodMemory-TDD-and-Evaluation-Strategy.md)\n- Strategy rollout guide:\n  [docs/GoodMemory-Strategy-Rollout-Guide.md](./docs/GoodMemory-Strategy-Rollout-Guide.md)\n- Release checklist:\n  [docs/GoodMemory-v1-Release-Checklist.md](./docs/GoodMemory-v1-Release-Checklist.md)\n- Historical quality-gate archive:\n  [docs/archive/quality-gates/README.md](./docs/archive/quality-gates/README.md)\n- Historical v1 snapshot:\n  [docs/GoodMemory-v1-Quality-Gate.md](./docs/GoodMemory-v1-Quality-Gate.md)\n- Framework cookbooks — durable memory in an agent framework:\n  [LangGraph](./docs/cookbooks/langgraph.md) ·\n  [CrewAI](./docs/cookbooks/crewai.md) ·\n  [OpenAI Agents SDK](./docs/cookbooks/openai-agents-sdk.md)\n\nUse [task-board/00-README.txt](./task-board/00-README.txt) for execution order,\nopen follow-up work, and phase-specific acceptance boundaries. Archived design\ninputs are not current truth and are routed through `docs/README.md`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjqcan%2FGoodMemory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhjqcan%2FGoodMemory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjqcan%2FGoodMemory/lists"}