v0.7.0 Epic — attested-cortex
One sentence: v0.7.0 rolls the v0.6.5 cortex-fluent legibility work together with ROADMAP §7.3’s full v0.7 trust + A2A maturity scope into a single release — the substrate becomes both more articulate (loaders that say “load,” capabilities that pre-compute their own description, schemas at half the token cost) and cryptographically trustworthy (Ed25519 attestation, sidechain transcripts, hook pipeline, namespace inheritance enforcement, A2A maturity).
Status: PLANNED · 2026-05-05
Supersedes: v0.6.5 epic (cortex-fluent) — rolled into this document
Predecessor: v0.6.4 — quiet-tools — shipped 2026-05-05
Original v0.7 spec: ROADMAP.md §7.3 (Q2 2026, June target — now consolidating into attested-cortex)
Tracking issues: #545 · #546 · #512 · plus all G/H/I/J/K issues to be filed at kickoff
Why this release exists
Two narratives converge in v0.7.0:
Narrative 1 — cortex-fluent (legibility) — from v0.6.5 epic:
The 2026-05-05 NHI Discovery Gate verdict on v0.6.4 came back 6/6 PASS, GATE GREEN, but three real-world LLM observation cells captured the same day showed a legibility gap — reasoning-class LLMs (Grok 4.2 reasoning) didn’t find the runtime loader because it’s hidden inside an introspection tool’s parameter set. The substrate did its job; the language hadn’t quite caught up.
Narrative 2 — attested (trust) — from ROADMAP §7.3:
The v0.6.3 release left Ed25519 signature columns in memory_links that nothing populates (“dead column” — flagged in §5.3 audit). Hook events are advertised via subscription system but lifecycle hooks aren’t programmable. Permissions are advisory, not enforced. Namespace inheritance is display-only — leaf-policy gating means a parent Approve rule doesn’t actually block a child write. A2A correlation, ACK retries, replay protection are all known gaps.
v0.7.0 closes both at once. The substrate becomes the thing it has been describing itself as: a self-documenting, attested, programmable, cryptographically trustworthy memory cortex that an NHI fleet can ground its identity in.
Goals (priority-ordered)
Mandatory cutline (per ROADMAP §7.3)
- G1 — Namespace inheritance enforcement. “Even if everything else slips, this fix ships.”
resolve_governance_policywalks the namespace chain; first non-null policy wins.
Required for cortex-fluent narrative (from v0.6.5 epic)
- Loader tools (
memory_load_family,memory_smart_load(intent)) get names that say “load.” Reasoning-class LLMs find them on first ask. memory_capabilitiesv3 carriessummary,to_describe_to_user,callable_now,agent_permitted_families— pre-computed calibration.--profile fulldrops to ≤ 3,500 input tokens via schema compaction.
Required for attested narrative (from ROADMAP §7.3)
- Hook pipeline ships: 20 lifecycle events, JSON-stdio + daemon-mode IPC, decision types, chain ordering, hot reload.
- Ed25519 attestation: per-agent keypair, outbound signing, inbound verification,
attest_levelenum, append-onlysigned_eventsaudit table. - Sidechain transcripts: zstd-compressed BLOBs, per-namespace TTL,
memory_replay, R5 auto-extraction substrate. - Apache AGE acceleration: AGE detected in Postgres SAL, Cypher implementations of KG ops, dual-path tests, R2
memory_find_paths. - A2A maturity: correlation IDs, ACKs, retry, TTL, replay protection. Subscription reliability (DLQ, replay-from-cursor, HMAC). Per-agent quotas. Permission system with deny-first semantics. Approval API (HTTP + SSE + MCP, HMAC,
remember=forever).
Strongly recommended (validation layer)
- Discovery Gate T0 calibration cells re-run after ship; ≥95% convergence across 4 LLMs.
- Cross-harness benchmark + per-harness positioning updates.
Non-goals
- R4 (curator CLI surface) → v0.8 Pillar 2.5
- R6 (consensus memory truth-determination) → v0.8 Pillar 3
- R8 (TOON v2 schema inference) → v0.9 or formally cut
- Per-agent profile pre-warm (NHI guardrails phase 2) → v0.7.1 or v0.8
- Hardware-backed key storage (TPM/HSM/Secure Enclave) → AgenticMem commercial layer, not OSS
- Pool-of-N reranker batching → v0.9 alongside default-on rerank
- Long-term per-namespace HNSW shard / sqlite-vec migration → v0.9
- Removing v0.6.4 capabilities v2 — backward compat preserved; v3 is additive
Workstream summary
| Track | Scope | Tasks | Effort | Required? | Source |
|---|---|---|---|---|---|
| A — Capabilities v3 response shape | 5 | ~1 wk | 🔴 REQUIRED | v0.6.5 #545 | |
B — Loader tools (memory_load_family, memory_smart_load) |
5 | ~2-3 wk | 🔴 REQUIRED | v0.6.5 #546 | |
| C — Schema compaction | 5 | ~1 wk | 🟢 STRONGLY REC | v0.6.5 #546 | |
| D — Per-harness positioning + tests | 4 | ~3-5 d | 🟢 STRONGLY REC | v0.6.5 | |
| E — Discovery Gate T0 cells | 3 | ~3 d | 🟢 STRONGLY REC | v0.6.5 | |
| G — Hook Pipeline (Bucket 0) | 11 | ~3-4 wk | 🔴 REQUIRED | ROADMAP §7.3 Bucket 0 | |
| H — Ed25519 Attested Identity (Bucket 1) | 6 | ~2 wk | 🔴 REQUIRED | ROADMAP §7.3 Bucket 1 | |
| I — Sidechain Transcripts (Bucket 1.7) | 5 | ~2 wk | 🔴 REQUIRED | ROADMAP §7.3 Bucket 1.7 | |
| J — Apache AGE Acceleration (Bucket 2) | 8 | ~3 wk | 🔴 REQUIRED | ROADMAP §7.3 Bucket 2 | |
| K — A2A + Permissions + G1 cutline (Bucket 3) | 11 | ~3-4 wk | 🔴 REQUIRED (G1 mandatory) | ROADMAP §7.3 Bucket 3 | |
| F — Docs + release | 6 | ~3-5 d | 🔴 REQUIRED (every release) | v0.6.5 + this rollup |
Total: 69 tasks across 11 tracks.
Sequential effort: ~17-20 weeks (~4-5 months). With moderate parallelism (2-3 contributors): ~10-12 weeks. Highly parallel (5+): ~6-8 weeks.
The original v0.7 ROADMAP.md target was Q2 2026 (June). Adding the v0.6.5 cortex-fluent rollup pushes that to roughly Q3 2026 (July-August) at the same staffing. Cuts:
- Defer Track C (compaction) to v0.7.1 → −1 week
- Defer Track D, E to v0.7.1 → −1 week
- Defer Track J (AGE acceleration) to v0.7.1 → −3 weeks (preserves the SQLite CTE path; AGE becomes opt-in next release)
- Defer Track I (sidechain transcripts) to v0.7.1 → −2 weeks (Bucket 0 hook pipeline still ships; R5 just slips to v0.7.1)
Most aggressive cut path: ship Tracks A + B + G + H + K (core legibility + hooks + attestation + G1 cutline + permissions) in ~8-10 weeks. That’s the real v0.7.0 minimum. Everything else slips to v0.7.1.
How to use the NHI starter prompts
Same conventions as the v0.6.5 epic — every task below has a self-contained NHI starter prompt that any agent (Claude Code, Grok, Codex, etc.) can take to begin work without further briefing.
Branch naming: feat/v0.7-<track>-<task>-<short-name> (e.g., feat/v0.7-h-2-link-signing)
Commit convention: feat(<scope>): <imperative summary> (#<task-id>)
PR title: feat: v0.7-<track><number> — <one-line title>
Definition of done: explicit per task, agent self-checks against the listed criteria.
Track A — Capabilities v3 response shape
Track goal:
memory_capabilitiesv3 response pre-computes the calibration work LLMs do today. Agents converge on accurate first-answer descriptions regardless of calibration bias.
This track is unchanged from the v0.6.5 epic. Five tasks A1-A5. See v0.6.5 epic Track A for full details + starter prompts. Summary:
- A1 — top-level
summaryfield - A2 —
to_describe_to_userfield - A3 — per-tool
callable_now: bool - A4 —
agent_permitted_families(when allowlist applies) - A5 — schema bumped to v3, v2 backward compat
Track B — Loader tools
Track goal: the loader of last resort gets a name that says “load.” Reasoning-class LLMs find it on first ask. Path 1’s reliability stops being curiosity-gated.
This track is unchanged from the v0.6.5 epic. Five tasks B1-B5. See v0.6.5 epic Track B for full details + starter prompts. Summary:
- B1 —
memory_load_family(family)tool in always-on - B2 —
memory_smart_load(intent)tool with embedding-based intent matching - B3 — pre-compute family-descriptor embeddings at build time
- B4 — detect harness from MCP
clientInfo; surfaceyour_harness_supports_deferred_registration - B5 — update
memory_capabilitiesdescription to point at the new loaders
Track C — Schema compaction
Track goal:
--profile fulldrops from ~6,200 input tokens to ≤3,500. Every harness benefits.
This track is unchanged from the v0.6.5 epic. Five tasks C1-C5. Summary:
- C1 — audit all 43 tool descriptions; identify verbosity hotspots
- C2 — move docstrings to
docsfield included only withverbose=true - C3 — drop redundant inline examples
- C4 — optional params not advertised by default
- C5 — CI gate enforces full-profile ≤ 3,500 tokens
Track D — Per-harness positioning + tests
Unchanged from v0.6.5 epic. Tasks D1-D4: cross-harness benchmark, landing-page compatibility-matrix update, install-time system-prompt snippet, harness integration tests.
Track E — Discovery Gate T0 cells
Unchanged from v0.6.5 epic. Tasks E1-E3: orchestrate T0 cells across 4 LLMs, post-ship convergence verification, loader-cell additions to T1-T3 tiers.
Track G — Hook Pipeline (Bucket 0)
Track goal: programmable lifecycle events at every memory operation point. Subprocess JSON-over-stdio with daemon-mode IPC for hot paths. The substrate that R3 (auto-link inference) and R5 (auto-extraction) depend on, plus a permanent extension surface for downstream automation.
Task G1: Hook config schema (hooks.toml)
File(s): src/hooks/config.rs (new), ~/.config/ai-memory/hooks.toml (config path)
Branch: feat/v0.7-g-1-hooks-config
Deliverable: TOML schema for hook configuration, parsed at boot, hot-reloadable on SIGHUP. Each hook entry: event (enum), command (path), priority (i32), timeout_ms (u32), mode (exec |
daemon), enabled (bool). |
Schema example:
[[hook]]
event = "post_store"
command = "/usr/local/bin/auto-link-detector"
priority = 100
timeout_ms = 5000
mode = "daemon"
enabled = true
namespace = "team/*" # optional pattern; default = "*"
NHI starter prompt for G1
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G1.
Goal: define the hooks.toml schema and config-loading pipeline. This is
the substrate every other Track G task depends on.
What to do:
1. Create src/hooks/config.rs with:
- struct HookConfig { event, command, priority, timeout_ms, mode, enabled, namespace }
- enum HookEvent { 20 variants — see G2 task for the full list }
- enum HookMode { Exec, Daemon }
- impl HookConfig::load_from_file(path) -> Result<Vec<HookConfig>>
2. Default config path: ~/.config/ai-memory/hooks.toml (use dirs crate).
3. SIGHUP triggers reload; in-flight hook executions complete on old config.
4. Validation: priority is i32, timeout_ms is u32 ≤ 30_000, namespace is
a glob pattern that matches src/namespace.rs::matches_pattern.
5. Parse-time errors must include line numbers from the toml::Spanned API.
6. Add unit tests covering valid/invalid configs.
Branch: feat/v0.7-g-1-hooks-config
Commit: feat(hooks): hooks.toml config schema with hot reload (#<filed>)
Definition of done:
- HookConfig parses canonical examples
- SIGHUP reload tested
- Invalid config produces line-number errors
- Hot reload doesn't kill in-flight hook executions
Task G2: 20 hook event types
File(s): src/hooks/events.rs (new)
Branch: feat/v0.7-g-2-hook-events
Deliverable: Define the 20 lifecycle events the hook pipeline supports. Each event has a payload type and a documented invocation point.
Event matrix (16 base + 2 compaction + 2 transcripts):
| Event | When fired | Payload |
|---|---|---|
pre_store |
before persist | MemoryDelta (writable) |
post_store |
after persist | Memory (read) |
pre_recall |
before recall query | RecallQuery (writable) |
post_recall |
after recall returns | RecallResult (read) |
pre_search |
before FTS query | SearchQuery (writable) |
post_search |
after FTS returns | SearchResult (read) |
pre_delete |
before delete | MemoryRef (writable) |
post_delete |
after delete | MemoryRef (read) |
pre_promote |
before tier promotion | MemoryRef + new tier |
post_promote |
after promotion | MemoryRef + tier change |
pre_link |
before link creation | LinkDelta (writable) |
post_link |
after link creation | Link (read) |
pre_consolidate |
before consolidation | ConsolidationDelta |
post_consolidate |
after consolidation | ConsolidationResult |
pre_governance_decision |
before gate decision | GovernanceContext |
post_governance_decision |
after gate decision | GovernanceDecision |
on_index_eviction |
(G2 audit) ANN eviction | EvictionEvent |
pre_archive |
before archive | MemoryRef |
pre_transcript_store |
(1.7) before transcript store | TranscriptDelta |
post_transcript_store |
(1.7) after transcript store | Transcript (read) |
NHI starter prompt for G2
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G2.
Depends on: G1 (hook config exists).
Goal: define the 20 lifecycle event types and their payloads.
What to do:
1. Create src/hooks/events.rs.
2. enum HookEvent — 20 variants per the table in V0.7-EPIC Track G2.
3. For each event, define the payload struct. Pre- events have writable
deltas; post- events have read-only payloads.
4. Implement Serialize for each payload (JSON for stdio IPC).
5. Document each event's invocation point with a doc comment that names
the source-code location (file:line) where it will fire.
6. Add unit tests asserting each variant round-trips through JSON.
7. Update CHANGELOG with the full enum for the v0.7.0 release notes.
Branch: feat/v0.7-g-2-hook-events
Commit: feat(hooks): 20 lifecycle event types with payloads (#<filed>)
Definition of done:
- 20 variants present
- All payloads serialize to JSON
- Each event documented with invocation file:line
Task G3: Hook executor (subprocess JSON-stdio + daemon mode)
File(s): src/hooks/executor.rs (new)
Branch: feat/v0.7-g-3-hook-executor
Deliverable: Two execution modes:
exec— subprocess per fire; JSON over stdin → stdout; clean shutdown on close.daemon— long-lived child process; JSON-RPC framed; reconnection on crash; backpressure.
Hot-path constraint: post_recall and post_search default to daemon mode (preserves the v0.6.3 50ms recall budget). mode = "exec" requires explicit override.
NHI starter prompt for G3
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G3.
Depends on: G1, G2.
Goal: build the hook executor. Two modes: exec (subprocess per fire)
and daemon (long-lived child with JSON-RPC framing).
What to do:
1. Create src/hooks/executor.rs.
2. trait HookExecutor { fn fire(event: HookEvent, payload: serde_json::Value)
-> Result<HookDecision>; }
3. struct ExecExecutor — uses tokio::process::Command per fire. Stdin =
JSON payload. Stdout = JSON decision. Clean shutdown on stdin close.
4. struct DaemonExecutor — long-lived child process. Connection pool of
1 per hook command. JSON-RPC framing (newline-delimited or length-prefixed
— pick one; document choice). Reconnect-on-crash with exponential backoff.
Backpressure: if child can't keep up, queue drains to deadline; oldest
first dropped with warning log.
5. ExecutorRegistry — maps HookConfig → HookExecutor instance.
6. Integration tests with a fake subprocess (in tests/hooks_executor_test.rs):
- exec mode: 100 concurrent fires complete within their timeout
- daemon mode: 1000 fires through one daemon child complete within
deadline; child crash mid-stream triggers reconnect
7. Add backpressure metrics to ai-memory doctor --tokens (new --hooks
subcommand): events fired, events dropped, mean latency.
Branch: feat/v0.7-g-3-hook-executor
Commit: feat(hooks): subprocess executor with exec + daemon modes (#<filed>)
Definition of done:
- Both modes pass integration tests
- 50ms recall budget preserved when post_recall is daemon-mode
- Child crash recovery tested
- Doctor reports executor metrics
Task G4: Decision types (Allow / Modify(MemoryDelta) / Deny / AskUser)
File(s): src/hooks/decision.rs (new)
Branch: feat/v0.7-g-4-decision-types
Deliverable: Hook subprocess returns one of four decision shapes; hook chain processes them.
enum HookDecision {
Allow,
Modify(MemoryDelta), // pre- events only
Deny { reason: String, code: i32 },
AskUser { prompt: String, options: Vec<String>, default: Option<String> },
}
NHI starter prompt for G4
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G4.
Depends on: G2 (HookEvent + payload types).
Goal: define HookDecision and its serialization contract.
What to do:
1. Create src/hooks/decision.rs.
2. enum HookDecision { Allow, Modify(...), Deny{reason, code}, AskUser{...} }.
3. Modify is only valid on pre- events (compile-time guard via separate types
or runtime validation in the dispatcher).
4. Document the JSON serialization at the top of the file:
{"action": "allow"} | {"action": "modify", "delta": {...}}
{"action": "deny", "reason": "...", "code": 403}
{"action": "ask_user", "prompt": "...", "options": [...], "default": "..."}
5. Implement Deserialize with strict validation — unknown actions or
missing required fields produce a parse error that the executor
surfaces as a "hook returned malformed decision" warning.
6. Unit tests covering each variant + invalid payloads.
Branch: feat/v0.7-g-4-decision-types
Commit: feat(hooks): decision type contract (#<filed>)
Definition of done:
- 4 variants present and serialized correctly
- Invalid payloads rejected with named errors
- Modify validated against pre-event-only constraint
Task G5: Chain ordering + first-deny-wins short-circuit
File(s): src/hooks/chain.rs (new)
Branch: feat/v0.7-g-5-chain-ordering
Deliverable: When multiple hooks fire on the same event, they execute in priority order (descending). First Deny short-circuits the chain. Modify accumulates (later hooks see the latest delta). AskUser is queued; first non-AskUser decision continues.
NHI starter prompt for G5
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G5.
Depends on: G3, G4.
Goal: chain multiple hooks on the same event; resolve conflicts.
What to do:
1. Create src/hooks/chain.rs.
2. struct HookChain { hooks: Vec<HookConfig> } — sorted by priority desc.
3. impl HookChain::fire(event, payload) -> ChainResult:
- iterate hooks in priority order
- call executor.fire() for each
- if Deny: short-circuit, return Deny
- if Modify: update payload with delta, continue chain
- if AskUser: queue prompt, continue chain (first non-AskUser
decision wins)
- if Allow: continue chain
4. ChainResult enum: Allow, ModifiedAllow(payload), Deny, AskUser(queue).
5. Unit tests:
- 3 hooks priority 100/50/0; first denies → chain stops at first
- 3 hooks all allow with modifications → final payload is composition
- Hook crashes mid-chain → log warning, continue chain, treat crash
as Allow (fail-open). Configurable per hook with fail_mode = "open"|"closed".
6. Integration with the existing dispatch_event path in src/subscriptions.rs
— hooks fire BEFORE subscriptions for pre- events, AFTER for post-.
Branch: feat/v0.7-g-5-chain-ordering
Commit: feat(hooks): chain ordering + first-deny-wins (#<filed>)
Definition of done:
- Priority-desc ordering tested
- Modify-then-allow composition tested
- Crash fallback tested (default fail-open)
- Subscription integration verified
Task G6: Hard timeouts per event class
File(s): src/hooks/timeouts.rs (new)
Branch: feat/v0.7-g-6-event-class-timeouts
Deliverable: Per-event-class deadlines: 5000ms for write events (pre_store, pre_link, etc.), 2000ms for read events (pre_recall, pre_search). Per-hook timeout_ms cannot exceed its event class’s class deadline. Total chain runtime is bounded.
NHI starter prompt for G6
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G6.
Depends on: G2, G5.
Goal: enforce hard per-event-class timeouts so hooks cannot collectively
break the 50ms-recall p95 budget.
What to do:
1. Create src/hooks/timeouts.rs.
2. fn event_class(event: HookEvent) -> EventClass { Write, Read, Index, Transcript }
3. const CLASS_DEADLINES: HashMap<EventClass, Duration> — 5000ms write,
2000ms read, 1000ms index, 5000ms transcript.
4. At HookChain::fire entry, compute deadline = now + class_deadline.
Each hook gets min(class_remaining, hook_timeout_ms).
5. If a hook exceeds its budget: kill the subprocess (or close the daemon
stream, depending on mode), log warning, treat as fail-open Allow.
6. CI test: a deliberately-slow hook chain on post_recall must not push
total recall p95 above the existing 50ms budget. Run the bench suite.
7. Doctor reports deadline-violation count alongside other hook metrics.
Branch: feat/v0.7-g-6-event-class-timeouts
Commit: feat(hooks): per-event-class timeout enforcement (#<filed>)
Definition of done:
- Class deadlines hardcoded per the table
- Per-hook timeout cannot exceed class
- Recall-budget bench test stays green with hooks active
- Doctor reports timeout-violation counts
Task G7: Hot reload via SIGHUP
See G1 (already covers SIGHUP reload). This is a verification task.
Branch: feat/v0.7-g-7-hot-reload-test
Deliverable: Integration test that fires SIGHUP, replaces hooks.toml, asserts new hooks fire on next event without server restart.
NHI starter prompt for G7
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G7.
Depends on: G1.
Goal: verify hot reload works end-to-end.
What to do:
1. tests/hooks_hot_reload.rs — start ai-memory in test mode with
hooks.toml = "config A".
2. Fire a memory_store, assert hook A's command was invoked.
3. Replace hooks.toml on disk with "config B" (different hook command).
4. Send SIGHUP.
5. Wait for reload signal (or poll for ≤500ms).
6. Fire a memory_store, assert hook B's command was invoked (not A).
7. 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 (#<filed>)
Task G8: G2 audit absorption — on_index_eviction event
File(s): src/storage/embedding_index.rs, src/hooks/events.rs
Branch: feat/v0.7-g-8-eviction-event
Deliverable: When the ANN index evicts (LRU or capacity), fire on_index_eviction with the evicted memory_id. Surface eviction count in ai-memory stats.
Task G9: G7 audit absorption — reranker batching (Mutex throughput)
File(s): src/reranker.rs
Branch: feat/v0.7-g-9-reranker-batching
Deliverable: Concurrent rerank requests group into a single forward pass over the union of inputs; demux on output. Closes the v0.6.3 audit’s G7 finding (single Mutex serializing rerank calls).
NHI starter prompt for G9
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G9.
Goal: close the G7 audit finding (Mutex throughput on reranker).
What to do:
1. Read src/reranker.rs and locate the existing Mutex-protected single-
request forward pass.
2. Replace with a batching layer:
- Incoming requests join a queue; each request gets a oneshot::Sender
for its result.
- A worker drains the queue every 5ms (configurable) OR when N requests
are queued (configurable; default 8).
- Worker runs a single forward pass over the union of all queued
query+candidate sets.
- Worker demuxes results back to each oneshot::Sender.
3. Bench: 100 concurrent rerank requests should complete in 2× the time
of a single request (not 100× as today's Mutex serialization implies).
4. Add a CI bench test that asserts batched throughput ≥10× single-request
throughput at concurrency=20.
Branch: feat/v0.7-g-9-reranker-batching
Commit: perf(reranker): batched single-pass throughput (#<filed>)
Definition of done:
- Mutex serialization removed
- Throughput bench test green at ≥10× speedup
- Single-request latency unchanged or improved
Task G10: G10 audit absorption — pre_recall daemon-mode hook for query expansion
File(s): src/hooks/events.rs, src/recall.rs
Branch: feat/v0.7-g-10-pre-recall-expand
Deliverable: memory_expand_query (advertised as a planned tool, currently MIA) becomes pipeable through the new pre_recall daemon-mode hook. Doesn’t violate “zero tokens until recall” — the expansion is server-side and never advertised in tools/list.
Task G11: R3 — Auto-link inference as post_store daemon-mode hook
File(s): tools/auto-link-detector/ (new utility), docs/hooks/auto-link.md (new)
Branch: feat/v0.7-g-11-auto-link-r3
Deliverable: A reference post_store hook implementation that examines the just-stored memory + recent neighbors, proposes related_to / contradicts links to a downstream LLM scoring step, persists high-confidence links via memory_link. Default off; opt-in per namespace.
NHI starter prompt for G11
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task G11 (R3).
Depends on: G1, G2, G3 (hook pipeline).
Goal: ship a reference auto-link detector hook. Recovers commitment R3
from the prior phased roadmap.
What to do:
1. Create tools/auto-link-detector/ as a separate Rust binary with its
own Cargo.toml.
2. The binary reads JSON HookEvent::PostStore from stdin (daemon mode):
- Receives the just-stored Memory.
- Queries ai-memory for neighbors via memory_recall (uses a thin
ai-memory SDK Rust client).
- Embeds the new memory + each neighbor; computes cosine.
- Heuristic: if cosine > 0.85 and neighbor is in same namespace → propose
"related_to" link.
- Heuristic: if cosine in (0.6, 0.85) but content has obvious negation
("not", "won't", "doesn't") aligned with neighbor positive form →
propose "contradicts" link.
- For each proposal: emit memory_link(...) call back through HookDecision::
Modify (so the chain can persist it transactionally with the original
store).
3. Emit metrics: proposals_emitted, links_persisted, conflicts_detected.
4. Default off — example hooks.toml entry shipped in
docs/hooks/auto-link.md as opt-in instructions.
5. Integration test in tests/hooks_auto_link.rs that runs ai-memory with
the hook enabled, stores a contradiction pair, asserts the link is
created.
Branch: feat/v0.7-g-11-auto-link-r3
Commit: feat(hooks): R3 auto-link detector reference hook (#<filed>)
Definition of done:
- Reference binary builds + runs as daemon-mode hook
- Heuristic produces correct link types in test corpus
- Default off; opt-in documented
- Per-namespace opt-in tested
Track H — Ed25519 Attested Identity (Bucket 1)
Track goal: fill the v0.6.3 dead
signaturecolumn with real cryptographic attestation. Per-agent Ed25519 keypair (operator-supplied, explicit; not derived from agent_id). Outbound signing on everymemory_linkswrite. Inbound verification againstobserved_byclaim.attest_levelenum:unsigned/self-signed/peer-attested. Append-onlysigned_eventsaudit table.
Task H1: Per-agent Ed25519 keypair management
File(s): src/identity/keypair.rs (new), CLI: ai-memory identity generate, ai-memory identity import, ai-memory identity list
Branch: feat/v0.7-h-1-agent-keypair
Deliverable: CLI to generate, import, list per-agent Ed25519 keypairs. Keys stored at ~/.config/ai-memory/keys/<agent_id>.{pub,priv}. Private keys mode 0600; public keys mode 0644. Operator-supplied — not derived from agent_id.
NHI starter prompt for H1
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H1.
Goal: introduce per-agent Ed25519 identity. CLI surface to generate /
import / list. File-based key storage with strict permissions.
What to do:
1. Create src/identity/keypair.rs:
- struct AgentKeypair { agent_id, public, private (Option) }
- fn generate(agent_id: &str) -> AgentKeypair (uses ed25519-dalek)
- fn save(keypair, dir) -> Result<()>; mode 0600 priv, 0644 pub
- fn load(agent_id, dir) -> Result<AgentKeypair>
- fn list(dir) -> Result<Vec<AgentKeypair>>; private key NOT loaded
2. CLI subcommand: src/cli/identity.rs
- 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> (for sharing)
3. Default key storage: ~/.config/ai-memory/keys/
4. Integration with NHI agent_id: the CLI default agent_id matches the
NHI-hardened default (ai:<client>@<host>:pid-<pid> etc.).
5. Test: round-trip a keypair (generate → save → load), permissions
verified.
6. Hardware-backed storage is OUT of OSS scope per ROADMAP.md; just
doc-comment this clearly and point at AgenticMem commercial layer.
Branch: feat/v0.7-h-1-agent-keypair
Commit: feat(identity): per-agent Ed25519 keypair CLI (#<filed>)
Definition of done:
- generate / import / list / export-pub all work
- File permissions strictly enforced
- Round-trip test green
- Hardware-key disclaimer documented
Task H2: Outbound link signing
File(s): src/storage/links.rs, src/identity/sign.rs (new)
Branch: feat/v0.7-h-2-link-signing
Deliverable: Every memory_links insert signs the canonical-CBOR-encoded link with the active agent’s private key. Signature stored in the signature column (currently dead). attest_level set to self-signed.
Canonical CBOR encoding (per RFC 8949 §4.2.1) of: {src_id, dst_id, relation, observed_by, valid_from, valid_until}.
NHI starter prompt for H2
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task H2.
Depends on: H1.
Goal: every outbound memory_link write signs the link with the active
agent's private key. Fills the dead signature column shipped in v0.6.3.
What to do:
1. Create src/identity/sign.rs:
- fn canonical_cbor(link: &Link) -> Vec<u8> — RFC 8949 §4.2.1 encoding
of {src_id, dst_id, relation, observed_by, valid_from, valid_until}
- fn sign(keypair: &AgentKeypair, link: &Link) -> Vec<u8>
2. Update src/storage/links.rs::insert_link to:
- Look up the active agent's keypair (from AppState::active_keypair)
- Compute canonical CBOR
- Sign with private key
- Store signature (64 bytes) in the existing signature column
- Set attest_level = "self-signed"
3. If active agent has no keypair: leave signature NULL, attest_level =
"unsigned" (preserves v0.6.4 backward compat).
4. Unit test: insert a link with a generated keypair, read it back,
verify signature against the public key.
5. Integration test against existing memory_link MCP tool — assert the
wire-level response includes attest_level field.
Branch: feat/v0.7-h-2-link-signing
Commit: feat(identity): outbound Ed25519 signing on memory_links (#<filed>)
Definition of done:
- All outbound links carry a valid signature when keypair present
- attest_level correctly populated (unsigned / self-signed)
- Unit + integration tests green
- v0.6.4-compatible: links without keypair still write
Task H3: Inbound verification against observed_by claim
File(s): src/storage/links.rs, src/identity/verify.rs (new)
Branch: feat/v0.7-h-3-inbound-verify
Deliverable: When a link arrives from a peer (federation), verify the signature against the public key associated with the link’s observed_by claim. If verification fails, reject the link with a logged warning. If observed_by has no known public key, accept-and-flag as unsigned.
Task H4: attest_level enum + verify() MCP tool
File(s): src/storage/links.rs, src/mcp.rs
Branch: feat/v0.7-h-4-attest-level
Deliverable: attest_level enum with three variants (unsigned |
self_signed |
peer_attested). New MCP tool memory_verify(link_id) returns {signature_verified: bool, attest_level, signed_by, signed_at}. |
Task H5: Append-only signed_events audit table
File(s): schema migration to v21, src/storage/signed_events.rs (new)
Branch: feat/v0.7-h-5-signed-events-table
Deliverable: New table signed_events(id, agent_id, event_type, payload_hash, signature, attest_level, timestamp). Append-only — no UPDATE or DELETE statements supported via the application layer. Each memory_link write also appends to this table for an immutable audit chain.
Task H6: Verification end-to-end test
File(s): tests/identity_e2e.rs (new)
Branch: feat/v0.7-h-6-verify-e2e-test
Deliverable: Test that:
- Generates a keypair for agent A
- Stores a link as agent A
- Reads the link back, confirms signature column is non-NULL
- Calls
memory_verify(link_id)→ assertssignature_verified: true - Negative test: tamper with the link content; verify returns
false
Closes G12 audit finding (signature column was dead in v0.6.3).
Track I — Sidechain Transcripts (Bucket 1.7)
Track goal: raw conversation/reasoning trail in zstd-compressed BLOBs, linked to derived memories via
memory_transcript_links. Default off (opt-in per namespace). Substrate for R5 auto-extraction.
Task I1: memory_transcripts table schema (BLOB + zstd-3)
File(s): schema migration v21 → v22, src/storage/transcripts.rs (new)
Branch: feat/v0.7-i-1-transcripts-schema
Deliverable: New table with columns: id, namespace, created_at, expires_at, compressed_size, original_size, zstd_level (3), content_blob (BLOB).
NHI starter prompt for I1
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task I1.
Goal: schema for compressed transcript storage.
What to do:
1. Add migration v21 -> v22 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) for archive sweeps.
4. cli::boot::MAX_SUPPORTED_SCHEMA bumped to 22.
5. src/storage/transcripts.rs:
- fn store(namespace, content: &str, ttl: Duration) -> Transcript
- Compresses with zstd level 3
- Writes row with computed sizes
- fn fetch(id) -> Result<String>
- Reads row, decompresses, returns content
- fn purge_expired() -> usize
- DELETE WHERE expires_at < now AND archived = true
6. Unit tests: store + fetch roundtrip; expected compression ratio 5-10×
on chat-shaped text.
Branch: feat/v0.7-i-1-transcripts-schema
Commit: feat(transcripts): schema v22 with zstd-3 BLOB storage (#<filed>)
Definition of done:
- Migration is idempotent
- Round-trip test green
- Compression ratio ≥5× on chat-shaped input
Task I2: memory_transcript_links join table
Branch: feat/v0.7-i-2-transcript-links
Deliverable: Join table memory_transcript_links(memory_id, transcript_id, span_start, span_end). Allows multiple memories derived from one transcript and one transcript shared across multiple memories.
Task I3: Per-namespace TTL with archive → prune lifecycle
Branch: feat/v0.7-i-3-transcript-lifecycle
Deliverable: Each namespace can configure a transcript TTL via [transcripts] table in config. Background sweeper archives transcripts whose memories are all expired, then prunes after a grace period.
Task I4: memory_replay <id> MCP tool
Branch: feat/v0.7-i-4-memory-replay
Deliverable: New MCP tool memory_replay(memory_id) that traverses memory_transcript_links and reconstructs the transcript chain for a given memory. Returns the decompressed text + span metadata.
Task I5: Substrate hook for R5 auto-extraction
Branch: feat/v0.7-i-5-pre-store-transcript-hook
Deliverable: A reference pre_store hook that, when given a transcript, extracts derived memories from it (uses an LLM via the existing query_expand infrastructure). Defaults off; opt-in per namespace. Recovers commitment R5.
Track J — Apache AGE Acceleration (Bucket 2)
Track goal: Postgres SAL adapter detects Apache AGE and projects
memory_linksas a property graph for Cypher access. Recursive CTE path stays as the SQLite fallback. Closes commitment R2 (memory_find_paths).
Task J1: AGE detection in Postgres SAL
Branch: feat/v0.7-j-1-age-detection
Deliverable: At Postgres SAL initialization, run SELECT * FROM pg_extension WHERE extname='age';. If present, set kg_backend = "age"; else kg_backend = "cte".
Task J2: Cypher implementation of memory_kg_query
Branch: feat/v0.7-j-2-kg-query-cypher
Deliverable: When kg_backend == "age", route memory_kg_query through Cypher (MATCH (a)-[:RELATION*1..N]->(b) ...). SQLite path unchanged.
Task J3: Cypher implementation of memory_kg_timeline
Branch: feat/v0.7-j-3-kg-timeline-cypher
Task J4: Cypher implementation of memory_kg_invalidate
Branch: feat/v0.7-j-4-kg-invalidate-cypher
Deliverable: Cypher implementation of memory_kg_invalidate plus G14 absorption (audit-edge emission on invalidate).
Task J5: Dual-path tests (AGE-Postgres vs. CTE-SQLite identical results)
Branch: feat/v0.7-j-5-dual-path-tests
Deliverable: Test harness that runs the same query against AGE-Postgres + CTE-SQLite + asserts the result sets are equivalent under set-equivalence (since order may differ). Required across all three KG operations.
NHI starter prompt for J5
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task J5.
Depends on: J2, J3, J4.
Goal: assert AGE and CTE paths produce identical results. Dual-path
discipline is the safety net against Cypher-vs-CTE divergence.
What to do:
1. tests/kg_dual_path.rs (new file).
2. setUp: a fixture corpus of 200 memories + 800 links covering enough
topology to exercise depth-1 through depth-5 traversals.
3. For each KG operation (kg_query, kg_timeline, kg_invalidate):
- Run against an AGE-enabled Postgres test DB
- Run against a CTE SQLite test DB (same fixture)
- Assert result sets equivalent under set-equivalence (since order
may differ between paths)
4. Test depths: 1, 2, 3, 5. Cyclic and non-cyclic graphs.
5. Run only when AI_MEMORY_TEST_AGE_URL env var is set; skip otherwise
(CI matrix configures this for the AGE-postgres job).
Branch: feat/v0.7-j-5-dual-path-tests
Commit: test(kg): AGE vs CTE dual-path equivalence (#<filed>)
Definition of done:
- 12 test cases (3 ops × 4 depths) passing on both paths
- Set-equivalence assertion (not order-sensitive)
- CI runs both paths
Task J6: PERFORMANCE.md updated with separate AGE/CTE budgets
Branch: feat/v0.7-j-6-perf-budgets
Task J7: R2 — memory_find_paths(source, target) MCP tool
Branch: feat/v0.7-j-7-r2-find-paths
Deliverable: New MCP tool memory_find_paths(source, target, max_depth=5). Cypher one-liner on AGE; recursive CTE on SQLite fallback. Recovers commitment R2.
Task J8: Bench gate — AGE-mode p95 ≥ 30% faster than CTE-mode at depth=5
Branch: feat/v0.7-j-8-age-bench-gate
Deliverable: New bench.yml CI gate that runs AGE + CTE at depth=5, asserts AGE p95 ≥ 30% faster. Justifies the AGE complexity. If AGE isn’t faster, drop AGE.
Track K — A2A + Permissions + G1 Inheritance (Bucket 3)
Track goal: the mandatory cutline. G1 inheritance is “even if everything else slips, this fix ships” per ROADMAP §7.3. Plus A2A maturity, subscription reliability, per-agent quotas, permissions overhaul, approval API.
Task K1 — G1: Namespace inheritance enforcement (CUTLINE-PROTECTED)
File(s): src/governance/policy.rs, src/namespace.rs
Branch: feat/v0.7-k-1-g1-inheritance-fix
Deliverable: resolve_governance_policy(namespace) walks build_namespace_chain(namespace) and returns the first non-null policy encountered, not just the leaf. Per-policy inherit: bool flag (default true).
Test (mandatory per ROADMAP §7.3): Parent namespace has Approve policy; child namespace has none. Write to child must require approval.
NHI starter prompt for K1
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 in v0.7.0 slips.
Goal: namespace inheritance enforcement. Today's behavior: a parent
"Approve" policy doesn't block a child write because resolve_governance_policy
only consults the leaf namespace. Fix: walk the namespace chain.
What to do:
1. Locate src/governance/policy.rs::resolve_governance_policy.
2. Replace its leaf-only logic with:
for ancestor in build_namespace_chain(namespace).iter().rev():
if let Some(policy) = lookup_policy(ancestor):
if policy.inherit OR ancestor == namespace:
return policy
return None
3. Update GovernancePolicy struct: add `inherit: bool` field, default true.
4. Migration: existing rows get inherit=true (backfill via UPDATE).
5. Ship-gate test:
- Parent namespace "team" has GovernancePolicy(approve_required=true).
- Child namespace "team/alice" has no policy.
- Write to "team/alice" → must require approval (currently does not).
This test goes in tests/governance_inheritance.rs and is FATAL —
if it fails, the release is blocked.
6. Update docs/governance.html with a worked example of inheritance.
7. Add an audit-log entry on every gate decision: which ancestor's
policy fired.
Branch: feat/v0.7-k-1-g1-inheritance-fix
Commit: fix(governance): G1 namespace inheritance enforcement (#<filed>)
Definition of done:
- resolve_governance_policy walks the chain
- inherit:bool added with default true and backfill migration
- Cutline test green
- Audit log records ancestor whose policy fired
- Doc updated with worked example
CRITICAL: this fix MUST ship in v0.7.0. If anything else slips, this
stays.
Task K2: pending_actions timeout sweeper
Branch: feat/v0.7-k-2-pending-actions-sweeper
Deliverable: Background task sweeps pending_actions table every 60 seconds; expires entries past default_timeout_seconds. Single SELECT-and-UPDATE statement. Closes the v0.6.3.1 honest-Capabilities-v2 disclosure that default_timeout_seconds was advertised but unused.
Task K3: permissions.mode actually consulted by gate
Branch: feat/v0.7-k-3-permissions-mode-honest
Deliverable: The permissions.mode = "advisory" honest-disclosure shipped in v0.6.3.1 becomes obsolete because permissions are now actually enforced. Gate consults permissions.mode and changes behavior accordingly: "enforce" → blocks; "advisory" → logs; "off" → allows.
Task K4: Approval-event routing through subscription system
Branch: feat/v0.7-k-4-approval-event-routing
Deliverable: When a pending_action requires approval, dispatch an approval.requested event through the existing subscriptions system. The Approval API HTTP+SSE handler in K10 consumes these events. Closes the v0.6.3.1 honest disclosure that approval.subscribers was advertised but never published.
Task K5: rule_summary populated
Branch: feat/v0.7-k-5-rule-summary
Deliverable: Capabilities v3’s rule_summary field gets a real value: ordered list of active governance rules with a one-line summary each. Closes the v0.6.3.1 honest-Capabilities-v2 disclosure that left this field as a placeholder.
Task K6: A2A correlation IDs + ACKs + retry + TTL + replay protection
Branch: feat/v0.7-k-6-a2a-maturity
Deliverable: Every A2A message carries a UUIDv4 correlation ID. Recipients ACK within configurable TTL. Sender retries up to 3× on no-ACK. Recipients track seen correlation IDs in a bounded LRU; duplicates dropped (replay protection).
NHI starter prompt for K6
You are working on alphaonedev/ai-memory-mcp toward v0.7.0 — task K6.
Goal: A2A maturity. Today, federation messages can be lost or replayed
with no detection. Add correlation IDs, ACK semantics, retry, replay
protection.
What to do:
1. src/federation/a2a.rs gets:
- struct A2AMessage { correlation_id: Uuid, sender, recipients,
payload, expires_at }
- struct A2AAck { correlation_id: Uuid, recipient, accepted: bool,
reason: Option<String> }
2. Sender:
- Generate UUIDv4 for each outbound message
- Wait for ACK with configurable TTL (default 30s)
- Retry up to 3× on no-ACK with exponential backoff
3. Receiver:
- Maintain a bounded LRU of seen correlation IDs (size 10_000)
- On duplicate: ACK with accepted=false, reason="duplicate"
- On expired (now > expires_at): drop, log warning
4. Tests:
- 100 messages: all ACK'd
- Replay attack (same UUID 2× from same sender): rejected
- Network partition simulation: retries kick in
- Expired message: dropped, not processed
5. Performance bench: A2A throughput under realistic mesh sizes
(3-node, 5-node, 10-node) — record p50/p95/p99 in PERFORMANCE.md.
Branch: feat/v0.7-k-6-a2a-maturity
Commit: feat(federation): A2A correlation IDs + ACK retry + replay protection (#<filed>)
Definition of done:
- All 4 tests pass
- Replay attacks verifiably rejected
- A2A bench numbers recorded in PERFORMANCE.md
Task K7: Subscription reliability (DLQ, replay-from-cursor, HMAC)
Branch: feat/v0.7-k-7-subscription-reliability
Deliverable: Subscription dispatcher gains:
- 5xx retry with exponential backoff
- Dead-letter queue table (
subscription_dlq) - Replay-from-cursor support (for restart recovery)
- HMAC signing of every dispatched event (was opt-in; now mandatory)
Task K8: Per-agent rate limits and storage caps
Branch: feat/v0.7-k-8-per-agent-quotas
Deliverable: Config table [quotas.per_agent] with rps_limit, storage_mb_cap. Enforced at MCP entry. 429 returned on RPS overage; insert blocked on storage cap.
Task K9: Permission system (rules + modes + hooks → decision; deny-first)
Branch: feat/v0.7-k-9-permission-system
Deliverable: Refactor existing governance system into: rules (declarative policies) + modes (enforce/advisory/off) + hooks (programmable from Track G) → Decision. Default deny-first; ask-by-default for ambiguous cases.
Task K10: Approval API (HTTP + SSE + MCP, HMAC mandatory, remember=forever)
Branch: feat/v0.7-k-10-approval-api
Deliverable: Three surfaces:
- HTTP:
GET /api/v1/approvals/pending+POST /api/v1/approvals/:id/decide - SSE:
GET /api/v1/approvals/stream(server-sent events for live updates) - MCP:
memory_approval_pending,memory_approval_decidetools
remember=forever parameter on decide: subsequent identical requests auto-approve (progressive trust). HMAC signing mandatory — non-optional per ROADMAP §7.3.
Task K11: ai-memory governance migrate-to-permissions CLI
Branch: feat/v0.7-k-11-permissions-migration
Deliverable: One-shot migration tool that converts existing governance rows into the new permissions schema. Idempotent. Dry-run by default; --apply commits.
Track F — Docs + release (consolidated v0.7.0 scope)
Task F1: docs/MIGRATION_v0.7.md
Branch: feat/v0.7-f-1-migration-guide
Deliverable: Comprehensive migration guide for users coming from v0.6.4. Covers:
- Capabilities v3 schema additions
- New tools (
memory_load_family,memory_smart_load,memory_find_paths,memory_replay,memory_approval_*) - Hook pipeline (opt-in; no default change)
- Ed25519 attestation (opt-in via
ai-memory identity generate) - Sidechain transcripts (opt-in per namespace)
- Apache AGE (opt-in via Postgres extension)
- G1 inheritance fix (behavior change — child writes may now require approval where they didn’t before)
- Permissions migration via
ai-memory governance migrate-to-permissions
Task F2: docs/whats-new-v07.html (Pages page)
Task F3: Top-nav + landing-page badges + v0.6.4→v0.7.0 references
Task F4: README + ADMIN_GUIDE updates (substantial — multiple new tracks of features to document)
Task F5: CHANGELOG, version bumps, tag, CI release
Task F6: docs/v0.7/rfc-attested-cortex.md (design RFC)
Deliverable: Design RFC documenting the architectural decisions for v0.7.0:
- Why Ed25519 over X25519 + ChaCha20 (separate concern; X25519 belongs to v0.8 end-to-end encryption per ROADMAP v0.8)
- Why subprocess-stdio + daemon-mode for hooks (vs. dynamic library plugins)
- Why AGE behind a feature flag (vs. hard dependency)
- Why permission system replaces governance instead of augmenting (and the migration story)
Critical-path sequencing
Phase 1 (Weeks 1-3) — Cortex-fluent + cutline
Track A complete (A1→A2→A3→A4→A5)
Track B complete (B4→B1→B3→B2→B5)
Track C complete (C1→C2→C3→C4→C5) — parallel with A/B
Track K cutline: K1 (G1 inheritance) — parallel with A/B
F1 + F6 drafted
Phase 2 (Weeks 3-7) — Hooks + Attestation
Track G complete (G1→G2→G3→G4→G5→G6→G7→G8→G9→G10→G11)
Track H complete (H1→H2→H3→H4→H5→H6) — parallel with G
Track I drafted (I1→I2 in this phase; I3-I5 spillover into Phase 3)
Track K2-K5 (the smaller permissions cleanups) — parallel
Phase 3 (Weeks 7-10) — AGE + Permissions overhaul
Track J complete (J1→J2→J3→J4→J5→J6→J7→J8)
Track K complete (K6→K7→K8→K9→K10→K11)
Track I3-I5 finished
Phase 4 (Weeks 10-11) — Validation + Release
Track D complete (D1-D4)
Track E complete (E1-E3)
F2-F5 finished
ai-memory-test-hub campaigns/v0.7.md — full evidence
ai-memory-discovery-gate runs/v0.7-ship-date/ — T0+ convergence
v0.7.0 release tagged + 5/5 distribution channels published
With one full-time engineer: 11-12 weeks (~3 months). With two engineers in parallel: 7-8 weeks (~2 months). With three engineers + good track decomposition: 5-6 weeks (~6 weeks).
The mandatory cutline for v0.7.0 ship: K1 (G1 inheritance) + Track A + Track B + Track G + Track H + F1+F5. That alone is ~6-8 weeks with one engineer. Tracks I, J, C, D, E can defer to v0.7.1 if scope pressure forces it — the v0.7.0 narrative (attested-cortex) still holds without them.
Definition of release-ready
v0.7.0 ships when all of these are true:
- K1 (G1 inheritance fix) shipped, tested, evidence on test-hub — non-negotiable
- All A1-A5 + B1-B5 + F1-F6 tasks merged
- Track G hook pipeline functional end-to-end (G1-G7 minimum; G8-G11 strongly recommended)
- Track H Ed25519 attestation functional end-to-end (H1-H6 all required)
- Track K permission system functional (K1-K5 minimum; K6-K11 strongly recommended)
- Capabilities v3 default + v2/v1 backward compat preserved
- Hook pipeline does not regress the v0.6.3 50ms recall p95 budget (CI bench gate)
- Schema migration v20 → v22 idempotent + tested against real production-shaped DB
- CI green on main, all required checks passing
- T0 calibration cells (E2) re-run against v0.7.0 binary, ≥95% pass rate across all 4 LLMs
- Cross-harness benchmark (D1) reproduced
- No SDK regression — existing 0.6.4 SDKs still work against v0.7.0 server
- 5/5 distribution channels live (release / brew / ghcr / COPR / crates.io)
- SHA256SUMS published as a release asset
- OIDC SDK publish via
publish-sdks.ymlworkflow
What’s deferred (out of v0.7.0 scope, per agreement)
- R4 (curator CLI surface) → v0.8 Pillar 2.5
- R6 (consensus memory truth-determination) → v0.8 Pillar 3
- R8 (TOON v2 schema inference) → v0.9 or formally cut
- Per-agent profile pre-warm (NHI guardrails phase 2) → v0.7.1 or v0.8
- Hardware-backed key storage (TPM/HSM/Secure Enclave) → AgenticMem commercial layer
- Pool-of-N reranker → v0.9 alongside default-on rerank
- Long-term per-namespace HNSW shard / sqlite-vec migration → v0.9
- End-to-end memory encryption (X25519 + ChaCha20-Poly1305 layer 3 peer-meshed) → v0.8 per existing #228
- API stability guarantee → v1.0
- Security audit → v1.0
Refs
- v0.6.4 release — predecessor (
quiet-tools, shipped 2026-05-05) - v0.6.5 epic (now superseded) — cortex-fluent narrative, rolled into this epic
- ROADMAP.md §7.3 — original v0.7 spec (Q2 2026 target; now consolidating into
attested-cortex) docs/v0.7/compatibility-matrix.html— D2: per-harness × per-feature compat grid (Claude Code, Claude Desktop, Codex, Cursor, Cline, Continue, Aider, Goose, generic JSON-RPC) with status emojis (✅ / ⚠️ / 🚧 / ❌ / N/A) and cross-links to the RFC, migration guide, and Discovery Gatedocs/v0.7/rfc-attested-cortex.md— F6: design RFC (compat-matrix authoritative source)docs/v0.7/canonical-phrasings.md— A1+A2: canonical phrasings for capabilities v3 / loadersdocs/MIGRATION_v0.7.md— F1: operator upgrade guide (v0.6.4 → v0.7.0)- Issues: #545 · #546 · #512
- Discovery Gate: alphaonedev/ai-memory-discovery-gate#1
- v0.6.4 NHI Witness transcripts (Grok 4.2 reasoning before/after): observation cells under Discovery Gate
runs/2026-05-05/
Codename: attested-cortex — the substrate becomes both more articulate and cryptographically trustworthy in one release. The two narratives (legibility from v0.6.5 + trust from ROADMAP’s v0.7) are not incidental siblings; they’re the same story told from two angles. An NHI fleet needs to know what its memory cortex says about itself and that what it says is signed.