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).
Warning
The smarter the model, the more effective this approach for context storage is.
That also means that lighter models might just outright not use this or fail to use it properly.
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 for humans; it's for things an agent needs to remember across sessions and only meant for agents to use:
- 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"
Add instructions to your project's AGENTS.md: it creates the file if it doesn't exist, or appends to existing file:
machine-memory update-agents-mdOr copy this block into your project's AGENTS.md:
# Project memory
This project uses `machine-memory` for persistent agent context stored at `.agents/memory.db`.
**MANDATORY: Memory scan MUST be completed BEFORE any code changes. Skipping this causes rework, regressions, and wasted time.**
## Required pre-workflow (DO NOT SKIP)
Before touching any code, you MUST complete this scan. No exceptions.
### Step 1: ALWAYS run one of these (choose based on what you know)
- `machine-memory suggest --files "<paths you'll touch>" --brief`
- `machine-memory query "<feature/topic>" --brief`
- `machine-memory list --tags "<domain>" --brief`
### Step 2: If results seem relevant, get full details
- `machine-memory get <id>`
**If you skip this:**
- You will miss prior decisions that constrain your solution
- You will duplicate work already done
- You will create inconsistencies with existing patterns
## 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:
update-agents-md- Appends the machine-memory AGENTS.md template to the current directory's AGENTS.md file
- Creates the file if it doesn't exist
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.