Persistent project-scoped memory for LLM agents. Stores facts, decisions, references, status snapshots, and other project context in a local SQLite database so future agent sessions can recall them.
By default, the database lives at .agents/memory.db relative to the project root. You can override it with MACHINE_MEMORY_DB_PATH (absolute or cwd-relative path).
Download the latest binary for your platform from Releases and place it somewhere on your $PATH.
Or build from source:
bun install
bun run buildThis is not a general-purpose note-taking tool. It's for things an agent needs to remember across sessions:
- Architectural decisions — "We chose Drizzle over Prisma because..."
- Reference docs/specs — "Runs API status enum:
running | errored | finished" - Status snapshots — "Coverage audit shows missing memory tags for
sdk/" - Project conventions — "All API routes return
{ data, error }shape" - Non-obvious gotchas — "The users table uses UUIDs, not auto-increment"
- Environment/tooling notes — "Run
machine-memory migrateafter pulling main" - User preferences — "User prefers explicit error handling over try/catch"
Copy this block into your project's AGENTS.md (or CLAUDE.md, .cursorrules, etc.):
## Project memory
This project uses `machine-memory` for persistent agent context stored at `.agents/memory.db`.
### One-sweep workflow (use this every task)
1. **Scan relevant context fast (compact mode)**
- `machine-memory suggest --files "<paths you'll touch>" --brief`
- `machine-memory query "<feature/topic>" --brief`
- `machine-memory list --tags "<domain>" --brief`
- Run this sweep once per task; repeat only if touched paths or scope materially change.
- Use `machine-memory get <id>` only when you need full detail.
2. **If your inference may conflict, verify before editing memory**
- `machine-memory verify <id> "<inferred fact>"`
- `machine-memory diff <id> "<proposed updated wording>"`
3. **Maintain memories while implementing**
- Prefer one canonical memory per feature thread:
- `machine-memory update --match "topic query" "new canonical content"`
- If no reliable match exists, create with `machine-memory add ... --upsert-match "topic query"` so repeated writes update instead of duplicating.
- Add new durable knowledge (prefer path-driven tagging):
- `machine-memory add "..." --path "documentation/content/docs/guides/example.mdx" --context "why it matters" --type "decision|reference|status|..." --certainty "verified|inferred|speculative"`
- If path mapping is unavailable, use `--tags "area:...,topic:...,kind:..."`.
- Update stale memories:
- `machine-memory update <id> "new content"`
- `machine-memory update <id1,id2,id3> "new content"` (multi-ID)
- `machine-memory update --match "topic" --from-file ./notes.md`
- Deprecate replaced memories:
- `machine-memory deprecate <id> --superseded-by <new_id>`
- `machine-memory deprecate <id1,id2,id3> --superseded-by <new_id>` (multi-ID)
- Delete invalid memories:
- `machine-memory delete <id>` or `machine-memory delete <id1,id2,id3>`
4. **Use tight tag taxonomy via path mapping (recommended)**
- Prefer scoped tags: `area:*`, `topic:*`, `kind:*` (for example: `area:cli,topic:vendor-aws,kind:status`)
- `machine-memory tag-map set "documentation/content/docs/guides/example.mdx" "area:docs,topic:guides,kind:reference"`
- `machine-memory tag-map suggest "documentation/content/docs/guides/example.mdx"`
- `machine-memory add "..." --path "documentation/content/docs/guides/example.mdx"` (preferred over manual tag strings)
5. **Status hygiene**
- When adding `--type status`, `status_cascade` suggestions are candidates, not auto-actions.
- Before any deprecate from `status_cascade`, run `machine-memory get <id>` and `machine-memory verify <id> "<replacement claim>"` (or `diff`) to confirm semantic overlap.
- Keep one active status memory per task thread; prefer updating it over adding same-task status memories unless scope materially changes.
- Short-lived status should include expiry: `--expires-after-days <n>`.
- Run `machine-memory doctor` and review suggested `deprecate`/`update` commands semantically before applying.
6. **Write for retrieval**
- Put key anchors in the first sentence when possible: command names, API paths, file paths, and exact feature keywords.
7. **Separate durable vs transient facts**
- Use `--type reference` for durable implementation facts, reusable docs notes, and non-obvious gotchas.
- Use `--type decision` for durable rules/architecture.
- Use `--type status` for progress snapshots/current state.
8. **Task-end persistence rule**
- Always persist non-obvious outcomes future sessions need (decisions, references, status snapshots, gotchas, tooling notes, user preferences).
- Do **not** store obvious code facts, temporary notes, or duplicates.Default output is JSON — designed to be parsed by an LLM agent.
--brief on query, list, and suggest emits compact text lines for fast scanning.
Run machine-memory help (or machine-memory --help) to get full usage information as JSON.
machine-memory add "Auth uses JWT with RS256" --tags "auth,architecture" --context "Found in src/auth/jwt.ts"
machine-memory add "Auth uses JWT with RS256" --no-conflicts
machine-memory add "Auth uses JWT with RS256" --brief
machine-memory add "Auth uses JWT with RS256" --json-min
machine-memory add "Auth uses JWT with RS256" --quiet
machine-memory add "Schema contract lives in SDK" --path "sdk/src/schema.ts"
machine-memory add --from-file ./docs/api-field-notes.md --type "reference"machine-memory add "Sessions are cached for 5m" \
--tags "auth,cache" \
--type "decision" \
--certainty "verified" \
--source-agent "gpt-5-codex" \
--refs '["docs/adr/session-cache.md","https://github.com/org/repo/pull/123"]' \
--expires-after-days 30machine-memory query "auth"
machine-memory query "auth" --type "decision" --certainty "verified"
machine-memory query "non-english"
machine-memory query "auth" --brief
machine-memory query "auth" --json-min
machine-memory query "auth" --quietmachine-memory list
machine-memory list --tags "database"
machine-memory list --type "gotcha" --certainty "inferred"
machine-memory list --briefmachine-memory get 1machine-memory update 1 "Auth uses JWT with RS256, keys in VAULT_* env vars" --tags "auth,security"
machine-memory update 1,4,7 "Resolved after migration v2"
machine-memory update 1 "Auth uses JWT with RS256" --certainty "verified" --updated-by "gpt-5-codex"
machine-memory update --match "views schema" --from-file ./notes/views-schema.md --type "reference"machine-memory deprecate 12
machine-memory deprecate 1,4,7 --superseded-by 12
machine-memory deprecate 12 --superseded-by 42
machine-memory deprecate --match "legacy views status fields"machine-memory verify 12 "Auth currently uses RS256 JWT signatures"
machine-memory diff 12 "Auth now uses EdDSA JWT signatures"machine-memory tag-map set "sdk/src/schema.ts" "schema,types"
machine-memory tag-map suggest "sdk/src/schema.ts"
machine-memory tag-map list
machine-memory tag-map delete "sdk/src/schema.ts"machine-memory suggest --files "src/auth/jwt.ts,src/middleware/session.ts"
machine-memory suggest --files "src/auth/jwt.ts,src/middleware/session.ts" --brief
machine-memory suggest --files "src/auth/jwt.ts,src/middleware/session.ts" --json-min
machine-memory suggest --files-json '["src/app/blog/$slug.tsx","src/app/blog/[slug]/page.tsx"]'
machine-memory suggest --files "src/auth/jwt.ts,src/middleware/session.ts" --quietmachine-memory migratemachine-memory coverage --root .
machine-memory gc --dry-run
machine-memory statsmachine-memory import memories.json
machine-memory export
machine-memory export --type "decision" --certainty "verified" --since "2026-02-01T00:00:00Z"machine-memory delete 1machine-memory version
# Self-update to latest release
machine-memory upgrade
# Optional: override network timeout (default 15000ms)
MACHINE_MEMORY_UPGRADE_TIMEOUT_MS=30000 machine-memory upgradeEach stored memory includes the original fields plus structured metadata:
idcontenttags(comma-separated string)contextmemory_type(decision | convention | gotcha | preference | constraint | reference | status)certainty(verified | inferred | speculative, defaults toinferred)status(active | deprecated | superseded_by, defaults toactive)superseded_by(ID ornull)source_agentlast_updated_byupdate_countrefs(JSON array in CLI output; stored internally as JSON string)expires_after_days(TTL hint; no auto-deprecation)created_atupdated_at
Notes:
query,list, andexportreturn only active memories by default.- Use
--include-deprecated(or--status ...onlist) to inspect deprecated/superseded entries. addreturnspotential_conflictsby default; use--no-conflictsto skip conflict search.- Adding a new
--type statusmemory with overlapping tags returnsstatus_cascadewith a suggesteddeprecatecommand; treat it as a candidate and semantically verify before deprecating. doctoraudits duplicate/stale entries, tag taxonomy drift (area:*,topic:*,kind:*), missing status expiry, and status/decision type-boundary mismatches.queryandsuggestreturn a numericscoreand are sorted descending by score.--brieflines use:[ID] <Certainty> <Type>: <Content> (#Tags).- Empty
queryresults return a diagnostic object withderived_terms,filters, andhints. - Reads open the DB in query-only mode; schema writes run via write commands and
migrate. - For shell-expanded paths like
$slug.tsx, prefer single quotes or--files-json.
add (<content> | --from-file <path>)- Flags:
--tags,--path,--context,--type,--certainty,--source-agent,--updated-by,--refs,--expires-after-days,--from-file,--no-conflicts,--brief,--json-min,--quiet - Returns inserted memory (plus
potential_conflictsunless--no-conflicts/minimal output) - For
--type status, returnsstatus_cascadewhen older active status memories share tags (review candidates withget+verify/diffbefore deprecating)
- Flags:
query <search_term>- Flags:
--tags,--type,--certainty,--include-deprecated,--brief,--json-min,--quiet - Returns ranked matches with
score; empty results return diagnostics/hints
- Flags:
list- Flags:
--tags,--type,--certainty,--status,--include-deprecated,--brief
- Flags:
get <id>update (<id|id,id,...> | --match <query>) (<content> | --from-file <path>)- Flags:
--tags,--context,--type,--certainty,--updated-by,--refs,--expires-after-days <n|null>,--match,--from-file - Increments
update_count
- Flags:
deprecate (<id|id,id,...> | --match <query>)- Flags:
--superseded-by <id>,--updated-by,--match - Sets status to
deprecatedorsuperseded_by
- Flags:
delete <id|id,id,...>suggest --files "<csv paths>"- Alternate input:
--files-json '["path/one.ts","path/two.ts"]'(shell-safe for$paths) - Flags:
--brief,--json-min,--quiet - Derives keywords from file paths and merges FTS with path-neighborhood matches
- Alternate input:
verify <id> <fact>- Returns
ok: true|falseandresult: consistent|conflict
- Returns
diff <id> <new_content>- Returns
conflict,similarity, and term-level changes
- Returns
tag-map <list|set|delete|suggest>- Stores path-prefix to tag mappings in
.agents/path-tags.json
- Stores path-prefix to tag mappings in
migrate- Ensures schema/FTS/triggers are up to date
coverage [--root <path>]- Returns
uncovered_pathsandtag_distribution
- Returns
gc --dry-run- Returns active memories whose
updated_at + expires_after_daysis in the past
- Returns active memories whose
stats- Returns totals, breakdowns, tag frequency, stale counts, etc.
import <memories.json>- Accepts a JSON array matching the schema and returns per-entry
success | conflict | skip
- Accepts a JSON array matching the schema and returns per-entry
export- Flags:
--tags,--type,--certainty,--since <ISO date> - Exports active memories by default
- Flags:
Note
You may not want to commit memory.db. Make sure to add it to .gitignore if that is the case.
But do add .agents/.db-* to it to ignore generated SQLite artifacts.
The binary can update itself:
machine-memory upgradeThis checks GitHub releases for a newer version, downloads the correct binary for your platform, and replaces itself in-place.