DEV Community

Hagicode
Hagicode

Posted on

Customizing OpenSpec Steps to Improve AI Generation Results

Customizing OpenSpec Steps to Improve AI Generation Results

When using OpenSpec to manage technical proposals, we encountered inconsistent quality in AI-generated documentation. There was really no other way but to modify the prompt templates ourselves. This article documents those days.

Background

OpenSpec is a system for managing technical proposals with a simple core idea: input a change description, automatically generate various documentation artifacts. Proposals, designs, specs, tasks—all can be auto-generated. Sounds pretty ideal, right?

But in actual use, we discovered some issues. How should I put it—not major problems, just that the generated output didn't feel quite right.

The generated design.md lacked necessary visual elements—no Mermaid flowcharts, no sequence diagrams, and no architecture diagrams. Such design documents made the technical team shake their heads; after all, who wants to read walls of pure text?

proposal.md was also unsatisfactory, lacking code change tables and UI prototypes. Decision-makers could stare at it for ages and still not understand what the change actually modified.

More frustrating was tasks.md, which mixed in various Git operation tasks. Responsibility boundaries became unclear, and developers looking at these tasks didn't know what they should or shouldn't do. This is also a bit helpless—after all, AI doesn't know your team's division of labor.

Visualization requirements for different document levels were also unclear. What charts should proposal and design contain? This question constantly troubled the team.

Where's the root of these problems? After analysis, we discovered the key point: the prompt templates lacked clear constraints and guidance.

This isn't surprising—after all, templates themselves are generic and can't perfectly adapt to every team's needs.

About HagiCode

The solution shared in this article comes from our practical experience in the HagiCode project. HagiCode is an AI code assistant project, and we heavily use OpenSpec to manage technical proposals during development.

It was precisely these real-world experiences that led to the birth of this improvement plan. Actually, it's nothing special—just encountering problems and solving them.

Analysis: Prompt System Architecture

To solve problems, first understand the system. Let's see how OpenSpec's prompt system works.

OpenSpec uses the Handlebars template system, where each prompt contains two parts:

JSON metadata file: Defines parameters, scenarios, version information
Handlebars template file: Contains actual prompt content

Resources/Prompts/
├── openspec-v1-ff.zh-CN.json    # metadata
├── openspec-v1-ff.zh-CN.hbs     # template content
├── openspec-v1-ff.en-US.json
└── openspec-v1-ff.en-US.hbs
Enter fullscreen mode Exit fullscreen mode

The advantages of this separation design are obvious: metadata and content are managed separately, facilitating maintenance and localization. It's also a bit like writing code—separation of logic and presentation, everyone understands this principle.

The FF (Fast Forward) workflow is OpenSpec's core generation process:

flowchart TD
    A[User inputs change description] --> B[Create change directory]
    B --> C[Get artifact build order]
    C --> D[Create artifacts in dependency order]
    D --> E[Check planning direction requirements]
    E --> F[Verify artifact completeness]
    F --> G[Display final state]
Enter fullscreen mode Exit fullscreen mode

This process looks perfect, but the problem lies in the "planning direction requirements" step—it lacks sufficiently clear guidance.

This is also a bit helpless; after all, when designing the system, it's impossible to consider every team's specific needs.

Planning Direction System

The planning direction system is OpenSpec's core customization mechanism, allowing users to select different generation options. The HagiCode project defines the following directions:

Direction ID Function Default Enabled
explore Exploration mode Yes
change-map Change map Yes
flowchart Interactive flowchart Yes
prototype UI prototype Yes
architecture Architecture diagram Yes
sequence API sequence diagram Yes

Each direction defines stable identifiers, default enabled states, display labels, and Chinese/English prompt fragments.

This system design is clever, but in HagiCode's practice, we discovered that having definitions alone isn't enough—the planning directions need to be explicitly used in prompt templates.

This is also a bit like many things in life: having options doesn't mean making choices; someone still needs to tell you how to choose.

Solution: Clear Constraints and Examples

Our improvement approach is straightforward: add clear constraints and reference examples to prompt templates.

Actually, there's nothing special—just making things clear.

