diff --git a/packages/core/src/workflow-manager.ts b/packages/core/src/workflow-manager.ts index 1efbd926..2d3d792e 100644 --- a/packages/core/src/workflow-manager.ts +++ b/packages/core/src/workflow-manager.ts @@ -15,6 +15,48 @@ import { ConfigManager } from './config-manager.js'; const logger = createLogger('WorkflowManager'); +/** + * Domain descriptions exposed to the LLM via the load_workflows tool and + * domain:// resource to help it discover and choose domains intelligently. + */ +export const DOMAIN_DESCRIPTIONS: Record = { + code: 'Day-to-day software engineering: features (epcc), test-driven development (tdd), bug fixes (bugfix, minor), greenfield projects (greenfield), large structured development (waterfall), and code reviews (pr-review)', + architecture: + 'System understanding and planning: architectural decisions (adr), legacy system modernization (big-bang-conversion), API and boundary analysis (boundary-testing), business capability modeling (business-analysis), and progressive architecture discovery (c4-analysis)', + sdd: 'Specification-driven development: write detailed specs before coding — structured requirements, user stories, testability focus, and constitutional compliance gates for bugfixes, features, and greenfield projects', + 'sdd-crowd': + 'Multi-agent collaborative specification-driven development: role-based handoffs between business analysts (specify), architects (plan), and developers (implement) for coordinated distributed teams', + skilled: + 'Skill-augmented development: explicit prompts to apply specialized expertise (architecture, coding, testing, application design) at each phase — for scenarios where best practices and domain expertise should be leveraged', + office: + 'Content creation and communication: structured workflows for writing blog posts (discovery through distribution) and creating slide presentations (ideate through deliver)', + children: + 'Educational game development for children ages 8-12: simplified, age-appropriate programming concepts with frequent positive reinforcement and incremental achievement', +}; + +/** + * Known domain names — single source of truth. Import from + * '@codemcp/workflows-core' in plugin/tool handler code. + */ +export const KNOWN_DOMAIN_NAMES = Object.keys(DOMAIN_DESCRIPTIONS) as [ + 'code', + 'architecture', + 'sdd', + 'sdd-crowd', + 'skilled', + 'office', + 'children', +]; + +export interface WorkflowManagerOptions { + /** + * Default domains to use for workflow filtering. + * Takes precedence over all environment variables. + * Can be a comma-separated string or an array of domain names. + */ + defaultDomains?: string | string[]; +} + export interface WorkflowInfo { name: string; displayName: string; @@ -41,46 +83,132 @@ export class WorkflowManager { private stateMachineLoader: StateMachineLoader; private lastProjectPath: string | null = null; // Track last loaded project path private enabledDomains: Set; + private _defaultDomains: string | string[] | null = null; // Constructor override - constructor() { + constructor(options?: WorkflowManagerOptions) { this.stateMachineLoader = new StateMachineLoader(); + if (options?.defaultDomains !== undefined) { + this._defaultDomains = options.defaultDomains; + } this.enabledDomains = this.parseEnabledDomains(); this.loadPredefinedWorkflows(); } /** - * Parse enabled domains from environment variable. - * WORKFLOW_DOMAINS is the canonical name. - * VIBE_WORKFLOW_DOMAINS is supported as a legacy alias for backward compatibility. - * WORKFLOW_DOMAINS takes precedence when both are set. + * Parse enabled domains from environment variable with four-level precedence chain: + * 1. Constructor parameter `defaultDomains` (highest priority) + * 2. `WORKFLOW_DOMAINS` env var (canonical runtime configuration) + * 3. `DEFAULT_DOMAINS` env var (runtime default when canonical is unset) + * 4. `VIBE_WORKFLOW_DOMAINS` env var (legacy alias for backward compatibility) + * 5. 'code' — final fallback: backward-compatible default */ private parseEnabledDomains(): Set { - // WORKFLOW_DOMAINS (canonical) takes precedence over VIBE_WORKFLOW_DOMAINS (legacy alias) - const domainsEnv = - process.env['WORKFLOW_DOMAINS'] || process.env['VIBE_WORKFLOW_DOMAINS']; + // 1. Constructor parameter (highest priority) + if (this._defaultDomains !== null) { + const domains = new Set( + Array.isArray(this._defaultDomains) + ? this._defaultDomains + : this._defaultDomains + .split(',') + .map(d => d.trim()) + .filter(d => d) + ); + logger.debug('Using constructor default domains', { + domains: Array.from(domains), + }); + return domains; + } + + // 2. WORKFLOW_DOMAINS (canonical) + if (process.env['WORKFLOW_DOMAINS']) { + return this._parseDomainString( + process.env['WORKFLOW_DOMAINS'], + 'WORKFLOW_DOMAINS' + ); + } - if (!domainsEnv) { - logger.debug('No domain configuration found, using default: code'); - return new Set(['code']); + // 3. DEFAULT_DOMAINS (runtime default) + if (process.env['DEFAULT_DOMAINS']) { + return this._parseDomainString( + process.env['DEFAULT_DOMAINS'], + 'DEFAULT_DOMAINS' + ); } + // 4. VIBE_WORKFLOW_DOMAINS (legacy alias) + if (process.env['VIBE_WORKFLOW_DOMAINS']) { + return this._parseDomainString( + process.env['VIBE_WORKFLOW_DOMAINS'], + 'VIBE_WORKFLOW_DOMAINS (legacy)' + ); + } + + // 5. Default — 'code' + logger.debug('No domain configuration found, using default: code'); + return new Set(['code']); + } + + /** + * Parse a comma-separated domain string into a Set. + */ + private _parseDomainString( + domainString: string, + source: string + ): Set { const domains = new Set( - domainsEnv + domainString .split(',') .map(d => d.trim()) .filter(d => d) ); - logger.debug('Parsed enabled domains', { - source: process.env['WORKFLOW_DOMAINS'] - ? 'WORKFLOW_DOMAINS' - : 'VIBE_WORKFLOW_DOMAINS (legacy)', + source, domains: Array.from(domains), }); - return domains; } + /** + * Replace the current domain set and reload workflows. + * Validates domains against DOMAIN_DESCRIPTIONS. + * Pass an empty array to load ALL workflows (no domain filtering). + * + * @throws Error if an unknown domain is provided + */ + public setDomains(domains: string | string[]): void { + const newSet = new Set( + Array.isArray(domains) + ? domains + : domains + .split(',') + .map(d => d.trim()) + .filter(d => d) + ); + + // Validate domains against known set + const knownDomains = new Set(Object.keys(DOMAIN_DESCRIPTIONS)); + for (const domain of newSet) { + if (!knownDomains.has(domain)) { + throw new Error( + `Unknown domain: '${domain}'. Known domains: ${Array.from(knownDomains).join(', ')}` + ); + } + } + + this.enabledDomains = newSet; + this.predefinedWorkflows.clear(); + this.workflowInfos.clear(); + this.loadPredefinedWorkflows(); + if (this.lastProjectPath) { + this.loadProjectWorkflows(this.lastProjectPath); + } + + logger.info('Domains updated', { + domains: Array.from(newSet), + totalWorkflows: this.predefinedWorkflows.size, + }); + } + /** * Load project-specific workflows from .vibe/workflows/ */ @@ -183,23 +311,15 @@ export class WorkflowManager { } } /** - * Get all available workflows regardless of domain filtering + * Get all available workflows regardless of domain filtering. + * Uses DEFAULT_ALL_DOMAINS env var if set, otherwise falls back to all known domains. */ public getAllAvailableWorkflows(): WorkflowInfo[] { - // Create a temporary manager with all domains enabled - const originalEnv = process.env['WORKFLOW_DOMAINS']; - process.env['WORKFLOW_DOMAINS'] = 'code,architecture,office,sdd'; - - try { - const tempManager = new WorkflowManager(); - return tempManager.getAvailableWorkflows(); - } finally { - if (originalEnv !== undefined) { - process.env['WORKFLOW_DOMAINS'] = originalEnv; - } else { - delete process.env['WORKFLOW_DOMAINS']; - } - } + const allDomains = + process.env['DEFAULT_ALL_DOMAINS'] || + Object.keys(DOMAIN_DESCRIPTIONS).join(','); + const tempManager = new WorkflowManager({ defaultDomains: allDomains }); + return tempManager.getAvailableWorkflows(); } public getAvailableWorkflows(): WorkflowInfo[] { diff --git a/packages/mcp-server/src/server-config.ts b/packages/mcp-server/src/server-config.ts index b1837f68..d012d3cf 100644 --- a/packages/mcp-server/src/server-config.ts +++ b/packages/mcp-server/src/server-config.ts @@ -20,6 +20,8 @@ import { TemplateManager } from '@codemcp/workflows-core'; import { createLogger, setLoggingLevelFromString, + DOMAIN_DESCRIPTIONS, + KNOWN_DOMAIN_NAMES, } from '@codemcp/workflows-core'; import { @@ -447,6 +449,31 @@ export async function registerMcpTools( createToolHandler('list_workflows', toolRegistry, responseRenderer, context) ); + // Register load_workflows tool — allows LLM to dynamically switch domains + const domainList = Object.entries(DOMAIN_DESCRIPTIONS) + .map(([d, desc]) => `${d}: ${desc}`) + .join(' | '); + + mcpServer.registerTool( + 'load_workflows', + { + description: `Load workflows from one or more domains. Replaces the current domain set. Available domains — ${domainList}`, + inputSchema: { + domains: z + .array(z.enum(KNOWN_DOMAIN_NAMES)) + .describe('Domain names to load.'), + }, + annotations: { + title: 'Workflow Domain Loader', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + openWorldHint: false, + }, + }, + createToolHandler('load_workflows', toolRegistry, responseRenderer, context) + ); + // Register setup_project_docs tool with enhanced file linking support const templateManager = new TemplateManager(); const availableTemplates = await templateManager.getAvailableTemplates(); diff --git a/packages/mcp-server/src/tool-handlers/index.ts b/packages/mcp-server/src/tool-handlers/index.ts index 3406c30a..911c6305 100644 --- a/packages/mcp-server/src/tool-handlers/index.ts +++ b/packages/mcp-server/src/tool-handlers/index.ts @@ -15,6 +15,7 @@ import { ResetDevelopmentHandler } from './reset-development.js'; import { ListWorkflowsHandler } from './list-workflows.js'; import { SetupProjectDocsHandler } from './setup-project-docs.js'; +import { LoadWorkflowsHandler } from './load-workflows.js'; import { ToolHandler, ToolRegistry } from '../types.js'; const logger = createLogger('ToolRegistry'); @@ -57,6 +58,7 @@ export function createToolRegistry(): ToolRegistry { registry.register('reset_development', new ResetDevelopmentHandler()); registry.register('list_workflows', new ListWorkflowsHandler()); registry.register('setup_project_docs', new SetupProjectDocsHandler()); + registry.register('load_workflows', new LoadWorkflowsHandler()); logger.info('Tool registry created with handlers', { handlers: registry.list(), @@ -74,6 +76,7 @@ export { ResumeWorkflowHandler } from './resume-workflow.js'; export { ResetDevelopmentHandler } from './reset-development.js'; export { ListWorkflowsHandler } from './list-workflows.js'; export { SetupProjectDocsHandler } from './setup-project-docs.js'; +export { LoadWorkflowsHandler } from './load-workflows.js'; export { BaseToolHandler, ConversationRequiredToolHandler, diff --git a/packages/mcp-server/src/tool-handlers/load-workflows.ts b/packages/mcp-server/src/tool-handlers/load-workflows.ts new file mode 100644 index 00000000..19f345fd --- /dev/null +++ b/packages/mcp-server/src/tool-handlers/load-workflows.ts @@ -0,0 +1,81 @@ +/** + * Load Workflows Tool Handler + * + * Allows the LLM to dynamically load workflows from one or more domains + * at runtime. Essential for long-lived processes (MCP server, OpenCode + * plugin) where the initial domain configuration may not include all + * needed workflows. + */ + +import { z } from 'zod'; +import { BaseToolHandler } from './base-tool-handler.js'; +import { createLogger } from '@codemcp/workflows-core'; +import { ServerContext } from '../types.js'; + +const logger = createLogger('LoadWorkflowsHandler'); + +const LoadWorkflowsArgsSchema = z.object({ + domains: z + .array(z.string()) + .describe( + 'Domain names to load. Use domain:// resource to discover available domains and their descriptions.' + ), +}); + +type LoadWorkflowsArgs = z.infer; + +interface LoadWorkflowsResponse { + success: boolean; + domains: string[]; + totalWorkflows: number; + message: string; +} + +export class LoadWorkflowsHandler extends BaseToolHandler< + LoadWorkflowsArgs, + LoadWorkflowsResponse +> { + protected readonly argsSchema = LoadWorkflowsArgsSchema; + + async executeHandler( + args: LoadWorkflowsArgs, + context: ServerContext + ): Promise { + logger.info('Loading workflows from domains', { + domains: args.domains, + projectPath: context.projectPath, + }); + + try { + context.workflowManager.setDomains(args.domains); + + const totalWorkflows = + context.workflowManager.getAvailableWorkflows().length; + + logger.info('Workflows loaded successfully', { + domains: args.domains, + totalWorkflows, + }); + + return { + success: true, + domains: args.domains, + totalWorkflows, + message: `Loaded workflows from domains: ${args.domains.join(', ')}. Total workflows available: ${totalWorkflows}.`, + }; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Unknown error'; + logger.error('Failed to load workflows', error as Error, { + domains: args.domains, + }); + + return { + success: false, + domains: [], + totalWorkflows: 0, + message: `Failed to load workflows: ${errorMessage}`, + }; + } + } +} diff --git a/packages/opencode-plugin/src/plugin.ts b/packages/opencode-plugin/src/plugin.ts index 0bace31f..d3d7f6c0 100644 --- a/packages/opencode-plugin/src/plugin.ts +++ b/packages/opencode-plugin/src/plugin.ts @@ -19,6 +19,7 @@ import { createConductReviewTool } from './tool-handlers/conduct-review.js'; import { createResetDevelopmentTool } from './tool-handlers/reset-development.js'; import { createStartDevelopmentTool } from './tool-handlers/start-development.js'; import { createSetupProjectDocsTool } from './tool-handlers/setup-project-docs.js'; +import { createLoadWorkflowsTool } from './tool-handlers/load-workflows.js'; import { createOpenCodeLogger, createOpenCodeLoggerFactory, @@ -844,6 +845,10 @@ ACTION REQUIRED: Use proceed_to_phase tool to move to a phase that allows editin 'setup_project_docs', await createSetupProjectDocsTool(input.directory, getServerContext) ), + load_workflows: wrap( + 'load_workflows', + createLoadWorkflowsTool(getServerContext) + ), }; })(), }; diff --git a/packages/opencode-plugin/src/tool-handlers/load-workflows.ts b/packages/opencode-plugin/src/tool-handlers/load-workflows.ts new file mode 100644 index 00000000..62e0200c --- /dev/null +++ b/packages/opencode-plugin/src/tool-handlers/load-workflows.ts @@ -0,0 +1,64 @@ +import { z } from 'zod'; +import type { ServerContext } from '@codemcp/workflows-server'; +import type { ToolDefinition } from '../types.js'; +import { tool } from './tool-helper.js'; +import { + createLogger, + KNOWN_DOMAIN_NAMES, + DOMAIN_DESCRIPTIONS, +} from '@codemcp/workflows-core'; + +const logger = createLogger('LoadWorkflowsHandler'); + +const domainList = Object.entries(DOMAIN_DESCRIPTIONS) + .map(([d, desc]) => `${d}: ${desc}`) + .join(' | '); + +export function createLoadWorkflowsTool( + getServerContext: () => Promise +): ToolDefinition { + return tool({ + description: `Load workflows from one or more domains. Replaces the current domain set. Available domains — ${domainList}`, + args: { + domains: z + .array(z.enum(KNOWN_DOMAIN_NAMES)) + .describe('Domain names to load.'), + }, + execute: async args => { + logger.info('Loading workflows from domains', { domains: args.domains }); + + try { + const serverContext = await getServerContext(); + serverContext.workflowManager.setDomains(args.domains); + + const totalWorkflows = + serverContext.workflowManager.getAvailableWorkflows().length; + + logger.info('Workflows loaded successfully', { + domains: args.domains, + totalWorkflows, + }); + + return JSON.stringify({ + success: true, + domains: args.domains, + totalWorkflows, + message: `Loaded workflows from domains: ${args.domains.join(', ')}. Total workflows available: ${totalWorkflows}.`, + }); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Unknown error'; + logger.error('Failed to load workflows', error as Error, { + domains: args.domains, + }); + + return JSON.stringify({ + success: false, + domains: [], + totalWorkflows: 0, + message: `Failed to load workflows: ${errorMessage}`, + }); + } + }, + }); +} diff --git a/resources/workflows/bugfix.yaml b/resources/workflows/bugfix.yaml index d9548d6b..a61ad47e 100644 --- a/resources/workflows/bugfix.yaml +++ b/resources/workflows/bugfix.yaml @@ -71,11 +71,6 @@ states: - perspective: 'security_expert' prompt: "Evaluate if the bug has security implications and ensure the fix doesn't introduce new vulnerabilities. Review the security aspects of the proposed solution." - - trigger: 'abandon_bug' - to: 'reproduce' - additional_instructions: 'Bug analysis abandoned. Clean up any analysis work and prepare for new bug reports.' - transition_reason: 'Bug analysis abandoned' - fix: description: 'Implement the bug fix' required_capability: 'coding' @@ -109,11 +104,6 @@ states: - perspective: 'performance_engineer' prompt: "Verify that the fix doesn't introduce performance regressions or new bottlenecks. Assess the performance impact of the implemented solution." - - trigger: 'abandon_bug' - to: 'reproduce' - additional_instructions: 'Bug fix abandoned. Clean up any fix work and prepare for new bug reports.' - transition_reason: 'Bug fix abandoned' - verify: description: 'Verify the fix and ensure no regressions' required_capability: 'thinking' @@ -135,11 +125,6 @@ states: to: 'finalize' transition_reason: 'Bug fix complete and verified, ready for next issue' - - trigger: 'abandon_bug' - to: 'reproduce' - additional_instructions: 'Bug verification abandoned. Clean up any verification work and prepare for new bug reports.' - transition_reason: 'Bug verification abandoned' - finalize: description: 'Code cleanup and documentation finalization' referred_docs: diff --git a/resources/workflows/epcc.yaml b/resources/workflows/epcc.yaml index 70bdc99e..a2bc5e57 100644 --- a/resources/workflows/epcc.yaml +++ b/resources/workflows/epcc.yaml @@ -84,14 +84,6 @@ states: - perspective: 'security_expert' prompt: 'Assess security considerations and potential risks in the planned implementation approach. Review data handling, authentication, and potential vulnerabilities.' - - trigger: 'abandon_feature' - to: 'explore' - instructions: > - Feature development abandoned during planning. Return to exploration state for new tasks. - Task history will remain for future reference. - additional_instructions: 'Feature development abandoned during planning. Clean up any planning work and prepare for new tasks.' - transition_reason: 'User decided to abandon feature during planning phase' - code: description: 'Implementation phase - writing and building the solution' required_capability: 'coding' @@ -129,14 +121,6 @@ states: - perspective: 'performance_engineer' prompt: 'Evaluate performance impact, resource efficiency, and scalability of the implemented solution. Check for potential bottlenecks or optimization opportunities.' - - trigger: 'abandon_feature' - to: 'explore' - instructions: > - Feature development abandoned during implementation. Clean up any incomplete code and return to exploration. - Task history and any completed work will remain for future reference. - additional_instructions: 'Clean up any incomplete code and prepare for new tasks.' - transition_reason: 'User decided to abandon feature during implementation' - commit: description: 'Code cleanup and documentation finalization' referred_docs: diff --git a/resources/workflows/greenfield.yaml b/resources/workflows/greenfield.yaml index 48e441d5..e316406e 100644 --- a/resources/workflows/greenfield.yaml +++ b/resources/workflows/greenfield.yaml @@ -84,14 +84,6 @@ states: - perspective: 'security_expert' prompt: 'Evaluate security architecture, data protection strategies, and potential vulnerabilities. Ensure security is built into the foundation of the greenfield project from the start.' - - trigger: 'abandon_project' - to: 'ideation' - instructions: > - Project development abandoned during architecture phase. Return to ideation state for new projects. - Task history and PRD will remain for future reference. - additional_instructions: 'Project development abandoned during architecture phase. Clean up any architecture work and prepare for new projects.' - transition_reason: 'User decided to abandon project during architecture phase' - plan: description: 'Implementation planning phase based on established architecture' referred_docs: @@ -127,14 +119,6 @@ states: additional_instructions: "Implementation plan is complete! ✅ Now transition to coding phase. Read specific documentation before using the chosen libraries and frameworks. Follow the architectural patterns and tech stack decisions you've made. Modularize your code according to best practices. Stay focused on the current project scope defined in your PRD. Update task progress as you complete planning work." transition_reason: 'Implementation plan is complete and ready for coding' - - trigger: 'abandon_project' - to: 'ideation' - instructions: > - Project development abandoned during planning. Return to ideation state for new projects. - Task history, PRD, and architecture documentation will remain for future reference. - additional_instructions: 'Project development abandoned during planning. Clean up any planning work and prepare for new projects.' - transition_reason: 'User decided to abandon project during planning phase' - code: description: 'Implementation phase following the established plan and architecture' required_capability: 'coding' @@ -167,14 +151,6 @@ states: to: 'finalize' transition_reason: 'Core implementation is complete, ready for comprehensive documentation' - - trigger: 'abandon_project' - to: 'ideation' - instructions: > - Project development abandoned during implementation. Clean up any incomplete code and return to ideation. - Task history, PRD, architecture documentation, and any completed work will remain for future reference. - additional_instructions: 'Project development abandoned during implementation. Clean up any incomplete code and prepare for new projects.' - transition_reason: 'User decided to abandon project during implementation' - finalize: description: 'Code cleanup and documentation finalization' referred_docs: diff --git a/resources/workflows/minor.yaml b/resources/workflows/minor.yaml index fefccbf7..0d9233f6 100644 --- a/resources/workflows/minor.yaml +++ b/resources/workflows/minor.yaml @@ -83,14 +83,6 @@ states: to: 'finalize' transition_reason: 'Implementation complete, ready for finalization' - - trigger: 'abandon_feature' - to: 'explore' - instructions: > - Minor enhancement abandoned during implementation. Clean up any incomplete code and return to exploration. - Task history and any completed work will remain for future reference. - additional_instructions: 'Clean up any incomplete code and prepare for new tasks.' - transition_reason: 'User decided to abandon minor enhancement during implementation' - finalize: description: 'Code cleanup and documentation finalization' referred_docs: diff --git a/resources/workflows/posts.yaml b/resources/workflows/posts.yaml index bda371bb..f0b459fd 100644 --- a/resources/workflows/posts.yaml +++ b/resources/workflows/posts.yaml @@ -75,14 +75,6 @@ states: additional_instructions: 'Resolve gaps in research or format clarity by focusing on foundational aspects.' transition_reason: 'Story work revealed need for additional discovery or research' - - trigger: abandon_post - to: discovery - instructions: | - Abandon post development during story phase. Clean up story work and return to discovery. - The `$PLAN_FILE` and any completed work will remain for future reference. - additional_instructions: 'Clean up and prepare for new topics.' - transition_reason: 'User decided to abandon post during story phase' - writing: description: 'Create the actual post content following story outline' default_instructions: | @@ -115,14 +107,6 @@ states: additional_instructions: 'Refine the story foundation to address issues with structure or narrative flow.' transition_reason: 'Content creation revealed need for story structure refinement' - - trigger: abandon_post - to: discovery - instructions: | - Abandon post development during writing. Clean up writing work and return to discovery. - The `$PLAN_FILE` and any completed work will remain for future reference. - additional_instructions: 'Clean up and prepare for new topics.' - transition_reason: 'User decided to abandon post during writing phase' - illustration: description: 'Create and integrate visual elements' default_instructions: | @@ -153,14 +137,6 @@ states: additional_instructions: 'Complete the content foundation to address gaps revealed during visual work.' transition_reason: 'Visual work revealed need for additional written content' - - trigger: abandon_post - to: discovery - instructions: | - Abandon post development during illustration. Clean up illustration work and return to discovery. - The `$PLAN_FILE` and any completed work will remain for future reference. - additional_instructions: 'Clean up and prepare for new topics.' - transition_reason: 'User decided to abandon post during illustration phase' - distribution: description: 'Optimize for SEO and publish across platforms' default_instructions: | diff --git a/resources/workflows/qrspi.yaml b/resources/workflows/qrspi.yaml index 1d80d4a0..55078dc4 100644 --- a/resources/workflows/qrspi.yaml +++ b/resources/workflows/qrspi.yaml @@ -49,11 +49,6 @@ states: to: 'research' transition_reason: 'Intent clarified, ready to gather facts' - - trigger: 'abandon_feature' - to: 'questions' - instructions: 'Feature abandoned. Reset for new tasks.' - transition_reason: 'User abandoned feature during questions' - research: description: 'Gather facts without forming conclusions or proposing solutions' required_capability: 'research' @@ -79,11 +74,6 @@ states: additional_instructions: 'Focus on the specific areas where intent is still unclear.' transition_reason: 'Research revealed gaps in understanding' - - trigger: 'abandon_feature' - to: 'questions' - instructions: 'Feature abandoned. Reset for new tasks.' - transition_reason: 'User abandoned feature during research' - design: description: 'Explore options and reach consensus on WHAT and high-level HOW' required_capability: 'thinking' @@ -116,11 +106,6 @@ states: additional_instructions: 'Focus on the specific gaps that block design consensus.' transition_reason: 'Design discussion revealed need for more research' - - trigger: 'abandon_feature' - to: 'questions' - instructions: 'Feature abandoned. Reset for new tasks.' - transition_reason: 'User abandoned feature during design' - structure: description: 'Decompose the approved design into end-to-end vertical slices' required_capability: 'thinking' @@ -148,11 +133,6 @@ states: additional_instructions: 'The design approach makes slicing difficult. Revisit the high-level approach with the user.' transition_reason: 'Structure work revealed design gaps' - - trigger: 'abandon_feature' - to: 'questions' - instructions: 'Feature abandoned. Reset for new tasks.' - transition_reason: 'User abandoned feature during structure' - plan: description: 'Create a detailed implementation plan per vertical slice' required_capability: 'thinking' @@ -188,11 +168,6 @@ states: additional_instructions: 'The slice boundaries are wrong. Redefine the vertical slices.' transition_reason: 'Planning revealed flaws in slice boundaries' - - trigger: 'abandon_feature' - to: 'questions' - instructions: 'Feature abandoned. Reset for new tasks.' - transition_reason: 'User abandoned feature during planning' - implement: description: 'Build the solution slice by slice' required_capability: 'coding' @@ -235,11 +210,6 @@ states: additional_instructions: 'Focus on the specific areas blocking implementation progress.' transition_reason: 'Implementation revealed need for more research' - - trigger: 'abandon_feature' - to: 'questions' - instructions: 'Feature abandoned. Clean up incomplete code and reset for new tasks.' - transition_reason: 'User abandoned feature during implementation' - commit: description: 'Cleanup, documentation finalization, and delivery' referred_docs: diff --git a/resources/workflows/sdd-bugfix.yaml b/resources/workflows/sdd-bugfix.yaml index 2d70245b..50a2ac78 100644 --- a/resources/workflows/sdd-bugfix.yaml +++ b/resources/workflows/sdd-bugfix.yaml @@ -371,11 +371,3 @@ states: Return to specification to better define the requirements. The fix doesn't fully address the original problem or reveals incomplete specification. transition_reason: 'Fix insufficient, need to revise specification' - -# Global transitions available from any state -global_transitions: - - trigger: 'abandon_bugfix' - to: 'reproduce' - instructions: > - If you want to restart, you'll begin again with reproducing and understanding the bug. - transition_reason: 'Bug fix abandoned, restart from beginning' diff --git a/resources/workflows/sdd-feature.yaml b/resources/workflows/sdd-feature.yaml index 4f27dc4f..65a01087 100644 --- a/resources/workflows/sdd-feature.yaml +++ b/resources/workflows/sdd-feature.yaml @@ -460,12 +460,3 @@ states: Significant integration issues discovered that require better understanding of the existing system. Return to analysis to gather more context. transition_reason: 'Integration issues require deeper system analysis' - -# Global transitions available from any state -global_transitions: - - trigger: 'abandon_feature' - to: 'analyze' - instructions: > - Feature development abandoned. If you want to restart, you'll begin again with - analyzing the requirements and current state. - transition_reason: 'Feature abandoned, restart from beginning' diff --git a/resources/workflows/sdd-greenfield.yaml b/resources/workflows/sdd-greenfield.yaml index a8897713..a827e899 100644 --- a/resources/workflows/sdd-greenfield.yaml +++ b/resources/workflows/sdd-greenfield.yaml @@ -453,11 +453,3 @@ states: Create comprehensive documentation that enables users to successfully adopt and use the project. transitions: [] - -# Global transitions available from any state -global_transitions: - - trigger: 'abandon_project' - to: 'constitution' - instructions: > - If you want to restart the project, you'll begin again with establishing the constitutional framework. - transition_reason: 'Project abandoned, restart from beginning' diff --git a/resources/workflows/skilled-bugfix.yaml b/resources/workflows/skilled-bugfix.yaml index 512ae98a..398fac4f 100644 --- a/resources/workflows/skilled-bugfix.yaml +++ b/resources/workflows/skilled-bugfix.yaml @@ -64,11 +64,6 @@ states: - perspective: 'security_expert' prompt: "Evaluate if the bug has security implications and ensure the fix doesn't introduce new vulnerabilities. Review the security aspects of the proposed solution." - - trigger: 'abandon_bug' - to: 'reproduce' - additional_instructions: 'Bug analysis abandoned. Clean up any analysis work and prepare for new bug reports.' - transition_reason: 'Bug analysis abandoned' - fix: description: 'Implement the bug fix' default_instructions: | @@ -99,11 +94,6 @@ states: - perspective: 'performance_engineer' prompt: "Verify that the fix doesn't introduce performance regressions or new bottlenecks. Assess the performance impact of the implemented solution." - - trigger: 'abandon_bug' - to: 'reproduce' - additional_instructions: 'Bug fix abandoned. Clean up any fix work and prepare for new bug reports.' - transition_reason: 'Bug fix abandoned' - verify: description: 'Verify the fix and ensure no regressions' default_instructions: | @@ -126,11 +116,6 @@ states: to: 'finalize' transition_reason: 'Bug fix complete and verified, ready for next issue' - - trigger: 'abandon_bug' - to: 'reproduce' - additional_instructions: 'Bug verification abandoned. Clean up any verification work and prepare for new bug reports.' - transition_reason: 'Bug verification abandoned' - finalize: description: 'Code cleanup and documentation finalization' default_instructions: | diff --git a/resources/workflows/skilled-epcc.yaml b/resources/workflows/skilled-epcc.yaml index ba419ee7..d0a288fc 100644 --- a/resources/workflows/skilled-epcc.yaml +++ b/resources/workflows/skilled-epcc.yaml @@ -67,14 +67,6 @@ states: - perspective: 'security_expert' prompt: 'Assess security considerations and potential risks in the planned implementation approach. Review data handling, authentication, and potential vulnerabilities.' - - trigger: 'abandon_feature' - to: 'explore' - instructions: > - Feature development abandoned during planning. Return to exploration state for new tasks. - Task history will remain for future reference. - additional_instructions: 'Feature development abandoned during planning. Clean up any planning work and prepare for new tasks.' - transition_reason: 'User decided to abandon feature during planning phase' - code: description: 'Implementation phase - writing and building the solution' default_instructions: | @@ -106,14 +98,6 @@ states: - perspective: 'performance_engineer' prompt: 'Evaluate performance impact, resource efficiency, and scalability of the implemented solution. Check for potential bottlenecks or optimization opportunities.' - - trigger: 'abandon_feature' - to: 'explore' - instructions: > - Feature development abandoned during implementation. Clean up any incomplete code and return to exploration. - Task history and any completed work will remain for future reference. - additional_instructions: 'Clean up any incomplete code and prepare for new tasks.' - transition_reason: 'User decided to abandon feature during implementation' - commit: description: 'Code cleanup and documentation finalization' default_instructions: > diff --git a/resources/workflows/skilled-greenfield.yaml b/resources/workflows/skilled-greenfield.yaml index 832f9c5e..1b8d85b4 100644 --- a/resources/workflows/skilled-greenfield.yaml +++ b/resources/workflows/skilled-greenfield.yaml @@ -75,14 +75,6 @@ states: - perspective: 'security_expert' prompt: 'Evaluate security architecture, data protection strategies, and potential vulnerabilities. Ensure security is built into the foundation of the greenfield project from the start.' - - trigger: 'abandon_project' - to: 'ideation' - instructions: > - Project development abandoned during architecture phase. Return to ideation state for new projects. - Task history and PRD will remain for future reference. - additional_instructions: 'Project development abandoned during architecture phase. Clean up any architecture work and prepare for new projects.' - transition_reason: 'User decided to abandon project during architecture phase' - plan: description: 'Implementation planning phase based on established architecture' default_instructions: | @@ -114,14 +106,6 @@ states: additional_instructions: "Implementation plan is complete! ✅ Now transition to coding phase. Read specific documentation before using the chosen libraries and frameworks. Follow the architectural patterns and tech stack decisions you've made. Modularize your code according to best practices. Stay focused on the current project scope defined in your PRD. Update task progress as you complete planning work." transition_reason: 'Implementation plan is complete and ready for coding' - - trigger: 'abandon_project' - to: 'ideation' - instructions: > - Project development abandoned during planning. Return to ideation state for new projects. - Task history, PRD, and architecture documentation will remain for future reference. - additional_instructions: 'Project development abandoned during planning. Clean up any planning work and prepare for new projects.' - transition_reason: 'User decided to abandon project during planning phase' - code: description: 'Implementation phase following the established plan and architecture' default_instructions: | @@ -150,14 +134,6 @@ states: to: 'finalize' transition_reason: 'Core implementation is complete, ready for comprehensive documentation' - - trigger: 'abandon_project' - to: 'ideation' - instructions: > - Project development abandoned during implementation. Clean up any incomplete code and return to ideation. - Task history, PRD, architecture documentation, and any completed work will remain for future reference. - additional_instructions: 'Project development abandoned during implementation. Clean up any incomplete code and prepare for new projects.' - transition_reason: 'User decided to abandon project during implementation' - finalize: description: 'Code cleanup and documentation finalization' default_instructions: | diff --git a/resources/workflows/slides.yaml b/resources/workflows/slides.yaml index f2cf520b..08311479 100644 --- a/resources/workflows/slides.yaml +++ b/resources/workflows/slides.yaml @@ -67,15 +67,6 @@ states: additional_instructions: 'Structural work revealed gaps in the initial concept or goals. Focus on clarifying these fundamental aspects.' transition_reason: 'Structure work revealed need for more ideation or concept refinement' - - trigger: abandon_presentation - to: ideate - instructions: | - **Abandon structural work** - Clean up structural work and return to ideation. - - The plan file and any completed work will remain for future reference. - additional_instructions: 'Presentation abandoned during structure phase. Clean up and prepare for new topics.' - transition_reason: 'User decided to abandon presentation during structure phase' - draft: description: 'Create content, speaker notes, and visual planning' default_instructions: | @@ -105,15 +96,6 @@ states: additional_instructions: 'Drafting revealed issues with content organization or flow. Focus on refining the structural foundation.' transition_reason: 'Content creation revealed need for better structure or organization' - - trigger: abandon_presentation - to: ideate - instructions: | - **Abandon drafting work** - Clean up content work and return to ideation. - - The plan file and any completed work will remain for future reference. - additional_instructions: 'Presentation abandoned during draft phase. Clean up and prepare for new topics.' - transition_reason: 'User decided to abandon presentation during draft phase' - style: description: 'Apply design, create visuals, and enhance presentation aesthetics' default_instructions: | @@ -144,15 +126,6 @@ states: additional_instructions: 'Styling work revealed gaps in content or speaker notes. Focus on completing the content foundation.' transition_reason: 'Visual design revealed need for additional content or speaker note refinement' - - trigger: abandon_presentation - to: ideate - instructions: | - **Abandon styling work** - Clean up design work and return to ideation. - - The plan file and any completed work will remain for future reference. - additional_instructions: 'Presentation abandoned during style phase. Clean up and prepare for new topics.' - transition_reason: 'User decided to abandon presentation during style phase' - review: description: 'Validate content quality and presentation effectiveness' default_instructions: | @@ -188,15 +161,6 @@ states: additional_instructions: 'Review revealed content gaps or issues that need addressing. Focus on refining the content and speaker notes.' transition_reason: 'Review process identified content issues requiring draft phase work' - - trigger: abandon_presentation - to: ideate - instructions: | - **Abandon review work** - Clean up review work and return to ideation. - - The plan file and any completed work will remain for future reference. - additional_instructions: 'Presentation abandoned during review phase. Clean up and prepare for new topics.' - transition_reason: 'User decided to abandon presentation during review phase' - deliver: description: 'Prepare final presentation for delivery' default_instructions: | diff --git a/resources/workflows/socratic-recovery.yaml b/resources/workflows/socratic-recovery.yaml new file mode 100644 index 00000000..59f56b5f --- /dev/null +++ b/resources/workflows/socratic-recovery.yaml @@ -0,0 +1,509 @@ +# yaml-language-server: $schema=../state-machine-schema.json +--- +name: 'socratic-recovery' +description: >- + Brownfield architecture recovery for undocumented codebases. + Builds a hierarchical Question Tree from source code, surfaces OPEN_QUESTIONS + for the team to answer, then synthesizes arc42 documentation, a PRD, Cockburn + use-case spec, and Nygard ADRs — with an independent Fagan/ATAM review pass. + The OPEN_QUESTIONS file is the primary deliverable: gaps are never invented. +initial_state: 'question_tree' +metadata: + domain: 'architecture' + complexity: 'high' + requiresDocumentation: false + bestFor: + - 'Brownfield / legacy system documentation' + - 'Recovering lost architecture knowledge' + - 'Producing arc42 from an undocumented codebase' + - 'Making implicit design decisions explicit' + - 'Identifying knowledge gaps before a major refactor or handover' + useCases: + - 'Document a legacy service before migrating it to a new platform' + - 'Onboard a new architect by recovering the system theory' + - 'Prepare for an architecture review board with no existing docs' + - 'Surface OPEN questions before a bounded-context redesign' + examples: + - 'Recover arc42 for a legacy Java payment service before cloud migration' + - 'Produce a PRD + use-case spec for an inherited Node.js API with no docs' + - 'Build an OPEN_QUESTIONS register for a monolith before strangler-fig extraction' + +states: + question_tree: + description: >- + Set up arc42 + Cockburn use-case documentation skeleton, then build a + hierarchical Question Tree from the codebase. Produces + QUESTION_TREE-.md and OPEN_QUESTIONS-.md + for a named bounded context. + allowed_file_patterns: + - 'QUESTION_TREE-*.md' + - 'OPEN_QUESTIONS-*.md' + default_instructions: > + **STEP 1 — Confirm the bounded context.** + + Before doing anything else, confirm with the user: + 1. The path to the bounded context (directory or set of directories). + NEVER default to CWD — always ask. + 2. A short kebab-case context name (e.g. `auth`, `order-service`, + `payment-gateway`). This name is appended to every output file so + that sequential runs on different contexts never overwrite each other. + + **STEP 2 — Build the Question Tree.** + + Delegate this step to an agent. Ask the agent specifically to: read the + codebase at [bounded context path], build a hierarchical Question Tree by + recursively decomposing five root questions down to leaf level, classify + every leaf as [ANSWERED] (with file:line evidence) or [OPEN] (with + category and role), run the sanity-check described in the prompt, and + write both output files before returning. + + **Agent prompt:** + + ``` + Build a hierarchical Question Tree for the codebase at + [bounded context path]. + + Start with these five root questions: + Q1 What problem does this bounded context solve, and for whom? + Q2 What is the specification of this bounded context? + Q3 What is the architecture of this bounded context? + Q4 What quality goals drive the design? + Q5 What risks and technical debt exist? + + The second level of the tree is FIXED — emit exactly these nodes in this + order, even when a node's only leaf is [OPEN] or [ANSWERED: not + applicable]: + Q1.1–Q1.6 product identity, primary users, channels, why-built, + success metrics, segment priority + Q2.1–Q2.6 actors, use-case catalog, per-interface system specs, + data/entity model, acceptance criteria, cross-cutting + business rules + Q3.1–Q3.12 the twelve arc42 chapters, in arc42 order + Q4.1–Q4.8 the eight ISO/IEC 25010 characteristics + Q4.9 which characteristic has priority + Q5.1–Q5.5 technical debt, security risks, operational risks, + dependency/supply-chain risks, scaling/performance risks + + Q3.2 (Architecture Constraints) carries a FIXED third level too: + Q3.2.1 technical constraints — language, runtime, mandated + frameworks/libraries + Q3.2.2 organizational/process constraints — git workflow, branching, + release process, review rules + Q3.2.3 conventional constraints — naming, file layout, code-style + rules, commit conventions + For Q3.2, also look beyond source code: CLAUDE.md / AGENTS.md, + CONTRIBUTING files, CI workflow definitions, and linter/formatter configs + are valid evidence sources — cite them file:line like any other evidence. + + Below the fixed second level, decompose ADAPTIVELY and code-driven. + A node is a leaf ONLY when its question can be answered with specific + file:line (or file::function) evidence, or definitively marked [OPEN]. + If the honest answer is still coarse (a whole directory, a bare package + name, a paragraph standing in for an entire arc42 chapter), the node is + NOT a leaf — decompose it further until every leaf maps to one specific, + citable piece of code. Do not decompose more than four levels below any + fixed node; if a leaf is still too coarse at that depth, mark it [OPEN] + (Category: business-context or design-rationale). + + For each leaf, classify it: + + [ANSWERED] + — You found the answer in the code. + — Cite evidence as : or ::. + — Be exact. A directory path is NOT valid evidence. + + [OPEN] + — The answer is not derivable from code alone. + — Category: business-context | design-rationale | quality-goals | + stakeholder-context | future-direction + — Ask role: Product Owner | Architect | Developer | Domain Expert | + Operations + — State precisely what cannot be answered and why. + + Quality (the Q4 branch) is not wholly team knowledge. Where the code + shows measurable behaviour — a timeout, a retry policy, a budget, a + truncation limit — write it as an [ANSWERED] quality scenario with + file:line. Only the quality-goal ranking (Q4.9) is [OPEN]. + + Write two output files in Markdown at the repository root. Name them + after the bounded context so sequential runs never overwrite each other: + + QUESTION_TREE-[context-name].md + — Full hierarchical tree with all nodes and Q-IDs. + — Each leaf marked [ANSWERED] (with evidence) or [OPEN] (with + Category and Ask role). + — Includes all reasoning, not only the leaves. + + OPEN_QUESTIONS-[context-name].md + — Only the [OPEN] leaves, copied verbatim from the Question Tree. + — One section per Ask role (Product Owner, Architect, Developer, + Domain Expert, Operations) — emit every section even when empty + ("No open questions for this role"). + — Each question short enough to be answered in 1–3 sentences. + + Before returning, run this sanity-check: + 1. Pick three [ANSWERED] leaves at random. Verify each cited file:line + actually contains the claimed fact. If any citation is fabricated, + stop and report that the bounded context is too large. + 2. Scan for [ANSWERED] leaves whose evidence is a directory path or + whole file. Those need further decomposition. + 3. Count [OPEN] leaves: 10–15 is healthy for a small context; + 15–30 acceptable for a larger one; > 50 means the context is too + large — split it; < 5 means check decomposition depth. + + Do not write any documentation other than these two files. + ``` + + **STEP 3 — Report to the user.** + + After the agent returns, summarise the OPEN leaf count and health + assessment. Do NOT proceed to synthesis — that happens only after the + team has answered every [OPEN] leaf. + + transitions: + - trigger: 'question_tree_complete' + to: 'answer_open_questions' + transition_reason: >- + Question Tree and OPEN_QUESTIONS files written, sanity-checked, + and ready for team routing. + additional_instructions: | + Remind the user: + + 1. Open `OPEN_QUESTIONS-.md`. + 2. Route each section to the appropriate role: + - **Product Owner** — Q1 / business context questions + - **Architect** — Q3 / design-rationale questions + - **Developer** — Q3 / implementation questions + - **Domain Expert** — Q1–Q2 / domain knowledge questions + - **Operations** — Q5 / operational / deployment questions + 3. Each person writes their answer **directly under the question** + in plain prose (1–3 sentences). + 4. If a question cannot be answered now, mark it explicitly as + `(deferred)` — do NOT leave it blank. + 5. When every question has an answer or `(deferred)`, trigger + `open_questions_answered`. + + answer_open_questions: + description: >- + Human-gated state. The team routes OPEN leaves to the right roles and + writes answers or explicit (deferred) markers directly in + OPEN_QUESTIONS-.md. The LLM acts as facilitator and + gate-keeper — it does NOT fill in gaps. + allowed_file_patterns: + - 'OPEN_QUESTIONS-*.md' + default_instructions: > + **CRITICAL RULE: Never invent answers to [OPEN] leaves.** + A deferred leaf is honest documentation. An invented answer is the + primary failure mode of this workflow. If in doubt, mark as (deferred). + + **STEP 1 — Read the file.** + + Read `OPEN_QUESTIONS-.md`. (Ask the user for the + context-name if it is not clear from context.) + + **STEP 2 — Check the gate condition.** + + Scan every [OPEN] leaf. For each one, check: + - Does it have a team answer written under it? (1–3 sentences of prose) + - Does it have an explicit `(deferred)` marker? + + If ANY leaf has neither: + - List all unanswered leaves grouped by Ask role. + - State: "The following questions must be answered or explicitly + deferred before synthesis can run." + - Do NOT proceed. Wait for the user to provide answers. + + If ALL leaves are answered or deferred: + - Confirm: "Gate condition met — every [OPEN] leaf has a team answer + or (deferred) marker." + - Suggest triggering `open_questions_answered`. + + **STEP 3 — Assist with answering (optional).** + + If the user asks for help formulating a question to send to a + stakeholder, help write a clear, concise question. Do NOT provide the + answer yourself unless you can derive it from the codebase with a + file:line citation. + + transitions: + - trigger: 'open_questions_answered' + to: 'synthesize_documentation' + transition_reason: >- + Every [OPEN] leaf has a team answer or (deferred) marker. + Synthesis can now proceed. + review_perspectives: + - perspective: 'fabrication_check' + prompt: >- + Review every team answer in OPEN_QUESTIONS-.md. + Flag any answer that: + (a) Could only be known by reading source code (should be + [ANSWERED] with file:line, not a team answer); + (b) Is suspiciously precise without citing evidence (possible + hallucination or invention); + (c) Contradicts an [ANSWERED] leaf in the Question Tree. + Report findings before allowing the transition to proceed. + + synthesize_documentation: + description: >- + Synthesize PRD, Cockburn use-case spec, arc42 (12 chapters), and Nygard + ADRs from the answered Question Tree. Code-derived claims cite file:line; + team answers are marked (team answer); deferred questions remain explicit + gaps — never filled by invention. + allowed_file_patterns: + - 'docs/specs/prd-*.md' + - 'docs/specs/use-cases-*.md' + - 'docs/arc42/arc42-*.md' + - 'docs/specs/adrs/*.md' + default_instructions: > + **STEP 1 — Re-verify the gate condition.** + + Read `OPEN_QUESTIONS-.md`. If ANY [OPEN] leaf has neither + a team answer nor an explicit `(deferred)` marker, STOP. List the + unanswered leaves and instruct the user to return to + `answer_open_questions`. + + **STEP 2 — Synthesize the four output documents.** + + Delegate the four output files to four agents running in parallel. Give + every agent the traceability rules below. Ask each agent specifically to + read `QUESTION_TREE-.md` and + `OPEN_QUESTIONS-.md`, synthesize only its assigned output + file, run the traceability self-check, write the file, and return only + after the file is written. + + - Agent for `docs/specs/prd-.md`: ask it specifically + to synthesize the PRD from the Q1 branch of the Question Tree, + covering problem statement, target users, goals, success criteria, + scope boundaries, constraints, and open questions. + + - Agent for `docs/specs/use-cases-.md`: ask it + specifically to synthesize the use-case spec from the Q2 branch + using Cockburn Fully Dressed format. Include Persona Use Cases + (user-goal level: actor, trigger, stakeholders & interests, + preconditions, main success scenario, extensions, postconditions, + business rules), System Use Cases per technical interface (input + + validation, processing, output + status codes, error responses), and + Supplementary Specifications (entity model, state machines, interface + contracts, validation rules). Add Gherkin acceptance criteria where + applicable. + + - Agent for `docs/arc42/arc42-.md`: ask it specifically + to synthesize all 12 arc42 chapters from the Q3 branch. Mark + chapters with no content as "No information" rather than fabricating + content. Chapter 10 (Quality Requirements) is an exception: + synthesize it from the answered Q4 quality scenarios plus the Q4.9 + ranking — reuse evidence already cited in Q3.8 (security scenarios + cite STRIDE T-IDs, maintainability scenarios the test concept). Only + the quality-goal ranking stays as a gap if Q4.9 was deferred. + + - Agent for `docs/specs/adrs/-adr-NNN-*.md`: ask it + specifically to synthesize one ADR file per significant design + decision from the Q3.9 branch. Use Nygard format (Title, Status, + Context, Decision, Consequences) and include a Pugh Matrix scoring + alternatives against Q4 quality goals on a -1 / 0 / +1 scale. + + **Traceability rules (give these to every agent):** + + ``` + Every claim in the output must trace to a leaf in the Question Tree. + Q-IDs must NOT appear in the output documents. + + - A claim from an [ANSWERED] leaf: cite the code evidence verbatim from + that leaf — e.g. "The system uses Hexagonal Architecture + [src/app/Ports.java, src/adapter/JpaOrderRepository.java:30]." Copy + the Evidence line exactly; do not invent, shorten, or re-derive paths. + A leaf with no Evidence line is not [ANSWERED] and must not be cited. + + - A claim from a team answer: mark it (team answer) — e.g. "Sessions + expire after 24 hours (team answer)." + + - A deferred item: keep it as an explicit gap — e.g. "Quality-goal + priorities are deferred and must be resolved before the next release." + + Do not introduce facts that do not appear in the Question Tree or + OPEN_QUESTIONS file. If a section feels under-specified, leave it + under-specified — that is signal, not a defect. + + Before returning, self-check: no Q-IDs in output, every code-derived + claim has a file:line citation, every deferred item is labelled. + ``` + + **STEP 3 — Verify the four artifacts.** + + After all agents return, confirm: + 1. `docs/specs/prd-.md` — problem, users, success + criteria, scope. + 2. `docs/specs/use-cases-.md` — Cockburn Fully Dressed + persona use cases + system use cases per interface. + 3. `docs/arc42/arc42-.md` — all 12 chapters (gaps + marked, not invented; Chapter 10 synthesized from Q4 scenarios). + 4. `docs/specs/adrs/-adr-NNN-*.md` — one Nygard ADR + with Pugh Matrix per Q3.9 decision. + + transitions: + - trigger: 'synthesis_complete' + to: 'review_and_rework' + transition_reason: >- + All four output documents produced and verified. Ready for + independent review. + additional_instructions: | + **IMPORTANT — Independent Review Session** + + The review in the next state should run in a fresh LLM session with + no memory of the synthesis session. A model that wrote the + documentation will miss its own errors. + + Hand the reviewer: + - `docs/specs/prd-.md` + - `docs/specs/use-cases-.md` + - `docs/arc42/arc42-.md` + - `docs/specs/adrs/-adr-NNN-*.md` + - `QUESTION_TREE-.md` (for traceability checking) + - `OPEN_QUESTIONS-.md` (for gap verification) + + review_and_rework: + description: >- + Independent review of the four synthesized documents — Fagan Inspection, + Traceability Check, and ATAM. Should run in a fresh session (different + model ideally). Fix confirmed defects only; leave (deferred) gaps as + gaps. Review results written to docs/reports/. + allowed_file_patterns: + - 'docs/reports/*.md' + - 'docs/specs/prd-*.md' + - 'docs/specs/use-cases-*.md' + - 'docs/arc42/arc42-*.md' + - 'docs/specs/adrs/*.md' + default_instructions: > + **IMPORTANT: This state should run in a fresh LLM session.** + + If you have memory of writing the documents you are about to review, + stop and tell the user: "I wrote these documents — review in this + session would be biased. Please start a new session for the review." + + **STEP 1 — Run the three review passes in parallel.** + + Delegate each pass to a separate agent. Ask each agent specifically to + read the six input files listed in its prompt, perform its assigned + review, write its report file, and return only after the report is + written. + + Input files for all agents (substitute ): + - `docs/specs/prd-.md` + - `docs/specs/use-cases-.md` + - `docs/arc42/arc42-.md` + - `docs/specs/adrs/-adr-NNN-*.md` (all ADRs) + - `QUESTION_TREE-.md` + - `OPEN_QUESTIONS-.md` + + **Agent prompt for Fagan Inspection:** + + ``` + Read the six input files listed above. Evaluate each of the four + synthesis documents against: + - Completeness: every required section present? ("No information" is + acceptable; blank or missing sections are defects.) + - Clarity: ambiguous statements, undefined terms? + - Consistency: contradictions across documents? + - Verifiability: claims stated in a testable or confirmable way? + Log each defect with document + section, severity (Major / Minor), and + description. Write all defects to + `docs/reports/fagan-inspection-.md`. Return only after + the file is written. + ``` + + **Agent prompt for Traceability Check:** + + ``` + Read the six input files listed above. For every code-derived claim in + the four synthesis documents, verify that the cited file:line exists and + contains the claimed fact. Verify that all team-supplied facts are marked + (team answer). List any uncited or wrongly-cited claims as defects. Write + all findings to `docs/reports/traceability-.md`. Return + only after the file is written. + ``` + + **Agent prompt for ATAM:** + + ``` + Read the six input files listed above. Read Chapter 10 (Quality + Requirements) of the arc42 document and each ADR's Pugh Matrix. + Evaluate whether the ADR trade-offs actually address the quality goals in + Chapter 10. If the quality-goal ranking (Q4.9) was marked (deferred), + mark the entire ATAM result as provisional — the ranking is assumed, not + confirmed. Write results to `docs/reports/atam-.md`. + Return only after the file is written. + ``` + + **STEP 2 — Fix confirmed defects.** + + - Fix defects that have wrong content or missing citations in the + source documents. + - Fixing means correcting a wrong fact or adding a missing citation — + not filling in a gap with speculation. + - `(deferred)` gaps are not defects. Do not fill them. + + **STEP 3 — Write review summary.** + + Write `docs/reports/review-summary-.md` with: + - Total defects found (major / minor) + - Total defects fixed + - Remaining (deferred) gaps and their significance + - Overall quality assessment + - Recommended next steps + + transitions: + - trigger: 'fix_defects' + to: 'review_and_rework' + transition_reason: >- + Defects found in review. Applying fixes and re-reviewing the + affected documents. + + - trigger: 'recovery_complete' + to: 'recovery_done' + transition_reason: >- + Review clean — all defects resolved or confirmed as intentional gaps. + Recovery is complete. + + recovery_done: + description: >- + Recovery complete. Four documentation artifacts produced (PRD, use-case + spec, arc42, ADRs) plus review reports. OPEN_QUESTIONS is the living + gap register. + default_instructions: > + Present the following summary to the user. + + **Deliverables:** + + - `docs/specs/prd-.md` — Product Requirements Document + - `docs/specs/use-cases-.md` — Cockburn Fully Dressed + use-case specification + system interface specs + - `docs/arc42/arc42-.md` — arc42 architecture + documentation (all 12 chapters) + - `docs/specs/adrs/-adr-NNN-*.md` — Nygard ADRs with + Pugh Matrices + - `docs/reports/fagan-inspection-.md` — inspection log + - `docs/reports/atam-.md` — ATAM results + - `docs/reports/review-summary-.md` — review summary + + **Living gap register:** + + `OPEN_QUESTIONS-.md` lists everything that could not be + recovered from code alone and was deferred by the team. Revisit it at + each release. + + **Spec drift — do this before every release:** + + Re-run the `question_tree` state against the current codebase and diff + the new `QUESTION_TREE-.md` against the existing docs: + - **NEW**: present in code, not yet in spec + - **CHANGED**: spec and code have diverged + - **DEAD**: in spec, but no longer in code + + **Next bounded context:** + + Only start the next bounded context when this one's documentation is + actively being used. Breadth-first recovery across a whole system + produces shallow trees everywhere — depth on one context first. + + $DONE_DEFAULT + transitions: [] diff --git a/resources/workflows/tdd.yaml b/resources/workflows/tdd.yaml index 74bbd37e..fb27289c 100644 --- a/resources/workflows/tdd.yaml +++ b/resources/workflows/tdd.yaml @@ -84,11 +84,6 @@ states: to: 'explore' transition_reason: 'Test writing revealed need for more exploration' - - trigger: 'abandon_feature' - to: 'explore' - additional_instructions: 'Clean up any test artifacts and prepare for new tasks.' - transition_reason: 'User decided to abandon feature during test phase' - green: description: 'GREEN phase - Write only the necessary code to make the test pass' required_capability: 'coding' @@ -126,11 +121,6 @@ states: to: 'explore' transition_reason: 'Implementation work revealed need for more exploration' - - trigger: 'abandon_feature' - to: 'explore' - additional_instructions: 'Clean up any incomplete code and prepare for new tasks.' - transition_reason: 'User decided to abandon feature during implementation' - refactor: description: 'REFACTOR phase - Improve code quality while keeping tests green (cleanup phase)' allowed_file_patterns: @@ -169,11 +159,6 @@ states: additional_instructions: 'Update task progress to reflect feature completion.' transition_reason: 'Feature fully implemented and cleaned up, ready to exit TDD cycle' - - trigger: 'abandon_feature' - to: 'explore' - additional_instructions: 'Clean up any refactoring work and prepare for new tasks.' - transition_reason: 'User decided to abandon feature during refactoring' - done: description: 'TDD cycle complete - feature fully implemented and cleaned up' allowed_file_patterns: