openclaw - ✅(Solved) Fix memory-wiki: per-agent vault path isolation for multi-tenant deployments [3 pull requests, 1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#66003Fetched 2026-04-14 05:39:19
View on GitHub
Comments
1
Participants
1
Timeline
5
Reactions
0
Participants
Timeline (top)
cross-referenced ×2referenced ×2commented ×1

Multi-tenant SaaS deployments running OpenClaw need per-tenant (per-org) isolation of the memory-wiki vault. The current plugins.entries.memory-wiki.config.vault.path is a static string resolved once at plugin registration, shared across every agent on the gateway process.

Root Cause

  • Workaround (one gateway process per tenant) doesn't scale.
  • Wrapper plugins can re-implement factory registration but must import internal exports from the dist bundle and break on any refactor.
  • Without this, multi-tenant apps can't adopt memory-wiki despite its better architecture vs raw markdown / external graph DBs.

Fix Action

Fix / Workaround

  • Workaround (one gateway process per tenant) doesn't scale.
  • Wrapper plugins can re-implement factory registration but must import internal exports from the dist bundle and break on any refactor.
  • Without this, multi-tenant apps can't adopt memory-wiki despite its better architecture vs raw markdown / external graph DBs.

PR fix notes

PR #66134: refactor(memory-wiki): use factory registration for wiki_apply/status/lint

Description (problem / solution / changelog)

Summary

  • Problem: wiki_apply, wiki_status, and wiki_lint are registered with the static api.registerTool(createX(config, api.config)) form, while their read-side siblings wiki_search and wiki_get use the factory form api.registerTool((ctx) => ...). The write-side tools close over a single config object resolved at register(api) call time and never see the per-invocation OpenClawPluginToolContext.
  • Why it matters: The inconsistency means downstream plugins and advanced configurations can hook into wiki reads via ctx but have no equivalent seam for writes without forking. It also makes the plugin harder to reason about — two registration shapes for five tools in the same file.
  • What changed: Switched wiki_status, wiki_lint, and wiki_apply to factory registration: api.registerTool(() => createX(config, api.config), { name: ... }).
  • What did NOT change (scope boundary): No changes to tool internals, config schema, resolved config values, or any public API surface. Factories currently ignore ctx (matching today's write-side behavior) — this PR is purely about registration shape.

Change Type (select all)

  • Refactor required for the fix

Scope (select all touched areas)

  • Memory / storage
  • Skills / tool execution

Linked Issue/PR

  • Related #66003

Root Cause (if applicable)

N/A — refactor, not a bug fix.

Regression Test Plan (if applicable)

N/A — existing extensions/memory-wiki/index.test.ts asserts all five tool registrations by name and continues to pass unchanged.

User-visible / Behavior Changes

None.

Diagram (if applicable)

Before:
  api.registerTool(createWikiStatusTool(config, api.config), { name: "wiki_status" })  // static
  api.registerTool((ctx) => createWikiSearchTool(config, api.config, {...}), ...)      // factory

After:
  api.registerTool(() => createWikiStatusTool(config, api.config), { name: "wiki_status" })  // factory
  api.registerTool((ctx) => createWikiSearchTool(config, api.config, {...}), ...)            // factory

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No (tool behavior identical; only registration shape changes)
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS 15.3
  • Runtime/container: Node 20, pnpm 10.32.1
  • Model/provider: N/A

Steps

  1. pnpm install
  2. node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-memory.config.ts extensions/memory-wiki/

Expected

All memory-wiki tests pass (including index.test.ts which asserts the five tool registrations).

Actual

 Test Files  22 passed (22)
      Tests  81 passed (81)

Evidence

  • Passing test output (above)

Human Verification (required)

  • Verified scenarios: Ran the full memory-wiki test suite locally (22 files, 81 tests, all passing). Confirmed extensions/memory-wiki/index.test.ts still passes — it asserts registration order and names, which are unchanged.
  • Edge cases checked: Confirmed OpenClawPluginApi.registerTool already accepts AnyAgentTool | OpenClawPluginToolFactory (src/plugins/types.ts:1887), so no API-level changes are needed.
  • What I did not verify: End-to-end runtime behavior inside a real OpenClaw agent session. The factories are called once per registration in the existing tool-lookup path, so behavior should be identical, but I have not exercised a live wiki_apply/status/lint call through an agent after the refactor.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Factory is invoked per tool resolution rather than once at register(api) time, so any consumer relying on identity of the returned tool object across calls would see a new object each time.
    • Mitigation: The read-side tools (wiki_search, wiki_get) have used this pattern since they were introduced, and no known consumer depends on tool identity. The plugin loader treats registered tools as descriptors, not singletons.

Changed files

  • extensions/memory-wiki/index.ts (modified, +3/-3)

PR #66149: feat(memory-wiki): add ctx-aware templating for vault.path

Description (problem / solution / changelog)

Summary

  • Problem: vault.path is resolved once at register(api) time, so a single plugin instance cannot serve agents living in different workspaces — they all share one vault. There is no way to derive the vault location from the per-invocation tool context (workspaceDir, agentId, etc.) that the tool factories already receive.
  • Why it matters: Setups where one OpenClaw instance runs multiple agent workspaces (shared hosts, containerized deployments, multi-profile setups) currently require either forking the plugin or running one OpenClaw process per agent. Both are heavy for a config-shaped problem.
  • What changed: vault.path now supports the template tokens {workspaceDir}, {agentDir}, {agentId}, {sessionKey}. Templates are expanded against the tool invocation context on each wiki tool call, using the factory registration landed in the prior commit. A new public helper resolveMemoryWikiConfigForCtx(base, ctx) handles the expansion and returns base by identity when no tokens are present.
  • What did NOT change (scope boundary): No change to default config values, resolved config shape, or any existing API. Non-templated paths hit an identity fast path (zero allocations). The openclaw wiki CLI and non-agent gateway methods intentionally continue to use the literal configured path — they have no invocation context to expand against, and silently pretending otherwise would be worse than the documented limitation.

Change Type (select all)

  • Feature

Scope (select all touched areas)

  • Memory / storage
  • Skills / tool execution

Linked Issue/PR

  • Depends on #66134 (factory registration for wiki_apply/status/lint — this PR is stacked on that branch and includes its commit). Please review/merge #66134 first; once it lands I'll rebase this on main and the diff will shrink to this feature commit only.
  • Related #66003

Root Cause (if applicable)

N/A — additive feature.

Regression Test Plan (if applicable)

N/A — new feature. Added 5 unit tests in extensions/memory-wiki/src/config.test.ts covering:

  • template token detection (including unknown tokens not triggering expansion)
  • expansion order vs path.normalize (traversal segments collapse only after expansion)
  • identity fast path for non-templated configs
  • full config expansion with {workspaceDir}
  • partial expansion when some ctx fields are absent

User-visible / Behavior Changes

  • New: vault.path accepts {workspaceDir}, {agentDir}, {agentId}, {sessionKey} placeholders.
  • Unchanged: existing literal and ~-prefixed paths continue to work identically.
  • Documented in docs/plugins/memory-wiki.md under "Key toggles".

Diagram (if applicable)

Before (shared vault):
  agent-a ──┐
  agent-b ──┼──> single resolved vault.path ──> /Users/me/.openclaw/wiki/main
  agent-c ──┘

After (templated vault, same plugin instance):
  agent-a (workspaceDir=/ws/a) ──> {workspaceDir}/wiki ──> /ws/a/wiki
  agent-b (workspaceDir=/ws/b) ──> {workspaceDir}/wiki ──> /ws/b/wiki
  agent-c (workspaceDir=/ws/c) ──> {workspaceDir}/wiki ──> /ws/c/wiki

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No (tool contracts unchanged)
  • Data access scope changed? Yes — if the user opts in to templating, wiki writes now land in ctx-derived paths instead of a single shared path.
  • Risk + mitigation: A malicious or mis-configured ctx could in principle coerce a vault into an unexpected location. Mitigations: (1) templates are opt-in — the default remains ~/.openclaw/wiki/main; (2) the fsPolicy check inside applyMemoryWikiMutation still applies; (3) only four specific tokens are substituted (no arbitrary string interpolation); (4) expansion happens via path.normalize which cannot escape by itself — the caller has to explicitly use .. segments. This is analogous to how ~ already allows user-scoped paths.

Repro + Verification

Environment

  • OS: macOS 15.3
  • Runtime: Node 20, pnpm 10.32.1
  • Model/provider: N/A

Steps

  1. pnpm install
  2. node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-memory.config.ts extensions/memory-wiki/

Expected

All memory-wiki tests pass, including the 5 new vault-path-templating tests.

Actual

 Test Files  22 passed (22)
      Tests  86 passed (86)

Evidence

  • Passing test output (above)

Human Verification (required)

  • Verified scenarios: Unit tests cover the identity fast path, the expansion path, traversal-after-expansion, and missing-ctx-field fallback. Manually walked through index.ts to confirm all five tool factories now route through resolveMemoryWikiConfigForCtx.
  • Edge cases checked:
    • {unknownToken} is left literal (does not match the pattern) — this means typos surface as "directory not found" rather than silently falling back, which is better UX.
    • {workspaceDir}/../shared-wiki → resolves .. only after expansion, so the result is the expected sibling directory and not the collapsed-template mistake of just shared-wiki.
    • ctx.workspaceDir === undefined → expands to an empty string, producing a relative-ish path. Documented; users opting in are expected to guarantee the fields they template against are populated.
  • What I did not verify: End-to-end run of wiki_apply through a live agent session with a templated vault.path. The unit tests exercise the config resolution but not the full applyMemoryWikiMutation pipeline against a real FS. Maintainers may want to spot-check this.

Compatibility / Migration

  • Backward compatible? Yes — existing configs take the identity fast path.
  • Config/env changes? No (schema unchanged — vault.path is still a string).
  • Migration needed? No.

Risks and Mitigations

  • Risk: Someone templates vault.path and later runs openclaw wiki doctor (or other CLI surfaces) which don't have ctx to expand against — the literal path contains {...} and throws a cryptic error.
    • Mitigation: Documented in docs/plugins/memory-wiki.md. Happy to add a runtime check + friendly error to the CLI surfaces in a follow-up if preferred.
  • Risk: Expansion is silent when a ctx field is unset, substituting empty string — could surprise users.
    • Mitigation: Tested; considered throwing instead but felt defensive coding against runtime-internal invariants was un-idiomatic. Open to flipping this to a warn-log or throw if maintainers prefer.

Changed files

  • docs/plugins/memory-wiki.md (modified, +8/-0)
  • extensions/memory-wiki/index.ts (modified, +19/-6)
  • extensions/memory-wiki/src/config.test.ts (modified, +63/-0)
  • extensions/memory-wiki/src/config.ts (modified, +66/-0)

PR #67584: feat(memory-wiki): per-org vaults via ctx-aware vault.path templating

Description (problem / solution / changelog)

Summary

Enables multi-tenant setups where one OpenClaw instance serves multiple orgs, each with an isolated wiki vault. Single combined PR replacing #66134 + #66149.

Changes:

  1. Factory registrationwiki_apply, wiki_status, and wiki_lint now use the factory form (ctx) => createXTool(config, ...), matching wiki_search and wiki_get. Pure registration-shape refactor, no behavioral change.

  2. vault.path templating — when vault.path contains {workspaceDir}, {agentDir}, {agentId}, or {sessionKey}, the path is expanded at tool-invocation time using the invocation context. A config like vault.path: "{workspaceDir}/../wiki" resolves to different directories per agent/org.

    • containsVaultPathTemplate(path) — fast check for template tokens
    • expandVaultPathTemplate(path, ctx) — token replacement + path.normalize
    • resolveMemoryWikiConfigForCtx(base, ctx) — returns a resolved config copy (identity fast-path when no template present)
  3. Tests — 5 new tests covering template detection, expansion, identity fast-path, full ctx resolution, and partial expansion.

Use case

We run one OpenClaw instance serving multiple orgs. Each org needs its own wiki vault. With this change, setting vault.path: "{workspaceDir}/../wiki" in plugin config gives each org an isolated vault resolved at invocation time — no per-agent config patching needed.

CI note

The memory-wiki-specific CI check (extension-fast-memory-wiki) passes. Any red checks are pre-existing TS errors in unrelated extensions (discord, telegram, whatsapp) — same failures present on main. Happy to rebase if those get fixed upstream.

Closes #66003 Supersedes #66134 and #66149

Changed files

  • docs/plugins/memory-wiki.md (modified, +8/-0)
  • extensions/memory-wiki/index.ts (modified, +19/-6)
  • extensions/memory-wiki/src/config.test.ts (modified, +63/-0)
  • extensions/memory-wiki/src/config.ts (modified, +66/-0)
RAW_BUFFERClick to expand / collapse

Context

Multi-tenant SaaS deployments running OpenClaw need per-tenant (per-org) isolation of the memory-wiki vault. The current plugins.entries.memory-wiki.config.vault.path is a static string resolved once at plugin registration, shared across every agent on the gateway process.

The gap

Per source inspection ([email protected], dist/extensions/memory-wiki/):

  • wiki_search and wiki_get are registered via factory (api.registerTool((ctx) => ...)) and already have access to ctx.agentId, ctx.workspaceDir, ctx.sessionKey.
  • wiki_apply, wiki_status, wiki_lint are registered as static tools that close over the single config resolved at register(api) time from api.pluginConfig. No way to vary vault.path per-agent.
  • vault.path only supports ~ / ~/ expansion — no template variables, no env vars, no runtime substitution.

Result: any agent on the gateway writes to and reads from the same physical vault. In multi-tenant deployments this is a cross-tenant data leak.

Proposals (any one solves it)

  1. Template variables in vault.path — support {agentId}, {workspaceDir}, {workspaceSlug} substitution at tool invocation time (not at register time).

  2. Factory-based registration for all wiki tools — register wiki_apply, wiki_status, wiki_lint with the same (ctx) => ... factory pattern used for wiki_search / wiki_get, so the vault path can be computed from ctx.workspaceDir per call.

  3. Per-agent pluginConfig override — allow agents.list[].plugins.memory-wiki to override vault.path (or the whole config block), merged over the global plugins.entries.memory-wiki.config.

Option 2 seems least invasive — ctx.workspaceDir is already threaded through for the read-side tools; extending it to the write-side tools would give natural per-agent isolation without any config changes.

Why this matters

  • Workaround (one gateway process per tenant) doesn't scale.
  • Wrapper plugins can re-implement factory registration but must import internal exports from the dist bundle and break on any refactor.
  • Without this, multi-tenant apps can't adopt memory-wiki despite its better architecture vs raw markdown / external graph DBs.

Environment

  • openclaw 2026.4.11 / 2026.4.12
  • Observed via source reading in `dist/extensions/memory-wiki/index.js` and `dist/config-CUv-SlNV.js`

extent analysis

TL;DR

Registering all wiki tools with a factory pattern, similar to wiki_search and wiki_get, can provide per-agent isolation of the memory-wiki vault.

Guidance

  • The current static vault.path configuration is the root cause of the cross-tenant data leak, as it is shared across all agents on the gateway process.
  • To verify the issue, check if multiple agents are writing to and reading from the same physical vault by inspecting the vault.path configuration.
  • Registering wiki_apply, wiki_status, and wiki_lint with a factory pattern, like wiki_search and wiki_get, can provide per-agent isolation by allowing the vault path to be computed from ctx.workspaceDir per call.
  • This approach seems to be the least invasive, as it leverages existing code patterns and does not require significant config changes.

Example

No code example is provided, as the issue description does not include specific code snippets that can be modified to fix the issue.

Notes

The proposed solution assumes that the ctx.workspaceDir is unique per agent and can be used to compute a unique vault path. If this is not the case, alternative solutions may be necessary.

Recommendation

Apply workaround by registering all wiki tools with a factory pattern, as it provides a straightforward and non-invasive solution to achieve per-agent isolation of the memory-wiki vault.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix memory-wiki: per-agent vault path isolation for multi-tenant deployments [3 pull requests, 1 comments, 1 participants]