How to Implement Three-Tier Context Loading (L0/L1/L2) in Custom OpenViking Agents

OpenViking implements three-tier context loading through the VikingFS abstraction, where L0 (.abstract.md) provides ~100-token summaries, L1 (.overview.md) provides ~300-token outlines, and L2 delivers full content, accessible via the OVFileTool with level parameters "abstract", "overview", or "read".

The OpenViking framework structures resources as directories containing hierarchical context files to optimize token usage and retrieval performance. Understanding how to implement three-tier context loading is essential for building efficient custom agents that balance cost and comprehensiveness. This guide explains the L0/L1/L2 architecture and provides implementation patterns using the core VikingFS API and agent tools according to the volcengine/OpenViking source code.

Understanding the Three-Tier Context Model

OpenViking stores every resource as a directory that contains three special files representing different granularity levels. This design minimizes token costs during initial retrieval while preserving access to full content when necessary.

L0 Abstract: High-Level Summaries

The L0 (abstract) tier resides in .abstract.md files containing approximately 100 tokens. These ultra-condensed summaries serve two critical functions: they populate the vector index for semantic search and enable rapid relevance filtering without loading heavy content. When your agent needs to scan large resource collections, requesting L0 abstracts keeps latency and token consumption minimal.

L1 Overview: Structured Outlines

The L1 (overview) tier exists in .overview.md files with roughly 300 tokens. This level provides more detailed structural information about the resource, typically shown when an agent returns a list of candidates to the user. The overview contains enough context for users to determine if they want the full document, bridging the gap between abstract summaries and complete content.

L2 Detail: Full Content Retrieval

The L2 (detail) tier corresponds to the original content file itself (for example, doc.md, image.png, or other binary payloads). This level contains the full, unabridged resource and should only be loaded when the user explicitly requests specific details. Loading L2 content incurs the highest token and bandwidth costs, making the three-tier hierarchy essential for scalable agent architectures.

Core Implementation: VikingFS and ContextLevel

The three-tier loading pattern is built into the core file-system abstraction VikingFS (openviking/storage/viking_fs.py). The system enforces these levels through the ContextLevel enum defined in openviking/core/context.py (lines 33-38), which standardizes the tier definitions across the entire stack.

The public API surface exposes three distinct methods:

await viking_fs.abstract(uri)          # → L0

await viking_fs.overview(uri)          # → L1  

await viking_fs.read_file(uri)         # → L2 (default) or explicit level="read"

In openviking/storage/viking_fs.py, the abstract and overview methods (lines 511-540) read the special hidden files and return clean strings through _handle_agfs_content. The read_file method (lines 1235-1247) handles L2 retrieval and accepts an optional level argument, enabling unified access patterns across all tiers.

The vector indexer respects this hierarchy through ALLOWED_CONTEXT_TYPES in viking_vector_index_backend.py, ensuring that L0 abstracts are stored as the default indexed payload for efficient similarity search.

Implementing Three-Tier Loading in Custom Agents

For agent development, the preferred retrieval method is the OVFileTool (bot/vikingbot/agent/tools/ov_file.py). This tool exposes a level argument in its JSON schema with three allowed values:

{
    "type": "object",
    "properties": {
        "uri": {"type": "string"},
        "level": {
            "type": "string",
            "description": "Reading level: 'abstract' (L0 summary), 'overview' (L1 overview), or 'read' (L2 full content)",
            "enum": ["abstract", "overview", "read"],
            "default": "abstract"
        }
    },
    "required": ["uri"]
}

To implement three-tier loading in your custom agent:

  1. Add the openviking_read tool to your agent's toolset (available in the default vikingbot package)
  2. Request L0 abstracts when generating candidate lists or performing initial similarity searches
  3. Upgrade to L1 overviews when the user asks for more context or file outlines
  4. Fetch L2 full content only upon explicit user request for the complete document

The tool forwards requests to VikingClient.read_content, meaning you do not need to manage file paths or AGFS details manually. The client handles URI-to-path conversion, access checks, and vector-store synchronization automatically.

Code Examples

Using OVFileTool for Tiered Access

The VikingReadTool class in bot/vikingbot/agent/tools/ov_file.py provides the cleanest interface for tiered access. The execute method (lines 58-60) forwards to client.read_content:

from vikingbot.agent.tools.ov_file import VikingReadTool

