Purpose: Comprehensive guide to the planning agent ecosystem — when to use each agent, how they integrate, and best practices for DDD, story mapping, prioritization, contract testing, and ADRs.
The planning agent ecosystem consists of five specialized agents that work together to transform feature requirements into actionable implementation plans:
Key Principle: Each agent is context-aware and ALWAYS calls ContextScout before executing to ensure alignment with project standards.
Feature Request
│
├─ Complex domain logic? ──YES──> ArchitectureAnalyzer
│ NO
│ ↓
├─ User journey unclear? ──YES──> StoryMapper
│ NO
│ ↓
├─ Need prioritization? ──YES──> PrioritizationEngine
│ NO
│ ↓
├─ Parallel dev needed? ──YES──> ContractManager
│ NO
│ ↓
└─ Architectural decision? ─YES──> ADRManager
Use ArchitectureAnalyzer when:
Do NOT use when:
task(
subagent_type="ArchitectureAnalyzer",
description="Analyze architecture for {feature}",
prompt="Analyze domain structure for {feature}.
Requirements: {requirements}
Identify bounded contexts, aggregates, and relationships."
)
Required Context:
Primary Output: .tmp/tasks/{feature}/contexts.json
{
"feature": "order-management",
"analyzed_at": "2026-02-14T00:00:00Z",
"bounded_contexts": [
{
"name": "order-management",
"type": "core",
"description": "Manages order lifecycle",
"module": "src/order",
"aggregates": [
{
"name": "Order",
"root": "Order",
"entities": ["Order", "LineItem"],
"value_objects": ["OrderStatus", "Money"],
"invariants": ["Order must have at least one line item"]
}
],
"domain_events": [
{
"name": "OrderPlaced",
"description": "Order was successfully placed",
"payload": ["orderId", "customerId", "total"]
}
],
"capabilities": ["Create order", "Modify order", "Cancel order"]
}
],
"context_relationships": [
{
"upstream": "inventory",
"downstream": "order-management",
"relationship_type": "customer-supplier",
"integration_pattern": "events",
"description": "Order reserves inventory via StockReserved event"
}
],
"ubiquitous_language": {
"Order": "Customer purchase request with line items",
"LineItem": "Product and quantity within an order"
}
}
Secondary Output: .tmp/tasks/{feature}/module-briefs/{context-name}.md
Module briefs provide implementation guidance for each bounded context.
With TaskManager:
ArchitectureAnalyzer → contexts.json → TaskManager
TaskManager uses bounded contexts to create subtasks aligned with domain boundaries.
With StoryMapper:
ArchitectureAnalyzer → bounded contexts → StoryMapper
StoryMapper maps user stories to bounded contexts for service boundary alignment.
✅ DDD Tactical Patterns:
✅ DDD Strategic Patterns:
✅ Quality Checks:
Problem: Too many bounded contexts identified
Problem: Unclear context boundaries
Problem: Circular dependencies between contexts
.opencode/agent/subagents/planning/architecture-analyzer.md.opencode/context/core/task-management/standards/enhanced-task-schema.mdUse StoryMapper when:
Do NOT use when:
task(
subagent_type="StoryMapper",
description="Map user journeys for {feature}",
prompt="Transform user requirements into user journeys, epics, and stories for {feature}.
Requirements: {requirements}
Map stories to bounded contexts from ArchitectureAnalyzer."
)
Required Context:
Primary Output: .tmp/planning/{feature}/map.json
{
"feature": "user-authentication",
"created_at": "2026-02-14T00:00:00Z",
"personas": [
{
"id": "end-customer",
"name": "End Customer",
"role": "Regular user",
"goals": ["Access account", "Secure data"],
"pain_points": ["Forgotten passwords", "Complex login"],
"technical_level": "low",
"primary_use_cases": ["login", "registration"]
}
],
"journeys": [
{
"id": "user-login",
"name": "User Login Flow",
"persona": "end-customer",
"steps": [
{
"id": "step-1",
"action": "Enter email and password",
"touchpoint": "Login form",
"validation": ["Email format", "Password presence"]
}
],
"success_criteria": ["User authenticated", "Session created"],
"edge_cases": ["Invalid credentials", "Account locked"]
}
],
"vertical_slices": [
{
"id": "user-login-slice",
"name": "User Login Slice",
"journeys": ["user-login"],
"bounded_contexts": ["authentication"],
"layers": {
"frontend": ["Login form", "Session management"],
"backend": ["Auth API", "JWT service"],
"database": ["User table", "Session table"],
"external": []
},
"dependencies": ["user-registration-slice"],
"estimated_effort": "1 week"
}
],
"epics": [
{
"id": "epic-user-auth",
"name": "User Authentication",
"description": "Enable secure user registration and login",
"journeys": ["user-registration", "user-login"],
"vertical_slices": ["user-registration-slice", "user-login-slice"],
"bounded_contexts": ["authentication"],
"acceptance_criteria": [
"Users can register with email/password",
"Users can login with credentials",
"JWT tokens used for session management"
],
"priority": "high",
"estimated_effort": "2 weeks"
}
],
"stories": [
{
"id": "story-auth-001",
"title": "User can login with email and password",
"story": "As an end customer, I want to login with my email and password so that I can access my account",
"epic": "epic-user-auth",
"bounded_context": "authentication",
"acceptance_criteria": [
"Login form accepts email and password",
"Email format is validated",
"Invalid credentials show clear error",
"Successful login creates JWT token",
"User is redirected to dashboard"
],
"dependencies": [],
"parallel": true,
"estimated_effort": "2 days",
"technical_notes": "Use bcrypt for password hashing, JWT for tokens"
}
],
"bounded_context_mapping": {
"authentication": {
"stories": ["story-auth-001", "story-auth-002"],
"epics": ["epic-user-auth"],
"vertical_slices": ["user-login-slice"]
}
}
}
With ArchitectureAnalyzer:
ArchitectureAnalyzer → bounded contexts → StoryMapper
StoryMapper uses bounded context definitions to map stories to service boundaries.
With PrioritizationEngine:
StoryMapper → map.json → PrioritizationEngine
PrioritizationEngine scores stories and identifies MVP features.
With TaskManager:
StoryMapper → map.json → TaskManager
TaskManager converts stories into implementation subtasks.
✅ Persona Identification:
✅ Journey Mapping:
✅ Vertical Slices:
✅ Story Decomposition:
Problem: Stories are too large
Problem: Unclear bounded context mapping
Problem: Circular story dependencies
Problem: Stories don't deliver user value
.opencode/agent/subagents/planning/story-mapper.mdUse PrioritizationEngine when:
Do NOT use when:
task(
subagent_type="PrioritizationEngine",
description="Prioritize backlog for {feature}",
prompt="Score and prioritize backlog items for {feature} using RICE and WSJF.
Input: {path-to-story-mapper-output}
Identify MVP vs. post-MVP features."
)
Required Context:
Primary Output: .tmp/planning/prioritized.json
{
"metadata": {
"generated_at": "2026-02-14T00:00:00Z",
"source": "StoryMapper output",
"frameworks": ["RICE", "WSJF"],
"total_items": 15,
"mvp_count": 5,
"post_mvp_count": 10
},
"scoring_criteria": {
"rice": {
"reach_period": "per quarter",
"impact_scale": "0.25 (minimal) to 3.0 (massive)",
"confidence_scale": "0-100%",
"effort_unit": "person-months"
},
"wsjf": {
"business_value_scale": "1-10",
"time_criticality_scale": "1-10",
"risk_reduction_scale": "1-10",
"job_size_scale": "1-10 (inverse effort)"
}
},
"mvp_features": [
{
"id": "story-auth-001",
"title": "User can login with email and password",
"epic": "User Authentication",
"rice_score": {
"reach": 50000,
"impact": 3.0,
"confidence": 90,
"effort": 0.1,
"score": 1350000,
"justification": {
"reach": "All users need login capability",
"impact": "Core value proposition, critical feature",
"confidence": "Industry standard, well-understood",
"effort": "2 days = 0.1 person-months"
}
},
"wsjf_score": {
"business_value": 10,
"time_criticality": 10,
"risk_reduction": 8,
"job_size": 9,
"score": 3.1,
"justification": {
"business_value": "Critical for product launch",
"time_criticality": "Blocker for all other features",
"risk_reduction": "Enables secure access",
"job_size": "2 days = tiny effort"
}
},
"combined_rank": 1,
"mvp_reason": "Core value proposition, dependency blocker",
"estimated_effort": "2 days",
"dependencies": []
}
],
"post_mvp_features": [...],
"release_recommendations": {
"mvp_timeline": "3 weeks",
"mvp_scope": "Core authentication and user management",
"post_mvp_phases": [
{
"phase": "Phase 2",
"timeline": "2 weeks",
"features": ["story-auth-010", "story-auth-011"],
"theme": "Advanced authentication (OAuth, 2FA)"
}
]
}
}
With StoryMapper:
StoryMapper → map.json → PrioritizationEngine
PrioritizationEngine scores stories from StoryMapper output.
With TaskManager:
PrioritizationEngine → prioritized.json → TaskManager
TaskManager creates subtasks for MVP features first.
✅ RICE Scoring:
✅ WSJF Scoring:
✅ MVP Identification:
✅ Score Justification:
Problem: Missing effort estimates
Problem: Unclear business goals
Problem: Conflicting RICE vs. WSJF priorities
Problem: MVP set too large
.opencode/agent/subagents/planning/prioritization-engine.mdUse ContractManager when:
Do NOT use when:
task(
subagent_type="ContractManager",
description="Define API contracts for {service}",
prompt="Create API contracts for {service} to enable parallel development.
Bounded contexts: {contexts-from-architecture-analyzer}
Define OpenAPI specs, consumer/provider relationships, and testing strategy."
)
Required Context:
Primary Output: .tmp/contracts/{bounded-context}/{service-name}/contract.json
{
"contract_id": "auth-api",
"version": "1.0.0",
"bounded_context": "authentication",
"service_name": "auth-service",
"description": "Authentication API for user login and registration",
"openapi_spec_path": "contract.openapi.yaml",
"consumers": [
{
"name": "web-frontend",
"type": "spa",
"endpoints_used": ["/auth/login", "/auth/register"],
"authentication": "JWT"
}
],
"providers": [
{
"name": "auth-backend",
"type": "rest-api",
"implementation_path": "src/api/auth",
"technology": "Node.js/Express"
}
],
"testing_strategy": {
"approach": "consumer-driven",
"framework": "pact",
"consumer_tests": [
{
"consumer": "web-frontend",
"test_path": "tests/contracts/auth-api.pact.spec.ts",
"scenarios": ["Login success", "Login failure", "Register success"]
}
],
"provider_verification": {
"provider": "auth-backend",
"verification_path": "tests/contracts/verify-pacts.spec.ts",
"run_on": "pre-commit, CI/CD"
}
},
"mock_server": {
"enabled": true,
"tool": "prism",
"command": "prism mock contract.openapi.yaml",
"port": 4010,
"purpose": "Enable frontend development before backend implementation"
},
"versioning": {
"scheme": "semantic",
"current_version": "1.0.0",
"breaking_change_policy": "new major version required",
"deprecation_policy": "6 months notice, support N-1 versions",
"version_in_url": true
},
"created_at": "2026-02-14T00:00:00Z"
}
Secondary Output: .tmp/contracts/{bounded-context}/{service-name}/contract.openapi.yaml
Full OpenAPI 3.0+ specification with endpoints, schemas, security definitions.
With ArchitectureAnalyzer:
ArchitectureAnalyzer → bounded contexts → ContractManager
ContractManager aligns API contracts with domain boundaries.
With TaskManager:
ContractManager → contracts → TaskManager
TaskManager creates parallel frontend/backend subtasks using contracts.
✅ OpenAPI 3.0+ Compliance:
✅ Consumer-Driven Contracts:
✅ Parallel Development Enablement:
✅ Versioning Strategy:
Problem: Unclear service boundaries
Problem: Contract tests failing
Problem: Breaking changes needed
Problem: Mock server not matching real API
.opencode/agent/subagents/planning/contract-manager.mdUse ADRManager when:
Do NOT use when:
task(
subagent_type="ADRManager",
description="Document decision for {topic}",
prompt="Create ADR for {decision topic}.
Context: {problem statement}
Alternatives: {options considered}
Decision: {chosen approach}
Document rationale and consequences."
)
Required Context:
Primary Output: docs/adr/{seq}-{kebab-case-title}.md
# 003. Use JWT for Stateless Authentication
**Status**: accepted
**Date**: 2026-02-14
**Context**: authentication | **Module**: @app/auth
**Related Tasks**: multi-stage-orchestration-workflow-05
**Related ADRs**: None
---
## Context
We need a stateless authentication mechanism that:
- Scales horizontally without session storage
- Works across multiple services (microservices architecture)
- Supports mobile and web clients
- Provides secure token-based authentication
## Decision
We will use JWT (JSON Web Tokens) with RS256 signing for stateless authentication:
- Access tokens: 15-minute expiry
- Refresh tokens: 7-day expiry
- RS256 algorithm (asymmetric signing)
- Token payload includes: userId, roles, permissions
## Alternatives Considered
### Option 1: Session-based authentication
- **Pros**: Simple, well-understood, easy to revoke
- **Cons**: Requires session storage (Redis), doesn't scale horizontally, not suitable for microservices
- **Why rejected**: Doesn't meet scalability requirements for microservices architecture
### Option 2: OAuth 2.0 with external provider
- **Pros**: Industry standard, offloads auth complexity, supports SSO
- **Cons**: Vendor lock-in, requires internet connectivity, adds latency
- **Why rejected**: Adds unnecessary complexity for internal authentication, vendor dependency
### Option 3: JWT with HS256 (symmetric signing)
- **Pros**: Simpler than RS256, faster signing/verification
- **Cons**: Shared secret across services, harder to rotate keys, less secure
- **Why rejected**: Security concerns with shared secrets in microservices
## Consequences
### Positive
- Stateless authentication enables horizontal scaling
- No session storage required (reduces infrastructure complexity)
- Works seamlessly across microservices
- Mobile and web clients use same authentication mechanism
- Token payload reduces database lookups for user info
### Negative
- Cannot revoke tokens before expiry (mitigated by short access token lifetime)
- Token size larger than session IDs (network overhead)
- Requires key management for RS256 (public/private key pairs)
- Clock synchronization required across services for expiry validation
## Implementation Notes
- Use `jsonwebtoken` library for Node.js
- Store private key in secure vault (not in code)
- Implement token refresh endpoint
- Add token blacklist for logout (Redis with TTL)
- Monitor token expiry and refresh patterns
With ArchitectureAnalyzer:
ArchitectureAnalyzer → bounded contexts → ADRManager
ADRs specify which bounded contexts are affected by decisions.
With TaskManager:
ADRManager → ADRs → TaskManager
Tasks reference ADRs for implementation constraints.
✅ Lightweight Format:
✅ Alternatives Required:
✅ Status Lifecycle:
✅ Linking:
Problem: ADR too verbose
Problem: No alternatives documented
Problem: Unclear which bounded contexts affected
Problem: ADR status unclear
.opencode/agent/subagents/planning/adr-manager.mddocs/adr/ directory1. ArchitectureAnalyzer
↓ contexts.json
2. StoryMapper (uses bounded contexts)
↓ map.json
3. PrioritizationEngine (scores stories)
↓ prioritized.json
4. ContractManager (defines API contracts per context)
↓ contracts/
5. ADRManager (documents key decisions)
↓ docs/adr/
6. TaskManager (creates subtasks using all outputs)
1. StoryMapper (user journeys and stories)
↓ map.json
2. PrioritizationEngine (MVP identification)
↓ prioritized.json
3. TaskManager (creates subtasks)
1. ArchitectureAnalyzer (bounded contexts)
↓ contexts.json
2. ContractManager (API contracts)
↓ contracts/
3. TaskManager (parallel frontend/backend tasks)
1. ADRManager (document decision)
↓ docs/adr/
2. TaskManager (implementation tasks referencing ADR)
All agents ALWAYS call ContextScout first:
// Before any planning work
task(
subagent_type="ContextScout",
description="Find context for {agent-task}",
prompt="Find {standards/patterns/conventions} for {agent-task}.
I need to understand {specific-requirements}."
)
Why: Ensures consistency with project standards, avoids reinventing patterns.
ArchitectureAnalyzer → StoryMapper → ContractManager:
Why: Service boundaries match domain boundaries, reduces coupling.
ContractManager enables frontend/backend parallelization:
Why: Teams work independently, integration verified by tests.
ADRManager captures architectural decisions:
Why: Future developers understand why decisions were made.
Symptoms:
Root Cause: Agents not calling ContextScout
Solution:
Symptoms:
Root Cause: StoryMapper executed before ArchitectureAnalyzer
Solution:
Symptoms:
Root Cause: OpenAPI spec not kept in sync with implementation
Solution:
Symptoms:
Root Cause: Tasks not linking to ADRs
Solution:
Symptoms:
Root Cause: PrioritizationEngine not applying strict MVP criteria
Solution:
| Agent | Input | Output | When to Use |
|---|---|---|---|
| ArchitectureAnalyzer | Feature requirements | contexts.json, module-briefs/ | Complex domain logic, unclear boundaries |
| StoryMapper | User requirements, contexts | map.json | User journeys unclear, need story breakdown |
| PrioritizationEngine | Stories, business goals | prioritized.json | Need MVP identification, backlog scoring |
| ContractManager | Bounded contexts, API needs | contracts/, OpenAPI specs | Parallel dev, API-first design |
| ADRManager | Decision context, alternatives | docs/adr/*.md | Architectural decisions, pattern choices |
.opencode/agent/subagents/planning/architecture-analyzer.md.opencode/agent/subagents/planning/story-mapper.md.opencode/agent/subagents/planning/prioritization-engine.md.opencode/agent/subagents/planning/contract-manager.md.opencode/agent/subagents/planning/adr-manager.md.opencode/agent/subagents/core/context-scout.md.opencode/agent/subagents/core/task-manager.mdThe planning agent ecosystem provides a comprehensive, context-aware approach to transforming feature requirements into actionable implementation plans. By following the patterns and best practices in this guide, you can:
Key Principle: Context first, execution second. Every agent calls ContextScout to ensure alignment with project standards.