Commit Graph
508 Commits
Author SHA1 Message Date
Qin Haojie e648b2679c feat(ovpack): add v2 manifest and backup restore (#1927)
* feat(ovpack): add v2 manifest and conflict policy

Add a portable OVPack manifest for scalar metadata and make imports validate scope, derived files, and conflicts before writing.

* fix(ovpack): remove import vectorize option

Make OVPack imports always rebuild vectors in the target environment, keep legacy packages compatible, and reject unsupported manifest versions before writing.

* fix(ovpack): remove force import alias

Use on_conflict as the single OVPack import conflict policy and reject removed force inputs.

* fix(ovpack): regenerate runtime vector metadata

Keep type portable but stop exporting or applying created_at, updated_at, and active_count from OVPack manifests.

* fix(ovpack): validate manifest contents

* fix(ovpack): require manifests for imports

* fix(ovpack): close manifest validation gaps

* fix(ovpack): defer parent creation until validation passes

* fix(ovpack): remove export size guard

* fix(ovpack): support session and scope-root restores

* docs(ovpack): document full backup migration

* feat(ovpack): add backup restore workflow

* fix(ovpack): validate import scope compatibility
2026-05-11 11:09:35 +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 c4794319c5 docs(ovcli.conf): note interactive setup-cli + multi-server switch from #1916 (#1961)
* docs(ovcli.conf): note interactive setup-cli + multi-server switch from #1916

* docs(ovcli.conf,zh): note interactive setup-cli + multi-server switch from #1916
2026-05-11 01:13:56 +08:00
Mingjian QueandGPT-5.5 0073ce7e05 fix(openclaw): split OpenViking import tools (#1946)
Replace the ambiguous OpenClaw ov_import surface with explicit add_resource and add_skill tools and slash commands.

Guide media attachment imports through the existing OpenViking temp-upload and resource import APIs instead of invented upload endpoints.

Update docs, plugin manifest, and unit coverage for the split import commands.

Co-authored-by: GPT-5.5 <noreply@openai.com>
2026-05-10 15:51:32 +08:00
t0saki 0f5a569eec fix(mcp): support recursive directory deletion in forget tool (#1935)
The MCP `forget` tool only forwarded `uri` to `fs.rm` and never set
`recursive`, so any directory URI hit a `FailedPreconditionError` from
`VikingFS.rm`. Docs and the REST DELETE endpoint already advertised
directory deletion, leaving MCP clients without an equivalent.

Add an optional `recursive` parameter to the MCP tool (default False to
preserve fail-closed behavior on accidental tree deletes), update the
zh/en MCP integration tables, and cover both directory paths in tests.

Fixes #1928
2026-05-09 15:05:24 +08:00
Hao Zhe 66d447187b fix(storage): canonicalize shorthand namespace URIs on write (#1929) 2026-05-09 14:05:36 +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
Evo 3d35c1ad62 docs(config): document temp_upload server config + ovcli.conf upload.mode (#1899) (#1925)
* docs(server,cli): document temp_upload server config + ovcli.conf upload.mode (#1899)

* docs(zh): mirror temp_upload + upload.mode docs (#1899)
2026-05-09 11:35:35 +08:00
t0saki 7d5fa62398 feat(oauth): native OAuth 2.1 authorization for MCP clients (#1870)
* feat(oauth): hand-sewn OAuth 2.1 M1+M2 (config, JWT, storage, /oauth/token, JWT discriminator)

Snapshot before evaluating migration to mcp.server.auth SDK provider. The
hand-rolled HS256 JWT implementation in openviking/server/oauth/jwt.py is
the main candidate for replacement: its surface area is small but it would
require careful crypto review by maintainers, while the official MCP SDK
already ships an OAuth provider wired into FastMCP.

Included so far:
- OAuthConfig + integration into OpenVikingConfig (default disabled)
- openviking/server/oauth/{jwt,storage,otp,router}.py
- POST /oauth/token (authorization_code + refresh_token, PKCE S256, RFC 6749 errors)
- JWT discriminator in resolve_identity (fail-closed; ResolvedIdentity.from_oauth)
- WWW-Authenticate Bearer hint on /mcp 401 (RFC 9728)
- 49 OAuth-specific unit/integration tests (all passing)

Not yet implemented (M3 / MVP gap):
- /oauth/register (DCR), /oauth/authorize (HTML + OTP submit), well-known metadata
- POST /api/v1/auth/otp REST endpoint

* refactor(oauth): switch to mcp.server.auth SDK provider, drop hand-sewn JWT

Replaces the hand-rolled HS256 JWT signer / token endpoint / DCR with
the OAuth 2.1 surface shipped in mcp.server.auth. We supply a Provider
that adapts the existing OAuthStore (SQLite) to the SDK Protocol, plus
two custom routes the SDK doesn't own: an OTP-entry HTML page (the URL
provider.authorize() returns) and POST /api/v1/auth/otp for issuing
OTPs against an existing API key.

Net result: all OAuth crypto is now the SDK's responsibility (PKCE
S256, redirect_uri matching, error formatting). The OpenViking-side code
contains zero cryptography — access tokens are opaque random strings
prefixed with `ovat_` and looked up in SQLite by SHA-256 hash. Refresh
tokens, auth codes, OTPs use the same scheme.

Highlights:
- openviking/server/oauth/provider.py: OpenVikingOAuthProvider implements
  the 8-method SDK Protocol, including subclassing AuthorizationCode /
  RefreshToken / AccessToken to pin (account_id, user_id, role) per
  token. Refresh-token replay triggers per-user chain revocation.
- openviking/server/oauth/storage.py: adds oauth_access_tokens and
  oauth_pending_authorizations tables; peek_auth_code / peek_refresh
  for non-destructive lookups; revoke_user_tokens cascades all OAuth
  state for an (account, user) pair when a key is rotated.
- openviking/server/oauth/router.py: minimal authorize page (inline
  HTML with frame-ancestors 'none') + OTP endpoint authenticated via
  existing get_request_context dependency.
- openviking/server/auth.py: replaces JWT discriminator with prefix
  match + provider.load_access_token; still fail-closed.
- openviking/server/app.py: mounts SDK routes via create_auth_routes
  alongside our authorize-page + OTP routes.
- Deletes openviking/server/oauth/jwt.py and tests/server/oauth/test_jwt.py.

Tests: 32 passing, including a full DCR -> OTP -> authorize page ->
token-exchange -> /mcp lookup happy path, refresh rotation, and replay
detection. Existing test_auth.py regression unchanged.

Phase 1 still missing for full Claude.ai connectivity:
- WWW-Authenticate hint already present on /mcp 401 (from M2)
- /.well-known/oauth-protected-resource (RFC 9728) — not currently
  emitted by the SDK; small custom route still TODO.

* docs(oauth): rewrite design doc to reflect mcp.server.auth SDK approach

The earlier draft described a hand-sewn HS256 JWT plan; the implementation
took a different route after discovering mcp.server.auth ships a complete
RFC 6749 / 7591 / 8414 server. Updated to reflect:

- SDK owns the protocol surface (DCR, /authorize parsing, /token, metadata,
  PKCE, redirect_uri matching, error codes).
- OpenViking only contributes a Provider implementation, the OTP-entry
  HTML page, and POST /api/v1/auth/otp.
- Tokens are opaque (ovat_ / ovrt_ / ovac_ prefixes) — no JWT, no crypto
  on our side.
- Implementation status: M1/M2/M3 done; only RFC 9728 protected-resource
  metadata + reverse-proxy issuer derivation remain for full Claude.ai
  end-to-end connectivity.

* feat(oauth): add /.well-known/oauth-protected-resource (RFC 9728)

The /mcp 401 path already advertises this URL via WWW-Authenticate
Bearer resource_metadata="...", but the endpoint itself didn't exist —
clients fetched it and got a 404, which silently broke the discovery
chain even though /.well-known/oauth-authorization-server worked. Wire
up the resource metadata document so the full RFC 9728 → RFC 8414
discovery chain works end-to-end.

Uses mcp.shared.auth.ProtectedResourceMetadata pydantic model. Reads
X-Forwarded-Proto/Host so the published resource URL matches what the
client used (matches our existing WWW-Authenticate behavior).

Cache-Control: max-age=3600 — metadata is stable across requests.

* feat(console): add OTP issuance button in Settings panel

Adds a "Get OTP" button under the Settings panel of the 8020 web
console. Clicking it issues an OAuth OTP via the user's existing API
key (already loaded into sessionStorage) and displays it inline with
a copy-to-clipboard button.

Replaces the previous workflow of users having to:
  curl -X POST -H "X-Api-Key: $KEY" http://1933/api/v1/auth/otp

…with a single button-click flow that the user can reach from any
machine with a browser.

Wires:
- console/app.py: new POST /console/api/v1/ov/auth/otp proxy route,
  forwarding to upstream /api/v1/auth/otp. Not gated by write_enabled
  since OTP issuance is an authentication artifact, not data mutation.
- index.html: new OAuth section in the Settings panel with otpBox
  (hidden until OTP is generated) and a Copy button.
- app.js: getOtpBtn click handler calls callConsole, otpCopyBtn copies
  to clipboard. Clear failure messages when the user has no API key
  loaded yet.

This is the lightweight half of the Console-OAuth integration. The
fuller "same-origin auto-authorize" flow (Phase 2) — where the
authorize page detects sessionStorage and submits the OTP form
automatically — is still TBD and will reuse this proxy route.

* feat(oauth): device-flow style authorize page + console verify form

Pivots the OTP flow direction so the UX matches OAuth 2.0 Device
Authorization Grant (RFC 8628) more closely:

  Old (push):  user goes to console -> Get OTP -> copy -> paste in
               client's authorize page -> submit -> redirect.
  New (pull):  client's authorize page DISPLAYS a 6-char code -> user
               types it into the console verify form -> page polls -> redirect.

This removes one tab switch and aligns with how users mentally model
authorization ("I'm approving the request shown over there from
where I'm already signed in"). The legacy POST /api/v1/auth/otp +
"Get OTP" button are kept under a collapsed details element for any
scripted/CLI flows that still drive the older pattern.

Also wires OPENVIKING_PUBLIC_BASE_URL env var as the highest-priority
public origin override, used consistently by:
  - /.well-known/oauth-protected-resource
  - WWW-Authenticate header
  - authorize page links
  - SDK issuer at app start.

Server changes:
- storage.py: oauth_pending_authorizations gains display_code,
  verified, verified_account_id/user_id/role columns; new
  find_pending_by_display_code + mark_pending_verified.
- provider.authorize() now generates display_code at pending creation
  and returns the page URL.
- router.py:
  * GET /oauth/authorize/page — renders the code + same-origin quick-
    authorize panel (sessionStorage detection, but click still required
    so authorization is never silent).
  * GET /oauth/authorize/page/status — polled by the page until verified;
    response carries the redirect_url with auth_code on approval.
  * POST /api/v1/auth/oauth-verify — authenticated; binds caller
    identity to a pending row (decision=approve|deny).

Console changes:
- Settings panel: new "Authorize an MCP client" section with code input
  and Authorize/Deny buttons. Legacy "Get OTP" still available under
  details.
- console proxy gains POST /console/api/v1/ov/auth/oauth-verify.

Tests: 38 OAuth tests passing, including a full device-flow happy path,
deny path, idempotency (one-shot pending), unknown-code rejection,
status-410 on consumed/expired, refresh rotation, OPENVIKING_PUBLIC_BASE_URL
override, and X-Forwarded-* fallback.

* docs(oauth): add 11-oauth guide + Caddy/nginx templates + .env-driven compose

Adds a top-level OAuth 2.1 guide (zh/en) covering the production path
end-to-end. Opens with a 5-step recommended setup so readers don't have
to wade through the rationale before they can deploy. Drops the "MCP"
qualifier from the doc name — OAuth 2.1 here is generic and serves any
OAuth client, not just MCP.

- docs/{en,zh}/guides/11-oauth.md: new. Recommended setup at the top,
  then background, full device flow, HTTP-local vs HTTPS-production
  deployment, Caddy + nginx templates, docker-compose with the shipped
  Caddy service, curl walkthrough, config reference, troubleshooting.
- docker-compose.yml: replace the prior PR's commented-out hint with a
  single OPENVIKING_PUBLIC_BASE_URL var (read by both the openviking
  service and an optional Caddy reverse-proxy service that's also
  shipped commented-out). Same env var drives Caddy via
  {$OPENVIKING_PUBLIC_BASE_URL}, so the public domain is configured
  once in .env.
- docs/{en,zh}/guides/06-mcp-integration.md: replace the "OAuth Proxy
  (planned, use community Cloudflare Worker)" section with a short
  pointer to the new 11-oauth guide. The community proxy is still
  mentioned as an alternative.

Same env-variable design also matches what the MCP add_resource tool
expects (it already reads OPENVIKING_PUBLIC_BASE_URL), so deployments
get a single source of truth for the public address.

* fix(oauth): read API key from localStorage on authorize page

The same-origin "Quick authorize" panel was reading sessionStorage,
which is per-tab. Since the OAuth authorize page opens in a different
tab from the console, the panel never showed up even when the user was
signed in.

The console persists the API key in localStorage as well (key
"ov_console_api_key" — see static/console_settings.js's
LEGACY_API_KEY_STORAGE_KEY) for cross-tab use, and that copy is what
the authorize page should consult.

Switch the page JS to localStorage first, fall back to sessionStorage
for resilience. No console-side change needed; the localStorage entry
has been written by the console all along.

* docs: add public access guide + default port 1934 aggregated proxy

- Add Caddyfile with :1934 HTTP aggregated proxy (merges 1933+8020)
- Enable Caddy service by default in docker-compose.yml on port 1934
- Add docs/{en,zh}/guides/12-public-access.md with full HTTPS setup guide
- Simplify 11-oauth.md: replace inline reverse proxy config with refs to 12
- Add HTTPS requirement callout to OAuth recommended setup
- Update 03-deployment.md to mention port 1934 as recommended entry point

* fix(oauth): address Copilot review + ruff format

- Update oauth_config.py docstrings to describe opaque tokens, not JWT
  (we switched away from JWT during implementation)
- Remove unused authorize_rate_limit_per_min config field — was never
  enforced anywhere in router/storage, dead config misled operators
- Wrap all OAuthStore read paths in self._lock (matching writes); the
  shared sqlite3.Connection with check_same_thread=False is not safe
  for concurrent cursor use across threads
- Clarify provider.exchange_refresh_token comment that replay revokes
  the entire (account, user) family, not just the (client, account,
  user) chain — broader blast radius is intentional
- ruff format: 8 files reformatted to satisfy CI lint

* perf(docker): add cargo + ccache cache mounts to py-builder stage

The two heavy RUN steps in py-builder (uv sync + maturin build) re-execute
on every Python source change because the upstream COPY layer for openviking/
invalidates the cache. Each rerun was ~510s + ~115s ≈ 10 min of wasted work
even though Rust/C++ source was unchanged.

Add BuildKit cache mounts so cargo and the C++ engine compilation can skip
work whose inputs are unchanged:

- Mount /cargo-target, cargo registry, and cargo git so cargo's incremental
  build artifacts persist across layer reruns. Pin CARGO_TARGET_DIR so the
  path stays stable when uv builds wheels in ephemeral isolated tempdirs.
- Install ccache and prepend /usr/lib/ccache to PATH so cmake (which calls
  shutil.which("gcc")) resolves the ccache wrapper. ccache is path-agnostic,
  so it benefits the cmake_build subdir even though setup.py recreates it
  in a fresh tempdir each wheel build.
- Mount /root/.ccache so the ccache hash store persists across reruns.

Expected: hot rebuilds on Python-only changes drop step 15 from ~510s to
~60-120s (uv wheel packaging overhead remains; cargo + g++ skip on cache hit).

* perf(docker): drop redundant second maturin build step

The second RUN step in py-builder built ragfs-python a second time and
extracted its .so into the installed openviking package. This was
redundant: setup.py's build_ragfs_python_artifact() already runs maturin
during step 15 (uv sync --no-editable), and because build_meta passes
'bdist_wheel' through PEP 517, _should_require_ragfs_artifact() returns
True and the build fails closed if maturin can't produce ragfs_python.so.
The .so is then bundled into the wheel via package_data and installed
into /app/.venv on wheel install. The second step's only effect was to
overwrite the same file, costing ~115s per build.

Verified after the fact by inspecting the installed venv and importing
ragfs_python in the runtime container.

* feat(oauth): bind OAuth token lifetime to authorizing API key

Previously OAuth tokens lived independently of the API key that authorized
them. Rotating a user's key did not invalidate already-issued OAuth access /
refresh tokens, so a compromised key remained dangerous even after rotation.

Tie every OAuth token to the SHA-256 fingerprint of the API key whose holder
authorized it:

- APIKeyManager grows get_user_key_fingerprint(account_id, user_id) ->
  sha256(stored_key_value). The stored value is whatever sits in
  user_info["key"] (plaintext key or argon2id hash), written once on
  create / regenerate and never mutated in place, so the fp is stable per
  key-generation and changes the moment regenerate_key runs.

- OAuth storage gains an authorizing_key_fp column on oauth_codes,
  oauth_pending_authorizations (verified_key_fp), oauth_refresh_tokens, and
  oauth_access_tokens. ALTER TABLE migration guarded by PRAGMA table_info
  for dev DBs that predate the field.

- Provider data classes thread the fp through authorize ->
  exchange_authorization_code -> _issue_token_pair, and refresh rotation
  preserves it from the consumed token's record.

- Router endpoints capture the caller's current fp at the only two
  identity-binding moments: /api/v1/auth/otp (caller) and
  /api/v1/auth/oauth-verify (verifier). If the manager returns None
  (ROOT key, trusted-mode identity, or removed user), refuse to issue
  OAuth state -- there is no key whose lifecycle we could honor.

- auth.py:_try_resolve_oauth_token recomputes the user's current fp on
  every OAuth bearer auth and demands strict equality via
  hmac.compare_digest. NULL / empty / mismatch all fail closed with a
  401 telling the client to re-authorize.

Crypto notes: sha256 over a 256-bit-random API key (or its argon2id hash)
is preimage-safe, so an oauth.db leak does not reveal the API key. No new
secret material introduced; the fp is derived deterministically from data
that already exists.

Tests: 3 new lifecycle tests in test_auth_integration (rotation rejected,
user-removed rejected, missing-fp fail-closed), 3 new router tests
(no-fp caller / verifier rejected, fp recorded on access + refresh), 2 new
APIKeyManager tests (fp changes on rotate / vanishes on remove).
Pre-existing inserts in test_storage updated to pass _FP. 82/82 OAuth +
APIKeyManager tests pass.

* docs(oauth): document OAuth lifetime ≤ authorizing key lifetime

The fingerprint binding landed in the previous commit; users need to know
that key rotation now auto-invalidates derived OAuth tokens (no separate
revoke step) and that ROOT / trusted-mode identities cannot issue OAuth.

Updates both en and zh under docs/guides/11-oauth.md, replacing the
"operator should also revoke ..." paragraph with the new automatic
behavior + brief note on the SHA-256 fingerprint scheme.

* fix(oauth): close 4 review findings on token lifecycle

External security review of #1870 surfaced four real gaps in the OAuth
implementation. All four directly affect the lifecycle / privilege model.

P1: role downgrade did not invalidate OAuth tokens
  set_role rewrites user_info["role"] without touching user_info["key"],
  so the SHA-256 fingerprint binding stays valid and an ADMIN demoted to
  USER continues to resolve as ADMIN. Refresh tokens keep minting fresh
  ADMIN access tokens. Fixed in two places:
  - auth.py:_try_resolve_oauth_token re-fetches Role.get_user_role and
    rejects when the embedded role outranks the current role.
  - provider.exchange_refresh_token gets a role_resolver callback (wired
    in app.py to api_key_manager.get_user_role) and applies the same
    gate before consuming a refresh.
  Promotion remains harmless — the embedded lower privilege is still
  authorized, only downgrades trigger rejection.

P1: confidential client secrets were never enforced
  provider.get_client returned client_secret=None regardless of the
  stored hash; the MCP SDK's ClientAuthenticator skips secret validation
  when the returned client has a falsy secret, silently allowing
  client_secret_basic / client_secret_post clients to authenticate with
  only client_id. Real MCP clients all use "none" + PKCE per RFC 8252
  §8.4 anyway, so register_client now rejects non-"none" auth methods at
  DCR. Native/desktop apps can't keep secrets — PKCE is the actual
  proof-of-possession.

P1: OAuth tokens could mint new OAuth grants
  /api/v1/auth/otp and /api/v1/auth/oauth-verify accepted any caller
  resolved through get_request_context, including identities resolved
  from OAuth bearers. A stolen 1h access token could call oauth_verify
  with its own pending row and walk away with a 30d refresh-token
  chain — privilege time-extension. RequestContext now carries
  from_oauth (mirroring ResolvedIdentity.from_oauth) and both endpoints
  reject from_oauth=True with 403, forcing primary auth.

P2: GC erased refresh-token replay tombstones
  gc_expired deleted "WHERE expires_at < ? OR consumed = 1" every
  minute. After GC, is_refresh_known_but_consumed could not distinguish
  a replay from an unknown token and exchange_refresh_token never fired
  revoke_chain — defeating RFC 9700 §4.14 family revocation for late
  replays. GC now keeps consumed refresh rows until their natural
  expires_at; storage cost bounded by the 30d max refresh TTL.

Also adds from_oauth field to RequestContext and propagates from
ResolvedIdentity in get_request_context.

Tests: 7 new (role downgrade rejection in bearer auth + refresh path,
role promotion is harmless, confidential DCR rejected, from_oauth
rejected at OTP and oauth-verify, refresh tombstone preserved across
GC). Pre-existing test_oauth_root_can_be_used and
test_dcr_registers_client updated to match the stricter contract.
89/89 OAuth + APIKeyManager tests pass.

* fix(oauth): downgrade confidential DCR to public instead of rejecting

The previous P1.2 fix rejected DCR when token_endpoint_auth_method was
not "none", reasoning that we never enforce client_secret server-side
so accepting confidential auth methods would be a silent security
downgrade. That is the right invariant — but the rejection broke real
clients: the OAuth 2.0 default for token_endpoint_auth_method is
"client_secret_basic", and at least Claude Desktop relies on the SDK to
fill in defaults rather than explicitly setting "none". DCR for those
clients started returning 400 even though they would work fine with PKCE
(which they all use anyway).

Soft-failure design instead: accept any registered auth method, but
overwrite the stored value to "none" and log a warning. The end-state
is identical to the rejection path — every client is treated as
public+PKCE, no secret is ever stored or enforced — but Claude Desktop's
DCR no longer blows up.

Updates the test from asserting 400 to asserting that a confidential
registration is silently downgraded: stored auth_method == "none",
client_secret_hash is None.

* delete(docs): remove error file

* docs(zh): sync 03-deployment.md with English version

c5cb241f only updated docs/en/guides/03-deployment.md when introducing
the 1934 aggregated entry point and the 12-public-access.md guide. This
backfills the same changes in the Chinese version:
  - Add port 1934 (Caddy aggregated entry point) to the access list
  - Link to 12-public-access.md for public HTTPS setup
  - Add 11-oauth.md and 12-public-access.md to "Related Documentation"
2026-05-08 20:21:21 +08:00
Jiahui Zhouandqin-ctx ac3346422a feat(rebuild): add rebuild api scaffold (#1592)
* feat(admin): add rebuild api scaffold

feat: add admin rebuild API

fix: harden admin rebuild execution

feat(cli): add rebuild command support

fix(rebuild): support namespace rebuild routing

refactor(rebuild): unify memory semantic rebuild mode

refactor(rebuild): move http endpoint to content route

fix(rebuild): skip root namespace vectorization

fix(rebuild): harden namespace classification

refactor: rename rebuild api to reindex

refactor: rename reindex executor module

refactor(reindex): remove unused reason field

* fix(reindex): tighten namespace URI handling

Share segment-based Viking URI classification across context inference and reindex execution, add skill namespace support, and require root reindex requests to select an account.

* refactor: reuse indexing pipeline in reindex

* Revert "refactor: reuse indexing pipeline in reindex"

This reverts commit 2725fe6733.

* fix(reindex): respect semantic vectorization skips

Avoid scheduling semantic DAG vectorization work during semantic_and_vectors reindex, and keep resource vector text selection aligned with normal vectorize_file handling for non-text files.

---------

Co-authored-by: qin-ctx <qinhaojie.exe@bytedance.com>
2026-05-08 17:48:33 +08:00
MaojiaShengandopenviking b9a8c4e120 feat: path variables and -p for add-resource (#1896)
* feat:   提交1:路径变量系统
  feat: Add path variable system with calendar variables

  - Implement {calendar:today}, {calendar:ym}, etc.
  - Integrate with all URI-handling API endpoints
  - Add comprehensive unit tests
  - Update documentation

  提交2:Rust CLI重构
  feat: Rust CLI refactor with progress bar support

  - Split HttpClient into BaseClient and FileUploader
  - Add dynamic timeout configuration
  - Add progress bar for compression/upload
  - Configure via --progress flag or config file

* feat:   提交1:路径变量系统
  feat: Add path variable system with calendar variables

  - Implement {calendar:today}, {calendar:ym}, etc.
  - Integrate with all URI-handling API endpoints
  - Add comprehensive unit tests
  - Update documentation

  提交2:Rust CLI重构
  feat: Rust CLI refactor with progress bar support

  - Split HttpClient into BaseClient and FileUploader
  - Add dynamic timeout configuration
  - Add progress bar for compression/upload
  - Configure via --progress flag or config file

* feat: support --parent, and change default root path for image

* feat: support --parent, and change default root path for image

* docs: fix docs

* fix: review comments

---------

Co-authored-by: openviking <openviking@example.com>
2026-05-08 15:06:31 +08:00
Jiahui Zhou 4f28f086bd feat(server): add shared temp upload mode (#1899)
fix(server): move shared temp uploads to upload namespace

refactor(server): flatten shared upload namespace

refactor(server): simplify shared upload semantics

fix(server): restrict upload scope and add python shared upload mode
2026-05-08 11:12:57 +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
yufeng 9b3b47a593 ci: deploy VitePress docs to TOS (#1897)
* ci: deploy docs to TOS

* ci: avoid listing TOS bucket during docs deploy

* ci: use virtual-hosted TOS uploads
2026-05-08 10:49:01 +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
Lumos088 43a8a734dc Delete docs/images/wechat-group-qrcode.jpg (#1864) 2026-05-07 13:13:36 +08:00
t0saki 23cfd61570 fix(favicon): preserve transparency instead of baking white background (#1881)
The favicons added in #1879 were generated with `-background white
-extent` to pad the trimmed logo to a square canvas. The source
ov-logo.png is a transparent sRGBA PNG, so this baked a solid white
square into the alpha channel. On dark-mode browser tabs the icon
showed up as a white block.

Regenerate the variants with `-background none` so the padded canvas
stays transparent. The visible glyph is unchanged; only the previously
white padding is now alpha=0.
2026-05-07 12:10:44 +08:00
t0saki 33113eb057 feat: serve tight favicon variants for API server and docs site (#1879)
* feat(server): serve favicon and apple-touch-icon at root

Browsers and MCP clients (claude.ai, Claude Desktop) auto-fetch
/favicon.ico and /apple-touch-icon.png to display a server icon.
The 1933 server previously returned JSON 404s for these paths,
leaving connectors with a generic placeholder.

Add small route handlers that serve OV-branded icons from the
existing console/static directory (already shipped as package
data). Also wire the console index.html to the new icons.

* feat(docs): use tight favicon variants for VitePress site

The docs site previously pointed `<link rel="icon">` at the same
1000x1000 ov-logo.png used by the in-page nav, so the tab favicon
rendered visibly small inside heavy whitespace.

Reuse the trim+square favicon variants generated for the API server
(favicon.ico, favicon-32.png, apple-touch-icon.png) under docs/images/
and wire them into the VitePress head config. The in-page nav logo
still uses the original PNG (whitespace looks fine in that context).
2026-05-07 12:02:28 +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
Hinotobiandqin-ctx d0b9fb415a [security] fix(admin): restrict privileged roles in register_user (#1624)
* [security] fix(admin): restrict privileged roles in register_user

* fix(admin): import invalid argument error

* fix(admin): allow admins to register co-admins

---------

Co-authored-by: qin-ctx <qinhaojie.exe@bytedance.com>
2026-05-06 16:14:00 +08:00
Lumos088 367b586699 Add files via upload (#1865) 2026-05-06 15:32:12 +08:00
Lumos088 9a9a8f9703 Add files via upload (#1863) 2026-05-06 14:33:35 +08:00
chenjw 44d3cc41b1 Feat/memory isolation 支持群聊模式 (#1711) 2026-05-06 10:45:06 +08:00
Zayn Jarvis 0f21cf66f7 docs: fix i18n switch, add v0.3.13/v0.3.14, normalize changelog, update Roadmap (#1845) 2026-05-04 16:59:46 +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
Evo f522b0cc84 docs(admin): add list_agents endpoint to API overview tables (#1826) 2026-05-03 09:46:38 +08:00
Qin Haojie e887744540 feat(admin): list agent namespaces (#1821)
Expose admin API and CLI support for discovering agent namespaces under an account.
2026-04-30 14:20:59 +08:00
Evo 7748036951 docs(multi-tenant): finish agentId→agent_prefix rename in OpenClaw Plugin 2.0 section (#1818)
* docs(multi-tenant): finish agentId→agent_prefix rename in OpenClaw Plugin 2.0 section

* docs(multi-tenant)(zh): finish agentId→agent_prefix rename in OpenClaw Plugin 2.0 section
2026-04-30 14:11:06 +08:00
DuTao e87751c7c6 fix(skill): Fix PR bug, delete invalid config in doc, fix deepseek API for bot (#1794)
* deepseek fix

* fix skill_extractor pr bug

* 去掉废弃字段的配置说明

* fix
2026-04-30 14:03:38 +08:00
sentisso 9b45c21499 feat(upload): respect root and nested .gitignore during filtering (#1812)
* feat: adding .gitignore compliance

* docs

* fix

* revert
2026-04-30 14:01:54 +08:00
baojun-zhang 21c8d08d6c doc(observability): add grpc metadata guide && format test code (#1807) 2026-04-29 20:30:23 +08:00
baojun-zhang d7fdb489ce feat(observability): support header param while OTLP export (#1805)
* feat(observability): support header param while OTLP export

* feat(observability): support header param while OTLP export
2026-04-29 20:14:31 +08:00
Zayn JarvisandClaude Opus 4.6 536747b53f fix(docker): bind server to 0.0.0.0 so Docker port-mapping works (#1803)
The default host (127.0.0.1) made the server unreachable from outside
the container. Now the entrypoint passes --host 0.0.0.0, which requires
root_api_key in ov.conf (enforced by existing validate_server_config).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 18:22:19 +08:00
MaojiaShengandopenviking fd71f677cc docs: update api docs for 04-08 (#1802)
Co-authored-by: openviking <openviking@example.com>
2026-04-29 18:12:38 +08:00
Evo ae250fdcfa docs(multi-tenant): rename agentId to agent_prefix per #1783 (#1786)
* docs(multi-tenant): rename agentId to agent_prefix per #1783 (en)

* docs(multi-tenant): rename agentId to agent_prefix per #1783 (zh)
2026-04-29 17:37:23 +08:00
MaojiaShengandopenviking a578f356cb docs: update api docs for 01,02 (#1784)
* docs: update api docs

* docs: update api docs

* docs: update api docs

---------

Co-authored-by: openviking <openviking@example.com>
2026-04-29 17:37:03 +08:00
t0saki 2513acdb46 docs(mcp): add OAuth 2.1 roadmap and MCP-Key2OAuth community disclaimer (#1791)
- Add "Official OAuth Support (Planned)" subsection describing three
  approaches under evaluation: OTP authorization, Console quick-auth,
  and third-party IdP login
- Reframe MCP-Key2OAuth as a community workaround with strengthened
  disclaimer (no security/availability guarantee)
- Replace hosted demo URL with self-deployment instruction
- Both zh and en docs updated symmetrically
2026-04-29 12:22:31 +08:00
yufeng 39b124d037 fix(docs): simplify docs workflow (#1778) 2026-04-29 10:55:57 +08:00
Qin Haojie b35d38a323 feat(config): 配置检索打分和 embedding 输入 (#1770)
* feat(retrieval): configure hotness score blending

* feat(retrieval): configure score propagation alpha

* test(retrieval): trim redundant propagation coverage

* feat(embedding): centralize token estimation

* fix(embedding): use shared token estimator

* fix(embedding): narrow token truncation scope
2026-04-28 19:04:24 +08:00
Zayn JarvisandClaude Opus 4.6 f2bd92803b docs: add CHANGELOG.md auto-generated from GitHub Releases (#1776)
* docs: add CHANGELOG.md generated from GitHub Releases

- Import all 32 releases into CHANGELOG.md
- Add GitHub Action to auto-update CHANGELOG on each new release

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: generate changelog from GitHub Releases with auto-update Action

- Replace placeholder changelog in docs/en and docs/zh with all 32 releases
- Remove root CHANGELOG.md (changelogs live in docs site)
- Add GitHub Action that on each release:
  - Uses Claude API to categorize changes into Keep a Changelog format
  - Generates both EN and ZH entries
  - Incrementally prepends to both changelog files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: compact changelogs and remove auto-update workflow

- Remove changelog.yml GitHub Action (per user request)
- Compact EN and ZH changelogs: strip PR links, authors, contributor
  sections, code examples; keep gist only (<50 lines per release)
- ZH uses Chinese summaries where available, EN uses English summaries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 18:59:32 +08:00
DuTao bb515b1007 feat(openviking): Add User-Level Skill Privacy Configuration Capability (#1745)
* 增加用户隐私信息,skill 提取

* 增加用户隐私信息,skill 提取

* 字段提取

* privacy 配置cli 指令

* doc

* doc
2026-04-28 18:32:16 +08:00
DuTao 48d0bcd8e1 feat(dot): Doc for agent setup (#1774)
* add relevant memories

* setup doc

* fix limit
2026-04-28 18:23:16 +08:00
Zayn JarvisandClaude Opus 4.6 75ac3cfe40 docs: fix code-documentation inconsistencies in docs (#1741)
* docs: fix code-doc inconsistencies in English documentation

- Fix default server host: docs claimed 0.0.0.0 but code defaults to 127.0.0.1
- Fix GLOBAL_SEARCH_TOPK: docs said 3 but code uses 10
- Fix VLM model name: docs had doubao-seed-2-0-code-preview-260215, code uses doubao-seed-2-0-pro-260215
- Fix metrics file reference: pointed to nonexistent .vscode/.workdir/metric/METRIC_res.md
- Fix build prerequisite: Go replaced by Rust/Cargo (no .go files remain in repo)
- Fix embedding provider list: README listed 7 providers, code supports 13
- Fix CLI command inconsistency: two ov commands in sessions doc should be openviking
- Add missing session archive endpoint to API overview table

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: revert ov→openviking CLI rename in sessions doc

Both `ov` and `openviking` are registered entry points for the same
Rust CLI binary (pyproject.toml). The short `ov` alias is intentional
and valid — reverting the previous rename.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: sync same fixes to Chinese docs, README_CN, and README_JA

Apply the same consistency fixes from the English docs to:
- docs/zh/ (Chinese documentation)
- README_CN.md (Chinese README)
- README_JA.md (Japanese README)

Changes mirror the English fixes: server host default, GLOBAL_SEARCH_TOPK,
VLM model name, build prerequisites (Go→Rust), embedding provider list,
metrics file reference, and missing session archive endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 15:37:18 +08:00
t0saki ccad9c5e0e feat(server): native MCP endpoint with 9 tools aligned to VikingBot (#1738)
* feat(server): add native MCP endpoint at /mcp

Serve 5 MCP tools (search, read, store, forget, health) directly from
the OV FastAPI server via streamable HTTP transport. This eliminates the
need for the Node.js MCP subprocess — the plugin's .mcp.json now points
to the server URL instead of spawning a process.

Identity headers (X-OpenViking-Account/User/Agent) are propagated to
service-layer calls via contextvars ASGI middleware.

* fix(mcp): disable DNS rebinding protection for reverse proxy compatibility

MCP SDK auto-enables host validation for localhost, rejecting requests
with external Host headers (e.g. from Cloudflare/Nginx reverse proxy).

* fix(mcp): reuse auth.resolve_identity for MCP endpoint authentication

MCP endpoint previously had no authentication — requests fell through
with default/default identity. Now delegates to the same resolve_identity
used by all REST routes, so auth_mode, API key validation, and identity
resolution are handled identically.

* fix(mcp): fix import path for TextPart in store tool

openviking.session.parts does not exist; the correct module is
openviking.message.part.

* fix(mcp): store tool now creates a new session and commits immediately

Each store call creates a unique session, adds the message, and commits
right away so memories are extracted and searchable without waiting for
a token threshold.

* chore: add mcp>=1.27.0 dependency for native MCP endpoint

* fix(mcp): align search/forget tools with REST API, fix forget crash

- Remove SEARCH_TARGETS and per-scope loop; use single
  service.search.find(target_uri="") call matching REST API behavior
- Fix forget crash: FSService has no delete(), use rm() instead
- Replace fragile _is_memory_uri() substring check with ContextType
- search tool: replace scope param with target_uri for direct passthrough
- Work directly with FindResult/MatchedContext objects instead of
  dict-munging via to_dict()

* fix(mcp): fail-closed on missing identity, remove unused Role import

- _get_ctx() now raises UnauthenticatedError instead of defaulting to
  ROOT when identity contextvar is not set
- Remove unused Role import
- Clean up comments in create_mcp_app

* test(mcp): add unit tests for MCP endpoint tools

17 tests covering all 5 MCP tools and identity propagation:
- _get_ctx: returns context when set, raises UnauthenticatedError when not
- health: healthy/unhealthy responses
- search: no results, with resource, with target_uri
- read: nonexistent URI, directory listing, batch reads
- store: user and assistant roles
- forget: input validation, non-memory guard, URI deletion, query fallback
- Route registration: /mcp route exists in app

* docs(mcp): update integration guide with verified platforms and correct tools

- Add verified platforms table (Claude Code, ChatGPT/Codex, Claude.ai,
  Manus, Trae)
- Document authentication (X-Api-Key / Bearer token)
- Add Claude.ai OAuth proxy (MCP-Key2OAuth) instructions
- Update tool table to match actual implementation (search, read, store,
  forget, health) — remove stale tool names
- Reorganize client config: generic first, then platform-specific

* feat(mcp): expand to 7 tools aligned with vikingbot, split read/list

Align MCP tool surface with vikingbot/agent/tools/ov_file.py:

- Split read/list: read is file-only with semaphore(10) concurrency;
  list is directory-only with recursive support
- store: accept batch messages[] (was single text), matching
  VikingMemoryCommitTool
- search: add min_score parameter (default 0.35), matching
  VikingSearchTool
- add_resource: new tool for adding files/URLs to resources
- Use @mcp.tool(name="list") to avoid shadowing Python builtin

7 tools: search, read, list, store, add_resource, forget, health

* feat(mcp): add grep and glob tools, update docs to 9 tools

Add grep (multi-pattern regex search) and glob (file pattern matching)
MCP tools to align with VikingBot's full tool surface. Update EN/ZH
integration docs to reflect all 9 tools with correct parameters.

* fix(mcp): store schema, forget safety, remove memories-only restriction

- store: use Pydantic StoreMessage model so MCP schema includes
  required role/content field definitions (was bare dict[str, str])
- forget: remove query parameter entirely — deletion requires exact URI,
  use search tool first to find candidates
- forget: remove /memories/ path restriction, allow deleting any URI

* docs(mcp): update forget tool description — exact URI only, no query

* fix(mcp): rename list_dir to ls, add forget safeguard, use Bearer in docs

- Rename list_dir → ls (MCP tool name stays "list") to avoid confusion
  with "only lists directories"
- Add safeguard to forget tool description: irreversible, requires user
  confirmation
- Docs: use Authorization: Bearer in all examples (standard, consistent
  with OAuth proxy flow)
- Fix ruff format on mcp_endpoint.py and test_mcp_endpoint.py
2026-04-28 15:19:16 +08:00
Jiahui Zhou c0ecbe3096 fix(ragfs): make s3 key normalization chars configurable (#1767) 2026-04-28 14:46:31 +08:00
Evo 7b1da1ef5e docs(agfs): document queue_db_path config option from #1751 (#1765)
* docs(agfs): document queue_db_path config option from #1751

* docs(agfs): document queue_db_path config option from #1751 (zh)
2026-04-28 14:28:44 +08:00
Lumos088 d31ec2398e wechat QR code update (#1766) 2026-04-28 14:27:53 +08:00
Qin Haojie ac9f679a0b fix(api): 统一错误 envelope 与会话元数据 (#1764)
* fix(api): standardize error envelopes and session metadata

* fix(session): update archive metadata on commit
2026-04-28 13:59:32 +08:00
Evo a7e4442cc3 docs(s3fs): document endpoint scheme auto-prefix from #1701 (#1720)
* docs(s3fs): document endpoint scheme auto-prefix from #1701

* docs(s3fs): document endpoint scheme auto-prefix from #1701 (zh)
2026-04-28 10:23:19 +08:00