Skip to content

Latest commit

 

History

History
300 lines (211 loc) · 10.3 KB

File metadata and controls

300 lines (211 loc) · 10.3 KB

Multi-Tenant

OpenViking multi-tenancy does not mean "deploy one isolated server per team." Instead, a single OpenViking Server uses three identity boundaries, account, user, and agent, to control sharing and isolation.

This model fits two common scenarios:

  • Multiple teams or customers share one OpenViking service, but their data must stay isolated
  • Multiple users and multiple agents inside one team need shared resources but isolated memories

What It Enables

With multi-tenancy enabled, you can:

  • Serve multiple teams, customers, or applications from one OpenViking Server
  • Isolate different teams with account
  • Share resources within the same account
  • Isolate user memories and sessions with user
  • Further separate agent memories, skills, and instructions with agent_id
  • Manage permissions with ROOT / ADMIN / USER roles
  • Support different integration patterns such as OpenClaw plugin, Vikingbot, CLI, and HTTP SDKs

Core Identity Model

account_id

account is the outer tenant boundary. You can think of it as a workspace, team, or customer space.

  • Data is isolated across different account values by default
  • ROOT can create and delete accounts
  • resources, user, agent, and session all live inside an account

user_id

user is the per-account user boundary.

  • User memories and user sessions are isolated by user_id
  • A normal user can only access its own user space
  • An admin can manage users inside the same account

agent_id

agent_id separates agent-level space.

  • In the default mode, agent space is derived from user_id + agent_id
  • That means different agents for the same user can have different agent memories
  • If memory.agent_scope_mode = "agent", the same agent_id can share agent space across users in the same account

Roles

Role Scope Typical capabilities
ROOT Global Create/delete accounts, cross-tenant access, user management
ADMIN Single account Manage users in the same account, regenerate user keys
USER Single account Access its own user/agent/session data and shared resources in the same account

Authentication Modes

OpenViking Server supports two multi-tenant related authentication modes:

Mode Config Identity source Typical use case
api_key server.auth_mode = "api_key" Root key or user key Standard deployment
trusted server.auth_mode = "trusted" Upstream-injected X-OpenViking-Account / X-OpenViking-User Behind a trusted gateway

What root_api_key Does

Once server.root_api_key is configured, OpenViking enters formal multi-tenant mode:

  • The root key manages accounts and users
  • User keys are generated by the Admin API for normal data access
  • The server resolves account_id, user_id, and role from the user key

If auth_mode = "api_key" and root_api_key is not configured, the server runs in dev mode:

  • All requests are treated as ROOT
  • The default identity is default/default/default
  • This is only allowed on localhost

Sharing and Isolation Boundaries

Logical Layer

Data type Shared across accounts Shared inside one account Default isolation boundary
resources No Yes account
user No No user
agent No Depends on memory.agent_scope_mode Default: user + agent
session No No user / session

Storage Layer

For users, URIs still look like normal viking://... paths:

viking://resources/project-a/
viking://user/alice/memories/
viking://agent/91f3ab12cd34/memories/

But the underlying storage automatically gains an account prefix:

/local/{account_id}/resources/project-a/
/local/{account_id}/user/alice/memories/
/local/{account_id}/agent/91f3ab12cd34/memories/

So multi-tenant isolation does not rely on a special public URI format. It relies on request context, account_id, user_id, and agent_id, applied consistently through the stack.

Retrieval Layer

Semantic retrieval is tenant-aware as well:

  • Non-ROOT requests are automatically filtered by account_id
  • resources can include account-shared resources
  • memory and skill are further filtered by the current user space and agent space

This keeps "what you can search" aligned with "what you can read."

Standard Usage Flow

1. Enable multi-tenancy

{
  "server": {
    "auth_mode": "api_key",
    "root_api_key": "your-secret-root-key"
  }
}

2. ROOT creates an account and the first admin

curl -X POST http://localhost:1933/api/v1/admin/accounts \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secret-root-key" \
  -d '{
    "account_id": "acme",
    "admin_user_id": "alice"
  }'

3. ADMIN or ROOT registers normal users

curl -X POST http://localhost:1933/api/v1/admin/accounts/acme/users \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <admin-or-root-key>" \
  -d '{
    "user_id": "bob",
    "role": "user"
  }'

