ivar memory
Memory commands, the memory_* MCP tools, page kinds and front matter, and the memory doctor findings.
ivar memory inspects, queries and maintains the hall memory: markdown pages
under docs/memory/, the handoffs between sessions and the session hooks. The
pages are the durable memory; .ivar/memory.db holds an index of them that a
reindex rebuilds, plus observations, handoffs and messages, which are lost when
the file is deleted.
Every subcommand accepts the global options:
| Option | Description |
|---|---|
--json | Emit machine-readable output |
--color <COLOR> | auto (default), always or never |
-C <dir> | Run as if ivar was started in <dir>, like git -C; repeated -C options compose |
--compact is for ivar graph only; a memory verb refuses it with exit 2.
Commands
status
ivar memory statusShow the memory database: path, schema version, application id, size,
observation counts per event, the capture spool, the last drain and the
retention sweep. It also reports pages per kind, the last reindex, pages that
failed validation, the last consolidation of session pages, pages waiting for
anchors and 30 days of query usage with the miss rate per source. It creates
.ivar/memory.db when it is missing and drains the capture spool.
clean
ivar memory cleanDelete the memory database after confirmation. Nothing else deletes it. The
pages under docs/memory/ stay; observations, handoffs and messages go.
query
ivar memory query "page index" --kind decision --limit 5Search the pages under docs/memory/. When no page matches and no filter is
set, retained observations answer in a separate section.
| Argument / option | Description |
|---|---|
<TEXT> | Words to search for |
--kind <KIND> | Keep only pages of this kind (repeatable) |
--tier <TIER> | Keep only pages of this tier: semantic, procedural, episodic or working |
--tag <TAG> | Keep only pages carrying this exact tag |
--limit <LIMIT> | Most results to return, default 10, at most 20 |
--include-expired | Also return pages whose expires_at has passed |
--explain | Show how each source ranked every result |
Text is quoted term by term, so quotes, AND, * and NEAR never raise a
syntax error. Each hit lists up to 10 anchors (repo, path, symbol,
broken), broken ones first.
reindex
ivar memory reindexRebuild the page index from docs/memory/. Observations are not touched. A
reindex also runs before memory query and memory status, in ivar sync
and on the MCP leader tick, so an uncommitted page appears at once.
lint
ivar memory lintCheck the pages under docs/memory/ against the page rules. It reads the
files, not the index, so it covers uncommitted pages. It exits non-zero when a
rule is broken.
| Code | When |
|---|---|
lint.kind_unknown | A directory under docs/memory/ that is not a durable kind |
lint.frontmatter_invalid | Unreadable YAML, a field of the wrong type, a kind that differs from the directory, or a malformed expires_at |
lint.field_unknown | A field outside the six front matter fields |
lint.link_broken | A markdown link to a missing .md under docs/memory/ |
lint.misplaced | A subfolder, a slug that is not kebab-case ASCII, or a product or update page without NNN- |
lint.anchor_broken | An anchor whose file or symbol the graph no longer has (warning) |
lint.reindex_failed | The index refresh before the anchor check failed (warning) |
lint.anchor_broken and lint.reindex_failed are lint issues of warning severity, reported in
the output; they are not CLI warnings, so they do not change the exit code.
review
ivar memory review billing-currencyShow what a feature wrote to memory, its gaps, the pages its diff may have made
stale, and the last review. It is read-only: the review that
ivar feature deliver requires is confirmed with the memory_review MCP tool.
| Argument | Description |
|---|---|
[FEATURE] | Feature to review; defaults to the session's feature |
handoff begin
ivar memory handoff begin --summary "Index rebuilt; lint still fails" --pending "Fix lint.link_broken"Open a handoff for the next session, in this session's feature queue or the hall's outside a feature.
| Option | Description |
|---|---|
--summary <SUMMARY> | Where the work stopped, in markdown (required) |
--pending <PENDING> | A task the next session should pick up (repeatable) |
--decision <DECISION> | A decision still open (repeatable) |
--file <FILE> | A file the work touched (repeatable) |
--feature <FEATURE> | Open it in this feature's queue instead |
--hall | Open it in the hall queue |
--to-provider <TO_PROVIDER> | Only sessions of this provider see it |
--to-session <TO_SESSION> | Only this ivar session sees it |
--session <SESSION> | Open it on behalf of this ivar session, which becomes its owner |
handoff list
ivar memory handoff list --hallList open handoffs. Read-only; it never creates memory.db.
| Option | Description |
|---|---|
--feature <FEATURE> | Only this feature's queue |
--hall | Only the hall queue |
handoff cancel
ivar memory handoff cancel 7f3a9cCancel an open handoff by <ID>, as list shows it, whoever owns it. Accepting
a handoff and every message verb are MCP-only.
capture
ivar memory capture --provider claude-codeA hook entry point: it records one session hook event, read from stdin, into
the capture spool. It always exits 0 and prints nothing. Without --provider
nothing is recorded.
brief
ivar memory brief --provider claude-codeA hook entry point for session start: it prints up to five open handoff headers
and the count of pending messages this session can see, framed as untrusted
historical data. It always exits 0 and prints nothing when there is nothing to
show or on any error. --provider names the provider whose hook runs it, for a
session outside ivar session.
MCP tools
The memory tools are served by the same MCP server as the graph tools. None takes a workspace or project argument: the hall is the scope. The memory tools never commit; a written page stays uncommitted until you commit it.
| Tool | Arguments | What it returns |
|---|---|---|
memory_query | query (required), kind[], tier, tag, limit, include_expired | Pages with title, kind, tier, path, excerpt, pinned and up to 10 anchors; observations only as a fallback |
memory_read_page | path | Front matter and body of one page, .ivar/memory/ included; refuses files over 256 KiB |
memory_write_page | kind, title (required), body, slug, tags, pinned, relations, expires_at, replace | path, hash, indexed and similar titles; refuses session |
memory_patch_page | path (required), old, new, tags, pinned, relations, expires_at | path, hash, indexed; only pinned and expires_at on a session page |
memory_delete_page | path | path, indexed |
memory_lint | none | issues, each {path, code, severity, message} |
memory_review | confirm, stale[{path, verdict}], not_required | Written pages, gaps, stale pages and the last review; with confirm: true it records the review delivery requires |
memory_status | none | The ivar memory status block, pending anchors and 30-day usage |
memory_recent | limit, source_event, feature | Observations, newest first, each with a one-line summary |
memory_read_session_observations | session (required), limit, cursor | One session's observations, oldest first, with next_cursor |
memory_handoff_begin | summary (required), pending_tasks[], open_decisions[], modified_files[], feature or hall, to | handoff_id, expires_at |
memory_handoff_list | feature or hall, limit | Open handoffs the caller sees, newest first |
memory_handoff_accept | handoff_id | claimed with the handoff, already_claimed or none_pending |
memory_handoff_cancel | handoff_id (required) | cancelled; only the owner cancels, and only an open handoff |
memory_message_send | body (required), subject, feature or hall, to | message_id, expires_at |
memory_message_list | box (inbox or outbox), feature or hall, limit | Pending messages, oldest first |
memory_message_pop | message_id | popped with the message, already_claimed or none_pending |
memory_message_cancel | message_id | How many of the caller's pending messages were retracted |
accept and pop claim an item once; only the winner gets the content, and
every answer that returns content marks it as untrusted data. Handoffs and
messages expire after memory.handoff_ttl_days days, 7 by default. Before
ivar feature deliver, call memory_review and give each stale page a verdict;
delivery refuses a feature without that review unless you pass
--skip-memory-review with a reason.
The full argument rules for writing, path confinement, review, handoffs and
messages are in the
MCP tools reference
of the ivar repository.
Pages
A page is a markdown file at <root>/<kind>/<slug>.md, with a kebab-case
slug. Pages are flat: a file in a subfolder, outside a kind directory or with an
uppercase extension is reported, not indexed. Nothing creates a kind
directory ahead of time: the first page written there creates it. ivar never
commits a page.
| Kind | Directory | Tier | Numbered |
|---|---|---|---|
product | docs/memory/product/ | semantic | yes |
decision | docs/memory/decision/ | semantic | no |
concept | docs/memory/concept/ | semantic | no |
gotcha | docs/memory/gotcha/ | procedural | no |
procedure | docs/memory/procedure/ | procedural | no |
update | docs/memory/update/ | episodic | yes |
session | .ivar/memory/session/ | episodic | no |
The six durable kinds are committed. session pages are not: ivar writes one
per provider conversation once it ends or has been idle 30 minutes, and deletes
it 30 days after the conversation's last observation unless it is pinned.
product and update slugs start with a three-digit NNN- prefix. The next
number is the highest one in the directory plus one, counting the
.cleanup.json records beside the update pages.
Front matter
Front matter is optional, and so is every field. A page without it takes its title from the first H1, then from the slug.
| Field | Type | Meaning |
|---|---|---|
title | string | Page title |
kind | string | Must equal the directory |
tags | list of strings | Matched exactly by --tag |
pinned | boolean | Ranks the page higher in memory query |
relations | list of {type, target} | Typed links; target is kind/slug |
expires_at | string | YYYY-MM-DDTHH:MM:SSZ, UTC only |
---
title: Page index follows the disk
tags: [memory, index]
relations:
- type: supersedes
target: decision/old-index
expires_at: 2027-01-31T00:00:00Z
---Any other key is kept and reported as a warning. A page past expires_at stays
on disk; memory query omits it unless --include-expired is passed. The body
links to other pages with [[slug]], [[kind/slug]] and markdown links to
.md files.
Doctor findings
ivar doctor reports these memory findings; each names the command that fixes
it.
| Code | Meaning | Fix |
|---|---|---|
memory.db_missing | .ivar/graph.db exists without .ivar/memory.db | ivar memory status creates it |
memory.db_corrupt | .ivar/memory.db fails to open, fails quick_check, or carries another application_id | ivar memory clean, then ivar memory status |
memory.schema_newer | Memory schema newer than the binary | ivar upgrade |
memory.db_polluted | An older ivar created graph tables inside .ivar/memory.db | Stop the older ivar, then ivar memory status repairs it |
memory.split_busy | A legacy graph at .ivar/memory.db is open in another process, so it was not moved | Stop sessions and MCP servers of the older ivar, then ivar doctor |
memory.split_failed | Moving the legacy graph failed for another reason | Check .ivar/ permissions and free space, then ivar doctor |
memory.spool_orphan | A capture spool file has waited over an hour to be drained | ivar memory status drains it |
memory.spool_dropped | A session spool reached 8 MiB and dropped events within the last 7 days | ivar memory status, or keep ivar graph mcp running; clears after 7 days without new drops |
memory.drain_failed | The last drain of the capture spool failed | ivar memory status; if it repeats, read the database findings of ivar doctor |
memory.sweep_failed | The last retention sweep failed | ivar memory status; if it repeats, read the database findings of ivar doctor |
memory.consolidate_failed | The last consolidation of session pages failed | ivar memory status; if it repeats, read the database findings of ivar doctor |
memory.retention_overdue | Session observations older than 37 days are still stored | Keep ivar graph mcp running; its leader deletes them hourly |
provider.capture_hook_missing | memory.capture is on and a provider has no capture hook | ivar sync, or set memory.capture to false in ivar.json |
memory.legacy_docs | Pages still live in docs/product or docs/updates | The git mv commands it prints |
memory.page_invalid | Front matter does not parse, kind differs from the directory, or expires_at is malformed | Edit the page |
memory.page_kind_unknown | A directory under docs/memory/ or .ivar/memory/ is not a kind of that root | Rename or move it |
memory.page_misplaced | A page is outside <kind>/, nested, has a non-kebab slug, does not end in lowercase .md, or lacks NNN- | Move or rename it |
memory.page_field_unknown | Front matter has a key the format does not know (warning) | Remove it or ignore it |
memory.page_uncommitted | Page files under docs/memory/ have uncommitted changes | Commit them |
memory.index_failed | The last page reindex failed | ivar memory reindex |