Skip to content

feat(memory-wiki): scope vault path to instanceId (Phase D2.1)#13

Merged
LightDriverCS merged 3 commits into
mainfrom
feat/memory-wiki-instance-vault
Apr 28, 2026
Merged

feat(memory-wiki): scope vault path to instanceId (Phase D2.1)#13
LightDriverCS merged 3 commits into
mainfrom
feat/memory-wiki-instance-vault

Conversation

@LightDriverCS

@LightDriverCS LightDriverCS commented Apr 28, 2026

Copy link
Copy Markdown

Summary

Threads instanceId from OpenClawConfig into the memory-wiki config resolver so each Bench instance gets its own vault directory:

  • Tier A (no instanceId) → ~/.openclaw/wiki/main/
  • Tier B/C (instanceId set) → ~/.openclaw/wiki/{instanceId}/

Explicit vault.path overrides still win, so existing single-user deployments that set a custom vault path are unaffected.

Why

Phase D2.1 — per-instance harnesses (Tier B local, Tier C cloud) need filesystem isolation between vaults so multi-tenant signals never co-mingle. The vault dir is the most security-relevant place to scope; the cloud-mirror state file (PR D) follows.

Changes

  • extensions/memory-wiki/src/config.ts:
    • INSTANCE_ID_PATTERN + normalizeInstanceId() — local copy of the same regex used by src/config/zod-schema.ts (kept local because memory-wiki doesn't import from src/config/*).
    • resolveDefaultMemoryWikiVaultPath(homedir, instanceId?) — appends {instanceId} or main.
    • resolveMemoryWikiConfig(config, { homedir, instanceId }) — accepts the new option.
  • extensions/memory-wiki/index.ts + cli-metadata.ts + src/cli.ts: thread appConfig.instanceId through to the resolver.
  • extensions/memory-wiki/src/config.test.ts: 7 new tests (vault scoping happy paths + path-traversal/empty/slash fallback to main/).

Path-traversal hardening

Inputs like "../evil", "has/slash", "", or anything not matching [A-Za-z0-9_-]{1,128} fall back to main/ rather than scoping into a malicious dir. Verified by tests.

Stacked PR

Stacked on #11. Once #11 merges, GitHub auto-rebases this onto main. Orthogonal to #10 (canon-kind indexing).

Test plan

  • pnpm vitest run extensions/memory-wiki/src/config.test.ts — 11 tests pass
  • Pre-commit hooks green

🤖 Generated with Claude Code

Anvil Handoff

  • Hammer summary: Threads appConfig.instanceId into resolveMemoryWikiConfig and resolveDefaultMemoryWikiVaultPath. Vault becomes ~/.openclaw/wiki/{instanceId}/; falls back to main/ when unset or invalid. Path-traversal inputs (../evil, has/slash, "", anything not matching the regex) safely fall back to main/. Stacked on feat(config): top-level instanceId field (Phase D2.1 foundation) #11. Orthogonal to open feat(memory-wiki): index canon/ directory in bridge #10 (canon-kind indexing) — verified zero file overlap.
  • Primary paths changed: extensions/memory-wiki/cli-metadata.ts, extensions/memory-wiki/index.ts, extensions/memory-wiki/src/cli.ts, extensions/memory-wiki/src/config.ts, extensions/memory-wiki/src/config.test.ts
  • Verification run: pnpm vitest run extensions/memory-wiki/src/config.test.ts → 11 passed (7 new covering vault scoping happy paths + path-traversal fallback). Pre-commit green.
  • Known risks: (1) No migration helper — installs that already have content under ~/.openclaw/wiki/main/ will keep using it (since instanceId defaults unset); flipping instanceId later creates a fresh wiki/{instanceId}/ and orphans the previous content. (2) INSTANCE_ID_PATTERN regex is a local copy of the one in feat(config): top-level instanceId field (Phase D2.1 foundation) #11's zod-schema.ts— drift risk. (3) Explicitvault.pathconfig override beats the newinstanceId scoping; the documented precedence isn't surfaced in schema.help.ts.
  • Suggested Anvil focus: Find every caller of resolveMemoryWikiConfig to confirm appConfig.instanceId is threaded everywhere (the PR touches cli-metadata.ts, index.ts, src/cli.ts — anywhere else?). Verify the path-traversal test set covers all variants the regex would reject (Unicode, leading ., null, Symbol()). Check whether the vault.path override + instanceId interaction needs documentation in schema.help.ts.

Cory Shelton and others added 2 commits April 28, 2026 01:03
Adds an optional `instanceId` field to OpenClawConfig. Validates
1-128 chars matching `[A-Za-z0-9_-]+` so the value can serve as a
filesystem-safe path component. When set, downstream features
(memory-wiki vault path, cloud-mirror state file, health snapshot,
shard directory layout) scope per-instance resources to this id.
When unset, single-user Tier A defaults apply.

This is the foundation PR for Phase D2.1 (per-instance harness
hardening); subsequent PRs surface the field on health, scope the
memory-wiki vault, and update the cloud-mirror daemon.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Threads `instanceId` from `OpenClawConfig` into the memory-wiki
config resolver so each Bench instance gets its own vault directory:

  Tier A (no instanceId):  ~/.openclaw/wiki/main/
  Tier B/C (instanceId):   ~/.openclaw/wiki/{instanceId}/

Validates the id with a local copy of the same regex used by the
core config schema (`/^[A-Za-z0-9_-]{1,128}$/`) — kept local because
the memory-wiki extension doesn't import from `src/config/*` and the
constraint must stay filesystem-safe regardless. Path-traversal
inputs (`"../evil"`, `"has/slash"`, `""`) fall back to `main/` rather
than scoping into a malicious dir.

Explicit `vault.path` overrides still win, so existing single-user
deployments that set a custom vault path are unaffected.

Depends on PR #11.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Surfaced by Codex Anvil (PR #13 smoke 20260428T080050Z):

1. `cli-metadata.test.ts` asserted the old one-arg call to
   `resolveMemoryWikiConfig`, but the entry now passes
   `{ instanceId }` as a second arg. Updated assertion + added
   `instanceId: "bench-prod-01"` to the test's `appConfig` fixture
   so it proves the threading works end-to-end.

2. README, `docs/plugins/memory-wiki.md`, and the plugin manifest
   `openclaw.plugin.json` all hardcoded `vault.path: "~/.openclaw/wiki/main"`
   in copy-paste examples. A user copying that into Tier B/C config
   would silently override the new instance-scoped default. Updated:
   - examples comment-out `path:` and document the new default.
   - manifest help text describes the
     `~/.openclaw/wiki/{instanceId}` default + override semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
LightDriverCS added a commit that referenced this pull request Apr 28, 2026
Phase D2.1 foundation. Adds optional top-level instanceId to OpenClawConfig with strict regex /^[A-Za-z0-9_-]{1,128}$/ for filesystem-safe per-instance scoping. Stack of #12 (health), #13 (memory-wiki vault), #14 (cloud-mirror) follows.

Codex Anvil (gpt-5.5 xhigh) verdict: PASS. 54 tests pass; pnpm config:schema:check + pnpm config:docs:check both green. Repair patch from first smoke (regenerate config-baseline.sha256) applied as second commit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@LightDriverCS
LightDriverCS changed the base branch from feat/config-instance-id to main April 28, 2026 08:23
@LightDriverCS
LightDriverCS merged commit 7276864 into main Apr 28, 2026
3 of 12 checks passed
@LightDriverCS
LightDriverCS deleted the feat/memory-wiki-instance-vault branch April 28, 2026 08:24
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.

1 participant