Optimizing OpenSpec Phase Efficiency with Different Agents: HagiCode Practice Summary
Generic prompts cannot handle the specific requirements of different development stages. Through phase-specific agents and a parameterized template system, AI can produce high-quality output at every step.
Background
OpenSpec is a proposal-driven development system that manages the creation, review, and implementation of technical proposals through structured workflows. The idea itself is sound, but in practice, we found significant issues with using a single generic AI prompt.
The explore stage lacks context anchoring, causing AI explorations to deviate from the proposal scope; artifact generation quality is unstable, with design.md missing visual elements, proposal.md lacking code change tables, and tasks.md even including Git operations that shouldn't be there; responsibility boundaries are blurred, with unclear content requirements for different document types; prompts lack flexibility, unable to dynamically adjust AI behavior based on different scenarios.
These issues directly impact the efficiency and output quality of the OpenSpec workflow. There's really no other way but to modify the prompt templates ourselves. This article documents that period of work.
About HagiCode
The solution shared in this article comes from our practical experience in the HagiCode project. HagiCode is an AI-powered code assistant, and we extensively use the OpenSpec workflow to manage technical proposals during development. The agent layering strategy introduced here is exactly the optimization solution we summarized from practical use.
If you find this approach valuable, it means our engineering practices are pretty solid—HagiCode itself is worth paying attention to.
OpenSpec Workflow Analysis
The OpenSpec system contains multiple core stages, each with specific goals and constraints. Understanding the responsibility boundaries of these stages is the foundation for designing effective agent strategies.
┌─────────────────────────────────────────────────────────────────────┐
│ OpenSpec Workflow Stages │
├─────────────────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Explore │ -> │ New │ -> │ FF │ -> │ Apply │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Archive │ │ Sync │ │ Verify │ │ Status │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Each stage has completely different goals: The Explore stage requires a thinking posture, focused on information gathering; the New stage focuses on requirement analysis and solution design; the FF stage creates artifacts in batch by dependency order; the Apply stage transforms proposals into actual code. Using the same prompt template to drive these vastly different tasks is clearly unreasonable.
Prompt System Architecture
OpenSpec uses a templated prompt system, which provides the technical foundation for agent layering. Template files use .hbs (Handlebars/Scriban) format, paired with .json metadata files to define parameters and validation rules, supporting both Chinese and English.
The key design is the PromptScenario enumeration, which defines prompt scenarios for different stages:
public enum PromptScenario
{
OpenspecV1Explore, // Exploration stage
OpenspecV1New, // New proposal
OpenspecV1Ff, // Fast generation
OpenspecV1Apply, // Apply changes
OpenspecV1Archive // Archive
}
Each scenario has a corresponding independent template file, such as openspec-v1-explore.zh-CN.hbs and openspec-v1-ff.zh-CN.hbs, allowing specific constraints and guidance to be injected for different stages.
Parameterized Prompt Loading
Implementing dynamic parameter injection is the core of the entire system. FilePromptProvider is responsible for loading prompts based on scenarios and parameters:
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);
}
This design allows us to dynamically inject parameters at runtime, such as changeName and planningDirectionInstructions, without modifying the template file itself.
Dynamic Planning Direction Configuration
HagiCode implements a flexible planning direction system that allows users to select different directions for each generation. Each direction has an independent ID, description, and prompt fragment:
public static class ProposalPlanningDirections
{
private static readonly ProposalPlanningDirectionDefinition[] Catalog =
[
new(
ExploreId,
"Explore mode",
DefaultEnabled: true,
EnglishPromptFragment:
"- Explore mode: add an explicit exploration pass...",
ChinesePromptFragment:
"- 探索模式:在定稿工件之前增加明确的探索阶段..."),
// ... change-map, flowchart, prototype, architecture, sequence
];
public static NormalizedProposalPlanningDirections Normalize(
bool? enableExploreMode,
IReadOnlyList<PlanningDirectionOptionDto>? planningDirections)
{
// Merge default configuration with user custom configuration
}
}
Supported directions include: explore (exploration mode), change-map (change map), flowchart (interaction flowchart), prototype (UI prototype), architecture (architecture diagram), sequence (API sequence diagram). Users can freely toggle these directions, and the system dynamically generates corresponding prompt instruction blocks.
Use conditional statements in Handlebars templates to inject these instructions:
{{#if planningDirectionInstructions}}
## Planning Directions for This Generation
{{{planningDirectionInstructions}}}
{{/if}}
Clear Content Scope Constraints
The most critical improvement is defining clear content scope constraints for different document types, especially tasks.md. We added strict constraint conditions in the prompt:
### 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
Using normative language (MUST/SHALL) rather than suggestive language ensures AI strictly understands these constraints. For proposal.md and design.md, we also clarified their respective responsibility boundaries: proposal.md must include code change tables and UI prototype diagrams (when involving UI changes), while design.md must include architecture diagrams and data flow diagrams.
Exploration Stage Context Anchoring
The Explore stage problem is easily overlooked—AI explorations may completely deviate from the proposal scope. We address this through enhanced prompts:
## Explore Execution Principles
- **No documentation needed** - Exploration results need not be saved as independent documents
- **Information transfer** - After exploration is complete, collected information will be passed to the Proposal creation stage
- **Focus on thinking** - The value of exploration lies in information gathering, not document output
## Connection with Proposal Creation
The Explore stage occurs after proposal creation and before project code is written. After exploration is complete,
the system will guide you to create or populate the `proposal.md` file, and exploration-collected information will serve as the foundation for proposal content.
This clarifies the positioning of the Explore stage: it's a preliminary step for information gathering, not an independent document production phase. Once AI understands this, it can focus more on proposal-related knowledge exploration.
Implementation Guide
If you want to apply this solution in HagiCode, follow these steps:
-
Define planning directions: Define direction IDs, default states, and prompt fragments in
ProposalPlanningDirections.cs -
Template parameterization: Use conditional statements and variable injection in
.hbstemplates - Verify output: When enabling specific directions, check that corresponding artifacts contain expected content
- Test boundaries: Verify that disabling directions doesn't generate corresponding content and doesn't affect other directions
Note that template modifications should remain synchronized with upstream, and Chinese and English template structures should be consistent. Planning direction rendering should complete in microseconds to avoid performance impact.
Summary
The efficiency optimization of the OpenSpec workflow lies in understanding the differentiated needs of different stages. Through stage-specific agents, parameterized templates, and clear content constraints, we enable AI to produce high-quality output at every step.
This solution has been validated in HagiCode's practice—not only improving document quality but also reducing manual modification workload. If your team is also using a similar proposal-driven workflow, I hope these experiences provide some inspiration.
It's really just about breaking down the problem. Each stage has its characteristics, use the right method, and the problem naturally becomes simple.
References
- HagiCode project repository: github.com/HagiCode-org/site
- HagiCode official website: hagicode.com
- Official version demo video: www.bilibili.com/video/BV1z4oWB3EpY/
- One-click installation experience: docs.hagicode.com/installation/docker-compose
- Desktop quick installation: hagicode.com/desktop/
If this article helps you:
- Give it a like to help more people see it
- Come to GitHub and give us a Star
- Visit the official website to learn more
- Watch the demo video to understand complete features
- One-click installation to start experiencing
Public beta has begun, welcome to install and experience!
Top comments (0)