spec-sizing
The shared 6-tier size ladder, per-type bands, and the nudge protocol delivery leads use to surface promotion recommendations on oversized specs.
SKILL.md.claude/skills/spec-sizing/SKILL.md
GitHubWhat I do
Define the shared 6-tier size ladder that lives in size: frontmatter
on every sized spec, and the nudge protocol delivery leads follow
when they encounter an oversized one.
Two jobs:
- Tell a lead what a
size:value means (and what the spec writer probably meant by choosing it). - Tell a lead exactly what to say, when, and how loud — so the same nudge fires consistently across sessions, agents, and trackers.
This skill is the source of truth. The delivery leads reference it;
the CLI (hero size, hero sprint estimate, hero check, hero_warnings)
implements the mechanics. The nudge text below is paste-ready — leads
quote it directly so wording stays consistent.
When to use me
- Design time — when authoring a new spec via
/design, stampsize:based on the design conversation. Default tomediumonly when truly undetermined. - Delivery pickup — when starting
/deliveron a spec, read itssize:andsize_ack:, runhero size --check, and fire the appropriate nudge. - Mid-delivery — if scope grows or drift surfaces, bump declared
size:viahero size <slug> <tier>instead of ignoring.
The ladder
One vocabulary across all sized spec types. Each tier represents roughly the same absolute magnitude of effort, regardless of which type carries it. What's "normal" for an initiative is alarming for a feature — that's what the per-type bands below capture.
| Tier | Magnitude | Rough shape |
|---|---|---|
trivial |
hours | A single change. Reads in one sitting. |
small |
~1 day | One file or one tight cluster. One PR. |
medium |
a few days | A small handful of files; one delivery loop. |
large |
week+ | Multi-day work; spans several files or one subsystem. |
x-large |
weeks | Real multi-week effort; likely wants phasing. |
giant |
month+ | Enormous; almost certainly an initiative in disguise. |
Per-type bands
| Tier | Feature / Bug / Enhancement | Epic | Initiative |
|---|---|---|---|
trivial |
normal | rare | — |
small |
normal | normal | small |
medium |
normal | normal | normal |
large |
soft nudge | normal | normal |
x-large |
strong nudge | nudge | normal |
giant |
promote → initiative | promote / /compose |
/compose into phases |
Why this shape (Option C)
Shared vocabulary, absolute magnitude, per-type bands layered on top.
A giant feature ≈ a small initiative in absolute effort — so
promotion is literally "move one step up the type ladder." One
mental model, one promotion rule. Don't re-litigate this choice;
the spec rejected the alternatives explicitly.
Nudge intensity by tier and moment
Even giant is advisory. Friction climbs but the user always
wins. Never block delivery; record the user's choice and proceed.
| Tier | Design-time | On scope-up edit | Mid-delivery |
|---|---|---|---|
large |
soft ask once | quiet | mention in handoff |
x-large |
strong ask; recommend /compose or /split |
re-ask if scope grew | flag each delivery session |
giant |
super-strong; require size_ack: giant |
re-recommend each time | strong rec every session until ack, split, or scope shrinks |
Tracker-aware tuning
The threshold at which the nudge fires shifts based on what the
tracker can do for hierarchy. Read hero.json: tracker.type and the
adapter's supports_hierarchy flag (slice 5 wires the adapter side;
until then default to "no tracker" behavior).
| Regime | Nudge schedule | Promotion offered |
|---|---|---|
No tracker (type: "none") |
Most aggressive: large → soft, x-large → strong, giant → super-strong |
Local promotion only — turn this spec into an initiative with children in .hero/. |
| Tracker without hierarchy (basic GitHub issues, flat Linear, etc.) | Same as no-tracker | Local promotion only — Hero handles parent/child locally; the tracker just sees the child issues. |
| Tracker with strong hierarchy (Jira epics, Linear projects, GitHub sub-issues) | Less aggressive: soft starts at x-large, strong at giant |
Promotion offers to create the parent in the tracker too, so the human team's view stays coherent. |
The acknowledgement protocol
size_ack: has two jobs. Both come down to the same principle: when
someone inspected the actual work and concluded the declared tier is
right, the system should stop arguing.
Job 1 — suppress the giant design-time nudge
---
title: ...
type: feature
size: giant
size_ack: giant
---
size_ack: giant says "yes, I know it's giant, I'm shipping it as
one spec anyway." Suppresses the super-strong design-time
recommendation to /compose. Does not suppress mid-delivery
surfacing — every delivery session on a giant spec still gets the
strong rec, because that's where the size is being felt.
Job 2 — inspector wins over the computed heuristic
---
title: ...
type: feature
size: medium
size_ack: medium
---
When size_ack: matches the declared size:, the drift detector
treats it as "the work was inspected; declared stands." Suppresses
the drift warning even when hero sprint estimate's computed bucket
disagrees. This is the inspector-wins rule: the person who
looked at the actual implementation outranks a word-count heuristic
that only inspected the spec body.
When to use it:
- A
/roadmap-reviewsession walked the drift and the user/agent confirmed declared is right (prose-dense specs that compute high, structured-data-dense specs that compute low) - A delivery-lead audit confirmed the spec scope matches declared
after delivery — agent acks before flipping
status: completed
When NOT to use it:
- Just to silence drift you haven't actually inspected. Acking
without thinking is the same anti-pattern as marking a ticket
won't-fixto clear a queue.
Rules
- The user, or an agent that just inspected the work, decides to
set
size_ack. The lead asks; the lead does not auto-stamp on a spec it hasn't read. - Stale acks are ignored. If you bump declared (
size: medium → large) but the ack stays at the old value (size_ack: medium), the drift detector treats the ack as stale and re-fires. Update the ack or drop it. - If the spec is split or scope shrinks, drop the
size_ackfield. - The
roadmap-revieweragent should ack every "keep declared as-is" decision in its session — that's the durable record of inspection.
Drift handling
When hero size --check, hero check, or hero_warnings surfaces
drift between declared and computed size, the lead does not
ignore it. Two flavors:
- Leaf drift (feature/bug/enhancement): declared
size:differs fromhero sprint estimatebucket. Bump declared viahero size <slug> <tier>to reflect what the spec actually is, then re-fire the nudge for the new tier. - Container drift (epic/initiative): declared
size:is smaller than the aggregated child rollup. Bump declared to at least the rollup tier.
Bumping the declared field is the lead's job, not the engineer's. Don't write code to auto-bump — surface the recommendation and let the user or the lead update it via the CLI.
Phrasing — paste-ready
These are the lines the lead should quote. Tune by tier and (where noted) tracker regime. Keep them short and concrete. Don't add hedging like "you might possibly want to consider"; say the thing.
large on feature/bug/enhancement — soft, design-time only
This is
large(week+ of work). Doable as one spec, but if it spans more than one subsystem consider/splitinto two specs. No action needed if you're comfortable with the scope.
Mid-delivery for large is quiet — mention in handoff only if
useful, otherwise stay out of the way.
x-large on feature/bug/enhancement — strong, every session
This is
x-large(multi-week). Strongly recommend/splitto break it into 2–3 child specs, or/composeif it deserves an initiative parent. Promotion creates a new initiative spec and converts this one into N child specs — real overhead, but cheaper than delivering a runaway spec. Want me to/splitnow?
Re-fire on every /deliver pickup. If the user says "ship it as-is,"
proceed — no size_ack needed for x-large.
giant on feature/bug/enhancement — super-strong, requires ack
Design-time and first delivery pickup:
This is
giant(month+). I strongly recommend promoting to an initiative with phased child specs —/composewill scaffold the parent and let you slot child specs under it. Promotion isn't free (new parent spec, re-parenting this one, writing N child specs), but a month-long single spec almost always runs aground. If you want to proceed without splitting, I'll stampsize_ack: giantin the frontmatter so I stop asking at design time. Mid-delivery I'll still surface the size each session. Split or ack?
Mid-delivery with size_ack: giant set:
Reminder: this spec is
giantand acknowledged. I'll proceed, but if the next phase feels rough, that's the signal to/split.
Mid-delivery without size_ack:
Still
giantand unacknowledged. Quick decision:/splitnow, or stampsize_ack: giantand I'll stop asking at design time (mid-delivery checks continue).
large/x-large on epic — light touch
Epics expect to be large. Only nudge at giant:
Epic is
giant— that's bigger than an epic should carry. Recommend promoting to an initiative (the next type up) and/compose-ing phases. Want me to scaffold the initiative parent?
giant on initiative — /compose recommendation
Initiative is
giant. Single-pass delivery isn't realistic at this scope. Strongly recommend/composeto break it into 3–5 sequential phases, each its own deliverable child. Want me to sketch the phase boundaries?
Tracker-aware variants
When tracker.type != "none" AND supports_hierarchy: true:
- Raise the trigger floor: skip the
largesoft nudge, start atx-large. - Append to the promotion ask:
When you split, I can also create the parent issue in <tracker> so your team's tracker view matches the spec hierarchy. Want both?
When the tracker has no hierarchy support, fire the local-only phrasing above and do not offer tracker-side parent creation.
What to do on drift
hero size --check flags declared-vs-computed mismatch. The lead's
move:
- Read the drift line. Two columns: declared tier and computed tier.
- If declared is too small (most common): bump it.
Then re-evaluate: the new tier may itself trigger a nudge (e.g. bumpinghero size <slug> <new-tier>medium→x-largelands you in strong-nudge territory). - If declared is too large (rare; usually after scope shrinks): bump it down. No nudge fires; the spec just looks less alarming.
- Container drift: same — bump the container's declared
size:to at least match the child rollup, then check whether the new container tier itself triggers a nudge.
Don't ignore drift. The whole point of the field is to make scope
changes visible — ignoring drift makes size: lie, and a lying
field is worse than no field.
Don't block
The user can override every nudge. The system records the choice
(via size_ack: for giant, or just by the user saying "ship it"
for large/x-large) and proceeds. Document the choice in the
delivery handoff so the next session sees it.
The nudge is a loud linter warning, not a gate. Treat it that way.
Composing with related skills
spec-format— definessize:as a living frontmatter field alongsidestatus:. Cross-references this skill for the ladder.agent-reliability— the Persistence rule applies: don't yield mid-delivery just because a nudge fired. Surface the nudge, get the user's call, proceed.kickoff-prompt— when rewriting a spec's## Kickoffafter a size change, reflect the new tier (and the ack state ifgiant).roadmap-review— the interactive triage surface for the drift this skill detects.hero size --checkreports drift;/roadmap-reviewwalks it one item at a time and executes the resolution CLI on confirm.spec-composition— owns the canonical "multiple related specs" phrasing and the multi-spec routing nudge. When a/designrequest would produce N related specs (user names multiple deliverables, or the rolled-up scope reacheslarge), the routing nudge fromspec-compositionfires first — the sizing nudge stands down for that moment per the precedence rule documented in that skill. Sizing nudges resurface per-child after the user either pivots to/compose(each child gets sized when its/designruns) or declines and proceeds with siblings (each sibling gets sized when written). One nudge per moment; never both at once.