Skip to content

feat:[ENG-2080] Integrate Memory Wiki with Swarm memory#405

Merged
danhdoan merged 5 commits intoproj/swarm-memoryfrom
feat/ENG-2080
Apr 14, 2026
Merged

feat:[ENG-2080] Integrate Memory Wiki with Swarm memory#405
danhdoan merged 5 commits intoproj/swarm-memoryfrom
feat/ENG-2080

Conversation

@cuongdo-byterover
Copy link
Copy Markdown
Collaborator

Summary

  • Problem: The Memory Swarm had no connection to OpenClaw's Memory Wiki — a compiled wiki with structured pages, claims, provenance tracking, and dashboards. Wiki content was invisible to brv swarm query.
  • Why it matters: Memory Wiki contains curated, compiled knowledge that is higher quality than raw notes. Teams using both ByteRover and OpenClaw had to manually search each system separately.
  • What changed: Added memory-wiki as the 7th swarm provider. The adapter reads directly from the wiki vault on disk (no subprocess), uses MiniSearch for fast in-process search (~12ms for 118 pages), supports writes to entities/ and concepts/ directories with proper OpenClaw frontmatter, and applies freshness + kind boosts for structured ranking.
  • What did NOT change (scope boundary): No changes to the OpenClaw wiki plugin itself. No bridge mode changes. No subprocess dependency — the adapter reads files directly. No changes to existing providers or the query pipeline. The adapter follows the same pattern as Obsidian and Local Markdown adapters.

Type of change

  • Bug fix
  • New feature
  • Refactor (no behavior change)
  • Documentation
  • Test
  • Chore (build, dependencies, CI)

Scope (select all touched areas)

  • TUI / REPL
  • Agent / Tools
  • LLM Providers
  • Server / Daemon
  • Shared (constants, types, transport events)
  • CLI Commands (oclif)
  • Hub / Connectors
  • Cloud Sync
  • CI/CD / Infra

Linked issues

  • Closes ENG-2080

Root cause (bug fixes only, otherwise write N/A)

N/A

Test plan

  • Coverage added:
    • Unit test
    • Integration test
    • Manual verification only
  • Test file(s):
    • test/unit/agent/core/domain/swarm/types.test.ts (updated: 7 providers)
  • Key scenario(s) covered:
    • Query: 15 diverse queries across 118 wiki pages — 14/15 rank wiki Feat/init #1 (93% precision)
    • Performance: 12ms average per query with 118 pages (in-process MiniSearch)
    • Write: Concept pages written to concepts/ with correct frontmatter, immediately queryable
    • Write routing: Entity → GBrain, note → local-md, general → GBrain, fallback → memory-wiki
    • Cross-provider: 5 providers return results together, wiki ranks highest (weight 0.9)
    • Status: Memory Wiki shows in brv swarm status
    • Enrichment: ByteRover → memory-wiki enrichment visible in --explain

User-visible changes

  • New provider: memory_wiki in .brv/swarm/config.yaml
    memory_wiki:
      enabled: true
      vault_path: ~/.openclaw/wiki/main
      # write_page_type: concept    # default: concept (entity|concept)
      # boost_fresh: true           # default: true
  • Query results show [wiki] source label in whiteBright
  • brv swarm status displays Memory Wiki health
  • brv swarm curate can write to wiki vault (concept/entity pages with OpenClaw frontmatter)
  • RRF weight 0.9 — wiki results rank second only to ByteRover (1.0)
  • Provider excluded from personal queries (wiki content is factual, not personal)

Evidence

  • Trace/log snippets

Status:

✓ ByteRover       context-tree (always on)
✓ Obsidian        /Users/cuong/Documents/MyObsidian
✓ Local .md       1 folder(s)
✓ GBrain          /Users/cuong/workspaces/gbrain
✓ Memory Wiki     OpenClaw wiki

Query with explain (118 pages, 5 providers):

