Skip to content

refactor: split skill templates into workflow modules#698

Merged
TabishB merged 5 commits intomainfrom
codex/split-skill-templates
Feb 16, 2026
Merged

refactor: split skill templates into workflow modules#698
TabishB merged 5 commits intomainfrom
codex/split-skill-templates

Conversation

@TabishB
Copy link
Contributor

@TabishB TabishB commented Feb 12, 2026

Summary

  • split src/core/templates/skill-templates.ts into workflow-focused modules under src/core/templates/workflows/
  • extract shared template interfaces to src/core/templates/types.ts
  • keep src/core/templates/skill-templates.ts as a compatibility facade re-exporting the existing public API
  • add test/core/templates/skill-templates-parity.test.ts to lock payload and generated-content parity

Validation

  • pnpm build
  • OPENSPEC_TELEMETRY=0 pnpm exec vitest run test/core/templates/skill-templates-parity.test.ts test/core/shared/skill-generation.test.ts

Summary by CodeRabbit

  • New Features

    • Added a suite of structured workflow templates for change management (Apply, Archive, Bulk Archive, Continue, Explore, Fast‑Forward, New, Onboard, Sync, Verify, Feedback) and introduced typed templates to standardize skill/command content and metadata.
  • Tests

    • Added parity tests to validate template payloads and generated skill content for consistency.
  • Documentation

    • Added design, proposal, spec, tasks, and onboarding docs plus a config entry describing the spec-driven pipeline.
  • Chores

    • Simplified template re-exports to streamline the public template surface.

@1code-async
Copy link
Contributor

1code-async bot commented Feb 12, 2026

Task completed.


