Merge EARS Specifications
You merge two or more EARS specification .md files into one standalone EARS spec.
The output must read as if it were authored as a single document — not a stapled-together pile of
files — while losing nothing: every business rule, entity, concept, error message, and source
reference from every input survives the merge.
You are structure-aware but project-neutral. You assume the input files follow the standard
EARS section layout (described in references/section-taxonomy.md), but you hardcode nothing about
any particular codebase, framework, or domain. Whatever domains the inputs describe, you merge them
faithfully.
The four governing decisions
- Consolidate & dedupe, but keep every reference. Overlapping content (shared cross-cutting
rules, shared entities, repeated concepts, identical error rows, identical business rules) is
merged into a single copy — but the surviving copy's
> **Source files:** annotation is the
union of the source-file lists from every copy it absorbed. Origin information is never lost.
- Ask for the merged system name. Each input scopes its statements to its own subject (e.g.
"the Group Management system", "the Member Management system"). Ask the user what the merged
system should be called, then rewrite every statement's subject to that one name.
- Flag conflicts, never drop them. When two inputs genuinely disagree (same entity described
with different property types/constraints, contradictory rules, same error condition mapped to
different messages), keep both versions and annotate them with a
[NEEDS REVIEW] marker that
names the conflicting sources. Guessing a winner is forbidden.
- Bias toward lossless. When you cannot confidently tell whether two statements express the
same rule, keep both. Over-keeping is a minor cosmetic cost; silently dropping a real
requirement corrupts the source of truth.
Workflow
Step 0 — Gather inputs (do not assume)
- Which files. Take the EARS files to merge from the user's request or arguments (paths or
globs). If none were given, list the candidate
.md files (e.g. in docs/ears/) and ask which
to combine. You need at least two.
- Merged system name. Ask the user for the system name every merged statement should use (e.g.
"the Member & Group Management system"). This is decision #2 — do not invent it silently.
- Output path. Default to
docs/ears/<MergedName>-EARS-Specification.md, derived from the
system name, in the same directory as the inputs. Confirm or let the user override. Overwrite an
existing file of that name.
Read every input file in full before writing anything. You cannot merge what you have not read.
Step 1 — Parse each input into canonical sections
Split each file by its markdown headings into the canonical section taxonomy. Read
references/section-taxonomy.md for the full section list and the exact merge rule for each one.
The taxonomy, in order:
- Title + front-matter blockquote
- Document Conventions
- System Overview
- Cross-Cutting Requirements (sub-blocks: Audit and Record Lifecycle; Authentication and
Authorisation; Request Handling; Operational Cross-Cuts; Error Response Format + its
error-condition→message table)
Module: sections (one or many; each may contain subsections, > **Source files:**
annotations, and **Field-level validation — …:** blocks)
- Domain Entities and Properties
- Domain Concepts and States
- Business Rules Summary (numbered)
- Open Questions
- Extraction Summary (metrics table + per-file ledger)
- Review by Developer (code)
- Review by Developer (business requirements)
Any heading you encounter that does not map to the taxonomy is carried through, never dropped —
collect such content and emit it under an ## Additional Sections heading near the end (before the
Review-by-Developer sections), noting which input it came from.
Step 2 — Merge section by section
Apply references/section-taxonomy.md's per-section rules. Summary:
- Title / front-matter. New title:
<MergedName> Business Requirements Specification (EARS).
In the blockquote, set > **System name used in statements:** the <MergedName> system; set
> **Source Entry Point(s):** to the union of all inputs' entry points; add
> **Merged from:** listing the input filenames and the merge date. Keep the standard
Format/Purpose/Note boilerplate.
- Document Conventions. Identical across well-formed inputs — emit once. If an input adds a
marker the others lack, include it.
- System Overview. Write one cohesive overview spanning all merged domains. Do not paste
the inputs' overviews back to back; synthesize a unified narrative that still names each domain's
distinct responsibilities.
- Cross-Cutting Requirements. Within each sub-block, gather every statement, normalize the
subject to the merged name, then dedupe rules that are semantically the same. Surviving statements
use the merged name. When two cross-cutting rules cover the same topic but differ in substance,
keep both and flag (decision #3, #4).
- Error-condition → message table. Union all rows. Dedupe identical
(condition, message)
pairs. If the same condition maps to different messages across inputs, emit a row for each
and append [NEEDS REVIEW: <SourceA> vs <SourceB>] so the divergence is visible.
- Module sections. Concatenate all
## Module: sections from all inputs in a sensible order
(group related domains together). Keep each module's > **Source files:** annotations and
**Field-level validation — …:** blocks intact and verbatim (these are not statement prose,
so they keep their original file paths). Rewrite only the statement-subject to the merged name.
If two inputs define a module with the same name, merge their subsections under one heading
and flag any contradictory statements.
- Domain Entities and Properties. Dedupe shared entities. Match entities by the domain file
in their
> **Source files:** line, not by heading text — the same entity often appears under
different headings across inputs (e.g. "Member" vs "MemberInfo", "Project" vs "ProjectInfo",
"Domain Status" vs "DomainStatus") while pointing to the same source file.
- Same entity, identical property table → keep one copy; set its
> **Source files:** to the
union of every copy's source files (decision #1).
- Same entity, differing tables → emit the superset of properties (union of rows). For any
property whose Type/Meaning/Constraints conflict between inputs, keep both descriptions and
append
[NEEDS REVIEW: <SourceA> vs <SourceB>] to that row. Still union the source files.
- Prefer the richer heading/description when names differ; you may note the alternate name.
- Domain Concepts and States. Same dedupe-by-meaning approach (e.g. Applicable Gender, Member
Status, Data/Domain Status, Project Association Type recur across inputs). Identical → keep one +
union refs; differing → keep both + flag.
- Business Rules Summary. Concatenate all rules, dedupe identical ones, then renumber
contiguously from 1. Keep conflicting rules and flag them.
- Open Questions. Union and dedupe. Preserve any
[NEEDS REVIEW] breadcrumb footers verbatim.
- Extraction Summary. Combine into one summary: sum the numeric metrics (controllers,
action services, statement-type tallies, etc.), union plugins/areas traced, and concatenate
the per-file coverage ledgers. Add a line:
Merged on <date> from <N> source specifications: <list>.
- Review by Developer (code) and Review by Developer (business requirements). Keep both
placeholder sections. Concatenate any non-empty findings from the inputs under the matching
heading; if all inputs are empty, keep the single empty placeholder.
How to decide two statements are "the same rule"
Normalize away the system-name subject and trivial wording differences (articles, "shall"/"must"
phrasing, British/American spelling). If what remains is the same condition acting on the same
subject producing the same outcome, they are duplicates → keep one. If the condition, the subject
entity, the threshold, or the outcome differs in any substantive way, they are not duplicates →
keep both (and flag if they appear to contradict). When genuinely unsure, keep both (decision #4).
Step 3 — Self-check before finishing
Run the bundled checker against your output and fix anything it reports:
python3 ~/.claude/skills/merge-ears/scripts/check_merged_spec.py <output-file> \
--inputs <input1> <input2> [...] --system-name "<MergedName>"
It verifies the structural invariants: no duplicate entity headings, contiguous Business-Rules
numbering, no duplicate (condition, message) error rows, every [NEEDS REVIEW] marker names its
sources, and the merged system name is the subject used throughout (reporting any leftover original
subjects). Treat its findings as a checklist — resolve each before declaring the merge done.
Then report to the user: the output path, how many statements/entities/rules came in vs. went out
(showing what was deduped), and a list of every [NEEDS REVIEW] conflict you flagged so they know
what needs a human decision.
Anti-patterns (do not do these)
- Stapling files together. Four overviews, four Cross-Cutting blocks, the Country entity four
times — that is concatenation, not a merge. Consolidate.
- Dropping a source reference during dedupe. The whole point of decision #1: the surviving copy
must carry the union of source files. A reader must still be able to trace any rule back.
- Picking a winner in a conflict. When inputs disagree, you flag — you never quietly choose.
- Keeping mixed system-name subjects. After the merge, every statement says the one merged
system name. Leftover "the Group Management system" sentences are a bug.
- Rewriting
> **Source files:** paths into prose or "merged-name" form. Those annotations are
not statements; they keep their literal file paths (just unioned where entities were deduped).
1---2name: merge-ears-23description: Merge, combine, or consolidate two or more EARS (Easy Approach to Requirements Syntax) specification .md files into a single coherent EARS spec. Use this whenever the user wants to unify several requirement/EARS spec files — e.g. "merge these EARS specs", "combine the Member and Group specifications into one", "consolidate docs/ears/*.md into a single document", or any request to fold multiple per-domain/per-controller spec files into one. The skill deduplicates overlapping cross-cutting rules, entities, concepts, error-message rows and business rules (preserving every source reference), flags genuine conflicts for review instead of silently dropping them, and is project-neutral — it works on any set of EARS files that follow the standard section layout, not just one codebase.4---56# Merge EARS Specifications78You merge **two or more EARS specification `.md` files** into **one** standalone EARS spec.9The output must read as if it were authored as a single document — not a stapled-together pile of10files — while losing **nothing**: every business rule, entity, concept, error message, and source11reference from every input survives the merge.1213You are **structure-aware but project-neutral**. You assume the input files follow the standard14EARS section layout (described in `references/section-taxonomy.md`), but you hardcode nothing about15any particular codebase, framework, or domain. Whatever domains the inputs describe, you merge them16faithfully.1718## The four governing decisions19201. **Consolidate & dedupe, but keep every reference.** Overlapping content (shared cross-cutting21 rules, shared entities, repeated concepts, identical error rows, identical business rules) is22 merged into a single copy — but the surviving copy's `> **Source files:**` annotation is the23 **union** of the source-file lists from every copy it absorbed. Origin information is never lost.242. **Ask for the merged system name.** Each input scopes its statements to its own subject (e.g.25 "the Group Management system", "the Member Management system"). Ask the user what the merged26 system should be called, then rewrite **every** statement's subject to that one name.273. **Flag conflicts, never drop them.** When two inputs genuinely disagree (same entity described28 with different property types/constraints, contradictory rules, same error condition mapped to29 different messages), keep **both** versions and annotate them with a `[NEEDS REVIEW]` marker that30 names the conflicting sources. Guessing a winner is forbidden.314. **Bias toward lossless.** When you cannot confidently tell whether two statements express the32 *same* rule, keep both. Over-keeping is a minor cosmetic cost; silently dropping a real33 requirement corrupts the source of truth.3435---3637## Workflow3839### Step 0 — Gather inputs (do not assume)4041- **Which files.** Take the EARS files to merge from the user's request or arguments (paths or42 globs). If none were given, list the candidate `.md` files (e.g. in `docs/ears/`) and ask which43 to combine. You need **at least two**.44- **Merged system name.** Ask the user for the system name every merged statement should use (e.g.45 "the Member & Group Management system"). This is decision #2 — do not invent it silently.46- **Output path.** Default to `docs/ears/<MergedName>-EARS-Specification.md`, derived from the47 system name, in the same directory as the inputs. Confirm or let the user override. Overwrite an48 existing file of that name.4950Read every input file **in full** before writing anything. You cannot merge what you have not read.5152### Step 1 — Parse each input into canonical sections5354Split each file by its markdown headings into the canonical section taxonomy. Read55`references/section-taxonomy.md` for the full section list and the exact merge rule for each one.56The taxonomy, in order:57581. Title + front-matter blockquote592. Document Conventions603. System Overview614. Cross-Cutting Requirements (sub-blocks: Audit and Record Lifecycle; Authentication and62 Authorisation; Request Handling; Operational Cross-Cuts; Error Response Format + its63 error-condition→message table)645. `Module:` sections (one or many; each may contain subsections, `> **Source files:**`65 annotations, and `**Field-level validation — …:**` blocks)666. Domain Entities and Properties677. Domain Concepts and States688. Business Rules Summary (numbered)699. Open Questions7010. Extraction Summary (metrics table + per-file ledger)7111. Review by Developer (code)7212. Review by Developer (business requirements)7374Any heading you encounter that does not map to the taxonomy is **carried through**, never dropped —75collect such content and emit it under an `## Additional Sections` heading near the end (before the76Review-by-Developer sections), noting which input it came from.7778### Step 2 — Merge section by section7980Apply `references/section-taxonomy.md`'s per-section rules. Summary:8182- **Title / front-matter.** New title: `<MergedName> Business Requirements Specification (EARS)`.83 In the blockquote, set `> **System name used in statements:** the <MergedName> system`; set84 `> **Source Entry Point(s):**` to the union of all inputs' entry points; add85 `> **Merged from:**` listing the input filenames and the merge date. Keep the standard86 Format/Purpose/Note boilerplate.87- **Document Conventions.** Identical across well-formed inputs — emit once. If an input adds a88 marker the others lack, include it.89- **System Overview.** Write **one** cohesive overview spanning all merged domains. Do not paste90 the inputs' overviews back to back; synthesize a unified narrative that still names each domain's91 distinct responsibilities.92- **Cross-Cutting Requirements.** Within each sub-block, gather every statement, normalize the93 subject to the merged name, then dedupe rules that are semantically the same. Surviving statements94 use the merged name. When two cross-cutting rules cover the same topic but differ in substance,95 keep both and flag (decision #3, #4).96- **Error-condition → message table.** Union all rows. Dedupe identical `(condition, message)`97 pairs. If the **same condition** maps to **different messages** across inputs, emit a row for each98 and append `[NEEDS REVIEW: <SourceA> vs <SourceB>]` so the divergence is visible.99- **Module sections.** Concatenate all `## Module:` sections from all inputs in a sensible order100 (group related domains together). Keep each module's `> **Source files:**` annotations and101 `**Field-level validation — …:**` blocks **intact and verbatim** (these are not statement prose,102 so they keep their original file paths). Rewrite only the statement-subject to the merged name.103 If two inputs define a module with the **same name**, merge their subsections under one heading104 and flag any contradictory statements.105- **Domain Entities and Properties.** Dedupe shared entities. **Match entities by the domain file106 in their `> **Source files:**` line, not by heading text** — the same entity often appears under107 different headings across inputs (e.g. "Member" vs "MemberInfo", "Project" vs "ProjectInfo",108 "Domain Status" vs "DomainStatus") while pointing to the same source file.109 - Same entity, identical property table → keep one copy; set its `> **Source files:**` to the110 **union** of every copy's source files (decision #1).111 - Same entity, differing tables → emit the **superset** of properties (union of rows). For any112 property whose Type/Meaning/Constraints **conflict** between inputs, keep both descriptions and113 append `[NEEDS REVIEW: <SourceA> vs <SourceB>]` to that row. Still union the source files.114 - Prefer the richer heading/description when names differ; you may note the alternate name.115- **Domain Concepts and States.** Same dedupe-by-meaning approach (e.g. Applicable Gender, Member116 Status, Data/Domain Status, Project Association Type recur across inputs). Identical → keep one +117 union refs; differing → keep both + flag.118- **Business Rules Summary.** Concatenate all rules, dedupe identical ones, then **renumber119 contiguously from 1**. Keep conflicting rules and flag them.120- **Open Questions.** Union and dedupe. Preserve any `[NEEDS REVIEW]` breadcrumb footers verbatim.121- **Extraction Summary.** Combine into one summary: **sum** the numeric metrics (controllers,122 action services, statement-type tallies, etc.), **union** plugins/areas traced, and **concatenate**123 the per-file coverage ledgers. Add a line: `Merged on <date> from <N> source specifications:124 <list>`.125- **Review by Developer (code)** and **Review by Developer (business requirements).** Keep both126 placeholder sections. Concatenate any non-empty findings from the inputs under the matching127 heading; if all inputs are empty, keep the single empty placeholder.128129#### How to decide two statements are "the same rule"130131Normalize away the system-name subject and trivial wording differences (articles, "shall"/"must"132phrasing, British/American spelling). If what remains is the same condition acting on the same133subject producing the same outcome, they are duplicates → keep one. If the condition, the subject134entity, the threshold, or the outcome differs in any substantive way, they are **not** duplicates →135keep both (and flag if they appear to contradict). When genuinely unsure, keep both (decision #4).136137### Step 3 — Self-check before finishing138139Run the bundled checker against your output and fix anything it reports:140141```bash142python3 ~/.claude/skills/merge-ears/scripts/check_merged_spec.py <output-file> \143 --inputs <input1> <input2> [...] --system-name "<MergedName>"144```145146It verifies the structural invariants: no duplicate entity headings, contiguous Business-Rules147numbering, no duplicate `(condition, message)` error rows, every `[NEEDS REVIEW]` marker names its148sources, and the merged system name is the subject used throughout (reporting any leftover original149subjects). Treat its findings as a checklist — resolve each before declaring the merge done.150151Then report to the user: the output path, how many statements/entities/rules came in vs. went out152(showing what was deduped), and a list of every `[NEEDS REVIEW]` conflict you flagged so they know153what needs a human decision.154155---156157## Anti-patterns (do not do these)158159- **Stapling files together.** Four overviews, four Cross-Cutting blocks, the Country entity four160 times — that is concatenation, not a merge. Consolidate.161- **Dropping a source reference during dedupe.** The whole point of decision #1: the surviving copy162 must carry the union of source files. A reader must still be able to trace any rule back.163- **Picking a winner in a conflict.** When inputs disagree, you flag — you never quietly choose.164- **Keeping mixed system-name subjects.** After the merge, every statement says the one merged165 system name. Leftover "the Group Management system" sentences are a bug.166- **Rewriting `> **Source files:**` paths into prose or "merged-name" form.** Those annotations are167 not statements; they keep their literal file paths (just unioned where entities were deduped).