Volatile vs Stable Context in Prompt Building for Pi Agents

Volatile context contains session-specific data that changes every turn and is appended to the user message, while stable context holds invariant workspace capabilities cached in the system prompt to prevent cache invalidation.

The craft-ai-agents/craft-agents-oss repository implements a sophisticated prompt-building strategy for Pi agents that splits context into two distinct categories. This architectural decision, implemented in the PromptBuilder class, solves critical caching issues while maintaining accurate session state. Understanding this split is essential for developers working with the Pi agent adapter or customizing prompt behavior.

What Is Volatile Context in Pi Agents?

Volatile context encompasses all data that may change on every turn of conversation. According to the source code in packages/shared/src/agent/core/prompt-builder.ts, this category includes minute-precision date/time stamps, session state variables (permission mode, plans/data paths), and one-shot mode-change signals.

Contents of Volatile Context

The buildVolatileContextParts method (lines 80-84) assembles several dynamic components:

  • Minute-precision date/time: Current timestamps that update continuously
  • Session state: Permission modes, plans folder paths, and data folder paths
  • One-shot mode-change signal: A special flag consumed exactly once per turn
  • Optional source-state block: Authentication and connection status indicators

Why Volatile Context Must Remain Uncached

These values are placed on the user-message tail rather than the system prompt. According to the detailed comment in lines 85-99 of prompt-builder.ts, placing volatile data in the cached system prefix would invalidate the entire prompt cache every turn (see issue #862). By appending volatile context after the stable blocks, the system preserves the reusable cached prefix while still transmitting current information.

What Is Stable Context in Pi Agents?

Stable context includes information that remains invariant for the lifetime of a session. The buildStableContextParts method (lines 135-147) constructs this component from workspace capabilities and working-directory context.

Contents of Stable Context

The stable block contains:

  • Workspace capabilities: Tool definitions and feature sets available to the workspace
  • Working-directory context: Fixed paths established when the session initializes

Caching Benefits

Because stable context never changes during a session, it can safely reside in the system prompt that is cached once and reused across many turns. This idempotent design allows the buildStableContextParts method to be called multiple times without side effects, while the underlying cached representation remains constant.

Implementation in PromptBuilder

The PromptBuilder class explicitly separates these concerns through distinct public methods. The buildContextParts method (lines 58-71) combines both halves in order—volatile first, stable second—preserving the exact byte-order expected by the underlying LLM.

import { PromptBuilder } from '@craft-agents/shared/agent';

// Initialize with workspace and session configuration
const pb = new PromptBuilder({
  workspace: { rootPath: '/my/workspace' },
  session: { id: 'sess-123', workingDirectory: '/my/workspace/project' },
  debugMode: { enabled: false },
});

// Build the two halves separately (as Pi agents do):
const volatile = pb.buildVolatileContextParts({
  permissionMode: 'explore',
  plansFolderPath: '/my/workspace/sessions/sess-123/plans',
  dataFolderPath: '/my/workspace/sessions/sess-123/data',
}, '<source_state>\n...');  // optional source block

const stable = pb.buildStableContextParts();

// Final message construction
const systemPrompt = stable.join('\n');                 // Cached once
const userMessage = `${volatile.join('\n')}\n\nHello!`; // Sent each turn

The PiAgent adapter (packages/shared/src/agent/pi-agent.ts, lines 2050-2052) utilizes this split to keep the cached system prefix clean while transmitting the volatile tail with every user request. This mirrors the Claude agent path but specifically avoids cache busts that would occur if volatile data were included in the system block.

Performance Impact and Cache Optimization

The volatile/stable distinction directly addresses performance bottlenecks in production deployments. When the Pi agent receives a turn, it concatenates the cached systemPrompt (stable) with the fresh userMessage (volatile plus actual user text).

Because the volatile part changes every turn while the stable part remains constant, the system avoids rebuilding the entire prompt cache. The volatile builder is the only code path that consumes the one-shot mode-change signal, guaranteeing it runs exactly once per turn without affecting the cached system state.

Summary

  • Volatile context contains time-sensitive data (timestamps, session state, source status) that changes every turn and is appended to the user message to prevent cache invalidation.
  • Stable context holds invariant workspace capabilities and working directory information that lives in the cached system prompt.
  • The buildVolatileContextParts and buildStableContextParts methods in prompt-builder.ts provide explicit separation of concerns.
  • This architecture prevents the prompt cache from being rebuilt every turn, solving issue #862 while maintaining accurate session representation.

Frequently Asked Questions

What happens if volatile context is placed in the system prompt?

Placing volatile context in the system prompt would invalidate the entire prompt cache on every turn because the cached prefix would change continuously. This would force a complete rebuild of the prompt context, eliminating performance benefits and increasing latency (see issue #862).

Can stable context change during a session?

No, stable context is designed to remain constant for the lifetime of a session. The buildStableContextParts method is pure and idempotent, meaning it can be called multiple times without side effects, but the underlying data (workspace capabilities and working directory) only changes when a new session begins.

How does the PiAgent utilize the volatile/stable split?

The PiAgent class specifically leverages this split to optimize API usage. It places the output of buildStableContextParts into the cached system prefix while appending buildVolatileContextParts to each user message tail. This approach, documented in pi-agent.ts lines 2050-2052, ensures the Pi LLM receives current context without sacrificing caching efficiency.

Where is the one-shot mode-change signal handled?

The one-shot mode-change signal is consumed exclusively within the buildVolatileContextParts method (lines 86-100 of prompt-builder.ts). This guarantees the signal runs exactly once per turn and only affects the volatile user-message portion, never contaminating the cached stable system context.

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 →