Service-architecture decision discipline — decide monolith vs modular monolith vs extracting a service, per candidate boundary, on evidence: real extraction drivers (deploy contention, asymmetric scaling, failure isolation, team ownership) weighed against the distributed tax, with "extract the seam before the service" as the governing rule. Verdict per boundary: STAY / MODULARIZE / EXTRACT, recorded as an ADR and routed to the right executor. TRIGGER when: the user asks "should we split this ...
Scanned 9/5/2026
Install to Claude Code
npx -y skills add mik2win/foureyes --skill decompose --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Decompose?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/mik2win-decompose)More formats (shields.io, HTML) on the badges page.
---
name: decompose
disable-model-invocation: true
description: >-
Service-architecture decision discipline — decide monolith vs modular monolith vs
extracting a service, per candidate boundary, on evidence: real extraction drivers
(deploy contention, asymmetric scaling, failure isolation, team ownership) weighed
against the distributed tax, with "extract the seam before the service" as the
governing rule. Verdict per boundary: STAY / MODULARIZE / EXTRACT, recorded as an ADR
and routed to the right executor.
TRIGGER when: the user asks "should we split this into services", "monolith or
microservices", "extract X into its own service", "is it time to break this up", or a
plan proposes a new service and the boundary hasn't been justified.
DO NOT TRIGGER when: the user wants in-process module/interface design (use
/codebase-design), a whole-tree rot scan (use /arch-health), the extraction is already
decided and needs a shipping strategy (use /rollout), or a past architecture decision
needs re-examination first (use /revisit).
allowed-tools: Read, Grep, Glob, Bash, Write, WebFetch, WebSearch, AskUserQuestion, Agent
effort: high
---
# Service Decomposition: $ARGUMENTS
`$ARGUMENTS` names the candidate boundary ("billing", "the notifications module") or is
empty = survey the whole system for extraction candidates and verdict each.
## Principle
A service boundary is not a code-quality tool — it is an **organizational and operational**
tool that happens to involve code. Splitting a process buys independent deploys, independent
scaling, and failure isolation; it pays for them with network partial-failure, the loss of
cross-boundary transactions, contract versioning, and an operational floor per service.
Messy code is never a driver: **a mess cut in two is two messes joined by a network**.
The governing rule is **extract the seam before the service**. Every good service boundary
must first exist and hold as a clean in-process module boundary — own interface, own data
access, no reach-ins. If the boundary can't be drawn inside one process, the network will
not draw it for you. This is `core.md`'s door rule: extraction is a heavy,
nearly-one-way door, but **modularization is how you change the door** — a proven in-process
seam makes later extraction cheap and is worth having even if you never extract. So the
default verdict is always the modular monolith, and extraction must argue its way past it.
This skill **decides and records** — it does not restructure. Execution routes out
(Phase 4).
## Phase 0 — Load profile
**Tooling preflight — one call, before step 1.** Some tools this skill relies on are **deferred**
by the harness: the session lists them by name only and loads their schemas on demand, so calling
one before it is fetched fails. Listing a tool in `allowed-tools` does **not** un-defer it. Issue
a single `ToolSearch` up front covering the whole run — `select:WebFetch,WebSearch` (Phase 1's
live feasibility checks on infra and platform limits) — instead of one round-trip per discovery.
A name already loaded costs nothing to include; a schema discovered missing mid-run costs a turn.
1. Read `.claude/PROJECT.md` — **Architecture** (layers, module map, dependency direction),
**Integrations** (existing infra: queues, gateways, deploy platform), **Commands**. If
missing or still `TEMPLATE`, fall back to the root `CLAUDE.md` (always in context) when it
carries those facts — proceed on it, noting you're running without a kit profile. Only if
*neither* has them, **STOP** and tell the user to run `/bootstrap` first.
2. Read `CONTEXT.md` / `CONTEXT-MAP.md` if present — bounded contexts are the natural
candidate boundaries; name candidates in their terms.
3. Read `docs/adr/` (or the ADR location in `PROJECT.md`) — a prior decision about this
boundary means **start at `/revisit`**, not here: reopening it requires a broken
assumption, not a second opinion.
4. Read `skills/codebase-design/SKILL.md` for the seam/interface vocabulary — every
boundary statement uses it.
## Phase 1 — Evidence, not vibes
Collect per candidate boundary. Fan out `arch-tracer` agents for the coupling map on
anything beyond a small tree; pass `.claude/schemas/finding.schema.json` for mergeable
output. Ground every claim in `path:line` or a command's output.
**Code evidence (agents can find this):**
- **Runtime coupling** — synchronous call chains crossing the candidate boundary, shared
tables/schemas, shared transactions, shared caches, shared in-memory state. Each one is
either severed before extraction or becomes a distributed failure mode after it.
- **Data ownership** — can each side own its data outright? A table written by both sides
is the single strongest STAY/MODULARIZE-first signal.
- **Change coupling** — `git log --format=%H --name-only` mined for commits touching both
sides of the boundary: code that ships together wants to live together. Independent
change histories support a split; interleaved ones refute it.
- **Scaling asymmetry** — evidence (from `/perf` reports, profiles, infra dashboards named
in Integrations) that one part needs materially different resources or scale.
**Organizational evidence (agents cannot see the org — ASK, never guess):**
Use `AskUserQuestion` for: team count and ownership map (Conway's law: the service
topology you can sustain is the team topology you have), deploy cadence and who blocks
whom, on-call/ops capacity, and the platform's operational maturity (CI/CD per service,
observability, service discovery). **One team ≈ one deployable** is the reference class;
a one-team org extracting microservices is buying tax with no driver.
**External evidence (research, when the answer isn't in the repo):**
Platform capabilities, event-bus/gateway options, reference-class outcomes for this kind
of split — verify live via WebSearch/WebFetch; route a load-bearing unknown ("can our
platform even run N services?") to `/spike`, and an infra component choice (broker,
gateway) to `/select-tech`. Never decide on remembered facts about platforms or tools.
## Phase 2 — Weigh drivers against the tax
**Real extraction drivers** (each needs Phase-1 evidence to count):
| Driver | Evidence that makes it real |
|--------|-----------------------------|
| Independent deploy cadence | releases demonstrably blocked/serialized across the boundary |
| Asymmetric scaling | measured resource profile divergence, not anticipation |
| Failure isolation | a part whose failure must not take the rest down (and currently can) |
| Team ownership | a real team wanting an independent roadmap for exactly this boundary |
| Divergent constraints | runtime/latency/compliance needs one side genuinely can't share |
**Fake drivers — name them when you see them, they never justify extraction:**
"the code is a mess" (→ `/arch-health`), "microservices are best practice", "it'll be
easier to understand" (locality *drops* across a network), "we might need to scale
someday" (speculative scale = STAY; extract when measured), résumé-driven architecture.
**The distributed tax — the extraction side must accept ALL of these, listed explicitly:**
network calls that partially fail (timeouts, retries, idempotency per `resilience` rule),
no cross-service transactions (sagas / eventual consistency where a `BEGIN` used to do),
versioned contracts between the parts (Hyrum's law now applies internally), per-service
observability + deploy + on-call floor, harder local dev, and data duplication where
joins used to be — plus the **agent tax**, which nobody prices in: one user-visible flow
now spans N repos, N deploys, and N telemetry stacks, so no single agent session can trace
it end-to-end with Read and Grep. Comprehension shifts from code-reading (cheap, always
available) to distributed tracing (needs the observability floor *already built*). The
monolith's most under-priced asset is that its entire truth fits one context window.
**Verdict per candidate boundary:**
- **STAY** — no evidenced driver. The monolith is the correct architecture; say so
plainly. A monolith serving its load with one team is a success, not a smell.
- **MODULARIZE** — drivers are real or plausible **but** Phase-1 found reach-ins, shared
data, or interleaved change history. Make the boundary real in-process first: own
interface, own data access, composition-root wiring. This is the default when in doubt —
it captures most of the benefit, keeps transactions, and leaves the door open.
- **EXTRACT** — evidenced drivers outweigh the accepted tax **and** the in-process seam
already exists and holds (no reach-ins, data ownable, contracts nameable). Both
conditions, not either.
## Phase 3 — Grill and record
Take the top-ranked verdict (user picks via `AskUserQuestion` if it's a genuine toss-up)
and `/grill` it: the exact interface at the seam, who owns which data, what happens on
partial failure, the migration's first reversible step. Then record the verdict — including
STAY — as an ADR via `/domain-model`, with the drivers, the accepted tax, and the
assumptions it rests on stated explicitly (that's what a future `/revisit` will test).
## Phase 4 — Route to the executor
| Verdict | Route |
|---------|-------|
| STAY | nothing to build; if the mess prompted the question, → `/arch-health` |
| MODULARIZE | `/prepare` → `/implement` (large) or `/refactor` (small, local) |
| EXTRACT | `/rollout` — strangler-fig staged strategy; each stage through `/prepare` → `/implement` |
| Missing evidence blocked a verdict | `/spike` (feasibility) · `/select-tech` (infra component) |
## Output
`Write` the report below to the **Plans location** from `PROJECT.md` (e.g.
`<plans>/<YYYY-MM-DD>-decompose.md`; git policy per `PROJECT.md` → Artifact git policy),
then present it:
```
## Decomposition — <scope>
### Verdicts
| Boundary | Verdict | Drivers (evidenced) | Blockers / tax accepted | Route |
### Evidence
- <boundary>: coupling `path:line`…, change-coupling stats, org facts (from user)
### Recommended next
- ⭐ <boundary> — <verdict> — <one-line why> → <route>
### ADR
- <recorded / to record via /domain-model>
```
## Hard rules
- **Decide and record only** — never restructure here; execution goes through Phase-4 routes.
- **Default is the modular monolith.** Extraction must clear both bars: evidenced drivers
AND a proven in-process seam. Never extract along a seam that doesn't hold in-process.
- **Org facts come from the user.** Team topology, ops maturity, deploy pain — ask; never
infer from code.
- **Fake drivers are findings.** Name them in the report instead of acting on them.
- **STAY is a first-class verdict.** Record it as an ADR so the question isn't relitigated.
- **External facts verified live**, never from memory.
## Cross-reference
- **`/codebase-design`** — the seam/interface vocabulary; MODULARIZE work is designed in it.
- **`/arch-health`** — finds the rot that often masquerades as an extraction driver.
- **`/revisit`** — start there when a prior ADR already covers this boundary.
- **`/rollout`** — the strangler-fig staged execution of an EXTRACT verdict.
- **`/domain-model`** — bounded contexts in; the verdict ADR out.
- **`/select-tech`, `/spike`** — infra component choice / feasibility unknowns.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!