# v3.0 Multi-Agent Memory Implementation Plan

> Status note (2026-03-08): Active roadmap order, blockers, and contributor priority live in the [Engram Feature Roadmap](https://github.com/users/joshuaswarren/projects/1). This file is historical design context and may describe scope that is only partially shipped.

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Add per-agent namespaces with access control, per-namespace QMD collections, and controlled cross-agent sharing via auto-promotion (opt-in) and explicit tools.

**Architecture:** Introduce a `principal` derived from `sessionKey`, map to a default namespace, and enforce read/write policies at the storage + retrieval layers. Use one QMD collection per namespace and merge results across allowed namespaces (default `self + shared`). Keep `workspace/IDENTITY.md` as a single file but write per-namespace sections for learned patterns/reflections.

**Tech Stack:** TypeScript (Node.js), existing file-based storage, QMD CLI, existing `Orchestrator`.

---

## Decisions (Locked)
- Principal resolution: derive from `sessionKey` via configurable mapping rules.
- QMD: one collection per namespace.
- Default recall/search: `self + shared`.
- Transcripts: global-per-install, filtered at recall time.
- Identity patterns: per-namespace sections inside `workspace/IDENTITY.md`.
- Auto-promote to `shared`: enabled by config, categories = `correction`, `decision`, `preference` (conservative defaults).

## Deliverables
- Namespace-aware storage layout:
- `memoryDir/namespaces/<namespace>/...`
- Namespace-aware retrieval:
- Search allowed namespaces; merge/dedupe results.
- Access control enforcement:
- Writes restricted to allowed namespaces; reads restricted in recall/search.
- Tools:
- Extend `memory_search`/`memory_store` with optional `namespace`.
- Add `memory_promote` (copy/move to `shared` with audit note).
- Auto-promotion (opt-in):
- On extraction writes, optionally mirror eligible memories into `shared`.

---

### Task 1: Add Namespace and Policy Types + Config Schema

**Files:**
- Modify: `src/types.ts`
- Modify: `src/config.ts`
- Modify: `openclaw.plugin.json`
- Test: `tests/namespaces-config.test.ts`

**Step 1: Tests (failing)**
- parseConfig defaults:
- `namespacesEnabled=false`
- `principalMappingMode="map"` and empty mappings
- `defaultNamespace="default"`
- `sharedNamespace="shared"`
- `defaultSearchNamespaces=["self","shared"]` (interpreted later)
- `autoPromoteToSharedEnabled=false`
- `autoPromoteCategories=["correction","decision","preference"]` only if enabled

**Step 2: Implement config parsing**
- Add types:
- `PrincipalRule`, `NamespacePolicy`, `NamespaceConfig`
- Add config keys:
- `namespacesEnabled`
- `defaultNamespace`
- `sharedNamespace`
- `principalFromSessionKeyMode` (`map|prefix|regex`)
- `principalFromSessionKeyRules` (ordered rules)
- `namespacePolicies` (read/write principals + includeInRecallByDefault)
- `defaultRecallNamespaces` (default: `["self","shared"]`)
- `autoPromoteToSharedEnabled`
- `autoPromoteToSharedCategories`
- `autoPromoteMinConfidenceTier` (default: `explicit`)

**Step 3: Commit**
```bash
git add src/types.ts src/config.ts openclaw.plugin.json tests/namespaces-config.test.ts
git commit -m "feat: v3.0 namespaces config + policy types"
```

---

### Task 2: Implement Principal Resolution Module

**Files:**
- Create: `src/namespaces/principal.ts`
- Test: `tests/principal.test.ts`

**Behavior**
- Input: `sessionKey`, config mapping mode + rules
- Output: `principal` string and `defaultNamespace` for that principal
- Rules:
- If no rule matches, principal = `default`
- Always sanitize principal/namespace to safe filesystem tokens (lowercase, hyphenate, strip weird chars)

**Commit**
```bash
git add src/namespaces/principal.ts tests/principal.test.ts
git commit -m "feat: v3.0 principal resolution from sessionKey"
```

---

### Task 3: Namespace Path Mapper + StorageManager Refactor (Non-breaking)

**Files:**
- Create: `src/namespaces/paths.ts`
- Modify: `src/storage.ts`
- Test: `tests/namespace-paths.test.ts`

**Approach**
- Add a `NamespacePaths` helper that provides:
- base dir for a namespace (`memoryDir/namespaces/<ns>`)
- category dirs inside namespace
- state dirs inside namespace
- Provide migration helper:
- if `namespacesEnabled` and `namespaces/default` missing but legacy structure exists, treat legacy as `default` until an explicit migration command is run.

**Commit**
```bash
git add src/namespaces/paths.ts src/storage.ts tests/namespace-paths.test.ts
git commit -m "feat: v3.0 namespace-aware storage paths"
```

---

### Task 4: QMD Router (One Collection Per Namespace)

**Files:**
- Create: `src/namespaces/qmd-router.ts`
- Modify: `src/qmd.ts`
- Modify: `src/orchestrator.ts`
- Test: `tests/qmd-router.test.ts` (unit-level; mock command invocations if needed)

**Approach**
- Keep existing `QmdClient` for single-collection behavior.
- Add `QmdRouter` that:
- returns a `QmdClient` for namespace collection name
- merges results from multiple namespaces
- de-dupes by canonical memory ID (prefer higher score)

**Commit**
```bash
git add src/namespaces/qmd-router.ts src/qmd.ts src/orchestrator.ts tests/qmd-router.test.ts
git commit -m "feat: v3.0 qmd router per namespace"
```

---

### Task 5: Access Control Enforcement (Read + Write)

**Files:**
- Create: `src/namespaces/policy.ts`
- Modify: `src/orchestrator.ts`
- Modify: `src/tools.ts`
- Test: `tests/policy.test.ts`

**Write enforcement**
- When writing a memory, require principal has write access to target namespace.
- Default target namespace = principal’s namespace.

**Read enforcement**
- In recall/search:
- Determine allowed namespaces = principal namespace + shared (default), intersected with read permissions.
- Search only allowed namespaces.

**Commit**
```bash
git add src/namespaces/policy.ts src/orchestrator.ts src/tools.ts tests/policy.test.ts
git commit -m "feat: v3.0 namespace access control"
```

---

### Task 6: Tooling Updates (Namespace-Aware)

**Files:**
- Modify: `src/tools.ts`
- Test: `tests/tools-namespace.test.ts` (unit)

**Changes**
- `memory_search`: add optional `namespace` (default: principal namespace) and optional `includeShared` (default true).
- `memory_store`: add optional `namespace` (default: principal namespace).
- Add `memory_promote`:
- params: `memoryId`, `fromNamespace?`, `toNamespace` (default `shared`), `mode: copy|move`, `note?`
- enforce policy: caller must have read access to from and write access to to.

**Commit**
```bash
git add src/tools.ts tests/tools-namespace.test.ts
git commit -m "feat: v3.0 namespace-aware tools + promote"
```

---

### Task 7: Auto-Promote To Shared (Opt-In, Conservative)

**Files:**
- Modify: `src/orchestrator.ts`
- Modify: `src/storage.ts`
- Test: `tests/auto-promote.test.ts`

**Behavior**
- If `autoPromoteToSharedEnabled=false`: do nothing.
- If enabled:
- For each extracted fact in categories allowlisted (`correction`, `decision`, `preference`):
- Require confidenceTier >= configured minimum (default `explicit`)
- Mirror a copy into `shared` namespace:
- Add tag `shared` and `promoted:auto`
- Add frontmatter `source: "auto-promote"` or `lineage` to original id
- Never promote transcripts/moments, and never promote raw message content.
- Must be idempotent:
- If shared copy already exists for same lineage/content hash, skip.

**Commit**
```bash
git add src/orchestrator.ts src/storage.ts tests/auto-promote.test.ts
git commit -m "feat: v3.0 auto-promote eligible memories to shared (opt-in)"
```

---

### Task 8: Identity Patterns Per Namespace Sections in `workspace/IDENTITY.md`

**Files:**
- Modify: `src/storage.ts`
- Modify: `src/orchestrator.ts`
- Test: `tests/identity-namespaces.test.ts`

**Goal**
- Keep one `IDENTITY.md`, but avoid blending:
- Create sections like:
- `## Learned Patterns (namespace: <ns>)`
- `## Reflection (namespace: <ns>) — <timestamp>`
- Append reflections into the namespace section, not just EOF.
- Consolidation should run per namespace section.

**Commit**
```bash
git add src/storage.ts src/orchestrator.ts tests/identity-namespaces.test.ts
git commit -m "feat: v3.0 identity patterns split by namespace"
```

---

### Task 9: Namespace Migration + CLI Support

**Files:**
- Modify: `src/cli.ts`
- Create: `src/namespaces/migrate.ts`
- Test: `tests/namespace-migrate.test.ts`

**CLI**
- `openclaw engram namespaces ls`
- `openclaw engram namespaces migrate --to <ns> [--dry-run]`
- Behavior: move legacy layout into `namespaces/default` (or `--to`) and rebuild QMD for that namespace collection.

**Commit**
```bash
git add src/cli.ts src/namespaces/migrate.ts tests/namespace-migrate.test.ts
git commit -m "feat: v3.0 namespaces cli + migration"
```

---

### Task 10: Docs + Full Verification

**Files:**
- Modify: `README.md`
- Create: `docs/namespaces.md`

**Step 1: Docs**
- In `docs/namespaces.md`, document:
- The concepts: principal, namespace, policy
- Principal derivation from `sessionKey` (with examples)
- Default search behavior: `self + shared`
- How transcripts are global but recall is filtered
- How auto-promote works and its conservative defaults
- Migration command(s)

**Step 2: README quickstart**
- Add a short “Namespaces” section:
- how to enable
- how to configure policies
- how to promote a memory

**Step 3: Verification**
Run:
```bash
npm test
npm run check-types
npm run build
```
Expected: PASS.

**Step 4: Manual smoke test (no gateway required)**
- Create two fake `sessionKey`s that map to different principals.
- Ensure reads/writes enforce the policy rules.
- Ensure QMD router merges results across allowed namespaces and dedupes correctly.

**Step 5: Commit**
```bash
git add README.md docs/namespaces.md
git commit -m "docs: v3.0 namespaces and policies"
```

**Files:**
- Modify: `README.md`
- Create: `docs/namespaces.md`
- Modify: `docs/import-export.md` (v2.3) to include `--namespace` semantics once v3.0 exists

**Verification**
```bash
npm test
npm run check-types
npm run build
```

**Commit**
```bash
git add README.md docs/namespaces.md docs/import-export.md
git commit -m "docs: v3.0 namespaces + access control"
```
