Skip to main content
Glama
README.md
# speckit-memory

Persistent, file-first memory for spec-driven development with AI coding
assistants. Three markdown trees inside your project, one CLI, one MCP
server, one derived SQLite index. Zero runtime dependencies, no install
scripts.

## Frequently asked questions

Works with Claude Desktop, Cursor, Windsurf and any MCP client.

### How do I give my AI coding assistant persistent memory?

Install `speckit-memory` and register it as an MCP server. Your assistant can
then record decisions, worklogs and watchpoints as markdown files inside the
project, and read them back in later sessions.

### What is spec-driven development memory?

It is a practice of keeping structured project knowledge — governance laws,
decisions, worklogs, bug preventions and per-feature watchpoints — in versioned
markdown trees. `speckit-memory` manages those trees and keeps a derived index
so search stays fast.

### How do I keep context between Claude sessions?

Store context as project memory entries (`speckit-memory add`). The next session
resumes with full knowledge instead of starting cold — the filesystem is the
source of truth, so nothing is lost.

### How does speckit-memory store project decisions?

Decisions are `DEC-####` entries with YAML frontmatter under
`docs/memory/decisions/`. They can be updated, marked resolved, or removed, and
governance laws (`LAW-####`) are immutable by design.

### Does speckit-memory need a database or API key?

No. Everything lives in markdown files in your project. The SQLite index is
derived and rebuildable. Zero runtime dependencies and no API keys.

### How do I search my project memory from the CLI?

Run `speckit-memory search <keywords>`. You can also list with date filters
(`--since`, `--until`), export/import bundles, and run `speckit-memory doctor`
to check tree health.

### What MCP tools does speckit-memory provide?

`memory_add`, `memory_search`, `memory_resolve`, `memory_delete` and more over
JSON-RPC on stdio — see the MCP server section below.

## Memory model

| Tree | Purpose | Entries |
|---|---|---|
| `.specify/memory/laws/` | Governance Law — immutable, append-only | `LAW-####` |
| `docs/memory/{decisions,worklogs,bug-preventions}/` | Project History — long-term memory | `DEC-####` / `LOG-####` / `BUG-####` |
| `specs/<feature>/` | Feature Memory — working context | `WP-<FEATURE>-####` watchpoints, `OQ-<FEATURE>-####` open questions |
| `specs/<feature>/memory.md` | Generated ~900-word synthesis (do not edit) | regenerated by `synthesize` |

Markdown files carry YAML frontmatter (`id`, `type`, `title`, `created`,
`updated`, `tags`, ...). The filesystem is the source of truth; everything in
`.speckit-memory/` (SQLite when `node:sqlite` is available — Node >= 22.5 —
JSON otherwise) is a derived, rebuildable index.

Governance laws are immutable: `update`/`remove` on a `LAW-` id throws
`ImmutableLawError`. History and feature entries can be updated, resolved
(`**[RESOLVED YYYY-MM-DD]**` marker), or removed.

## Docker

Run the MCP server in a container:

    docker build -t speckit-memory .
    docker run -i --rm -v "$PWD:/project" -w /project speckit-memory

The image uses `node:22-alpine` and starts the MCP stdio server by default.

## Install

    npm install speckit-memory

Requires Node.js 22.5 or newer. No postinstall, no native builds, no dependencies.

## CLI

    speckit-memory init
    speckit-memory add law "Never store plaintext private keys" --tag security
    speckit-memory add history "Chose argon2id for password hashing" --category decision
    speckit-memory add feature "Token expiry drifts under load" --feature auth --kind watchpoint
    speckit-memory add feature "Which redirect flow for mobile?" --feature auth --kind open-question
    speckit-memory list --type law
    speckit-memory list --feature auth --json
    speckit-memory list --since 2026-01-01 --until 2026-06-30
    speckit-memory show WP-AUTH-0001
    speckit-memory search "token expiry" auth --limit 10
    speckit-memory remove LOG-0002
    speckit-memory resolve OQ-AUTH-0001
    speckit-memory export backup.json     # full JSON backup of every entry
    speckit-memory import backup.json     # restore (existing ids are skipped)
    speckit-memory stats                  # counts by type/category/status
    speckit-memory doctor                 # tree + cache health check
    speckit-memory synthesize auth        # writes specs/auth/memory.md (~900 words)
    speckit-memory synthesize auth --words 600 --stdout
    speckit-memory mcp-start              # MCP server on stdio (JSON-RPC 2.0)

All commands accept `--root DIR` to target a specific project root (default:
auto-discover via `.specify`, `package.json`, or `.git`). Exit codes:
0 success, 1 domain/runtime error, 2 usage error.

## Synthesis

`speckit-memory synthesize <feature>` assembles a bounded (~900 word,
`--words` to override) memory document, deterministically and offline:

1. **Active watchpoints** and **open questions** for the feature take the
   largest share of the word budget.
