session-context-pattern.md 16 KB

Session Context Pattern

Problem

Context Fragmentation in Multi-Agent Orchestration

When orchestrating complex features across multiple agents (TaskManager → CoderAgent → TestEngineer), each agent is stateless and loses context between delegations:

  • TaskManager creates subtasks but doesn't know what ContextScout discovered
  • CoderAgent doesn't see what ArchitectureAnalyzer decided
  • TestEngineer doesn't know what files CoderAgent created
  • Orchestrator has to manually pass context in every delegation

This leads to:

  • ❌ Repeated context discovery (inefficient)
  • ❌ Inconsistent decisions (agents don't see previous choices)
  • ❌ Lost architectural context (bounded contexts, contracts, ADRs)
  • ❌ Manual context passing (error-prone, verbose)

Solution

Persistent Session Context File

Create a single context.md file that all agents read and update throughout the feature lifecycle:

.tmp/sessions/{session-id}/context.md

This file acts as the shared memory for the entire orchestration session.

Architecture

Session Lifecycle

1. Orchestrator creates session → context.md initialized
2. ContextScout updates → adds context_files
3. ArchitectureAnalyzer updates → adds bounded_context, module
4. TaskManager reads context → creates subtasks with full context
5. CoderAgent reads context → knows all decisions, files, contracts
6. TestEngineer reads context → knows what to test
7. Orchestrator marks complete → session archived

Context.md Structure

# Task Context: {Feature Name}

Session ID: {session-id}
Created: {timestamp}
Status: in_progress | completed | blocked

## Current Request
{Original user request - what we're building}

## Context Files to Load
- {Standards paths - coding conventions, patterns, security rules}

## Reference Files
- {Source material - existing project files to look at}

## Architecture
- Bounded Context: {DDD context from ArchitectureAnalyzer}
- Module: {Package/module name}
- Vertical Slice: {Feature slice from StoryMapper}

## User Stories
- {Story 1 from StoryMapper}
- {Story 2}

## Priorities
- RICE Score: {score from PrioritizationEngine}
- WSJF Score: {score}
- Release Slice: {v1.0.0, Q1-2026, MVP}

## Contracts
- {type}: {name} ({status})
  Path: {contract file path}

## Architectural Decision Records
- {ADR-ID}: {title}
  Path: {adr file path}

## Progress
Current Stage: {Stage N: Name}

Completed Stages:
- {Stage 0: Context Loading}
- {Stage 1: Planning}

Stage Outputs:
- {Stage 0}:
  - {Output 1}
  - {Output 2}

## Key Decisions
- [{timestamp}] {decision}
  Rationale: {why this choice was made}

## Files Created
- {file path 1}
- {file path 2}

## Exit Criteria
- [ ] {criterion 1}
- [ ] {criterion 2}
- [x] {completed criterion}

When to Use

Use Session Context When:

Multi-agent orchestration - Feature requires 3+ agents working sequentially ✅ Complex features - Needs architecture analysis, contracts, ADRs ✅ Stateful workflows - Later agents need to know what earlier agents did ✅ Context-heavy tasks - Lots of standards, patterns, decisions to track

Don't Use Session Context When:

Single agent tasks - Simple subtask execution (CoderAgent alone) ❌ Stateless operations - Each task is independent ❌ Quick fixes - Bug fixes, small updates

Usage by Agent Type

Orchestrator (MetaAgent)

Stage 0: Initialize Session

import { createSession } from '.opencode/skill/task-management/scripts/session-context-manager';

const result = createSession(feature, request, {
  contextFiles: [], // Will be populated by ContextScout
  referenceFiles: [],
  exitCriteria: [
    'All subtasks completed',
    'Tests passing',
    'Documentation updated'
  ]
});

const sessionId = result.sessionId;
// Pass sessionId to all subsequent agents

Between Stages: Update Context

import { updateSession, markStageComplete } from './session-context-manager';

// After ContextScout completes
updateSession(sessionId, {
  contextFiles: [
    '.opencode/context/core/standards/code-quality.md',
    '.opencode/context/core/standards/security-patterns.md'
  ]
});

// After ArchitectureAnalyzer completes
updateSession(sessionId, {
  architecture: {
    boundedContext: 'authentication',
    module: '@app/auth'
  }
});

// Mark stage complete
markStageComplete(sessionId, 'Stage 1: Planning', [
  '.tmp/tasks/auth-system/task.json',
  '.tmp/tasks/auth-system/subtask_01.json'
]);

Final Stage: Complete Session

updateSession(sessionId, { status: 'completed' });

TaskManager

Stage 0: Load Session Context

import { loadSession } from '.opencode/skill/task-management/scripts/session-context-manager';

const result = loadSession(sessionId);
if (!result.success) {
  throw new Error(`Session not found: ${sessionId}`);
}

const session = result.session;

// Use session context for task planning
const contextFiles = session.contextFiles; // Standards to follow
const referenceFiles = session.referenceFiles; // Source files to look at
const architecture = session.architecture; // Bounded context, module
const contracts = session.contracts; // API contracts
const adrs = session.adrs; // Architectural decisions

Stage 2: Create Tasks with Full Context

{
  "id": "auth-system",
  "name": "Authentication System",
  "context_files": ["...from session.contextFiles..."],
  "reference_files": ["...from session.referenceFiles..."],
  "bounded_context": "...from session.architecture.boundedContext...",
  "module": "...from session.architecture.module...",
  "contracts": ["...from session.contracts..."],
  "related_adrs": ["...from session.adrs..."]
}

Stage 3: Update Progress

import { addDecision } from './session-context-manager';

addDecision(sessionId, {
  decision: 'Split authentication into 3 subtasks: schema, service, middleware',
  rationale: 'Each subtask is atomic (1-2 hours) and has clear dependencies'
});

CoderAgent

Before Coding: Load Session Context

import { loadSession } from '.opencode/skill/task-management/scripts/session-context-manager';

const result = loadSession(sessionId);
const session = result.session;

// Read context files (standards)
session.contextFiles.forEach(file => {
  // Load coding standards, security patterns
});

// Read reference files (existing code)
session.referenceFiles.forEach(file => {
  // Study existing patterns
});

// Check architectural constraints
const boundedContext = session.architecture?.boundedContext;
const contracts = session.contracts; // API contracts to implement
const adrs = session.adrs; // Architectural decisions to follow

After Coding: Track Files Created

import { addFile } from './session-context-manager';

addFile(sessionId, 'src/auth/jwt.service.ts');
addFile(sessionId, 'src/auth/jwt.service.test.ts');

ContextScout

After Discovery: Update Session

import { updateSession } from './session-context-manager';

updateSession(sessionId, {
  contextFiles: [
    '.opencode/context/core/standards/code-quality.md',
    '.opencode/context/core/standards/security-patterns.md',
    '(example: .opencode/context/core/standards/naming-conventions.md)'
  ],
  referenceFiles: [
    'src/middleware/auth.middleware.ts',
    'src/config/jwt.config.ts'
  ]
});

ArchitectureAnalyzer

After Analysis: Update Session

import { updateSession, addDecision } from './session-context-manager';

updateSession(sessionId, {
  architecture: {
    boundedContext: 'authentication',
    module: '@app/auth',
    verticalSlice: 'user-login'
  }
});

addDecision(sessionId, {
  decision: 'Place authentication in separate bounded context',
  rationale: 'Auth is a core domain with clear boundaries, used by multiple features'
});

ContractManager

After Contract Definition: Update Session

import { updateSession } from './session-context-manager';

updateSession(sessionId, {
  contracts: [
    {
      type: 'api',
      name: 'AuthAPI',
      path: 'src/api/auth.contract.ts',
      status: 'defined'
    },
    {
      type: 'interface',
      name: 'JWTService',
      path: 'src/auth/jwt.service.ts',
      status: 'draft'
    }
  ]
});

API Reference

createSession(feature, request, options)

Initialize a new session with context.md file.

Parameters:

  • feature (string) - Feature name (kebab-case)
  • request (string) - Original user request
  • options (object) - Optional configuration
    • contextFiles (string[]) - Standards paths
    • referenceFiles (string[]) - Source file paths
    • exitCriteria (string[]) - Completion criteria
    • architecture (object) - Bounded context, module, vertical slice
    • stories (string[]) - User stories
    • priorities (object) - RICE/WSJF scores, release slice
    • contracts (array) - API/interface contracts
    • adrs (array) - Architectural decision records

Returns:

{ success: boolean; sessionId?: string; error?: string }

Example:

const result = createSession('auth-system', 'Implement JWT authentication', {
  exitCriteria: ['All tests passing', 'JWT tokens signed with RS256']
});
// result.sessionId = "auth-system-2026-02-15T10-30-00-000Z"

loadSession(sessionId)

Read session context from context.md.

Parameters:

  • sessionId (string) - Session identifier

Returns:

{ success: boolean; session?: SessionContext; error?: string }

Example:

const result = loadSession('auth-system-2026-02-15T10-30-00-000Z');
if (result.success) {
  const contextFiles = result.session.contextFiles;
  const architecture = result.session.architecture;
}

updateSession(sessionId, updates)

Append new information to session context.

Parameters:

  • sessionId (string) - Session identifier
  • updates (object) - Fields to update
    • status - 'in_progress' | 'completed' | 'blocked'
    • contextFiles - Add standards paths (merged with existing)
    • referenceFiles - Add source file paths (merged with existing)
    • architecture - Update bounded context, module, vertical slice
    • stories - Add user stories
    • priorities - Update RICE/WSJF scores
    • contracts - Add contracts
    • adrs - Add ADRs

Returns:

{ success: boolean; error?: string }

Example:

updateSession(sessionId, {
  architecture: {
    boundedContext: 'authentication',
    module: '@app/auth'
  },
  contracts: [
    { type: 'api', name: 'AuthAPI', path: 'src/api/auth.contract.ts', status: 'defined' }
  ]
});

markStageComplete(sessionId, stage, outputs)

Mark a workflow stage as complete and record outputs.

Parameters:

  • sessionId (string) - Session identifier
  • stage (string) - Stage name (e.g., "Stage 1: Planning")
  • outputs (string[]) - Files/artifacts created in this stage

Returns:

{ success: boolean; error?: string }

Example:

markStageComplete(sessionId, 'Stage 1: Planning', [
  '.tmp/tasks/auth-system/task.json',
  '.tmp/tasks/auth-system/subtask_01.json',
  '.tmp/tasks/auth-system/subtask_02.json'
]);

addDecision(sessionId, decision)

Log a key decision with rationale.

Parameters:

  • sessionId (string) - Session identifier
  • decision (object)
    • decision (string) - What was decided
    • rationale (string) - Why this choice was made

Returns:

{ success: boolean; error?: string }

Example:

addDecision(sessionId, {
  decision: 'Use RS256 for JWT signing instead of HS256',
  rationale: 'RS256 (asymmetric) is more secure for distributed systems where tokens are verified by multiple services'
});

addFile(sessionId, filePath)

Track a file created during the session.

Parameters:

  • sessionId (string) - Session identifier
  • filePath (string) - Path to created file

Returns:

{ success: boolean; error?: string }

Example:

addFile(sessionId, 'src/auth/jwt.service.ts');
addFile(sessionId, 'src/auth/jwt.service.test.ts');

getSessionSummary(sessionId)

Get current session state summary.

Parameters:

  • sessionId (string) - Session identifier

Returns:

{
  success: boolean;
  summary?: {
    sessionId: string;
    feature: string;
    status: string;
    currentStage: string;
    completedStages: number;
    totalDecisions: number;
    filesCreated: number;
    exitCriteriaMet: number;
    exitCriteriaTotal: number;
  };
  error?: string;
}

Example:

const result = getSessionSummary(sessionId);
console.log(`Progress: ${result.summary.completedStages} stages complete`);
console.log(`Files: ${result.summary.filesCreated} created`);
console.log(`Exit Criteria: ${result.summary.exitCriteriaMet}/${result.summary.exitCriteriaTotal}`);

CLI Usage

# Create session
npx ts-node session-context-manager.ts create auth-system "Implement JWT authentication"

# Load session
npx ts-node session-context-manager.ts load auth-system-2026-02-15T10-30-00-000Z

# Show summary
npx ts-node session-context-manager.ts summary auth-system-2026-02-15T10-30-00-000Z

Benefits

No context loss - All agents see the full picture ✅ Consistent decisions - Architectural choices tracked and visible ✅ Efficient - Context discovered once, used by all agents ✅ Auditable - Complete history of decisions and progress ✅ Self-documenting - context.md is human-readable ✅ Resumable - Can pause and resume orchestration

Best Practices

1. Initialize Early

Create session at the start of orchestration, before any agent work begins.

2. Update After Each Stage

Every agent that completes work should update the session context.

3. Read Before Acting

Every agent should load session context before starting work.

4. Track Decisions

Use addDecision() for any architectural or design choice.

5. Track Files

Use addFile() for every file created (helps with cleanup, rollback).

6. Use Exit Criteria

Define clear, binary exit criteria at session creation.

Example: Full Orchestration Flow

// Orchestrator: Initialize
const { sessionId } = createSession('auth-system', 'Implement JWT authentication', {
  exitCriteria: ['All tests passing', 'JWT tokens signed with RS256']
});

// Stage 0: ContextScout discovers context
updateSession(sessionId, {
  contextFiles: ['.opencode/context/core/standards/code-quality.md'],
  referenceFiles: ['src/middleware/auth.middleware.ts']
});
markStageComplete(sessionId, 'Stage 0: Context Loading', []);

// Stage 1: ArchitectureAnalyzer analyzes
updateSession(sessionId, {
  architecture: { boundedContext: 'authentication', module: '@app/auth' }
});
addDecision(sessionId, {
  decision: 'Separate bounded context for auth',
  rationale: 'Core domain with clear boundaries'
});
markStageComplete(sessionId, 'Stage 1: Architecture Analysis', []);

// Stage 2: TaskManager creates tasks
const { session } = loadSession(sessionId);
// Use session.contextFiles, session.architecture in task.json
markStageComplete(sessionId, 'Stage 2: Task Planning', [
  '.tmp/tasks/auth-system/task.json'
]);

// Stage 3: CoderAgent implements
const { session } = loadSession(sessionId);
// Read session.contextFiles, session.contracts
addFile(sessionId, 'src/auth/jwt.service.ts');
markStageComplete(sessionId, 'Stage 3: Implementation', [
  'src/auth/jwt.service.ts'
]);

// Stage 4: Complete
updateSession(sessionId, { status: 'completed' });

Related

  • .opencode/skill/task-management/scripts/session-context-manager.ts - Implementation
  • .opencode/context/core/task-management/standards/task-schema.md - Task JSON schema
  • .opencode/context/core/workflows/task-delegation.md - Multi-agent orchestration
  • .tmp/sessions/test-task-manager/context.md - Example session context