Skip to content

Local memory

Save findings, decisions and rules for agents to recall, without an account.

  • The Blop CLI (Quickstart). Memory commands work without a running collector.

memory.db sits beside the telemetry store (blop status prints its path). It holds authored nodes and read-only folder projections, not captured telemetry:

  • Kinds: entity, document, finding, decision, rule or procedure.
  • Authored revisions: every authored change makes a new immutable revision; writes must name the revision they expect. Markdown projection retains only its current indexed snapshot.
  • Relations and sources: typed node links and supporting trace/session references. Unsourced nodes are claims, not evidence.

Opening memory never uploads anything. To share knowledge with a team, see Organization memory.

Terminal window
blop memory add --kind decision --title "Round two probe" --body "the flags work"
blop memory search --text "Round two probe"

Default ID: local: plus lowercase SHA-256 of exact UTF-8 JSON.stringify([title, body]). Identical retries preserve revisions. See blop help memory add.

  1. Write the change as JSON:

    {
    "type": "add",
    "id": "note:checkout-timeout",
    "scope": "project",
    "projectId": "my-app",
    "expectedRevision": 0,
    "content": {
    "kind": "finding",
    "title": "Checkout times out under load",
    "body": "POST /api/pay exceeds 5 s when the payment stub is cold."
    }
    }
  2. Add it:

    Terminal window
    blop memory add --input add.json --json
  3. Find it again:

    Terminal window
    blop memory search --text checkout --project my-app --json
CommandPurpose
blop memory search --text <text>Exact text search in titles and bodies, in stable node-ID order
blop memory get <node-id>One node; --revision N for an older one, --body-offset and --body-length for long bodies
blop memory history <node-id>Revision list with previews
blop memory neighbors <node-id>Recorded relations
blop memory context --text <text>A bounded brief for an agent
blop memory edit, patch, retire, restore, purgeChange a node with an --input JSON file
blop memory skills list, skills get <id>Saved procedures
blop memory indexBuild vectors for search by meaning

Read commands take --json and return bounded pages; follow the returned --cursor. Coding agents connected over MCP get the same reads as read-only tools (Connect a coding agent); writes always go through the CLI.

No account, collector, model or network: Attachment/indexing never rewrite authoritative Markdown:

Terminal window
blop memory markdown init ./knowledge # Optional template; never overwrites.
blop memory markdown attach ./knowledge --json # Save attachment ID.
blop memory markdown index <attachment-id> --json
blop memory search --text checkout --json
blop memory get <node-id> --json
blop memory neighbors <node-id> --json
blop memory context --text checkout --json
blop memory markdown list --json
blop memory markdown detach <attachment-id> --json

Reindex after edits/deletes; replacement is atomic. Detach removes retrieval/vectors, not files or authored assertions. Missing endpoints hide relations; restored IDs recover original approval provenance. memory index remains optional vector/model indexing. --project configures attachment scope only on markdown attach; unrelated flags, including --dry-run, fail.

  • Arbitrary layouts with .md, .mdown or .markdown work without frontmatter. Optional scalar id: checkout-policy preserves note identity across renames; duplicate IDs fail. Without an ID, rename means delete/add.
  • Whole notes and ATX/Setext heading sections are addressable. Anchors lowercase Unicode letters/numbers, retain _/-, remove other punctuation and replace whitespace with -. Duplicates receive the first unused numeric suffix; heading edits/reordering may change section IDs.
  • Relative Markdown/reference-style links and [[relative/path#Heading]] create unapproved references, not causal assertions. Wikilinks may omit .md; no global basename matching. Code creates no links. Unresolved/external links produce warnings; URLs, images and HTML are never fetched/executed.
  • Projections are unapproved documents. Frontmatter grants no policy, guards, scope or upload permission. Edit source and reindex; authored mutations fail. Publication copies one selected snapshot, never syncs. Projection history is empty; get --revision addresses current only, otherwise null.

Reads preserve node/page envelopes and include path/section/hash/snapshot, indexing time and freshness: indexed-snapshot means last successful scan, not live filesystem freshness; last-scan-failed labels retained prior content. There is no watcher. Local CLI/MCP assessment is explicitly not_configured, not “assessed without findings.” MCP exposes no Markdown writes; its existing collector health announcement contains no note content.

Initialization requires Linux with accessible /proc/self/fd; other platforms return markdown_init_unsupported, never unsafe pathname writes. Directory handles anchor exclusive creation against symlink swaps. Attach/index reject symlink roots/ancestors and exclude child symlinks. Hidden entries, node_modules, dist, build, vendor, coverage, secrets and config are ignored. .blopignore accepts literal relative prefixes with # comments, not globs.

Limits: 100,000 bytes/file, 16,000,000 bytes/scan, 20,000 entries, depth 32, 10,000 nodes, 200 link occurrences/file (including whole-note copies), 100 attachments. Paths cap at 1,024 characters; headings at 512. Exact citations allow 1,029-character sourceId (path: prefix) and 1,537-character path (path + # + heading), without truncation. Invalid/oversized sources or detected concurrent changes preserve the prior snapshot; successful empty scans remove it. Scan checks are not locks; pause concurrent writers.

Optional frontmatter sources uses the existing reference contract:

---
sources:
- namespace: otlp:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
sourceId: "1111111111111111"
recordedAt: "2026-11-06T00:00:00.000Z"
plane: runtime
accessibility: unknown
---

This addresses an exact trace+span; otlp.trace with a trace ID addresses the trace. opencode:<encoded-session-id> keeps exact source-ID semantics. Only existence metadata is read: present is local-only, missing is unavailable; absent stores/tables, unknown namespaces or unverifiable hash/revision constraints are unknown. Existence is not verification. No hosted run or upload is implied.

Open /inspector?view=memory on the collector, for example http://127.0.0.1:27811/inspector?view=memory&project=my-app&q=checkout. The view is read-only. Filter with project, q (text), kind, status (active or retired) and semantic=1 (rank by meaning).

Terminal window
blop memory index

Search by meaning needs an index you build explicitly. The first index or search downloads a local embedding model and caches it; your notes and queries are never uploaded. Reindex after changes: a stale index state means vectors cover older revisions. If the index is not ready, search falls back to exact text. Similarity is not evidence, and ranking never creates a relation.

Retire a node to hide it from search while keeping its history:

Terminal window
echo '{"type":"retire","nodeId":"note:checkout-timeout","expectedRevision":1}' > retire.json
blop memory retire --input retire.json

restore brings a retired revision back. To erase a node’s content, revisions and index entries, purge it at its current revision:

Terminal window
echo '{"type":"purge","nodeId":"note:checkout-timeout","expectedRevision":2}' > purge.json
blop memory purge --input purge.json

A purged ID cannot be reused. Purging is logical deletion: database write-ahead pages and backups are not erased at once. Telemetry is deleted separately, with blop delete.

blop memory get note:checkout-timeout --json returns the node with its revision, and null after a purge.