Hybrid Specification Format (HSF v6)
Generate well-structured hybrid specifications from user requests. Given a domain, complexity indicators, and user intent, produce a specification that uses prose instructions within an XML envelope (<purpose>, <scope>, <config>, <instructions>, <rules>, <errors>, <examples>), JSON configuration in <config> blocks, XML <route> decision tables for multi-branch logic, <output-schema> for structured output specification, $variable threading for complex data flows, and consolidated error tables. Follows the correct tier format and passes structural validation.
Not in scope: executing the generated specs, providing domain expertise for spec content, maintaining the validator script, runtime interpretation of specs
Inputs
user_request: string - what the user wants specified - requireddomain: string - subject area for the specification - requiredcomplexity_indicators: signals that inform tier selection (concern count, shared structures, overlapping rules, stateful behavior) - optionaltarget_tier: enum [micro, standard, complex] - explicit tier override - optional
Outputs
specification: string - the complete HSF v6 specification documentvalidation_result: pass/fail/warnings from the validatorextracted_assets: reference material extracted to assets/ if applicable
Tier Selection
When the user explicitly requests a tier via target_tier, use that tier regardless of complexity indicators. When a spec exceeds its tier's line budget, suggest promotion to the next tier.
Instructions
How to Select a Tier
Use the <route> table above. Default to standard when signals are ambiguous. A micro spec that grows past 80 lines SHOULD become standard. A complex spec with only one concern after refactoring SHOULD demote to micro.
How to Structure the Document
Always required (all tiers):
<purpose>(1-3 sentences — the opening section of the spec)<scope>(IN/OUT as bullet lists, or a single "Not in scope" line for micro)<config>(if any static params exist — use<config>with JSON body for 3+ values, or inline in prose for fewer)<instructions>(the actual procedure — in prose, with clear###phase/step headers inside)<errors>(as a table: Error | Severity | Action)
Required for Standard and Complex only:
<inputs>/<outputs>(typed parameter lists)<rules>(grouped by concern, as prose with bold headers — for cross-cutting rules that apply across ALL phases only)<examples>(edge cases only, with pass/fail)
Optional (include only when they add value):
<route>tables (only for 3+ branch decision logic)<config>blocks (only when 3+ configuration values exist)<output-schema>blocks (for specifying structured output format)- $variable threading (only when data flows between phases are complex enough to need explicit tracking)
- Worked examples with derivation chains (only for specs where chain integrity matters)
Removed entirely — do NOT include:
- Meta section (version goes in YAML frontmatter if needed)
- Notation section (symbols are self-evident or explained inline on first use)
- Types section (inline field descriptions where they're used)
- Functions section (logic goes in Instructions or Rules)
- Precedence section (resolve conflicts in the prose directly)
- Dependencies section (agent discovers these from context)
- Changelog section (use git history; version in frontmatter is sufficient)
Forbidden syntax — do NOT use:
## Sectiontop-level headers (use XML tags:<purpose>,<scope>, etc.)@configblocks (use<config>with JSON body)@routetables (use<route>with XML<case>elements)$config.keyreferences (useconfig.keywithout the$prefix)
How to Write Rules
Write rules as prose with ### sub-headers and bold list items inside <rules>. Use RFC 2119 keywords (MUST, SHOULD, MAY) for precision. State each constraint ONCE, in the section where it applies.
Do NOT use:
**BEHAVIOR**or**RULE**keywords- WHEN/THEN/ELSE syntax
- Scattered inline ERROR declarations after individual rules
Do use:
###headers for rule groups (inside<rules>)- Bold list items (
- **Rule name:**) for individual rules - Natural sentences that combine condition and action
- Consolidated error table inside
<errors>at the end
Example of correct rule writing:
<rules>
### Critical Thinking Rules
Apply throughout ALL phases:
- **Professional skepticism:** When a speaker claims something is easy, possible, or valuable — ask: what evidence supports this? What could go wrong? Document both scenarios.
- **Intellectual honesty:** Challenge claims. Identify logical flaws. Provide counterarguments not considered. Flag overconfidence.
</rules>
How to Write Procedures / Instructions
Write procedures as prose inside <instructions> with ### phase headers. Use numbered lists for ordered steps, bullet lists for parallel concerns. Bold key terms.
Do NOT use:
**PROCEDURE**or**STEP**keywords→ $variableoutput declarations (unless data flow between phases is genuinely complex)- References to BEHAVIOR blocks (inline the actual rules where they apply)
Do use:
###headers for phases:### Phase 1: Extraction- Numbered lists for sequences within a phase
- Inline constraints where they apply instead of referencing a separate rules section
- $variable threading only when explicit data flow tracking prevents bugs
Example of correct instruction writing:
<instructions>
### Setup
Run `mkdir -p /tmp/scratchpad/`. Create all 6 tasks upfront using TaskCreate.
### Phase 1: Extraction → `phase1_extraction.md`
Read the entire transcript (no skimming). Produce a scratchpad artifact containing:
- **Labeled extracted ideas:** E1, E2, E3... (explicit and implicit)
- **Frameworks and philosophies** identified
- **Critical analysis** of at least 3 major claims
</instructions>
How to Use <route> and <config>
These are the decision-table and configuration mechanisms of HSF.
<route> decision tables:
- Use ONLY for 3+ branch decision logic
- Fewer branches → use a prose conditional instead
- Must specify mode:
mode="first_match_wins"ormode="all_matches" - SHOULD include a
<default>element when a meaningful default exists
<config> blocks:
- Use ONLY when 3+ configuration values exist
- Body MUST be valid JSON
- Keys MUST use snake_case
- Values MUST be literals (strings, numbers, arrays, nested objects)
- Reference with
config.keyorconfig.nested.key(no$prefix) <config>is for static values only — use $variable threading for runtime data
How to Use <output-schema>
Use <output-schema> to specify structured output formats inline within <instructions>. This is useful when the spec produces JSON, structured objects, or machine-readable output.
When to use:
- SHOULD include for standard and complex tier specs that produce structured output
- MAY include for micro tier specs when output format clarity adds value
- Place inside
<instructions>, in the phase that produces the output
Syntax:
<output-schema format="json">
{
"field_name": "string",
"score": "float 0.0-1.0",
"optional_field": "string | null",
"items": ["string"]
}
</output-schema>
Type annotations: Use descriptive types like "string", "integer", "float 0.0-1.0", "boolean", "string | null", ["string"] (array of strings), or nested objects.
How to Write Examples
Edge cases only — boundary conditions, error paths, non-obvious behavior. If the happy path is obvious from the rules, do not exemplify it. Use the compact single-line format or multi-line worked examples. Place inside <examples>.
Compact format: example_name: input_description → expected_outcome
Worked examples (for specs where derivation chain integrity matters):
[good_example]:
Input: [concrete values]
Expected: [concrete outcome]
Why: [explain which rule applies and the reasoning]
How to Write Errors
Consolidate ALL errors into a single table inside <errors> at the end of the spec:
<errors>
| Error | Severity | Action |
|-------|----------|--------|
| missing_field | critical | halt and report which field is missing |
| over_budget | warning | review for redundancy, suggest promotion |
| empty_result | info | generate empty report, log the date range |
</errors>
Severity values: critical (halt processing), warning (continue with degradation), info (log only).
Do NOT scatter error declarations inline after individual rules.
Rules
Format Compliance
- XML envelope required: MUST use XML tags (
<purpose>,<scope>,<config>,<instructions>,<rules>,<errors>,<examples>) for top-level sections. MUST NOT use## Sectionmarkdown headers for top-level sections.###sub-headers are used for structure within sections. - No legacy syntax: MUST NOT use
@config,@route, or$config.keyanywhere in the spec. Use<config>with JSON,<route>with XML cases, andconfig.keyreferences instead. - No formal wrappers: MUST NOT use
**BEHAVIOR**,**RULE**,**PROCEDURE**, or**STEP**keywords anywhere in the spec. Use###headers and bold list items instead. - No empty sections: If a section would say "none" or be blank, omit it entirely. Do not template the absence of content.
- No duplicate constraints: Each rule MUST be stated once, in the section where it applies. No separate "define" then "reference" pattern.
- No notation legend: Symbols ($, →) are self-evident. Explain inline on first use only if genuinely non-obvious for the target audience.
- Errors as consolidated table: All errors MUST appear in a single
<errors>table, not scattered inline after rules. - RFC 2119 keywords preserved: MUST, SHOULD, MAY MUST be capitalized when used with their operative meanings.
Notation Usage
<route>only for 3+ branches: Fewer branches → prose conditional. The form is determined by branch count, not author preference.<config>only for 3+ values: Fewer values → inline in the text.- $variable threading only for complex flows: Most specs do not need it. "Phase 2 reads the output of Phase 1" is clear enough in prose.
- No
<route>outside instructions:<route>tables belong inline in the<instructions>section or in a dedicated routing section — not in separate rule blocks.
Line Budget
- Micro specs SHOULD stay within 20-80 lines
- Standard specs SHOULD stay within 80-200 lines
- Complex specs SHOULD stay within 200-400 lines
Quality Assurance
- Run the validator when the spec is complete:
python3 config.validator_path <spec.md>and fix all failures - Concrete examples only: Examples MUST use concrete values — never placeholders. Cover edge cases and boundary conditions only.
- No ambiguity: Rules MUST NOT use vague language like "handle appropriately", "use common sense", or "extract relevant fields". Specify each case explicitly.
- Reference extraction: When reference/lookup data exceeds 10 lines, extract to
assets/and add a one-line pointer. - YAML frontmatter: When the specification is a Claude Code skill, it MUST include YAML frontmatter with
nameanddescriptionfields.
Quality Checklist
| Check | Rule |
|---|---|
| XML envelope used | Top-level sections use XML tags, not ## headers |
| No legacy syntax | No @config, @route, or $config.key anywhere |
| No empty sections | If a section would say "none" or be blank, omit it entirely |
| No duplicate constraints | Each rule stated once, in the section where it applies |
| No formal wrappers on prose | No **BEHAVIOR**, **RULE**, **PROCEDURE**, **STEP** keywords. Use ### headers and bold list items. |
<route> only for 3+ branches |
Fewer branches → prose conditional |
<config> only for 3+ values |
Fewer values → inline in the text |
Errors in <errors> table |
Not scattered inline after rules |
| RFC 2119 keywords preserved | MUST, SHOULD, MAY still capitalized for precision |
| Line budget compliance | Micro ≤80, Standard ≤200, Complex ≤400 |
| Edge-case examples only | No happy-path examples |
| No notation legend | Symbols explained inline on first use if non-obvious |
Errors
| Error | Severity | Action |
|---|---|---|
| formal_wrapper_used | critical | Remove BEHAVIOR/RULE/PROCEDURE/STEP keywords; rewrite as prose with ### headers |
| empty_section | critical | Delete the empty section entirely |
| legacy_syntax_used | critical | Replace @config with <config> JSON, @route with <route> XML, $config.key with config.key |
| missing_xml_envelope | critical | Wrap top-level sections in XML tags; remove ## headers |
| duplicate_constraint | warning | Remove the duplicate; keep only the instance in the section where it applies |
| route_under_threshold | warning | Convert <route> with fewer than 3 branches to a prose conditional |
| config_under_threshold | warning | Inline <config> values referenced fewer than 3 times |
| over_budget | warning | Review for redundancy, extract reference material, consolidate rules |
| vague_rule | critical | Rewrite with specific conditions and actions |
| missing_error_table | warning | Add consolidated error table inside <errors> at end of spec |
| validation_failure | critical | Fix structural issues identified by the validator |
| config_key_mismatch | critical | Add key to <config> or fix the reference |