4. Prefer user keys for normal application traffic

For normal reads, writes, searches, and session commits, prefer a user key:

curl http://localhost:1933/api/v1/fs/ls?uri=viking:// \
  -H "X-API-Key: <bob-user-key>" \
  -H "X-OpenViking-Agent: coding-agent"

This lets the server resolve identity directly from the key, without extra tenant headers.

5. Only ROOT uses explicit tenant headers for tenant-scoped data APIs

ROOT does not need tenant headers for Admin APIs, but it does need them for tenant-scoped data APIs such as ls, find, and sessions:

curl http://localhost:1933/api/v1/fs/ls?uri=viking:// \
  -H "X-API-Key: <root-key>" \
  -H "X-OpenViking-Account: acme" \
  -H "X-OpenViking-User: alice" \
  -H "X-OpenViking-Agent: coding-agent"

Integration Patterns

OpenClaw Plugin 2.0: one instance uses one user key

The current OpenClaw plugin follows a "plugin holds one user identity" model:

  • Remote mode config is baseUrl + apiKey + agentId
  • apiKey should normally be a user key
  • The server resolves account_id and user_id from that user key
  • The plugin explicitly passes X-OpenViking-Agent

Typical config:

openclaw config set plugins.entries.openviking.config.mode remote
openclaw config set plugins.entries.openviking.config.baseUrl "http://your-server:1933"
openclaw config set plugins.entries.openviking.config.apiKey "<user-api-key>"
openclaw config set plugins.entries.openviking.config.agentId "<agent-id>"

Characteristics of this model:

  • Simple integration, because the plugin does not manage account/user lifecycle
  • Best for "one OpenClaw instance maps to one OpenViking user identity"
  • agentId distinguishes different OpenClaw instances or agent roles
  • resources can be shared inside the same account, while user and agent memory stay identity-scoped

Why the OpenClaw plugin usually does not set account / user

In api_key mode, a user key is already enough to express identity:

  • account and user are resolved server-side from the key
  • The plugin only needs to provide agentId
  • Internally, the plugin derives default user and agent memory scopes from the runtime identity

If you give the plugin a root key directly, normal tenant-scoped data APIs will lack X-OpenViking-Account and X-OpenViking-User, so that is not a good default for day-to-day access.

Vikingbot: root key manages many end users

Vikingbot uses a different practice. It behaves more like a platform serving many end users:

  • The bot connects to OpenViking with a root key
  • The bot config fixes an account_id
  • The bot automatically registers users inside that account
  • The bot caches per-user user keys and uses them for memory commit/search whenever possible

Example config:

{
  "bot": {
    "ov_server": {
      "server_url": "http://127.0.0.1:1933",
      "root_api_key": "test",
      "account_id": "default",
      "admin_user_id": "default"
    }
  }
}

Characteristics of this model:

  • Good for one bot service serving many chat users
  • All users inside the same account share resources
  • User memories are isolated through auto-managed user identities
  • The bot takes on more tenant lifecycle management logic than the OpenClaw plugin

Which Practice to Choose

Scenario Recommended pattern
One OpenClaw instance maps to one fixed identity OpenClaw plugin + user key
One gateway or bot service serves many end users Vikingbot + root-key-managed users
A trusted gateway injects identity upstream trusted mode
Local single-user experience without formal tenant isolation Dev mode without root_api_key

Common Misunderstandings

1. root_api_key is not the normal business-access key

The root key is mainly for:

  • Creating and deleting accounts
  • Registering users
  • Regenerating keys
  • Operations and diagnostics

Normal application traffic should prefer user keys.

2. agentId does not define the tenant

agentId only defines the agent-level space.

  • The tenant boundary is account_id
  • The user boundary is user_id
  • The agent boundary is agent_id

3. No root_api_key does not mean "formal single-tenant production mode"

That is only dev mode:

  • All requests run as ROOT
  • It is not suitable for public or shared deployments

4. OpenClaw plugin and Vikingbot are not the same multi-tenant pattern

  • OpenClaw plugin is closer to "a client directly uses one user identity"
  • Vikingbot is closer to "a platform manages many users and their user keys"

Related Documentation