Skip to content

Viking URI ​

Viking URI is the unified resource identifier for all content in OpenViking.

Format ​

viking://{scope}/{path}
  • scheme: Always viking
  • scope: Top-level namespace (resources, user, agent; temp, queue, and upload are internal)
  • path: Resource path within the scope

Scopes ​

ScopeDescriptionLifecycleVisibility
resourcesIndependent resources / objective knowledgeLong-termAccount global
userUser-level data, including sessionsLong-term / session lifetimeCurrent user
agentAccount-shared skills and Agent configuration; endpoint, tool, and payment directories are plannedLong-termAccount global
queueProcessing queueTemporaryInternal
tempTemporary filesDuring parsingInternal
uploadTemporary upload filesTemporaryInternal

Public API and CLI filesystem/content operations accept the public scopes resources, user, and agent, plus the root URI viking://. session is retained as a backward-compatible alias for user session paths; new session data lives under viking://user/{user_id}/sessions. temp, queue, and upload are internal implementation scopes and cannot be addressed directly through public API URI parameters.

Home Alias ~ ​

~ is a server-side alias for the caller's own user root. viking://~ expands to viking://user/{user_id}, and viking://~/memories/note.md to viking://user/{user_id}/memories/note.md, where {user_id} comes from the request's authenticated identity — the same string therefore points at a different directory for each caller.

  • Universal: accepted by every control plane (REST API, ov CLI, SDKs, MCP), anywhere a public-scope URI is accepted.
  • First segment only: viking://resources/~/x and viking://user/alice/~/x keep ~ as a literal path segment.
  • ~ is a user-path alias, not a separate storage scope.
  • Responses always echo the expanded canonical URI, never viking://~, and persisted data (vector records, watch keys) stays canonical as well.
  • Requires an authenticated request identity. Expansion uses that identity's effective user_id for every request role, including root. Places that demand an already-canonical URI (internal storage paths and background tasks without a request context) reject the alias instead of guessing a user.
  • Replaces the removed uid-less shorthand: viking://user/<segment>/... for memories, resources, skills, peers, privacy, and sessions is rejected at USER/ADMIN request boundaries with an error that names the viking://~/... replacement.

Initial Directory Structure ​

Context is organized into directories. With a known URI, an agent can list a directory or read a file directly. Otherwise, it can search first and read the returned paths.

viking://
├── user/
│   └── {user_id}/
│       ├── memories/         # User memory storage
│       │   └── profile.md        # User profile
│       ├── resources/        # User-owned private resources
│       ├── skills/           # User skills
│       ├── peers/
│       │   └── {peer_id}/
│       │       ├── memories/  # Memory about a specific interaction peer
│       │       └── resources/ # Resources scoped to that peer
│       └── sessions/         # User session storage
│           └── {session_id}/
│               ├── .abstract.md
│               ├── .overview.md
│               ├── .meta.json
│               ├── messages.jsonl
│               ├── tools/
│               └── history/
│
├── agent/                     # Agent capabilities and configuration (global)
│   ├── skills/                # Skill definitions
│   ├── endpoints/             # Communication endpoints (a2a, anp, etc.) (planned)
│   ├── tools/                 # Tool configuration (mcp, etc.) (planned)
│   └── payments/              # Payment configuration (ap2, etc.) (planned)
│
└── resources/{project}/      # Resource workspace

File IDs ​

In addition to its URI, every file is automatically assigned a stable id that serves as the primary key of its vector record in VikingDB. The id is deterministically computed as md5(f"{account_id}:{uri}") for level 2 (regular file) records, and is returned by stat() and other metadata APIs. This allows callers to cross-reference vector index entries without a separate lookup. The id is scoped to the account and changes if the file is moved to a different URI (vector records are re-keyed during URI migration). Directories do not expose a single id because a directory may span multiple semantic levels (L0 abstract, L1 overview), each with its own record.

URI Examples ​

Resources ​

viking://resources/                           # All resources
viking://resources/my-project/                # Project root
viking://resources/my-project/docs/           # Docs directory
viking://resources/my-project/docs/api.md     # Specific file

User Data ​

viking://user/                                # Container of all user spaces (a user key lists only its own)
viking://~/                                   # Your own user root (expands to viking://user/{user_id}/)
viking://~/memories/                          # All your memories
viking://~/memories/preferences/              # Your preferences
viking://~/memories/preferences/coding        # Specific preference
viking://~/memories/entities/                 # Entity memories
viking://~/memories/events/                   # Event memories
viking://~/resources/                         # Your private resources
viking://~/resources/docs/                    # Your private resource directory
viking://user/{user_id}/memories/             # Explicit user path (own user_id only, ADMIN included; ROOT can read across user spaces, but ROOT API keys cannot use data APIs in api_key mode)

viking://resources/... is the shared scope for the current account and supports per-directory or per-file ACLs. viking://user/{user}/resources/... is private; move a resource into the shared scope to share it.

User Skills and Peer Content ​

viking://~/skills/                            # Your skills
viking://~/skills/search-web                  # Specific skill
viking://~/memories/                          # Your memories
viking://~/memories/cases/                    # Task cases used for training and evaluation
viking://~/memories/trajectories/             # Reusable task-execution trajectories
viking://~/memories/experiences/              # Experience distilled from execution outcomes
viking://user/{user_id}/peers/{peer_id}/memories/
viking://user/{user_id}/peers/{peer_id}/resources/

Agent Capabilities and Configuration ​

viking://agent/skills/search-web                    # A specific skill definition
viking://agent/skills/                              # All skill definitions
viking://agent/endpoints/                           # Communication endpoints (a2a, anp, etc.) (planned)
viking://agent/tools/mcp/                           # MCP tool configuration (planned)
viking://agent/payments/ap2/                        # Payment configuration (planned)

viking://agent/... is an account-shared directory for capabilities and configuration, including skills, endpoints, tools, payments, and other subdirectories. Directory names do not identify agents, and actor_peer_id does not filter this scope. Sharing is limited to the current account. Peer data belongs under viking://user/<user_id>/peers/<peer_id>/....

The home alias viking://~/... is relative to the current request identity. OpenViking expands it internally to the explicit namespace path viking://user/{user_id}/... before storage and retrieval, and responses echo the expanded form.

The older uid-less spelling — viking://user/memories/... and the same shape for resources, skills, peers, privacy, and sessions — is no longer accepted at the request boundary. Such requests fail with an error that points at the viking://~/... replacement. viking://user itself is the container of user spaces, not a shortcut to your own root: listing it with a user key shows only your own space.

Identity path segments such as {user_id} and {peer_id} must be safe single segments, for example alice or web-visitor-alice.

Session Data ​

viking://user/{user_id}/sessions/{session_id}/          # Session root
viking://user/{user_id}/sessions/{session_id}/messages.jsonl  # Session messages
viking://user/{user_id}/sessions/{session_id}/tools     # Tool executions
viking://user/{user_id}/sessions/{session_id}/history   # Archived history
viking://~/sessions/{session_id}/                       # Your own session, via the home alias

viking://session/{session_id} is accepted as a backward-compatible alias for the current user's session path. It is not a separate storage root for new session data.

Path Variables ​

Viking URI supports path variables for dynamic path generation. This is especially useful for organizing time-series data like emails, logs, daily reports, etc.

Variable Syntax ​

{namespace:key}
  • namespace: Variable provider namespace (calendar is built in)
  • key: Variable name within the namespace

Calendar Variables ​

The calendar namespace provides date-related variables:

VariableDescriptionExample (2026-05-07)
{calendar:today}Full date path2026/05/07
{calendar:yesterday}Yesterday's date path2026/05/06
{calendar:tomorrow}Tomorrow's date path2026/05/08
{calendar:year}Year2026
{calendar:month}Month with leading zero05
{calendar:day}Day with leading zero07
{calendar:ym}Year/month2026/05
{calendar:quarter}Quarter (Q1-Q4)Q2
{calendar:yq}Year/quarter2026/Q2
{calendar:week}ISO week number with leading zero19
{calendar:yw}Year/ISO week2026/w19

Usage Examples ​

text
# Organize emails by date
viking://resources/emails/{calendar:today}/inbox
# Renders to: viking://resources/emails/2026/05/07/inbox

# View yesterday's logs
viking://resources/logs/{calendar:yesterday}/app.log
# Renders to: viking://resources/logs/2026/05/06/app.log

# Pre-upload tomorrow's tasks
viking://resources/tasks/{calendar:tomorrow}/todo.md
# Renders to: viking://resources/tasks/2026/05/08/todo.md

# Monthly logs
viking://resources/logs/{calendar:year}/{calendar:month}/app.log
# Renders to: viking://resources/logs/2026/05/app.log

# Daily snapshots
viking://resources/snapshots/{calendar:today}/
# Renders to: viking://resources/snapshots/2026/05/07/

Resolution ​

Path variables are resolved server-side at the time of API execution. The CLI/SDK passes the URI template as-is, and the server renders it to a concrete path based on the current context (time, authenticated user, etc.).

Use with CLI ​

bash
# Add today's emails, --parent-auto-create can be shortened to -p
ov add-resource --parent-auto-create "viking://resources/emails/{calendar:today}/inbox" ./emails/

# Read yesterday's log
ov read "viking://resources/logs/{calendar:yesterday}/app.log"

# Prep tomorrow's tasks
ov write "viking://resources/tasks/{calendar:tomorrow}/todo.md" --content "Plan the day"

# Upload monthly report, --parent-auto-create can be shortened to -p
ov add-resource --parent-auto-create "viking://resources/reports/{calendar:ym}" ./report.pdf

Directory Structure ​

viking://
├── resources/       # Account-shared reference material
│   └── {project}/
│       ├── .abstract.md
│       ├── .overview.md
│       └── {files...}
│
├── user/{user_id}/
│   ├── memories/
│   │   ├── profile.md        # User profile
│   │   ├── preferences/          # By topic
│   │   ├── entities/             # Each independent
│   │   └── events/               # Each independent
│   ├── resources/
│   │   └── {project}/
│   ├── skills/
│   └── peers/{peer_id}/
│       ├── memories/
│       └── resources/
│
├── agent/                        # Agent capabilities and configuration (account global)
│   ├── skills/                   # Skill definitions
│   ├── endpoints/                # Communication endpoints (a2a, anp, etc.) (planned)
│   ├── tools/                    # Tool configuration (mcp, etc.) (planned)
│   └── payments/                 # Payment configuration (ap2, etc.) (planned)
│
└── user/{user_id}/sessions/{session_id}/
    ├── messages.jsonl
    ├── tools/
    └── history/

viking://agent/... is an account-shared directory without an Agent ID identity layer. actor_peer_id filters only the current user's peers collection. Shared directories remain isolated by account.

URI Operations ​

The VikingURI helper below comes from the openviking_cli package installed with the server, not the standalone Python SDK public interface.

Parsing ​

python
from openviking_cli.utils.uri import VikingURI

uri = VikingURI("viking://resources/docs/api")
print(uri.scope)      # "resources"
print(uri.full_path)  # "resources/docs/api"

Building ​

python
# Join paths
base = "viking://resources/docs/"
full = VikingURI(base).join("api.md").uri  # viking://resources/docs/api.md

# Parent directory
uri = "viking://resources/docs/api.md"
parent = VikingURI(uri).parent.uri  # viking://resources/docs

API Usage ​

The Python examples below use a configured SyncHTTPClient instance named client; see Client Configuration.

Targeting Specific Scopes ​

python
# Search only in resources
results = client.find(
    query="authentication",
    target_uri="viking://resources/",
)

# Search only in your own resources
results = client.find(
    query="private project notes",
    target_uri="viking://~/resources/"
)

# Search only in your own memories
results = client.find(
    query="coding preferences",
    target_uri="viking://~/memories/"
)

# Search only in your own skills
results = client.find(
    query="web search",
    target_uri="viking://~/skills/"
)

# Search only in global agent skills
results = client.find(
    query="web search",
    target_uri="viking://agent/skills/",
)

File System Operations ​

python
# List directory
entries = client.ls(uri="viking://resources/")

# Read file
content = client.read(uri="viking://resources/docs/api.md")

# Get abstract
abstract = client.abstract(uri="viking://resources/docs/")

# Get overview
overview = client.overview(uri="viking://resources/docs/")

Special Files ​

Each directory may contain special files:

FilePurpose
.abstract.mdL0 directory abstract (default body limit: 256 characters)
.overview.mdL1 directory overview (default body limit: 4,000 characters)
.meta.jsonMetadata

Best Practices ​

Use Trailing Slash for Directories ​

python
# Directory
"viking://resources/docs/"

# File
"viking://resources/docs/api.md"

Scope-Specific Operations ​

python
# Add resources to the shared account resource scope
client.add_resource(url, to="viking://resources/project/")

# Add private resources to your own resource root
client.add_resource(path, parent="viking://~/resources/project/")

# Skills are added to your own skills root by default
client.add_skill(skill)  # default root: viking://~/skills/

Install into the account-shared skills directory with the CLI. This requires write access to that path:

bash
ov skills add ./skills/search-web -p viking://agent/skills/

Resources Scope Constraint ​

Store reference documents, code, and specifications under resources. To make content discoverable and loadable as a Skill, install it through the skill API under viking://~/skills/ or the shared viking://agent/skills/. Uploading SKILL.md as an ordinary resource does not install a skill.

Open source under the AGPL-3.0 License. Font licenses