hrt-align-consistency-review
About hrt-align-consistency-review
hrt-align-consistency-review checks tempa-spec artifacts for consistency before code is written. It maps relationships across proposals, specs, designs, and tasks, verifies codebase claims, and incorporates human walkthrough feedback; a fresh-context review is added when ALIGN finds a HIGH issue.
Key features
- 01Check consistency across proposal, specs, design, and tasks
- 02Run strict OpenSpec validation and artifact lint
- 03Verify design and task claims against the codebase
- 04Classify findings by severity and resolution type
- 05Repeat review cycles with human walkthrough feedback
Use cases
- 01Check that specs and design agree before implementation
- 02Confirm design decisions are reflected in task groups
- 03Validate task dependencies and codebase references
- 04Run an independent re-check after a HIGH finding
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ hash-id/ openspec-schema --skill hrt-align-consistency-reviewAfter installing, type/hrt-align-consistency-reviewin Claude Code to confirm it loaded.
Details
From the project READMEhrt-align-consistency-review
Verify that every tempa-spec artifact is mutually consistent and faithful to the requirements BEFORE any code is written, and that a human has actually read them — not just that an agent checked them against each other.
One cycle: ALIGN (this agent checks cross-artifact consistency) then VERIFY (a fresh-context subagent re-checks ALIGN's own map and fixes — only when this cycle's ALIGN raised at least one HIGH finding) then WALKTHROUGH (the human is shown a digest led by specs and design and asked once whether anything needs to change). Feedback from WALKTHROUGH re-enters ALIGN. Repeat until a WALKTHROUGH round raises nothing new, or the user signs off early (see "Ending the loop"). Each cycle's number is reported as it starts. After the third cycle that doesn't end the loop, ask the user whether to continue or sign off — do not stop on your own.
ALIGN
- Re-read all artifacts: proposal.md, specs/**/*.md, design.md, tasks.md. Run
openspec validate --strictand thehrt-artifact-lintskill. The lint owns structure and coverage: spec structure, capability <-> spec file, designCovers:targets, every scenario covered by a task group (and every groupCovers:name real), every threat answered by a negative scenario or a named check, proposal size and shape. Fix every lint ERROR directly and record each as a MECHANICAL finding; if an ERROR has more than one valid fix (for example a scenario that several groups could deliver), record it as a DECISION finding instead. Note whether the lint ran clean, and keep itsSize facts:line for the WALKTHROUGH.design.mdis mandatory — its absence is a HIGH finding. - Build a consistency map: for each dimension below, list what you checked and what you found — BEFORE moving to classification. These are the dimensions that need judgement; the lint already covers the rest, so do not re-check it by hand unless the lint could not run.
- proposal <-> design and specs: both directions. Forward: every outcome in proposal.md's Why and every capability in Capabilities is carried by a scenario in specs and explained in design. Backward: specs and design add no capability or behaviour the proposal omits, and nothing listed under Out of Scope appears in them. The lint already checked that each capability has a spec file - here, judge only whether the content matches. LLM judgment only.
- specs <-> design (including seams): design explains how each requirement is met and contradicts none of them. LLM judgment only. Seams: every
#### Scenarioinspecs/**has a seam indesign.md's Shape / Seams section its tests could attach to. The lint in step 1 already checked that each seam'sCovers:target names a real requirement/scenario - here, judge only the forward direction (does each scenario have a seam its tests could attach to) and whether the attachment actually fits. Skip the seam half only when Shape / Seams is the one-line "no new code surface" note (pure config/data change). If the lint in step 1 raised a security-gate WARN (a trust-boundary keyword in proposal/specs but no[Threatentry and noSecurity pass: skipped - <reason>line), judge whether the boundary is real: a real one with no threat list is MEDIUM, and a skip reason that the specs contradict is MEDIUM. Even with no WARN, check that each trust boundary the specs touch (an upload, a login, a webhook) has a[Threatline: the lint is silenced by any single threat line, so an uncovered boundary is MEDIUM. - design <-> tasks: both directions. Forward: every Decision in design.md has a task that carries it out, and a prefactor the design records is an early group that the slices needing it depend on. Backward: no task builds beyond the design's scope or outside its seams, and groups are sized and ordered so each can be driven RED then GREEN (a group too coarse to demo, or one that needs another group's code without saying so, is a finding). The lint already checked scenario and threat coverage - do not repeat it. LLM judgment only.
- tasks graph: skip unless
tasks.mdhas anyDepends on:line. The lint in step 1 already checked the structure (malformed values, unknown ids, cycles) - here, judge only whether the declared graph is true, since declared dependencies are the only isolation between groups running at the same time: a group that needs another group's code or tests but does not list it inDepends on:, and two groups with no dependency path between them that would edit the same file (look at the filesdesign.md's Shape / Seams and the tasks name). A missing edge is the dangerous direction. - design/tasks -> codebase: every concrete claim design.md or tasks.md makes about the existing system (a function, method, module, file, endpoint, schema, or config it says already exists or must be touched) is checked against the actual codebase, not assumed. MUST use a tool (codegraph > codebase-memory-mcp > ripgrep) for existence; judge only whether the artifact's characterization of that code is accurate. Record each checked claim and its result in align.md. On cycle 2+, re-check only claims that are new or changed since the prior cycle — the codebase does not change during align (code is written in apply), so a claim verified in an earlier cycle and unchanged since is still valid.
- On cycle 2+: also fold in whatever the prior WALKTHROUGH round raised — treat each as its own item in the map, not a footnote.
- Rule for all dimensions above: mechanize only the existence/reference/structural half (does X exist, is X referenced, is the format right), never the semantic half (does X actually fulfill the intent). A keyword match is not a substitute for that judgment.
- STOP. Do not classify yet. Confirm the consistency map above is complete for all 5 dimensions (plus any carried-over walkthrough items) before proceeding.
- Classify every finding. Consequence gate first: a finding is HIGH or MEDIUM only if you can name what goes wrong downstream when it's unfixed — an implementer codes a contradiction wrong, a requirement ships untested,
applyfollows a misleading codebase claim. Everything else is LOW — e.g. "design.md and tasks.md use different words for the same thing" or "these requirements would read better regrouped" name no downstream break.- HIGH: a contradiction between artifacts; a design that adds a capability the proposal omits; a structural error that breaks OpenSpec parsing; an outcome stated in proposal.md's Why that no spec scenario exercises; a design/tasks claim about the codebase (a referenced function, module, file, or API) that doesn't match reality.
- MEDIUM: partial coverage; a non-trivial technical choice with no design decision; tasks too coarse or mis-ordered; a Decision with no task that carries it out; an edge case implied by the proposal but left unscenarioed; a scenario with no seam it could attach to; a task outside the design's scope or seams; a boundary the specs touch with no
[Threatline. - LOW: terminology drift, wording, formatting, ordering, minor omissions — anything real that failed the consequence gate.
A requirement being vague or untestable is the Structural Auditor's finding at
specstime, not analignfinding.
- Tag every finding MECHANICAL or DECISION:
- MECHANICAL: exactly one correct fix, no scope or intent judgement, AND a deterministic anchor — a grep/regex/count you can re-run to confirm before fixing (e.g. hashtag count, checkbox format, a kebab-case name mismatch, task reordering). "Obviously mechanical" isn't enough without that re-runnable check — a finding that fits the shape but has no anchor (e.g. "terminology unification" — deciding two terms mean the same thing; an "obvious" missing-scenario call) is DECISION instead.
- DECISION: more than one valid resolution, it touches scope or intent, or it fits MECHANICAL's shape but has no anchor (e.g. a design-vs-spec contradiction, an outcome with no scenario, a boundary with no threat line, plus the unanchored cases above). "Defer it" / "accept the drift" doesn't count as one of those valid resolutions — but a finding stays DECISION even with a clean fix in hand if a competent author could still pick differently.
- Show this cycle's findings grouped under HIGH / MEDIUM / LOW, each tagged MECHANICAL or DECISION, stating each problem plainly.
- Resolve them:
- MECHANICAL findings (any severity): fix directly and record what changed.
- Needs its own answer: every HIGH DECISION finding, and any DECISION finding that changes scope
proposal.mdalready settled, is a one-way door (a data migration or destructive schema change, deletion of stored data, a change to a published API or event contract, a config or flag removal other code reads, or a step that has to be undone by hand), or is a High-severity security trade-off. Do NOT edit silently, and do NOT exit the skill to report them. Show all of them together in one message. For each: state the tradeoff neutrally first (what conflicts, and the valid resolution options), THEN your recommended resolution (grounded in proposal.md as the source of intent) — recommendation second, not first, so the user weighs the tradeoff before seeing your answer. The user answers each one separately; a bare "ok" does not cover them. Get an actual resolution or an explicit, reasoned defer for each one — do not move on with a HIGH unaddressed. - Digest: every other DECISION finding (MEDIUM and LOW) goes into one digest message shown after the above are resolved: each with the recommended resolution and a one-line reason. "ok" accepts all of it; the user names any exception. Show at most 5 LOW findings; the rest stay in align.md's Known Issues and the digest says how many. Findings left unresolved at the end are listed in Known Issues ("no action needed unless you want it"). They do not block the cycle.
- Both messages MUST follow the
plain-language-writingskill's COMMS rules.
- Append this cycle's ALIGN results to align.md: the findings (severity x mechanical/decision), the mechanical fixes applied, and the decisions the user made (including any explicit defer, with the user's stated reason). Give every recorded decision and resolved HIGH a source pointer — document and section (e.g. "proposal.md > What Changes");
applyreads align.md first and follows these to the exact passage. If the user says a check was wrong or noisy (a lint rule, a dimension, a review pass, the change-size question), add one line under Gate Records: the gate, its input, its output, and what the user did (accepted, overruled, edited). This keeps the gate in force and gives the maintainer data. This prose MUST follow theplain-language-writingskill's ARTIFACT rules. - Every HIGH issue needs one of two outcomes before ALIGN is done: fixed (mechanically or via the user's chosen resolution), or explicitly ruled out of scope by the user with a recorded reason — that counts as resolved, not deferred. A bare "let's deal with it later" is not enough; keep step 8's resolution conversation open on that item until it lands on one of these two outcomes. Only once every HIGH from this cycle's map has one of them, proceed to VERIFY.
VERIFY
ALIGN classifies its own findings and applies its own MECHANICAL fixes with nothing independent checking that work. VERIFY closes that gap with one fresh-context re-check, spent where it pays: on a cycle that found a HIGH.
Trigger. Run VERIFY only if this cycle's ALIGN raised at least one HIGH finding. Otherwise skip it and record the skip in align.md. A MEDIUM or LOW finding, or a lint ERROR, does not trigger it. Measured on 47 real runs, this trigger skips some runs that would have found something new, and the WALKTHROUGH is the backstop; if misses show up in practice, widen the trigger.
- Spawn a subagent with no memory of the ALIGN pass above: it receives only the artifacts as they now stand (post-fix) and this skill's ALIGN step 2 checklist. It does NOT receive the consistency map, findings, or resolutions ALIGN produced.
- It re-derives its own consistency map against the same 5 dimensions (plus carried-over walkthrough items, if any) and reports back: any HIGH it finds that ALIGN's map missed — including a finding ALIGN placed at LOW that a fresh read would call HIGH or MEDIUM (a consequence the gate missed) — and any MECHANICAL fix ALIGN applied that it can verify is actually correct (fix matches what the artifact now needs) vs. still wrong or incomplete.
- If VERIFY finds nothing new: proceed to WALKTHROUGH.
- If VERIFY finds a HIGH ALIGN missed, or a MECHANICAL fix that didn't actually resolve the finding: fold it into this cycle's map (append to align.md same as any ALIGN finding), resolve it via ALIGN step 8's rules (MECHANICAL fixed directly, a HIGH DECISION shown for its own answer), then proceed to WALKTHROUGH — do not re-run VERIFY again within the same cycle; a second miss is caught by the next cycle's VERIFY if WALKTHROUGH reopens one.
- If a subagent cannot be spawned in the current environment: state that VERIFY could not run and ask the user whether to proceed to WALKTHROUGH without it. Do not silently skip this step.
WALKTHROUGH
ALIGN and VERIFY verify the artifacts are consistent with each other. Neither verifies a human has read them — both can find nothing worth surfacing while nobody but an agent ever looked at the content. Run WALKTHROUGH once VERIFY is done (or skipped), every cycle, including the first one, even when ALIGN and VERIFY found nothing at all.
One round, one question, in the order the reviewer reads:
- Show a one-page digest, in this order:
- Specs: one line per capability — what it requires, and how many scenarios it has.
- Design: the Decisions headlines, the Risks / Trade-offs threat lines, and Shape / Seams by name. When it lists real seams (not "no new code surface"), ask the user to read that section itself: the seams are the test boundaries the implementation is built against, and a wrong one is easy to skim past because it reads as a signature, not a behavior.
- Coverage table: one row per scenario: scenario -> task group (from
tasks.mdCovers:) -> seam (fromdesign.mdShape / Seams). Built from the links the lint already checked; a scenario with no seam shows "no seam" and was already raised as a finding. - Tasks and proposal: one line each, naming the file only; they sit behind the specs and design the reviewer reads first.
- Size facts: the lint's
Size facts:line as plain facts (capabilities, scenarios, task groups). No verdict.
- Ask a single generic question covering the whole digest: whether there's anything across these files the user wants changed — not a yes/no confirmation. An empty "nothing" answer is a valid outcome. This question MUST follow the
plain-language-writingskill's COMMS rules. - Record the round in align.md's Walkthrough log: the files shown, tagged with the cycle number, and the user's answer verbatim (including a "nothing" answer).
Do not infer the round was completed from silence, or from the user answering some other question in the conversation. The round needs its own recorded answer covering the whole digest.
Ending the loop
After a WALKTHROUGH round completes (the round's question answered), decide:
- Clean round: the answer was "nothing." The loop ends. Proceed to apply.
- Feedback raised: the answer raised something. Start a new cycle — take that feedback into the next ALIGN's consistency map (step 2), resolve it there (HIGH/MEDIUM/LOW, MECHANICAL/DECISION, same as any other finding), then run WALKTHROUGH again with a fresh round.
- User signs off early: the user may explicitly state the artifacts are ready and no further cycles are needed. This is only valid after at least one full WALKTHROUGH round has completed — it cannot substitute for the first walkthrough, only end the loop after one has actually happened. Record the sign-off (cycle number, user's statement) in align.md and stop.
- Three cycles reached: after the third cycle completes without the loop ending, ask the user whether to continue or sign off (a WALKTHROUGH sign-off is still valid here). Record their answer. This is a checkpoint, not a cap — the loop continues if they want it to.
Do NOT proceed to apply on any other basis — not on ALIGN alone, not on a partial walkthrough, not on silence.