# Volatile vs Stable Context in Prompt Building for Pi Agents

> Understand the difference between volatile and stable context in prompt building for Pi agents. Learn how session-specific and invariant data optimize agent responses.

- Repository: [Craft Ai Agents/craft-agents-oss](https://github.com/craft-ai-agents/craft-agents-oss)
- Tags: deep-dive
- Published: 2026-07-06

---

**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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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.

```typescript
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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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.