# dsh-openviking-manager English | [简体中文](README.md) ![OpenViking Manager](docs/assets/banner-en.png) `dsh-openviking-manager` is a DSH Web UI plugin for managing an existing OpenViking service connection, user keys, and local configuration diagnostics, plus a per-session OpenViking memory toggle. It manages client configuration and enablement only; memory synchronization, commit, and recall remain the responsibility of the official [`@openviking/dsh-memory-plugin`](https://www.npmjs.com/package/@openviking/dsh-memory-plugin). OpenViking is an **open-source context database from Volcengine, purpose-built for AI agents**, solving long-context, memory, and knowledge-base management for agents. It requires deploying the corresponding server; because the service supports remote access and account isolation, it also serves as a remote memory hub shared across devices and sessions. This plugin only adds a configuration UI for OpenViking, to make the local client configuration easier to manage. See the official documentation for installing and configuring OpenViking: [DeepSeek Harness Memory Bundle](https://docs.openviking.ai/en/agent-integrations/17-dsh) ## Install ```bash # Install the official OpenViking plugin dsh plugin --profile web add @openviking/dsh-memory-plugin@latest # Install the configuration manager dsh plugin --profile web add dsh-openviking-manager@latest ``` A fresh install (the package name is not yet a dependency of the profile) is usable immediately under the default `web` profile: HMR is on, so neither a restart nor a page refresh is needed. Only updating an already-installed package of the same name, or a profile with HMR off (headless / SDK / ACP), requires restarting `dsh web`. The `openviking-manager` configuration page then appears on the DSH plugins page. You can also install a GitHub Release asset directly — pre-releases ship only there, never to npm: ```bash dsh plugin --profile web add https://github.com/xbzbing/dsh-openviking-manager/releases/download//dsh-openviking-manager-.tgz ``` `lib/` is not committed, so `dsh plugin --profile web add github:xbzbing/dsh-openviking-manager` is not supported: a git install hands over a source tree with no build output, and the plugin will not load. ## Features - Read, import, and atomically update `~/.openviking/ovcli.conf`. - Preserve an existing `user_key`; the browser receives a masked value only. - Check OpenViking `/health`, `/ready`, and authenticated user identity. - Detect malformed JSON and unsafe `ovcli.conf` permissions; offer a confirmed local permission repair. - Local discovery reads non-sensitive `~/.openviking/ov.conf` state, such as authentication mode and root-key availability. `ovcli.conf` always takes precedence. - Temporarily use a `root_api_key` with the official Admin API to list accounts/users, create accounts/users, and rotate a user key. - Derive the Studio URL as `/studio`; users can override it for a reverse proxy. - Per-session OpenViking toggle: a button on the left of the conversation input toolbar (on by default). Turning a session off makes this plugin intercept the official plugin's context injection and memory writes/commits for that session and deny its `mcp__openviking__*` tool calls, so the session no longer reads or writes OpenViking. - Memory isolation switch "Disallow sharing memories across topics": writes the official `plugin.recallPeerScope` key in `ovcli.conf` and is **on by default** — on the first config-page load, when the file does not define the key yet, the plugin default pins `actor` once and reloads, so out of the box memories are isolated per topic; turning it off writes back the official default `all` to allow cross-topic sharing. The official memory plugin **reloads automatically** after saving so the change applies immediately (the card warns about the reload and its side effects up front, and reports the outcome on the status line). The user-level profile injection and shared resources are not affected by this switch. Workspace configuration such as `.openviking/config.json` is managed by the user; this plugin neither reads nor writes it. - Recall tuning: adjust the official plugin's automatic recall from the same page — `scoreThreshold` (recall score threshold: this plugin defaults to 0.5, the official default is 0.35), `recallLimit` (maximum injected items, official default 10), `recallQueryExpansion` (query expansion: this plugin defaults to off, the official default is auto), `recallExcludeUris` (URI subtrees that are never recalled, handy for boilerplate directory files such as skills or resources indexes), `timeoutMs` (request timeout: this plugin defaults to 15000ms, the official dsh default is 10000) and `recallContextTimeoutMs` (recall search timeout: official default 0 = derive from the request timeout and the expansion/rewrite floor). When the backend's search/rerank hangs, lowering these two timeouts lets recall fail fast instead of stalling the whole turn (session-aware search has a 15s/45s floor, so only a positive `recallContextTimeoutMs` shortens it). Key names and value domains come straight from the official config-schema; only `ovcli.conf`'s `plugin` section is written and every other key is preserved. The threshold, the expansion and the request timeout carry a **product default**: the first config-page load writes them when the file does not define them and reloads, the same mechanism the isolation switch uses. Clearing a field returns that knob to its default, while the remaining keys are removed to restore the official default. `OPENVIKING_*` environment variables outrank the file, so an overridden field is read-only and shows a warning. Saving reloads the official memory plugin automatically, exactly like the isolation switch. - Actor peer id (advanced, **empty by default**): writes the official `plugin.peerId` key in `ovcli.conf` to declare which peer (topic) this DSH process belongs to. It is different from the isolation switch — `recallPeerScope` sets only the recall *range*, while the peer id sets *which* peer you are: - **Empty (recommended, multi-repository setup)**: the official plugin derives a peer from each session's workspace git identity, so every repository automatically becomes its own topic with recall across sessions inside it, and no per-repository configuration is needed. **When one DSH instance works across multiple repositories, keep this empty** — the `OpenViking MCP: actor-scoped recall needs an explicit peer id ...` log line is expected then and can be ignored: it only affects the manual MCP tools (which fall back to broad cross-peer recall), not the automatically injected, isolated memories. - **Set**: every session in this process is pinned to this one peer and the automatic per-repository derivation is overridden. Use it only when one DSH instance serves a single repository, or when you deliberately want several repositories to share one topic; once set, the manual MCP tools scope to this peer and the log line disappears. The "Fill from current repository" button derives the peer id from the current repository's git remote via the official workspace-identity logic. Clearing the field removes `plugin.peerId` and restores automatic derivation. `OPENVIKING_PEER_ID`, and a top-level `actor_peer_id`/`peer_id` credential in `ovcli.conf`, outrank this file: when either is in effect the field is read-only with a warning (this plugin does not edit the top-level credential key). Saving reloads the official memory plugin automatically as well. - Follow the DSH system language setting with Simplified Chinese and English UI dictionaries. ## Screenshots | In DSH | Recovery and initialization | | :---: | :---: | | ![openviking-manager in the DSH plugins page](docs/assets/screenshots/en/01-plugin-list.png) | ![Recover or initialize access: list accounts](docs/assets/screenshots/en/03-recovery-accounts.png) | | ![Plugin page: connection configuration and verification](docs/assets/screenshots/en/02-configuration.png) | ![Recover or initialize access: create user](docs/assets/screenshots/en/04-create-user.png) | Screenshots are captured from an isolated DSH instance by `npm run screenshots`; the Simplified Chinese set lives in [README.md](README.md). ## Security boundaries - `root_api_key` is used only for the current browser form and a same-origin management request. It is never written to `ovcli.conf`; the form is cleared after creation or key rotation succeeds. - An existing `user_key` is read locally by the server and never returned to the browser in plaintext. Connection verification works without exposing that key. - Management routes accept same-origin requests only, use `no-store` responses, and do not log authorization headers. - Toggle state lives only in plugin process memory; restarting DSH resets every session to the default (on). - Turning a session off only affects subsequent agent steps: OpenViking context already injected into history remains until compaction, and writes the official plugin queued while the session was on may still be replayed by its global recovery. This plugin does not start, stop, or reconfigure the OpenViking server, and does not replace the official memory plugin. - The sharing switch only writes the officially declared `plugin.recallPeerScope` key and preserves every unknown key in `ovcli.conf`. The automatic reload after saving goes through the host's public Cordis mechanisms so the official plugin re-reads its configuration; it never modifies official code. Side effects (disclosed on the card): one final commit/archive pass over open sessions and a brief MCP tool rebuild. If the automatic reload does not complete, the status line reports it; when the official plugin is not loaded, the page asks you to restart the DSH instance manually. The `OPENVIKING_RECALL_PEER_SCOPE` environment variable outranks every file and shows an override warning on the page. - Recall tuning writes only the officially declared `scoreThreshold`, `recallLimit`, `recallQueryExpansion`, `recallExcludeUris`, `timeoutMs` and `recallContextTimeoutMs` keys. Values are validated against the official config-schema's domain, so an out-of-range or malformed request is rejected without touching the file, and every other key in `ovcli.conf` (credentials included) is preserved. The product defaults (`scoreThreshold` 0.5, `recallQueryExpansion` off, `timeoutMs` 15000) only write an official key on the first config-page load — they never redefine the official default, so a file or environment value still wins and a keyless file behaves officially until it is initialised. `OPENVIKING_SCORE_THRESHOLD`, `OPENVIKING_RECALL_LIMIT`, `OPENVIKING_RECALL_QUERY_EXPANSION`, `OPENVIKING_RECALL_EXCLUDE_URIS`, `OPENVIKING_TIMEOUT_MS` and `OPENVIKING_RECALL_CONTEXT_TIMEOUT_MS` outrank the file, so an overridden field is read-only and shows a warning. - Actor peer id writes only the officially declared `plugin.peerId` key (clearing its `peer_id` alias and any `plugin.dsh` override), and preserves every unknown key and the top-level credentials in `ovcli.conf`. Validation rejects only clearly invalid input (out-of-range length or a non-official charset) and does not stand in for the server's own sanitisation. Clearing the field removes the key and restores the official per-session git-identity derivation (it never redefines the official default); this plugin **does not edit** the top-level `actor_peer_id`/`peer_id` credential key and only shows a read-only warning when one is in effect. `OPENVIKING_PEER_ID` outranks the file. "Fill from current repository" derives only through the official `shared/workspace-peer.mjs` without reimplementing the rules, and yields an empty suggestion rather than an error when the official package is absent or the directory is outside a git repository. For multi-repository memory isolation this field **should stay empty**, and the OpenViking MCP log about a missing explicit peer id can be ignored. ## Requirements - Node.js `>= 22` - DSH `>= 0.1.6-alpha.2 < 0.3.0-0` - A reachable OpenViking service - Official `@openviking/dsh-memory-plugin` `>= 0.3.2` (no upper bound; this repository has been fully tested through `0.5.0`, and the deployed `0.5.20` was checked method by method for every runtime interface this plugin depends on) ## Server compatibility This plugin writes only the `plugin` section of `ovcli.conf` and calls only the data-plane `/health`, `/ready` and `/api/v1/system/status` endpoints plus the Admin `accounts`/`users`/`key` endpoints. It relies on no removed or deprecated endpoint, so the breaking changes in OpenViking server v0.4.22 (removal of the session `used` report, deprecation of `/admin/accounts/{id}/settings` and `/admin/agent-evolution`, the restructured `skills/find` response, and so on) need no adaptation here. The one semantic change worth noting (v0.4.22 #5358): the local vector engines (`vectordb.backend = local`/`cuvs`) map pure cosine scores from `[-1,1]` to `(cos + 1) / 2`, i.e. `[0,1]`. Ranking is unchanged, existing indexes need no rebuild, and a server downgrade restores raw scores — but **thresholds are not adjusted automatically**. This plugin's `scoreThreshold` default (0.5) and the official default (0.35) are passed through verbatim as the server's `score_threshold`/`min_score`, so after the mapping the same threshold admits more weak matches: | Threshold | Old domain ([-1,1]) means | New domain ([0,1]) means | | --- | --- | --- | | 0.35 (official default) | `cos ≥ 0.35` | `cos ≥ -0.3` | | 0.5 (this plugin's default) | `cos ≥ 0.5` | `cos ≥ 0` | | 0.75 | `cos ≥ 0.75` | `cos ≥ 0.5` (equivalent to the old 0.5) | - To keep the same filtering strength as ≤ 0.4.21, set `scoreThreshold` to 0.75; - Remote vector backends (`http`/`volcengine`/`vikingdb`) and IP/L2/sparse-fusion scores are **unaffected** — no adjustment is needed; - If weak matches become more visible after upgrading, tune between 0.5 and 0.75 as needed. ### OpenViking server v0.5.0 - **Config-file location follows the official plugin**: the `ovcli.conf` / `ov.conf` this plugin reads and writes now resolve through the same chain as the official plugin's `shared/credentials.mjs` — `OPENVIKING_CLI_CONFIG_FILE` selects `ovcli.conf`, `OPENVIKING_CONFIG_FILE` selects `ov.conf`, each falling back to the default under `~/.openviking`, with the same backward-compat where a lone ovcli-shaped `OPENVIKING_CONFIG_FILE` stands in for `ovcli.conf`. v0.5.0 (#5551) makes `OPENVIKING_CLI_CONFIG_FILE` the canonical selector for `ov status` / `ov config`, so the config page always edits the file the running plugin actually loads instead of a different one when that variable is set. - **`recallExcludeUris` with a directory excludes the whole subtree**: since v0.5.0 (#5627), passing a directory URI in `exclude_uris` excludes the entire subtree (older servers matched the string exactly, so a directory excluded nothing). This plugin passes the key through verbatim; the name and value domain (a list of URIs) are unchanged, so no adaptation is needed — expect every entry under a directory to be excluded when you list one. - Working Memory defaulting off, plugin commit archiving all messages, context recall no longer returning system preset directories, and the MCP `remember` return-text change are all server- or official-plugin-internal; none touch the keys this plugin writes or the endpoints it calls, so no adaptation is needed. OpenViking Gateway is a separate component (its own process, the `gateway` section of `ov.conf`, and `/api/v1/admin/gateway/*`); this plugin neither configures nor orchestrates the gateway. ## Development ```bash npm ci npm run build # Generates lib/; no .tgz is produced npm test # Unit tests + Playwright E2E ``` `lib/` is not committed: the release workflow generates it with `npm pack` after the gate passes, and ships the tarball both as a GitHub Release asset and to npm. `npm run build` clears `lib/` before compiling, so deleting a source file cannot leave a stale artifact behind; `lib/standalone.js` exists only for Playwright and is never published. The release process and body format live in `.github/RELEASE_TEMPLATE.md` — do not tag or publish by hand. ## Tests ```bash npm run test:unit npm run test:e2e ``` The Playwright suite covers `ovcli.conf` import and save, invalid endpoint protection, server-side user-key validation, temporary-root-key account/user selection, and Chinese browser-language rendering. ## Project layout ```text src/ ovcli-config.ts ovcli.conf read, validation, atomic writes, permissions openviking-paths.ts resolve ovcli.conf / ov.conf paths like the official plugin local-discovery.ts non-sensitive ov.conf discovery openviking-client.ts data-plane connection and identity validation openviking-admin.ts official Admin API adapter manager-api.ts DSH same-origin HTTP routes (including session toggle) session-toggle.ts in-memory per-session OpenViking toggle state ov-prestep.ts identify and strip official-plugin pre-step injections ov-tool-guard.ts deny mcp__openviking__* tools while a session is off openviking-gate.ts per-session short-circuit wrapper over OpenVikingRuntime client/ DSH Web UI, input-bar toggle button, styles, i18n ``` ## License [MIT License](LICENSE).