This page looks best with JavaScript enabled

OpenViking Usage and OpenClaw Integration

 ·  ☕ 3 min read

1. Introduction to OpenViking

1.1 Use Cases

ProblemHow OpenViking Handles It
Fragmented contextUnified management with a filesystem paradigm: memory, resources, and skills all map to a viking:// virtual directory, so context is managed the way files are
High token consumptionL0/L1/L2 tiering: the L0 summary (~100 tokens) is used for retrieval, the L1 overview (~2k tokens) for decisions, and the L2 full text is loaded on demand — significant cost savings
Poor retrieval qualityRecursive directory retrieval: vector search first locates a high-scoring directory, then refines recursively inside it, combining semantics with hierarchical structure to improve accuracy
Opaque retrievalEach retrieval path maps to an explicit URI, and retrieval traces can be visualized, making debugging and optimization easier
Memory is hard to iterate onAutomatic session management: when a conversation ends it is compressed and archived automatically, and an LLM extracts long-term memory into user/memories and agent/memories, getting more accurate the more it is used

1.2 Core Concepts

  • Three context types

Resource (knowledge and documents added by the user), Memory (the user’s/Agent’s memory), and Skill (callable capabilities), all organized with Viking URIs

  • Storage architecture

VikingFS provides the URI abstraction; underneath, AGFS stores the content (L0/L1/L2 files) and the Vector Index stores vectors and metadata. Separating the two makes scaling easier

  • Retrieval flow

Supports find() (single-query vector retrieval) and search() (intent analysis → tiered retrieval → Rerank); results are returned by URI and can be distinguished as memories/resources/skills

2. Deploying OpenViking

  • Prepare the data directory
1
2
mkdir -p openviking/data
chmod -R 777 openviking
  • Generate the ROOT_API_KEY
1
openssl rand -hex 32
1
your-token
  • Prepare the configuration file
1
2
3
export OPENAI_API_KEY=sk-xxx
export OPENAI_API_BASE=https://llmapi.xxx.com/v1
export ROOT_API_KEY="your-token"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
cat > openviking/ov.conf <<EOF
{
  "server": {
    "host": "0.0.0.0",
    "port": 1933,
    "root_api_key": "$ROOT_API_KEY",
    "cors_origins": ["*"]
  },
  "storage": {
    "workspace": "/app/data",
    "vectordb": {
      "name": "context",
      "backend": "local"
    },
    "agfs": {
      "backend": "local",
      "port": 1833,
      "log_level": "warn"
    }
  },
  "embedding": {
    "max_concurrent": 10,
    "dense": {
      "provider": "openai",
      "api_key": "$OPENAI_API_KEY",
      "api_base": "$OPENAI_API_BASE",
      "model": "text-embedding-v4",
      "dimension": 1024,
      "input": "text",
      "batch_size": 32
    }
  },
  "vlm": {
    "provider": "openai",
    "api_key": "$OPENAI_API_KEY",
    "api_base": "$OPENAI_API_BASE",
    "model": "default",
    "temperature": 0.0,
    "max_retries": 2,
    "max_concurrent": 100
  },
  "log": {
    "level": "INFO",
    "output": "stdout"
  }
}
EOF

The embedding configuration is used for vectorization, and the vlm configuration is used for summarization, L0/L1, memory extraction, and image and content understanding. No rerank model is configured here. In addition, the backend for vectordb and agfs is set to local, meaning the local filesystem is used for storage.

  • Run the OpenViking container
1
2
3
4
5
6
7
8
9
nerdctl run -d \
   --name openviking \
   --restart always \
   --security-opt apparmor=unconfined \
   --security-opt seccomp=unconfined \
   -p 1933:1933 \
   -v $(pwd)/openviking/data:/app/data \
   -v $(pwd)/openviking/ov.conf:/app/ov.conf \
   ghcr.io/volcengine/openviking:v0.2.9
  • Remove the OpenViking container
1
nerdctl rm -f openviking
  • Verify that the OpenViking service is healthy
1
curl http://127.0.0.1:1933/health

A return of {"status":"ok","healthy":true,"version":"v0.2.9"} means the service is ready.

3. OpenViking User Management

  • Set environment variables
1
2
export OPENVIKING_BASE_URL="http://10.0.0.10:1933"
export ROOT_API_KEY="your-token"
  • List accounts
1
2
curl -fsS -H "X-API-Key: $ROOT_API_KEY" \
  "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts"
1
{"status":"ok","result":[{"account_id":"default","created_at":"2026-03-23T09:58:40.472608+00:00","user_count":0}],"error":null,"telemetry":null}
  • Create an account and admin user
1
2
3
4
curl -fsS -X POST "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $ROOT_API_KEY" \
  -d '{"account_id":"my-team","admin_user_id":"my-admin"}'
1
{"status":"ok","result":{"account_id":"my-team","admin_user_id":"my-admin","user_key":"49331c3c1cafb6e5670f316d47aabfaae6c628b6ae72a0d05f35b7c93da763a2"},"error":null,"telemetry":null}
  • Create a user

You need to provide the admin user key under the account

1
2
3
4
5
export ADMIN_USER_KEY="49331c3c1cafb6e5670f316d47aabfaae6c628b6ae72a0d05f35b7c93da763a2"
curl -fsS -X POST "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts/my-team/users" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $ADMIN_USER_KEY" \
  -d '{"user_id":"my-user","role":"user"}'
1
{"status":"ok","result":{"account_id":"my-team","user_id":"my-user","user_key":"ad133ab241f779f19e2efe0c69655bd97dd67ac3a26a58d36a4a30c346e4b53f"},"error":null,"telemetry":null}
  • List the users under an account
1
2
curl -fsS -H "X-API-Key: $ADMIN_USER_KEY" \
  "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts/my-team/users"
1
{"status":"ok","result":[{"user_id":"my-admin","role":"admin"},{"user_id":"my-user","role":"user"}],"error":null,"telemetry":null}
  • Change a user’s role
1
2
3
4
curl -fsS -X PUT "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts/my-team/users/my-user/role" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $ROOT_API_KEY" \
  -d '{"role":"admin"}'
1
{"status":"ok","result":{"account_id":"my-team","user_id":"my-user","role":"admin"},"error":null,"telemetry":null}
  • Regenerate the user key (the old key is invalidated immediately; use the Root or Admin User Key)
1
2
3
4
curl -fsS -X POST "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts/my-team/users/my-user/key" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $ADMIN_USER_KEY" \
  -d '{}'
1
{"status":"ok","result":{"user_key":"97b790bed56e40d288d3c60ee09abb41d821fb039fb2a53f92fe4fbd629ea8cd"},"error":null,"telemetry":null}
  • Delete a user
1
2
curl -fsS -X DELETE "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts/my-team/users/my-user" \
  -H "X-API-Key: $ADMIN_USER_KEY"
  • Delete an entire account
1
2
curl -fsS -X DELETE "${OPENVIKING_BASE_URL%/}/api/v1/admin/accounts/my-team" \
  -H "X-API-Key: $ROOT_API_KEY"

4. Using OpenViking Features

  • Set environment variables
1
2
3
export OPENVIKING_BASE_URL="http://10.0.0.10:1933"
export USER_ID="my-user"
export USER_KEY="97b790bed56e40d288d3c60ee09abb41d821fb039fb2a53f92fe4fbd629ea8cd"
  • Create a directory
1
2
3
4
curl -fsS -X POST "$OPENVIKING_BASE_URL/api/v1/fs/mkdir" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $USER_KEY" \
  -d '{"uri":"viking://resources/lifecycle-demo/"}'
1
{"status":"ok","result":{"uri":"viking://resources/lifecycle-demo/"},"error":null,"telemetry":null}
  • Upload to a temporary directory
1
2
3
4
5
export FILE_PATH="/tmp/ov-lifecycle.md"
echo 'Hello OpenViking lifecycle' > $FILE_PATH
curl -fsS -X POST "$OPENVIKING_BASE_URL/api/v1/resources/temp_upload" \
  -H "X-API-Key: $USER_KEY" \
  -F "file=@$FILE_PATH"
