Conversation
…tus` Implements the onboarding and health-check surface for the memory swarm system, which will unify multiple memory providers (ByteRover, Obsidian, Honcho, Hindsight, Local .md, GBrain) into a single intelligent memory layer. Phase 1 delivers: - IMemoryProvider interface and shared swarm domain types - Zod config schema with snake_case YAML → camelCase TS mapping - Config loader with env var resolution and tilde expansion - Error accumulation pattern (MemorySwarmValidationError) - Runtime provider validation (paths, credentials, connection strings) - Provider auto-discovery (Obsidian vaults, .md folders, env vars) - Interactive onboarding wizard with ESC back-navigation - Config scaffolder with multi-folder merging and duplicate warnings - `brv swarm onboard` — interactive setup wizard (oclif command) - `brv swarm status` — provider health display with proactive suggestions 94 tests covering all modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ent tool Implement the query pipeline for the memory swarm: query classification, provider selection, parallel DAG execution with enrichment chains, and Reciprocal Rank Fusion result merging. Core engine: - SwarmRouter: regex-based query classification (factual/temporal/personal/relational) - SwarmGraph: topological DAG executor with multi-level enrichment chains and fan-in - SwarmMerger: weighted RRF fusion with content deduplication - SwarmCoordinator: orchestrates route → execute → merge, filters unhealthy providers - ISwarmCoordinator interface with execute(), getActiveProviders(), getSummary() Provider adapters: - ByteRoverAdapter: wraps SearchKnowledgeService (writeSupported: false) - ObsidianAdapter: MiniSearch index + wikilink graph expansion, honors ignorePatterns - LocalMarkdownAdapter: per-folder MiniSearch, honors readOnly/followWikilinks/watchForChanges - Provider factory builds adapters from config with name deduplication CLI + agent integration: - `brv swarm query` command with real SearchKnowledgeService in CLI mode - swarm_query agent tool registered in tool registry - SwarmStateContributor injects provider info into system prompt when >1 provider - service-initializer wires coordinator into ToolProvider (fail-open on missing config, warns on invalid config) 191 unit tests covering all new code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow users to control how providers feed context into each other
via enrichment edges in config.yaml. This wires the existing DAG
execution engine into user-facing config.
Config schema:
- New `enrichment.edges` section with `{from, to}` edge pairs
- Generic endpoints (e.g. `local-markdown`) expand to concrete
provider IDs (`local-markdown:notes`) at both validation and
execution time
Validation (expanded-graph aware):
- Cycle detection via DFS on the expanded edge set
- Self-edge rejection after generic expansion
- Provider existence check with prefix matching
- Folder-scoped typos (`local-markdown:missing`) rejected as errors
- Disabled-provider edges produce warnings only, not topology errors
- Enrichment errors excluded from cloud cascade note
Coordinator wiring:
- Reads config edges, expands generic endpoints, deduplicates,
drops expansion-induced cycles, then passes to SwarmGraph
- Only enrichment topology errors block execution; provider-specific
errors (bad paths, missing API keys) are logged as warnings and
handled by health checks at runtime (degraded-mode preserved)
CLI + onboarding:
- `brv swarm status` displays enrichment topology in text and JSON
- `brv swarm onboard` scaffolder suggests default edges when 2+
providers are enabled (byterover → obsidian, byterover → local-markdown)
- `brv swarm query` validates topology before executing
26 new tests covering schema parsing, edge validation, expansion,
dedup, cycle detection, coordinator wiring, status display, and
scaffolder defaults.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GBrain adapter (Phase 3a): - New GBrainAdapter invokes gbrain CLI via subprocess with JSON output - Binary resolution: explicit path → PATH → repoPath/src/cli.ts → workspace sibling (Bun fallback), with bun availability check in validation - Three search modes: hybrid (vector+keyword+RRF), keyword-only, vector-only - Auto-detection in provider-detector scans common locations for src/cli.ts - Factory wiring creates adapter from config when gbrain.enabled - Onboarding uses constrained select for search_mode (no typo risk) - 15 new tests (adapter, factory, detector, scaffolder) Temporarily disabled: - Honcho + Hindsight removed from provider-detector, router matrix, and status display — adapters not yet implemented, re-enable in Phase 3b - Budget step removed from onboarding wizard — no cloud cost tracking yet - All disabled code marked with "re-enable in Phase 3" comments Router matrix updated: - All query types now route to available providers (byterover, obsidian, local-markdown, gbrain) since honcho/hindsight are disabled - Personal queries no longer restricted to byterover-only Enrichment defaults updated: - Scaffolder generates byterover → gbrain edge when both enabled - Onboarding enrichment explanation lists all downstream providers 237 unit tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use mkdtempSync for healthCheck tests so repoPath existence check passes before the executor is invoked. Add test for nonexistent repo path returning unavailable without calling the executor. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Write routing (Phase 3b):
- New swarm-write-router with classifyWrite() (entity/note/general) and
selectWriteTarget() — regex-based, same pattern as query classification
- SwarmCoordinator.store() routes by explicit --provider, contentType hint,
or auto-classification. Reuses healthCache from execute().
- `brv swarm curate` CLI command with --provider and --format flags
- swarm_store agent tool registered in tool registry
- System prompt shows write guidance when writable providers exist
- `brv swarm status` shows Write Targets section
Sandbox integration (Phase 3c):
- tools.swarmQuery(query, {limit?, scope?}) added to ToolsSDK
- tools.swarmStore({content, contentType?, provider?}) added to ToolsSDK
- swarmStore disabled in query (read-only) mode, swarmQuery allowed
- SandboxService.setSwarmCoordinator() setter with invalidateSandboxes()
- Conditional injection in CODE_EXEC factory (swarmCoordinator stays optional)
- ISandboxService interface extended with optional setSwarmCoordinator
- code_exec.txt tool description updated
Write target routing:
- entity content → GBrain (typed pages)
- note content → local-markdown (writable folder)
- general content → first healthy writable provider (config order)
- ByteRover and Obsidian are never write targets
- Explicit --provider overrides all classification
280 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Low precision in swarm queries (e.g. "project management" matching "session_management") was caused by raw MiniSearch with no filtering in the Local Markdown and Obsidian adapters, and no quality gate in the RRF merger. This ports ByteRover's proven precision patterns to the swarm. Adapter-level (T1/T2/T3): - Stop-word filtering + AND-first search strategy with OR fallback - Absolute score floor (0.3) rejects out-of-domain queries - Gap ratio filter (0.75) trims low-scoring tail results - Second gap-ratio pass (0.6) after wikilink expansion Merger-level (T4/T5): - minRRFScore: absolute RRF floor (configurable via routing config) - rrfGapRatio: relative RRF gap filter (configurable, must be > 0) Also increases GBrain subprocess timeout from 10s to 120s (PGLite WASM cold-start via Node execFile takes ~60s for write operations). 288 tests passing (35 new). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
Claude finished @ngduyanhece's task in 4m 2s —— View job PR Review: Federated Memory Swarm SystemTasks
Overall Assessment: 4/5This is a well-scoped, architecturally sound feature. The outside-in design is correct — Issues fall into three severity buckets: Blocking / High1. Unbounded loop in 2. Synchronous 3. Synchronous Medium / Should Fix4. Stale health cache — 5. 6. 7. Non-null assertion Low / Nit8. Duplicated cycle-detection and 9. Duplicated 10. Duplicated markdown scan/index/wikilink utilities — 11. Enrichment passes raw content as "keywords" — 12. Content-string deduplication in merger — 13. Unimplemented schema sections (budget enforcement, optimization, provenance) — 14. Broad env-var substitution in config loader — 15. Scope Observations (not blocking)
|
- Add default values for minRrfScore (0.005) and rrfGapRatio (0.5) in routing schema so RRF filters are active by default instead of being silently skipped when config omits them - Add term-coverage validation on OR fallback in search-precision: when AND search returns no results, OR fallback now requires matched terms to exceed 50% of query terms, preventing partial-match noise - Replace this.error() with logToStderr + exit(2) in swarm query/curate commands to suppress stack traces in dev mode
- Make curate.ts error handling consistent: replace remaining
this.error() at result.success===false path with logToStderr+exit(2)
- Extract SearchResultWithTerms type alias to eliminate duplicate
`as unknown as {queryTerms}` casts in search-precision.ts
- Add comment explaining why 2-word OR fallback is intentionally
a near-no-op (AND failed exact match, OR may match via prefix/fuzzy)
- Rename misleading merger test and add 200-result scenario that
actually exercises minRRFScore filtering at high ranks
- Add resultCacheTtlMs (default 10s) to performance config schema - Cache check at start of execute() returns instantly on hit - LRU semantics via delete+re-set on cache hit (Map insertion order) - Cache store after successful execution with max 20 entries - Invalidation on store() (content changed) and refreshHealth() (provider availability changed) - TTL 0 disables caching entirely - 11 test cases covering hits, misses, TTL, invalidation, LRU eviction
- Add request.type and request.timeRange to cache key to prevent cross-type and cross-timerange cache collisions - Deep-clone QueryResult items (including metadata) on both cache store and cache hit to prevent nested object mutation - Skip cache store when resultCacheTtlMs=0 to avoid dead writes and unnecessary LRU eviction runs - Mark healthCache and resultCache as readonly (mutated in-place via .set/.delete/.clear, never reassigned)
feat:[ENG-2073] add short-lived result cache in SwarmCoordinator
|
Claude finished @danhdoan's task in 2m 25s —— View job PR Review: Federated Memory Swarm System (4th Review) — 4/5Tasks
What's New Since Last ReviewTwo feature branches merged in (ENG-2073, ENG-2072 finalisation):
No changes to any of the files flagged in the previous three reviews. Blocking / High — All 3 Still Open1. Unbounded while (true) { // ← no upper bound
const candidate = suffix === 0 ? `${baseName}.md` : `${baseName}-${suffix}.md`
if (!existsSync(join(folderPath, candidate))) return candidate
suffix++
}Unchanged across all four reviews. A folder pre-loaded with 2. Blocking // resolveGBrainBin(), called from constructor:
execFileSync('gbrain', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000})
// …
this.executor = executor ?? createDefaultExecutor(resolveGBrainBin(options)) // constructorStill blocks the event loop up to 5 s on every adapter construction. Fix this → 3. Blocking execFileSync('gbrain', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000}) // line 175
execFileSync('bun', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000}) // line 192Two sequential synchronous probes — up to 10 s total — inside an already- Medium / Should Fix — Status Update4. Health cache —
Remaining gap: cache starts all- 5. Unreachable
6. readOnly: z.boolean().optional().default(true), // ← config-parsed folders are read-only by defaultUsers who add a 7. Non-null assertions Violates the project's "avoid 8.
Low / Nit — Carry-over (unchanged)
Summary
The three blocking issues have been flagged in every review cycle and are real bugs that must be fixed before merge. The |
- Change selectWriteTarget() to return null instead of throwing when no writable providers are available - Add optional ICurateService to SwarmCoordinator constructor - Add fallbackToByterover() that routes content to the curation pipeline (snippets) when no external provider can accept the write - Add fallback?: boolean to SwarmStoreResult type - Update CLI curate output to show fallback message - 5 new tests: fallback with/without curateService, fallback on curate failure, no fallback for explicit --provider, normal write without fallback flag
Resolved conflicts in swarm-coordinator.ts: - Constructor: keep both curateService (ENG-2075) and resultCacheTtlMs (ENG-2073) - Private methods: keep fallbackToByterover (ENG-2075) alongside buildCacheKey and evictIfOverSize (ENG-2073)
…teService The fallback now shells out to `brv curate --detach` — same path as the CLI command. This goes through the daemon + LLM agent for proper domain detection, topic routing, and content structuring, instead of manually constructing CurateOperation objects with hardcoded paths. Also addresses PR review comments: - Fix stale @throws JSDoc in selectWriteTarget (now returns null) - Remove fallback: false from no-curateService path (use undefined) - Remove CurateService dependency from coordinator and CLI
- Use --format json for brv curate subprocess, parse logId from JSON instead of capturing human-readable stdout - Extract execBrvCurate as a standalone function, inject via constructor (CurateFallbackFn) so tests can mock without ES module stubbing issues - Add proper unit tests with sinon stubs for both success and failure fallback paths - Fix stale @throws JSDoc in selectWriteTarget (now @returns null)
- Move imports to top of file, place execBrvCurate after (fix lint) - Add error field to BrvCurateResult type, propagate parsed.error into SwarmStoreResult when brv curate returns success: false - Remove export from execBrvCurate (only used internally, tests inject via CurateFallbackFn constructor param) - Handle empty id in CLI output (no trailing "as ") Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use util.promisify(execFile) instead of manual Promise wrapper - Export BrvCurateResult type so CurateFallbackFn is complete for external consumers - Fix stale selectWriteTarget docstring (no longer says callers must pre-filter providers)
feat:[ENG-2075] add ByteRover context tree as write fallback
|
Claude finished @danhdoan's task in 3m 9s —— View job PR Review: Federated Memory Swarm System (5th Review) — 4/5Tasks
What's New Since Last ReviewThe ENG-2075 feature merged since the 4th review:
Blocking / High — All 3 Still Open (5 consecutive reviews)1. Unbounded while (true) { // ← no upper bound; unchanged since review 1
const candidate = suffix === 0 ? `${baseName}.md` : `${baseName}-${suffix}.md`
if (!existsSync(join(folderPath, candidate))) return candidate
suffix++
}2. Blocking // Called from the constructor at line 158:
this.executor = executor ?? createDefaultExecutor(resolveGBrainBin(options))
// Inside resolveGBrainBin:
execFileSync('gbrain', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000})Blocks event loop up to 5 s on every adapter construction. Fix this → 3. Blocking execFileSync('gbrain', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000}) // line 175
execFileSync('bun', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000}) // line 192New Issues from ENG-20759. Large content passed as CLI argument — await execFileAsync('brv', ['curate', '--detach', '--format', 'json', content], ...)
const {stdout} = await execFileAsync('brv', ['curate', '--detach', '--format', 'json', '--stdin'], {
encoding: 'utf8',
input: content,
timeout: 30_000,
})10. const err = error as {message: string; stderr?: string} // ← violates "avoid as Type assertions"
throw new Error(err.stderr?.trim() || err.message) // ← || triggers on empty stringUse if (error instanceof Error) throw new Error((error as NodeJS.ErrnoException).stderr?.trim() ?? error.message)
throw new Error(String(error))11. this.log(JSON.stringify({error: (error as Error).message, success: false}))
this.logToStderr(`Error: ${(error as Error).message}`)Both violate "avoid Medium / Should Fix — Status Update4. Stale health cache — Partially addressed ✅
5. Unreachable
6. Users who add a 7. Non-null assertions Violates the project's "avoid 8.
Low / Nit — Carry-over
Summary
The three original blocking issues have been flagged in every review since the PR opened. Issues #9–#11 are new from the ENG-2075 merge, with #9 being a new blocking issue: |
Adds memory-wiki as the 7th swarm provider, connecting to OpenClaw's Memory Wiki plugin via the `openclaw wiki search/get` CLI subprocess. - Add 'memory-wiki' to PROVIDER_TYPES and createDefaultCapabilities - Add MemoryWikiProviderSchema to config schema (openclaw_path, vault_path, search_corpus) - Create MemoryWikiAdapter implementing IMemoryProvider with injectable executor for testability (same pattern as GBrain) - Wire in provider factory, DEFAULT_WEIGHTS (0.8), selection matrix (all types except personal) - Add [wiki] source label in whiteBright for CLI output - Add memory-wiki to config validator (getEnabledProviderIds, isConfiguredProvider) - Add memory-wiki to swarm status display - Score normalization: BM25 unbounded → [0,1) via score/(1+score) - Read-only provider (wiki is compiled, not directly writable) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical bugs:
- Fix inverted capabilities in createDefaultCapabilities (semanticSearch
false not true, writeSupported true not false, avgLatencyMs 60 not 150)
- Add memory-wiki to LOCAL_PROVIDERS set (was misclassified as cloud)
- Add mkdirSync in store() to handle fresh vaults without concepts/
or entities/ directories
Correctness:
- Add validateMemoryWiki in config validator (checks vault_path exists)
- Fix status count: include memoryWiki in enabledCount, dynamic
denominator instead of hardcoded /4
- Add memory-wiki to write targets display
- Show vault_path instead of hardcoded 'OpenClaw wiki' in status
- Fix RRF weight to 0.9 (was reverted to 0.8 by merge)
Content extraction:
- extractContentSection now checks openclaw:wiki:content markers first
(recognizes pages written by store()), then code blocks, then
frontmatter stripping
Tests:
- Add createDefaultCapabilities('memory-wiki') test
- Add isLocalProvider/isCloudProvider tests for memory-wiki
… adapter - Fix indentation misalignment on private readonly boostFresh field - Replace writeFileSync with async writeFile from fs/promises to avoid blocking the event loop in the async store() method
- Fix indentation: boostFresh field in adapter, errors.push in validator - Remove redundant vaultPath truthy guard in factory (required field) - Fold memory-wiki isLocalProvider/isCloudProvider assertions into existing describe blocks instead of standalone section
feat:[ENG-2080] Integrate Memory Wiki with Swarm memory
|
Claude finished @danhdoan's task in 3m 44s —— View job PR Review: Federated Memory Swarm System (6th Review) — 4/5Tasks
What's New Since Last ReviewENG-2080 merged since the 5th review:
Blocking / High — All 4 Still Open + 1 New1. Unbounded while (true) { // ← no cap after 6 reviews
const candidate = suffix === 0 ? `${baseName}.md` : `${baseName}-${suffix}.md`
if (!existsSync(join(folderPath, candidate))) return candidate
suffix++
}2. Blocking // Inside resolveGBrainBin(), called from constructor at line 158:
execFileSync('gbrain', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000})
this.executor = executor ?? createDefaultExecutor(resolveGBrainBin(options))3. Blocking execFileSync('gbrain', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000}) // line 175
execFileSync('bun', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000}) // line 1924. Large content passed as CLI argument — ;({stdout} = await execFileAsync('brv', ['curate', '--detach', '--format', 'json', content], {
encoding: 'utf8',
timeout: 30_000,
}))
5. New unbounded loop in ENG-2080 introduced the exact same unbounded-loop pattern that has been flagged in // memory-wiki-adapter.ts:210
let suffix = 1
while (existsSync(filePath)) { // ← no upper bound
filename = `${slug}-${suffix}.md`
filePath = join(dirPath, filename)
suffix++
}A wiki vault pre-loaded with Medium / Should Fix — Status Update6. Unreachable ENG-2080 added creative: ['byterover', 'obsidian', 'local-markdown', 'gbrain', 'memory-wiki'], // ← still unreachable
7. readOnly: z.boolean().optional().default(true), // ← config-parsed folders are read-only by defaultUsers who add a 8. Non-null assertions Violates the project's "avoid // memory-wiki-adapter.ts:152 — correct pattern ✅
if (!this.index) {
return []
}
// local-markdown-adapter.ts:190 — still wrong ❌
const precisionResults = searchWithPrecision(this.index!, request.query, {maxResults})
// obsidian-adapter.ts:153 — still wrong ❌
const precisionResults = searchWithPrecision(this.index!, request.query, {maxResults})9.
10. const err = error as {message: string; stderr?: string} // ← violates "avoid as Type assertions"
throw new Error(err.stderr?.trim() || err.message) // ← || triggers on empty string ''11. this.log(JSON.stringify({error: (error as Error).message, success: false}))
this.logToStderr(`Error: ${(error as Error).message}`)Low / Nit — Carry-over
Summary
The |
Blocking (5 fixes): - #1: Bound resolveUniqueFilename loop to MAX_SUFFIX=10000 with timestamp fallback (local-markdown-adapter) - #2: Make GBrain bin resolution lazy — execFileSync no longer runs in constructor, deferred to first executor use - #3: Replace execFileSync with async execFileAsync in config-validator (validateGBrain is now async) - #4: Add MAX_ARG_LENGTH guard (200KB) in execBrvCurate to prevent E2BIG on large content - #5: Bound memory-wiki store() filename loop with same pattern Medium (6 fixes): - #6: Remove unreachable 'creative' from QueryType union and SELECTION_MATRIX - #8: Replace this.index! non-null assertions with explicit null guards in obsidian and local-markdown adapters - #9: Fix byterover writeSupported: true → false in createDefaultCapabilities (matches adapter) - #10: Replace 'as' type assertion with instanceof narrowing in execBrvCurate error handler - #11: Replace 'as Error' assertions with instanceof checks in swarm curate and query CLI commands - Stale JSDoc: remove 'creative' from router comment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ments Prevent YAML title injection by using JSON.stringify instead of raw interpolation. Add clarifying comments for null guard and sync probe.
Fix/swarm memory resolve comment
|
Claude finished @danhdoan's task in 3m 28s —— View job PR Review: Federated Memory Swarm System (7th Review) — 4.5/5Tasks
What's New Since Last ReviewTwo commits landed since the 6th review:
Previously Blocking — All Resolved ✅
Previously Medium — Nearly All Resolved
Remaining Open Issue
// LocalMarkdownFolderSchema line 83:
readOnly: z.boolean().optional().default(true), // ← still defaults to read-onlyThis has been flagged every review. The adapter derives The fix is one character: New Issues from Latest CommitsNew: YAML injection hardened in
Residual: // Comment says "runs lazily on first executor access" — correct.
// But the call is still synchronous when it does run:
execFileSync('gbrain', ['--version'], {encoding: 'utf8', stdio: 'pipe', timeout: 5000})The lazy getter pattern solves the construction-time blocking issue (#2 above). However, Low / Nit — Carry-over (7 reviews)
Summary
One line change separates this PR from merge-ready: |
|
Claude finished @leehpham's task in 2m 10s —— View job PR Review: Federated Memory Swarm System (8th Review) — 4.5/5Tasks
What's New Since Last ReviewOne merge commit landed since the 7th review:
Blocking / High — All Resolved ✅All five previously blocking issues remain fixed:
Still Open: One Medium Issue (8 consecutive reviews)
// LocalMarkdownFolderSchema — swarm-config-schema.ts:83
readOnly: z.boolean().optional().default(true), // ← still defaults to read-onlyThis is unchanged since the first review. The adapter derives The Previously Medium — All Resolved ✅
Low / Nit — Carry-over
Summary
The merge from |
Summary
brv curate,search_knowledgetool) is untouched. Honcho and Hindsight adapters are not implemented (temporarily disabled). GBrain precision filtering is out of scope (handled by its own hybrid search). No changes to TUI rendering, LLM providers, or daemon transport.Type of change
Scope (select all touched areas)
Linked issues
Root cause (bug fixes only, otherwise write
N/A)N/A
Test plan
test/unit/agent/swarm/search-precision.test.ts(18 tests)test/unit/agent/swarm/adapters/byterover-adapter.test.ts(14 tests)test/unit/agent/swarm/adapters/obsidian-adapter.test.ts(17 tests)test/unit/agent/swarm/adapters/local-markdown-adapter.test.ts(19 tests)test/unit/agent/swarm/adapters/gbrain-adapter.test.ts(14 tests)test/unit/agent/swarm/swarm-coordinator.test.ts(12 tests)test/unit/agent/swarm/swarm-graph.test.ts(12 tests)test/unit/agent/swarm/swarm-merger.test.ts(13 tests)test/unit/agent/swarm/swarm-router.test.ts(8 tests)test/unit/agent/swarm/swarm-write-router.test.ts(10 tests)test/unit/agent/swarm/config/swarm-config-schema.test.ts(16 tests)test/unit/agent/swarm/validation/config-validator.test.ts(15 tests)test/unit/agent/swarm/wizard/swarm-wizard.test.ts(13 tests)test/unit/agent/swarm/cli/query-renderer.test.ts(6 tests)test/unit/agent/swarm/tools/swarm-query-tool.test.ts(8 tests)test/unit/agent/swarm/tools/swarm-store-tool.test.ts(7 tests)test/unit/agent/swarm/system-prompt/swarm-state-contributor.test.ts(7 tests)test/unit/agent/sandbox/tools-sdk-swarm.test.ts(8 tests)tools.swarmQuery()/tools.swarmStore()with read-only mode enforcementdocs/release-notes/swarm-memory-uat.md)User-visible changes
brv swarm onboard— Interactive setup wizard with auto-detectionbrv swarm status— Provider health, enrichment topology, write targetsbrv swarm query "<text>"— Federated search (supports--format json,-n)brv swarm curate "<content>"— Write routing (supports--provider,--format json)swarm_query,swarm_store(auto-available when 2+ providers configured)tools.swarmQuery(),tools.swarmStore()incode_exec.brv/swarm/config.yaml(generated by wizard or manual)routing.min_rrf_score,routing.rrf_gap_ratiofor precision tuningEvidence
npx mocha --forbid-only "test/unit/agent/swarm/**/*.test.ts"docs/release-notes/swarm-memory-uat.mdnpm run typecheckChecklist
npm test)npm run lint)npm run typecheck)npm run build)mainRisks and mitigations
execFile(PGLite WASM cold-start)min_rrf_scoreandrrf_gap_ratiocan be tuned via config.