* fix: correct task-delegation reference in session-context-pattern - Changed outdated reference from task-delegation.md to task-delegation-basics.md - The file task-delegation-basics.md exists, task-delegation.md does not - This caused 'file not found' errors during installation via install.sh * feat: add install-fork.sh for fork-based installation - Creates install-fork.sh that installs from digi4care/OpenAgentsControl fork - Allows users to install the forked version with fixes before upstream merge - Usage: bash install-fork.sh or curl directly from fork repo * docs: add root README.md and CONTRIBUTING.md for GitHub best practices - Add README.md in repository root (GitHub requirement) - Add CONTRIBUTING.md in repository root with contribution guidelines - Both files redirect to detailed documentation in docs/ directory - Fixes installer 404 error for readme config item - Follows GitHub community standards for repository structure * chore: remove fork-specific files per maintainer request --------- Co-authored-by: Chris Engelhard <chris@chrisengelhard.nl>
16 KiB
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 requestoptions(object) - Optional configurationcontextFiles(string[]) - Standards pathsreferenceFiles(string[]) - Source file pathsexitCriteria(string[]) - Completion criteriaarchitecture(object) - Bounded context, module, vertical slicestories(string[]) - User storiespriorities(object) - RICE/WSJF scores, release slicecontracts(array) - API/interface contractsadrs(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 identifierupdates(object) - Fields to updatestatus- '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 slicestories- Add user storiespriorities- Update RICE/WSJF scorescontracts- Add contractsadrs- 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 identifierstage(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 identifierdecision(object)decision(string) - What was decidedrationale(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 identifierfilePath(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-basics.md- Multi-agent orchestration.tmp/sessions/test-task-manager/context.md- Example session context