Skip to content

Viking URI: How OpenViking Identifies and Organizes AI Agent Context

Purpose

This post explains the Viking URI specification and how it enables deterministic context access in OpenViking.

Problem

When I first started using OpenViking, I kept getting confused about how to reference specific pieces of context. I’d use find() for everything, even when I knew exactly where the resource was.

Here’s what my code looked like:

inefficient-retrieval.py
# I knew the file was at resources/docs/auth/oauth.md
# But I still used semantic search
results = client.find("oauth authentication guide")
for result in results:
if "oauth" in result.path:
content = result.content
break

This felt wrong. I knew the exact location—why was I searching? It was like using Google every time I wanted to open a file on my own computer.

Then I discovered Viking URIs.

What is a Viking URI?

A Viking URI is OpenViking’s unified resource identifier format. Every piece of context—documents, memories, skills, sessions—has a unique URI that determines its location in the virtual filesystem.

The format is simple:

uri-format.txt
viking://[context_type]/[namespace]/[path]

From the OpenViking documentation:

“Each context is assigned a unique viking:// URI, enabling precise location and access to resources stored in different locations.”

This transforms vague semantic matching into precise, traceable operations.

Environment

  • Python 3.10+
  • OpenViking SDK
  • Basic understanding of filesystem navigation

URI Components

Let me break down each component:

uri-breakdown.txt
viking://resources/github.com/owner/repo/docs/api.md
│ │ │ │
│ │ │ └── Path: hierarchical location
│ │ └── Namespace: logical grouping
│ └── Context Type: what kind of resource
└── Protocol: always "viking://"

Context Types

OpenViking uses four main context types:

context-types.txt
resources/ -> External knowledge (docs, PDFs, web pages)
user/ -> User-specific memories
agent/ -> Agent-learned memories and skills
session/ -> Conversation sessions

I made a quick reference table:

TypeURI PrefixPurpose
Resourceviking://resources/External knowledge from URLs or files
User Memoryviking://user/memories/User preferences and facts
Agent Memoryviking://agent/memories/Agent task experiences
Skillviking://agent/skills/Callable capabilities
Sessionviking://session/Conversation history

URI in Action

Resource URIs

For external resources, I use URL-based namespaces:

resource-uris.py
from openviking import OpenViking
client = OpenViking()
# Add a resource from GitHub
client.add_resource(
url="https://github.com/volcengine/OpenViking/blob/main/README.md",
path="viking://resources/github.com/volcengine/OpenViking/README.md"
)
# Later, access it directly without search
content = client.read("viking://resources/github.com/volcengine/OpenViking/README.md")

No semantic search needed. I knew the URI, so I accessed it directly.

Memory URIs

User memories follow a predictable structure:

memory-uris.py
# User profile memory
profile = client.read("viking://user/memories/profile.md")
# User preferences
prefs = client.read("viking://user/memories/preferences/coding_style.md")
# Entity memories (project, person, company)
entity = client.read("viking://user/memories/entities/project_alpha.md")

Agent memories for task experiences:

agent-memories.py
# Case memories - specific debugging scenarios
case = client.read("viking://agent/memories/cases/debug_auth_issue.md")
# Pattern memories - reusable solutions
pattern = client.read("viking://agent/memories/patterns/api_error_handling.md")

Skill URIs

Skills have their own namespace:

skill-uris.py
# List available skills
skills = client.ls("viking://agent/skills/")
# Returns: ['search_web/', 'analyze_code/', 'send_email/']
# Read a skill definition
skill_def = client.read("viking://agent/skills/search_web/SKILL.md")

Operations with URIs

List and Tree

I use ls and tree to explore:

explore-uris.py
# List contents of a directory
entries = client.ls("viking://resources/my_project/")
# Returns: ['docs/', 'src/', 'README.md']
# View hierarchical structure
tree = client.tree("viking://resources/my_project", depth=3)

The tree output shows the hierarchy:

tree-output.txt
viking://resources/my_project
├── docs/
│ ├── api/
│ │ ├── authentication.md
│ │ └── endpoints.md
│ └── getting-started.md
├── src/
│ └── main.py
└── README.md

Read

Direct access when I know the URI:

direct-read.py
content = client.read("viking://resources/docs/api/authentication.md")
print(content)

Search Within a URI

I can combine search with URI paths for scoped retrieval:

scoped-search.py
# Search only within docs/api/
results = client.find(
"authentication",
target_uri="viking://resources/docs/api/"
)
for ctx in results.resources:
print(f"URI: {ctx.uri}")
print(f"Abstract: {ctx.abstract}")
print(f"Score: {ctx.score}")

This is powerful: semantic search within a known directory.

Grep

Search for patterns within files:

grep-uris.py
# Find all TODO comments in a project
matches = client.grep(
"TODO",
uri="viking://resources/my_project/"
)

Special Files: Abstracts and Overviews

Every directory can contain metadata files that support OpenViking’s tiered loading:

special-files.txt
viking://resources/docs/auth/
├── .abstract.md # L0: ~100 token summary (always loaded)
├── .overview.md # L1: ~2k token overview (on demand)
├── .relations.json # Links to related contexts
├── oauth.md # L2: Full content (when needed)
└── jwt.md

I read these directly:

special-uris.py
# Get the abstract (L0)
abstract = client.read("viking://resources/docs/auth/.abstract.md")
# Get the overview (L1)
overview = client.read("viking://resources/docs/auth/.overview.md")
# Get relations (linked contexts)
relations = client.read("viking://resources/docs/auth/.relations.json")

Or use the convenience methods:

tier-methods.py
# These methods handle the special files automatically
abstract = client.abstract("viking://resources/docs/auth/")
overview = client.overview("viking://resources/docs/auth/")

Namespace Conventions

URL-based Namespaces

For web resources, I mirror the URL structure:

url-namespaces.txt
viking://resources/github.com/owner/repo/...
viking://resources/docs.python.org/3/library/...
viking://resources/web/example.com/articles/...

This makes it easy to trace back to the original source.

Custom Namespaces

For local or custom resources:

custom-namespaces.txt
viking://resources/my_project/...
viking://resources/company_docs/...
viking://resources/knowledge_base/...

URI in Session Messages

I can reference context in conversations using URIs:

session-uris.py
from openviking.message import TextPart, ContextPart
session.add_message("assistant", [
TextPart("Here's the authentication guide:"),
ContextPart(
uri="viking://resources/docs/auth/oauth.md",
abstract="OAuth 2.0 guide for API authentication"
)
])

The agent can then load the full content if needed.

Real-World Example: Debugging Retrieval

Last week, my agent was retrieving the wrong OAuth documentation. I traced the problem using URIs.

First, I checked what was stored:

debug-list.py
# List all OAuth-related resources
results = client.find("oauth", target_uri="viking://resources/")
for r in results.resources:
print(f"URI: {r.uri}")
print(f"Abstract: {r.abstract[:100]}")

I found two OAuth documents:

found-resources.txt
URI: viking://resources/docs/auth/oauth.md
Abstract: OAuth 2.0 implementation for our API...
URI: viking://resources/legacy/old_oauth.html
Abstract: Deprecated OAuth 1.0 documentation...

The agent was picking up the deprecated OAuth 1.0 docs. I fixed this by:

  1. Removing the legacy doc: client.remove("viking://resources/legacy/old_oauth.html")
  2. Or scoping the search: client.find("oauth", target_uri="viking://resources/docs/")

Without URIs, I would have struggled to identify the problem. URIs gave me a clear view of what was stored and where.

URI vs Search: When to Use Which

I learned this distinction through trial and error:

Use URIs when:

  • You know the exact location
  • You need deterministic access
  • You’re debugging retrieval
  • You want to scope search to a directory

Use search when:

  • You don’t know the location
  • You want semantic matching
  • You’re exploring unfamiliar content
uri-vs-search.py
# URI: Deterministic, fast
content = client.read("viking://resources/docs/auth/oauth.md")
# Search: Flexible, semantic
results = client.find("how do I authenticate with oauth")

Best Practices

After working with Viking URIs for a few weeks, I settled on these practices:

  1. Consistent naming: Use clear, hierarchical paths that mirror your mental model
naming-convention.py
# Good: Clear hierarchy
client.add_resource(url, "viking://resources/project/docs/api/endpoints.md")
# Bad: Flat structure
client.add_resource(url, "viking://resources/project_api_endpoints.md")
  1. Logical grouping: Keep related resources in the same namespace
logical-grouping.txt
viking://resources/my_project/
├── docs/
├── src/
└── tests/
  1. Document structure: Add README files for major directories
add-readme.py
client.write(
"viking://resources/my_project/README.md",
"# My Project Resources\n\nThis directory contains..."
)
  1. Use relations: Link related contexts via .relations.json
.relations.json
{
"related": [
"viking://resources/docs/api/authentication.md",
"viking://agent/skills/oauth_handler/SKILL.md"
]
}

Summary

In this post, I explained the Viking URI specification and how it enables deterministic context access in OpenViking. The key insight is that every piece of context has a unique hierarchical identifier, turning vague semantic matching into precise, traceable operations.

Viking URIs solve a fundamental problem: knowing where something is but having to search for it anyway. With URIs, I can list, read, and grep context just like a filesystem, while still having semantic search when I need it. This combination of deterministic access and flexible search makes OpenViking practical for real-world agent development.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments