Better Memory
A persistent, file-based memory store. Memories are JSON entries, each scoped by a
project and labeled with one or more tags, plus a short id. Everything
goes through one script, scripts/memory.sh:
recall — compact index of what's stored, including the tags in scope (run first)
add — store a new memory (one or more tags required)
list — list memories in full
search — find memories by literal content match
get — show one memory in full
update — change a memory's content and/or tags
delete — remove a memory, or memories in a project by tag
Use it like memory
This store only surfaces what you ask for, so treat it as an active habit:
- Recall at the start of work. Run
scripts/memory.sh recall to load what's
known (snippets plus the tags in scope) before acting. Pull full content with
get/list when a snippet looks relevant.
- Capture what's worth keeping. After the user corrects you, states a durable
preference, or makes a decision worth remembering,
add it with descriptive
tags. Capture proactively, but only things that will matter again.
- Verify before you trust. A memory naming a file, function, or flag was true
when written and can go stale. Check it against the current code before acting,
then
update or delete if it is wrong now.
Tags
Tags are the retrieval axis: you save with the tags that describe a memory and
fetch by tag. A memory can carry several.
- Filtering by multiple
--tag is AND: a memory must have all the given tags.
Narrow an ambiguous fetch by adding more tags.
recall prints "Tags in scope" so you can see the existing vocabulary.
Reuse exact tags (matching is case-sensitive); avoid near-duplicates like
db vs database.
- Combine a type tag with topic tags. A type tag says what kind of memory it
is (
decision, convention, gotcha, preference, reference, todo); topic
tags say what it is about (database, auth, billing, letter). Together they
make memories findable from either angle.
- Tags bridge wording that literal
search misses. A note whose text says
"open formal correspondence with a courteous salutation" can be tagged letter,
so recall --tag letter finds it even though search --query letter would not.
Commands
# Recall: compact index (snippets + tags). --format json gives {id, project, tags, summary}.
scripts/memory.sh recall
scripts/memory.sh recall --tag letter --all
# Add: project defaults to the current repo; at least one --tag and --content required.
scripts/memory.sh add --tag decision --tag database --content "Chose Postgres over Mongo."
scripts/memory.sh add --project acme-api --tag gotcha --tag users --content "users table uses soft deletes."
# List full content, grouped by project (tags shown under each).
scripts/memory.sh list
scripts/memory.sh list --all --tag decision
# Search content literally (case-insensitive); --regex for patterns. Optional --tag filter.
scripts/memory.sh search --query postgres
scripts/memory.sh search --query salutation --all
# Get one memory (by id, or by tag(s) in scope; --all searches every project).
scripts/memory.sh get --id 1a2b3c4d
scripts/memory.sh get --tag letter --all
# Update content and/or tags (target by id, or by tag(s) in scope).
scripts/memory.sh update --id 1a2b3c4d --content "Revised note."
scripts/memory.sh update --id 1a2b3c4d --add-tag urgent --remove-tag draft
# Delete (explicit project or id only).
scripts/memory.sh delete --id 1a2b3c4d
scripts/memory.sh delete --project acme-api --tag scratch --yes
Re-adding the same content under the same project is a no-op (reports the existing id).
Scope (project)
Read commands (recall, list, search) and add default the project to the
current repo (git repository basename, else the current directory name).
get and update use the same default when you target by --tag.
--project <name> targets a specific project instead.
--all spans every project (on recall/list/search, and on get/update
when targeting by --tag).
delete never auto-detects the project — pass --project or --id explicitly.
Data model
Memories live in a single file at ~/.agents/better-memories/memories.json
(chmod 600), created on first write. It is one store shared across all repos,
partitioned by each memory's project. A memory looks like:
{ "id": "1a2b3c4d", "project": "acme-api", "tags": ["decision", "database"],
"content": "...", "created_at": "...", "updated_at": "..." }
Tags are de-duplicated on write.
Targeting rules
--id targets exactly one memory. Use it whenever you have the id.
get/update accept --tag (in the current or --project scope) and act only
when exactly one memory matches. If several match, the script lists their ids so
you re-run with --id or add more --tag to narrow.
delete takes --id, or --project optionally narrowed by --tag (AND); a
multi-match delete requires --yes.
update changes content (--content) and/or tags (--add-tag/--remove-tag),
but never a memory's project; a memory must keep at least one tag.
Mapping requests to commands
Translate what the user says into a command. When unsure, recall first.
| The user says |
Do |
| Starting work, or "what do you know about this project?" |
recall |
| "what do you remember about auth?" |
recall --tag auth, then read and answer |
| "what do you remember about writing a letter?" |
recall --tag letter (tags bridge wording search misses) |
| "find the note that mentions Postgres" |
search --query postgres |
| "remember we use pnpm, not npm" |
add --tag preference --tag tooling --content "Use pnpm, not npm." |
| "note the users table uses soft deletes" |
add --tag gotcha --tag database --content "users table uses soft deletes; filter deleted_at IS NULL." |
| "that decision changed, we use SQS now" |
find it via recall, then update --id <id> --content "..." |
| "tag that note urgent" |
update --id <id> --add-tag urgent |
| "forget the scratch notes for this repo" |
delete --project <repo> --tag scratch (confirm first) |
Worked example
Capture a decision, then recall it in a later session:
# 1) The user decides something worth keeping (project auto-detected from the repo)
$ scripts/memory.sh add --tag decision --tag database \
--content "Chose Postgres over Mongo for relational integrity."
Added memory [4f8a2c1d] under acme-api [tags: database, decision] (project auto-detected; use --project to override).
# 2) Next session, before related work, recall the current repo's memories
$ scripts/memory.sh recall
Memory index - acme-api (current repo; pass --project <name> or --all)
Tags in scope: database (1), decision (1)
acme-api (1)
[4f8a2c1d] Chose Postgres over Mongo for relational integrity. #database #decision
# 3) Pull the full entry when a snippet looks relevant
$ scripts/memory.sh get --id 4f8a2c1d
What to store (and not)
Store durable, reusable facts: decisions and their rationale, project
conventions, gotchas, user/team preferences, and pointers to external resources.
Don't store: secrets or tokens; facts trivially derivable by reading the code;
ephemeral task state; or one-off answers. Run recall/search before adding to
avoid near-duplicates.
Safety
- Deletes are destructive and permanent. Confirm with the user before deleting
a whole project or any multi-match (
--yes) delete.
- Recall or list before
update/delete to confirm the id and current content.
- Don't fabricate memories. Store only what is actually true and worth keeping.
Gotchas
- Tag and project matching is exact and case-sensitive. Recall first and reuse
existing tags rather than creating variants.
search matches memory text literally, so it misses synonyms and paraphrases.
For concept-based recall, use recall (and tags), not search.
recall shows truncated snippets; list/get show full content.
- The store is
~/.agents/better-memories/memories.json (created on first write);
a store in the skill's own directory is still read if one exists there.
update can change content and tags, but never a memory's project; a memory
must always keep at least one tag.
- A skill loads only when invoked, so this store is not auto-injected every
session — run
recall to bring memories into context.
1---2name: better-memory3description: Persistent project memory stored as JSON, scoped by project and tags. Use to recall what's already known at the start of work, capture things worth remembering after a correction, preference, or decision, and to add, list, search, update, or delete memories by tag — whenever the user says remember this, note that, what do you remember about X, or forget Y. Tags let you save and fetch precisely and bridge wording that literal search misses. Defaults to the current repo and persists across sessions.4---56# Better Memory78A persistent, file-based memory store. Memories are JSON entries, each scoped by a9**project** and labeled with one or more **tags**, plus a short **id**. Everything10goes through one script, `scripts/memory.sh`:1112- `recall` — compact index of what's stored, including the tags in scope (run first)13- `add` — store a new memory (one or more tags required)14- `list` — list memories in full15- `search` — find memories by literal content match16- `get` — show one memory in full17- `update` — change a memory's content and/or tags18- `delete` — remove a memory, or memories in a project by tag1920## Use it like memory2122This store only surfaces what you ask for, so treat it as an active habit:23241. **Recall at the start of work.** Run `scripts/memory.sh recall` to load what's25 known (snippets plus the tags in scope) before acting. Pull full content with26 `get`/`list` when a snippet looks relevant.272. **Capture what's worth keeping.** After the user corrects you, states a durable28 preference, or makes a decision worth remembering, `add` it with descriptive29 tags. Capture proactively, but only things that will matter again.303. **Verify before you trust.** A memory naming a file, function, or flag was true31 when written and can go stale. Check it against the current code before acting,32 then `update` or `delete` if it is wrong now.3334## Tags3536Tags are the retrieval axis: you **save with the tags that describe a memory and37fetch by tag**. A memory can carry several.3839- **Filtering by multiple `--tag` is AND**: a memory must have all the given tags.40 Narrow an ambiguous fetch by adding more tags.41- **`recall` prints "Tags in scope"** so you can see the existing vocabulary.42 Reuse exact tags (matching is case-sensitive); avoid near-duplicates like43 `db` vs `database`.44- **Combine a type tag with topic tags.** A type tag says what kind of memory it45 is (`decision`, `convention`, `gotcha`, `preference`, `reference`, `todo`); topic46 tags say what it is about (`database`, `auth`, `billing`, `letter`). Together they47 make memories findable from either angle.48- **Tags bridge wording that literal `search` misses.** A note whose text says49 "open formal correspondence with a courteous salutation" can be tagged `letter`,50 so `recall --tag letter` finds it even though `search --query letter` would not.5152## Commands5354```bash55# Recall: compact index (snippets + tags). --format json gives {id, project, tags, summary}.56scripts/memory.sh recall57scripts/memory.sh recall --tag letter --all5859# Add: project defaults to the current repo; at least one --tag and --content required.60scripts/memory.sh add --tag decision --tag database --content "Chose Postgres over Mongo."61scripts/memory.sh add --project acme-api --tag gotcha --tag users --content "users table uses soft deletes."6263# List full content, grouped by project (tags shown under each).64scripts/memory.sh list65scripts/memory.sh list --all --tag decision6667# Search content literally (case-insensitive); --regex for patterns. Optional --tag filter.68scripts/memory.sh search --query postgres69scripts/memory.sh search --query salutation --all7071# Get one memory (by id, or by tag(s) in scope; --all searches every project).72scripts/memory.sh get --id 1a2b3c4d73scripts/memory.sh get --tag letter --all7475# Update content and/or tags (target by id, or by tag(s) in scope).76scripts/memory.sh update --id 1a2b3c4d --content "Revised note."77scripts/memory.sh update --id 1a2b3c4d --add-tag urgent --remove-tag draft7879# Delete (explicit project or id only).80scripts/memory.sh delete --id 1a2b3c4d81scripts/memory.sh delete --project acme-api --tag scratch --yes82```8384Re-adding the same content under the same project is a no-op (reports the existing id).8586## Scope (project)8788Read commands (`recall`, `list`, `search`) and `add` default the project to the89**current repo** (git repository basename, else the current directory name).90`get` and `update` use the same default when you target by `--tag`.9192- `--project <name>` targets a specific project instead.93- `--all` spans every project (on `recall`/`list`/`search`, and on `get`/`update`94 when targeting by `--tag`).95- `delete` never auto-detects the project — pass `--project` or `--id` explicitly.9697## Data model9899Memories live in a single file at `~/.agents/better-memories/memories.json`100(`chmod 600`), created on first write. It is one store shared across all repos,101partitioned by each memory's `project`. A memory looks like:102103```json104{ "id": "1a2b3c4d", "project": "acme-api", "tags": ["decision", "database"],105 "content": "...", "created_at": "...", "updated_at": "..." }106```107108Tags are de-duplicated on write.109110## Targeting rules111112- `--id` targets exactly one memory. Use it whenever you have the id.113- `get`/`update` accept `--tag` (in the current or `--project` scope) and act only114 when exactly one memory matches. If several match, the script lists their ids so115 you re-run with `--id` or add more `--tag` to narrow.116- `delete` takes `--id`, or `--project` optionally narrowed by `--tag` (AND); a117 multi-match delete requires `--yes`.118- `update` changes content (`--content`) and/or tags (`--add-tag`/`--remove-tag`),119 but never a memory's project; a memory must keep at least one tag.120121## Mapping requests to commands122123Translate what the user says into a command. When unsure, `recall` first.124125| The user says | Do |126| --- | --- |127| Starting work, or "what do you know about this project?" | `recall` |128| "what do you remember about auth?" | `recall --tag auth`, then read and answer |129| "what do you remember about writing a letter?" | `recall --tag letter` (tags bridge wording `search` misses) |130| "find the note that mentions Postgres" | `search --query postgres` |131| "remember we use pnpm, not npm" | `add --tag preference --tag tooling --content "Use pnpm, not npm."` |132| "note the users table uses soft deletes" | `add --tag gotcha --tag database --content "users table uses soft deletes; filter deleted_at IS NULL."` |133| "that decision changed, we use SQS now" | find it via `recall`, then `update --id <id> --content "..."` |134| "tag that note urgent" | `update --id <id> --add-tag urgent` |135| "forget the scratch notes for this repo" | `delete --project <repo> --tag scratch` (confirm first) |136137## Worked example138139Capture a decision, then recall it in a later session:140141```bash142# 1) The user decides something worth keeping (project auto-detected from the repo)143$ scripts/memory.sh add --tag decision --tag database \144 --content "Chose Postgres over Mongo for relational integrity."145Added memory [4f8a2c1d] under acme-api [tags: database, decision] (project auto-detected; use --project to override).146147# 2) Next session, before related work, recall the current repo's memories148$ scripts/memory.sh recall149Memory index - acme-api (current repo; pass --project <name> or --all)150Tags in scope: database (1), decision (1)151152acme-api (1)153 [4f8a2c1d] Chose Postgres over Mongo for relational integrity. #database #decision154155# 3) Pull the full entry when a snippet looks relevant156$ scripts/memory.sh get --id 4f8a2c1d157```158159## What to store (and not)160161**Store** durable, reusable facts: decisions and their rationale, project162conventions, gotchas, user/team preferences, and pointers to external resources.163164**Don't store:** secrets or tokens; facts trivially derivable by reading the code;165ephemeral task state; or one-off answers. Run `recall`/`search` before adding to166avoid near-duplicates.167168## Safety169170- **Deletes are destructive and permanent.** Confirm with the user before deleting171 a whole project or any multi-match (`--yes`) delete.172- **Recall or list before `update`/`delete`** to confirm the id and current content.173- **Don't fabricate memories.** Store only what is actually true and worth keeping.174175## Gotchas176177- Tag and project matching is exact and case-sensitive. Recall first and reuse178 existing tags rather than creating variants.179- `search` matches memory text literally, so it misses synonyms and paraphrases.180 For concept-based recall, use `recall` (and tags), not `search`.181- `recall` shows truncated snippets; `list`/`get` show full content.182- The store is `~/.agents/better-memories/memories.json` (created on first write);183 a store in the skill's own directory is still read if one exists there.184- `update` can change content and tags, but never a memory's project; a memory185 must always keep at least one tag.186- A skill loads only when invoked, so this store is not auto-injected every187 session — run `recall` to bring memories into context.188