1. Add Document Visualization Requirements

In the openspec-v1-ff.zh-CN.hbs template, we added explicit content scope constraints:

### tasks.md Content Scope Constraints

When creating `tasks.md` artifacts, the following content scope constraints must be observed:

Must include:
- Business logic tasks (code implementation, feature development)
- Technical implementation tasks (component integration, API development)
- Testing tasks (unit tests, integration tests)
- Documentation tasks (updating documentation, adding comments)

Must not include:
- Git commit operations (git add, git commit, git push)
- Version control management workflows
- Deployment and release operations
Enter fullscreen mode Exit fullscreen mode

Using standardized "MUST/MUST NOT" language rather than "suggested" or "may" allows AI to more accurately understand constraints.

This is also a bit like teaching children—say what you mean, no ambiguity allowed.

2. Provide Reference Examples for Each Direction

Just saying "include flowcharts" isn't enough. We provided specific output examples for each enabled direction.

After all, talk is cheap—give a concrete example, and AI can better understand.

Change map direction example:

| File path | Change type | Change reason | Impact scope |
|-----------|-------------|---------------|-------------|
| Path/to/file | Add | Description | Module name |
Enter fullscreen mode Exit fullscreen mode

Prototype direction example:

┌─────────────────────────────────────────┐
│ User Login                            [×] │
├─────────────────────────────────────────┤
│  Email address *                       │
│ ┌─────────────────────────────────────┐ │
│ │ user@example.com                   │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Flowchart direction example:

sequenceDiagram
    participant U as User
    participant UI as Login Interface
    participant API as Backend API
    U->>UI: Click login button
    UI->>API: POST /api/auth/login
Enter fullscreen mode Exit fullscreen mode

These examples allow AI to accurately understand the expected output format rather than improvising.

This is also a bit like providing reference answers during an exam—while not exactly the same, the format should at least be correct.

3. Use Standardized Language for Clear Requirements

For visualization requirements of different document types, we use standardized language to constrain:

For proposal.md:
- Must include code change table (when change-map direction enabled)
- Must include UI prototype (when involving UI changes and prototype direction enabled)
- Must not include detailed architecture diagrams (these should be in design.md)

For design.md:
- Must include all proposal.md content (more detailed version)
- Must include architecture diagram (when architecture direction enabled)
- Must include data flow diagram (when flowchart direction enabled)
Enter fullscreen mode Exit fullscreen mode

These clear constraints significantly improved generation quality.

Actually, there's nothing else—just making things clear, don't let AI guess.

Practice: Code Implementation

Theory covered, let's see how it's implemented in the HagiCode project.

Define Planning Directions

Define planning directions in ProposalPlanningDirections.cs:

public static class ProposalPlanningDirections
{
    private static readonly ProposalPlanningDirectionDefinition[] Catalog =
    [
        new(
            ChangeMapId,
            "Change map",
            DefaultEnabled: true,
            EnglishPromptFragment:
            "- Change map: include structured file-impact views...",
            ChinesePromptFragment:
            "- 变更地图:加入结构化的文件影响视图..."),
        // ... other directions
    ];

    public static string RenderInstructionBlock(
        IEnumerable<ProposalPlanningDirectionState> directions,
        string? locale)
    {
        var enabledDirections = directions
            .Where(direction => direction.Enabled)
            .ToArray();

        if (enabledDirections.Length == 0)
        {
            return string.Empty;
        }

        var heading = IsChineseLocale(locale)
            ? "本次生成启用以下规划方向:"
            : "Apply the following planning directions:";

        return string.Join(Environment.NewLine,
            [heading, .. enabledDirections.Select(d => d.GetPromptFragment(locale))]);
    }
}
Enter fullscreen mode Exit fullscreen mode

This code has several noteworthy design points:

  1. Using arrays instead of lists because definitions don't change at runtime
  2. Lazy rendering—only generate text when there are enabled directions
  3. Multi-language support, selecting appropriate prompt fragments based on locale

Actually, there's nothing special—just some常规 code design.

Template Parameterization

Use conditional statements in Handlebars templates:

