{"id":51530690,"url":"https://github.com/acoyfellow/deja","last_synced_at":"2026-07-09T02:01:04.877Z","repository":{"id":335488148,"uuid":"1145964412","full_name":"acoyfellow/deja","owner":"acoyfellow","description":"Persistent memory for agents. Agents learn from failures. Deja remembers.","archived":false,"fork":false,"pushed_at":"2026-06-11T10:31:14.000Z","size":3193,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-11T12:14:45.692Z","etag":null,"topics":["agent-infrastructure","agent-memory","ai-agents","cloudflare","cloudflare-workers","durable","llm-memory","recall","semantic-search","vector-search","vectorize","workers-ai"],"latest_commit_sha":null,"homepage":"https://deja.coey.dev/","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/acoyfellow.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-30T12:53:00.000Z","updated_at":"2026-06-11T10:31:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/acoyfellow/deja","commit_stats":null,"previous_names":["acoyfellow/deja"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/acoyfellow/deja","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Fdeja","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Fdeja/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Fdeja/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Fdeja/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acoyfellow","download_url":"https://codeload.github.com/acoyfellow/deja/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Fdeja/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35283905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","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-infrastructure","agent-memory","ai-agents","cloudflare","cloudflare-workers","durable","llm-memory","recall","semantic-search","vector-search","vectorize","workers-ai"],"created_at":"2026-07-09T02:01:02.656Z","updated_at":"2026-07-09T02:01:04.869Z","avatar_url":"https://github.com/acoyfellow.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# deja\n\n[![CI](https://github.com/acoyfellow/deja/actions/workflows/ci.yml/badge.svg)](https://github.com/acoyfellow/deja/actions/workflows/ci.yml)\n\n**Memory that lets coding agents continue instead of start over.**\n\nDeja gives an agent a fast, repository-scoped memory between sessions. It stores decisions, preferences, procedures, pitfalls, facts, and work in progress in one inspectable SQLite file. Recall is local, bounded, cited, and honest about uncertainty.\n\n```text\nfinish a session                         start the next one\n       │                                        │\n       ▼                                        ▼\n remember decisions ──► SQLite + FTS ──► recall relevant context\n leave a handoff         per-repo scope    continue the work\n       ▲                                        │\n       └──────── useful / wrong feedback ◄──────┘\n```\n\nNo account. No daemon. No embeddings required. No transcript dump into the prompt.\n\n\u003e **Release status:** local Deja is the production surface in `v0.1.0`. Shared mode is a tested preview and intentionally remains local-only until its security review is complete.\n\n## Why Deja\n\nCoding agents repeatedly lose the expensive parts of prior work:\n\n- the decision and why it was made;\n- the command that finally worked;\n- the failure mode that should not be repeated;\n- the exact next step after context compaction;\n- the user's project-specific preference.\n\nA notes database is not enough. Memory must appear in the right repository, fit inside a context budget, distinguish relevance from trust, stop surfacing completed work, and expose evidence when it fails. Those constraints shape Deja.\n\n## Install\n\nDeja currently requires [Bun](https://bun.sh).\n\n```bash\nbun add github:acoyfellow/deja\nbunx github:acoyfellow/deja init\n```\n\nOr clone it:\n\n```bash\ngit clone https://github.com/acoyfellow/deja\ncd deja\nbun install\nbun run src/cli.ts init\n```\n\n`deja init` creates `~/.deja/deja.db` and prints MCP configuration for Claude Code, OpenCode, and Pi.\n\n## The 60-second agent setup\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"deja\": {\n      \"command\": \"bunx\",\n      \"args\": [\"github:acoyfellow/deja\", \"mcp\"]\n    }\n  }\n}\n```\n\nThe tool descriptions are the operating contract. Deja does not require a `SKILL.md`, `AGENTS.md`, or a memory paragraph copied into every system prompt.\n\nAt the beginning of work, an agent calls:\n\n```text\nrecall(\"\")\n```\n\nAt the end, it calls:\n\n```text\nhandoff({ summary: \"Implemented scoped auth\", next: [\"run the remote smoke test\"] })\n```\n\n## What ships in v0.1.0\n\n### Repository isolation by default\n\nDeja derives a stable scope from the nearest Git repository and its normalized `origin`. Two checkouts of the same repository share a scope; unrelated repositories do not leak slips or handoffs into each other.\n\nUse `DEJA_SCOPE=global` deliberately for a cross-project preference. Global slips may match any repository query, but global handoffs never direct repository work.\n\nDatabases created before scoping migrate safely to `legacy:global`. Those rows are excluded unless `DEJA_INCLUDE_LEGACY=1` is explicitly set during migration.\n\n### Typed memory without filing work\n\nEvery slip has one kind:\n\n| Kind | Use it for |\n|---|---|\n| `decision` | A choice that constrains future work |\n| `preference` | A user or project preference |\n| `procedure` | A reusable, verified sequence |\n| `pitfall` | A failure, sharp edge, or thing not to repeat |\n| `fact` | A verified project-specific finding |\n| `wip` | Current work, blockers, and next steps |\n| `note` | Safe fallback for everything else |\n\nAgents may set the kind. If they do not, Deja uses a conservative deterministic heuristic—never a hidden model call.\n\n### Bounded context packets\n\nRecall accepts an approximate token budget and optional kind filters:\n\n```ts\nconst result = d.recall(\"deploy staging\", {\n  limit: 8,\n  maxTokens: 700,\n  kinds: [\"decision\", \"procedure\", \"pitfall\"],\n});\n```\n\nDeja retrieves locally, follows explicit supersession to current memory, deduplicates, and stops before the packet grows beyond the budget. Each hit carries its kind, provenance, evidence trust, and links.\n\n### Trust is not relevance\n\nBM25 answers **“does this text match?”** It does not answer **“is this true?”**\n\nDeja keeps those concepts separate:\n\n| Trust | Meaning |\n|---|---|\n| `low` | Draft or disputed; verify before relying on it |\n| `medium` | Kept, but not yet confirmed through use |\n| `high` | Kept and materially useful at least twice |\n\nMutable facts should still be checked against live code and systems. Deja never labels a lexical match “authoritative.”\n\n### Current truth without rewriting history\n\nSlips are immutable. A correction creates a new slip and links it:\n\n```ts\nconst old = d.remember(\"Use Jest\", { kind: \"decision\" });\nconst current = d.remember(\"Use Vitest\", {\n  kind: \"decision\",\n  links: [{ toId: old.id, kind: \"supersedes\" }],\n});\n```\n\nRecall follows `supersedes` to the current slip. `contradicts` keeps both claims visible. The history remains inspectable.\n\n### Handoffs that stop when work stops\n\nA handoff is an active continuation packet, not a permanent instruction. Keeping an obvious decision/preference/WIP memory can create an automatic safety-net handoff; the session's explicit final handoff replaces that automatic packet rather than failing:\n\n```ts\nconst h = d.handoff({\n  summary: \"Auth refactor is implemented but not deployed.\",\n  next: [\"run integration tests\", \"deploy canary\"],\n});\n\n// Later:\nd.resolveHandoff(h.id, \"completed\");\n```\n\nOnly active, repository-scoped handoffs appear in normal recall. Resolved or abandoned work no longer directs the next agent. An unresolved handoff older than three days is labeled stale and advisory so an agent verifies it before acting.\n\n### A measurable feedback loop\n\nBy default, each recall returns a content-free receipt id. Library callers handling sensitive queries may disable trace storage with `recordRecallTraces: false`; those calls return `traceId: null`. After acting, an agent can assess a stored retrieval:\n\n```ts\nconst result = d.recall(\"test runner\");\nd.assessRecall(result.traceId, \"useful\");\n```\n\nAssessments are:\n\n- `useful` — the packet helped;\n- `wrong` — surfaced context was misleading;\n- `missed` — needed memory existed or should have existed but was absent;\n- `no_memory_needed` — not a memory-shaped task.\n\nThe trace stores query, scope, returned IDs, handoff ID, session, author, and timestamp. It does **not** duplicate memory text or transcripts. `deja eval` reports scoped evidence so retrieval changes can be evaluated against real use.\n\n## Agent API\n\n```ts\nimport { Deja } from \"deja\";\n\nconst d = new Deja();\n\nconst slip = d.remember(\"Decision: use Bun for repository scripts\", {\n  kind: \"decision\",\n  tags: [\"tooling\"],\n});\n\nd.keep([slip.id]);\n\nconst recalled = d.recall(\"repository runtime\", {\n  maxTokens: 600,\n  kinds: [\"decision\", \"pitfall\"],\n});\n\nif (recalled.hits[0]) d.used(recalled.hits[0].slip.id);\nd.assessRecall(recalled.traceId, \"useful\", \"avoided rechecking package scripts\");\n\nd.handoff({\n  summary: \"Converted scripts to Bun; tests pass.\",\n  next: [\"update the release workflow\"],\n});\n```\n\n### Core lifecycle\n\n```ts\nd.remember(text, options?)\nd.keep(ids)\nd.recall(query, { limit?, maxTokens?, kinds? })\nd.handoff({ summary, next? })\nd.resolveHandoff(id, \"completed\" | \"abandoned\")\n```\n\n### Evidence and correction\n\n```ts\nd.used(slipId)\nd.wrong(slipId)\nd.forget(slipId)\nd.link(fromId, toId, \"supersedes\" | \"contradicts\" | \"related\")\nd.assessRecall(traceId, assessment, note?)\nd.recallReport()\n```\n\n### Deliberate bulk cleanup\n\n```ts\nd.forgetSession(sessionId) // current repository scope only\n```\n\n## MCP tools\n\nThe local MCP server exposes two small groups.\n\n**Memory**\n\n| Tool | Purpose |\n|---|---|\n| `recall` | Scoped, budgeted retrieval plus the active handoff |\n| `remember` | Draft or keep a typed memory; optionally supersede/contradict old slips |\n| `handoff` | Leave one active continuation packet for the next session |\n| `resolve_handoff` | Complete or abandon a handoff |\n| `signal` | Mark one slip used, wrong, or forgotten |\n| `link` | Relate two existing slips |\n| `assess` | Evaluate a recall receipt |\n\n**Local coordination**\n\n| Tool | Purpose |\n|---|---|\n| `send` | Send an asynchronous local message |\n| `inbox` | Read messages for an agent identity |\n| `read` | Mark a message read |\n| `reply` | Continue the message thread |\n\nThe mailbox is intentionally not memory truth. It is a small local coordination channel.\n\n## CLI\n\n```bash\ndeja init\ndeja verify\ndeja stats\n\ndeja recall                         # scoped recents + active handoff\ndeja recall \"deployment decision\" --tokens=700 --kind=decision,pitfall\ndeja remember \"Decision: deploy with Wrangler\" --kind=decision --keep\ndeja handoff \"Canary is live; verify logs next\"\ndeja resolve \u003chandoff-id\u003e completed\n\ndeja link \u003cnew-id\u003e supersedes \u003cold-id\u003e\ndeja assess \u003ctrace-id\u003e useful \"saved a repository scan\"\ndeja eval\n\ndeja ls\ndeja show \u003cslip-id\u003e\ndeja handoffs\ndeja forget-session \u003csession-id\u003e --yes\n```\n\nDestructive session cleanup requires `--yes` and is restricted to the current repository scope.\n\n## Storage and migration\n\nThe default database is `~/.deja/deja.db`.\n\n| Table | Purpose |\n|---|---|\n| `slips` | Immutable memory text, kind, scope, lifecycle, evidence counts |\n| `slips_fts` | Porter-stemmed FTS5 index over text and tags |\n| `links` | Supersession, contradiction, and related-memory edges |\n| `handoffs` | Active/resolved continuation packets |\n| `recall_traces` | Retrieval receipts and assessments, without duplicated memory text |\n| `messages` | Local asynchronous agent mailbox |\n\nSchema changes are additive and run automatically when Deja opens the database. Existing text is never rewritten during migration.\n\nUseful environment variables:\n\n```bash\nDEJA_DB=~/.deja/deja.db       # database path\nDEJA_AUTHOR=pi                # provenance identity\nDEJA_SESSION=\u003cconversation\u003e   # stable session supplied by the harness\nDEJA_SCOPE=global             # deliberate override; normally automatic\nDEJA_INCLUDE_LEGACY=1         # temporary pre-v0.1 migration aid\n```\n\nLocal SQLite is plaintext. Do not store credentials, customer data, or secrets. See [`SECURITY.md`](SECURITY.md) for the supported boundary and vulnerability-reporting guidance.\n\n## Shared mode — preview\n\nShared Deja uses Cloudflare infrastructure only:\n\n```text\nWorker + one Durable Object SQL database per memory space\n                        │\n          numbered committed changes + SSE\n                        │\n          rebuildable local SQLite/FTS mirrors\n```\n\nIt already proves:\n\n- server commit before write receipt;\n- immediate read-after-write in the writer's local mirror;\n- live peer updates that never block writes;\n- contiguous revision watermarks and explicit stale state;\n- offline catch-up;\n- replayable hard deletion with remembered payload redaction;\n- bounded stream lifetimes and reauthentication points;\n- token-to-space isolation in local dogfood.\n\nRun the full two-client proof locally:\n\n```bash\n./shared-server/test-local.sh\n```\n\n**Do not deploy it yet.** Bearer-token dogfood is not a production identity system. Employee or multi-user use still requires verified identity, revocation, content policy, audit/retention decisions, and an encryption story. The blocking review is documented in [`docs/shared-security-review.md`](docs/shared-security-review.md).\n\nSee [`docs/shared-memory.md`](docs/shared-memory.md) for the protocol and [`docs/shared-memory-implementation-contract.md`](docs/shared-memory-implementation-contract.md) for invariants.\n\n## Evidence\n\nRun the complete local release gate:\n\n```bash\nbun run check\n```\n\nIt runs:\n\n```bash\nbun test ./test\nbun run typecheck\nbun run bench/recall.ts\nbun run bench:behavior\n```\n\nThe repository also contains:\n\n- [`docs/bench/claims.md`](docs/bench/claims.md) — claim-to-evidence map;\n- [`docs/loops/`](docs/loops/) — failed and successful agent behavior experiments;\n- [`experiments/`](experiments/) — Cloudflare shared-memory protocol receipts;\n- [`experiments/MEMORY-SEAMS-2026-06-11.md`](experiments/MEMORY-SEAMS-2026-06-11.md) — Cloudflare-native Workspace, Containers, Workflows, DO, AI Gateway, Access, continuity, provider-contract, and model-compatibility experiments;\n- [`eval/next-agent/`](eval/next-agent/) — a retained negative result that prevented an unproven ranker from becoming default behavior.\n\nThe eight-case lexical benchmark is a smoke test, not proof that memory improves agents. Recall receipts and baseline-vs-Deja session experiments are the path to stronger claims.\n\n## Design boundaries\n\nDeja is deliberately:\n\n- **local-first**, not remote-only;\n- **lexical and deterministic by default**, not vector-first;\n- **repository-scoped**, not one global memory soup;\n- **append-only and auditable**, not silently self-rewriting;\n- **budgeted**, not a transcript injector;\n- **honest about stale state**, not eventually-consistent theater.\n\nDeja is not a secrets manager, generic RAG platform, team ACL product, or replacement for source control.\n\n## Roadmap\n\nThe complete production/share roadmap, release gates, and next feature batch live in [`docs/ROADMAP.md`](docs/ROADMAP.md). Completed work stays checked off; hypotheses remain explicitly unshipped until an eval earns them.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facoyfellow%2Fdeja","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facoyfellow%2Fdeja","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facoyfellow%2Fdeja/lists"}