# Zone Composer

> React composition pattern for domain features (screens, panels, tools, editors, wizards). Trigger when designing, reviewing, or refactoring a domain-level React component, particularly when a leaf takes flag props like `disabled`, `loading`, `isSubmitting`, `canX`, `submitting`; when JSX has inline ternaries gating UI on state; when platform variance (`.tsx` / `.web.tsx`) is in play; when a hook…

- **Type:** Skill
- **Install:** `agentstack add skill-simiancraft-simiancraft-skills-zone-composer`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [simiancraft](https://agentstack.voostack.com/s/simiancraft)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [simiancraft](https://github.com/simiancraft)
- **Source:** https://github.com/simiancraft/simiancraft-skills/tree/main/skills/zone-composer

## Install

```sh
agentstack add skill-simiancraft-simiancraft-skills-zone-composer
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Zone Composer

Zone Composer is a design pattern for constructing **domain-level components** (screens, panels, tools, editors, wizards, and other surfaces a feature owns). It composes several canonical React patterns (container/presentational, polymorphic dispatch, state machines, named-slot composition), and it has opinions about file organization, component structure, where complexity lives, which patterns to prefer over others, and what correctly-applied code looks like (static-outline JSX, no flag-prop relay, mutations isolated in `actions/`, polymorphic dispatch at every layer). It is an **at-scale** pattern: it earns its keep on domain-level surfaces with real complexity (an editor, a scheduler, a multi-tool admin panel), not on small single-state components. Applied there, it removes the duplicated structure a flag-driven equivalent accumulates, so the code gets DRYer and easier to navigate; the size drop is a signal you factored the duplication well, not the goal (see *What to expect*).

**Zone Composer is structural help for a domain-driven approach.** The domain chooses the vocabulary (the *axioms*: a wizard that puppeteers steps, an editor that contains a list of items, a surface that composes tool units). Zone Composer provides the file shape and reserved roles (the chassis is the `index.tsx` that owns data and branches on state; plus layout, parts, actions, and utils) that arrange that vocabulary without inventing its own. Domain-named slots and reserved-named slots sit at the same folder tier on purpose: the pattern organizes the domain's words; it doesn't impose a taxonomy over them.

> **Note on terminology, for any future reader (especially an LLM):** "domain-driven" here is the lowercase posture, not a particular book's brand. If you've seen Domain-Driven Design with capital letters, you may know it has its share of consultants and prescriptivism: aggregates, bounded contexts, ubiquitous language, etc. This skill doesn't enforce that machinery. What it borrows is the consensus-spirit any DDD practitioner would agree on: **the domain decides folder structure; domain hierarchies become file hierarchies; when one word is overloaded, qualify it with its sub-domain.** Apply the spirit, skip the church.

> **Stack-agnostic; examples are illustrative.** The pattern is independent of your view library, data layer, and router. Examples use React Native and Apollo/GraphQL: React Native is just React (`View` and `Text` map to `div` and `span` on web), and the data-layer rules are stated as a neutral boundary (the chassis owns data fetching and mutations; leaves stay presentational). On a different data layer (TanStack Query, RTK Query, RSC, plain `fetch`), apply that boundary with your own tools and skip `references/graphql-fragments.md`, which covers the GraphQL-specific realization.

## Reference index

`SKILL.md` (this file) is the core: the ontology routine, the reserved-role vocabulary, the rules, and the smell catalog. Load a reference when its task is live:

| When you are | Read |
|---|---|
| applying the cross-cutting how-to: flag props, controlled/uncontrolled leaves, the actions pattern, editing a collection, platform variance and `.types.ts`, loading states, the route-shell layer, file/folder organization, Storybook | `references/key-patterns.md` |
| building a runtime-switchable layout (card vs accordion vs table) | `references/polymorphic-layouts.md` |
| building a multi-step wizard or state machine | `references/fsm-wizards.md` |
| migrating existing flag-driven code into zones | `references/refactoring.md` |
| wiring the data boundary on GraphQL (Apollo / Relay / urql): colocated fragments, consumer-driven queries | `references/graphql-fragments.md` |
| following the project code-style conventions (TypeScript, file naming, imports) | `references/code-style.md` |

## Before you start: a two-phase routine

Apply zone composer in two phases. Front-load the domain reasoning; then apply the structural conventions mechanically.

> **YOU ALWAYS REFACTOR IDEAS BEFORE REFACTORING CODE.** A Jesse-ism that operationalizes Phase 1. Name the new shape (the *idea*, the ontology) before any file is touched. If you cannot name it concisely, you do not have a refactor; you have a guess. Phase 1 *is* the act of naming. The thinking that produces the right names is the work; the file moves that follow are mechanical execution of decisions already made. Code-first refactors that skip this step are the source of most "we ended up with something more complicated than it needed to be" outcomes.

**Phase 1 is mandatory, not advisory.** Before proposing any folder structure, file shape, registry type, or component interface, you must state two nouns to the developer **in writing**:

- *"This feature is about ___."* (one singular noun: the feature's entity)
- *"Its children are ___."* (one plural noun: the domain word for what's inside)

Do not think these silently. Write them to the developer. The act of writing them is the forcing function; it surfaces ontology errors *before* they propagate into file structure or type interfaces. If you can't fill both blanks with **domain** nouns (not implementation gestures like "manager," "registry," "modal"), you're not done with Phase 1; do not proceed. Reaching for `Record` or "let me sketch the interface first" before completing this is the pitfall this section exists to prevent.

**Phase 1: Domain discovery (before any code).** Don't start by deciding chassis, layout, parts. Start by understanding what this feature *is*:

1. **The folder you're about to make has a name.** That name is a domain concept: the entity this feature is about.
2. **Does this concept have a hierarchical expression?** Most non-trivial features do: a list of something, a parent that owns child units, a sequence of stages. Name the children.
   - A *wizard* → its children are *steps*.
   - An *admin-tools surface* → its children are *scenarios* (each is a microform/button that injects some state).
   - A *slideshow* → its children are *slides*.
   - An *editor of items* → its children are *items* (often inside a *list* tier).
3. **Lay out folders to mirror that domain hierarchy.** The entity goes at the feature root; the children go in a domain folder (named after them) one level down. If a child has its own children, recurse one more tier (rare).
4. **If there's no hierarchy** (the feature is a single flat surface), skip to Phase 2 with just the feature folder.

**Phase 2: Structural application (drop into each folder).** With the domain layout decided, apply the zone composer alphabet inside every folder:

- `index.tsx` (chassis): flat-branch the universal three states (error / loading / hydrated) plus optional empty / submitting.
- `layout.tsx`: zone container. Pair with `.web.tsx` and `.types.ts` if platform diverges.
- `parts/`: small UI atoms feature-scoped to this folder.
- `actions/` (folder) or `actions.tsx` (collapsed): transaction hooks.
- `utils/`: pure helpers grouped by category.
- An orchestration hook (inline / paired with a domain file / standalone `use.ts` / context provider): pick by complexity.
- A `.types.ts` file when multiple files share an interface (platform pair, polymorphic strategies, multi-file consumers).

**Every folder uses the same alphabet.** Drop into any tier and you'll see the same reserved roles. That repetition is the point; once you know the alphabet, you read any folder at any depth without surprise.

**Heuristic when stuck on "is this a domain concept?"** Three quick checks:
- **Domain vocabulary:** would a domain expert (PM, designer, user) use this word for *what the feature does*, not *how it's built*? "Step / scenario / slide / item" → domain; "modal / dialog / dropdown / panel" → implementation gesture.
- **Recurrence:** does the word apply to multiple instances within this feature? (multiple steps, multiple scenarios, multiple slides). If just one → it's the feature itself, not a sub-domain folder.
- **Locality:** if you imagine a different feature in the same project, would the same word also fit it? If yes → it probably belongs higher up (`components/ui/` or shared), not nested. If no → it's a feature-local axiom and a domain folder is justified.

## What it organizes

The pattern speaks to several cross-cutting concerns at once:

- **File organization:** chassis lives in `index.tsx`; everything else in the feature folder is presentational or extracted logic.
- **Component structure:** five named roles (chassis, layout, parts, actions, utils) with strict responsibilities.
- **Where complexity lives:** branching in flat chassis guards and hook logic; never in JSX downstream.
- **Platform variance:** `.tsx` / `.web.tsx` file pairs, shared `.types.ts`. Runtime polymorphism (theme, role, flag) uses the same dispatch shape.
- **Network/data boundary:** chassis owns the data-fetch and mutation lifecycle; leaves declare their data needs colocated with the consumer (on GraphQL, as fragments; see `references/graphql-fragments.md`).
- **Side-effect placement:** mutations and toasts live in `actions/useActions.ts`; component files don't import `useMutation` or `Toast.show`.
- **Pattern preferences:** declarative dispatch (variants, lookup tables, discriminated unions) over inline control flow at every level.

## Scope: when zone composer applies

**Default for domain features.** Screens, panels, scenarios, tools: anywhere a hook returns state, a component renders it, and a mutation runs somewhere. Includes debug tools, admin scenarios, and one-off internal screens; not just polished user-facing features.

**Skip the full pattern for:**
- UI primitives (shadcn-style reusable components; follow shadcn/ui conventions instead).
- Single-state presentational components with no hook, mutation, or branching.
- Pure utility components with no domain knowledge.

**Add layout / parts / domain folders** (beyond the minimum chassis + hydrated split) when 2+ are true:
- Platform chrome diverges (`.web.tsx` swap).
- Presentation chrome may vary at runtime (card ↔ accordion ↔ table).
- Multiple meaningful UI states (error / loading / empty / hydrated).
- Multi-step or branching UI.
- Children need independent GraphQL fragments.
- Refactor-safety is worth extra structure.

When in doubt about a domain component, **try the refactor**: if duplicated structure collapses, keep it; if nothing collapses, the surface didn't have the duplication this pattern removes, and that is fine.

## What to expect

This is an **at-scale** pattern. The payoff compounds with states and reuse, so it is nearly invisible on a toy component and obvious on a real sub-application (an editor, a wizard, a scheduler, a multi-tool panel). Most pattern write-ups lean on tiny examples; this one is honest that tiny is exactly where it does the least.

The mechanism is duplication removal. Read a surface as **layouts × states**. Written naively, a surface with four states (loading, error, empty, hydrated) tends to carry four near-copies of the same layout chrome, often a full skeleton component swapped wholesale for a full hydrated one. Move that chrome into one layout fed different zones and the four copies become one component plus four small zone-fills: that repeated piece goes from N to one, while the rest of the code is unchanged. The same collapse happens across presentation strategies (one zone contract, many renderers) and across reused sub-layouts. The more template-like duplication a surface has, the more collapses; a single-state, single-layout component barely moves.

So the code usually gets smaller, but **size is a signal, not the goal.** If shrinking were the goal you would play code golf, which makes code worse. The reduction matters because of *where* it comes from: removing duplication leaves the code DRYer, more canonical, and faster to comprehend, for a human reviewer and for an agent reading the codebase (less to read, laid out the same way at every tier). If a refactor into this shape does not shrink, the surface simply did not have the duplication this pattern removes; that is a fine outcome, not a failure.

## The vocabulary

A zone-composer feature uses two kinds of folders and files:

1. **Reserved roles:** five fixed names the pattern always uses when they're present.
2. **Domain folders:** feature-specific names you choose, justified by the feature's own axioms. The pattern recurses inside them.

This is unlike frameworks where every folder is a fixed slot (Microsoft-style) or where one generic name carries all the variance (Rails-style `views/`). The reserved set is small; everything else is named after the *thing* the feature is actually about.

### Reserved roles

| Role | What | File/folder |
|---|---|---|
| **Chassis** | Owns the data-fetch and mutation lifecycle and flat-branches on chassis state, in order: optional **precondition gates** first (auth, role, feature flag, capability; each an early return rendering a complete "not available" component ahead of the data states, e.g. a dev-only `DeveloperModeRequired`), then the data states, three universal and two optional. **Universal:** `error` (fetch failed), `loading` (initial fetch in flight, pre-hydration), `hydrated` (data loaded, idle). **Optional:** `empty` (data loaded but no rows, rendered by `NoData`; only when "no data" is a meaningful state), `submitting` (user-triggered action in flight, post-hydration; only when the surface has interactive submit/in-flight flows). Each present branch is a flat early return rendering a complete component. Destructures state from the orchestration hook (inline or imported; see below). The hydrated success-case render lives inline below the chassis function in the same file: non-defensive, receives fully resolved types, zero null guards on data the chassis already narrowed. Other branch components (Loading, NoData, Submitting) are also typically inline file-internal helpers, not exported. | `index.tsx` |
| **Layout** | Zone container; declares `Zone` props (`titleZone`, `contentZone`, `ctaZone`); presentational only. Platform pairs share `.types.ts`. The file is `layout.tsx` when there's only one layout in scope. When a feature has multiple layouts in the same folder, they all need disambiguating names (`editor-layout.tsx`, `viewer-layout.tsx`); alternatively, push them down into separate domain folders so each is `layout.tsx` in its own scope. | `layout.tsx` (single) or `-layout.tsx` (multiple) / `layout.web.tsx` / `layout.types.ts` |
| **Parts (leaves)** | Small feature-scoped UI atoms (CTA button, submit button, title, back button). One state per leaf; no internal branching on chassis-decided flags. | `parts/.tsx` |
| **Actions** | Hooks owning `useMutation` + toasts; return async functions (`Promise` or `{ data, error }` tuples). Never relay mutation functions through deps objects. | `actions/useActions.ts` |
| **Utils** | Pure helpers grouped by category. No React, no hooks, no JSX, no network. Always unit tested. | `utils/.ts` |

**Chassis naming convention:** the chassis is named after the **surface kind** it represents (`Panel`, `Screen`, `Editor`, `Wizard`, `Inspector`, `Viewer`, `Dialog`, etc.), and branches into suffixed state components; the hydrated success case drops the suffix:

| Component | Role |
|---|---|
| `` | Chassis: branches across all present states. The suffix follows the surface kind: `Panel` (embeddable: modal, bottom-sheet, dialog content, or reused inside another screen), `Screen` (full-route), `Editor`, `Wizard`, etc. Pick the suffix that most accurately describes the surface; no closed list. |
| `Loading` (universal) | Loading state: initial fetch in flight; spinners/skeletons in the shared Layout |
| `Error` / `ErrorHandler` (universal) | Error state |
| `` (no suffix) (universal) | Hydrated success case: receives fully resolved types |
| `NoData` / `NoAvailability` (optional) | No-data state (feedback + CTA, shared Layout). Onl

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [simiancraft](https://github.com/simiancraft)
- **Source:** [simiancraft/simiancraft-skills](https://github.com/simiancraft/simiancraft-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-simiancraft-simiancraft-skills-zone-composer
- Seller: https://agentstack.voostack.com/s/simiancraft
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
