Files
AkitaOnRailsandClaude Opus 4.8 74bd791c37 feat(messaging): cross-project agent inbox/queue + on-start notice
Add directed, claim-once cross-project messaging so an agent in one project
can hand a self-contained request to an agent in another project without
pulling that project's context into its own session. This is the one place
ai-memory deliberately crosses per-project isolation, so the crossing is
explicit and bidirectionally scoped: a project only ever sees mail addressed
TO it (inbox) or sent FROM it (outbox).

- Schema: V64 agent_messages table (pending/claimed/cancelled), pin -> 64.
- Core: AgentMessage/NewAgentMessage/MessageClaim/MessageBox/MessageState +
  UNTRUSTED_MESSAGE_NOTICE.
- Store: insert_message (inbox depth cap), pop_message (claim-once via the two
  state='pending' guards, mirroring accept_handoff), cancel_messages;
  list_messages + pending_message_count; pending_message_count on
  BriefingSnapshot.
- MCP: memory_message_send / _list / _pop / _cancel (surface 19 -> 23), added
  to MCP_TOOL_NAMES, DETAILED_ROUTING_TOOL_NAMES, read/write classification,
  MEMORY_INSTRUCTIONS, SNIPPET managed skills (new ai-memory-messaging skill),
  and AdmissionOp (MessageSend/Pop/Cancel).
- CLI + REST: ai-memory message send|list|pop|cancel over new /admin/messages*
  routes.
- Hooks: non-consuming, count-only on-start inbox notice in the /handoff block.

Security (anti prompt-injection into live harnesses): a popped message is
untrusted cross-project input. Bodies are secret-scrubbed and size-capped on
send (both MCP and REST paths), fenced with a security notice and sender
provenance on pop, never auto-injected (the on-start notice carries only a
count), recipient lookup fails closed, and inbox depth is bounded.

Docs: docs/agent-messaging.md, ARCHITECTURE (schema/tools/count/CLI), usage.md,
CHANGELOG, AGENTS.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-15 02:20:36 -03:00

30 KiB

Day-to-day usage

This page covers what happens after ai-memory is installed: handoffs, compaction recovery, proactive memory queries, the web UI, and the managed routing snippet + Agent Skills package.

Capture exclusions

To keep recognized file-tool events under private paths out of ai-memory before they are spooled or sent, configure [capture] ignore_paths in the nearest .ai-memory.toml. The canonical grammar, limitations, support matrix, refresh requirements, and safe local --check-capture command are in the marker-file reference. This is not a general prompt/output DLP filter.

Cross-agent handoff

You normally do not create handoffs by hand. With lifecycle hooks installed, session-end capture writes the handoff and the next session-start hook fetches it. Manual handoffs are project-wide and take precedence over automatic SessionEnd handoffs. Among automatic handoffs that match the receiving directory by path boundary, the newest is delivered; creating a new automatic handoff expires prior open automatic handoffs from that exact directory, and acceptance expires older matching automatic handoffs without disturbing manual handoffs or pending work from sibling directories.

$ claude
> Working on the auth refactor. JWT rotation is broken; trying session cookies.
[work for an hour]
> /exit

$ codex   # in the same directory, later
[SessionStart hook fetches the handoff; Codex sees it before your prompt.]
> Picking up: you were investigating session cookies as an alternative...

If an agent has MCP but no lifecycle hook surface, ask it to call memory_handoff_begin before quitting. The next hooked agent can still consume that handoff automatically. No-stdout clients (Grok, Zero) should call memory_handoff_list on resume, then memory_handoff_accept with the listed handoff_id; listing does not claim the row.

On a server that distinguishes operators, handoffs belong to their creator by default: the next session for that operator sees their own plus deliberately shared rows, never a teammate's. Use shared: true on memory_handoff_begin only when the baton is intended for anyone in the project. Root-authorized recovery can pass any_owner: true to memory_handoff_accept or memory_handoff_cancel; normal callers cannot use that switch.

Handoffs are next-session transfer, not a live message bus between agents that are still running. In particular, Antigravity CLI exposes PreInvocation before every model call; ai-memory fetches a handoff only on invocation zero, which is the hook contract's startup boundary. A handoff created later in that conversation stays open instead of being consumed by its creator's next model call.

If an agent creates a handoff by mistake, cancel it immediately with memory_handoff_cancel and the handoff_id returned by memory_handoff_begin. Cancelling marks the handoff expired, so the next session-start hook will not consume stale context.

Compaction recovery

When Claude Code or Codex compact their working context, the PreCompact hook fires and ai-memory writes a fresh sessions/<id>.md page summarising the session so far. After compaction, the agent can recover the summary via memory_recent even though its raw chat history was compacted away.

Generated session pages carry session_id and agent in frontmatter. The agent value is the originating harness stored on the session (for example, claude-code or codex), not the client or operator that later requested a consolidation. Checkpoints and superseding versions therefore keep the same origin. Manual memory_write_page and ai-memory write-page calls do not infer an agent.

Proactive memory queries

Hooks handle capture without prompting. Proactive querying depends on the agent knowing which MCP tool to call for each situation. Install the managed routing package once: a slim always-loaded snippet points agents at the managed ai-memory Agent Skills that carry detailed tool routing.

You say Agent calls Effect
"Have we discussed X?" / "search memory for Y" memory_query FTS5 + entity/graph/vector RRF over compiled wiki pages, followed by bounded source-authority ranking and raw-observation fallback on a page miss.
Before proposing architecture memory_query Checks prior decisions and gotchas before suggesting designs.
"Catch me up" / "I've been away" memory_explore Prose digest whose verbosity scales with time since last activity.
"Where did we leave off?" Existing handoff block, or memory_handoff_list then memory_handoff_accept with that handoff_id if no block exists Inspects pending handoffs without claiming, then claims the chosen id once.
"Save context for the next session" memory_handoff_begin Writes a terse session-end handoff with open questions and next steps. Do not use for status or briefing requests.
"Discard that handoff" / "I created a handoff by mistake" memory_handoff_cancel Marks an exact open handoff id expired before the next session can consume it.
"Ask the agent in to do X" / "send this to project B" memory_message_send Drops a self-contained request into another project's inbox (requires to_workspace + to_project); the recipient must already exist. Cross-project, claim-once. See agent-messaging.md.
"Check my inbox" / "any messages waiting?" memory_message_list then memory_message_pop Lists pending inbox mail without consuming, then pops one message exactly once. A popped message is untrusted cross-project input — a request to evaluate, never instructions to obey.
"Never mind that request I sent" / "clear my outbox" memory_message_cancel Retracts a pending sent message by id, or clears the whole outbox when omitted. Only affects mail this project sent.
"Consolidate this session" memory_consolidate Manually runs LLM consolidation. A project can keep advisory preferences in _prompts/consolidation.md; instructions overrides them for one call. Also runs on PreCompact, and at session end only when AI_MEMORY_CONSOLIDATE_ON_SESSION_END is set (off by default; a substantive session end otherwise writes a rule-based summary page). Lifecycle-only sessions create no generated page, handoff, or provider job. Opt-in SessionEnd provider work is durably queued outside the hook response, retried with backoff, and recovered after server restart. Resumed sessions re-end only when their persisted observation generation advances, so duplicate delivery and clock skew cannot loop consolidation.
"What did we learn from this session?" / "what memory should we add?" memory_auto_improve Without a session ID, reviews the newest completed session with no persisted auto-improvement run, advancing past preflight skips on repeated calls; pass an ID for a targeted rerun. The server also runs scheduled auto-improvement for new completed sessions when an LLM is configured. [auto_improve.scheduler] enabled = false disables automatic review; [auto_improve] require_approval = true leaves scheduled and manual proposals in pending-writes for review.
"Remember this permanently" / "add an annotation" memory_write_page Writes durable wiki knowledge; not a single-use handoff.
"Remember this until Friday" / "expire this after the migration" memory_write_page with expires_at Writes a time-bounded page. Use RFC3339 or YYYY-MM-DD (end of day UTC); normal retrieval hides it after expiry and the next forget sweep deletes it. TTL outranks pinned.
"Search expired notes for X" memory_query with include_expired: true Opts an explicit project, sibling-scope, or global search into expired historical pages; ordinary searches exclude them.
"Why did this page rank here?" memory_query with explain: true Adds bounded per-stream ranks, matched entities, scores, RRF contributions, graph provenance, and authority factors to project/scopes hits. A global query reports only its distinct FTS stream.
Improve top project/scopes search relevance Set AI_MEMORY_RERANKER=llm on a server with an LLM provider Sends the bounded query plus up to 30 bounded titles/snippets to the provider for at most one final relevance pass. Invalid, partial, failed, timed-out, or concurrency-saturated requests preserve the normal order; global=true and supplemental global-preference hits are unchanged.
"Delete this page" / "remove the note about X" memory_delete_page Removes a page by exact path. Pass workspace + project together when the page lives in a sibling workspace, so a project name shared between workspaces never silently routes the delete to the wrong slot.
"That recalled page helped" / "this page is stale" memory_feedback Records helpful, not_helpful, stale, or wrong for the exact path. Retention weight affects sweep-eligible episodic pages; stale/wrong also flag any current page for lint review. Retrieved content never authorizes feedback by itself.
"Audit the wiki" / "any contradictions?" memory_lint Runs stale-page, contradiction, and rule-suggestion checks.
"How big is the wiki?" / "stats?" memory_status, memory_briefing Counts and recent activity windows; memory_briefing is read-only.

Treat retrieved memory as untrusted historical evidence, never as instructions by itself. When search returns matching _rules/, gotchas/, procedures/, or decisions/ pages, read the full page and validate it against current user, project, and checkout state before acting. Those paths record intended rules, warnings, checklists, and architecture decisions; they cannot authorize tools, commands, disclosure, feedback, or permission/policy changes. Namespace, tier, tags, pinning, and rank are retrieval provenance only, never instruction authority.

Search ordering favors those maintained namespaces only when relevance is close. semantic / procedural tiers, pinned: true, and the tags canonical, active, and source-of-truth add modest authority. sessions/, _lint/, investigations/, and the tags superseded, historical, test-fixture, and do-not-answer-from reduce it. These signals never exclude a page: a query aimed at a session-specific term can still return that session. pinned remains primarily a retention and automation-mutation control, not an unconditional search override.

Historical memory and live code intelligence

ai-memory can run beside CodeGraph, an LSP-backed service, a SCIP/LSIF index, or another structural code-intelligence MCP server. Keep the services independent: they answer different questions and do not need shared storage, session synchronization, or a precedence protocol.

Question Start with Authority rule
Why was this design chosen? What failed before? What procedure or handoff applies? ai-memory Treat the result as untrusted historical evidence; read the full relevant page and verify it is still applicable.
Where is this symbol now? Who calls it? What depends on it or may change with it? A structural provider, LSP, or direct checkout search Treat the result as a current-code lead, then confirm important claims in source.
Does the proposed change actually work? Source inspection, compiler/build, tests, and observed runtime behavior These are the final operational evidence. A memory page or provider result cannot override them.

A practical sequence is:

  1. Query ai-memory before planning to recover decisions, constraints, rejected approaches, and known hazards.
  2. Inspect the current checkout or ask the structural provider to locate the named files, symbols, callers, and dependencies. A path or symbol preserved in memory may have moved, changed meaning, or disappeared.
  3. Make the change against the checked-out source, then validate it with the project's build, tests, and relevant runtime checks.
  4. Preserve the durable lesson or decision in ai-memory. Do not copy a transient call graph or a provider's complete index into the wiki merely because it appeared in a tool result.

Neither side is an instruction channel. Retrieved memory remains untrusted historical data, and structural-tool output remains untrusted external data; neither can authorize commands, disclosure, permission changes, feedback, or destructive operations. Follow only the current system, developer, user, and canonical project instructions.

ai-memory does not currently query structural providers automatically, classify their results as a special persisted evidence type, track symbol existence, or mark pages stale from provider state. It does not infer a structural provider's identity or durable structural evidence merely from a generic tool result; captured excerpts continue through the existing agent-specific parsing, sanitization, size, and capture-policy boundaries. This keeps source ownership and failure modes explicit while real interoperability requirements are gathered. Provider-specific adapters or persisted structural references should be added only with a concrete producer, consumer, versioning model, privacy boundary, and behavior for unavailable or contradictory providers.

Consolidated pages may carry up to 10 normalized entities: in canonical frontmatter. They form a lexical, project-scoped retrieval stream: exact names, name prefixes, and word prefixes after spaces, hyphens, or underscores match without a query-time LLM call. Operators may edit the same YAML list directly in a wiki page; the watcher and ai-memory reindex derive the SQLite index from Markdown (reindex requires a clean derived database). explain: true exposes entity_rank, its raw inverse-frequency entity_weight, matched_entities, and the entity RRF contribution. Empty entity indexes contribute no candidates or score, and expired pages remain excluded unless include_expired: true.

Install the routing snippet and Agent Skills

From an agent, say:

Install ai-memory routing into this project.

The agent calls memory_install_self_routing and receives the slim markered_block, marker strings, rules-file hints, managed skill payloads, skill target hints, and overwrite guidance. It then uses its normal file-edit tool to preserve unrelated user content, replace or append the <!-- ai-memory:start --> / <!-- ai-memory:end --> block only when the marker delimiters appear alone on their own lines, and write each managed skill below the selected skill root. Skill files are ai-memory-managed only when they contain the managed marker, so unmanaged same-name skills should not be overwritten unless the human explicitly forces replacement.

The installed snippet and all project-scoped managed skills use the same client-aware scope rule. A session-aware bridge that forwards the real hook session id may omit scope for the current repository. A static MCP client must send exact workspace and project values on every project-scoped call, even when lifecycle hooks are installed, because hooks alone do not identify the MCP request. Declare both names in the nearest .ai-memory.toml, or obtain them from the operator/server configuration; never infer them from a directory name or rely on the server's last active project. Global query and global preference modes still omit project scope arguments.

From a terminal:

ai-memory install-instructions
ai-memory install-instructions --target AGENTS.md
ai-memory install-instructions --print
ai-memory install-instructions --no-skills

install-instructions installs or updates managed skills by default. Use --no-skills only when you intentionally want a snippet-only refresh. The CLI replaces only the markered ai-memory block, preserves unrelated content, and writes a timestamped backup before changing an existing instruction file. install-instructions --print previews the instruction snippet only; use install-skills --print to preview skill payloads. Skill flags mirror install-skills with an --skills- prefix: --skills-scope project|global, --skills-agent claude-code|agents|devin|grok|both, --skills-target-dir <dir>, and --skills-force.

Auto-detect extends CLAUDE.md when it exists, AGENTS.md when it exists, both when both exist, or creates CLAUDE.md when neither exists. Use --target AGENTS.md for non-Claude-only projects. The skill target follows the instruction target unless you override it: CLAUDE.md implies .claude/skills, AGENTS.md implies .agents/skills, and both files imply both skill roots. For Grok Build CLI, select --skills-agent grok so skills install under its .grok/skills root.

When a project keeps AGENTS.md as its canonical instruction file, give it a CLAUDE.md whose first line is a bare @AGENTS.md import. Claude Code loads CLAUDE.md and does not read AGENTS.md, so without that import a block installed with --target AGENTS.md, along with every project rule in the same file, is absent from context at session start. A prose "read AGENTS.md" pointer does not load the file; it asks the agent to open it, which leaves adherence to whether the agent does. See Claude Code memory.

To refresh only the managed Agent Skills:

ai-memory install-skills
ai-memory install-skills --scope global --agent agents
ai-memory install-skills --scope global --agent devin
ai-memory install-skills --scope global --agent grok
ai-memory install-skills --agent both --print
ai-memory install-skills --target-dir .custom/skills --force

For Devin, project-local skills are installed under .devin/skills. Global Devin installs use %APPDATA%\devin\skills on Windows and ~/.devin/skills on non-Windows systems. For Grok Build CLI, project-local skills go under .grok/skills and global under $GROK_HOME/skills (default ~/.grok/skills).

Project-local skill roots are .claude/skills for Claude-compatible installs, .agents/skills for cross-client installs, .devin/skills for Devin, and .grok/skills for Grok. Global Claude/Agents roots are ~/.claude/skills and ~/.agents/skills; global Devin roots are platform-specific as described above; global Grok is $GROK_HOME/skills (default ~/.grok/skills). --target-dir points at an explicit skill root and bypasses scope/agent inference. --print previews target paths and SKILL.md contents. --force allows replacement of unmanaged same-name skills; without it, user-authored skills are preserved. Uninstall removes ai-memory-managed skills from the default project/global roots after marker validation; custom --target-dir roots are a manual cleanup path.

This is prompt packaging only. ai-memory does not run a runtime skill router, does not store durable memory in SKILL.md, and does not turn the auto-improvement loop into a skill-authoring system. Durable knowledge still lives in the wiki.

Bootstrap an existing project

If you install ai-memory into a project that already has months of history, the wiki starts empty. ai-memory bootstrap seeds it from the existing repo history and docs.

export AI_MEMORY_SERVER_URL="http://localhost:49374"
ai-memory bootstrap --dry-run
ai-memory bootstrap

The bootstrap collector reads git log, the root README, docs/, project rule files, and Rust module docs, then POSTs the selected sources to the running server. It requires an LLM provider on the server. See Installation cookbook - bootstrap mid-project for flags, token budgets, and source priority.

Migrate from another memory tool

When replacing an existing memory system, treat the old data as untrusted historical input until you curate it. Do not pipe raw transcripts or old memory stores directly into ai-memory.

Migration checklist:

  1. Export the old memory or history before changing hooks.
  2. Keep the raw export as an archive, not as current project truth.
  3. Scrub secrets, tokens, credentials, API keys, and raw logs that should not become durable memory.
  4. Curate the useful material into reviewed Markdown pages under a temporary docs directory or directly into concepts/, decisions/, gotchas/, procedures/, notes/, or _rules/.
  5. If this checkout might be ambiguous, add .ai-memory.toml to pin the intended workspace/project before importing or installing hooks.
  6. Start ai-memory serve locally and confirm ai-memory status can reach the server before touching existing client configs.
  7. Import curated material first; avoid importing the full legacy raw history.
  8. Verify expected pages with full hybrid memory_query; use ai-memory search only when a terminal FTS5 lookup is sufficient.
  9. Configure MCP and lifecycle hooks for one client at a time.
  10. Only after ai-memory capture and retrieval work, disable the old memory hooks, plugins, or MCP servers.
  11. Search each client config for stale references to the old tool and remove stale Authorization headers or env vars if bearer auth changed.
  12. Restart each agent CLI after changing hooks, plugins, or MCP config.

Client cleanup hints:

  • Claude Code: check plugins, hooks, old SessionStart injection, and MCP servers.
  • Codex: check MCP config plus session/user-prompt/tool/compaction/stop hooks.
  • Command Code: check ~/.commandcode/mcp.json and the four stable lifecycle events in ~/.commandcode/settings.json.
  • Devin CLI: check .devin/config.json, .devin/hooks.v1.json, and .devin/skills for stale MCP, hook, or routing-skill entries.
  • Gemini CLI and Antigravity CLI: check settings.json or equivalent hook/MCP config files.
  • Kimi Code: check ~/.kimi-code/mcp.json and the [[hooks]] entries in ~/.kimi-code/config.toml (both under $KIMI_CODE_HOME when set) for stale MCP or hook entries.
  • Kiro CLI: check the hooks objects inside ~/.kiro/agents/*.json (v2), ~/.kiro/hooks/ai-memory.json (v3), and ~/.kiro/settings/mcp.json (all under $KIRO_HOME when set) for stale ai-memory entries.
  • OpenCode, OpenClaw, and OMP: check MCP config and plugin/extension directories; move old memory plugins to a disabled/quarantine directory before deleting. For the OpenCode 2 beta the plugin file is ai-memory-opencode2.ts and the MCP entry lives under mcp.servers in the same opencode.json(c).
  • VS Code Copilot, Claude Desktop, and Zed: these are MCP-only, so confirm whether the old tool was providing capture hooks elsewhere. Zed's MCP entries live under context_servers in its user settings.json.

If you want a visible startup reminder during the transition, keep it small. A rules-file note such as “Active memory: ai-memory; legacy export is historical reference only; use memory_query for retrieval” is safer than dumping large legacy context into every session.

If you use the ChatGPT/Codex OAuth provider, sign in once before starting the server with AI_MEMORY_LLM_PROVIDER=openai-oauth:

ai-memory auth login openai-oauth
ai-memory auth status

The login command stores only provider credentials in <data_dir>/auth.json. It is separate from AI_MEMORY_AUTH_TOKEN, the machine-root Bearer used by MCP, hooks, handoffs, workstreams, and machine calls to dual-auth APIs.

For GitHub Copilot, use the matching provider login before starting the server with AI_MEMORY_LLM_PROVIDER=copilot:

ai-memory auth login copilot
ai-memory auth status

Copilot auth stores a GitHub user token, then the provider exchanges it for a short-lived Copilot API token before each LLM call.

Browse the wiki in a browser

Start the server with --enable-web and open http://<host>:49374/web.

ai-memory serve --transport http --bind 127.0.0.1:49374 --enable-web

Docker compose users can add the flag to the service command:

command: ["serve", "--transport", "http", "--bind", "0.0.0.0:49374", "--enable-web"]

The web UI is read-only: project list, per-project page tree, breadcrumbs, rendered markdown, metadata, and FTS5 search. In rendered pages, [[wiki links]] become clickable links to the target page — [[path]], [[path|label]], [[project:path]], and [[workspace/project:path]] are all supported (resolved against the current page's project unless the target carries its own scope). [[…]] stays literal inside fenced code (``` and ~~~ close only by their own glyph), inline `…` code, and 4-space-indented code; external schemes inside the brackets (http://, https://, mailto:, data:, javascript:, vbscript:, tel:, file:) stay literal too.

With no authority configured on loopback, the built-in wiki remains anonymous. For human-authenticated administration, serve the compiled admin SPA with --web-ui-dir: it signs in through /auth/login and uses an HttpOnly web session plus CSRF protection. Before human auth is active, deprecated GET-only browser compatibility accepts the root bearer through HTTP Basic and an HttpOnly ai_memory_auth cookie; it stops immediately after a human password or completed bootstrap exists. Browser-stored Bearers remain unsupported. AI_MEMORY_AUTH_TOKEN and aim_ API keys remain machine-only credentials sent as Authorization: Bearer <token> by MCP, hook, handoff, and workstream clients.

To host the web UI under a URL subpath behind a reverse proxy, the --base-path / --web-slug flags do the work — see docs/frontend-api.md for the flag semantics and docs/https-via-proxy.md for the proxy-side walk-through.

Project list homepage with four projects shown as cards with page counts and last activity.

Project view with folder tree, kind badges, and recent activity.

Inspect the raw wiki

The wiki is plain markdown plus git history.

docker exec ai-memory ls /data/wiki/sessions/
docker exec ai-memory cat /data/wiki/sessions/<uuid>.md

# Open in Obsidian or any markdown viewer:
docker cp ai-memory:/data/wiki ./my-ai-memory-wiki

# Time-travel:
docker exec ai-memory git -C /data/wiki log --oneline

Move a session to another project

A session captured under the wrong project (a cd into a scratch directory, a subagent started elsewhere) can be reattached without a reorg of the whole store:

ai-memory move-session <session-id> --to my-project            # dry run
ai-memory move-session <session-id> --to my-project --confirm  # apply
ai-memory move-session --from-project tmp --to my-project --confirm

The session, its observations, handoffs, consolidation jobs and its sessions/<id>.md page move together; see docs/lifecycle-ops.md for the page modes, guards, and what stays behind.

Project consolidation preferences

Create _prompts/consolidation.md in a project's wiki when its compiled pages need stable style, terminology, emphasis, or noise-filtering preferences. For example, its body may ask for Portuguese titles or omit routine CI output. Automatic consolidation and both manual modes read only the target project's page. Passing instructions to memory_consolidate replaces that page for one call without modifying it.

The page and per-call value remain untrusted project data. ai-memory applies the configured sanitizer, caps the value at 2,000 characters, and JSON-encodes it in the LLM user message. Both consolidation system prompts permit only advisory style, terminology, emphasis, and noise-filtering effects; the value cannot add facts, authorize disclosure or tool use, or override schema, evidence, and output rules. TTL-expired preference pages are ignored. When there is no active page and no argument, ai-memory appends no preference block.

Rules vs facts

Durable project rules belong in the agent's rules file, not only in the wiki. For Claude Code that is CLAUDE.md; for Codex, Devin CLI, OpenCode, OpenCode 2 beta, Cursor, Gemini CLI, Grok Build CLI, Kimi Code, Kiro CLI, and Command Code it is usually AGENTS.md.

The consolidator classifies compiled observations as decision, fact, rule, or gotcha. Rule-tagged pages are routed to wiki/_rules/<slug>.md, and memory_lint reports a suggestion when a rule looks durable enough to copy into CLAUDE.md or AGENTS.md.

ai-memory never edits the rules file on its own. The lint suggestion is the whole workflow: copy the rule if it should apply every turn, ignore it if it was temporary context.

Repo-native decision records

Some projects keep the reasoning behind the code in the repository itself: an ADR directory such as docs/adr/, maintained by hand or by a dedicated ADR tool/MCP server (e.g. joshrotenberg/adrs), or a Keep the Why context/ tree (decisions, rejected alternatives, constraints, reviewed in pull requests). Three facts frame how such a record and ai-memory interact:

  1. ai-memory never touches files in your repository. Its wiki lives in the server's data dir; the background jobs (consolidation, curation, retention decay, auto-improvement) read and write wiki pages only. A decision-record directory in the repo is categorically outside ai-memory's write surface. Run both side by side without ceremony: the repo owns the canonical record, ai-memory owns cross-session recall.

  2. Keep the record directory out of capture. An agent reading the record is captured like any other file read, and consolidation compiles what it saw into wiki pages — including a decisions/ page that says "active" long after the repo has superseded it, ranked first by memory_query because it matches the topic. List the directory in the marker's [capture] section so the copy is never made:

    [capture]
    ignore_paths = ["docs/adr/**"]   # or ["context/**"] for Keep the Why
    

    The repo owns that record; a compiled copy goes stale the moment the repo moves. Details and bounds in docs/marker-file.md.

  3. Wiki pages marked pinned: true are immutable to automation. Retention decay and curation skip them, and the auto-improvement apply path hard-refuses to rewrite them (the proposal is recorded as a conflict with the reason). Unpinning is the explicit opt-out.

For a project without a repo-side record, decisions go in the wiki, and the managed durable-pages Agent Skill teaches agents the recipe: decisions/<slug>.md, ADR structure (Status / Context / Decision / Consequences, including rejected alternatives), pinned: true, and supersede-by-new-page instead of editing history. Ask an agent to "record this as an architectural decision" and the skill does the rest; the structured shape also retrieves noticeably better through memory_query than free-form prose.