async def get_resource_summary(uri: str, tool_context):
    """L0 - Fast, cheap retrieval for indexing and filtering"""
    read_tool = VikingReadTool()
    abstract = await read_tool.execute(tool_context, uri=uri, level="abstract")
    return abstract

async def get_resource_outline(uri: str, tool_context):
    """L1 - Detailed outline for candidate presentation"""
    read_tool = VikingReadTool()
    overview = await read_tool.execute(tool_context, uri=uri, level="overview")
    return overview

async def get_resource_full(uri: str, tool_context):
    """L2 - Complete content for deep analysis"""
    read_tool = VikingReadTool()
    content = await read_tool.execute(tool_context, uri=uri, level="read")
    return content

Direct VikingClient Integration

For non-tool code or custom services, use VikingClient directly from bot/vikingbot/openviking_mount/ov_server.py. The read_content method (lines 116-130) wraps the three-tier API:

from bot.vikingbot.openviking_mount.ov_server import VikingClient

async def read_l0(uri: str):
    client = await VikingClient.create(workspace_id="default")
    return await client.read_content(uri, level="abstract")   # L0

async def read_l1(uri: str):
    client = await VikingClient.create(workspace_id="default")
    return await client.read_content(uri, level="overview")  # L1

async def read_l2(uri: str):
    client = await VikingClient.create(workspace_id="default")
    return await client.read_content(uri, level="read")      # L2

Batch Processing in Context Builders

For advanced implementations, integrate tiered loading into your ContextBuilder using VikingFS batch methods. The _batch_fetch_abstracts method (lines 555-585) already performs parallel L0 fetches:

async def build_system_prompt(self, session_key, current_message, history):
    # Stage 1: Load only abstracts for candidate resources (L0)

    abstracts = await self.viking_fs._batch_fetch_abstracts(
        candidate_entries, abs_limit=256
    )
    
    # Stage 2: Fetch L1 overviews when user requests outlines

    if "outline" in current_message.intent:
        outlines = await self.viking_fs._batch_fetch_overviews(
            candidate_uris
        )
    
    # Stage 3: Retrieve L2 full content on explicit demand

    if "full_document" in current_message.intent:
        full_content = await self.viking_fs.read_file(
            target_uri, level="read"
        )

Summary

  • L0 Abstract (.abstract.md): ~100 tokens, ideal for vector indexing and initial filtering via viking_fs.abstract()
  • L1 Overview (.overview.md): ~300 tokens, suitable for candidate lists and outlines via viking_fs.overview()
  • L2 Detail (original file): Full content, loaded only on explicit request via viking_fs.read_file()
  • Implementation: Use VikingReadTool with level="abstract", "overview", or "read" to access tiers without managing file paths
  • Source references: ContextLevel enum in openviking/core/context.py, VikingFS implementation in openviking/storage/viking_fs.py, and tool schema in bot/vikingbot/agent/tools/ov_file.py

Frequently Asked Questions

What is the typical token count for each OpenViking context level?

According to the source implementation, L0 abstracts contain approximately 100 tokens, L1 overviews contain roughly 300 tokens, and L2 represents the full, unbounded content of the original file. These limits ensure that vector indexing and initial retrieval remain cost-effective while preserving detailed access when necessary.

How does the vector indexer handle the three-tier context model?

The vector indexer uses the ContextLevel enum defined in openviking/core/context.py and respects ALLOWED_CONTEXT_TYPES in viking_vector_index_backend.py. By default, the system indexes L0 abstracts as the vector payload, enabling efficient semantic search without storing expensive full-text embeddings. L1 and L2 content remains accessible through the file system but is not embedded in the vector store.

Can I customize the context loading behavior for specific resource types?

While the OVFileTool schema enforces the three standard levels ("abstract", "overview", "read"), you can implement custom logic in your agent's context builder to determine when to escalate from L0 to L1 or L2. The underlying VikingFS methods in openviking/storage/viking_fs.py support direct file access if you need to bypass the standard tiering for specialized resource types, though this requires manual URI-to-path resolution.

Where is the ContextLevel enum defined in the OpenViking source?

The ContextLevel enum is defined in openviking/core/context.py at lines 33-38. This enumeration standardizes the L0/L1/L2 designations across the framework, ensuring that components like the vector backend, VikingFS, and agent tools maintain consistent tier semantics throughout the retrieval pipeline.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →