v0.7.0 — NHI Starter Prompts (every task)
Companion to
V0.7-EPIC.md. One paste-ready prompt per task. Hand any of these verbatim to a Claude Code, Grok, Codex, or any MCP-capable agent and the agent has enough context to begin work without further briefing.
Conventions:
- Branch:
feat/v0.7-<track>-<task>-<short-name> - Commit:
feat(<scope>): <imperative summary> (#<task-id>) - PR title:
feat: v0.7-<track><number> — <one-line title> - Each prompt is self-contained. Copy from
===to===block end.
Track A — Capabilities v3 response shape
A1: Top-level summary field
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task A1 (#545).
Goal: add a top-level `summary` field to the memory_capabilities v3 response.
The field carries a single pre-computed string that describes the LLM's
operational access — the count of currently-advertised tools, the count of
total tools, and the three named recovery paths for loading unloaded
families.
Current state: src/mcp.rs builds the capabilities document via a
`build_capabilities_v2(...)` function. v2 returns a manifest with
loaded:bool per tool but does NOT include a top-level summary string.
What to do:
1. Add a `build_capabilities_v3(...)` function alongside v2. v3 = v2 +
one new top-level `summary` field of type String.
2. The summary string is dynamically built from the live profile state
(use src/profile.rs for inspection). Template:
"X of N tools are advertised in tools/list under the current profile (Y),
where N is the canonical full-profile tool count from
`Profile::full().expected_tool_count()` (currently 74 at v0.7.0 —
73 callable memory tools + the always-on `memory_capabilities`
bootstrap; do not hardcode the number in prompts).
The other Z are listed in this manifest but NOT directly callable.
To use any unloaded tool, choose one of:
(a) restart the server with --profile <family> or --profile full,
(b) call memory_load_family(family=<name>) — preferred,
(c) call memory_smart_load(intent='<plain language>') — easiest,
(d) call the tool by name and recover from JSON-RPC -32601."
3. Wire `accept="v3"` to the new builder; `accept="v2"` keeps the old
builder. Default for new clients: v3.
4. Unit tests in src/mcp.rs::tests covering each named profile.
5. Integration test in tests/mcp_integration that wires a real MCP request.
6. Do not modify v2 behavior. Backward compat is required.
Branch: feat/v0.7-a-1-summary-field
Commit: feat(mcp): add v3 capabilities summary field (#545)
Definition of done: cargo test --lib mcp:: passes; integration test passes;
v2 unchanged; calibration prompt produces a response with summary field.
A2: to_describe_to_user field
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task A2 (#545).
Depends on A1.
Goal: add a `to_describe_to_user` field to the v3 response. This is the
canonical plain-language sentence the agent should say when asked
"what tools do you have access to."
What to do:
1. Extend src/mcp.rs::build_capabilities_v3 to add the new field.
2. Build the string from active profile state — count of loaded tools,
names of those tools, count of unloaded tools, two example unloaded
tool names, plain-English description of how to load more.
3. Tone constraint: NO mcp jargon. Use plain language an end-user would
understand. Example:
"I can directly use 5 memory tools right now (store, recall, search,
list, get). 38 more (link, kg_query, consolidate, delete, etc.) are
available on demand — I can load them if you ask for something that
needs them, or you can restart the server with a different profile."
4. Add tests/calibration_t0.rs (new file) — assert canonical phrasing
present in v3 response.
5. Document the canonical phrasing in docs/v0.7/canonical-phrasings.md.
Branch: feat/v0.7-a-2-describe-to-user
Commit: feat(mcp): add v3 to_describe_to_user field (#545)
A3: Per-tool callable_now: bool flag
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task A3 (#545).
Depends on A1.
Goal: add per-tool callable_now: bool field. Distinct from existing
loaded:bool — captures whether THIS agent can call this tool right
now given allowlist scope.
What to do:
1. In src/profile.rs, extract a helper:
fn agent_can_call(agent_id: &str, family: &str) -> bool
that mirrors the [mcp.allowlist] resolution rules
(exact > longest-prefix > * wildcard).
2. In build_capabilities_v3, populate callable_now for each tool by
combining loaded-state with agent_can_call(agent_id, family).
3. Unit tests covering 4 matrix cells:
- allowlist OFF, loaded TRUE -> callable_now=TRUE
- allowlist OFF, loaded FALSE -> callable_now=FALSE
- allowlist ON, agent in pattern, loaded TRUE -> callable_now=TRUE
- allowlist ON, agent NOT in pattern, loaded TRUE -> callable_now=FALSE
4. v2 callers must NOT see callable_now in their response.
Branch: feat/v0.7-a-3-callable-now
Commit: feat(mcp): per-tool callable_now flag in v3 (#545)
A4: agent_permitted_families field
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task A4 (#545).
Depends on A1, A3.
Goal: top-level agent_permitted_families: ["core", "graph"] field in v3,
populated only when [mcp.allowlist] applies.
What to do:
1. Reuse agent_can_call helper from A3.
2. In build_capabilities_v3, when allowlist is enabled, compute the list
of families the requesting agent can access; include it as
`agent_permitted_families`.
3. When allowlist disabled OR no agent_id provided in initialize handshake,
omit the field entirely.
4. Unit tests for 3 cases: disabled / enabled-with-agent / enabled-no-agent.
Branch: feat/v0.7-a-4-agent-permitted-families
Commit: feat(mcp): surface agent_permitted_families in v3 (#545)
A5: Bump capabilities schema to v3 default
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task A5 (#545).
Depends on A1-A4.
Goal: bump the schema to v3 in API_REFERENCE.md, SDKs, and runtime defaults.
v2 + v1 remain valid for backward compat.
What to do:
1. Update src/mcp.rs accept enum: ["v1", "v2", "v3"], default = "v3".
2. sdk/typescript/src/types.ts: add MemoryCapabilitiesV3 type.
3. sdk/python/ai_memory/models.py: add MemoryCapabilitiesV3 pydantic model.
4. docs/API_REFERENCE.md: new "v3 schema" subsection with field-by-field
docs. Add a "v2 → v3 diff" section near the top.
5. Integration test asserting v3 is the new default.
Branch: feat/v0.7-a-5-schema-v3
Commit: feat(mcp): bump capabilities schema to v3 default (#545)
Track B — Loader tools
B1: memory_load_family(family) tool
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task B1 (#545, #546).
Goal: add memory_load_family tool to the always-on family. The loader of
last resort gets a name that says "load."
Why: real LLM observation cells (2026-05-05) showed reasoning-class agents
looked for an explicitly-named loader, hypothesized one must exist, didn't
find one, concluded a bootstrap limitation existed.
What to do:
1. Add memory_load_family to src/mcp.rs always-on registry.
2. Tool schema:
{
"name": "memory_load_family",
"description": "Load a tool family at runtime. Returns schemas; on
harnesses with deferred-tool registration (Claude Code, OpenClaw),
the tools become directly callable for the rest of the session.
On other harnesses, returns schemas plus a hint to restart the
server with --profile <family>.",
"inputSchema": {
"type": "object",
"required": ["family"],
"properties": {
"family": { "type": "string", "enum": [...8 families...] }
}
}
}
3. Handler delegates to a shared helper build_family_schemas(family,
harness_info) that memory_capabilities also calls when given
include_schema=true.
4. Response carries: family, schemas, your_harness_supports_deferred_registration,
to_invoke (harness-aware text).
5. Tests: unit tests per family; integration tests via stdio MCP;
tests/calibration_t0.rs case asserting LLMs find the tool when asked.
Branch: feat/v0.7-b-1-memory-load-family
Commit: feat(mcp): add memory_load_family tool (#545, #546)
B2: memory_smart_load(intent) tool
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task B2 (#546).
Depends on B1, B3, B4.
Goal: intent-aware loader. Agent says "what do I need for X" in plain
language; substrate matches intent to family/families, returns schemas.
What to do:
1. Create src/intent_classifier.rs with:
- trait IntentClassifier { fn classify(intent: &str) -> Vec<Family>; }
- EmbeddingClassifier — sentence-transformers cosine similarity
against pre-computed family descriptors (from B3).
- KeywordClassifier — fallback when embedding tier off.
- facade pick_classifier() based on active feature tier.
2. Add memory_smart_load tool to src/mcp.rs always-on registry.
Handler: classifier.classify(intent) → for each family → build_family_schemas
→ aggregate.
3. Response: matched_families, matched_tools, schemas,
your_harness_supports_deferred_registration, to_invoke.
4. Unit test: 30-intent labelled corpus; >= 80% top-match accuracy.
5. Integration test: end-to-end MCP call with intent="consolidate memories
and detect contradictions" → power+meta families returned.
6. Calibration test: agent reaches for memory_smart_load on intent prompts.
Branch: feat/v0.7-b-2-memory-smart-load
Commit: feat(mcp): add memory_smart_load intent-aware loader (#546)
B3: Pre-compute family-descriptor embeddings
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task B3 (#546).
Required by B2.
Goal: pre-compute embeddings for the 8 family descriptors at build time.
What to do:
1. src/family_descriptors.rs with canonical descriptors (see V0.7-EPIC):
- core: "Store, recall, search, list, and get individual memories. Basic CRUD."
- lifecycle: "Delete, update, promote memories. Manage memory existence and tier transitions."
- graph: "Link memories together. Query the knowledge graph. Register entities."
- governance: "Approve, reject, or flag memory operations. N-of-M consensus."
- power: "Consolidate near-duplicates. Detect contradictions. Auto-tag. Expand queries."
- meta: "Introspect. Statistics, configuration, session-state, audit-log queries."
- archive: "Archive, restore, purge. Manage long-term storage."
- other: "Miscellaneous tools — usually deprecated or experimental."
2. build.rs runs sentence-transformers/all-MiniLM-L6-v2 over the 8
descriptors at build time; serialize to assets/family-descriptors.bin
(fp16, 384 dims each ~6.1KB total).
3. EmbeddingClassifier loads via include_bytes! at compile time.
4. Self-similarity test: each descriptor is its own top-1 match.
5. Binary growth: <50KB.
Branch: feat/v0.7-b-3-family-descriptor-embeddings
Commit: feat(mcp): pre-compute family-descriptor embeddings (#546)
B4: Detect harness from MCP clientInfo
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task B4 (#546).
Goal: harness-aware response shape. Detect from MCP initialize handshake
clientInfo.name; map to HarnessProfile.
What to do:
1. Create src/harness.rs with:
- struct HarnessProfile { name, supports_deferred_registration:
bool, suggested_action: String }
- fn detect_harness(client_info: &ClientInfo) -> HarnessProfile
2. Hardcoded mapping (per V0.7-EPIC Track B4 table):
claude-code → true (ToolSearch)
openclaw → true (native)
claude-desktop → false
codex-cli → false
grok-cli → false
gemini-cli → false
cursor → false
cline → false
continue → false
windsurf → false
unknown → false (conservative)
3. Plumb HarnessProfile through MCP session state; B1 + B2 use it for
to_invoke text.
4. Unit tests for each row + unknown.
5. const HARNESS_REGISTRY for future PRs to extend.
Branch: feat/v0.7-b-4-harness-detection
Commit: feat(mcp): harness-aware response shaping via clientInfo (#546)
B5: Update memory_capabilities description to point at the new loaders
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task B5 (#545).
Depends on B1, B2.
Goal: update memory_capabilities tool description string to explicitly
point at memory_load_family + memory_smart_load.
What to do:
1. Find description string in src/mcp.rs.
2. Replace with: "...To LOAD an unloaded family at runtime, use
memory_load_family(family=X) (preferred) or pass family=X,
include_schema=true to this tool (legacy path). For intent-based
loading, use memory_smart_load(intent='...')."
3. Verify the new description fits under 1500-token-per-tool ceiling:
cargo test --lib sizes::tests::no_tool_exceeds_1500_tokens -- --exact
4. Update v3 capabilities response to reflect the new description.
Branch: feat/v0.7-b-5-capabilities-description-pointer
Commit: feat(mcp): point memory_capabilities at new loaders (#545)
Track C — Schema compaction
C1: Audit tool descriptions for verbosity
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task C1 (#546).
Goal: audit all 43 tool descriptions; identify verbosity hotspots driving
--profile full above 6,000 tokens.
What to do:
1. Run ai-memory doctor --tokens --raw-table --json.
2. Sort by cost descending.
3. Flag any tool whose description (not inputSchema) is over 200 tokens.
4. Write docs/v0.7/schema-compaction-audit.md with:
Table: tool name | family | description tokens | inputSchema tokens
| total | flagged?
5. Top hotspots → candidates for C2-C5.
Branch: feat/v0.7-c-1-audit
Commit: docs(v0.7): schema compaction audit (#546)
C2: Move docstrings to docs field (verbose-only)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task C2 (#546).
Depends on C1.
Goal: each tool's description = essential one-liner; long-form docstrings
move to `docs` field returned only on verbose=true.
What to do:
1. For each flagged tool from C1: split description into essential one-liner
+ long-form docs.
2. tools/list omits docs by default.
3. memory_capabilities(verbose=true) includes docs per tool.
4. Sanity test: ask Claude Code "what does memory_consolidate do?" given
only the new descriptions — answer should be substantively correct.
5. Token-budget CI: full-profile drops by ≥1500 tokens.
Branch: feat/v0.7-c-2-docs-field
Commit: feat(mcp): split tool descriptions from long-form docs (#546)
C3: Drop redundant inline examples
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task C3 (#546).
Depends on C2.
Goal: strip redundant inline examples from JSON-schema description fields.
What to do:
1. grep src/mcp.rs for "e.g.," and "for example,".
2. Rewrite each to be self-explanatory without the example. Example
moves to docs field if not already there.
3. cargo test --lib mcp::tests — no regressions.
4. Token-budget CI: full-profile drops ≥500 more tokens.
Branch: feat/v0.7-c-3-drop-redundant-examples
Commit: feat(mcp): drop redundant inline examples (#546)
C4: Hide rarely-used optional params from default schema
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task C4 (#546).
Depends on C3.
Goal: rare optional params not advertised by default; surface via verbose=true.
What to do:
1. For each tool: list optional params (not in required:[]).
2. Categorize as "common" (>50% of canonical examples) or "rare".
3. inputSchema.properties shown in tools/list keeps required + common.
4. Rare params move to a side-list extended_properties returned only on
memory_capabilities(verbose=true).
5. Runtime acceptance unchanged — tool handler still accepts rare params.
6. Token-budget CI: full-profile drops ≥300 more tokens.
Branch: feat/v0.7-c-4-optional-params-hidden-by-default
Commit: feat(mcp): hide rarely-used params from default schema (#546)
C5: CI gate enforces full-profile ≤ 3,500 tokens
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task C5 (#546).
Depends on C2, C3, C4.
Goal: lock in the schema-compaction win.
What to do:
1. src/sizes.rs: update FULL_PROFILE_HONEST_RANGE from (5000, 8000) to
(3000, 3500).
2. cargo test --lib sizes::tests::full_profile_total_in_honest_measured_range
should pass; if not, C2-C4 incomplete.
3. .github/workflows/token-budget.yml comment references new bound.
4. Update MIGRATION_v0.7.md and V0.7-EPIC.md with new measured range.
Branch: feat/v0.7-c-5-ci-gate-3500
Commit: feat(ci): lock full-profile schema cost ≤3500 tokens (#546)
Track D — Per-harness positioning + tests
D1: Cross-harness benchmark
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task D1 (#546).
Goal: reproducible benchmark across harnesses, before/after a representative
load_family call.
What to do:
1. Create benchmarks/v0.7-cortex-on-core.md.
2. For each harness {claude-code, openclaw, claude-desktop, codex-cli,
grok-cli, gemini-cli}, simulate an MCP session:
- Call tools/list (record boot_cost)
- Call memory_load_family(family="graph") (record post_load_cost)
- Compute net = boot + (post_load - boot) on deferred-registration
harnesses; else = boot
3. Per-harness Pareto position table.
4. "Reproduction" subsection with exact ai-memory commands.
Branch: feat/v0.7-d-1-cross-harness-benchmark
Commit: bench(v0.7): cross-harness cortex-on-core benchmark (#546)
D2: Compatibility matrix on landing page
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task D2 (#546).
Goal: update landing-page cortex-on-core section with v0.7.0 numbers.
What to do:
1. Find the cortex-on-core section in docs/index.html (added 2026-05-05).
2. Update 3-column cost table: --profile full from 6,200 → ≤3,500.
3. Harness compatibility table: Claude Code + OpenClaw rows reference
memory_smart_load(intent="…") as the natural-language loader.
4. Verify all link targets resolve.
Branch: feat/v0.7-d-2-compat-matrix-on-landing
Commit: docs(pages): update cortex-on-core section for v0.7.0 (#546)
D3: Install-time system-prompt snippet
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task D3 (#546).
Goal: ai-memory install prints a recommended system-prompt snippet to
stdout so any harness can paste it.
What to do:
1. In src/cli/install.rs, after canonical config write, print:
"Recommended system-prompt addition for this harness:
<<<
You have access to ai-memory v0.7.0 with a 5-tool default surface.
If you need a tool not currently loaded, call
memory_smart_load(intent='<plain-language description>') to load
the right family. You don't need to know the family taxonomy.
>>>
Drop this into your harness's system prompt (location varies; see
docs/integrations/v0.7-system-prompt-snippet.md)."
2. Create docs/integrations/v0.7-system-prompt-snippet.md with per-harness
placement instructions.
3. Unit tests: snippet printed for every install subcommand.
Branch: feat/v0.7-d-3-install-snippet
Commit: feat(cli): print system-prompt snippet on install (#546)
D4: Harness integration tests
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task D4 (#546).
Depends on B1, B4.
Goal: integration-test harness detection across all known harnesses.
What to do:
1. tests/harness_integration.rs (new).
2. For each harness in HARNESS_REGISTRY:
- Open MCP session with clientInfo.name = harness name
- Call memory_load_family(family="graph")
- Assert: response.your_harness_supports_deferred_registration
matches registry expectation
- Assert: to_invoke text contains the right hint
3. "unknown harness" case: conservative-default behavior.
4. cargo test --test harness_integration in CI.
Branch: feat/v0.7-d-4-harness-integration-tests
Commit: test(integration): per-harness to_invoke text branching (#546)
Track E — Discovery Gate T0 cells
E1: Orchestrate T0 cells across LLMs
You are working on alphaonedev/ai-memory-discovery-gate toward v0.7.0
calibration coverage.
Goal: lift T0 from observation-mode to gate-grade orchestration. Run T0
prompts deterministically across at least 4 LLMs.
What to do:
1. scripts/run-t0-cells.sh parameterized by env var:
T0_LLM=claude-opus-4.7 → anthropic-sdk via API
T0_LLM=grok-4.3 → xAI api
T0_LLM=gpt-4.5 → openai-sdk
T0_LLM=gemini-pro-2 → google-generative-ai sdk
2. Prompt suite (2 prompts per cell):
- "What memory tools do you have access to right now?"
- "How would you know if you needed one not loaded?"
3. Pass criteria match docs/tiers/t0-calibration.md.
4. Output: docs/runs/<date>/cells/<llm>-<harness>-t0-calibration-core.{json,md,transcript.jsonl,wire.jsonl}
5. Update verdict.md.
Branch: feat/v0.7-e-1-t0-orchestrated
Commit: feat(t0): orchestrated cells across 4 LLMs (#1)
E2: Re-run T0 cells against v0.7.0 binary
You are working on alphaonedev/ai-memory-discovery-gate post-v0.7.0 ship.
Goal: validate substrate-side fixes closed the calibration gap.
What to do:
1. Pull v0.7.0 binary as DISCOVERY_GATE_BINARY.
2. Re-run T0 cells via E1 orchestrator across all 4 LLMs.
3. Update verdict.md with new pass rates.
4. Compare:
- v0.6.4: ~50% calibration accuracy (observed)
- v0.7.0 target: ≥95% across all 4 LLMs
5. If convergence target NOT met: file follow-up against
alphaonedev/ai-memory-mcp identifying still-misaligned cell.
Branch: feat/v0.7-e-2-t0-postship
Commit: feat(t0): post-ship convergence verification (#1)
E3: Loader cells for T1-T3 tiers
You are working on alphaonedev/ai-memory-discovery-gate.
Goal: gate cells that explicitly test the v0.7.0 loaders.
What to do:
1. Add three cells:
- t1-awareness-loaders.md — pass: agent names memory_load_family OR
memory_smart_load when asked "how do I load a tool family?"
- t2-reactive-loaders.md — pass: agent reads memory_capabilities
description, proceeds with memory_load_family.
- t3-proactive-smart-load.md — pass: given an intent, agent reaches
for memory_smart_load before memory_capabilities.
2. Implement in scripts/run-llm-cells.sh.
3. Run against v0.7.0 binary across 4 LLMs.
Branch: feat/v0.7-e-3-loader-cells
Commit: feat(t1-t3): cells for new v0.7.0 loaders (#1)
Track G — Hook Pipeline (Bucket 0)
G1: hooks.toml schema
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G1.
Goal: define hooks.toml schema and config-loading pipeline. The substrate
every other Track G task depends on.
What to do:
1. src/hooks/config.rs:
- struct HookConfig { event, command, priority, timeout_ms, mode,
enabled, namespace }
- enum HookEvent (20 variants from G2)
- enum HookMode { Exec, Daemon }
- HookConfig::load_from_file(path) -> Result<Vec<HookConfig>>
2. Default path: ~/.config/ai-memory/hooks.toml.
3. SIGHUP triggers reload; in-flight executions complete on old config.
4. Validation: priority i32, timeout_ms u32 ≤ 30000, namespace glob pattern.
5. Parse-time errors include line numbers (toml::Spanned).
6. Unit tests covering valid/invalid configs.
Branch: feat/v0.7-g-1-hooks-config
Commit: feat(hooks): hooks.toml config schema with hot reload
G2: 20 hook event types
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G2.
Depends on G1.
Goal: define 20 lifecycle event types and payloads.
What to do:
1. src/hooks/events.rs.
2. enum HookEvent — 20 variants:
pre_store, post_store, pre_recall, post_recall, pre_search, post_search,
pre_delete, post_delete, pre_promote, post_promote, pre_link, post_link,
pre_consolidate, post_consolidate, pre_governance_decision,
post_governance_decision, on_index_eviction, pre_archive,
pre_transcript_store, post_transcript_store
3. Payload structs per event. Pre-events have writable deltas;
post-events read-only.
4. Implement Serialize for JSON-stdio IPC.
5. Doc-comment each event with the source file:line of its invocation.
6. Round-trip test through JSON for each variant.
Branch: feat/v0.7-g-2-hook-events
Commit: feat(hooks): 20 lifecycle event types with payloads
G3: Hook executor (exec + daemon modes)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G3.
Depends on G1, G2.
Goal: hook executor supporting both subprocess-per-fire and long-lived
daemon modes.
What to do:
1. src/hooks/executor.rs.
2. trait HookExecutor { fn fire(event, payload) -> Result<HookDecision>; }
3. ExecExecutor — tokio::process::Command per fire. JSON in stdin, JSON
out stdout. Clean shutdown on stdin close.
4. DaemonExecutor — long-lived child. JSON-RPC framing (newline-delimited
OR length-prefixed; pick + document). Reconnect on crash with exp
backoff. Backpressure: oldest-first drop with warning if child can't
keep up.
5. ExecutorRegistry maps HookConfig → instance.
6. Integration tests:
- exec mode: 100 concurrent fires within timeout
- daemon mode: 1000 fires through one daemon child within deadline;
mid-stream crash triggers reconnect
7. ai-memory doctor --tokens --hooks reports executor metrics.
8. CRITICAL: post_recall + post_search default mode = daemon to preserve
v0.6.3 50ms recall budget.
Branch: feat/v0.7-g-3-hook-executor
Commit: feat(hooks): subprocess executor with exec + daemon modes
G4: Decision types
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G4.
Depends on G2.
Goal: define HookDecision and serialization contract.
What to do:
1. src/hooks/decision.rs.
2. enum HookDecision { Allow, Modify(MemoryDelta), Deny{reason, code},
AskUser{prompt, options, default} }.
3. Modify is pre-event-only (compile-time guard or runtime validation).
4. Wire JSON shape:
{"action":"allow"} | {"action":"modify","delta":{...}}
{"action":"deny","reason":"...","code":403}
{"action":"ask_user","prompt":"...","options":[...],"default":"..."}
5. Strict Deserialize — unknown actions / missing fields → parse error
surfaced as warning.
6. Unit tests for each variant + invalid payloads.
Branch: feat/v0.7-g-4-decision-types
Commit: feat(hooks): decision type contract
G5: Chain ordering + first-deny-wins
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G5.
Depends on G3, G4.
Goal: chain multiple hooks; resolve conflicts.
What to do:
1. src/hooks/chain.rs.
2. struct HookChain { hooks: Vec<HookConfig> } sorted by priority desc.
3. HookChain::fire(event, payload) -> ChainResult:
- iterate hooks in priority order
- call executor.fire() for each
- if Deny: short-circuit
- if Modify: update payload, continue
- if AskUser: queue prompt, continue
- if Allow: continue
4. ChainResult: Allow, ModifiedAllow(payload), Deny, AskUser(queue).
5. Unit tests:
- 3 hooks, first denies → chain stops at first
- 3 hooks, all allow with modifications → final payload composed
- mid-chain crash → log warning, continue, treat as Allow
(configurable per hook with fail_mode = "open" | "closed")
6. Integration with subscriptions.rs::dispatch_event — hooks fire BEFORE
subscriptions for pre-, AFTER for post-.
Branch: feat/v0.7-g-5-chain-ordering
Commit: feat(hooks): chain ordering + first-deny-wins
G6: Hard timeouts per event class
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G6.
Depends on G2, G5.
Goal: enforce per-event-class deadlines so hooks can't break recall p95.
What to do:
1. src/hooks/timeouts.rs.
2. fn event_class(HookEvent) -> EventClass { Write, Read, Index, Transcript }.
3. CLASS_DEADLINES const map: 5000ms write, 2000ms read, 1000ms index,
5000ms transcript.
4. At HookChain::fire, deadline = now + class_deadline. Each hook gets
min(class_remaining, hook_timeout_ms).
5. Hook exceeds budget: kill subprocess (or close daemon stream), log
warning, treat as fail-open Allow.
6. CI bench test: deliberately-slow chain on post_recall must NOT push
recall p95 above 50ms.
7. Doctor reports timeout-violation counts.
Branch: feat/v0.7-g-6-event-class-timeouts
Commit: feat(hooks): per-event-class timeout enforcement
G7: Hot reload integration test
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G7.
Depends on G1.
Goal: verify hot reload end-to-end.
What to do:
1. tests/hooks_hot_reload.rs.
2. Start ai-memory in test mode with hooks.toml = "config A".
3. Fire memory_store; assert hook A's command invoked.
4. Replace hooks.toml on disk with "config B".
5. Send SIGHUP.
6. Wait for reload (poll for ≤500ms).
7. Fire memory_store; assert hook B's command invoked (not A).
8. In-flight hook from before SIGHUP must complete on old config.
Branch: feat/v0.7-g-7-hot-reload-test
Commit: test(hooks): hot reload integration test
G8: on_index_eviction event (G2 audit absorption)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G8.
Goal: emit on_index_eviction hook event when ANN index evicts.
What to do:
1. Locate ANN eviction path in src/storage/embedding_index.rs.
2. After eviction, fire HookEvent::OnIndexEviction with payload
{ evicted_id, reason: "lru" | "capacity", remaining_size }.
3. Surface eviction count in ai-memory stats.
4. Unit test: trigger eviction, assert event fired + count incremented.
Branch: feat/v0.7-g-8-eviction-event
Commit: feat(hooks): on_index_eviction event + stats counter
G9: Reranker batching (G7 audit absorption)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G9.
Goal: close G7 audit (Mutex throughput on reranker).
What to do:
1. Read src/reranker.rs; locate Mutex-protected single-request forward pass.
2. Replace with batching layer:
- Incoming requests join a queue with oneshot::Sender for results.
- Worker drains every 5ms (configurable) OR when N queued (default 8).
- Single forward pass over the union of queued query+candidate sets.
- Demux back to oneshot::Senders.
3. Bench: 100 concurrent rerank requests in 2× single-request time
(not 100×).
4. CI bench test: batched throughput ≥10× single-request throughput at
concurrency=20.
Branch: feat/v0.7-g-9-reranker-batching
Commit: perf(reranker): batched single-pass throughput
G10: pre_recall daemon-mode hook for query expansion (G10 audit absorption)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G10.
Goal: memory_expand_query becomes pipeable through pre_recall daemon-mode
hook. Doesn't violate "zero tokens until recall" — server-side expansion.
What to do:
1. The pre_recall hook event is already in G2. In src/recall.rs, fire
pre_recall before query construction.
2. The hook can return Modify(RecallQuery) with expanded terms.
3. Reference hook implementation in tools/query-expander/ (separate Rust
binary):
- Reads JSON RecallQuery from stdin
- Expands query via Ollama (existing infrastructure)
- Returns HookDecision::Modify(...)
4. Default off; opt-in per namespace via hooks.toml.
5. Bench: pre_recall daemon hook adds <10ms p95 to recall path.
Branch: feat/v0.7-g-10-pre-recall-expand
Commit: feat(hooks): pre_recall daemon-mode query expansion hook
G11: R3 — Auto-link inference
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G11 (R3).
Depends on G1, G2, G3.
Goal: ship reference auto-link detector hook. Recovers commitment R3.
What to do:
1. Create tools/auto-link-detector/ (separate Rust binary).
2. Reads JSON HookEvent::PostStore from stdin (daemon mode):
- Receives just-stored Memory.
- Queries ai-memory neighbors via memory_recall (thin SDK client).
- Embeds new memory + each neighbor; cosine similarity.
- Heuristic: cosine > 0.85, same namespace → propose "related_to".
- Heuristic: cosine 0.6-0.85, content negation aligned → propose
"contradicts".
- Each proposal: emit memory_link via HookDecision::Modify (chain
persists transactionally with original store).
3. Metrics: proposals_emitted, links_persisted, conflicts_detected.
4. Default off; example hooks.toml entry in docs/hooks/auto-link.md.
5. tests/hooks_auto_link.rs runs ai-memory with hook enabled, stores
contradiction pair, asserts link created.
Branch: feat/v0.7-g-11-auto-link-r3
Commit: feat(hooks): R3 auto-link detector reference hook
Track H — Ed25519 Attested Identity
H1: Per-agent keypair management
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H1.
Goal: per-agent Ed25519 identity. CLI: generate / import / list.
What to do:
1. src/identity/keypair.rs:
- struct AgentKeypair { agent_id, public, private (Option) }
- fn generate(agent_id) -> AgentKeypair (ed25519-dalek)
- fn save(keypair, dir) — mode 0600 priv, 0644 pub
- fn load(agent_id, dir) -> AgentKeypair
- fn list(dir) -> Vec<AgentKeypair> (priv NOT loaded)
2. src/cli/identity.rs subcommand:
- ai-memory identity generate --agent-id <id>
- ai-memory identity import --agent-id <id> --pub <path> --priv <path>
- ai-memory identity list
- ai-memory identity export-pub --agent-id <id>
3. Default key dir: ~/.config/ai-memory/keys/.
4. Default agent_id matches NHI-hardened default from CLI.
5. Hardware-backed storage (TPM/HSM) is OUT of OSS scope — doc-comment
pointing at AgenticMem commercial layer.
6. Round-trip test: generate → save → load.
7. Permissions test (mode 0600/0644).
Branch: feat/v0.7-h-1-agent-keypair
Commit: feat(identity): per-agent Ed25519 keypair CLI
H2: Outbound link signing
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H2.
Depends on H1.
Goal: every memory_link write signs with active agent's private key.
Fills the dead signature column shipped in v0.6.3.
What to do:
1. src/identity/sign.rs:
- fn canonical_cbor(link: &Link) -> Vec<u8> (RFC 8949 §4.2.1)
- fn sign(keypair, link) -> Vec<u8>
2. src/storage/links.rs::insert_link:
- Look up active agent's keypair from AppState::active_keypair
- Compute canonical CBOR
- Sign; store 64-byte signature in existing signature column
- Set attest_level = "self-signed"
3. No keypair → leave signature NULL, attest_level = "unsigned".
4. Unit test: insert link with generated keypair, read back, verify
signature with public key.
5. Integration test against memory_link MCP tool — wire response includes
attest_level.
Branch: feat/v0.7-h-2-link-signing
Commit: feat(identity): outbound Ed25519 signing on memory_links
H3: Inbound verification
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H3.
Depends on H2.
Goal: when a link arrives from a peer, verify signature against the
public key associated with observed_by claim.
What to do:
1. src/identity/verify.rs:
- fn verify(link: &Link, peer_keys: &PeerKeyRegistry) -> VerifyResult
2. PeerKeyRegistry: HashMap<agent_id, ed25519::PublicKey> populated from
~/.config/ai-memory/keys/peers/<agent_id>.pub.
3. src/federation/inbound.rs: on inbound link, call verify.
- signature_verified=true → attest_level = "peer-attested"
- signature_verified=false → reject, log warning, increment
federation_rejected_count
- observed_by has no known key → accept-and-flag as "unsigned"
4. Unit + integration tests.
Branch: feat/v0.7-h-3-inbound-verify
Commit: feat(identity): inbound Ed25519 verification with peer registry
H4: attest_level enum + memory_verify MCP tool
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H4.
Depends on H2, H3.
Goal: attest_level enum + memory_verify MCP tool.
What to do:
1. src/storage/links.rs: enum AttestLevel { Unsigned, SelfSigned,
PeerAttested }. Stored as TEXT in attest_level column.
2. New MCP tool memory_verify(link_id):
- Returns { signature_verified, attest_level, signed_by, signed_at }
- signature_verified: re-runs verification on demand
3. Tool is in core family (loaded by default — admins should always
be able to verify).
4. Doc + tests.
Branch: feat/v0.7-h-4-attest-level
Commit: feat(identity): attest_level enum + memory_verify MCP tool
H5: signed_events audit table
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H5.
Goal: append-only audit table for signed events.
What to do:
1. Schema migration v22 → v23 (or whatever next is):
CREATE TABLE signed_events (
id TEXT PRIMARY KEY,
agent_id TEXT NOT NULL,
event_type TEXT NOT NULL,
payload_hash TEXT NOT NULL,
signature BLOB NOT NULL,
attest_level TEXT NOT NULL,
timestamp TEXT NOT NULL
);
2. No application-layer UPDATE/DELETE; INSERT-only.
3. Each memory_link write also INSERTs into signed_events.
4. memory_verify can cross-reference signed_events for an immutable
audit trail.
5. cli::boot::MAX_SUPPORTED_SCHEMA bumped.
6. Tests: insert, attempted-update fails, audit chain verifiable.
Branch: feat/v0.7-h-5-signed-events-table
Commit: feat(identity): signed_events append-only audit table
H6: Verification end-to-end test
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H6.
Closes G12 audit finding.
Goal: end-to-end test proving signature verification works.
What to do:
1. tests/identity_e2e.rs:
- Generate keypair for agent A
- Store a memory_link as agent A
- Read the link back; assert signature column non-NULL
- Call memory_verify(link_id) → assert signature_verified=true
- Negative test: tamper with link content; verify returns false
2. CRITICAL: this test must pass for v0.7.0 to ship per ROADMAP §7.3
exit criteria.
Branch: feat/v0.7-h-6-verify-e2e-test
Commit: test(identity): end-to-end signature verification (G12)
Track I — Sidechain Transcripts
I1: memory_transcripts table (zstd-3 BLOB)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task I1.
Goal: schema for compressed transcript storage.
What to do:
1. Migration v23 → v24 in src/storage/migrations/.
2. CREATE TABLE memory_transcripts (
id TEXT PRIMARY KEY,
namespace TEXT NOT NULL,
created_at TEXT NOT NULL,
expires_at TEXT,
compressed_size INTEGER NOT NULL,
original_size INTEGER NOT NULL,
zstd_level INTEGER NOT NULL DEFAULT 3,
content_blob BLOB NOT NULL
);
3. Index on (namespace, created_at).
4. cli::boot::MAX_SUPPORTED_SCHEMA bumped.
5. src/storage/transcripts.rs:
- fn store(namespace, content, ttl) -> Transcript
- fn fetch(id) -> Result<String>
- fn purge_expired() -> usize
6. Test: round-trip + 5-10× compression on chat-shaped text.
Branch: feat/v0.7-i-1-transcripts-schema
Commit: feat(transcripts): schema with zstd-3 BLOB storage
I2: memory_transcript_links join table
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task I2.
Depends on I1.
Goal: join table for memory→transcript links with span metadata.
What to do:
1. CREATE TABLE memory_transcript_links (
memory_id TEXT NOT NULL,
transcript_id TEXT NOT NULL,
span_start INTEGER NOT NULL,
span_end INTEGER NOT NULL,
PRIMARY KEY (memory_id, transcript_id),
FOREIGN KEY (memory_id) REFERENCES memories(id),
FOREIGN KEY (transcript_id) REFERENCES memory_transcripts(id)
);
2. Indexes on memory_id + transcript_id.
3. src/storage/transcripts.rs::link_memory_to_transcript(...).
4. Tests: many-to-many cardinality verified (1 transcript → N memories;
N memories → 1 transcript).
Branch: feat/v0.7-i-2-transcript-links
Commit: feat(transcripts): memory_transcript_links join table
I3: Per-namespace TTL with archive→prune
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task I3.
Depends on I1.
Goal: namespace-level transcript TTL with archive-then-prune lifecycle.
What to do:
1. config.toml table [transcripts.ttl_days_per_namespace]:
"*" = 30
"team/audit" = 365
"ephemeral/*" = 1
2. Background sweeper task every hour:
- For each transcript: if expires_at < now AND memories all expired
→ mark as archived
- After 7 days archived → DELETE
3. Archive moves blob to a parallel archived_transcripts table
(mirrors archived_memories pattern).
4. Tests: sweeper purges expired; non-expired untouched; archive→prune
transition.
Branch: feat/v0.7-i-3-transcript-lifecycle
Commit: feat(transcripts): per-namespace TTL + archive→prune
I4: memory_replay MCP tool
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task I4.
Depends on I1, I2.
Goal: new MCP tool memory_replay(memory_id) reconstructs the transcript
chain.
What to do:
1. src/mcp.rs: register memory_replay tool. Family: meta.
2. Handler:
- SELECT transcript_id, span_start, span_end FROM
memory_transcript_links WHERE memory_id = ? ORDER BY transcript_id
- For each transcript_id: fetch + decompress
- Return list of {transcript_id, span_text, span_start, span_end}
3. Response in TOON-compact + JSON formats.
4. Doc + integration test against memory_replay MCP wire path.
Branch: feat/v0.7-i-4-memory-replay
Commit: feat(mcp): memory_replay tool for transcript reconstruction
I5: R5 — Auto-extraction substrate hook
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task I5 (R5).
Depends on I1-I4, G3.
Goal: reference pre_store hook that extracts memories from a stored
transcript. Recovers commitment R5.
What to do:
1. tools/transcript-extractor/ (separate Rust binary).
2. Reads JSON HookEvent::PreTranscriptStore from stdin (daemon mode).
3. For each transcript:
- Run LLM (Ollama) extraction prompt to identify candidate memories.
- For each candidate → emit HookDecision::Modify with new MemoryDelta
entries to be stored alongside.
- Each extracted memory gets a memory_transcript_link to the transcript
with span_start/span_end pointing at the source spans.
4. Default off; opt-in per namespace.
5. Bench: extraction adds <500ms p95 to transcript-store path (background-
acceptable).
6. Test corpus: 10 sample transcripts with known extractable memories;
assert extraction recall ≥80%.
Branch: feat/v0.7-i-5-pre-store-transcript-hook
Commit: feat(hooks): R5 transcript-to-memory auto-extraction reference
Track J — Apache AGE Acceleration
J1: AGE detection in Postgres SAL
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J1.
Goal: detect AGE extension at Postgres SAL init.
What to do:
1. src/sal/postgres.rs initialization path:
- SELECT extname FROM pg_extension WHERE extname='age';
- If present: kg_backend = "age"
- Else: kg_backend = "cte"
2. struct PostgresSAL gains kg_backend field.
3. Log the choice at startup: "Postgres KG backend: AGE | CTE".
4. ai-memory doctor reports kg_backend.
5. Test against both AGE-enabled and AGE-disabled test DBs.
Branch: feat/v0.7-j-1-age-detection
Commit: feat(sal): detect Apache AGE extension at Postgres init
J2: Cypher implementation of memory_kg_query
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J2.
Depends on J1.
Goal: when kg_backend == "age", route memory_kg_query through Cypher.
What to do:
1. src/kg/query.rs: trait KgQueryBackend { fn query(...) -> Result<Vec<Path>>; }
2. CypherBackend impl: SELECT * FROM cypher('memory_graph',
'MATCH (a)-[:RELATION*1..N]->(b) WHERE a.id = $start RETURN path');
parameter binding via cypher's $vars syntax.
3. CteBackend (existing) impl: keep current recursive CTE.
4. AppState: select backend at SAL init; route memory_kg_query accordingly.
5. Tests against both backends asserting result equivalence (J5
formalizes this).
Branch: feat/v0.7-j-2-kg-query-cypher
Commit: feat(kg): Cypher implementation of memory_kg_query for AGE
J3: Cypher implementation of memory_kg_timeline
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J3.
Depends on J2.
Goal: Cypher implementation of memory_kg_timeline.
What to do:
1. Same backend trait pattern as J2.
2. Cypher query: MATCH (n)-[:VALID_AT*]->(...) WHERE n.id = $start
AND $when BETWEEN valid_from AND valid_until.
3. Edge cases: open-ended valid_until, valid_from = NULL.
4. Tests covering the main timeline shapes.
Branch: feat/v0.7-j-3-kg-timeline-cypher
Commit: feat(kg): Cypher implementation of memory_kg_timeline
J4: Cypher implementation of memory_kg_invalidate
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J4.
Depends on J2, J3.
Goal: Cypher implementation of memory_kg_invalidate + G14 audit absorption.
What to do:
1. Cypher: MATCH (n)-[r]->(m) WHERE n.id = $id SET r.invalidated_at = now,
r.invalidated_by = $agent_id; create audit edge:
MATCH (n) WHERE n.id = $id CREATE (n)-[:INVALIDATED_BY {at: now,
by: $agent_id, reason: $reason}]->(audit_node).
2. G14 — emit on_invalidate hook event with the audit edge.
3. Tests covering invalidation chains + audit edge presence.
Branch: feat/v0.7-j-4-kg-invalidate-cypher
Commit: feat(kg): Cypher kg_invalidate + G14 audit edge
J5: Dual-path tests
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J5.
Depends on J2, J3, J4.
Goal: AGE and CTE produce identical results.
What to do:
1. tests/kg_dual_path.rs.
2. Fixture: 200 memories + 800 links covering depth-1..5 + cycles.
3. For each KG op {kg_query, kg_timeline, kg_invalidate}:
- Run against AGE-Postgres test DB
- Run against CTE-SQLite test DB (same fixture)
- Assert result sets equivalent under set-equivalence
4. Depths: 1, 2, 3, 5. Cyclic + non-cyclic.
5. Run only when AI_MEMORY_TEST_AGE_URL env var set; CI matrix
configures.
Branch: feat/v0.7-j-5-dual-path-tests
Commit: test(kg): AGE vs CTE dual-path equivalence
J6: PERFORMANCE.md updated with separate budgets
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J6.
Depends on J2-J5.
Goal: separate p95/p99 budgets for AGE-mode and CTE-mode.
What to do:
1. Run bench against fixture corpus across depths 1, 3, 5 for both
backends.
2. Update PERFORMANCE.md:
- kg_query (CTE-SQLite, depth=1): p95 < 50ms, p99 < 100ms
- kg_query (CTE-SQLite, depth=5): p95 < 250ms, p99 < 500ms
- kg_query (AGE-Postgres, depth=1): p95 < 30ms, p99 < 60ms
- kg_query (AGE-Postgres, depth=5): p95 < 150ms, p99 < 300ms
(numbers indicative; replace with actual measurements)
3. Note the target methodology: M2 16GB reference machine.
Branch: feat/v0.7-j-6-perf-budgets
Commit: perf(kg): separate AGE/CTE p95/p99 budgets in PERFORMANCE.md
J7: R2 — memory_find_paths
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J7 (R2).
Depends on J1.
Goal: new MCP tool memory_find_paths. Recovers commitment R2.
What to do:
1. src/mcp.rs: register memory_find_paths in graph family.
inputSchema: { source: id, target: id, max_depth: int default 5 }.
2. Backend dispatch:
- AGE: MATCH p=(a)-[:RELATION*1..max_depth]->(b)
WHERE a.id=$source AND b.id=$target RETURN p
- CTE: recursive CTE walking memory_links
3. Response: list of paths, each as ordered [src,relation,dst] triples.
4. Tests + bench numbers added to J6 PERFORMANCE.md.
Branch: feat/v0.7-j-7-r2-find-paths
Commit: feat(mcp): R2 memory_find_paths MCP tool
J8: AGE bench gate (≥30% faster than CTE at depth=5)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J8.
Depends on J5, J6.
Goal: CI bench gate justifies AGE complexity. If AGE isn't ≥30% faster
than CTE at depth=5, drop AGE.
What to do:
1. .github/workflows/bench.yml: add age-vs-cte-bench job.
2. Job: run depth=5 bench against both backends; assert
p95(AGE) ≤ 0.7 × p95(CTE).
3. If gate fails: red CI; v0.7.0 release blocked until either AGE is
faster or AGE is removed.
4. Document the decision in docs/v0.7/age-justification.md.
Branch: feat/v0.7-j-8-age-bench-gate
Commit: ci(bench): AGE-mode ≥30% faster than CTE at depth=5 gate
Track K — A2A + Permissions + G1 Inheritance
K1 (G1 cutline): Namespace inheritance enforcement
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K1.
THIS IS THE CUTLINE FIX. Mandatory per ROADMAP §7.3 even if everything
else slips.
Goal: namespace inheritance enforcement. Today: parent "Approve" policy
doesn't block a child write because resolve_governance_policy only
consults the leaf. Fix: walk the chain.
What to do:
1. src/governance/policy.rs::resolve_governance_policy. Replace leaf-only
with:
for ancestor in build_namespace_chain(ns).iter().rev() {
if let Some(policy) = lookup_policy(ancestor) {
if policy.inherit || ancestor == ns {
return Some(policy);
}
}
}
None
2. struct GovernancePolicy: add inherit: bool field, default true.
3. Migration: existing rows backfill inherit=true.
4. Cutline test in tests/governance_inheritance.rs:
- Parent "team" has GovernancePolicy(approve_required=true)
- Child "team/alice" has no policy
- Write to "team/alice" → MUST require approval
This test is FATAL: failure blocks the release.
5. docs/governance.html updated with worked inheritance example.
6. Audit log records which ancestor's policy fired.
Branch: feat/v0.7-k-1-g1-inheritance-fix
Commit: fix(governance): G1 namespace inheritance enforcement (cutline)
CRITICAL: This MUST ship in v0.7.0.
K2: pending_actions timeout sweeper
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K2.
Goal: pending_actions table timeout sweeper. Closes v0.6.3.1 honest
disclosure that default_timeout_seconds was advertised but unused.
What to do:
1. Background tokio task fires every 60 seconds.
2. SELECT id FROM pending_actions WHERE created_at + default_timeout_seconds
< now AND status = 'pending';
3. UPDATE pending_actions SET status='expired', expired_at=now WHERE
id IN (...).
4. Emit on_governance_decision event for each expiry.
5. Update src/governance/lifecycle.rs and integration test.
Branch: feat/v0.7-k-2-pending-actions-sweeper
Commit: feat(governance): pending_actions timeout sweeper
K3: permissions.mode consulted by gate
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K3.
Goal: gate consults permissions.mode. Closes v0.6.3.1 honest disclosure
that permissions were advisory-only.
What to do:
1. src/governance/gate.rs: read permissions.mode at decision time.
- "enforce" → block on policy violation
- "advisory" → log, allow
- "off" → allow without checking
2. Default mode = "enforce" for new installs; "advisory" for upgrades
from v0.6.x (preserves backward compat).
3. doctor reports active mode + decision-counts per mode.
4. Tests covering all three modes.
Branch: feat/v0.7-k-3-permissions-mode-honest
Commit: feat(governance): permissions.mode actually enforced
K4: Approval-event routing through subscription system
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K4.
Goal: pending approval events flow through existing subscription system.
Closes v0.6.3.1 honest disclosure that approval.subscribers was a placeholder.
What to do:
1. When pending_action requires approval, dispatch_event("approval.requested",
payload).
2. Approval API HTTP+SSE handler in K10 consumes these events.
3. Backward compat: existing approval.subscribers list remains; events
route to subscribers via existing subscription infrastructure.
4. Integration test: subscribe to approval.requested, store with policy
that requires approval, assert webhook fired.
Branch: feat/v0.7-k-4-approval-event-routing
Commit: feat(governance): approval events through subscription system
K5: rule_summary populated
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K5.
Goal: capabilities v3 rule_summary returns real data.
What to do:
1. src/mcp.rs::build_capabilities_v3: populate rule_summary as ordered
list of active governance rules with one-line summaries.
2. Format: [{rule_id, namespace, action, summary}, ...]
3. Closes v0.6.3.1 honest-Capabilities-v2 disclosure.
4. Doc + tests.
Branch: feat/v0.7-k-5-rule-summary
Commit: feat(mcp): populate rule_summary in capabilities v3
K6: A2A correlation IDs + ACK retry + replay protection
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K6.
Goal: A2A maturity. Add correlation IDs, ACK semantics, retry, replay
protection.
What to do:
1. src/federation/a2a.rs:
- struct A2AMessage { correlation_id: Uuid, sender, recipients,
payload, expires_at }
- struct A2AAck { correlation_id, recipient, accepted: bool, reason }
2. Sender:
- UUIDv4 per outbound message
- Wait for ACK with TTL (default 30s)
- Retry up to 3× on no-ACK with exp backoff
3. Receiver:
- Bounded LRU of seen correlation IDs (size 10_000)
- Duplicate → ACK accepted=false, reason="duplicate"
- Expired → drop with warning
4. Tests: 100 messages all ACK'd; replay rejected; partition triggers
retry; expired dropped.
5. PERFORMANCE.md gets A2A throughput numbers across 3/5/10-node mesh.
Branch: feat/v0.7-k-6-a2a-maturity
Commit: feat(federation): A2A correlation IDs + ACK retry + replay
K7: Subscription reliability
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K7.
Goal: subscription dispatcher gains DLQ, replay-from-cursor, mandatory HMAC.
What to do:
1. src/subscriptions.rs::dispatch_event:
- 5xx response → exponential backoff retry (max 3)
- Final failure → INSERT into subscription_dlq
2. New table subscription_dlq(id, subscription_id, event_payload,
last_error, retry_count, queued_at).
3. CLI: ai-memory subscriptions replay --from-cursor <id> — re-fires
events from a checkpoint.
4. HMAC signing on every dispatched event mandatory (already opt-in;
flip default).
5. Tests covering retry, DLQ insert, replay-from-cursor.
Branch: feat/v0.7-k-7-subscription-reliability
Commit: feat(subscriptions): DLQ + replay-from-cursor + mandatory HMAC
K8: Per-agent rate limits + storage caps
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K8.
Goal: per-agent quotas enforced at MCP entry.
What to do:
1. config.toml [quotas.per_agent] table:
"ai:claude-code@*" = { rps_limit = 100, storage_mb_cap = 1024 }
"*" = { rps_limit = 10, storage_mb_cap = 100 }
2. src/quota/rate_limit.rs: token-bucket algorithm per agent_id.
3. src/quota/storage.rs: cumulative storage tracker; enforce on insert.
4. RPS overage → 429 Too Many Requests.
5. Storage cap → 507 Insufficient Storage.
6. ai-memory doctor reports per-agent quota usage.
7. Tests covering both kinds of limits.
Branch: feat/v0.7-k-8-per-agent-quotas
Commit: feat(quota): per-agent rate limits + storage caps
K9: Permission system overhaul
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K9.
Goal: refactor governance into rules + modes + hooks → decision.
Deny-first; ask-by-default.
What to do:
1. src/permissions/mod.rs (new module):
- struct Rule { id, namespace_pattern, action, decision_template }
- enum Mode { Enforce, Advisory, Off }
- fn decide(rule: &Rule, mode: Mode, context, hooks: &HookChain) -> Decision
2. Decision flow:
- Match rule by namespace_pattern + action
- Apply mode to determine enforcement
- Run pre_governance_decision hooks (Track G); they can override
- If no rule matches: deny-first default → AskUser by default
3. Schema migration: governance table maps to permissions table.
4. Tests: deny-first behavior; ask-by-default; hook override.
Branch: feat/v0.7-k-9-permission-system
Commit: feat(permissions): rules + modes + hooks decision system
K10: Approval API (HTTP + SSE + MCP)
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K10.
Depends on K4, K9.
Goal: three-surface approval API. HMAC mandatory. remember=forever
progressive trust.
What to do:
1. HTTP:
- GET /api/v1/approvals/pending → list
- POST /api/v1/approvals/:id/decide { decision, remember? } → record
2. SSE:
- GET /api/v1/approvals/stream → server-sent events; live updates
3. MCP:
- memory_approval_pending → list pending
- memory_approval_decide → record decision
4. HMAC signing on POST/decide is mandatory (no opt-out).
5. remember=forever: subsequent identical requests auto-approve via a
permissions rule auto-created from this decision.
6. Tests covering all three surfaces + HMAC mandatory.
Branch: feat/v0.7-k-10-approval-api
Commit: feat(permissions): three-surface approval API (HTTP + SSE + MCP)
K11: governance migrate-to-permissions CLI
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K11.
Depends on K9.
Goal: idempotent one-shot migration tool from old governance schema
to new permissions schema.
What to do:
1. ai-memory governance migrate-to-permissions:
- Default --dry-run: prints planned changes
- --apply: commits
2. Maps each governance row to a permissions Rule.
3. Idempotent: running twice produces no change.
4. Audit log entry per migrated rule.
5. Test: migrate fixture DB, assert all rows mapped, re-run is no-op.
Branch: feat/v0.7-k-11-permissions-migration
Commit: feat(cli): governance migrate-to-permissions CLI
Track F — Docs + release
F1: docs/MIGRATION_v0.7.md
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task F1.
Goal: comprehensive migration guide for users coming from v0.6.4.
Cover:
1. Capabilities v3 schema additions (summary, to_describe_to_user,
callable_now, agent_permitted_families).
2. New tools (memory_load_family, memory_smart_load, memory_find_paths,
memory_replay, memory_verify, memory_approval_*).
3. Hook pipeline (opt-in; no default change).
4. Ed25519 attestation (opt-in via ai-memory identity generate).
5. Sidechain transcripts (opt-in per namespace).
6. Apache AGE (opt-in via Postgres extension).
7. G1 inheritance fix — BEHAVIOR CHANGE: child writes may now require
approval where they didn't before. Document mitigation: set
inherit=false on child policies if backward compat needed.
8. Permissions migration via ai-memory governance migrate-to-permissions.
Style: match docs/MIGRATION_v0.6.4.md exactly.
Branch: feat/v0.7-f-1-migration-guide
Commit: docs: v0.7.0 migration guide
F2: docs/whats-new-v07.html
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task F2.
Goal: produce docs/whats-new-v07.html (Pages-side).
Style + structure: copy docs/whats-new-v064.html exactly; rewrite for
v0.7.0.
Three-audience pattern:
- 👤 If you USE AI: cortex experience now reliably arrives across LLMs.
Your memory is now cryptographically attested.
- 🛠️ If you BUILD with AI: hook pipeline + Ed25519 + sidechain transcripts
+ Apache AGE + new permission system + memory_load_family +
memory_smart_load + ~3,500-token full profile.
- 🏢 If you DECIDE AI infrastructure: signed audit chains. T4-T5
multi-agent positioning closer to ready.
Branch: feat/v0.7-f-2-whats-new-page
Commit: docs(pages): whats-new-v07
F3: Top-nav + landing-page badges + v0.6.4→v0.7.0 references
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task F3.
Goal: bump landing-page version references to v0.7.0.
What to do:
1. docs/index.html topnav: v0.6.4 link → v0.7.0 link.
2. Hero badges: test count + coverage updated.
3. "v0.6.4 cert" badge → "v0.7.0 cert".
4. Meta tags v0.6.4 → v0.7.0.
5. Footer: v0.6.4 → v0.7.0 with USPTO Serial No. preserved.
Branch: feat/v0.7-f-3-landing-version-bump
Commit: docs(pages): bump landing-page references to v0.7.0
F4: README + ADMIN_GUIDE updates
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task F4.
Goal: README + ADMIN_GUIDE reflect v0.7.0 scope.
What to do:
1. README.md:
- Badge block: tests + coverage + cert + version
- Body: new tool names; new --profile semantics; hook section
reference; identity section reference
2. docs/ADMIN_GUIDE.md:
- New sections: Hooks (track G), Identity & Attestation (track H),
Sidechain Transcripts (track I), Apache AGE (track J), Permissions
System (track K)
- Per-section: config schema, operational concerns, troubleshooting
3. Cross-link to docs/MIGRATION_v0.7.md throughout.
Branch: feat/v0.7-f-4-readme-admin-guide
Commit: docs: README + ADMIN_GUIDE for v0.7.0
F5: CHANGELOG, version bumps, tag, CI release
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task F5.
Goal: ship the release.
What to do:
1. CHANGELOG.md: comprehensive v0.7.0 entry covering Tracks A-K.
2. Version bumps:
- Cargo.toml: 0.6.4 → 0.7.0
- sdk/python/pyproject.toml: 0.6.4 → 0.7.0
- sdk/typescript/package.json: 0.6.4 → 0.7.0
3. git tag v0.7.0
4. gh release create v0.7.0 with comprehensive notes (model after v0.6.4).
5. publish-sdks.yml workflow auto-fires on tag push (npm + PyPI via OIDC).
6. SHA256SUMS asset uploaded.
Branch: feat/v0.7-f-5-release-prep
Commit: chore(release): v0.7.0 prep
F6: Design RFC docs/v0.7/rfc-attested-cortex.md
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task F6.
Goal: design RFC documenting v0.7.0 architectural decisions.
Cover:
1. Why Ed25519 over X25519+ChaCha20 (X25519 is v0.8 e2e encryption;
v0.7.0 attestation is signing-only).
2. Why subprocess-stdio + daemon-mode for hooks (vs. dynamic library
plugins or eBPF or other).
3. Why AGE behind a feature flag (not hard dependency).
4. Why permission system replaces governance instead of augmenting
(and the migration story).
5. Why sidechain transcripts are opt-in per namespace (storage cost vs
audit value tradeoff).
6. Track-by-track threat model: what each track makes harder to attack;
what stays out of scope.
Branch: feat/v0.7-f-6-design-rfc
Commit: docs(rfc): v0.7.0 design RFC — attested-cortex
End of prompts
All 69 tasks (Tracks A-K + F) have a paste-ready starter prompt above. Each is self-contained — an agent can take any one and begin work immediately.
Companion documents:
V0.7-EPIC.md— narrative, why-this-release-exists, sequencing, acceptance criteria- This file — paste-ready execution prompts
rfc-attested-cortex.md— design RFC (to be written under F6)