From 96f1b254f6da3e89e856d1d55c5bce6b690a941e Mon Sep 17 00:00:00 2001 From: palucdev Date: Sun, 14 Jun 2026 08:33:19 +0200 Subject: [PATCH 1/2] Templates moved into /templates directory --- scripts/copy-markdowns.js | 6 ++ src/commands/quick-dev.md | 15 +-- src/commands/quick-plan.md | 16 +--- src/index.ts | 4 + src/skills/development/SKILL.md | 44 +-------- src/skills/migration/SKILL.md | 34 +------ .../references/orchestrator-patterns.md | 62 +----------- src/skills/performance/SKILL.md | 31 +----- src/skills/product-design/SKILL.md | 43 +-------- src/skills/quick-bugfix/SKILL.md | 15 +-- src/skills/research/SKILL.md | 44 +-------- src/templates/orchestrator-state-base.yml | 17 ++++ .../orchestrator-state-development.yml | 95 +++++++++++++++++++ .../orchestrator-state-migration.yml | 55 +++++++++++ .../orchestrator-state-performance.yml | 53 +++++++++++ .../orchestrator-state-product-design.yml | 65 +++++++++++++ src/templates/orchestrator-state-research.yml | 61 ++++++++++++ src/templates/quick-bugfix-task.yml | 10 ++ src/templates/quick-dev-task.yml | 10 ++ src/templates/quick-plan-task.yml | 11 +++ src/tools/verify_template.ts | 75 +++++++++++++++ 21 files changed, 474 insertions(+), 292 deletions(-) create mode 100644 src/templates/orchestrator-state-base.yml create mode 100644 src/templates/orchestrator-state-development.yml create mode 100644 src/templates/orchestrator-state-migration.yml create mode 100644 src/templates/orchestrator-state-performance.yml create mode 100644 src/templates/orchestrator-state-product-design.yml create mode 100644 src/templates/orchestrator-state-research.yml create mode 100644 src/templates/quick-bugfix-task.yml create mode 100644 src/templates/quick-dev-task.yml create mode 100644 src/templates/quick-plan-task.yml create mode 100644 src/tools/verify_template.ts diff --git a/scripts/copy-markdowns.js b/scripts/copy-markdowns.js index 27a8dc8..d011b8f 100644 --- a/scripts/copy-markdowns.js +++ b/scripts/copy-markdowns.js @@ -14,3 +14,9 @@ console.log("Copied agents to dist/"); fs.cpSync("src/commands", "dist/commands", { recursive: true }); console.log("Copied commands to dist/"); + +// Copy the 'templates' folder recursively into 'dist/templates' +fs.cpSync("src/templates", "dist/templates", { recursive: true }); + +console.log("Copied templates to dist/"); + diff --git a/src/commands/quick-dev.md b/src/commands/quick-dev.md index 5f43af0..cccac72 100644 --- a/src/commands/quick-dev.md +++ b/src/commands/quick-dev.md @@ -62,20 +62,7 @@ Implement a task directly without entering planning mode, while still applying p - Prepend today's date: `YYYY-MM-DD-kebab-name` - Examples: "Add a logout button to the navbar" → `2026-05-28-add-navbar-logout-button`, "Update the API endpoint to accept JSON" → `2026-05-28-update-api-accept-json` 2. Create directory: `.owflow/tasks/quick-dev/YYYY-MM-DD-task-name/` -3. Write `task.yml` with initial state: - -```yaml -command: quick-dev -title: "Short title from task description" -description: "Full task description as provided by user" -status: in_progress -created: "YYYY-MM-DDTHH:MM:SSZ" -updated: "YYYY-MM-DDTHH:MM:SSZ" -task_path: .owflow/tasks/quick-dev/YYYY-MM-DD-task-name -escalated_to: null -escalation_reason: null -standards_applied: [] -``` +3. Write `task.yml` with initial state using the template [src/templates/quick-dev-task.yml](../templates/quick-dev-task.yml). ### Step 2: Discover Standards diff --git a/src/commands/quick-plan.md b/src/commands/quick-plan.md index 8365aa9..08a9226 100644 --- a/src/commands/quick-plan.md +++ b/src/commands/quick-plan.md @@ -45,21 +45,7 @@ Enter OpenCode's planning mode for a task, with automatic discovery of project s - Examples: "Add retry logic to API client" → `2026-05-28-add-api-retry-logic`, "Refactor the payment processing module" → `2026-05-28-refactor-payment-module` 2. Create directory: `.owflow/tasks/quick-plan/YYYY-MM-DD-task-name/` 3. Create `analysis/` subdirectory inside it -4. Write `task.yml` with initial state: - -```yaml -command: quick-plan -title: "Short title from task description" -description: "Full task description as provided by user" -status: in_progress -created: "YYYY-MM-DDTHH:MM:SSZ" -updated: "YYYY-MM-DDTHH:MM:SSZ" -task_path: .owflow/tasks/quick-plan/YYYY-MM-DD-task-name -escalated_to: null -escalation_reason: null -standards_applied: [] -plan_path: null -``` +4. Write `task.yml` with initial state using the template [src/templates/quick-plan-task.yml](../templates/quick-plan-task.yml). ### Step 2: Discover and Read Standards (BEFORE Plan Mode) diff --git a/src/index.ts b/src/index.ts index 7d888e0..0e9f70e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ import fs from "node:fs"; import { fileURLToPath } from "url"; import type { OpenCodeConfig } from "./types/opencode-types"; import matter from "gray-matter"; +import { verify_template } from "./tools/verify_template"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const PLUGIN_ROOT = __dirname; // Points to dist/ where skills/commands/agents are copied @@ -92,6 +93,9 @@ const prepareAgent = ( const OwflowPlugin: Plugin = async ({ $, directory }) => { const agentBySession = new Map(); return { + tool: { + verify_template, + }, /** * Register owflow's skills, commands, and agents so OpenCode discovers * them without requiring manual config file edits. diff --git a/src/skills/development/SKILL.md b/src/skills/development/SKILL.md index 9d79fdf..f1d28d7 100644 --- a/src/skills/development/SKILL.md +++ b/src/skills/development/SKILL.md @@ -548,49 +548,7 @@ question - "Documentation complete. Continue to Phase 14?" Development-specific fields in `orchestrator-state.yml`: -```yaml -orchestrator: - options: - spec_audit_enabled: true - skip_test_suite: true - e2e_enabled: null - user_docs_enabled: null - code_review_enabled: true - pragmatic_review_enabled: true - reality_check_enabled: true - production_check_enabled: true - task_context: - risk_level: null - clarifications_resolved: null - scope_expanded: null - architecture_decision: null - task_characteristics: - has_reproducible_defect: false - modifies_existing_code: false - creates_new_entities: false - involves_data_operations: false - ui_heavy: false - research_reference: - path: null - research_question: null - research_type: null - confidence_level: null - quick_reference: - path: null - command: null # quick-bugfix | quick-plan | quick-dev - escalation_reason: null - phase_summaries: - research: { summary: null, key_findings: [], recommended_approach: null } - quick_analysis: { summary: null, affected_files: [], root_cause: null } - codebase_analysis: - { key_files: [], primary_language: null, summary: null } - clarifications: [] - gap_analysis: { integration_points: [], summary: null } - scope_clarifications: { scope_expanded: null, summary: null } - ui_mockups: { components_designed: [], summary: null } - specification: { summary: null } - architecture_decision: { decision: null, summary: null } -``` +Refer to the template [src/templates/orchestrator-state-development.yml](../../templates/orchestrator-state-development.yml). --- diff --git a/src/skills/migration/SKILL.md b/src/skills/migration/SKILL.md index 7838e45..18ebc4a 100644 --- a/src/skills/migration/SKILL.md +++ b/src/skills/migration/SKILL.md @@ -308,39 +308,7 @@ question - Display executive summary: total issues found, issues fixed, issues r Migration-specific fields in `orchestrator-state.yml`: -```yaml -migration_context: - migration_type: "code" | "data" | "architecture" | "general" - current_system: - description: null - technologies: [] - target_system: - description: null - technologies: [] - migration_strategy: - approach: "incremental" | "big-bang" | "dual-run" | "phased" - phases: [] - risk_level: null - breaking_changes: [] - rollback_plan_created: false - dual_run_configured: false - -external_research: - performed: false - category: null - breaking_changes: [] - migration_guide_url: null - -verification_context: - last_status: null - issues_found: null - fixes_applied: [] - decisions_made: [] - reverify_count: 0 - -options: - docs_enabled: false -``` +Refer to the template [src/templates/orchestrator-state-migration.yml](../../templates/orchestrator-state-migration.yml). --- diff --git a/src/skills/orchestrator-framework/references/orchestrator-patterns.md b/src/skills/orchestrator-framework/references/orchestrator-patterns.md index b6b8250..3720bd8 100644 --- a/src/skills/orchestrator-framework/references/orchestrator-patterns.md +++ b/src/skills/orchestrator-framework/references/orchestrator-patterns.md @@ -163,42 +163,7 @@ All orchestrators use `orchestrator-state.yml` at `.owflow/tasks/[type]/YYYY-MM- ### Common Fields -```yaml -orchestrator: - # Phase tracking - started_phase: [phase-name] - completed_phases: [] - failed_phases: [] - - # Auto-fix tracking (per phase) - auto_fix_attempts: - phase-1: 0 - phase-2: 0 - - # Optional phase flags - options: - e2e_enabled: true | false | null - user_docs_enabled: true | false | null - code_review_enabled: true | false | null - - # Timestamps - created: [ISO 8601 timestamp] - updated: [ISO 8601 timestamp] - task_path: .owflow/tasks/[type]/YYYY-MM-DD-task-name - - # Task tracking IDs (maps phase names to TaskCreate IDs) - task_ids: - phase-1: null - phase-2: null - -# Task metadata -task: - title: [human-readable task title] - description: [full task description] - status: pending | in_progress | completed | failed | blocked - tags: [] - priority: null # high | medium | low -``` +Refer to the template [src/templates/orchestrator-state-base.yml](../../../templates/orchestrator-state-base.yml). ### Extension Pattern @@ -217,21 +182,7 @@ See each orchestrator's SKILL.md "Domain Context" section for full schema. When development starts from completed research (`--research` flag): -```yaml -task_context: - research_reference: - path: null - research_question: null - research_type: null # technical | requirements | literature | mixed - confidence_level: null # high | medium | low - - phase_summaries: - research: - summary: null - key_findings: [] - recommended_approach: null - decisions_made: [] -``` +Refer to `research_reference` in the template [src/templates/orchestrator-state-development.yml](../../../templates/orchestrator-state-development.yml). Research context flows to ALL phases via context passing. Artifacts are also copied to `analysis/research-context/`. @@ -239,14 +190,7 @@ Research context flows to ALL phases via context passing. Artifacts are also cop All orchestrators with verification phases use: -```yaml -verification_context: - last_status: passed | passed_with_issues | failed | null - issues_found: [] - fixes_applied: [] - decisions_made: [] - reverify_count: 0 # max 3 -``` +Refer to `verification_context` in the template [src/templates/orchestrator-state-base.yml](../../../templates/orchestrator-state-base.yml) or domain templates. --- diff --git a/src/skills/performance/SKILL.md b/src/skills/performance/SKILL.md index 4d71667..53c0597 100644 --- a/src/skills/performance/SKILL.md +++ b/src/skills/performance/SKILL.md @@ -353,36 +353,7 @@ question - Display executive summary: total issues found, issues fixed, issues r Performance-specific fields in `orchestrator-state.yml`: -```yaml -performance_context: - bottlenecks_identified: null # count from bottleneck-analyzer - user_data_available: false # whether user provided profiling data - bottleneck_priorities: - p0: 0 - p1: 0 - p2: 0 - p3: 0 - phase_summaries: - codebase_analysis: { key_files: [], summary: null } - bottleneck_analysis: - { bottlenecks: [], summary: null, user_data_incorporated: false } - specification: { summary: null } - -verification_context: - last_status: null - issues_found: null - fixes_applied: [] - decisions_made: [] - reverify_count: 0 - -options: - spec_audit_enabled: null - skip_test_suite: true - code_review_enabled: true - pragmatic_review_enabled: true - reality_check_enabled: true - production_check_enabled: null -``` +Refer to the template [src/templates/orchestrator-state-performance.yml](../../templates/orchestrator-state-performance.yml). --- diff --git a/src/skills/product-design/SKILL.md b/src/skills/product-design/SKILL.md index 3c2ad40..373419c 100644 --- a/src/skills/product-design/SKILL.md +++ b/src/skills/product-design/SKILL.md @@ -715,48 +715,7 @@ To start development based on this design, clear context first or start a new se Product-design-specific fields in `orchestrator-state.yml`: -```yaml -design_context: - design_characteristics: - is_greenfield: false - is_enhancement: false - is_ui_focused: false - is_backend: false - is_complex: false - is_simple: false - complexity_level: "standard" # "simple" | "standard" | "complex" - collected_urls: [] - research_topics: [] - user_files_list: [] - refinement_iterations: - phase_2: 0 - phase_3: 0 - phase_5: 0 - phase_6_sections: {} # per-section tracking: {problem_statement: 1, features: 0, ...} - phase_7: 0 - visual_companion: - available: null # null=not yet checked, true/false after check - port: null - pid: null - fallback_to_ascii: false - research_reference: - path: null - research_question: null - phase_summaries: - context_synthesis: { summary: null, sources_count: 0 } - problem_exploration: - { problem_statement: null, constraints: [], success_criteria: [] } - persona_exploration: { personas: [], user_journeys: [] } - idea_generation: { alternatives_count: 0, summary: null } - idea_convergence: - { selected_approach: null, trade_offs_accepted: [], key_decisions: [] } - feature_specification: { spec_sections: {}, sections_count: 0 } - visual_prototyping: { mockup_references: [], summary: null } - review_handoff: { brief_layers: [], summary: null } - -options: - visual_enabled: null # null=auto-detect, false=--no-visual flag -``` +Refer to the template [src/templates/orchestrator-state-product-design.yml](../../templates/orchestrator-state-product-design.yml). --- diff --git a/src/skills/quick-bugfix/SKILL.md b/src/skills/quick-bugfix/SKILL.md index 045f247..fb8c0eb 100644 --- a/src/skills/quick-bugfix/SKILL.md +++ b/src/skills/quick-bugfix/SKILL.md @@ -58,20 +58,7 @@ For complex bugs that grow beyond a quick fix, suggests escalating to the full d - Examples: "Fix login timeout bug" → `2026-05-28-fix-login-timeout`, "Login form submits twice on slow connections" → `2026-05-28-login-double-submit` 2. Create directory: `.owflow/tasks/quick-bugfix/YYYY-MM-DD-task-name/` 3. Create `analysis/` subdirectory inside it -4. Write `task.yml` with initial state: - -```yaml -command: quick-bugfix -title: "Short title from bug description" -description: "Full bug description as provided by user" -status: in_progress -created: "YYYY-MM-DDTHH:MM:SSZ" -updated: "YYYY-MM-DDTHH:MM:SSZ" -task_path: .owflow/tasks/quick-bugfix/YYYY-MM-DD-task-name -escalated_to: null -escalation_reason: null -standards_applied: [] -``` +4. Write `task.yml` with initial state using the template [src/templates/quick-bugfix-task.yml](../../templates/quick-bugfix-task.yml). ### Step 3: Discover Standards diff --git a/src/skills/research/SKILL.md b/src/skills/research/SKILL.md index aedef85..f81879a 100644 --- a/src/skills/research/SKILL.md +++ b/src/skills/research/SKILL.md @@ -369,40 +369,7 @@ question - "Design complete. Continue to output generation?" Research-specific fields in `orchestrator-state.yml`: -```yaml -research_context: - research_type: "technical" | "requirements" | "literature" | "mixed" - research_question: "[user's question]" - scope: - included: [] - excluded: [] - constraints: [] - methodology: [] - sources: [] - confidence_level: "high" | "medium" | "low" - gathering_strategy: - categories: [] # e.g., ["codebase", "documentation", "external-apis"] - count: 4 # number of gatherer instances - source: "planner" | "default" # where strategy came from - phase_summaries: - phase-1: - summary: "..." - steps_completed: [] # track which steps completed for resume - phase-3: - summary: "..." - phase-4: - summary: "..." - decision_areas: [] # list of {area, alternatives_count, chosen_approach} - deferred_ideas: [] - phase-5: - summary: "..." - architecture_style: null - decisions_count: 0 - -options: - brainstorming_enabled: null # null=not yet decided, set by Phase 2 or --brainstorm/--no-brainstorm flag - design_enabled: null # independent, set by Phase 2 or --design/--no-design flag -``` +Refer to the template [src/templates/orchestrator-state-research.yml](../../templates/orchestrator-state-research.yml). --- @@ -468,14 +435,7 @@ options: **Handoff**: -```yaml -research_outputs: - research_report: "[path to outputs/research-report.md]" - findings_directory: "[path to analysis/findings/]" - solution_exploration: "[path to outputs/solution-exploration.md]" - high_level_design: "[path to outputs/high-level-design.md]" - decision_log: "[path to outputs/decision-log.md]" -``` +Refer to `research_outputs` in the template [src/templates/orchestrator-state-research.yml](../../templates/orchestrator-state-research.yml). --- diff --git a/src/templates/orchestrator-state-base.yml b/src/templates/orchestrator-state-base.yml new file mode 100644 index 0000000..00de179 --- /dev/null +++ b/src/templates/orchestrator-state-base.yml @@ -0,0 +1,17 @@ +orchestrator: + started_phase: null + completed_phases: [] + failed_phases: [] + auto_fix_attempts: {} + options: {} + created: "YYYY-MM-DDTHH:MM:SSZ" + updated: "YYYY-MM-DDTHH:MM:SSZ" + task_path: null + task_ids: {} + +task: + title: null + description: null + status: pending + tags: [] + priority: null diff --git a/src/templates/orchestrator-state-development.yml b/src/templates/orchestrator-state-development.yml new file mode 100644 index 0000000..f7e31a2 --- /dev/null +++ b/src/templates/orchestrator-state-development.yml @@ -0,0 +1,95 @@ +orchestrator: + started_phase: null + completed_phases: [] + failed_phases: [] + auto_fix_attempts: + phase-1: 0 + phase-2: 0 + phase-3: 0 + phase-4: 0 + phase-5: 0 + phase-6: 0 + phase-7: 0 + phase-8: 0 + phase-9: 0 + phase-10: 0 + phase-11: 0 + phase-12: 0 + phase-13: 0 + phase-14: 0 + options: + spec_audit_enabled: true + skip_test_suite: true + e2e_enabled: null + user_docs_enabled: null + code_review_enabled: true + pragmatic_review_enabled: true + reality_check_enabled: true + production_check_enabled: true + created: "YYYY-MM-DDTHH:MM:SSZ" + updated: "YYYY-MM-DDTHH:MM:SSZ" + task_path: null + task_ids: {} + +task: + title: null + description: null + status: pending + tags: [] + priority: null + +task_context: + risk_level: null + clarifications_resolved: null + scope_expanded: null + architecture_decision: null + task_characteristics: + has_reproducible_defect: false + modifies_existing_code: false + creates_new_entities: false + involves_data_operations: false + ui_heavy: false + user_journey: + reachability: null + persona_impact: null + flow_integration: null + navigation_consistency: null + discoverability_before: null + discoverability_after: null + data_lifecycle: + three_layer_framework: null + backend_user_operability: null + orphaned_display_detected: null + orphaned_input_detected: null + layer_3_critical_checks: null + multi_touchpoint_discovery: null + crud_completeness: null + scope_expansion_recommended: null + safety_critical_awareness: null + gaps: [] + research_reference: + path: null + research_question: null + research_type: null + confidence_level: null + quick_reference: + path: null + command: null + escalation_reason: null + phase_summaries: + research: { summary: null, key_findings: [], recommended_approach: null } + quick_analysis: { summary: null, affected_files: [], root_cause: null } + codebase_analysis: { key_files: [], primary_language: null, summary: null } + clarifications: [] + gap_analysis: { integration_points: [], summary: null } + scope_clarifications: { scope_expanded: null, summary: null } + ui_mockups: { components_designed: [], summary: null } + specification: { summary: null } + architecture_decision: { decision: null, summary: null } + +verification_context: + last_status: null + issues_found: [] + fixes_applied: [] + decisions_made: [] + reverify_count: 0 diff --git a/src/templates/orchestrator-state-migration.yml b/src/templates/orchestrator-state-migration.yml new file mode 100644 index 0000000..d311d5b --- /dev/null +++ b/src/templates/orchestrator-state-migration.yml @@ -0,0 +1,55 @@ +orchestrator: + started_phase: null + completed_phases: [] + failed_phases: [] + auto_fix_attempts: + phase-1: 0 + phase-2: 0 + phase-3: 0 + phase-4: 0 + phase-5: 0 + phase-6: 0 + phase-7: 0 + phase-8: 0 + options: + docs_enabled: false + created: "YYYY-MM-DDTHH:MM:SSZ" + updated: "YYYY-MM-DDTHH:MM:SSZ" + task_path: null + task_ids: {} + +task: + title: null + description: null + status: pending + tags: [] + priority: null + +migration_context: + migration_type: "code" | "data" | "architecture" | "general" + current_system: + description: null + technologies: [] + target_system: + description: null + technologies: [] + migration_strategy: + approach: "incremental" | "big-bang" | "dual-run" | "phased" + phases: [] + risk_level: null + breaking_changes: [] + rollback_plan_created: false + dual_run_configured: false + +external_research: + performed: false + category: null + breaking_changes: [] + migration_guide_url: null + +verification_context: + last_status: null + issues_found: null + fixes_applied: [] + decisions_made: [] + reverify_count: 0 diff --git a/src/templates/orchestrator-state-performance.yml b/src/templates/orchestrator-state-performance.yml new file mode 100644 index 0000000..0199de0 --- /dev/null +++ b/src/templates/orchestrator-state-performance.yml @@ -0,0 +1,53 @@ +orchestrator: + started_phase: null + completed_phases: [] + failed_phases: [] + auto_fix_attempts: + phase-1: 0 + phase-2: 0 + phase-3: 0 + phase-4: 0 + phase-5: 0 + phase-6: 0 + phase-7: 0 + phase-8: 0 + phase-9: 0 + options: + spec_audit_enabled: null + skip_test_suite: true + code_review_enabled: true + pragmatic_review_enabled: true + reality_check_enabled: true + production_check_enabled: null + created: "YYYY-MM-DDTHH:MM:SSZ" + updated: "YYYY-MM-DDTHH:MM:SSZ" + task_path: null + task_ids: {} + +task: + title: null + description: null + status: pending + tags: [] + priority: null + +performance_context: + bottlenecks_identified: null + user_data_available: false + bottleneck_priorities: + p0: 0 + p1: 0 + p2: 0 + p3: 0 + phase_summaries: + codebase_analysis: { key_files: [], summary: null } + bottleneck_analysis: + { bottlenecks: [], summary: null, user_data_incorporated: false } + specification: { summary: null } + +verification_context: + last_status: null + issues_found: null + fixes_applied: [] + decisions_made: [] + reverify_count: 0 diff --git a/src/templates/orchestrator-state-product-design.yml b/src/templates/orchestrator-state-product-design.yml new file mode 100644 index 0000000..44d23c2 --- /dev/null +++ b/src/templates/orchestrator-state-product-design.yml @@ -0,0 +1,65 @@ +orchestrator: + started_phase: null + completed_phases: [] + failed_phases: [] + auto_fix_attempts: + phase-0: 0 + phase-1: 0 + phase-2: 0 + phase-3: 0 + phase-4: 0 + phase-5: 0 + phase-6: 0 + phase-7: 0 + phase-8: 0 + options: + visual_enabled: null + created: "YYYY-MM-DDTHH:MM:SSZ" + updated: "YYYY-MM-DDTHH:MM:SSZ" + task_path: null + task_ids: {} + +task: + title: null + description: null + status: pending + tags: [] + priority: null + +design_context: + design_characteristics: + is_greenfield: false + is_enhancement: false + is_ui_focused: false + is_backend: false + is_complex: false + is_simple: false + complexity_level: "standard" + collected_urls: [] + research_topics: [] + user_files_list: [] + refinement_iterations: + phase_2: 0 + phase_3: 0 + phase_5: 0 + phase_6_sections: {} + phase_7: 0 + visual_companion: + available: null + port: null + pid: null + fallback_to_ascii: false + research_reference: + path: null + research_question: null + phase_summaries: + context_synthesis: { summary: null, sources_count: 0 } + problem_exploration: + { problem_statement: null, constraints: [], success_criteria: [] } + persona_exploration: { personas: [], user_journeys: [] } + idea_generation: { alternatives_count: 0, summary: null } + idea_convergence: + { selected_approach: null, trade_offs_accepted: [], key_decisions: [] } + feature_specification: { spec_sections: {}, sections_count: 0 } + visual_prototyping: { mockup_references: [], summary: null } + review_handoff: { brief_layers: [], summary: null } diff --git a/src/templates/orchestrator-state-research.yml b/src/templates/orchestrator-state-research.yml new file mode 100644 index 0000000..3c6aa4b --- /dev/null +++ b/src/templates/orchestrator-state-research.yml @@ -0,0 +1,61 @@ +orchestrator: + started_phase: null + completed_phases: [] + failed_phases: [] + auto_fix_attempts: + phase-1: 0 + phase-2: 0 + phase-3: 0 + phase-4: 0 + phase-5: 0 + phase-6: 0 + options: + brainstorming_enabled: null + design_enabled: null + created: "YYYY-MM-DDTHH:MM:SSZ" + updated: "YYYY-MM-DDTHH:MM:SSZ" + task_path: null + task_ids: {} + +task: + title: null + description: null + status: pending + tags: [] + priority: null + +research_context: + research_type: "technical" | "requirements" | "literature" | "mixed" + research_question: null + scope: + included: [] + excluded: [] + constraints: [] + methodology: [] + sources: [] + confidence_level: "high" | "medium" | "low" + gathering_strategy: + categories: [] + count: 0 + source: "planner" | "default" + phase_summaries: + phase-1: + summary: null + steps_completed: [] + phase-3: + summary: null + phase-4: + summary: null + decision_areas: [] + deferred_ideas: [] + phase-5: + summary: null + architecture_style: null + decisions_count: 0 + +research_outputs: + research_report: null + findings_directory: null + solution_exploration: null + high_level_design: null + decision_log: null diff --git a/src/templates/quick-bugfix-task.yml b/src/templates/quick-bugfix-task.yml new file mode 100644 index 0000000..5dc4632 --- /dev/null +++ b/src/templates/quick-bugfix-task.yml @@ -0,0 +1,10 @@ +command: quick-bugfix +title: "Short title from bug description" +description: "Full bug description as provided by user" +status: in_progress +created: "YYYY-MM-DDTHH:MM:SSZ" +updated: "YYYY-MM-DDTHH:MM:SSZ" +task_path: .owflow/tasks/quick-bugfix/YYYY-MM-DD-task-name +escalated_to: null +escalation_reason: null +standards_applied: [] diff --git a/src/templates/quick-dev-task.yml b/src/templates/quick-dev-task.yml new file mode 100644 index 0000000..6d387fb --- /dev/null +++ b/src/templates/quick-dev-task.yml @@ -0,0 +1,10 @@ +command: quick-dev +title: "Short title from task description" +description: "Full task description as provided by user" +status: in_progress +created: "YYYY-MM-DDTHH:MM:SSZ" +updated: "YYYY-MM-DDTHH:MM:SSZ" +task_path: .owflow/tasks/quick-dev/YYYY-MM-DD-task-name +escalated_to: null +escalation_reason: null +standards_applied: [] diff --git a/src/templates/quick-plan-task.yml b/src/templates/quick-plan-task.yml new file mode 100644 index 0000000..53cdef3 --- /dev/null +++ b/src/templates/quick-plan-task.yml @@ -0,0 +1,11 @@ +command: quick-plan +title: "Short title from task description" +description: "Full task description as provided by user" +status: in_progress +created: "YYYY-MM-DDTHH:MM:SSZ" +updated: "YYYY-MM-DDTHH:MM:SSZ" +task_path: .owflow/tasks/quick-plan/YYYY-MM-DD-task-name +escalated_to: null +escalation_reason: null +standards_applied: [] +plan_path: null diff --git a/src/tools/verify_template.ts b/src/tools/verify_template.ts new file mode 100644 index 0000000..ed0678f --- /dev/null +++ b/src/tools/verify_template.ts @@ -0,0 +1,75 @@ +import { tool } from "@opencode-ai/plugin"; +import fs from "node:fs"; +import path from "node:path"; +import yaml from "yaml"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export const verify_template = tool({ + description: "Check if file in the given path exists and follows correct YAML structure by checking against the template file from /templates.", + args: { + filePath: tool.schema.string().describe("Path to the file to check"), + templateName: tool.schema.string().describe("Name of the template from /templates (e.g. orchestrator-state-development.yml)"), + }, + async execute({ filePath, templateName }, context) { + const absolutePath = path.resolve(context.directory, filePath); + + if (!fs.existsSync(absolutePath)) { + return { output: `File not found at ${filePath}. Hint: Double-check the path, create the file if it's missing, or verify you are in the correct directory.` }; + } + + const templatePath = path.join(__dirname, "../templates", templateName); + + if (!fs.existsSync(templatePath)) { + return { output: `Template '${templateName}' not found. Hint: Verify the template name is correct and exists in the /templates folder (e.g., 'orchestrator-state-development.yml').` }; + } + + let targetYaml; + try { + const fileContent = fs.readFileSync(absolutePath, "utf8"); + targetYaml = yaml.parse(fileContent); + } catch (error: any) { + return { output: `YAML Syntax Error in ${filePath}: ${error.message}. Hint: Check the file content for invalid YAML formatting, such as incorrect indentation or unescaped strings, and fix them.` }; + } + + let templateYaml; + try { + const templateContent = fs.readFileSync(templatePath, "utf8"); + templateYaml = yaml.parse(templateContent); + } catch (error: any) { + return { output: `Internal Error: Failed to parse reference template YAML '${templateName}': ${error.message}. Hint: The template file itself contains invalid YAML syntax.` }; + } + + function checkStructure(templateObj: any, targetObj: any, currentPath: string = ""): string[] { + let errors: string[] = []; + + if (typeof templateObj !== 'object' || templateObj === null) { + return errors; + } + + for (const key of Object.keys(templateObj)) { + const newPath = currentPath ? `${currentPath}.${key}` : key; + + if (typeof targetObj !== 'object' || targetObj === null || !(key in targetObj)) { + errors.push(`Missing key: ${newPath}`); + continue; + } + + if (typeof templateObj[key] === 'object' && templateObj[key] !== null && !Array.isArray(templateObj[key])) { + errors.push(...checkStructure(templateObj[key], targetObj[key], newPath)); + } + } + + return errors; + } + + const errors = checkStructure(templateYaml, targetYaml); + + if (errors.length > 0) { + return { output: `YAML Structure Validation Failed. Your file is missing the following required keys:\n- ${errors.join("\n- ")}\n\nHint: Update the file at ${filePath} to include these missing keys so it matches the structure of '${templateName}'.` }; + } + + return { output: "File exists and follows the correct YAML structure." }; + } +}); From 98239c3386dd838bab59a8fc6335e3e987f79312 Mon Sep 17 00:00:00 2001 From: palucdev Date: Sun, 14 Jun 2026 12:55:00 +0200 Subject: [PATCH 2/2] Programatically verify templates --- package.json | 3 +- src/__tests__/verify_template.test.ts | 166 ++++++++++++++++++ src/commands/quick-dev.md | 1 + src/commands/quick-plan.md | 1 + src/skills/development/SKILL.md | 1 + src/skills/migration/SKILL.md | 1 + .../orchestrator-creation-checklist.md | 1 + .../references/orchestrator-patterns.md | 1 + src/skills/performance/SKILL.md | 1 + src/skills/product-design/SKILL.md | 1 + src/skills/quick-bugfix/SKILL.md | 1 + src/skills/research/SKILL.md | 1 + .../orchestrator-state-migration.yml | 4 +- src/templates/orchestrator-state-research.yml | 6 +- tsconfig.json | 3 +- 15 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 src/__tests__/verify_template.test.ts diff --git a/package.json b/package.json index be5fe5f..718420d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "scripts": { "build": "rm -rf dist && tsc && npm run copy-markdowns", "copy-markdowns": "node ./scripts/copy-markdowns.js", - "prepack": "npm run build" + "prepack": "npm run build", + "test": "bun test" }, "keywords": [ "opencode", diff --git a/src/__tests__/verify_template.test.ts b/src/__tests__/verify_template.test.ts new file mode 100644 index 0000000..f6796e4 --- /dev/null +++ b/src/__tests__/verify_template.test.ts @@ -0,0 +1,166 @@ +import { expect, test, describe, beforeAll, afterAll } from "bun:test"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { verify_template } from "../tools/verify_template"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +describe("verify_template tool", () => { + const templatesDir = path.join(__dirname, "../templates"); + const testDir = path.join(__dirname, "test_tmp_dir"); + const testTemplateName = "test-template.yml"; + const testTemplatePath = path.join(templatesDir, testTemplateName); + + beforeAll(() => { + // Ensure templates dir exists + if (!fs.existsSync(templatesDir)) { + fs.mkdirSync(templatesDir, { recursive: true }); + } + // Create a dummy template + fs.writeFileSync( + testTemplatePath, + ` +key1: value1 +key2: + subKey1: subValue1 + `, + ); + + // Ensure test dir exists + if (!fs.existsSync(testDir)) { + fs.mkdirSync(testDir, { recursive: true }); + } + }); + + afterAll(() => { + // Cleanup + if (fs.existsSync(testTemplatePath)) { + fs.rmSync(testTemplatePath); + } + if (fs.existsSync(testDir)) { + fs.rmSync(testDir, { recursive: true, force: true }); + } + }); + + test("should return error if file not found", async () => { + const result = await verify_template.execute( + { filePath: "nonexistent.yml", templateName: testTemplateName }, + { directory: testDir } as any, + ); + expect((result as any).output).toContain( + "File not found at nonexistent.yml", + ); + }); + + test("should return error if template not found", async () => { + const filePath = "target.yml"; + fs.writeFileSync(path.join(testDir, filePath), "key1: value"); + + const result = await verify_template.execute( + { filePath, templateName: "nonexistent-template.yml" }, + { directory: testDir } as any, + ); + expect((result as any).output).toContain( + "Template 'nonexistent-template.yml' not found", + ); + }); + + test("should return error if target file has invalid YAML syntax", async () => { + const filePath = "invalid.yml"; + fs.writeFileSync(path.join(testDir, filePath), "key1: : value\n invalid"); + + const result = await verify_template.execute( + { filePath, templateName: testTemplateName }, + { directory: testDir } as any, + ); + expect((result as any).output).toContain( + "YAML Syntax Error in invalid.yml", + ); + }); + + test("should return error if target file is missing keys from template", async () => { + const filePath = "missing-keys.yml"; + // Missing key2 + fs.writeFileSync(path.join(testDir, filePath), "key1: some-value"); + + const result = await verify_template.execute( + { filePath, templateName: testTemplateName }, + { directory: testDir } as any, + ); + expect((result as any).output).toContain( + "YAML Structure Validation Failed", + ); + expect((result as any).output).toContain("- Missing key: key2"); + }); + + test("should pass if target file matches template structure", async () => { + const filePath = "valid.yml"; + fs.writeFileSync( + path.join(testDir, filePath), + ` +key1: different_value +key2: + subKey1: different_sub_value +extraKey: this is fine + `, + ); + + const result = await verify_template.execute( + { filePath, templateName: testTemplateName }, + { directory: testDir } as any, + ); + expect((result as any).output).toBe( + "File exists and follows the correct YAML structure.", + ); + }); + + test("should pass if template has null or non-object values and target has them too", async () => { + const nullTemplateName = "null-template.yml"; + const nullTemplatePath = path.join(templatesDir, nullTemplateName); + fs.writeFileSync(nullTemplatePath, "key: null\nother: 123"); + + const filePath = "valid-null.yml"; + fs.writeFileSync( + path.join(testDir, filePath), + "key: something\nother: 456", + ); + + const result = await verify_template.execute( + { filePath, templateName: nullTemplateName }, + { directory: testDir } as any, + ); + + expect((result as any).output).toBe( + "File exists and follows the correct YAML structure.", + ); + + fs.rmSync(nullTemplatePath); + }); + + describe("real templates validation", () => { + let templateFiles: string[] = []; + try { + const files = fs.readdirSync(templatesDir); + templateFiles = files.filter(f => f.endsWith('.yml') || f.endsWith('.yaml') || f.endsWith('.md')); + // Filter out our dummy test template + templateFiles = templateFiles.filter(f => f !== "test-template.yml" && f !== "null-template.yml"); + } catch (e) { + // templates dir might not exist or be readable in some contexts, though beforeAll ensures it exists + } + + for (const templateName of templateFiles) { + test(`should successfully validate a valid instance of ${templateName}`, async () => { + // We use the templates directory as the working directory + // and the template name as the filePath, effectively comparing the template to itself to ensure it's structurally valid. + const result = await verify_template.execute( + { filePath: templateName, templateName }, + { directory: templatesDir } as any, + ); + expect((result as any).output).toBe( + "File exists and follows the correct YAML structure.", + ); + }); + } + }); +}); diff --git a/src/commands/quick-dev.md b/src/commands/quick-dev.md index cccac72..847ee84 100644 --- a/src/commands/quick-dev.md +++ b/src/commands/quick-dev.md @@ -63,6 +63,7 @@ Implement a task directly without entering planning mode, while still applying p - Examples: "Add a logout button to the navbar" → `2026-05-28-add-navbar-logout-button`, "Update the API endpoint to accept JSON" → `2026-05-28-update-api-accept-json` 2. Create directory: `.owflow/tasks/quick-dev/YYYY-MM-DD-task-name/` 3. Write `task.yml` with initial state using the template [src/templates/quick-dev-task.yml](../templates/quick-dev-task.yml). +4. **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `quick-dev-task.yml`. ### Step 2: Discover Standards diff --git a/src/commands/quick-plan.md b/src/commands/quick-plan.md index 08a9226..6a45915 100644 --- a/src/commands/quick-plan.md +++ b/src/commands/quick-plan.md @@ -46,6 +46,7 @@ Enter OpenCode's planning mode for a task, with automatic discovery of project s 2. Create directory: `.owflow/tasks/quick-plan/YYYY-MM-DD-task-name/` 3. Create `analysis/` subdirectory inside it 4. Write `task.yml` with initial state using the template [src/templates/quick-plan-task.yml](../templates/quick-plan-task.yml). +5. **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `quick-plan-task.yml`. ### Step 2: Discover and Read Standards (BEFORE Plan Mode) diff --git a/src/skills/development/SKILL.md b/src/skills/development/SKILL.md index f1d28d7..18fc144 100644 --- a/src/skills/development/SKILL.md +++ b/src/skills/development/SKILL.md @@ -63,6 +63,7 @@ Unified workflow for all development tasks — bug fixes, enhancements, and new 1. **Create Task Items**: Use `TaskCreate` for all phases (see Phase Configuration), then set dependencies with `TaskUpdate addBlockedBy` 2. **Create Task Directory**: `.owflow/tasks/development/YYYY-MM-DD-task-name/` 3. **Initialize State**: Create `orchestrator-state.yml` with task info and research reference + - **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `orchestrator-state-development.yml`. 4. **Discover project documentation**: Read `.owflow/docs/INDEX.md` (if exists), extract ALL file paths from the "Project Documentation" section. This includes predefined docs (vision, roadmap, tech-stack, architecture) AND any user-added project docs (e.g., deployment.md, api-strategy.md). Store complete list as `project_context.project_doc_paths` in state. **Output**: diff --git a/src/skills/migration/SKILL.md b/src/skills/migration/SKILL.md index 18ebc4a..2549211 100644 --- a/src/skills/migration/SKILL.md +++ b/src/skills/migration/SKILL.md @@ -23,6 +23,7 @@ Systematic migration workflow from current state analysis to verified migration 1. **Create Task Items**: Use `TaskCreate` for all phases (see Phase Configuration), then set dependencies with `TaskUpdate addBlockedBy` 2. **Create Task Directory**: `.owflow/tasks/migrations/YYYY-MM-DD-task-name/` 3. **Initialize State**: Create `orchestrator-state.yml` with migration context + - **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `orchestrator-state-migration.yml`. 4. **Discover project documentation**: Read `.owflow/docs/INDEX.md` (if exists), extract ALL file paths from the "Project Documentation" section — includes predefined docs AND any user-added project docs. Store as `project_context.project_doc_paths` in state. **Output**: diff --git a/src/skills/orchestrator-framework/references/orchestrator-creation-checklist.md b/src/skills/orchestrator-framework/references/orchestrator-creation-checklist.md index cb0102c..376165b 100644 --- a/src/skills/orchestrator-framework/references/orchestrator-creation-checklist.md +++ b/src/skills/orchestrator-framework/references/orchestrator-creation-checklist.md @@ -10,6 +10,7 @@ Before considering an orchestrator complete, verify ALL items: - [ ] **Step 0: Load Framework** — Initialization reads `orchestrator-patterns.md` - [ ] **State file creation** — Explicit step to CREATE `orchestrator-state.yml` +- [ ] **State verification** — Explicit step to use `verify_template` to check YAML validity after creation - [ ] **Phase structure** — Each phase has: Purpose, Execute, Output, State, Transition (`→ Pause` / `→ AUTO-CONTINUE` / `→ Conditional`) - [ ] **Delegation enforcement** — Each delegated phase has: ANTI-PATTERN block, INVOKE NOW block, SELF-CHECK - [ ] **POST-CONTINUATION blocks** — After Skill tool phases, explicit instructions to read state, update completed_phases, and continue diff --git a/src/skills/orchestrator-framework/references/orchestrator-patterns.md b/src/skills/orchestrator-framework/references/orchestrator-patterns.md index 3720bd8..7ac67ad 100644 --- a/src/skills/orchestrator-framework/references/orchestrator-patterns.md +++ b/src/skills/orchestrator-framework/references/orchestrator-patterns.md @@ -202,6 +202,7 @@ Refer to `verification_context` in the template [src/templates/orchestrator-stat 2. **Determine starting phase**: New task starts Phase 1; resume reads state for first incomplete phase 3. **Create task directory**: Standard structure with analysis/, implementation/, verification/, documentation/ _(skip on resume)_ 4. **Create state file**: `orchestrator-state.yml` _(skip on resume)_ + - **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against the corresponding template. 5. **Create task items**: `TaskCreate` for all phases, then `TaskUpdate addBlockedBy` for dependencies. On resume, also restore completed phase statuses. 6. **Output summary**: Show task info, phases, starting message diff --git a/src/skills/performance/SKILL.md b/src/skills/performance/SKILL.md index 53c0597..9b46d8c 100644 --- a/src/skills/performance/SKILL.md +++ b/src/skills/performance/SKILL.md @@ -24,6 +24,7 @@ Static-analysis-first performance optimization workflow. Identifies bottlenecks 2. **Create Task Directory**: `.owflow/tasks/performance/YYYY-MM-DD-task-name/` 3. **Create Subdirectories**: `analysis/`, `analysis/user-profiling-data/`, `implementation/`, `verification/` 4. **Initialize State**: Create `orchestrator-state.yml` with performance context + - **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `orchestrator-state-performance.yml`. 5. **Discover project documentation**: Read `.owflow/docs/INDEX.md` (if exists), extract ALL file paths from the "Project Documentation" section — includes predefined docs AND any user-added project docs. Store as `project_context.project_doc_paths` in state. **Output**: diff --git a/src/skills/product-design/SKILL.md b/src/skills/product-design/SKILL.md index 373419c..b65e9fc 100644 --- a/src/skills/product-design/SKILL.md +++ b/src/skills/product-design/SKILL.md @@ -39,6 +39,7 @@ Interactive workflow for product and feature design -- from fuzzy idea to develo - Create `context/` folder with `README.md` instructing users to drop relevant files there (meeting transcripts, existing designs, spreadsheets, docs, PDFs, images) - Create `analysis/` and `outputs/` directories 3. **Initialize State**: Create `orchestrator-state.yml` with design context schema (see Domain Context section) + - **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `orchestrator-state-product-design.yml`. **Output**: diff --git a/src/skills/quick-bugfix/SKILL.md b/src/skills/quick-bugfix/SKILL.md index fb8c0eb..7748ac6 100644 --- a/src/skills/quick-bugfix/SKILL.md +++ b/src/skills/quick-bugfix/SKILL.md @@ -59,6 +59,7 @@ For complex bugs that grow beyond a quick fix, suggests escalating to the full d 2. Create directory: `.owflow/tasks/quick-bugfix/YYYY-MM-DD-task-name/` 3. Create `analysis/` subdirectory inside it 4. Write `task.yml` with initial state using the template [src/templates/quick-bugfix-task.yml](../../templates/quick-bugfix-task.yml). +5. **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `quick-bugfix-task.yml`. ### Step 3: Discover Standards diff --git a/src/skills/research/SKILL.md b/src/skills/research/SKILL.md index f81879a..52091d9 100644 --- a/src/skills/research/SKILL.md +++ b/src/skills/research/SKILL.md @@ -23,6 +23,7 @@ Systematic research workflow from question definition to evidence-based document 1. **Create Task Items**: Use `TaskCreate` for all phases (see Phase Configuration), then set dependencies with `TaskUpdate addBlockedBy` 2. **Create Task Directory**: `.owflow/tasks/research/YYYY-MM-DD-task-name/` 3. **Initialize State**: Create `orchestrator-state.yml` with research context + - **CRITICAL**: Use the `verify_template` tool immediately after creation to check YAML validity against `orchestrator-state-research.yml`. **Output**: diff --git a/src/templates/orchestrator-state-migration.yml b/src/templates/orchestrator-state-migration.yml index d311d5b..93bed69 100644 --- a/src/templates/orchestrator-state-migration.yml +++ b/src/templates/orchestrator-state-migration.yml @@ -26,7 +26,7 @@ task: priority: null migration_context: - migration_type: "code" | "data" | "architecture" | "general" + migration_type: "code | data | architecture | general" current_system: description: null technologies: [] @@ -34,7 +34,7 @@ migration_context: description: null technologies: [] migration_strategy: - approach: "incremental" | "big-bang" | "dual-run" | "phased" + approach: "incremental | big-bang | dual-run | phased" phases: [] risk_level: null breaking_changes: [] diff --git a/src/templates/orchestrator-state-research.yml b/src/templates/orchestrator-state-research.yml index 3c6aa4b..da6a29f 100644 --- a/src/templates/orchestrator-state-research.yml +++ b/src/templates/orchestrator-state-research.yml @@ -25,7 +25,7 @@ task: priority: null research_context: - research_type: "technical" | "requirements" | "literature" | "mixed" + research_type: "technical | requirements | literature | mixed" research_question: null scope: included: [] @@ -33,11 +33,11 @@ research_context: constraints: [] methodology: [] sources: [] - confidence_level: "high" | "medium" | "low" + confidence_level: "high | medium | low" gathering_strategy: categories: [] count: 0 - source: "planner" | "default" + source: "planner | default" phase_summaries: phase-1: summary: null diff --git a/tsconfig.json b/tsconfig.json index c250a6b..2211a97 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,7 @@ "noPropertyAccessFromIndexSignature": false }, "include": [ - "src/**/*" + "src/**/*", + "src/__tests__/verify_template.test.ts" ], } \ No newline at end of file