Provider selection: 5 of 5 available
  ✓ byterover    (healthy, selected, 0 results, 14ms)
  ✓ obsidian    (healthy, selected, 5 results, 91ms)
  ✓ local-markdown:project-docs    (healthy, selected, 1 results, 18ms)
  ✓ memory-wiki    (healthy, selected, 2 results, 15ms)
  ✓ gbrain    (healthy, selected, 1 results, 260ms)

Write to wiki:

$ brv swarm curate "Our notification system uses AWS SNS..."
Stored to memory-wiki as concept.swarm.our_notification_system_uses_aws_sns_for_push_notifications

$ cat ~/.openclaw/wiki/main/concepts/our_notification_system_...md
---
pageType: concept
id: concept.swarm.our_notification_system...
status: active
sourceType: swarm-curate
---

Performance (15 queries, 118 pages):

JWT refresh        → wiki: 2 results (15ms) | #1=[wiki]
rate limiting      → wiki: 5 results (15ms) | #1=[wiki]
Kubernetes         → wiki: 3 results (13ms) | #1=[wiki]
chaos testing      → wiki: 1 results (9ms)  | #1=[wiki]
CQRS               → wiki: 4 results (8ms)  | #1=[wiki]

Checklist

  • Tests added or updated and passing (npm test) — 5891 passing
  • Lint passes (npm run lint) — pre-commit hook verified
  • Type check passes (npm run typecheck)
  • Build succeeds (npm run build)
  • Commits follow Conventional Commits format
  • Documentation updated (if applicable)
  • No breaking changes (or clearly documented above)
  • Branch is up to date with main

Risks and mitigations

  • Risk: Direct file system access to wiki vault — concurrent writes from OpenClaw and ByteRover could conflict.

    • Mitigation: ByteRover writes to concepts/ and entities/ with a swarm. prefix in the page ID. OpenClaw wiki operations target different page types (sources, syntheses). The .openclaw-wiki/locks/ directory exists for OpenClaw's internal locking — ByteRover does not acquire locks (acceptable for low-frequency writes).
  • Risk: MiniSearch index not invalidated when OpenClaw updates wiki pages externally.

    • Mitigation: Index signature is based on agent-digest.json mtime. When OpenClaw runs wiki compile, the digest is updated, which invalidates the MiniSearch cache on next query.
  • Risk: extractContentSection() may not correctly strip all OpenClaw page templates.

    • Mitigation: Two extraction strategies: (1) look for ```text\n...\n``` code block (standard wiki source page format), (2) fallback to stripping YAML frontmatter. Tested with both imported source pages and manually curated concept pages.

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>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Claude finished @cuongdo-byterover's task in 2m 45s —— View job


PR Review: feat:[ENG-2080] Integrate Memory Wiki with Swarm memory

  • Gather context and understand PR scope
  • Review memory-wiki-adapter.ts (main new file)
  • Review type definitions and config schema changes
  • Review coordinator, router, factory, and validator changes
  • Review CLI/status command changes
  • Review test coverage
  • Compile findings and post final review

Overall Assessment: 3/5

The adapter architecture is well-structured and consistent with the existing Obsidian/Local Markdown adapter pattern. The MiniSearch integration, digest-based cache invalidation, and freshness/kind boosting are solid. However, there are several correctness bugs and integration gaps that need to be addressed.


Bugs

bug (critical): createDefaultCapabilities('memory-wiki') contradicts the adapter's own capability declaration

src/agent/core/domain/swarm/types.ts lines 249–261:

case 'memory-wiki': {
  return {
    // ...
    semanticSearch: true,   // ← WRONG: adapter declares false
    writeSupported: false,  // ← WRONG: adapter declares true and implements store()
  }
}

The adapter at src/agent/infra/swarm/adapters/memory-wiki-adapter.ts lines 95–105 declares:

public readonly capabilities: ProviderCapabilities = {
  semanticSearch: false,
  writeSupported: true,
  // ...
}

Both fields are inverted in the static defaults function. Any code path that reads defaults before constructing an adapter instance (e.g. onboarding, cost estimators) gets wrong data. Fix this →


bug: memory-wiki missing from LOCAL_PROVIDERS — classified as cloud provider

src/agent/core/domain/swarm/types.ts line 27:

