The FOUNDATIONAL domain-model capability: extract a codebase's domain — testable
business rules (with confidence + provenance), entities, requirements — as a
schema-conformant model on the estate graph. The workers annotate the store;
wicked-core reads it and builds the requirements graph, coverage-gating
fail-closed. Steers three workers.
A shared substrate, not a modernization tool. The `modernize` archetype DERIVES
from it; build / migrate / review / specify / explore consume the SAME dom...
9 stars
0 votes
0 copies
1 view
Added October 18, 2026
ai-agentspythongoshellbashsqlnodeexpresstesting
Works with
claude code
cli
Security analysis
A92/100
mediumInstalls packages at runtime which could introduce malicious dependencies
Installs into .claude/skills of the current project.
Are you the author of Domain?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/mikeparcewski-domain)
---
name: wicked-garden-domain
description: |
The FOUNDATIONAL domain-model capability: extract a codebase's domain — testable
business rules (with confidence + provenance), entities, requirements — as a
schema-conformant model on the estate graph. The workers annotate the store;
wicked-core reads it and builds the requirements graph, coverage-gating
fail-closed. Steers three workers.
A shared substrate, not a modernization tool. The `modernize` archetype DERIVES
from it; build / migrate / review / specify / explore consume the SAME domain
model — none OWN it.
Use when: "extract the business rules / domain model from this codebase", "build
a requirements graph from the code", "what does this system actually require",
"reverse-engineer the domain before we build/port/migrate". Works on ANY codebase
(modern or legacy) — the value is the domain model, not the porting.
NOT the code transform itself (that is the archetype consuming this model). This
skill produces the DOMAIN MODEL, not new code.
metadata:
role: router
phases: "discover,extract,blueprint,plan,specify"
archetypes: "modernize,build,migrate,review,specify,explore"
---
# wicked-garden-domain
The **domain-model capability** — a foundational substrate, not a step inside one
archetype. It produces the shared **domain model** (business rules + entities +
requirements on the estate graph); the `modernize` archetype derives from it, and
build / migrate / review / specify / explore consume the same model. Understanding
a codebase's domain is upstream of building, porting, reviewing, or governing it.
**The contract in one line:** the only thing that crosses repo lines is a
document validating against the domain-model schema `1.0.0` (vendored at
`vendor/domain-model.schema.json`, owner: `wicked-core/crates/wicked-governance/schemas/`)
plus an estate `SymbolId` string. Garden STEERS (annotates the estate store + cross-checks the built document), core
BUILDS (`wicked-core domain-graph` reads the store, builds the requirements graph,
and coverage-gates fail-closed), estate GROUNDS (owns SymbolId identity + the
graph), crew GOVERNS (drives the run). The peer CLIs are shelled via
`scripts/domain/_clients.py`, or mocked behind fixtures when absent.
## Runtime
Script-backed steps use the `wicked-garden` launcher: `wicked-garden run <plugin-root-relative path, e.g. scripts/…> [args]`. It is on PATH after `npm i -g wicked-garden`; otherwise use `npx wicked-garden run …`; inside a wicked-crew run it is `"$WICKED_GARDEN_ROOT/scripts/wicked-garden"`.
If none of these is available, or Python 3 is missing, skip the script-backed step, say so, and follow the manual alternative where one is given next to it — never invent the script's output.
Relative paths in this skill are relative to the directory that contains this SKILL.md.
## The four-way seam
```
crew GOVERNS → garden STEERS → core BUILDS → estate GROUNDS
(drives the run) (this skill + (domain-graph + (SymbolId + graph
3 workers) coverage gate) + Louvain clusters)
```
Garden never imports core or estate code — it shells their CLIs (argv lists, no
shell string) or mocks them. It annotates the estate store and references SymbolId
strings; core reads the store and builds + coverage-gates the requirements graph;
estate is the sole writer of graph structure.
## Routing — the three workers
| Ask | Worker | Produces |
|-----|--------|----------|
| Mine business rules from the estate → domain-model doc | domain-extractor (`wicked-garden-domain-extractor`) | `business_rules[]` with confidence + provenance; estate `requirement` annotations |
| Group clusters into domains → invoke core's domain-graph build | domain-modeler (`wicked-garden-domain-modeler`) | `domains{}` keyed to estate Louvain communities; `requirements_graph.json` built by `wicked-core domain-graph` |
| Threat-model the extracted model before build | domain-coverage (`wicked-garden-domain-coverage`) | pre-build threat list / RISK-flag reasons |
**Hand-off** — open the worker's skill by name (`wicked-garden-domain-extractor`,
`wicked-garden-domain-modeler`, `wicked-garden-domain-coverage`) and carry out its SKILL.md
with the ask as the argument; on Claude Code this is the Skill tool, on any
other seat open the named skill from your catalog and run it inline, keeping its output
separate from yours, then continue here. Run order for a full extraction: **extractor →
translator → antagonist**. Each is independently invocable.
## The document this skill emits
A `domain-model@1.0.0` document (see `vendor/domain-model.schema.json`).
Top-level `{ metadata, domains }`; every domain has `requirements` + `entities`;
every requirement carries the full field set and **≥1 business rule**; every
business rule carries a **numeric `confidence ∈ [0,1]`** and a
**`provenance{source, ref, source_kinds}`**. Full field map + the hard
invariants: [refs/domain-model-emit.md](refs/domain-model-emit.md).
Reference-not-copy: `legacy_components[]` and `provenance.ref` hold estate
**SymbolId references**, never a copy of the symbol's code, file, or line.
estate resolves them live.
## The working core slice (what ships in PHASE-1)
Garden is skills-only, but the deterministic assembly + invariant enforcement is
real code you can run and test today:
```bash
# Emit a conformant domain-model doc from mocked estate + rule inputs
wicked-garden run scripts/domain/emit_domain_model.py --fixture > /tmp/domain-model.json
# Validate any doc against the vendored schema + hard invariants
wicked-garden run scripts/domain/validate_domain_model.py /tmp/domain-model.json
```
- `emit_domain_model.py` — the extractor's **deterministic core**: takes a mocked
estate cluster + a list of extracted rules and assembles a schema-conformant
document, enforcing the hard invariants at build time (drop needs a reason,
≥1 rule per requirement, numeric confidence).
- `validate_domain_model.py` — a stdlib-only draft-07 subset validation against
the vendored schema (no third-party dependency — the repo is stdlib+pytest
only), plus the extra invariants the schema can't express (numeric confidence
type, SymbolId-shaped references).
- `scripts/domain/_clients.py` — the selection seam: `estate_client(db)` /
`core_client()` return CLI-backed clients when `wicked-estate` / `wicked-core`
resolve, else the mocks. Shells the peers (argv lists, no shell string).
- `scripts/domain/_mocks.py` — the disjoint fixtures: a fake estate client
(canned clusters + `resolve`/`annotate`) and a fake brain client (the hermetic
doc-assembly lane). **These mock the peers; no other-product code is imported.**
## Honest scope — implemented vs stubbed
**Implemented + tested:** the vendored + pinned schema; the deterministic
document assembler; the validator (schema + hard invariants); the CLI-backed
clients (`_clients.py`) that shell the real `wicked-estate` + `wicked-core`, with
argv-construction tests + an opt-in real-CLI lane; the fixture mocks; a conformant
fixture document; the pytest suite that validates emitter output and the fixture
against the schema.
**Wired to live CLIs (`_clients.py`):** the estate surface (`resolve`,
`annotate --replace`, `semantics`, `clusters --json --summary`,
`annotations`) → `CliEstateClient`; the domain-graph build
(`wicked-core domain-graph` — reads the store, builds the requirements graph,
coverage-gates fail-closed) → `CliCoreClient`. When the peers are absent, the
selection seam falls back to `_mocks` for hermetic testing.
**Still stubbed:** the LLM rule-statement extraction step (rules are injected as
input — the "skill-supplied extractor" seam). And the real end-to-end run needs a
fully-annotated, INDEXED store (coverage == 1.0) to clear core's fail-closed gate
— that store-seeding step is the end-to-end milestone (core#28), not this slice.
## Estate id-scheme migration (2026-08) — when the pipeline must be re-run
Estate id-scheme **"2"** nests method/field SymbolIds under their enclosing type
(`<module>/Repo#save().` instead of `<module>/save().`). The first
`wicked-estate index` per repo under a new-scheme binary hits the `id_scheme`
meta mismatch and performs a **forced full re-extract** that re-mints every
definition id — and the pipeline's outputs (`business_rule`/`risk` annotations +
`node_semantics` written by `scripts/domain/extract_loop.py`) stay keyed to the
OLD ids. Method/field-keyed rows **orphan**; module-level (top-level function /
file) rows survive. Annotations are documented loss, not re-keyed.
**Re-runs are required** for every repo that carries domain annotations, after
its first index under the new binary — in exactly this order:
1. `wicked-estate index <repo>` with the new binary (the loud full re-extract).
2. Re-run the extraction loop: `wicked-garden run scripts/domain/extract_loop.py --db "<store>" …`
(it re-seeds from `wicked-core coverage`'s `unaccounted_nodes`, so orphaned
nodes simply reappear as unaccounted; the loop's pre-flight also warns when it
detects orphaned annotations before writing).
3. Rebuild the domain graph: `wicked-core domain-graph` (coverage-gates
fail-closed against the re-annotated store).
Previously emitted `requirements_graph.json` / domain-model documents embedding
old-scheme SymbolIds are stale until step 3 completes.
**Quantify the damage first (operators)** — how many annotation rows would
orphan (method/field-keyed) vs survive (still-live node), against any store:
```sql
-- rows whose node no longer exists (orphaned) vs rows still keyed to a live node
SELECT (n.symbol IS NULL) AS orphaned, count(*) AS rows
FROM annotations a LEFT JOIN nodes n ON n.symbol = a.node_sym
GROUP BY orphaned;
-- pre-migration estimate on an OLD-scheme store: rows keyed to a definition
-- nested inside a type (its id re-mints → orphans) vs module-level rows (id
-- unchanged → survive). Old flat ids don't encode nesting, so containment is
-- derived from byte spans: a Type-kinded node in the same file encloses it.
SELECT EXISTS (
SELECT 1 FROM nodes t
WHERE t.file = n.file AND t.symbol != n.symbol
AND t.kind IN ('"class"','"struct"','"enum"','"trait"','"interface"',
'"module"','"namespace"','"type_alias"','"type"')
AND json_extract(t.data,'$.location.span.start_byte')
<= json_extract(n.data,'$.location.span.start_byte')
AND json_extract(t.data,'$.location.span.end_byte')
>= json_extract(n.data,'$.location.span.end_byte')
) AS would_orphan, count(*) AS rows
FROM annotations a JOIN nodes n ON n.symbol = a.node_sym
GROUP BY would_orphan;
```
## Ground in the repo's method first
Before extracting, check for **wicked-understanding** repo playbooks (the
"how to work in THIS repo" layer). A modernization lives or dies on
repo-specific wiring. If present, load the matching playbook.
## Depth
- [refs/domain-model-emit.md](refs/domain-model-emit.md) — the full field map,
the seven hard invariants, and the SymbolId reference rule.
- [refs/extraction-flow.md](refs/extraction-flow.md) — how the extractor drives
estate (resolve → annotate → semantics) and core (`domain-graph`), the
`_clients.py` selection seam, and the mock lane.
- `vendor/README.md` — the vendored-schema pin + drift discipline.