2. **Project history** is ranked by relevance to the feature (tags/title/
   content mentions, `feature:` references), then recency.
3. **Governance laws** appear as one-line digests.
4. Anything trimmed for budget is listed by id under **Synthesis Notes**;
   nothing is invented — every sentence comes from a stored entry.

## MCP server

`speckit-memory mcp-start` (or `node mcp-server.js`) speaks MCP over stdio
and exposes six tools: `memory_add`, `memory_list`, `memory_search`,
`memory_synthesize`, `memory_resolve`, `memory_delete`. The server resolves
its engine in this order:

1. `SPECKIT_MEMORY_ENGINE` env var (path to an engine module)
2. `lib/engine.js` — **canonical engine** (shipped; backed by MemoryStore)
3. `lib/memory-engine.js` — alternate name
4. `lib/fallback-engine.js` — built-in single-file store (always present)

The canonical engine maps friendly types (`decision`, `pattern`, `lesson`,
`watchpoint`, ...) onto the three trees and honors `SPECKIT_MEMORY_ROOT`
(explicit project root) and `SPECKIT_MEMORY_PATH` (project directory, or a
legacy `.json`/`.db` path whose parent directory becomes the project root).
CLI and MCP therefore read and write the same memories.

### MCP client configuration

Register the server in your MCP client, e.g. `claude_desktop_config.json`:

    {
      "mcpServers": {
        "speckit-memory": {
          "command": "npx",
          "args": ["-y", "speckit-memory", "mcp-start"]
        }
      }
    }

Or point `command` at a local checkout (`node /path/to/speckit-memory
mcp-start`). Set `SPECKIT_MEMORY_ROOT` in `env` when the server should bind to
a specific project instead of auto-discovering one.

### Search semantics

`speckit-memory search` and `memory_search` treat the query as OR-ish
keywords: a memory matches when the keywords hit, and more hits rank higher.
The standalone `lib/sqlite-cache.js` search helper instead requires **all**
keywords (AND). This is intentional: the CLI/MCP search is a friendly
recall tool, while the cache helper is a strict filter.

## Programmatic API

    const { MemoryStore, synthesize } = require('speckit-memory/lib');

    const store = MemoryStore.open(process.cwd()); // or new MemoryStore(rootDir)
    store.init();
    store.add({ type: 'law', content: '...', tags: ['security'] });
    store.add({ type: 'history', content: '...', category: 'decisions', feature: 'auth' });
    store.add({ type: 'feature', content: '...', feature: 'auth', kind: 'watchpoint' });
    const laws = store.list({ type: 'law' });
    const one = store.get('LAW-0001');
    store.update('DEC-0001', { content: 'revised' });
    store.resolve('OQ-AUTH-0001');
    store.remove('LOG-0002');           // throws for LAW-#### ids
    const doc = synthesize(store, 'auth'); // { wordCount, body, document, file, ... }

Entry shape: `{ id, type, category, feature, title, filePath, created,
updated, tags, content, status, hash, wordCount }`.

Derived index cache (`store.cache`): `replaceAll(entries)`,
`query({type, category, feature, tag})`, `count()`, `close()` — schema
version tracked in the `meta` table (`CACHE_SCHEMA_VERSION`). Rebuild at any
time with `store.scan()`.

## Troubleshooting

- **"Memory trees are not initialized"** — since 0.1.3 the MCP engine no
  longer silently creates `.specify/`/`docs/memory/` trees in whatever
  directory it was started from. Run `speckit-memory init` in the project
  (or point `SPECKIT_MEMORY_ROOT` at an initialized one) before starting the
  server.

- **"file is not a database" or a corrupt `.speckit-memory/index.db`** — the
  index is a derived cache. Since 0.1.3 a corrupt `index.db` is moved aside as
  `index.db.corrupt-<timestamp>` and rebuilt automatically; the original
  markdown trees are never touched. If problems persist, delete
  `.speckit-memory/` and run `speckit-memory doctor`.
- **Windows-authored markdown loses frontmatter** — files saved with a UTF-8
  BOM are handled correctly since 0.1.3 (the BOM is stripped before parsing).
- **`no SQLite backend available`** — `lib/sqlite-cache.js` and
  `lib/synthesis-engine.js` need `node:sqlite` (Node 22.5+, still marked
  experimental by Node; you may see an `ExperimentalWarning`). The core
  memory store (`lib/memory-store.js`) falls back to JSON when sqlite is
  missing, so basic add/list/search keep working everywhere.

## Development

    npm test            # full suite: core + MCP + SQLite/synthesis + engine contract
    node test/mcp-smoke.js

## License

MIT

## Links

- GitHub: https://github.com/venkatreddygutha9-stack/speckit-memory
- Issues: https://github.com/venkatreddygutha9-stack/speckit-memory/issues
- npm: https://www.npmjs.com/package/speckit-memory