Commit Graph
41 Commits
Author SHA1 Message Date
yufeng a949517f27 docs: add OpenViking Helper integration and fix stale links (#3445)
* docs: add OpenViking Helper integration

* docs: use mock data in Helper screenshots
2026-07-22 14:14:57 +08:00
huangruitengandhuangruiteng 810a22d881 docs: isolate OpenViking installs for Hermes (#3365)
* docs: isolate OpenViking installs for Hermes

* docs: keep install guidance scoped to Hermes

---------

Co-authored-by: huangruiteng <huangruiteng@bytedance.com>
2026-07-20 08:21:03 +08:00
yufeng 0a14967f6b docs: align MCP references with implementation (#3146)
* docs: align MCP references with implementation

* docs: fix remaining factual drift

* docs: correct remaining API examples

* docs: fix observer status response type
2026-07-11 15:54:07 +08:00
yufeng d14dd69665 feat: add Cursor and TRAE memory integrations (#3109)
* feat: add Cursor and TRAE memory integrations

* fix: install Cursor plugin from shared command

* refactor: share Cursor and TRAE integration runtime

* fix: migrate legacy OpenViking MCP entry

* docs: simplify Cursor and TRAE setup guides

* fix: harden Cursor and TRAE memory integrations

* refactor: standardize Cursor and TRAE integrations

* refactor: clarify Cursor and TRAE hook entrypoints

* fix: address Cursor and TRAE integration review
2026-07-10 16:57:19 +08:00
t0sakiandZaynJarvis 85b9878be3 feat(pi): add OpenViking context takeover (#3081)
Co-authored-by: ZaynJarvis <31875147+ZaynJarvis@users.noreply.github.com>
2026-07-08 20:15:16 +08:00
t0saki b511d91ee5 feat(plugins): retrofit OpenCode and pi memory integrations (hybrid MCP, shared lib, 4-harness installer) (#3079)
* feat(plugins): align opencode and pi memory integrations

* fix(installer): tolerate missing optional harness CLIs

* fix(installer): install opencode file wrapper

* fix(opencode): import path for logger initialization

* fix(installer): register pi extension after copy

* feat(plugins): use MCP for opencode integration

* docs: move OpenCode and pi integrations to dedicated pages

Promote the OpenCode plugin and pi extension out of the community-plugins
page into their own numbered agent-integrations pages (10-opencode, 11-pi,
en + zh), update the overview routing table, and refresh the OpenCode image
cards to the hybrid MCP architecture (unified installer, openviking_* MCP
tools, ovcli.conf credentials).

* docs: bare TOS installer commands and reference more examples

Drop --harness from TOS-mirror install commands (image cards use the bare
installer URL, matching the claude-code/codex cards); add Open WebUI tool
server and an examples/ pointer to the community-plugins page (en + zh).

* docs: bare TOS installer commands across agent-integration pages

TOS-mirror install commands carry no flags anywhere; the installer wizard
asks for source, harnesses, language, and credentials.
2026-07-08 15:54:37 +08:00
t0saki f905562534 feat(plugins): stdio MCP proxy, remote marketplace install, and type-quota recall for memory plugins (#3039)
* feat: add memory plugin mcp harness

* refactor: vendor shared memory plugin modules

* feat: add type quota recall api

* feat: commit codex memory by token threshold

* feat: capture codex tool calls as parts

* feat: add claude skill experience recall

* chore: fix lint in type quota recall server files

* feat: remote marketplace install with unified openviking naming

- Fix root .claude-plugin/marketplace.json git-subdir discriminator key
  ("type" -> "source"); claude plugin validate now passes.
- Unified installer gains --source remote|archive|dev: remote registers a
  synthesized git-subdir marketplace for Claude Code and a git marketplace
  for Codex (no repo clone); archive consumes the slim TOS marketplace zip;
  dev registers the checkout's examples/ directory for both harnesses.
- One marketplace name (openviking) across all modes and harnesses, so the
  plugin id is always openviking-memory@openviking; installer migrates old
  openviking-plugins-local registrations and config.toml sections.
- Restore legacy Claude Code (<2.0) support: claude mcp add (stdio proxy)
  plus node-based hooks merge into ~/.claude/settings.json.
- Restore optional statusline registration (fetches sources on opt-in).
- Checkbox TUI harness selection via /dev/tty with non-tty fallback.
- Add examples/.agents/plugins/marketplace.json so Codex directory installs
  drop the synthetic symlink marketplace.
- Add shared setup wizard (scripts/setup.mjs) for pure-marketplace installs.
- release-tos.yml: upload memory-plugin-shared/install.sh and build/upload
  the memory-plugin-marketplace zip; tos-install.sh prefers it and pins all
  fetches to TOS via OPENVIKING_SHARED_INSTALL_URL.
- CI: bash -n on installer scripts; marketplace contract tests updated.

* fix(installer): register Claude remote marketplace as a directory

File-type marketplaces (bare marketplace.json path) make Claude Code derive
a wrong installLocation and 'marketplace update' fails with EISDIR. Write
the synthesized manifest to <dir>/.claude-plugin/marketplace.json and add
the directory instead; compare registered sources by exact match so the
old file registration migrates cleanly.

* feat(statusline): show model name and native-style context percentage

A custom statusLine replaces Claude Code's native line including its context
indicator, so reproduce it from the statusline stdin payload: 'Fable 5 ·
ctx 42%' right after the health segment, with native color thresholds
(<70% dim, 70-89% yellow, >=90% red). Falls back from used_percentage to
remaining_percentage to token counts, and stays visible in bypass mode
since it describes the CC conversation, not OV. Opt out with
OPENVIKING_STATUSLINE_CTX=off. Line cap raised 80 -> 100 visible chars.

* fix(installer): keep checkout progress off stdout in plugin_dir_on_disk

Callers capture the function's stdout, so ensure_checkout's info lines were
concatenated into the statusline command registered in settings.json.

* fix(installer): re-register codex git marketplace instead of upgrading

Codex doesn't expose which --ref a git marketplace was added with, and
'marketplace upgrade' refreshes the old ref — so a URL match must not skip
re-registration or a ref override installs the wrong snapshot. Also remove
the stale pre-unification plugin cache directory during migration.

* fix(installer): include .agents in codex sparse checkout

A plugin-dir-only sparse checkout omits the repo-root marketplace manifest
and fails with 'marketplace root does not contain a supported manifest'.
Adding --sparse .agents keeps the snapshot slim (~7.5M vs full repo).

* feat(installer): bilingual prompts, dist channel selection, and TOS git marketplace for codex

- Interactive language selection (English/中文, --lang, auto-detected from
  locale); every user-facing prompt is bilingual.
- Download-source selection (--dist github|tos, prompted interactively):
  github keeps the remote marketplaces; tos serves GitHub-blocked regions.
- Credentials step now always shows the current ovcli.conf values (masked
  key) and offers keep-or-reconfigure instead of silently reusing them.
- Codex on TOS installs from a TOS-hosted git repo over dumb HTTP and keeps
  remote updates (codex plugin marketplace upgrade); falls back to the
  archive directory if the repo is unavailable. release-tos.yml builds and
  uploads the single-commit bare repo (repack + update-server-info).
- Claude Code on TOS warns that directory marketplaces cannot auto-update.
- tos-install.sh bootstraps shrink to TOS_BASE + --dist tos.
- Docs (READMEs, agent-integrations pages, image cards, en+zh) now all use
  the single shared installer and drop the deleted wrapper instructions.

* feat(installer): unify all choice prompts on an arrow-key TUI menu

Language, download source, connection mode, keep-or-reconfigure
credentials, statusline enable/replace, and legacy-mode confirmation all
render as the same single-select menu (arrow keys / digit shortcuts /
enter, radio-style highlight) instead of mixed numbered and y/N prompts.
Falls back to numbered input when /dev/tty can't be drawn on and to the
default choice when non-interactive. Free-text fields (URL, API key) stay
line inputs; the harness picker keeps its checkbox multi-select.

* fix(installer): stop piping plugin lists into grep -q under pipefail

grep -q exits on first match and SIGPIPEs the producer, so with pipefail
the 'codex plugin list | grep -q' check read as a miss every time (codex's
list is long; claude's short list masked the bug). Capture the output and
substring-match in bash instead — validation no longer false-warns.

Also: drop the stdio-proxy line from the Done summary; always offer the
install-source menu unless --dist/--source was given (with a checkout the
menu gains a dev option and defaults to it); surface the Claude-on-TOS
no-auto-update warning at source resolution instead of after install.

* fix: unignore examples/memory-plugin-shared/lib and commit the shared modules

The Python build-artifact 'lib/' gitignore rule silently swallowed the
shared plugin module source, so CI checkouts had only the vendored copies
and sync.test.mjs failed with ENOENT on the source directory.

* fix(recall): budget summary/uri fallbacks and sanitize non-finite scores

max_chars is the recall API's contract, but only full fragments counted
toward it — VikingBot's client-side heuristic, faithfully ported, lets
summary and uri fallbacks render far past the budget (repro: max_chars=100
rendered 548 chars). Every fragment now counts; oversized summaries degrade
to uri fragments and entries that can't even fit a uri line are dropped
(reported via stats.dropped). VikingBot itself is intentionally unchanged.

Also run _sanitize_floats over the /recall response like the neighboring
/find and /search routes, so inf/nan scores return 0.0 instead of a 500.
2026-07-07 12:33:59 +08:00
Qin Haojie a8b9ff57cd docs: clarify OpenCode integration setup (#3053) 2026-07-07 12:14:40 +08:00
t0sakiandbaobaodae 72d04cd488 feat(ingest): replay local agent-harness logs into OpenViking sessions (#2892)
* feat(ingest): replay local agent-harness logs into OV sessions / 本地 agent harness 日志重放入库

Add openviking/ingest/: parse Claude Code / Codex / OpenCode / Hermes / OpenClaw conversation logs into normalized messages and replay them through OpenViking's existing session pipeline (create_session -> batch_add_messages -> commit -> async memory extraction), instead of a bespoke ETL.

Supports one-shot backfill ("存量") and cursor-driven incremental polling ("新增", WatchScheduler-style, no fs-event dependency), per-harness enable/mode/paths config, and meaningful peer_id on every turn (assistant = {harness}/{model}; user = git identity for single-user harnesses, original username for group-chat harnesses). Cursor IDE is a registered but deferred stub.

Read-position cursors persist under ~/.openviking/ingest/state.db for crash-safe, idempotent resume. New openviking-ingest CLI (backfill/watch/run/status/list-sources) and an "ingest" section on OpenVikingConfig. Verified end-to-end against a local server: 3-message fixture -> session commit -> 10 memories extracted -> idempotent re-run.

Inspired by / supersedes volcengine/OpenViking#2674.

Co-authored-by: baobaodae <2014596548@qq.com>

* docs(ingest): bilingual guide + ov.conf.example for openviking-ingest / 本地日志入库双语文档与配置示例

Add docs/{zh,en}/agent-integrations/09-log-ingestion.md (auto-registered in the VitePress sidebar) and an `ingest` section in examples/ov.conf.example (off by default).

* fix(ingest): address review — gating, crash-safe batch replay, commit recovery, single-instance lock / 修复评审问题

Fixes the merge-blockers from the adversarial review:
- master switch ingest.enabled now actually gates enabled_harnesses();
- idempotent per-batch append with a durable pending-intent reconciled against the server message count on restart (no duplicate imports after a mid-append crash);
- bounded reads (<=100 msgs/call) so huge sessions don't materialize at once;
- needs_commit flag + commit_if_needed so appended-but-uncommitted sessions still get extracted (commit even when no new source rows);
- poller keeps dirty sessions until a commit actually succeeds;
- OpenCode advances its SQLite cursor only past complete rows (late part text no longer skipped);
- single-instance file lock guards concurrent ingest processes;
- positive-value config validation (no poll busy-loop); malformed ov.conf surfaces instead of silently defaulting.

Adds 6 tests (config gating/validation, crash reconcile both ways, commit recovery).

* refactor(ingest): expose as 'openviking-server ingest' subcommand; English-only code/docs

- Route the ingest CLI through 'openviking-server ingest ...' (same dispatch as 'init'/'doctor') and drop the separate 'openviking-ingest' console_script.
- Remove mixed-in Chinese terms (存量/新增) from source docstrings, CLI help, and the English doc; the Chinese doc keeps them.

* style(ingest): ruff format + import sort (isort I)

Run ruff 0.15.16 (from the uv cache) with the repo config: fixes 5 I001 import-order errors in tests and reformats 9 files. 'ruff check' and 'ruff format --check' now pass on all added/edited files.

---------

Co-authored-by: baobaodae <2014596548@qq.com>
2026-06-30 12:14:31 +08:00
t0saki 2c1c8bc785 docs(codex): revert #2879 doc changes; demote marketplace to local-only (#2901)
#2879 added a Codex marketplace section to the English integration docs. Revert
those docs-only additions so docs/ matches the pre-#2879 state — no marketplace
content in the agent-integration pages.

Keep the marketplace path in the plugin README, but demote it: it is local-only
(unauthenticated http://127.0.0.1:1933), does not support authenticated or
remote/cloud servers, and is not recommended. Reorder the Quick Start so the
one-line installer is path A (recommended, supports remote/cloud) and the
marketplace install is path B (local-only, not recommended).
2026-06-30 12:10:49 +08:00
LinQiang391andLinQiang391 8708debe10 feat(codex): support upstream marketplace install (#2879)
Co-authored-by: LinQiang391 <linqiang391@users.noreply.github.com>
2026-06-30 11:22:41 +08:00
Zayn Jarvis e43a4c5e6e ci(opencode-plugin): publish scoped npm package (#2807)
* fix(opencode-plugin): use js source install wrapper

* ci(opencode-plugin): publish scoped npm package
2026-06-24 21:21:57 +08:00
Zayn Jarvis 5e622ba6ea docs(plugin): keep one OpenCode plugin (#2540)
* docs(plugin): keep one OpenCode plugin

* docs(opencode): expand plugin install guide
2026-06-22 10:26:46 +08:00
Evo 38430aa20d docs(hermes): update OpenViking peer identity wording (#2686) 2026-06-17 20:48:51 +08:00
Zayn Jarvis c6990e4cd6 [codex] tighten memory recall, capture, and resume (#2598)
* Fix Codex memory hook recall noise and stop timeouts

* Tighten Codex recall compression output

* Add Codex archive resume and capture filtering

* Wrap Codex memory injection for capture filtering

* Detect Codex recall compressor profile

* Refresh Codex compressor profile on startup

* fix codex ov credential resolution

* [codex] resolve compressor profile via models_cache.json, not codex exec probe

SessionStart used to spawn 'codex exec' sequentially against each
candidate model to detect which one would respond — up to 3 probes ×
~15s timeout each, on every session start, even on resume. The
configured-on-startup default made this a guaranteed first-page-load
tax of several seconds.

Replace the probe with a lookup against codex's own model catalogue
(~/.codex/models_cache.json, refreshed by codex CLI's etag-backed
fetch). The first candidate whose slug is present wins. SessionStart
now goes cache-first: load the persisted profile if any, only resolve
on cache miss. The runtime compress path (auto-recall) deletes the
cached profile on any compress failure so the next SessionStart
re-resolves against the current catalogue.

- recall-compressor-profile.mjs:
  * loadCodexModelsCache(env) reads ~/.codex/models_cache.json; missing
    cache yields {present:false,slugs:Set()}.
  * resolveRecallCompressorProfile picks the first available candidate
    by slug; falls back optimistically to the first candidate when
    the catalogue is missing.
  * invalidateRecallCompressorProfileCache() rms the persisted file.
  * detectRecallCompressorProfile is now cache-first and never spawns.
- auto-recall.mjs: runCodexCompressor invalidates the cache on spawn
  error, timeout, non-zero exit, and read failure (best-effort,
  no error surface to user).
- recall-compressor-profile.test.mjs: 11 unit tests covering catalogue
  read, candidate selection (with/without configured first), missing
  catalogue fallback, configured_off path, invalidate, cache-first
  detect, and re-resolve after invalidate.

Notes:
- buildCodexExecArgs is still exported so auto-recall can spawn the
  actual compress run; the change only removes the *probe* spawn, not
  the compress spawn.
- recallCompressDetectTtlMs and recallCompressDetectTimeoutMs are
  preserved in config for back-compat; the timeout no longer matters
  but the TTL still bounds how stale a cached profile may be.

* [codex] omit X-OpenViking-Actor-Peer env_http_headers when no peer configured

syncMcpConfig used to unconditionally write all three OV header→env
mappings. The wrapper strips empty OPENVIKING_PEER_ID before exec'ing
codex, so an unset env var would silently flip the header to "" — the
OV side then has to disambiguate that from "no peer scope". Match the
bearer_token_env_var pattern: present only when there's something to
send. Also drops a stale X-OpenViking-Actor-Peer entry when the peer
is unset (e.g. after switching ovcli configs).

- Existing test 4 became two cases: with-peer keeps the mapping,
  without-peer drops it (symmetric to bearer).
- New test asserts an in-place drop when the cached .mcp.json had a
  stale peer mapping but the active config no longer has a peer.

* [codex] runtime_failed compressor marker stops same-session retry storms

Previous fix invalidated the profile cache on compress failure. Within a
single codex session that still bled `recallCompressTimeoutMs` of wall
time per UserPromptSubmit because the next hook reread cache (miss),
fell back to fallbackRecallCompressorProfile, and tried the same model.

Replace plain invalidate with a runtime_failed sentinel cached in the
profile slot. UserPromptSubmit's compressMemoryContext already short-
circuits on `profile.enabled === false`, so the marker stops further
spawns for the rest of the codex process. The next SessionStart cache-
first detect treats `source === 'runtime_failed'` as cache miss and
re-resolves against the current models_cache.json, so a transient
failure self-recovers across codex restarts without operator action.
detect_on_startup=false respects the marker (no auto-recover, matches
the "manual control" intent of that flag).

- recall-compressor-profile.mjs:
  * markRecallCompressorRuntimeFailed(cfg, {failedModel}) writes the
    disabled sentinel.
  * detectRecallCompressorProfile branches on cached.source ===
    'runtime_failed': cache hit otherwise, recover-via-resolve when
    startup-detect on, respect marker when off.
- auto-recall.mjs::runCodexCompressor: swap invalidate-on-error with
  markRecallCompressorRuntimeFailed(cfg, {failedModel: profile.model}).
- recall-compressor-profile.test.mjs: 4 new tests covering marker
  write, cross-restart recovery picking a different slug, and the
  detect_on_startup=false honor path. 20/20 pass.

invalidateRecallCompressorProfileCache is kept as a public API for
explicit operator use (e.g. a future `ov codex reset-compressor`
command), but is no longer called from the runtime path.
2026-06-16 02:05:18 +08:00
t0saki aca58bf3b9 feat: TOS release upload + GitHub-free install path for memory plugins (#2575)
* ci: upload source zip and plugin installers to TOS on release

Add a standalone workflow (20. Release TOS Upload) that runs on release
publish (or manual dispatch with a tag for backfill) and uploads:

- the source archive to releases/<tag>/ and releases/latest/
- both memory-plugin install.sh scripts to versioned paths and to
  stable root paths for a China-reachable one-liner URL

Reuses the existing TOS secrets (AK/SK/region/endpoint) with a new
TOS_RELEASE_BUCKET secret so release artifacts stay out of the docs
bucket. Missing secrets skip gracefully (fork-friendly); real upload
failures fail the workflow.

* ci: server-side copy for the latest source zip

* feat(plugins): GitHub-free TOS install path for memory plugins

Domestic users can't reach github.com / raw.githubusercontent.com, so the
existing one-liner installers stall at their step-3 `git clone`. Add a
GitHub-free path that sources everything from Volcengine TOS:

- Both install.sh learn OPENVIKING_REPO_ARCHIVE_URL: when set, fetch the
  source from a zip (curl + unzip) instead of git clone. A
  .openviking-archive-source marker makes re-runs idempotent and refuses
  to clobber a git checkout or unrelated data at REPO_DIR.
- New setup-helper/tos-install.sh bootstrap per plugin: sets the TOS
  archive URL, downloads the real install.sh from TOS to a temp file
  (kept off the stdin pipe so prompts stay interactive), and delegates.
- release-tos.yml uploads both tos-install.sh alongside install.sh.

One-liner for users behind the GFW:
  bash <(curl -fsSL https://ovrelease.tos-cn-beijing.volces.com/claude-code-memory-plugin/tos-install.sh)

The GitHub default path is unchanged; archive mode only activates when
OPENVIKING_REPO_ARCHIVE_URL is set.

* docs: document the TOS (GitHub-free) install path for memory plugins

Main agent-integration docs (zh/en, claude-code + codex) keep the GitHub
one-liner and add the TOS equivalent for regions where GitHub is hard to
reach. The CDN integration cards switch their install one-liner to the TOS
bootstrap only, since that gallery is served where GitHub raw is unreliable.

* docs: trim the TOS install note to one line
2026-06-15 14:20:09 +08:00
Qin Haojie 49e4d76913 feat(core): add actor peer filesystem view (#2594)
* feat(core): enforce actor scoped retrieval

* fix(core): narrow actor peer filtering to retrieval

* fix(core): enforce actor peer filesystem view
2026-06-13 15:49:34 +08:00
t0saki 7237ac611c fix(plugins): skip shell aliases when wrapping extra launch commands (#2471)
Adding a shell-alias name (e.g. `cc` from `alias cc=claude`) to
OPENVIKING_CC_WRAP_EXTRA / OPENVIKING_CODEX_WRAP_EXTRA broke the wrapper:
bash expands the alias mid-eval and clobbers the base `claude`/`codex`
function (so `command cc` ends up running the C compiler), while zsh
aborts with a parse error on every shell start. Guard the wrapper-defining
loop to skip names that are already shell aliases — an alias already
routes through the base wrapper once it expands, so it needs no function.
Also reject heads starting with `-`, which `alias`/`command` would
otherwise misparse as an option.

Also document the custom-launch-command feature and the alias guidance:
- 8 agent-integration docs (en/zh main + CDN cards): brief install note,
  plus two troubleshooting rows (wrapper-not-sourced, alias gap)
- claude/codex plugin READMEs (+ README_CN, which was missing the section
  entirely): wrap the real target command, never the alias name
2026-06-06 12:40:14 +08:00
Evo 863f68db97 docs(openclaw): document autoRecallTimeoutMs config in integration guide (#2391) (#2472)
* docs(openclaw): document autoRecallTimeoutMs config in integration guide (#2391)

* docs(openclaw): document autoRecallTimeoutMs config in integration guide (#2391)
2026-06-06 10:17:44 +08:00
Hao Zhe ed2e5483c5 feat(cli): rename config providers (#2463)
* feat: rename ov config providers

* fix: align config provider JSON labels
2026-06-05 18:24:41 +08:00
t0saki 0f6160edaf docs: refresh Claude Code & Codex memory plugin integration docs (#2457)
* docs: refresh Claude Code & Codex memory plugin integration docs

- Fix dead anchor #1-wrap-claude-to-inject-env-from-ovcliconf -> #configuring-mcp
  in the Claude Code manual setup (zh/en agent-integrations + CDN cards)
- Add the post-install wrapper activation step (source .../wrapper.sh) to the
  Claude Code docs, and make Codex's activation shell-agnostic
  (source ~/.zshrc -> source .../codex-memory-plugin/setup-helper/wrapper.sh)
- Rewrite Claude Code manual step 1 to the guarded `source wrapper.sh` form
- Convert Claude Code "How it works" into a lifecycle bullet list
- Language polish pass across all eight Claude Code / Codex docs
- Sync docs/images/agents/zh/index.json summaries with the refreshed intros

* docs: foolproof the verify step against an inactive wrapper

Add a guard note to the Verify section of every Claude Code / Codex doc:
if `type claude` / `type codex` prints a path instead of "shell function",
the wrapper isn't active, so re-source it (or open a new terminal) before
launching — otherwise Claude Code silently connects to 127.0.0.1 with no
auth, and Codex starts without OPENVIKING_API_KEY and reports
"MCP server is not logged in". For Claude Code, also state explicitly to
launch `claude` from the terminal where the wrapper is active.

Applies to all eight surfaces (zh/en, agent-integrations guides + CDN cards).
2026-06-05 15:52:39 +08:00
Qin Haojie ff258768c2 feat(memory): 引入 User/Peer 记忆隔离模型 (#2236)
* feat(memory): introduce user and peer memory isolation

Unify agent-scoped memory behavior into user-owned memory spaces, add peer_id compatibility for session and retrieval paths, and wire memory_policy through session commit flows.

* feat(memory): align session identity around peer IDs

* feat(search): pass peer id through retrieval

* refactor(memory): remove agent identity from integrations

* fix(memory): isolate peer identity from self extraction

* fix(tau2): provision benchmark user configs

* fix(auth): allow admin keys to access data APIs

* fix(openclaw): enable peer memory policy for peer roles

* fix(openclaw): resolve sender for peer recall

* refactor(session): simplify memory extraction routing

* refactor(ov-cli): reduce formatting-only diff

* refactor(message): remove unused message helpers

* refactor(retrieval): simplify peer target resolution

* refactor(namespace): remove deprecated agent namespace policy

* fix(agent): propagate peer id through integrations

* fix(auth): align integration clients with api-key mode
2026-06-05 10:55:48 +08:00
yufeng f627a09662 docs: fix Claude agent documentation links (#2443) 2026-06-04 21:36:52 +08:00
t0saki 77a2ee88c3 docs: overhaul agent-integrations section (#2217)
* docs: overhaul agent-integrations section for clarity and beginner-friendliness

Restructure the agent-integrations documentation (EN + ZH) to be concise,
beginner-friendly, and consistently structured across all runtimes.

* docs(mcp-clients): clarify OAuth flow for Claude Desktop / Claude.ai

* docs(mcp-clients): add public access guide link for OAuth section

* docs: address review — clarify dev-mode auth, add missing import

* docs(mcp-guide): update verified platforms, fix OAuth section scope
2026-05-25 17:15:05 +08:00
t0saki 415eaa0692 docs: add AstrBot plugin to agent integrations (#2211) 2026-05-24 22:01:35 +08:00
LinQiang391andCursor 87039cac4c docs(openclaw): align plugin docs with ClawHub standard install experience (#2150)
Use explicit clawhub: prefix across all install paths (README, INSTALL, INSTALL-ZH, INSTALL-AGENT, SKILL.md) since bare specs resolve to npm on current OpenClaw. Restructure ClawHub README with Quick Start first screen, How It Works, Tools table, Data Flow and Privacy section. Move engineering details into collapsible section. Demote ov-install to fallback. Fix ov-install params, OpenClaw min version, and parameter table. Allow images in ClawHub bundle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 20:15:23 +08:00
LinQiang391andLinQiang391 933ece4acb docs(openclaw): use canonical OpenViking plugin package (#2099)
Co-authored-by: LinQiang391 <linqiang391@users.noreply.github.com>
2026-05-18 10:55:01 +08:00
Evo bc8fe8be67 docs(openclaw): document plugin-source / plugin-package and plugin-version auto-detect from #2072 (#2077)
* docs(openclaw): document plugin-source / plugin-package and plugin-version auto-detect from #2072 (en)

* docs(openclaw): document plugin-source / plugin-package and plugin-version auto-detect from #2072 (zh)
2026-05-15 20:44:49 +08:00
t0saki 42484bf91d fix(plugin/codex): default-on assistant capture, recommend env vars over ov.conf for tuning (#2065)
Two related fixes to plugin tuning ergonomics:

1. `captureAssistantTurns` defaults to true (mirrors claude-code-memory-plugin).
   A memory plugin that only captures the user side of every turn extracts
   half the conversation and produces noticeably worse memories. Operators
   who want the old user-only behavior can still set
   `OPENVIKING_CAPTURE_ASSISTANT_TURNS=0` or `codex.captureAssistantTurns=false`.

2. README + agent-integrations docs (zh+en) now recommend `OPENVIKING_*`
   environment variables in shell rc as the primary way to tune the plugin.
   The previous docs claimed the tuning block lived in `ovcli.conf`, but
   `scripts/config.mjs` only reads `codex.*` from `ov.conf` — and `ov.conf`
   is server-scope, so per-machine plugin tuning doesn't belong there
   anyway. The legacy `ov.conf` path is acknowledged and kept working for
   backward compat, but de-emphasized.
2026-05-15 13:07:33 +08:00
t0saki c73a32f270 fix(plugin/codex): allow empty api_key (unauthenticated local OV) (#2023)
* fix(plugin/codex): allow empty api_key (unauthenticated local OV)

Reported: with an ovcli.conf that has no `api_key` (typical local OV
without auth), the plugin would not start cleanly. Root cause: .mcp.json
ships with `bearer_token_env_var: "OPENVIKING_API_KEY"`, and when that
env var resolves to an empty string at codex launch (because ovcli.conf
has no key), Codex interprets it as "auth configured but not provided"
and falls back to its OAuth dance — which then fails against an OV that
doesn't speak OAuth.

Hook side is unaffected: scripts/config.mjs already gates the Bearer
header on `if (cfg.apiKey)`, so empty api_key → no Authorization header
sent → OV accepts in unauth mode. Verified end-to-end with auto-recall
against `http://127.0.0.1:1933` and an empty-key ovcli.conf.

Fix: at install time, detect whether ANY api_key is configured (env or
ovcli.conf) and conditionally render `.mcp.json` *with or without*
`bearer_token_env_var`:

  - api_key present → keep `bearer_token_env_var: "OPENVIKING_API_KEY"`
  - api_key absent  → drop the field entirely (Codex will then just hit
                      OV without Authorization and treat 200 as success)

Implementation uses node (already required) to read/edit the cached
.mcp.json as proper JSON rather than sed, so we don't have to worry
about field-position-dependent regexes.

Installer footer now also reports the resolved auth mode so the user
sees `MCP auth: Bearer (OPENVIKING_API_KEY)` vs `MCP auth: none
(unauthenticated)` at the end of the run.

env_http_headers stays in both modes — identity headers
(X-OpenViking-Account / User / Agent) are independent of auth and OV
accepts empty values (defaults to "default").

* fix(plugin/codex): support runtime OPENVIKING_CLI_CONFIG_FILE swap

Reported: setting OPENVIKING_CLI_CONFIG_FILE=ovcli-local.conf (a config
without api_key, for benchmark-memory isolation) and running codex fails
with:

  Environment variable OPENVIKING_API_KEY for MCP server 'openviking-memory'
  is empty

Two issues stacked on top of each other:

1. Codex 0.130 hard-fails MCP startup when bearer_token_env_var resolves
   to an EMPTY env var (confirmed empirically — not OAuth fallback, just
   a startup error).

2. The previous codex() wrapper exported `OPENVIKING_API_KEY=""` via the
   inline-prefix syntax `OPENVIKING_API_KEY="${...:-${...:-}}" codex`,
   which sets the variable to an empty string when no key is resolvable.
   So even my prior fix (don't render bearer_token_env_var when no key
   at install time) didn't help users who install with one conf and run
   with another via OPENVIKING_CLI_CONFIG_FILE.

Fix is two parts:

a) Build the env prefix dynamically into a bash array, skipping any
   OPENVIKING_* whose resolved value is empty. So an empty api_key
   produces no OPENVIKING_API_KEY at all in codex's env — neither
   set-to-empty nor set-to-something.

b) Have the wrapper re-render the cached .mcp.json's bearer_token_env_var
   on every codex launch based on the currently-active ovcli.conf. The
   idempotent fast-path skips writing when the desired state already
   matches. This makes swapping configs at runtime (typical benchmark
   isolation workflow) work without re-running the installer.

The wrapper now uses `env "${_env_args[@]}" codex "$@"` instead of the
inline-prefix form for the same reason — proper handling of conditional
env-var presence.

Manual setup snippets in README + docs (en/zh) updated to the same
empty-aware pattern; the cache-rendering bit is left to the installer-
emitted wrapper since it's noisy and only needed when actually swapping
configs.

Validated with synthetic test:

  ovcli-local.conf (no api_key)
    → env passed to codex: URL=..., ACCOUNT=..., USER=..., AGENT_ID=codex
      (no OPENVIKING_API_KEY at all)
    → cache .mcp.json rewritten to drop bearer_token_env_var

  ovcli.conf (with api_key)
    → env passed to codex: URL=..., API_KEY=..., ACCOUNT=..., USER=..., AGENT_ID=codex
    → cache .mcp.json rewritten to re-add bearer_token_env_var

  Idempotent: re-render with same hasKey state does not bump file mtime.

* fix(plugin/codex): wrapper also re-renders cache .mcp.json URL

Previously the codex() wrapper only re-rendered bearer_token_env_var
based on the active ovcli.conf, but the cached .mcp.json URL stayed
whatever was baked at install time. Result: swapping
OPENVIKING_CLI_CONFIG_FILE to a config that points at a different OV
server (e.g. localhost) would still hit the install-time URL —
typically the remote production OV — and fail auth.

Reported in testing:

  OPENVIKING_CLI_CONFIG_FILE=ovcli-local.conf codex
  # ovcli-local.conf: { "url": "http://127.0.0.1:1933" }
  # cache .mcp.json still says url=https://ov-dev.tosaki.top/mcp
  # Codex hits remote ov-dev with no bearer → 401 → "Not logged in" OAuth dance

Fix: the rewrite block now also patches s.url from the conf-resolved
URL (`${_ov_url%/}/mcp`, or `$OPENVIKING_MCP_URL` if explicitly set).
Same idempotent fast-path — only writes when something actually changed.

Tested both directions:
  ovcli-local.conf (no key, localhost)
    → cache .mcp.json: url=http://127.0.0.1:1933/mcp, no bearer field
    → env passed to codex: no OPENVIKING_API_KEY
    → /mcp: Auth: None, tools list populated
  ovcli.conf (with key, remote)
    → cache .mcp.json: url=https://ov-dev.tosaki.top/mcp, bearer present
    → /mcp: Auth: Bearer token, tools list populated
2026-05-13 21:40:30 +08:00
t0saki b0076110ae refactor(plugin/codex): switch MCP from local stdio to OV /mcp directly (#2022)
* refactor(plugin/codex): switch MCP from local stdio server to OV /mcp (http)

Codex 0.130 supports streamable-HTTP MCP servers with bearer auth via
`bearer_token_env_var` in `.mcp.json` (and per-header env binding via
`env_http_headers`). OpenViking server has exposed `/mcp` natively since
1.27, so the local stdio MCP middleman (`src/memory-server.ts` +
`servers/memory-server.js` + the npm-ci runtime bootstrap) is dead weight:
the model now gets a strictly larger tool set (search, store, read, list,
grep, glob, forget, add_resource, health — vs the previous recall/store/
forget/health) by talking to OV directly, and the plugin loses its only
build/dependency surface.

What changed

- `.mcp.json`: switched to `url` + `bearer_token_env_var: "OPENVIKING_API_KEY"`
  + `env_http_headers` for the multi-tenant identity headers. URL is a
  `__OPENVIKING_MCP_URL__` placeholder; installer renders it from ovcli.conf
  / `OPENVIKING_URL` at install time. API key never lands on disk in the
  cached .mcp.json — it's pulled from process env at codex launch.

- `setup-helper/install.sh`: resolves the OV /mcp URL (OPENVIKING_MCP_URL >
  OPENVIKING_URL/mcp > ovcli.conf.url/mcp > localhost), renders the
  .mcp.json placeholder into the cached copy, and appends a `codex()` shell
  function wrapper to the user's rc that promotes ovcli.conf fields into
  env vars before exec'ing codex (mirrors the claude-code-memory-plugin
  pattern; needed because Codex reads OPENVIKING_API_KEY from process env
  at MCP launch, not from any file).

- Deleted: `src/memory-server.ts`, `servers/memory-server.js`, `tsconfig.json`,
  `package.json`, `package-lock.json`, `scripts/bootstrap-runtime.mjs`,
  `scripts/runtime-common.mjs`, `scripts/start-memory-server.mjs`. Net
  ~2400 lines removed. Hook scripts remain zero-dep .mjs running on
  Codex's bundled Node 22.

- README + docs/{en,zh}/agent-integrations/04-codex.md: rewritten to
  describe the new architecture. The MCP tools list and protocol details
  are now referenced via a link to docs/{en,zh}/guides/06-mcp-integration.md
  rather than duplicated in the plugin docs.

- Plugin version: 0.4.1 → 0.5.0.

Validation

Verified end-to-end on Codex 0.130 against `ov-dev.tosaki.top`:

  /mcp
  🔌 MCP Tools
    • openviking-memory
      • Auth: Bearer token
      • Tools: add_resource, forget, glob, grep, health, list, read, search, store

`openviking-memory.health` returned `OpenViking is healthy ... storage: VikingFS`;
Stop hook reported `appended 2 turn(s) to OpenViking session <id>`.

Notes

- `.mcp.json` headers that don't have a corresponding env var (e.g. user
  didn't set `OPENVIKING_USER`) are simply not sent — `env_http_headers`
  silently omits missing vars per Codex's MCP runtime.
- Rotating the API key now just needs `codex` restart (env re-reads from
  ovcli.conf via the wrapper). URL changes still need a re-install since
  the URL is baked into the cached .mcp.json.
- The shell function wrapper has a marker-delimited block so re-running
  the installer replaces it in place rather than appending duplicates.

* review(plugin/codex): address copilot feedback on installer + docs

1. Switch the codex() shell-function wrapper from jq to node. The installer
   already hard-requires node 22+, while jq is not always present; the old
   wrapper would silently fall through to `command codex` with no env
   injection when jq was missing, which caused Codex to start with no
   Bearer token, OV to return 401, and Codex to drop into its OAuth
   fallback. Now there is a single tool dependency for both the installer
   and the wrapper it emits.

2. Marker-replacement is now defensive: rewrite-in-place only triggers
   when BOTH the BEGIN and END markers exist in the rc. If only BEGIN
   is present (manual edit / corruption), warn and append a fresh block
   instead of awk-dropping everything from BEGIN to EOF.

3. When no rc is detected, omit the `source $RC` line from the final
   "Next:" hint and tell the user to paste the snippet manually instead
   of printing `source ` with a trailing space.

4. Docs (README + 04-codex.md zh/en): use the full env var names
   (OPENVIKING_API_KEY / OPENVIKING_ACCOUNT / OPENVIKING_USER /
   OPENVIKING_AGENT_ID) instead of `_ACCOUNT` / `_USER` shorthand;
   update the manual-setup snippets to the node-based wrapper.

The wrapper body is now defined once and reused for both the appended-to-rc
path and the manual-paste path, so the two cannot drift.
2026-05-13 21:08:57 +08:00
t0saki 8034abc158 docs(plugin/codex): dedicated agent-integrations page (zh+en) + fix MCP startup (#2019)
* docs(plugin/codex): add dedicated agent-integrations page + fix MCP startup

Follow-up to #1957. Lifts Codex out of `04-other-plugins.md` into its own
`04-codex.md` (en + zh) with full install steps, configuration, hook
behavior, and troubleshooting — mirrors the shape of `02-claude-code.md`.

Renumbers `04-other-plugins.md` → `05-` and `05-langchain-langgraph.md`
→ `06-`. Overview tables in both locales updated; cross-refs fixed.

Also fixes two install/runtime bugs surfaced while validating the fresh
installer flow against the merged PR:

1. **Stale repo clone**: `setup-helper/install.sh` previously skipped the
   clone if `~/.openviking/openviking-repo` already existed, so a user
   who installed before #1957 merged ended up with a pre-PR plugin
   checkout (no `scripts/`, no `servers/memory-server.js`). The installer
   now `git fetch + reset --hard` an existing checkout to `$REPO_REF`
   (default `main`), matching the claude-code installer pattern.

2. **`${CODEX_PLUGIN_ROOT}` not expanded in `.mcp.json`**: Codex 0.130
   does not substitute env vars in `.mcp.json` `args`/`env` and does not
   always inject `CODEX_PLUGIN_ROOT` into MCP child env. The literal
   string `${CODEX_PLUGIN_ROOT}` was being passed to node, which then
   tried to resolve `${CODEX_PLUGIN_ROOT}/scripts/start-memory-server.mjs`
   against codex's cwd and failed with `MODULE_NOT_FOUND`. Fix:
   - `.mcp.json`: `args: ["scripts/start-memory-server.mjs"]` + `cwd: "."`
     (matches the syntax 0.1.0 used, which Codex does honor)
   - `scripts/runtime-common.mjs`: derive plugin root from
     `import.meta.url` as a fallback so the launcher works regardless of
     whether `CODEX_PLUGIN_ROOT` is set in the spawn env

Bumps plugin to 0.4.1 (package.json + plugin.json + lockfile) since the
runtime-common.mjs change invalidates the install-state hash and forces
a re-install of node_modules into the per-user runtime data root.

* fix(plugin/codex): hooks.json must use relative paths, not ${CODEX_PLUGIN_ROOT}

Same root cause as the .mcp.json fix in the previous commit: Codex 0.130
does not expand ${CODEX_PLUGIN_ROOT} in hooks.json `command` strings. The
shell that runs the hook sees the literal ${CODEX_PLUGIN_ROOT} and expands
it to "" (or leaves it literal), so node tries to load `/scripts/...mjs`
and exits 1.

Symptom in the chat UI:
  • SessionStart hook (failed)  error: hook exited with code 1
  • UserPromptSubmit hook (failed)
  • Stop hook (failed)

Fix: use `./scripts/<name>.mjs` paths, matching the pattern Codex's own
bundled plugins (e.g. figma) use. Codex's hook dispatcher resolves these
relative to the plugin root (where hooks.json lives).

The MCP launcher fix from the prior commit already handles the same class
of bug for .mcp.json; this catches the hooks path.

* fix(plugin/codex): hooks.json needs absolute paths rendered at install time

Previous fix (relative ./scripts/...) was based on the figma example but
empirically does not work on Codex 0.130: the hook subprocess runs with
cwd = user's cwd (not plugin root) and CODEX_PLUGIN_ROOT is NOT injected
into the env. So both ${CODEX_PLUGIN_ROOT}/scripts/foo.mjs and
./scripts/foo.mjs resolve to the wrong absolute path and node exits 1.

Verified with a probe shell script wired into hooks.json:
  argv: /tmp/codex-hook-probe.sh SessionStart
  cwd: /Users/<user>
  CODEX_PLUGIN_ROOT: <unset>
  CODEX_PLUGIN_DATA: <unset>

(The "Under-development features are incomplete" banner Codex prints when
plugin_hooks is enabled is real - the hook env wiring is unfinished in
0.130.)

Fix: keep the source hooks.json as a template (uses __OPENVIKING_PLUGIN_ROOT__
placeholder) and have install.sh sed-render the cache copy with the
absolute $CACHE_DIR path on every install. The cached hooks.json is now
fully self-contained absolute-path commands; the repo's checked-in copy
stays portable.

.mcp.json is unaffected: Codex 0.130 does honor the `cwd: "."` field for
MCP servers, so relative args resolve against plugin root there.

* fix(plugin/codex): bump UserPromptSubmit timeout to 15s

Empirically the auto-recall hook can take 0.8s–4s end-to-end (depending on
result count and remote OV latency), and Codex 0.130 sometimes adds 4-5s
of spawn overhead before our script even starts. The original 8s budget
was borderline and produced spurious "hook timed out after 8s" UI errors
on slow paths even when the recall would have succeeded.

15s matches the auto-recall internal timeoutMs default (config.mjs:186)
and gives enough headroom for spawn-time variance without holding the
user's input noticeably longer in the worst case.

* fix(plugin/codex): installer accepts OPENVIKING_REPO_BRANCH as alias

Per review feedback: the claude-code installer uses OPENVIKING_REPO_BRANCH
for the same purpose. Aliasing both names lets users reuse one env var
across installers without remembering which plugin uses which name.

Precedence: OPENVIKING_REPO_REF > OPENVIKING_REPO_BRANCH > "main".
2026-05-13 20:33:36 +08:00
e92180a7e1 feat(plugin/codex): add lifecycle hooks (recall, capture, pre-compact) to codex-memory-plugin (#1957)
* feat(plugin/codex): add lifecycle hooks (recall, capture, pre-compact)

Brings the codex-memory-plugin to feature parity with the claude-code-memory-plugin
by wiring the four Codex lifecycle hooks via `hooks.json`:

- SessionStart  -> bootstrap-runtime.mjs (npm ci into ${CODEX_PLUGIN_DATA}/runtime)
- UserPromptSubmit -> auto-recall.mjs (search OV, inject via hookSpecificOutput.additionalContext)
- Stop -> auto-capture.mjs (incremental transcript capture + last_assistant_message commit)
- PreCompact -> pre-compact-capture.mjs (full transcript -> single OV session -> commit)

Differences from the Claude Code plugin baked into the scripts:

- Codex output schema does not allow `decision: "approve"`; no-op is `{}`
- Stop/PreCompact only support `systemMessage`, not `additionalContext`
- Plugin envs are CODEX_PLUGIN_ROOT / CODEX_PLUGIN_DATA
- Config section is `codex` (was `claude_code`); config file defaults to
  `~/.openviking/ovcli.conf`, falling back to legacy `~/.openviking/ov.conf`

Other changes:

- src/memory-server.ts now reads ovcli.conf-style configs (top-level `url`,
  `api_key`, `account`, `user`, `agent_id`) so the plugin works against
  hosted OpenViking deployments out of the box. Env-var-only operation
  (OPENVIKING_URL set, no config file) is also supported.
- .mcp.json points at scripts/start-memory-server.mjs, which boots the same
  runtime the hooks use, so the MCP path benefits from npm-ci bootstrap.
- README rewritten with architecture diagram, validation SOP, configuration
  reference, and a Codex-vs-Claude-Code differences table.

Validated end-to-end against an OpenViking deployment:

- Auto-recall returns ranked memories with full content and emits
  hookSpecificOutput.additionalContext.
- Auto-capture (last_assistant_message path) creates a session, commits, and
  the OV pipeline extracts events + preferences within ~60s.
- Pre-compact-capture posts a full 4-turn transcript to one OV session,
  commits with archived=true, and produces structured leaf memories
  (preferences, events, entities) under viking://user/<user>/memories/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(plugin/codex): drop SessionStart, split Stop=add_message vs PreCompact=commit

Codex's `Stop` hook fires per turn, not at session end, so committing per-Stop
over-fragments memory extraction. And codex re-fires `SessionStart` on short
reconnects, so registering an `npm ci` bootstrap there reinstalls the runtime
unnecessarily.

This change keeps one long-lived OpenViking session per codex `session_id`
across all `Stop` invocations, and only triggers the OV memory extractor on
`PreCompact` (or via an idle-sweep best-effort commit when codex exits without
compacting).

- hooks.json: drop SessionStart entry; keep UserPromptSubmit/Stop/PreCompact
- scripts/session-state.mjs (new): per-codex-session state under
  ~/.openviking/codex-plugin-state/, tracks ovSessionId + capturedTurnCount
- scripts/auto-capture.mjs (Stop): incremental add_message only, idle-sweep at
  the tail to commit stale codex sessions (default IDLE_TTL=30 min, override
  with OPENVIKING_CODEX_IDLE_TTL_MS)
- scripts/pre-compact-capture.mjs (PreCompact): catch-up append + commit the
  long-lived OV session, then null out ovSessionId so the next Stop opens a
  fresh OV session for the post-compact half
- MCP runtime install stays lazy in start-memory-server.mjs (already there);
  no SessionStart hook means short reconnects don't re-trigger npm ci
- VERIFICATION.md: end-to-end SOP against a live OV server (~3 min)
- bump plugin to 0.3.0

Verified end-to-end against ov.zaynjarvis.com:
  Stop adds turns idempotently and incrementally; PreCompact commits to
  history/archive_001/ with extractor producing memories under
  viking://user/<user>/memories/profile.md after ~30 s; post-compact Stop
  opens a fresh OV session; idle-sweep commits stale state files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(plugin/codex): replace idle-sweep with SessionStart(source=clear) commit

Per Zayn's followup ("非必要不要加 idle commit"): drop the idle-sweep added
in the previous commit and use codex's actual context-disappearing signal —
SessionStart with source=clear — to commit orphaned sessions.

Codex hook signal map:
- /compact         → PreCompact      ✅ commit (already)
- /clear           → SessionStart(source=clear) for the NEW session_id;
                     the prior transcript is orphaned. Now committed.
- /new             → SessionStart(source=startup); ambiguous with fresh
                     codex startup, so we don't act on it.
- /resume / short reconnect → SessionStart(source=resume|startup); no-op
                     to avoid corrupting still-active sessions.
- SIGTERM/Ctrl+C/exit → no hook fires. Documented as a known gap; users
                     should /compact before /exit if they want commit.

Changes:
- new scripts/session-start-commit.mjs: gates internally on source=clear,
  iterates listStates(), and commits any state file whose codexSessionId
  != the new SessionStart session_id, then clears that state file
- hooks/hooks.json: re-register SessionStart pointing at the new script
  (timeout 30s)
- scripts/auto-capture.mjs: remove sweepIdleSessions() and
  IDLE_TTL_MS env handling; Stop is now strictly add_message
- README/VERIFICATION.md: update arch diagram, replace idle-sweep step
  with SessionStart(source=clear) verify (positive + negative paths),
  add "Known gap: SIGTERM/exit are silent" section
- bump to 0.3.1

Verified end-to-end against ov.zaynjarvis.com:
  Stop add+idempotent ✓
  SessionStart source=startup → {} ✓
  SessionStart source=resume → {} ✓
  SessionStart source=clear → committed prior OV session, history/archive_001/
  appeared, profile.md gained "Favorite snack: dark chocolate" within 30 s.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(plugin/codex): SessionStart matcher = "clear" (native dispatcher gate)

Codex's hooks dispatcher matches the SessionStart hook's `matcher` field
against the SessionStart `source` value. Setting matcher to "clear" means
codex won't even spawn our script on `source=startup` or `source=resume`
(short reconnects); we previously gated this in-script. The internal
source check in session-start-commit.mjs is kept as defense-in-depth.

Source: codex-rs/hooks/src/events/session_start.rs `select_handlers(...,
matcher_input: Some(request.source.as_str()))` and
codex-rs/hooks/src/events/common.rs `is_exact_matcher` — "clear" is
all-alphanumeric so it's matched as exact equality, not regex.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(plugin/codex): active-window heuristic + idle-TTL sweep at SessionStart (v0.4.0)

Source of truth: examples/codex-memory-plugin/DESIGN.md (added in this commit).

Behavioral changes:

- SessionStart matcher widens from `clear` to `clear|startup`. Both sources
  run the same active-window heuristic; `resume` is a hard no-op (still fires
  on short reconnects).
- Heuristic (DESIGN.md §3): count state files (excluding new session_id) within
  ACTIVE_WINDOW_MS (default 2 min). 0 → noop, 1 → commit it (just-ended
  session), ≥2 → skip and rely on idle TTL. Tunable via
  OPENVIKING_CODEX_ACTIVE_WINDOW_MS.
- Idle-TTL sweep returns at the tail of session-start-commit.mjs only (not
  every Stop). Default IDLE_TTL_MS = 30 min via OPENVIKING_CODEX_IDLE_TTL_MS.
  Catches SIGTERM/Ctrl+C/`/exit` orphans and the ≥2-active skip path.
- Stop hook deliberately does NOT sweep — state-write-on-every-turn already
  gives us the freshness signal. Marker comment added.
- Stop hook adds post-compact transcript-shrink defense: if
  allTurns.length < state.capturedTurnCount, reset capturedTurnCount = 0.
- Commit-on-failure preserves state everywhere (PreCompact, heuristic,
  idle sweep). A non-2xx /commit no longer clears ovSessionId; the next
  sweep retries.
- session-state.mjs saveState now uses atomic write (tmpfile + rename) for
  crash safety. listStates ignores the brief `<id>.json.tmp` window.

Bump: package.json + .codex-plugin/plugin.json → 0.4.0.

Docs: README "How It Works" gained a DESIGN.md pointer and rewrites the
SessionStart section to reflect heuristic + idle TTL. VERIFICATION.md step 6
now exercises all four heuristic branches (0/1/≥2 active, idle TTL, resume).

Phase-2 resume context inject documented in DESIGN.md but explicitly out of
scope here.

Verified locally with synthetic stdin tests against a fake OV server:
1-active commit, ≥2-active skip, idle TTL sweep, resume noop,
unreachable-server keeps state.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(plugin/codex): align config loading with claude-code plugin

Addresses three review points on PR #1957:

1. Honor OPENVIKING_CLI_CONFIG_FILE for the ovcli.conf override path
   (matches the convention used by `ov` CLI and claude-code-memory-plugin).
   OPENVIKING_CONFIG_FILE stays as the ov.conf override; for backward
   compat it still works when pointed at an ovcli-shaped file.

2. Strict env-first priority for every connection / identity field
   (baseUrl, apiKey, account, user, agentId). Env vars now win over
   ovcli.conf, which wins over ov.conf's codex.* block / server.*,
   which wins over built-in defaults.

3. Unify hook and MCP-server config loading: src/memory-server.ts now
   imports loadConfig from scripts/config.mjs (relative path stays
   valid post-compile because servers/ and scripts/ are siblings),
   eliminating the divergent account/user/agentId fallback chains
   the PR-Agent reviewer flagged.

Auth header: emit Authorization: Bearer (primary, required by OpenViking
Cloud) plus the legacy X-API-Key during the transition window. All six
fetch sites updated (4 hook scripts + memory-server.ts + compiled
servers/memory-server.js).

README: document the new resolution chain, OPENVIKING_CLI_CONFIG_FILE,
OPENVIKING_BEARER_TOKEN alias, and the Authorization: Bearer migration.

* docs(plugin/codex): put installation first

* fix(plugin/codex): harden runtime and capture paths

* docs(plugin/codex): align local marketplace name

* docs(plugin/codex): add one-line installer

* fix(plugin/codex): support branch installer testing

* fix(plugin/codex): keep installer env surface stable

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: zhengxiao.wu <zhengxiao.wu@bytedance.com>
2026-05-13 19:25:30 +08:00
Hao Zhe 81d1b5afd7 feat(langchain): add LangChain and LangGraph context adapters (#1964)
* feat(langchain-langgraph): add adapter primitives

* feat(langchain-langgraph): add context backend lifecycle

* fix(langchain-langgraph): harden context backend integration

* fix(langchain-langgraph): accept canonical store result URIs

* docs(langchain): point users to runnable examples

* docs(langchain): add missing integration examples

* refactor(langchain): address integration review feedback

* fix(langchain): address review-blocking integration bugs

* fix(langchain): honor user ids and safe store filters

* fix(langchain): reject unsupported store TTL writes
2026-05-12 16:28:11 +08:00
Evo b88b9c3baf docs(claude-code): describe session-start profile injection (#1914) (#1962)
* docs(claude-code): describe session-start profile injection from #1914

* docs(claude-code): describe session-start profile injection from #1914 (zh)
2026-05-11 10:41:41 +08:00
Evo 6c58cb18b8 docs(openclaw-plugin): surface openclaw openviking status in Verify section (#1924)
Source: PR #1904 (LinQiang391, merged 2026-05-08T09:38:05Z by qin-ctx) added
two CLI commands to the OpenViking OpenClaw plugin:

- `openclaw openviking setup` — interactive + non-interactive (`--base-url ...`)
  with `--api-key`, `--agent-prefix`, `--account-id`, `--user-id`,
  `--allow-offline`, `--force-slot`, `--reconfigure`, `--zh`, `--json`
- `openclaw openviking status` — `Show current OpenViking plugin status and
  connectivity`, with `--zh`, `--json`

The integration page docs/{en,zh}/agent-integrations/03-openclaw.md was not
touched by #1904; its Verify section still only lists indirect manual checks
(`openclaw config get plugins.slots.contextEngine`, `openclaw logs --follow`,
`cat openviking.log`, `ov-install --current-version`). None of those probe
server compatibility or give a single-command health summary.

This commit adds a small additive intro to Verify in both en + zh that:
- Documents `openclaw openviking status` as the one-shot health check
  (registration, connectivity, version compatibility — calls
  `getStatus(configPath)` + `checkServiceHealth` + `formatCompatRange` per
  examples/openclaw-plugin/commands/setup.ts L590-612).
- Calls out `--json` for automation, with the explicit caveat that
  `setup --json` requires `--base-url` (setup.ts L498 enforces this; without
  the caveat readers may attempt bare `setup --json` and hit
  `--json requires --base-url for non-interactive mode`).
- Leaves all existing manual-signal verifications in place — the original
  steps are still useful for debugging individual layers.
2026-05-09 11:36:13 +08:00
a5649a4d20 chore(agent-tools): converge MCP tool names (#1851)
* chore(agent-tools): converge MCP tool names

Rename model-visible explicit memory tools without adding a new agent HTTP API or changing existing CLI behavior.

Keep OV server /mcp store renamed to remember while preserving its existing session write and commit implementation.

Rename Codex MCP openviking_store to remember and keep its original session create/message/commit/cleanup flow; leave OpenClaw memory_store and ov add-memory unchanged.

Co-authored-by: GPT-5.5 <noreply@openai.com>

* refactor(agent-tools): align MCP and search tool names

Apply the search-tool alignment patch across Codex MCP, OpenClaw, OV MCP docs, and focused tests.

Co-authored-by: wlff123 <wulf234@163.com>

Co-authored-by: GPT-5.5 <noreply@openai.com>

---------

Co-authored-by: GPT-5.5 <noreply@openai.com>
2026-05-08 10:50:20 +08:00
t0saki acec33bb5f fix(server,plugin): readable OV session id + MCP store role_id (#1895)
* refactor(claude-code-plugin): readable OV session id (cc-<uuid>__agent-<id>)

Replace the SHA-256-derived `cc-<hash>` form with a literal embedding of the
CC session_id, so OV/CC ids can be matched by eye instead of via shasum.
Subagent isolation still works by appending `__agent-<agentId>` to the parent
id, preserving lineage in the string itself.

Old `cc-<hash>` sessions are left untouched (no migration); they expire
naturally as users start new CC sessions.

Docs (zh/en) gain a short subsection explaining the format and where to find
the live cc_session_id ↔ ov_session_id pair (~/.openviking/state/last-capture.json).

* fix(server): MCP store now resolves role_id via shared ctx helper

Messages stored through the MCP `store` tool persisted with `role_id=null`
because that path called `Session.add_message` directly, skipping the HTTP
router's `_resolve_message_role_id` fallback (user.user_id for role=user,
user.agent_id for role=assistant).

Lift the resolver onto `RequestContext.resolve_role_id(role, override=None)`
so both call paths share one implementation:
- HTTP `POST /api/v1/sessions/{id}/messages` now calls
  `_ctx.resolve_role_id(request.role, request.role_id)`.
- MCP `store` tool calls `ctx.resolve_role_id(msg.role)` per message.

Drop the now-vestigial `http_request: Request` parameter from the HTTP
add_message handler (the local resolver was the only thing using it).

* fix(server): address copilot review on PR #1895

- identity.py: rename `role` → `message_role` in resolve_role_id signature so
  it doesn't shadow `RequestContext.role` (the authz role). Also adds blank
  line after ToolContext docstring to satisfy ruff format.
- tests/server/test_api_sessions.py: drop now-unused `http_request=...` and
  the `auth_mode` / `api_key_manager` plumbing from `_call_add_message_route`
  helper and its call sites — these were only needed by the resolver's stale
  `http_request` parameter, which the previous commit deleted.
- tests/server/test_mcp_endpoint.py: add regression test asserting MCP `store`
  now passes the resolved role_id (user.user_id for user, user.agent_id for
  assistant) to Session.add_message. Also fixes a pre-existing import bug
  (`list_dir` → `ls`) that was preventing the whole file from being collected.
2026-05-07 19:22:53 +08:00
t0saki 268147d110 feat(claude-code-plugin): OpenViking statusline (opt-in) (#1890)
* feat(claude-code-plugin): add OpenViking statusline (opt-in)

A one-line OV status renders under the CC input box: server health,
last-turn recall stats, pending capture, and queue alerts. Network
calls share a 5 s file cache and have a 250 ms hard timeout so the
statusline never blocks render.

- scripts/statusline.mjs: main entry, ANSI degrade, 80-char cap
- scripts/lib/state.mjs: atomic JSON state writer + TTL reader
- scripts/lib/server-probe.mjs: cached /health (+ /observer/queue)
- auto-recall / auto-capture: write last-recall.json / last-capture.json
- setup-helper/install.sh: opt-in prompt; replace-or-skip for existing
  user statusline; backup + restore-instructions
- bump plugin version 0.2.0 -> 0.3.0

* fix(claude-code-plugin): give /observer/queue its own 250ms budget

Queue probe was sharing the /health 250 ms budget; on remote servers
where /health used 200ms+, the queue probe got ~50ms or was skipped
entirely, so queue_healthy flapped between false (when /health was
fast) and null (when /health was slow). Result: ⚠ queue badge appeared
intermittently even when the queue was consistently unhealthy.

Worst-case statusline latency goes from 250ms to 500ms; typical case
is unchanged (~150ms) since both endpoints respond in tens of ms when
the server is healthy.

* fix(claude-code-plugin): loosen statusline timeout to 1s, show archive count

- 250ms was too aggressive for remote OV servers; ordinary network jitter
  (200-400ms /health) was producing spurious "OV ✗ offline" flicker.
  Bumped to 1s per endpoint. Worst case render is now ~2s but the 5s
  cache amortises this to once per 5s window per session.

- pending_tokens is a sawtooth: it climbs to commit_threshold then snaps
  to 0 on commit. Showing only "X/20k tok" of a long conversation read
  as "we only captured X tokens", which hid the work already archived.
  Now the statusline also shows "N arch" — the running commit_count
  pulled from the OV session metadata. So a long session now shows
  e.g. "✎ 573/20k tok · 2 arch" instead of just "✎ 573/20k tok".

* fix(claude-code-plugin): drop ⚠ queue badge — false-alarm by design

QueueObserver.is_healthy() is derived from QueueManager.has_errors(),
which is `any(q._error_count > 0 for q in queues)`. _error_count is a
lifetime cumulative counter that never resets, so any server with a
single transient embedding failure ever flips is_healthy to false
forever — even when the next 1000 jobs all succeed.

Real example from a production server: 41 jobs processed, 2 historic
errors (95%+ success rate), is_healthy returns false. The badge then
appears constantly for users whose OV experience is fine.

Removing the badge and the second network round-trip. Connectivity
(OV ✓), recall activity (↩ N mem), and capture progress (✎ N/20k arch)
already cover whether OV is functioning end-to-end.

* feat(claude-code-plugin): four new statusline signals

- ↩ N mem (0.92): max recall score appended in parens. Quality hint
  without an extra segment. auto-recall.mjs now writes top_score in
  last-recall.json.

- ✗ N dropped: turns that auto-capture failed to push this batch. Not
  sticky — auto-capture overwrites last-capture.json each Stop hook,
  so transient failures clear themselves on next success. Sustained
  failures stay visible (which is when the user needs to know).

- 🔗 resumed / 🔗 compact: session-start.mjs writes a 1-min TTL
  event when CC source is resume or compact. Lets the user see that
  OV did re-hydrate context across restarts instead of having to
  guess.

- +N today: cross-session daily commit_count. auto-capture maintains
  daily-stats.json (resets on date rollover). Hidden when 0 to keep
  fresh-day mornings unobtrusive. Distinct from per-session "M arch"
  which only counts the current CC session.

Truncation order verified: server → recall → capture → dropped (alert)
→ resumed (info) → today (info). 80-char cap drops the lowest-priority
tail when the line gets crowded.

* fix(claude-code-plugin): drop "tok" unit from statusline size numbers

Recall side: `tokens_used` is a chars/4 heuristic (estimateTokens in
auto-recall.mjs), not real tokens. For CJK-heavy text the heuristic
underestimates by 2-4x, so labelling it "tok" is misleading.

Capture side: `pending_tokens` comes from the server, but the server's
own counter is also approximate. Mixing the two under the same label
invites the wrong mental model.

Just drop the unit. The magnitude is meaningful on its own (1.2k =
medium injection, 573/20k = 3% of next archive). Configuration field
names (recallTokenBudget, commitTokenThreshold) keep "Token" so we
don't churn user-facing config.

* fix(claude-code-plugin): drop recall size number — heuristic was misleading

The "1.2k" between mem count and latency was estimateTokens(text) =
ceil(text.length / 4) on the assembled injection block. For CJK-heavy
content the heuristic underestimates by 2-4x, which is enough that
showing the number does more harm than presenting count + score +
latency alone.

Capture side keeps "573/20k" because the server reports pending_tokens
itself (more accurate, and the ratio against threshold is meaningful
even if the absolute count is approximate).

* fix(claude-code-plugin): always emit session-event marker on resume/compact

Statusline expected `🔗 resumed/compact` to reflect that the event happened,
but session-start.mjs only wrote the marker when `formatArchiveContext` had
something to inject. Fresh sessions with no prior archive saw a `/compact`
silently — statusline showed nothing, leaving the user wondering whether the
hook fired at all.

Move the writeJsonState call ahead of the no-archive early return and tag
the payload with `had_context: false` for the empty case. The badge now
fires on every resume/compact event with a 1-minute TTL.

`✎` capture pending is unaffected — that segment is gated on
`cc_session_id === sessionId` and after `/branch` there's no Stop hook for
the new session yet, which is correct (stale capture from a different
session would be misleading).

* docs(claude-code-plugin): add STATUSLINE.md personalization guide

Statusline has more knobs than env vars expose — segment ordering, colors,
composing with another statusline, custom segments, state file shapes — and
the integration doc is the wrong venue for that level of detail. Add a
recipe-style guide aimed at an AI assistant reading it end-to-end, so users
can ask Claude Code "personalize my statusline" instead of spelunking source.

- examples/claude-code-memory-plugin/docs/STATUSLINE.md: recipes (drop a
  segment, recolor, compose, reset state, add a custom segment) + state
  file schemas + pointers to the canonical files. Defers env-var reference
  back to docs/en/agent-integrations/02-claude-code.md.
- install.sh: print a copy-pasteable seed prompt at the end of install. Not
  intrusive — no auto-launch, just a tip the user can ignore.
- docs/{en,zh}/agent-integrations/02-claude-code.md: cross-link the new doc
  from the Statusline section.

* docs(claude-code-plugin): anchor STATUSLINE.md paths to install location

Recipes referenced \`scripts/statusline.mjs\` etc. with no anchor, so an
agent reading the doc had no way to resolve them — `~/.openviking/openviking-repo/examples/claude-code-memory-plugin/scripts/...`
is far enough off the beaten path that "go look in scripts/" doesn't land.

Define \`\$REPO\` / \`\$PLUGIN\` / \`\$STATE\` once at the top with how to
verify each (jq on settings.json, find as fallback), then propagate the
prefixes through every recipe. The install seed prompt already passes the
absolute path of STATUSLINE.md, so the chain is now self-contained.

* feat(claude-code-plugin): segment glossary + yellow ⚠ slow + dual-purpose install tip

Three small refinements after seeing the statusline in the wild:

- statusline.mjs: split the unhealthy branch — `OV ⚠ slow` (yellow) when
  the probe times out, `OV ✗ offline` (red) when it errors. Slow ≠ dead;
  red was alarmist for transient lag (e.g. remote SaaS GC pauses).

- examples/claude-code-memory-plugin/docs/STATUSLINE.md: add "What each
  segment means" — a full glossary covering every state combination
  (✓/⚠/✗/⚡, ↩, ✎ in its three forms, dropped, 🔗 resumed/compact, +N
  today), plus a "missing when?" troubleshooting list. The integration
  docs only had four example lines, two of which were stale; the canonical
  reference now lives next to the code.

- docs/{en,zh}/agent-integrations/02-claude-code.md: refresh the example
  block (drop stale `1.2k tok` / `12k/20k tok`, add ⚠ slow + 🔗 resumed
  + +N today rows), and broaden the cross-link to advertise both
  explanation and personalization.

- install.sh: rewrite the seed prompt as "walk me through what each
  segment means, then ask if I want to personalize" — covers the more
  common "what does this badge mean?" path before customization.

* docs: link STATUSLINE.md via absolute GitHub URL, not relative path

VitePress only ships docs under \`docs/\`, but STATUSLINE.md lives in
\`examples/claude-code-memory-plugin/docs/\` (next to the plugin code, where
it logically belongs). Relative \`../../examples/...\` resolved on GitHub
but 404'd on the published docs site.

Use an absolute https://github.com/volcengine/OpenViking/blob/main/...
URL — works in both renders, and a parenthetical note tells readers why.

* docs: drop the parenthetical about why the link goes to GitHub

It was meta — readers don't need to know why the link's absolute. Just click.

* docs(claude-code-plugin): move STATUSLINE.md to plugin root

A docs/ folder with one file is awkward when README.md and README_CN.md
already sit at the plugin root. Moves STATUSLINE.md alongside them and
fixes up:

- Stale opening line that pointed at the integration doc for the segment
  glossary — that glossary now lives in STATUSLINE.md itself, so the
  cross-reference is just for env vars.
- Drop the "(path notation defined just below)" parenthetical (meta).
- Update the install seed prompt and the en/zh integration cross-links to
  the new path.

* fix(claude-code-plugin): address Copilot review on PR #1890

Code:
- state.mjs: derive STATE_DIR from \$OPENVIKING_HOME (with ~ expansion) so
  the override the docs already advertised actually works. Default
  unchanged. Was hard-coded to homedir().
- auto-recall.mjs: rename \`session_id\` → \`cc_session_id\` in last-recall.json
  to match last-capture.json / last-session-event.json. STATUSLINE.md
  schema already used \`cc_session_id\`. No reader filtered on the recall
  field, so this is a schema-cleanup, not a behavior change.
- install.sh: quote the plugin path inside the JSON \`command\` value, so
  CC's /bin/sh -c invocation tolerates spaces / metacharacters in
  \$REPO_DIR (custom OPENVIKING_REPO_DIR locations).
- install.sh: mktemp inside ~/.claude/ instead of \$TMPDIR, so the final
  rename is within one filesystem (atomic). Was crossing tmpfs/$HOME on
  Linux, where \`mv\` falls back to copy+unlink and isn't crash-safe.

Comments / docs (drift from earlier "drop tok / 250→1000ms" passes):
- server-probe.mjs: header comment said "Hard 250 ms" while the constant
  is 1000. Replaced with a forward-reference to the constant block which
  already explains the choice.
- README.md / README_CN.md: refresh the example block (drop \`1.2k tok\` /
  \`12k/20k tok\`, add \`⚠ slow\` / \`🔗 resumed\` / \`+N today\` rows), correct
  the hard-timeout sentence (250 ms → 1 s), cross-link STATUSLINE.md.
- install.sh: the \`info\` sample at registration time was also stale.

* chore(claude-code-plugin): version 0.3.0 → 0.2.1

Statusline is additive and opt-in — no API breaks, no behavior change for
existing installs that skip the prompt. A patch bump fits better than a
minor.
2026-05-07 16:38:15 +08:00
t0saki 5576bb2842 fix(cc-plugin): drop --scope from plugin commands, add legacy install path (#1876)
* fix(cc-plugin): drop --scope from plugin commands, add legacy-mode install path

- Removed `--scope user` from `claude plugin marketplace add` and
  `claude plugin install` everywhere (install.sh + READMEs + docs).
  These commands default to user scope already, and older 2.0.x builds
  (e.g. 2.0.76) reject the flag outright. Kept `--scope user` on
  `claude mcp add` because its default is `local` (current-project only)
  and the flag has been supported since MCP first shipped.
- install.sh now probes for `claude plugin` subcommand existence rather
  than parsing version strings. If absent, prompts the user to enable
  legacy compatibility mode, which wires the same functionality through
  `claude mcp add` + a JSON-merge into ~/.claude/settings.json. The
  modern path also falls back to legacy on plugin-install failure.
- Legacy mode keeps `${VAR}` placeholders single-quoted so Claude Code
  expands them at MCP launch time (the rc wrapper injects the values),
  rather than letting the shell expand them to empty strings at install
  time. Settings.json is backed up with a timestamp before the merge,
  and the merged JSON is validated before overwriting.
- Documented the legacy path in both READMEs and the agent-integration
  docs (EN + CN), with a pointer from the docs back to the README.

* fix(cc-plugin): highlight 'source rc' final step in installer

The script runs in a subshell (bash <(curl ...)), so it can't source
the rc back into the user's interactive shell. Make the manual
follow-up step visually unmissable with bold + color, and explain why
auto-source isn't possible in a comment.

* fix(cc-plugin): address copilot review on legacy install path

- mktemp + XXXXXX for tmp files (was $$ — predictable, symlink-race
  on shared /tmp).
- Replace sed substitution with jq walk + gsub. $plugin_dir comes from
  OPENVIKING_REPO_DIR (user-configurable) and may contain &, |, \
  which would corrupt sed. jq with --arg is byte-safe.
- Wrap the merge jq in an explicit if-branch so 'set -e' can't kill the
  script before cleanup runs. Drop the now-redundant post-validation
  jq -e (a successful jq run already guarantees valid JSON output).
- README EN/CN: clarify that the 'plugin enable --scope user' tip only
  applies on newer builds that accept --scope, removing the apparent
  contradiction with the surrounding 'older builds reject --scope'.
2026-05-06 23:50:05 +08:00
t0saki 8c01e97ee4 feat(cc-memory-plugin): persistent session and recall redesign (#1615)
## feat(cc-memory-plugin): implement persistent sessions, native MCP, and async write path

This update transitions the Claude Code memory plugin from a one-shot capture model to a persistent, per-session integration with OpenViking. It introduces native MCP support directly from the FastAPI server, significantly expands the tool surface, and optimizes performance via detached async write hooks.

### Core Engineering & Capabilities
* **Persistent Sessions:** Reworked lifecycle hooks (SessionStart, PreCompact, SessionEnd) to maintain stable session IDs across the entire Claude Code conversation.
* **Native MCP Endpoint:** Replaced the Node.js MCP subprocess with a native `/mcp` endpoint on the OpenViking server.
    * Expands to 9 specialized tools: `search`, `read`, `list`, `store`, `add_resource`, `forget`, `grep`, `glob`, and `health`.
    * Propagates identity headers (`X-OpenViking-Account`, `X-OpenViking-User`) through the MCP transport.
* **Async Write Path:** Introduced a detached worker pattern for `auto-capture`, `session-end`, and `subagent-stop` hooks. Claude Code no longer blocks on network round-trips to the OpenViking server.
* **Multi-Source Recall:** Enhanced `auto-recall` to search across memories, resources, and skills with URI-deduplication and score-based filtering.

### Configuration & Integration
* **Unified Auth:** Standardized on `Authorization: Bearer` tokens.
* **Config Resolution:** Established a clear priority chain: **Env Vars → ovcli.conf → ov.conf → Defaults**.
    * Added comprehensive environment variable coverage for all tuning fields (e.g., `OPENVIKING_SCORE_THRESHOLD`, `OPENVIKING_COMMIT_TOKEN_THRESHOLD`).
* **One-Line Installer:** Added an interactive bash installer (`install.sh`) that handles dependencies, `ovcli.conf` setup, and marketplace registration, with support for both self-hosted and Volcengine Cloud options.

### Bug Fixes & Refinement
* **Self-Injection Prevention:** Implemented block-stripping logic in `auto-capture` to prevent the plugin from re-storing its own injected context blocks into the memory pool.
* **Session Bypass:** Fixed a bug where `session-start` and `subagent-start` ignored bypass patterns.
* **Subagent Isolation:** Implemented `SubagentStart/Stop` hooks with isolated session IDs and specialized agent headers for memory segregation.
* **Docs & Maintenance:** Bumped version to `0.2.2`; added comprehensive agent integration guides; fixed Vue interpolation and markdown fence issues in documentation.
2026-05-04 13:10:44 +08:00