1
{"status":"ok","result":{"temp_path":"/app/data/temp/upload/upload_3c5f30d789b9439e91f16da9b22555cc.md"}}
  • Ingest into the directory created in the previous step
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
export TEMP_PATH="/app/data/temp/upload/upload_3c5f30d789b9439e91f16da9b22555cc.md"
curl -fsS -X POST "$OPENVIKING_BASE_URL/api/v1/resources" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $USER_KEY" \
  -d "{
    \"temp_path\": \"$TEMP_PATH\",
    \"parent\": \"viking://resources/lifecycle-demo/\",
    \"wait\": false,
    \"reason\": \"curl lifecycle\"
  }"
1
{"status":"ok","result":{"status":"success","errors":[],"source_path":"/app/data/temp/upload/upload_3c5f30d789b9439e91f16da9b22555cc.md","meta":{},"root_uri":"viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc","temp_uri":"viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc"}}
  • List a directory
1
2
3
4
5
curl -fsS -G \
  -H "X-API-Key: $USER_KEY" \
  --data-urlencode "uri=viking://resources/lifecycle-demo/" \
  --data-urlencode "recursive=true" \
  "$OPENVIKING_BASE_URL/api/v1/fs/ls"
1
{"status":"ok","result":[{"uri":"viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc","size":88,"isDir":true,"modTime":"09:02:48","rel_path":"upload_3c5f30d789b9439e91f16da9b22555cc","abstract":""},{"uri":"viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc/upload_3c5f30d789b9439e91f16da9b22555cc.md","size":27,"isDir":false,"modTime":"09:02:48","rel_path":"upload_3c5f30d789b9439e91f16da9b22555cc/upload_3c5f30d789b9439e91f16da9b22555cc.md","abstract":""}],"error":null,"telemetry":null}
  • Read the full text
1
2
3
4
5
export FILE_URI="viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc/upload_3c5f30d789b9439e91f16da9b22555cc.md"
curl -fsS -G \
  -H "X-API-Key: $USER_KEY" \
  --data-urlencode "uri=$FILE_URI" \
  "$OPENVIKING_BASE_URL/api/v1/content/read"
1
{"status":"ok","result":"Hello OpenViking lifecycle\n","error":null,"telemetry":null}
  • View metadata
1
2
3
4
5
export FILE_URI="viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc/upload_3c5f30d789b9439e91f16da9b22555cc.md"
curl -fsS -G \
  -H "X-API-Key: $USER_KEY" \
  --data-urlencode "uri=$FILE_URI" \
  "$OPENVIKING_BASE_URL/api/v1/fs/stat"
1
{"status":"ok","result":{"isDir":false,"modTime":"2026-03-24T09:02:48.710880298Z","mode":420,"name":"upload_3c5f30d789b9439e91f16da9b22555cc.md","size":27},"error":null,"telemetry":null}
  • find: semantic retrieval

A rerank model can be configured.

1
2
3
4
5
6
7
8
curl -fsS -X POST "$OPENVIKING_BASE_URL/api/v1/search/find" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $USER_KEY" \
  -d '{
    "query": "Hello",
    "target_uri": "viking://resources/lifecycle-demo/",
    "limit": 5
  }'

The response will be relatively slow, since a model is called.

1
{"status":"ok","result":{"memories":[],"resources":[{"context_type":"resource","uri":"viking://resources/lifecycle-demo/upload_a67d1858a30f4c4d91df60e7a489448c/upload_a67d1858a30f4c4d91df60e7a489448c_1.md","level":2,"score":0.09988392326968897,"category":"","match_reason":"","relations":[],"abstract":"","overview":null}],"skills":[],"total":2}}
  • grep: text matching
1
2
3
4
curl -fsS -X POST "$OPENVIKING_BASE_URL/api/v1/search/grep" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $USER_KEY" \
  -d '{"uri":"viking://resources/lifecycle-demo/","pattern":"Hello"}'
1
{"status":"ok","result":{"matches":[{"line":24,"uri":"viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc/.overview.md","content":""},{"line":1,"uri":"viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc/upload_3c5f30d789b9439e91f16da9b22555cc.md","content":"Hello OpenViking lifecycle"},{"line":1,"uri":"viking://resources/lifecycle-demo/upload_d318b2c6f0494e88af77f9d1afbc18de/upload_d318b2c6f0494e88af77f9d1afbc18de.md","content":"Hello OpenViking lifecycle"}],"count":3},"error":null,"telemetry":null}
  • search: semantic and intent retrieval, optionally with a session.
1
2
3
4
curl -fsS -X POST "$OPENVIKING_BASE_URL/api/v1/sessions" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $USER_KEY" \
  -d '{}'
1
{"status":"ok","result":{"session_id":"d46e0160-1ebc-483d-971f-32d60bb1de9a","user":{"account_id":"my-team","user_id":"my-user","agent_id":"default"}},"error":null,"telemetry":null}
1
2
3
4
5
6
7
8
9
export SESSION_ID="d46e0160-1ebc-483d-971f-32d60bb1de9a"
curl -fsS -X POST "$OPENVIKING_BASE_URL/api/v1/search/search" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $USER_KEY" \
  -d '{
    "query": "Hello",
    "session_id": "$SESSION_ID",
    "limit": 5
  }'

A model is called here as well.

  • Delete a file
1
2
3
4
curl -fsS -X DELETE \
  -H "X-API-Key: $USER_KEY" \
  --get "$OPENVIKING_BASE_URL/api/v1/fs" \
  --data-urlencode "uri=$FILE_URI"
1
{"status":"ok","result":{"uri":"viking://resources/lifecycle-demo/upload_3c5f30d789b9439e91f16da9b22555cc/upload_3c5f30d789b9439e91f16da9b22555cc.md"},"error":null,"telemetry":null}
  • Delete a directory
1
2
3
curl -fsS -X DELETE \
  -H "X-API-Key: $USER_KEY" \
  "$OPENVIKING_BASE_URL/api/v1/fs?uri=viking://resources/lifecycle-demo/&recursive=true"
1
{"status":"ok","result":{"uri":"viking://resources/lifecycle-demo/"},"error":null,"telemetry":null}
  • Confirm it is empty
1
2
3
4
curl -fsS -G \
  -H "X-API-Key: $USER_KEY" \
  --data-urlencode "uri=viking://resources/" \
  "$OPENVIKING_BASE_URL/api/v1/fs/ls"
1
{"status":"ok","result":[],"error":null,"telemetry":null}

5. Integrating OpenClaw with OpenViking

OpenClaw: 2026.3.11 is recommended; higher versions may have compatibility issues

  • Enter the OpenClaw container
1
nerdctl exec -it openclaw bash
  • Disable the default memory backend
1
2
3
4
openclaw config set agents.defaults.memorySearch.enabled false --json
openclaw config set memory.qmd.includeDefaultMemory false --json
openclaw config set hooks.internal.entries.session-memory.enabled false --json
openclaw config set agents.defaults.compaction.memoryFlush.enabled false --json
  • Install the setup wizard
1
npm install -g openclaw-openviking-setup-helper
  • Start configuration
1
ov-install

Choose remote, and fill in the OpenViking service address and USER_KEY.

  • Enable the plugin
1
openclaw config set plugins.slots.memory openviking
  • Restart OpenClaw
1
openclaw gateway restart
  • View the plugin configuration
1
openclaw config get plugins.entries.openviking.config
1
2
3
4
5
6
7
8
🦞 OpenClaw 2026.3.11 (unknown) — I've survived more breaking changes than your last three relationships.

{
  "mode": "remote",
  "baseUrl": "http://10.0.0.10:1933",
  "apiKey": "__OPENCLAW_REDACTED__",
  "agentId": "openclaw-viking"
}
  • View the plugin status
1
node openclaw.mjs status |grep Memory
1
│ Memory          │ enabled (plugin openviking)
  • Verify that the integration succeeded

Try a conversation with OpenClaw; you will see logs of OpenViking creating the relevant memory.

1
nerdctl logs openviking -f
1
2026-03-24 10:20:59,392 - openviking.session.memory_extractor - INFO - uri viking://user/my-user/memories/events/mem_372fc569-f140-4a31-a266-6a795bf49af0.md abstract: 正在学习参考 LVM 日常运维文章作为速查手册,将其作为运维工作的速查手册使用。文章内容涵盖物理卷(PV)、卷组(VG)、逻辑卷(LV)的管理命令,以及 RAID 逻辑卷配置、扩容缩容操作等实用内容。

6. References


微信公众号
WRITTEN BY
微信公众号