const LOCAL_PROVIDERS: ReadonlySet<ProviderType> = new Set(['byterover', 'local-markdown', 'obsidian'])

The adapter correctly declares localOnly: true (no network calls, reads files directly), but isLocalProvider('memory-wiki') returns false and isCloudProvider('memory-wiki') returns true. Any routing logic that uses these helpers to make local-vs-cloud decisions will misclassify memory-wiki. Fix this →


bug: store() will throw ENOENT on a fresh wiki vault

src/agent/infra/swarm/adapters/memory-wiki-adapter.ts lines 195–228: the method constructs dirPath = join(this.vaultPath, dir) and calls writeFileSync(filePath, pageContent) without ever ensuring the parent directory exists. A vault that has never had a concepts/ or entities/ subdirectory (or one where ByteRover is writing for the first time) will throw ENOENT. Fix this →


Correctness Issues

issue: Missing vault-path validation in validateSwarmProviders

Every other path-based provider has a dedicated validator called from validateSwarmProviders (Obsidian → validateObsidian, local-markdown → validateLocalMarkdown, GBrain → validateGBrain). Memory Wiki has a vault_path but nothing validates it at config time — errors only surface at runtime via healthCheck(). The status.ts code checks for e.provider === 'memory-wiki' errors, but none will ever be generated until first query.

Add a validateMemoryWiki call in src/agent/infra/swarm/validation/config-validator.ts after line 443 to check that vault_path exists. Fix this →


issue: renderSwarmSummary count is stale — doesn't include memory-wiki

src/oclif/commands/swarm/status.ts lines 264–278:

const enabledCount = [
  providers.byterover.enabled,
  providers.obsidian?.enabled,
  providers.localMarkdown?.enabled,
  // Honcho and Hindsight temporarily disabled
  providers.gbrain?.enabled,
].filter(Boolean).length
// ...
this.log(`\nSwarm is ${status} (${enabledCount}/4 providers configured).`)

memoryWiki is not counted, so enabling it doesn't change the displayed number. The denominator 4 is also stale — it was correct before this PR but is now misleading. Fix this →


issue: renderWriteTargets doesn't show memory-wiki

src/oclif/commands/swarm/status.ts lines 328–347: the method only lists gbrain and local-markdown write targets. Since memory-wiki supports writes, it should appear here too (e.g. memory-wiki (concept, entity)).


Nitpicks

nitpick: Indentation misalignment on line 108

src/agent/infra/swarm/adapters/memory-wiki-adapter.ts line 108:

private readonly boostFresh: boolean   // ← missing 2-space indent
  private readonly vaultPath: string   // ← correctly indented

nitpick: extractContentSection doesn't recognize its own output format

The store() method writes content wrapped in / markers. But extractContentSection only checks for ```text\n...\n``` code blocks, then falls back to stripping frontmatter. Pages curated by ByteRover itself will hit the fallback and return the full body including `` noise. Consider checking for those markers first.


nitpick: RRF weight in docs (0.9) doesn't match code (0.8)

PR description says "RRF weight 0.9 — wiki results rank second only to ByteRover (1.0)", but DEFAULT_WEIGHTS in swarm-coordinator.ts sets 'memory-wiki': 0.8, same as local-markdown and hindsight. The discrepancy should be resolved — either update the comment or change the weight.


nitpick: store() is async but uses writeFileSync

The store() method is declared async and is on the hot path for curate operations. writeFileSync blocks the event loop. Prefer writeFile from node:fs/promises.


Test Coverage Gap

suggestion: createDefaultCapabilities('memory-wiki') and isLocalProvider('memory-wiki') are not tested

Both have bugs (see above) that would have been caught if the existing test suite in test/unit/agent/core/domain/swarm/types.test.ts had covered them. There's test coverage for byterover, obsidian, honcho, hindsight, gbrain, and local-markdown in createDefaultCapabilities, but no case for memory-wiki. Similarly, isLocalProvider/isCloudProvider tests don't include memory-wiki.


@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Claude finished @cuongdo-byterover's task in 2m 54s —— View job


PR Review: feat:[ENG-2080] Integrate Memory Wiki with Swarm memory

  • Gather context and understand PR scope
  • Read memory-wiki-adapter.ts (main new file)
  • Read type definitions, config schema, coordinator, router, factory, validator
  • Read CLI status command changes and test file
  • Compile findings and post final review

Overall Assessment: 2/5

The adapter architecture is clean and follows the Obsidian/LocalMarkdown pattern well. MiniSearch integration, digest-based cache invalidation, and the freshness/kind boost scoring model are all solid. However, there are 3 confirmed correctness bugs that will cause wrong routing decisions or runtime failures, plus several display/count issues and test coverage gaps. These need to be resolved before merge.


Bugs (Critical)

bug (critical): createDefaultCapabilities('memory-wiki') — two capability fields are inverted

src/agent/core/domain/swarm/types.ts lines 256–259:

case 'memory-wiki': {
  semanticSearch: true,   // ← WRONG: adapter declares false
  writeSupported: false,  // ← WRONG: adapter declares true
}

The adapter (memory-wiki-adapter.ts lines 101–104) declares the opposite:

semanticSearch: false,
writeSupported: true,

Any onboarding, cost estimator, or routing path that reads these defaults before constructing an adapter will get inverted data — potentially excluding memory-wiki from write routing or treating it as a semantic-search provider it is not. Fix this →


bug: memory-wiki missing from LOCAL_PROVIDERS — misclassified as cloud provider

src/agent/core/domain/swarm/types.ts line 27:

const LOCAL_PROVIDERS: ReadonlySet<ProviderType> = new Set(['byterover', 'local-markdown', 'obsidian'])

The adapter declares localOnly: true (no network calls, reads disk directly), yet isLocalProvider('memory-wiki') returns false and isCloudProvider('memory-wiki') returns true. Any routing logic keying on these helpers will misclassify it. Fix this →


bug: store() will throw ENOENT on a fresh wiki vault

src/agent/infra/swarm/adapters/memory-wiki-adapter.ts lines 194–228:

const dirPath = join(this.vaultPath, dir)
// ... filename resolution loop ...
writeFileSync(filePath, pageContent)  // ← ENOENT if dir doesn't exist

mkdirSync is never called. A vault that has never had a concepts/ or entities/ directory (or a user's first brv swarm curate) will crash with ENOENT. Fix this →


Correctness Issues

issue: Missing validateMemoryWiki in validateSwarmProviders

src/agent/infra/swarm/validation/config-validator.ts lines 417–459: every other path-based provider (obsidian, local-markdown, gbrain) has a dedicated validator called from validateSwarmProviders. Memory Wiki has a vault_path but nothing checks it at config time — errors surface at runtime via healthCheck() only after the first query. Add a validateMemoryWiki call (checking existsSync(config.vaultPath)) alongside validateGBrain. Fix this →


issue: renderSwarmSummary count is stale

src/oclif/commands/swarm/status.ts lines 265–278:

const enabledCount = [
  providers.byterover.enabled,
  providers.obsidian?.enabled,
  providers.localMarkdown?.enabled,
  providers.gbrain?.enabled,
].filter(Boolean).length
// ...
this.log(`\nSwarm is ${status} (${enabledCount}/4 providers configured).`)

memoryWiki is not counted and the denominator is hardcoded as 4. Enabling memory-wiki has no effect on the displayed number. Fix this →


issue: renderWriteTargets doesn't list memory-wiki

src/oclif/commands/swarm/status.ts lines 324–348: only gbrain and local-markdown are listed as write targets. Since memory-wiki supports writes (writeSupported: true), it should appear here as well. Fix this →


Test Coverage Gaps

suggestion: createDefaultCapabilities('memory-wiki') and isLocalProvider('memory-wiki') are untested

test/unit/agent/core/domain/swarm/types.test.ts covers createDefaultCapabilities for all six existing providers but has no case for memory-wiki. The two inverted-boolean bugs above would have been caught immediately if this existed. Similarly, the isLocalProvider/isCloudProvider tests only cover the six original providers — memory-wiki is not tested for either helper. Fix this →


Nitpicks

nitpick: Indentation misalignment at line 108

src/agent/infra/swarm/adapters/memory-wiki-adapter.ts line 108:

private readonly boostFresh: boolean   // ← missing 2-space indent vs. sibling fields
  private readonly vaultPath: string

nitpick: extractContentSection doesn't recognize its own output format

store() wraps content in / markers, but extractContentSection only checks for ```text\n...\n``` code blocks, then falls back to frontmatter-stripping. Pages written by ByteRover itself will include the HTML comment markers as noise in query results. Consider checking for `` first.


nitpick: RRF weight in PR description (0.9) doesn't match code (0.8)

src/agent/infra/swarm/swarm-coordinator.ts line 55:

'memory-wiki': 0.8,   // PR description says 0.9

Resolve the discrepancy — either update the description or change the weight.


nitpick: store() is async but uses writeFileSync

src/agent/infra/swarm/adapters/memory-wiki-adapter.ts line 228: writeFileSync blocks the event loop on a method declared async. Prefer writeFile from node:fs/promises for consistency with the rest of the async codebase.


nitpick: avgLatencyMs mismatch between adapter and defaults

The adapter declares avgLatencyMs: 60 (line 98) but createDefaultCapabilities returns avgLatencyMs: 150 (line 252). Same-PR, same type — they should match.


nitpick: renderProviderStatusLines shows hardcoded 'OpenClaw wiki' instead of vault path

src/oclif/commands/swarm/status.ts line 245:

this.renderProviderLine('Memory Wiki', providers.memoryWiki.enabled && !hasError, 'OpenClaw wiki')

GBrain and Obsidian both display their configured path. Memory Wiki should show providers.memoryWiki.vaultPath for consistency and debuggability.


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
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Claude finished @cuongdo-byterover's task in 1m 31s —— View job


PR Review: feat:[ENG-2080] Integrate Memory Wiki with Swarm memory

  • Gather context and understand PR scope
  • Read changed files (types.ts, memory-wiki-adapter.ts, config-validator.ts, status.ts, swarm-coordinator.ts, swarm-router.ts, config schema, test file)
  • Check if previous review issues were addressed
  • Compile findings and post final review

Overall Assessment: 4/5

All three critical bugs from the previous reviews have been resolved, and most nitpicks were addressed. The adapter is now well-integrated: capabilities are correct, memory-wiki is classified as a local provider, vault directory creation works on first write, the status command shows the configured vault path, write targets are listed, and RRF weight is consistently 0.9. Two minor issues remain.


Remaining Issues

nitpick: store() is async but uses writeFileSync

src/agent/infra/swarm/adapters/memory-wiki-adapter.ts line 235:

writeFileSync(filePath, pageContent)

The method is declared async and lives on the curate hot path. writeFileSync blocks the event loop during file I/O. Prefer writeFile from node:fs/promises:

import {writeFile, mkdirSync, ...} from 'node:fs'
import {writeFile} from 'node:fs/promises'
// ...
await writeFile(filePath, pageContent, 'utf8')

Fix this →


nitpick: Indentation misalignment — two places

  1. src/agent/infra/swarm/adapters/memory-wiki-adapter.ts line 114:
  public readonly type = 'memory-wiki' as const
private readonly boostFresh: boolean   // ← missing 2-space indent
  private readonly vaultPath: string
  1. src/agent/infra/swarm/validation/config-validator.ts lines 447–452:
if (providers.memoryWiki?.enabled && !existsSync(providers.memoryWiki.vaultPath)) {
      errors.push({   // ← 6-space indent; sibling validators use 4-space
        ...
      })
    }

Both are cosmetic but inconsistent with the surrounding code style.


Fixed Since Last Review ✓

Issue Status
createDefaultCapabilitiessemanticSearch/writeSupported inverted Fixed (lines 249–261)
LOCAL_PROVIDERS missing memory-wiki Fixed (line 27)
store() ENOENT on fresh vault (mkdirSync missing) Fixed (line 202)
extractContentSection didn't recognize its own marker format Fixed (lines 83–87)
renderSwarmSummary stale count / hardcoded /4 denominator Fixed — now dynamic
renderWriteTargets omitted memory-wiki Fixed (lines 351–353)
renderProviderStatusLines showed hardcoded 'OpenClaw wiki' Fixed — now shows vaultPath
avgLatencyMs mismatch (adapter: 60ms, defaults: 150ms) Fixed — both 60ms
RRF weight discrepancy (PR description 0.9 vs code 0.8) Fixed — code is now 0.9
Test: createDefaultCapabilities('memory-wiki') not covered Fixed (lines 118–126)
Test: isLocalProvider/isCloudProvider for memory-wiki untested Fixed (lines 129–137)

Minor Observation — Test Structure

The new isLocalProvider / isCloudProvider assertions for memory-wiki live in a separate top-level describe('isLocalProvider - memory-wiki') block rather than being folded into the existing describe('isLocalProvider') and describe('isCloudProvider') blocks. This is functional but slightly inconsistent with the test file's established structure. Worth consolidating in a follow-up if you care about uniformity.

… 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
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Claude finished @cuongdo-byterover's task in 2m 2s —— View job


PR Review: feat:[ENG-2080] Integrate Memory Wiki with Swarm memory

  • Gather context and understand PR scope
  • Read changed files (memory-wiki-adapter.ts, types.ts, config-validator.ts, status.ts, coordinator, test file)
  • Check if remaining nitpicks from last review were addressed
  • Review for any new issues
  • Compile findings and post final review

Overall Assessment: 4.5/5

Good progress — the one blocking nitpick from the previous review (writeFileSync on an async method) has been fixed. Two cosmetic indentation issues remain. The adapter is otherwise correct and well-integrated.


Fixed Since Last Review ✓

Issue Status
store() used writeFileSync on an async method Fixed — now await writeFile from node:fs/promises (line 236)

Remaining Nitpicks

nitpick: Indentation misalignment — memory-wiki-adapter.ts line 115

  public readonly type = 'memory-wiki' as const
private readonly boostFresh: boolean   // ← missing 2-space indent
  private readonly vaultPath: string   // ← correctly indented

boostFresh is the only field missing its 2-space indent. Fix this →


nitpick: Indentation misalignment — config-validator.ts lines 447–452

  if (providers.memoryWiki?.enabled && !existsSync(providers.memoryWiki.vaultPath)) {
-      errors.push({         // ← 6-space; sibling validators use 4-space
-        field: '...',
-        message: '...',
-        provider: 'memory-wiki',
-      })
-    }                       // ← 4-space; should be 2-space
+    errors.push({
+      field: '...',
+      message: '...',
+      provider: 'memory-wiki',
+    })
+  }

The errors.push(...) body is indented 2 extra spaces relative to the enclosing if, and the closing } is 2 spaces deeper than its sibling if closings. Fix this →


Minor Observation (Non-blocking)

isLocalProvider / isCloudProvider tests for memory-wiki in a separate top-level describe

test/unit/agent/core/domain/swarm/types.test.ts lines 129–137: the new assertions live in a standalone describe('isLocalProvider - memory-wiki') block rather than being folded into the existing describe('isLocalProvider') (lines 30–56) and describe('isCloudProvider') (lines 44–56) blocks. Functionally correct; a minor structural inconsistency worth cleaning up.

provider-factory.ts line 84: redundant truthy guard on required field

if (config.providers.memoryWiki?.enabled && config.providers.memoryWiki.vaultPath) {

vaultPath is a required, non-optional z.string() in MemoryWikiProviderSchema — it can never be absent once the object is present. The && config.providers.memoryWiki.vaultPath check is dead code. All sibling providers (obsidian, gbrain) only check ?.enabled. Harmless but inconsistent.

query-renderer.ts: label renders as [memory-wiki], PR description says [wiki]

providerTypeToLabel returns 'memory-wiki' (line 27), which wraps to [memory-wiki]. The PR description says "Query results show [wiki] source label in whiteBright." Either the description is stale or the label should be 'wiki'. Cosmetic but worth aligning.


- 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
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 14, 2026

Claude finished @cuongdo-byterover's task in 2m 3s —— View job


PR Review: feat:[ENG-2080] Integrate Memory Wiki with Swarm memory

  • Gather context and understand PR scope
  • Read changed files (adapter, types, config-validator, status, coordinator, router, factory, test)
  • Check if previous review nitpicks were addressed
  • Review for any new issues or gaps
  • Compile findings and post final review

Overall Assessment: 5/5

All previous review issues have been resolved. The adapter is correct, complete, and well-integrated. Two minor nitpicks remain — one is cosmetically wrong in a specific edge case, the other is a docs-vs-code inconsistency.


Fixed Since Last Review ✓

Issue Status
Indentation misalignment — memory-wiki-adapter.ts boostFresh field Fixed (line 115 — 2-space indent correct)
Indentation misalignment — config-validator.ts memoryWiki block Fixed (lines 446–452 — 4-space block body, 2-space close)
isLocalProvider/isCloudProvider memory-wiki tests in a separate top-level describe Fixed — folded into existing describe('isLocalProvider') (line 35) and describe('isCloudProvider') (line 57) blocks
Redundant && config.providers.memoryWiki.vaultPath guard in provider-factory.ts Fixed — factory now only checks ?.enabled (line 84)

Remaining Nitpicks

nitpick: renderWriteTargets — produces memory-wiki (entity, entity) when writePageType is 'entity'

src/oclif/commands/swarm/status.ts line 352:

targets.push(`memory-wiki (${providers.memoryWiki.writePageType ?? 'concept'}, entity)`)

When the user has set write_page_type: entity in config, this renders as memory-wiki (entity, entity), which is redundant and misleading. The suffix entity appears to be hardcoded from the suggestion to list "both types", but the adapter only writes to one configured type at a time. Either use a static label or show only the configured type:

// Option A — show both possible page types (static, always accurate):
targets.push('memory-wiki (concept, entity)')
// Option B — show only the configured type:
targets.push(`memory-wiki (${providers.memoryWiki.writePageType ?? 'concept'})`)

Fix this →


nitpick: providerTypeToLabel returns 'memory-wiki' but PR description says [wiki]

src/agent/infra/swarm/cli/query-renderer.ts line 27:

case 'memory-wiki': { return 'memory-wiki' }

Renders as [memory-wiki] in query output. The PR description says "Query results show [wiki] source label in whiteBright." Either the PR description is stale or the label should be 'wiki'. If wiki was the intended UX (shorter, consistent with notes:name for local-markdown), update the label: Fix this →


Minor Observations (Non-blocking)

validateMemoryWiki is inlined rather than a dedicated function

src/agent/infra/swarm/validation/config-validator.ts lines 446–452: every other path-based provider has its own validateObsidian / validateLocalMarkdown / validateGBrain function. Memory Wiki validation is inlined as 6 lines in validateSwarmProviders. Functionally correct, but inconsistent with the pattern. Also, validateObsidian includes a suggestion field in its error push; the inlined memory-wiki block does not. Both are cosmetic — worth cleaning up in a follow-up.

validateMemoryWiki checks only path existence, not vault structure

validateObsidian additionally checks for .obsidian/ to confirm it's actually an Obsidian vault. Memory Wiki has its own marker (.openclaw-wiki/), but the validator doesn't check for it — a non-wiki directory would pass validation and only fail at query time (when the digest is missing and loadDigest() returns null, resulting in empty results rather than a clear error). Acceptable for now given the healthCheck() backstop, but a follow-up could add this check.


Copy link
Copy Markdown
Collaborator

@danhdoan danhdoan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm

@danhdoan danhdoan merged commit d45941d into proj/swarm-memory Apr 14, 2026
6 checks passed
@bao-byterover bao-byterover mentioned this pull request Apr 14, 2026
29 tasks
@cuongdo-byterover cuongdo-byterover deleted the feat/ENG-2080 branch April 14, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants