# How to Manage Resources Using the viking:// URI Protocol in OpenViking

> Learn to manage resources effectively in OpenViking using the viking:// URI protocol. Discover how the VikingURI class simplifies parsing, validation, and composition for seamless resource management.

- Repository: [Volcengine/OpenViking](https://github.com/volcengine/OpenViking)
- Tags: how-to-guide
- Published: 2026-03-08

---

**OpenViking uses the `viking://` URI scheme to uniquely identify every object in the system, with the `VikingURI` class in [`openviking_cli/utils/uri.py`](https://github.com/volcengine/OpenViking/blob/main/openviking_cli/utils/uri.py) providing parsing, validation, normalization, and composition utilities that serve as the single source of truth for resource management across the SDK.**

The OpenViking SDK from Volcengine implements a unified resource addressing system through the `viking://` URI protocol. Every file, directory, semantic node, queue, and session receives a unique identifier following the `viking://<scope>/<path>` format. The `VikingURI` class serves as the central abstraction for managing these identifiers, ensuring consistent validation and manipulation across the HTTP client, storage layer, and file system wrappers.

## Understanding the viking:// URI Structure

OpenViking identifies every object with a **Viking URI** following the strict format:

```

viking://<scope>/<path>

```

The **scope** component defines the namespace and must be one of the predefined values: `resources`, `user`, `agent`, `session`, `queue`, or `temp`. The remainder of the path varies by scope type, representing project names, file hierarchies, or unique identifiers depending on the resource category.

## Core URI Operations with VikingURI

The `VikingURI` class in [`openviking_cli/utils/uri.py`](https://github.com/volcengine/OpenViking/blob/main/openviking_cli/utils/uri.py) implements the complete lifecycle of URI handling. According to the OpenViking source code, this class provides immutable, hashable objects that normalize input, validate scope constraints, and enable hierarchical navigation.

### Normalization and Validation

The **`normalize()`** class method guarantees the `viking://` scheme even when callers provide short-form strings such as `/resources/docs` or bare paths like `resources/docs`. The **`is_valid()`** method returns `True` only for syntactically correct URIs with approved scope values, as validated against the internal `VALID_SCOPES` constant.

### Parsing and Scope Inspection

The internal **`_parse()`** method splits a full URI into `scheme`, `scope`, and `full_path` components. For `resources` scope URIs, the **`resource_name`** property extracts the project name, while the **`parent`** property walks one level up the hierarchy to return a new `VikingURI` instance.

### URI Composition and Building

The **`build()`** class method constructs URIs from a scope and arbitrary path parts, while **`join()`** appends new segments handling slash normalization automatically. For semantic node creation, **`build_semantic_uri()`** creates hierarchical paths with optional node IDs for leaf nodes.

### Temporary Workspace Generation

The **`create_temp_uri()`** method generates unique `viking://temp/...` paths for short-lived workspaces, returning fully validated `VikingURI` instances ready for immediate use.

## Practical Resource Management Examples

The following examples demonstrate common patterns for managing resources using the `viking://` URI protocol.

### Normalizing Short-Form URIs

```python
from openviking_cli.utils import VikingURI

# Short-form input automatically becomes full-form

uri = VikingURI("/resources/docs")
print(uri.uri)          # → viking://resources/docs

# Normalizing an already-full URI is a no-op

print(VikingURI.normalize("viking://user/profile"))  # → viking://user/profile

```

### Validating Resource Identifiers

```python

# Validate a URI string

assert VikingURI.is_valid("viking://agent/skills/pdf")

# Invalid scope raises at construction time

try:
    VikingURI("viking://invalid_scope/foo")
except ValueError as e:
    print(e)   # → Invalid scope 'invalid_scope'. Must be one of {...}

```

### Constructing Hierarchical Paths

```python

# Build a URI from a scope and arbitrary path parts

full_uri = VikingURI.build("resources", "my_project", "docs", "api")
print(full_uri)   # → viking://resources/my_project/docs/api

# Join a new segment to an existing URI

uri = VikingURI("viking://resources/my_project")
new_uri = uri.join("readme.md")
print(new_uri.uri)   # → viking://resources/my_project/readme.md

```

### Navigating Parent Directories

```python
uri = VikingURI("viking://resources/my_project/docs/api")
print(uri.parent.uri)          # → viking://resources/my_project/docs

print(uri.resource_name)       # → my_project

```

### Creating Semantic Nodes

```python
parent = "viking://resources/my_project"
semantic = VikingURI.build_semantic_uri(parent, "Chapter 1")
print(semantic)                # → viking://resources/my_project/Chapter_1

# Leaf node with explicit ID

leaf = VikingURI.build_semantic_uri(parent, "Section A", node_id="12345", is_leaf=True)
print(leaf)                    # → viking://resources/my_project/Section_A/12345

```

### Generating Temporary Workspaces

```python
tmp_uri = VikingURI.create_temp_uri()
print(tmp_uri)   # → viking://temp/03291530_1a2b3c (example)

```

## Integration with OpenViking Components

Higher-level components rely on `VikingURI` primitives, creating a single source of truth for URI handling across the codebase.

### HTTP Client Normalization

The HTTP client in [`openviking_cli/client/http.py`](https://github.com/volcengine/OpenViking/blob/main/openviking_cli/client/http.py) normalizes every incoming user-provided string before sending it to the backend:

```python
uri = VikingURI.normalize(uri)          # https://github.com/volcengine/OpenViking/blob/main/openviking_cli/client/http.py#L95-L98

```

### Storage Layer Operations

The file-system wrapper in [`openviking/storage/viking_fs.py`](https://github.com/volcengine/OpenViking/blob/main/openviking/storage/viking_fs.py) uses `VikingURI` for parent resolution, resource-name extraction, and validation when interacting with the underlying AGFS storage:

```python
parent_uri = VikingURI(uri).parent.uri   # https://github.com/volcengine/OpenViking/blob/main/openviking/storage/viking_fs.py#L891

```

### Test Coverage

Unit tests in [`tests/unit/test_uri_short_format.py`](https://github.com/volcengine/OpenViking/blob/main/tests/unit/test_uri_short_format.py) verify short-format normalization, validation, parent resolution, and scope handling, while integration tests across `tests/vectordb/` and `tests/storage/` exercise `VikingURI` in real-world scenarios.

## Summary

- **OpenViking** addresses all resources using the `viking://<scope>/<path>` format with six valid scopes: `resources`, `user`, `agent`, `session`, `queue`, and `temp`.
- The **`VikingURI`** class in [`openviking_cli/utils/uri.py`](https://github.com/volcengine/OpenViking/blob/main/openviking_cli/utils/uri.py) provides immutable, hashable objects supporting normalization, validation, composition, and hierarchical navigation.
- **`normalize()`** ensures consistent `viking://` prefixes while **`build()`**, **`join()`**, and **`build_semantic_uri()`** enable programmatic URI construction for the `viking://` URI protocol.
- **Integration points** in [`openviking_cli/client/http.py`](https://github.com/volcengine/OpenViking/blob/main/openviking_cli/client/http.py) and [`openviking/storage/viking_fs.py`](https://github.com/volcengine/OpenViking/blob/main/openviking/storage/viking_fs.py) demonstrate the class role as the bridge between user-facing strings and internal storage APIs.

## Frequently Asked Questions

### What are the valid scope types for viking:// URIs?

OpenViking recognizes six predefined scopes: `resources` for project files and data, `user` for user-specific data, `agent` for agent configurations and skills, `session` for session state, `queue` for task queues, and `temp` for temporary workspaces. The `VikingURI` class validates all scopes against the `VALID_SCOPES` constant in [`openviking_cli/utils/uri.py`](https://github.com/volcengine/OpenViking/blob/main/openviking_cli/utils/uri.py), raising `ValueError` for any invalid scope identifier.

### How does VikingURI handle short-form URI strings?

The **`normalize()`** method automatically converts short-form inputs like `/resources/docs` or bare `resources/docs` into full `viking://resources/docs` format. This normalization occurs at construction time and throughout the SDK, ensuring the HTTP client and storage layer always receive properly formatted URIs regardless of user input style.

### Can VikingURI objects be used as dictionary keys?

Yes. The `VikingURI` class implements `__eq__` and `__hash__` methods, making instances immutable and hashable. This design allows URIs to serve as keys in dictionaries or elements in sets, enabling efficient lookup and deduplication of resource identifiers across the OpenViking codebase.

### How do I create a temporary workspace URI in OpenViking?

Call **`VikingURI.create_temp_uri()`** to generate a unique temporary URI under the `viking://temp/` scope. This method returns a fully validated `VikingURI` instance with a generated path segment suitable for short-lived workspaces, as implemented in [`openviking_cli/utils/uri.py`](https://github.com/volcengine/OpenViking/blob/main/openviking_cli/utils/uri.py).