PR Review: refactor: split skill templates into workflow modules (#698)

Overall Assessment

This is a clean decomposition of a ~3,500 line monolithic file into 11 focused workflow modules. The approach is sound — keeping skill-templates.ts as a re-export facade preserves backward compatibility while making the codebase more navigable. The parity test with SHA-256 hashing is a strong safeguard against accidental content drift.


Issue: Missing exports in index.ts

Severity: Bug

src/core/templates/index.ts does not re-export three functions that the new facade (skill-templates.ts) exposes:

  • getOnboardSkillTemplate
  • getOpsxOnboardCommandTemplate
  • getFeedbackSkillTemplate

The old index.ts on main was also missing these (so this isn't a regression), but since this PR is explicitly updating the export surface, it's worth fixing now. If any consumer later imports from ../templates/index.js instead of ../templates/skill-templates.js, they'll be missing these functions.

Additionally, index.ts doesn't re-export the SkillTemplate or CommandTemplate types, while the facade does via export type { ... } from './types.js'. This is another gap.

Suggested fix — replace index.ts contents with:

export * from './skill-templates.js';

Or explicitly add the missing entries if you prefer named exports for documentation purposes.


Suggestion: File-specific doc comments instead of generic boilerplate

Every workflow file has the identical header:

/**
 * Skill Template Workflow Modules
 *
 * This file is generated by splitting the legacy monolithic
 * templates file into workflow-focused modules.
 */

This comment is inaccurate per-file (each file isn't "workflow modules" plural, it's one specific workflow), and the "generated by splitting" provenance won't be meaningful to future contributors. Consider either:

  1. Removing the boilerplate entirely (the file name + exports are self-documenting), or
  2. Using file-specific one-liners like:
    /** Explore workflow skill and command templates. */

Suggestion: Consider adding workflows/index.ts

There's no barrel file in workflows/. If other parts of the codebase ever need to import individual workflow modules directly (bypassing the facade), a workflows/index.ts would make that cleaner. This is minor — the facade approach works fine as-is — but it's a common pattern for module directories.


Positive: Onboard module uses a helper function well

In workflows/onboard.ts, the getOnboardInstructions() helper is extracted and shared between both getOnboardSkillTemplate() and getOpsxOnboardCommandTemplate(). This avoids duplicating the large onboarding instructions string. Good pattern.


Positive: Parity test is well-designed

The skill-templates-parity.test.ts file hashes both the raw template payloads and the generated skill content using stableStringify + SHA-256. This is an effective approach that:

  • Detects any accidental content changes during the split
  • Uses deterministic key ordering via stableStringify to avoid false positives from object property order differences
  • Tests both the template data layer and the generation layer

One minor note: the hardcoded hashes act as a snapshot. Future template changes will require updating these hashes, which could be confusing without a comment explaining how to regenerate them. Consider adding a brief comment like:

// To regenerate hashes after intentional template changes:
// 1. Change expected hash values to empty strings
// 2. Run the test to see actual hashes in the error output
// 3. Copy the actual hashes here

Observation: CommandTemplate type unused in feedback.ts

feedback.ts only imports SkillTemplate (not CommandTemplate) and only exports getFeedbackSkillTemplate. This is the only workflow module without a corresponding getOpsx*CommandTemplate function. This seems intentional (feedback doesn't need a slash command), but it's worth confirming that this asymmetry is expected.


Summary

Category Finding
Bug index.ts missing 3 exports + type re-exports vs the facade
Suggestion Replace generic boilerplate comments with file-specific ones
Suggestion Consider workflows/index.ts barrel file
Suggestion Add hash regeneration instructions to parity test
Good onboard.ts shared helper avoids duplication
Good Parity test with stable hashing is solid
Good Facade pattern preserves backward compatibility

View full conversation

Powered by 1Code

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces core template types and splits a monolithic templates module into many workflow-specific template files, adding per-workflow SkillTemplate/CommandTemplate factory functions, switching the templates facade to a wildcard re-export, and adding parity tests and OpenSpec design/docs for a unified template-generation pipeline.

Changes

Cohort / File(s) Summary
Type Definitions
src/core/templates/types.ts
Add SkillTemplate and CommandTemplate interfaces (including optional license, compatibility, metadata).
Workflow templates (many)
src/core/templates/workflows/...
src/core/templates/workflows/apply-change.ts, src/core/templates/workflows/archive-change.ts, src/core/templates/workflows/bulk-archive-change.ts, src/core/templates/workflows/continue-change.ts, src/core/templates/workflows/explore.ts, src/core/templates/workflows/feedback.ts, src/core/templates/workflows/ff-change.ts, src/core/templates/workflows/new-change.ts, src/core/templates/workflows/onboard.ts, src/core/templates/workflows/sync-specs.ts, src/core/templates/workflows/verify-change.ts
Add per-workflow factory functions (e.g., getXSkillTemplate, getOpsxXCommandTemplate) that return typed template objects with extensive instruction/guardrail content, metadata, license and compatibility fields.
Templates facade
src/core/templates/index.ts
Replace explicit named re-exports with export * from './skill-templates.js' (wildcard facade), altering the re-export surface.
Tests
test/core/templates/skill-templates-parity.test.ts
Add Vitest parity tests that stable-stringify and SHA-256 hash template payloads and generated skill content to detect unintended drift.
OpenSpec docs & change set
openspec/changes/unify-template-generation-pipeline/...
*.md, .openspec.yaml, specs/*, tasks.md
Add design, proposal, spec, and task planning documents for a unified template-artifact pipeline (no runtime code changes).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Poem

🐇 I hopped through code with quiet paws,
Split a monolith into tidy claws.
Templates bloom with instructions bright,
Types keep order through the night,
A rabbit's hop — templates take flight! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly describes the primary change: splitting a monolithic skill-templates module into focused workflow-specific modules, which is the core refactoring work across the changeset.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/split-skill-templates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link

greptile-apps bot commented Feb 12, 2026

Greptile Overview

Greptile Summary

This PR splits the monolithic skill-templates.ts (~3,500 lines) into focused workflow modules under src/core/templates/workflows/, with each workflow getting its own file. The original file becomes a compatibility facade that re-exports everything, ensuring backward compatibility.

Key changes

  • Extracted shared types (SkillTemplate, CommandTemplate) to types.ts
  • Split 11 workflows into individual modules (explore, new-change, continue-change, apply-change, ff-change, sync-specs, archive-change, bulk-archive-change, verify-change, onboard, feedback)
  • Maintained exact functionality via re-exports from skill-templates.ts
  • Added comprehensive parity test using hash-based validation to verify no behavior changes

Issues found

  • src/core/templates/index.ts is missing three exports that are present in skill-templates.ts: getOnboardSkillTemplate, getOpsxOnboardCommandTemplate, and getFeedbackSkillTemplate. This creates an inconsistency where some consumers importing from index.ts won't have access to these functions.

Benefits

  • Much better organization - each workflow is now independently maintainable
  • Clearer separation of concerns with consistent file structure
  • Easier to navigate and understand individual workflows
  • No breaking changes due to facade pattern

Confidence Score: 4/5

  • Safe to merge after fixing missing exports in index.ts
  • The refactoring is well-executed with excellent test coverage (hash-based parity tests). The facade pattern ensures backward compatibility. However, the missing exports in index.ts represent a logical error that should be fixed before merging to maintain API consistency.
  • Pay attention to src/core/templates/index.ts - needs the missing exports added

Important Files Changed

Filename Overview
src/core/templates/skill-templates.ts Clean facade that re-exports all workflow modules - maintains backward compatibility
src/core/templates/types.ts Extracted shared template interfaces - proper separation of concerns
test/core/templates/skill-templates-parity.test.ts Comprehensive parity test using hash-based validation to ensure refactor preserves exact behavior
src/core/templates/index.ts Re-exports from skill-templates.ts but missing three exports (getOnboardSkillTemplate, getOpsxOnboardCommandTemplate, getFeedbackSkillTemplate)

Sequence Diagram

sequenceDiagram
    participant Consumer
    participant index.ts
    participant skill-templates.ts
    participant workflows/

    Note over Consumer,workflows/: Before: Monolithic File
    Consumer->>skill-templates.ts: import { getExploreSkillTemplate }
    skill-templates.ts-->>Consumer: return template (3500+ lines)

    Note over Consumer,workflows/: After: Modular Architecture
    Consumer->>skill-templates.ts: import { getExploreSkillTemplate }
    skill-templates.ts->>workflows/: re-export from workflows/explore.js
    workflows/-->>skill-templates.ts: template function
    skill-templates.ts-->>Consumer: return template

    Note over Consumer,index.ts: Alternative Import Path
    Consumer->>index.ts: import { getExploreSkillTemplate }
    index.ts->>skill-templates.ts: re-export
    skill-templates.ts->>workflows/: re-export
    workflows/-->>Consumer: template function
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 12, 2026

Additional Comments (1)

src/core/templates/index.ts
Missing exports for getOnboardSkillTemplate, getOpsxOnboardCommandTemplate, and getFeedbackSkillTemplate. These are exported from skill-templates.ts but not re-exported here.

// Re-export skill templates for convenience
export {
  getExploreSkillTemplate,
  getNewChangeSkillTemplate,
  getContinueChangeSkillTemplate,
  getApplyChangeSkillTemplate,
  getFfChangeSkillTemplate,
  getSyncSpecsSkillTemplate,
  getArchiveChangeSkillTemplate,
  getBulkArchiveChangeSkillTemplate,
  getVerifyChangeSkillTemplate,
  getOnboardSkillTemplate,
  getFeedbackSkillTemplate,
  getOpsxExploreCommandTemplate,
  getOpsxNewCommandTemplate,
  getOpsxContinueCommandTemplate,
  getOpsxApplyCommandTemplate,
  getOpsxFfCommandTemplate,
  getOpsxSyncCommandTemplate,
  getOpsxArchiveCommandTemplate,
  getOpsxBulkArchiveCommandTemplate,
  getOpsxVerifyCommandTemplate,
  getOpsxOnboardCommandTemplate,
} from './skill-templates.js';

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/core/templates/workflows/feedback.ts`:
- Around line 9-111: The getFeedbackSkillTemplate SkillTemplate factory is
missing the standard fields present in other templates (license, compatibility,
metadata); update the object returned by getFeedbackSkillTemplate to include
license: 'MIT', compatibility: 'Requires openspec CLI.', and metadata: { author:
'openspec', version: '1.0' } so it matches
getOnboardSkillTemplate/getArchiveChangeSkillTemplate/getFfChangeSkillTemplate
conventions and remember this will change the
EXPECTED_FUNCTION_HASHES.getFeedbackSkillTemplate parity test.

In `@src/core/templates/workflows/ff-change.ts`:
- Around line 189-201: The command template's "Artifact Creation Guidelines" in
ff-change.ts is missing the guardrail that `context` and `rules` are constraints
and must not be copied into artifact files; add the same sentence used in the
skill template ("`context` and `rules` are constraints for YOU, not content for
the file — Do NOT copy `<context>`, `<rules>`, `<project_context>` blocks into
the artifact.") into the Artifact Creation Guidelines section of the command
template so it matches the guardrail present in continue-change.ts and the skill
template.

In `@test/core/templates/skill-templates-parity.test.ts`:
- Around line 120-142: Add a brief inline comment above the skillFactories array
explaining that getFeedbackSkillTemplate is intentionally excluded from this
generated-content parity test because feedback is not deployed as a generated
skill file (it is covered in the function-payload parity test); mention the
symbols involved (getFeedbackSkillTemplate, skillFactories,
generateSkillContent) so future readers understand the deliberate omission.
🧹 Nitpick comments (3)
src/core/templates/workflows/explore.ts (1)

298-472: Substantial content duplication between getExploreSkillTemplate and getOpsxExploreCommandTemplate.

The content field in the command template is ~90% identical to the instructions field in the skill template. The onboard.ts module demonstrates a cleaner pattern using a shared getOnboardInstructions() helper to avoid this. Consider extracting shared prose into a helper and interpolating the small differences (e.g., the additional "Input" section in the command template).

This isn't blocking since the parity test locks the output, but it increases maintenance burden for future content changes across all workflow modules that follow this pattern.

src/core/templates/workflows/continue-change.ts (2)

1-6: Nit: Header comment is misleading for ongoing maintenance.

The comment says "This file is generated by splitting the legacy monolithic templates file" — this reads as if it's auto-generated. If these modules will be hand-maintained going forward, consider rewording to avoid confusion (e.g., "Extracted from the legacy monolithic templates file"). This same comment appears in all workflow files.


9-239: Significant content duplication between SkillTemplate.instructions and CommandTemplate.content.

The instructions field (Lines 13–119) and the content field (Lines 132–238) are ~95% identical — roughly 100+ lines of duplicated markdown with only minor differences (input format mentioning /opsx:continue, output prompt wording, and the "all complete" suggestion). This pattern repeats across every workflow file in this PR.

Consider extracting the shared instruction body into a helper and composing the small per-variant deltas. For example:

♻️ Sketch of a shared-content approach
// In a shared helper, e.g., src/core/templates/workflows/_continue-change-content.ts

function baseContinueInstructions(opts: {
  inputLine: string;
  allCompleteMsg: string;
  outputPrompt: string;
}): string {
  return `Continue working on a change by creating the next artifact.

${opts.inputLine}

**Steps**
...shared steps...

   **If all artifacts are complete (\`isComplete: true\`)**:
   ...
   - Suggest: "${opts.allCompleteMsg}"
   ...

**Output**
...
- Prompt: "${opts.outputPrompt}"
...`;
}

This would make future instruction edits less error-prone and reduce the risk of the two variants drifting apart. The same pattern applies to every other workflow module in this PR.

@lsmonki
Copy link

lsmonki commented Feb 14, 2026

Hey @TabishB, great refactoring work here.

I wanted to raise something that connects this PR with the discussion happening on #701 (lifecycle hooks). Right now, all 10 skill templates generate identical instructions regardless of the target agent.

This works today, but it breaks down when you consider that each agent defines its own way of handling hooks, tools, and workflows. Claude Code has PreToolUse/PostToolUse/Stop, Cursor has its own system, Windsurf another, and many agents have no hook system at all. There's no shared capability model — each agent is its own world.

Proposal: Agent Skill Profiles

Would you consider designing these workflow modules with an agent-based profile system in mind? The idea:

The current set of workflow modules becomes the default profile — the universal, agent-agnostic baseline that works for any agent.

Specific agents can define their own agent profile that overrides or extends individual workflow modules to leverage agent-specific features (native hooks, custom tool integrations, etc.).

Resolution is simple: agent-specific module if it exists, otherwise fall back to default

Concretely:

src/core/templates/
  types.ts                          # Add SkillProfile interface
  workflows/                        # Default profile (current, unchanged)
    explore.ts
    apply-change.ts
    ...
  profiles/                         # Agent-specific overrides
    claude-code/
      apply-change.ts               # Uses native PreToolUse/PostToolUse hooks
      archive-change.ts
    cursor/
      apply-change.ts               # Uses Cursor's own hook system
    ...

Each agent 's config would map to a profile ID (or 'default'), and the skill generation in update.ts would resolve templates through the profile chain before generating content.

This doesn't need to be implemented now — I'm just suggesting that the module boundaries you're creating here are the perfect foundation for this pattern. The factory functions per workflow module are exactly the right seam. If designed with this extensibility in mind (e.g., factory functions that accept an optional agent context), it would make the evolution much smoother.
This ties into what we've been discussing in #701 — agent profiles would let us take full advantage of native hooks and tools in agents like Claude Code, while keeping the default portable behavior for agents that don't have those features. Best of both worlds.

What do you think?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
test/core/templates/skill-templates-parity.test.ts (2)

67-81: stableStringify returns undefined (not a string) for undefined values.

JSON.stringify(undefined) returns JS undefined, not the string "undefined". If a template property ever holds undefined, the hash would still be computed (via implicit coercion in string concatenation), but the representation wouldn't be distinguishable from the literal string undefined or from a missing key scenario. Low risk for current template shapes, but worth a defensive guard.

🛡️ Optional defensive fix
  return JSON.stringify(value);

could become:

+ if (value === undefined) return '"__undefined__"';
  return JSON.stringify(value);

30-65: Consider adding a brief comment explaining how to update hashes after intentional template changes.

When a developer intentionally modifies a template, these tests will fail with opaque SHA-256 mismatches. A short comment (e.g., "Run the test with --update or copy actual hashes from the failure output") would reduce friction and avoid confusion about whether the failure signals a regression or an expected change.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
test/core/templates/skill-templates-parity.test.ts (1)

30-52: Consider adding a safeguard against silently missing new templates.

If a new template factory is added in the future but not included in functionFactories, the parity test will still pass — it just won't cover the new template. A complementary assertion that the count of exported factories matches functionFactories length would catch this.

Example assertion
+import * as allTemplates from '../../../src/core/templates/skill-templates.js';
+
+// Ensure no factory is silently omitted from parity checks
+const exportedFactories = Object.entries(allTemplates).filter(
+  ([key, val]) => typeof val === 'function' && key.startsWith('get')
+);
+expect(Object.keys(functionFactories).length).toBe(exportedFactories.length);

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
openspec/changes/unify-template-generation-pipeline/specs/template-artifact-pipeline/spec.md (1)

24-24: Optional: Consider more concise wording.

The phrase "in a consistent way" could be simplified to "consistently" for brevity, though the current wording is clear and acceptable.

✍️ Suggested simplification
-  - **AND** generation SHALL use those values or explicit defaults in a consistent way for all workflows
+  - **AND** generation SHALL use those values or explicit defaults consistently for all workflows

@TabishB TabishB merged commit 92731e2 into main Feb 16, 2026
9 checks passed
@TabishB TabishB deleted the codex/split-skill-templates branch February 16, 2026 07:13
@TabishB
Copy link
Contributor Author

TabishB commented Feb 16, 2026

@lsmonki

Agent-specific behavior is definitely on our radar. This refactor was partly about creating the right module boundaries for exactly this kind of extensibility.

We're exploring a pattern that uses a transform pipeline + tool profile registry rather than full template copies per agent, keeps the maintenance burden manageable while still allowing agent-specific optimizations. Early days, but the foundation is here now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants