Files
OpenViking/examples/zcode-memory-plugin
t0saki a83b81715b feat(uri)!: remove uid-less current-user shorthand in favor of viking://~ (#4196)
* feat(uri)!: reject uid-less current-user shorthand in favor of viking://~

viking://user/<segment> (memories/resources/skills/peers/privacy/sessions
without a user id) was ambiguous with a user literally named after the
segment, and a user actually named e.g. "memories" was unreachable for
USER/ADMIN callers. Now that the viking://~ home alias (#4167) covers the
same need unambiguously, the shorthand fails closed at the request
boundary instead of expanding:

- resolve_current_user_uri raises NamespaceShapeError with a corrective
  hint naming both viking://~/<rest> and the explicit-uid form. Silently
  parsing the reserved segment as a peer user id would misdirect reads
  and writes, so rejection is the only safe removal.
- Bare viking://user falls through to the canonical parser and keeps
  container semantics (a user key listing it sees only its own space).
- The self-id escape stays: a caller whose user_id equals a reserved
  name keeps viking://user/<own-id> as their canonical root. ROOT-role
  literal parsing and the legacy viking://session alias are unchanged.
- AddTargetsConfig normalizes stored legacy config spellings
  (viking://user/resources|skills) to the viking://~ form at validation
  so existing ov.conf/user_config deployments keep working; the accepted
  per-user spelling is now viking://~/resources and viking://~/skills.
- usage_reporter keeps canonicalizing the historical shorthand found in
  old transcripts and additionally recognizes viking://~/memories/.

BREAKING CHANGE: requests using the uid-less viking://user/<segment>
spelling now fail with 400; use viking://~/<segment> or an explicit
viking://user/{user_id}/<segment> URI.

* refactor(clients): migrate first-party emitters to the viking://~ home alias

Every in-repo client that emitted the removed uid-less current-user
shorthand now sends viking://~/... instead: vikingbot fallbacks and
default sentinels, the LangChain store/tools defaults, the shared
recall-core.mjs (all synced plugin copies), the codex/claude-code/
openclaw/openwebui/dsh/zcode/pi plugin emitters, quick-app examples,
Go SDK example, tau2 benchmark targets, and the eval golden dataset.

Compat kept where legacy strings live in stored user configs: bot and
ov_dream sentinels accept both spellings while emitting only ~, and
recall-core still rewrites legacy viking://user/<reserved> config values
client-side. langchain_openviking._uri now classifies viking://~ with
the explicit-user shape so canonicalized server responses keep matching
a ~ root. Plugin READMEs note the server requirement for the alias.

* docs: replace current-user shorthand guidance with the viking://~ home alias

Rewrite every EN/ZH doc and model-facing prompt that advertised the
uid-less viking://user/<segment> spelling: URI concept catalogue,
context-types/storage/extraction/retrieval/session/privacy concepts,
configuration guide (with the legacy add_targets auto-normalization
note), resources/skills/sessions/retrieval/admin API references, FAQ,
capability reference, and the openviking-memory / ov-experience-memory /
openclaw / ov-resources skills. The stale MCP viking://user/<path>
dialect passage in the MCP guide is replaced by ~ guidance, and bare
viking://user is documented as the container of user spaces.

* test(api): migrate live API session-used tests off the removed shorthand

tests/api_test/sessions sent uid-less viking://user/skills/... URIs to
record_used, which the request boundary now rejects with 400 (caught by
the API & CLI Integration Tests CI job; these tests need a live server
and are not part of the local suites). The api_test client authenticates
as an admin-role user key, so the viking://~ home alias expands for it.
tests/api_test/common/test_edge_cases.py is left as is: it asserts a 400
for a non-resource add target, which still holds.
2026-08-21 19:00:19 +08:00
..

OpenViking Memory Plugin for ZCode

This package provides a ZCode lifecycle adapter for OpenViking long-term memory. It reuses the shared memory-plugin-shared runtime — no memory logic is duplicated. Only a thin ZCode adapter is new.

Requires an OpenViking server with viking://~ home-alias support. Recall targets the caller's own context space through viking://~/memories and viking://~/skills; the uid-less viking://user/memories shorthand is rejected by newer servers.

What it does

  • SessionStart — injects user profile and preferences/entities into context.
  • UserPromptSubmit — searches OpenViking for relevant memories and injects them.
  • PreToolUse (Read|Glob|Grep) — denies direct access to viking:// URIs, redirects to MCP tools.
  • Stop — returns immediately, then captures incremental user/assistant turns and commits the OpenViking session in a detached worker.

ZCode does not support PreCompact/SessionEnd/SubagentStart/SubagentStop, so the commit-on-Stop strategy compensates for the absence of compact/end-of-session signals. The rollout file is the authoritative incremental transcript: stable host turnId values drive deduplication and allow a later Stop to recover missed turns. Hook stdin is only a fallback when the rollout file is unavailable.

Install

Use the shared installer:

bash examples/memory-plugin-shared/install.sh --harness zcode

The installer detects ZCode via ~/.zcode/ or a zcode binary, merges hooks and MCP config into ~/.zcode/cli/config.json, and writes OpenViking credentials to ~/.openviking/ovcli.conf.

Architecture

The plugin vendors the shared runtime into scripts/shared/ via sync.mjs. The dispatcher (zcode-hook.mjs) branches on event name; three thin shim scripts set an environment variable and import the dispatcher, while the URI guard has its own entry point. Shared runtime modules provide recall, batching, pending queue, credential resolution, and MCP proxying; zcode-capture.mjs owns the ZCode-specific acknowledgement and cursor state transition.

See DESIGN.md for verified ZCode extension-surface facts and decision provenance.

Tests

node --test scripts/*.test.mjs