Spec Sync Integration
spec-sync is a tool that keeps Markdown module specs aligned with the code they describe. Merlin uses it for two things:
- Read specs at task start to inject as planning constraints.
- Verify specs at task end as part of the verify lane.
How Specs Look
Every spec is a Markdown file in specs/<module>/<module>.spec.md with
YAML frontmatter:
---
module: agent
version: 2
status: draft
files:
- crates/merlin-core/src/agent.rs
- crates/merlin-core/src/spec_loader.rs
db_tables: []
depends_on:
- provider
- fledge-protocol
---
# Agent
## Purpose
The agent module implements Merlin's core state machine...
## Public API
...
## Invariants
1. State always starts and ends at Idle...
...
The required sections are configured in .specsync/config.toml:
required_sections = [
"Purpose",
"Public API",
"Invariants",
"Behavioral Examples",
"Error Cases",
"Dependencies",
"Change Log",
]
enforcement = "strict"
Reading Specs (Task-time)
Agent::load_relevant_specs(task) runs:
fledge plugins run specsync-list→ list of registered modules.spec_loader::select_relevant_specs(task, &all, top_n=3)→ top matches by token overlap.- For each pick:
fledge plugins run specsync-read <name>→ full markdown. spec_loader::extract_constraint_sections(name, content)→ constraint-bearing sections only.Context::add_spec_constraint(text)→ injected into the system prompt under “Active Spec Constraints”.
See Spec-aware Planning for the user-facing view.
Verifying Specs (Verify-lane)
fledge.toml wires spec-check into the verify lane:
[lanes.verify]
steps = ["fmt-check", "lint", "test", "integration-test", "spec-check"]
[tasks]
spec-check = "fledge spec check"
fledge spec check exits non-zero on any of:
- Required section missing from a registered spec.
- File listed in spec frontmatter doesn’t exist.
- Code file in
source_dirsreferences no spec (underenforcement = "strict").
When verify_before_complete = true and spec-check fails, the
verifier output is fed back to the LLM as part of the retry message
(see Verification & Retries).
Updating Specs
If you change a public API in code, the corresponding spec needs to
move with it. Bump the spec’s version, add a row to ## Change Log, and update the API tables. The spec-check step won’t catch
staleness — it catches missing sections and missing files. Discipline
matters.
The default agent system prompt explicitly tells the LLM “Read relevant specs before modifying code” — and Merlin runs spec-check after every change. The combination is what makes specs binding rather than aspirational.