{{#if planningDirectionInstructions}}
## Planning Directions for This Generation

{{{planningDirectionInstructions}}}
{{/if}}

**Steps**
1. **If input not provided, use reasonable defaults**
2. **Create change directory**
3. **Get artifact build order**
4. **Create artifacts sequentially until apply-ready**
   a. For each ready artifact:
      - Get instructions
      - Read dependency files
      - Create artifact file
Enter fullscreen mode Exit fullscreen mode

Note that {{{planningDirectionInstructions}}}—three curly braces mean don't escape HTML, which preserves formats like Mermaid code blocks.

This is also a bit like compromise in life—sometimes you need to keep some original content, can't escape everything.

Prompt Loading Implementation

Implement parameterized prompt loading through FilePromptProvider:

public async Task<string> GetOpenspecV1FfPromptAsync(
    string changeName,
    string changeDescription,
    string locale = "en-US",
    string? planningDirectionInstructions = null,
    CancellationToken cancellationToken = default)
{
    var parameters = new Dictionary<string, object>
    {
        { "planningDirectionInstructions",
          ResolvePlanningDirectionInstructions(locale, planningDirectionInstructions) }
    };

    if (!string.IsNullOrWhiteSpace(changeName))
    {
        parameters["changeName"] = changeName;
    }

    return await GetPromptWithParametersAsync(
        PromptScenario.OpenspecV1Ff,
        locale,
        cancellationToken,
        parameters) ?? string.Empty;
}
Enter fullscreen mode Exit fullscreen mode

This design is flexible: planningDirectionInstructions is optional—if not provided, the system uses default configuration.

After all, no one wants to pass in a bunch of parameters every time; having a default value is always good.

Validation and Testing

After implementation, the HagiCode team conducted comprehensive validation:

When Specific Directions Are Enabled

  • Check if generated proposal.md contains code change table
  • Check if generated design.md contains architecture diagrams
  • Verify tasks.md doesn't include Git operation tasks

When Specific Directions Are Disabled

  • Verify corresponding visualization content isn't generated
  • Ensure other directions' output isn't affected

Edge Cases

  • Behavior when all directions are disabled
  • Error handling for invalid direction IDs

These tests ensure system stability and predictability—critical for team adoption of new tools.

Actually, there's nothing special—just test what should be tested, after all, no one wants problems after going live.

Considerations

When implementing this solution, avoid these pitfalls:

Template synchronization: When modifying templates, keep them in sync with upstream. The HagiCode team encountered a template conflict that took half a day to resolve. This is also a bit helpless—after all, upgrades always bring some compatibility issues.

Bilingual consistency: Ensure Chinese and English templates have consistent structure and constraints. We encountered a situation where the Chinese version had constraints but the English version didn't, causing inconsistent document quality. This is also a bit awkward—after all, who knows which language users will use.

Performance impact: Planning direction rendering should complete in microseconds. If rendering takes too long, it affects user experience. After all, who wants to wait ages to see results.

Backward compatibility: Maintain support for old version APIs. For example, the enableExploreMode parameter—although we now use the planning direction system, old code still uses it. This is also a bit helpless—can't always require everyone to upgrade.

Clear expression: Use standardized language (MUST/SHALL) rather than suggestive language. This point was fully validated in HagiCode's practice. Actually, there's nothing else—just making things clear.

Summary

By customizing OpenSpec prompt steps, we successfully improved the quality of AI-generated documentation. Key improvements include:

  1. Adding clear constraint conditions to prompt templates
  2. Providing specific output examples for each planning direction
  3. Using standardized language (MUST/MUST NOT) to constrain AI behavior
  4. Implementing flexible parameterized prompt loading through code

This solution was validated in the HagiCode project, with significantly improved document quality: design documents include complete visual elements, proposal documents have clear code change tables, and task lists have clear responsibilities.

Actually, it's nothing special—just solving the problem.

If you're also using similar AI-assisted documentation generation systems, I hope these experiences help you. Remember: clear constraints and concrete examples are key to obtaining high-quality output.

After all, for some things, it's better to be clear...

References

Top comments (0)