Handoff Readiness
Overview
Readiness is judged per consumption channel, not per repo: first detect what is being handed off and every way the project itself advertises consuming it, then walk each channel end-to-end as a cold external consumer would. An artifact that builds internally but breaks on npm install or on copy-paste is NOT ready.
When to use / when NOT
Use for:
- Pre-publish audits of packages, SDKs, CLIs, component kits, templates
- Hosted/copy registries (shadcn-style) before exposing them to users
- "Is this ready / can we ship / can we hand this off" questions about reusable artifacts
- Verifying exports maps, type declarations, peer dependencies, files whitelists
Do NOT use for:
- Docs/content site deploy checks → see docs-deploy-readiness
- Internal cross-package reuse/duplication questions → see reusability-audit
- General code quality/architecture → see code-audit
- Deep security or a11y review → see security-review, accessibility-compliance (this skill only checks the contract exists)
- Running this audit across many packages with parallel agents → orchestrate via convergence-loop
How it works
- DETECT the artifact and its channels. Read, in order: root + per-package manifests (
package.json or ecosystem equivalent — pyproject.toml, Cargo.toml, go.mod), exports/bin/files/main/types fields, build config (tsup/rollup/vite/esbuild/etc.), any committed registry JSON directories, README + docs install instructions. Classify the artifact as one or more of:
- Runtime package (installed from a registry like npm, imported at runtime)
- Copy/source distribution (code lands in the consumer's repo: shadcn-style registry, template, "copy this folder")
- Hosted registry (committed JSON/index that a CLI or tool resolves; illustrative example only:
public/r/*.json consumed by a shadcn-compatible or project-specific add CLI)
- CLI binary (
bin entry, installed globally or via npx/pnpm dlx)
- Template/starter (cloned, then built by the consumer)
- Enumerate every ADVERTISED consumption path. Only what the project documents counts as a channel — README install sections, docs "Installation" pages, registry index files,
bin entries. Each advertised path becomes a row in the scorecard. An advertised-but-broken path is a blocker; an unadvertised path is out of scope.
- Apply the universal bar (a–e below) to each channel. Skip dimensions that don't apply (e.g. exports-map checks for a pure copy distribution) and mark them N/A — never silently.
- Simulate the consumer journey statically per channel. Follow the project's own install docs from zero: every referenced file, command, flag, alias, import specifier, and registry item must exist; no orphan imports (files importing siblings that the channel doesn't deliver); CSS/peer/env setup steps documented where required.
- Run mechanical verifiers where tools exist. For npm-ecosystem packages,
publint and @arethetypeswrong/cli --pack are the named 2026 baseline; also inspect pnpm pack (or npm pack --dry-run) output against what runtime actually needs. Use ecosystem equivalents elsewhere (twine check, cargo package --list). Prefer running tools over eyeballing.
- Score and report using the Output format. Order blockers by what breaks the consumer first.
Quality bar (universal, per channel)
(a) Packaging correctness — runtime packages
| Check |
Pass condition |
| Exports map |
Every public subpath present; types condition first in every condition block |
| Declarations |
Real .d.ts resolvable for every subpath (verify with attw, not by eye) |
| peerDependencies |
Honest: frameworks/host libs as peers with ranges matching actual API usage; not duplicated in dependencies |
| sideEffects |
Correct: false (or list) with CSS/global-effect files excepted |
| files whitelist |
pack output contains everything runtime needs and nothing else (no src-only assumptions, no secrets) |
| Module format |
ESM/CJS reality matches declarations; no workspace:/path-alias leakage into published output |
| Registry metadata |
LICENSE, README (renders on the registry page), CHANGELOG, repository (+directory in monorepos), provenance where the ecosystem supports it |
(b) Public API contract
- UI value controls: controlled/uncontrolled duality (
value/defaultValue/onChange-style pairs); semantic callback names (onOpenChange, not setOpen/handleClick2)
ref handled per current ecosystem norm; stable ids wired via a useId-style mechanism, not hardcoded
- The stable public surface is documented; internals are not reachable through public entries
- No deprecated aliases before the first public release — rename and update all consumers/docs/registry files instead
- React-specific depth → react-senior-guide
(c) Division standard (file/component split)
- Detect the ecosystem norm the artifact targets (e.g. shadcn-style single file, per-part folders, flat one-file-per-component) and judge the split by-responsibility and ecosystem-compatible, not by personal taste
- For copy-distributed units: one install yields a complete, buildable unit; one obvious public entry per unit; remove/diff tooling treats the unit as the ownership boundary; docs list the installed file set
(d) Installability end-to-end
- Each channel verified separately; copy mode must rewrite package-only imports to local relative paths
- No dangling references: every documented command, item name, file target, and import specifier resolves
- Peer setup (CSS imports, provider wrapping, config files) is part of the install docs, not tribal knowledge
(e) A11y contract (UI libraries only)
- Each interactive component states its pattern contract (roles, keyboard table, focus behavior) somewhere consumable
- Deep verification is out of scope here → run accessibility-compliance
If the artifact handles user input, secrets, or network listeners (e.g. a CLI that starts a local server), also dispatch security-review.
Quality bar (2026 snapshot)
Snapshot dated 2026-06-10, distilled from researched sources. Refresh via websearch with the current year before trusting any version number or tool claim below.
Packaging (npm ecosystem):
publint + @arethetypeswrong/cli --pack are the standard mechanical pair; "types condition first in every condition block" is the named rule
- ESM-only is the accepted default for new packages (Node ≥20.19/22.12 can
require() ESM); dual CJS/ESM only for a concrete consumer need
sideEffects: false with CSS files excepted; files verified via pnpm pack
- Changesets is the standard versioning tool for pnpm monorepos; npm provenance/trusted publishing (OIDC) increasingly expected for public packages
- 0.x semver is honest pre-release signaling (
^0.x only patches within the minor), but README/LICENSE/CHANGELOG/repository.directory are still required
Component libraries (React line):
forwardRef is deprecated; ref-as-prop is the norm (React 19+). New library code should not contain forwardRef
- React Compiler v1.0: npm libraries pre-compile before publishing; copy-distributed source still follows "no defensive
useMemo/useCallback/memo" since consumer compiler use is unknown
- Consumers assume: controlled/uncontrolled pairs, state exposed as data-attributes (
data-state, data-slot) for Tailwind selectors, composition via asChild or a render prop, useId for ARIA wiring
- Tailwind v4 libs: ship uncompiled source CSS consumers
@import; never ship @import "tailwindcss" in dist CSS; document the @source "../node_modules/<pkg>" directive (v4 skips node_modules scanning)
"use client" must survive the build (bundlers strip directives by default) for RSC-host compatibility; peer ranges honest (>=19 for ref-as-prop, >=19.2 for useEffectEvent/Activity)
File division / registry distribution:
- The shadcn registry schema fully supports multi-file items (
files[] with per-file path, type, target; target placeholders preserve subdirectories) — both single-file (Radix/React Aria/classic shadcn) and per-part folders (Base UI, now a supported shadcn layer) are mainstream
- A multi-file-but-ecosystem-compatible unit MUST: (1) declare every file in the registry item with correct targets so one add is complete and buildable; (2) rewrite package-only imports to local relative paths in copy mode; (3) keep one obvious entry (
index.ts per unit); (4) have remove/diff treat the unit as the ownership boundary; (5) list the installed file set in docs
- Split by responsibility (part/hook/variants/types), never by line-count ritual — copy readers must still be able to skim
- Registry index (
registry.json) + per-item (registry-item.json); dependencies (npm) vs registryDependencies (other items); namespaced registries and CLI/MCP installs are current norms
- Copy/registry "published" = the committed public registry JSON is the contract; it must install cleanly via every advertised path — same bar as npm publish validation
Output
Produce exactly this report shape:
# Handoff Readiness — <artifact/repo name>
Detected artifact: <classification, e.g. "npm package + copy registry + CLI binary">
Detected channels (advertised):
- <channel> — evidence: <file path(s)>
## Per-channel scorecard
| Channel | Packaging | API contract | Division | Installability | A11y contract | Verdict |
|---|---|---|---|---|---|---|
| <channel> | PASS/FAIL/N/A | PASS/FAIL/N/A | PASS/FAIL/N/A | PASS/FAIL/N/A | PASS/FAIL/N/A | READY / BLOCKED |
## Blockers (ordered: what breaks the consumer first)
1. [BLOCKER] <channel> — <what a real consumer hits> — <file:line> — <concrete fix>
## Warnings (non-blocking)
1. [WARN] <channel> — <issue> — <file:line>
## Verification run
- <tool/command> → <result> (e.g. publint, attw --pack, pnpm pack inspection; or "not available: <why>")
## Verdict: READY | NOT READY (<n> blockers)
A channel is BLOCKED if any consumer-facing failure exists on it; the artifact is NOT READY if any advertised channel is blocked.
Common mistakes
- Auditing only the npm channel when copy/registry/CLI paths are also advertised — every documented path is a contract
- Eyeballing the exports map instead of running publint/attw; the map can look right and still resolve wrong types
- Treating a green internal monorepo build as proof consumers can build —
workspace: protocol, tsconfig path aliases, and sibling-source imports all vanish or break outside the repo
- Judging file division by taste instead of the detected ecosystem norm
- Marking READY with undocumented peer/CSS/provider setup ("it works in our app" is not install docs)
- Hardcoding one project's specifics as required checks — a Hono localhost server, a
dgadd-style CLI, or --tui-* tokens are illustrative shapes to detect, never assumed to exist
- Skipping the a11y-contract row for UI kits because "accessibility is a separate audit" — the contract's existence is part of handoff
- Re-explaining sibling skills inline instead of dispatching to accessibility-compliance, security-review, react-senior-guide, or reusability-audit
- Trusting the dated snapshot above without refreshing it against the current year
1---2name: handoff-readiness3description: Use when judging whether a publishable or reusable artifact — npm package, library, SDK, component kit, CLI binary, copy-paste/shadcn-style registry, or template — is ready to hand to real external users. Triggers include "is this publishable", "release ready", "handoff readiness", "can users actually install this", "audit package exports/types/peerDependencies", "pre-publish check", first public release, registry installability, or broken-consumer-import doubts.4---56# Handoff Readiness78## Overview910Readiness is judged **per consumption channel**, not per repo: first detect what is being handed off and every way the project itself advertises consuming it, then walk each channel end-to-end as a cold external consumer would. An artifact that builds internally but breaks on `npm install` or on copy-paste is NOT ready.1112## When to use / when NOT1314**Use for:**15- Pre-publish audits of packages, SDKs, CLIs, component kits, templates16- Hosted/copy registries (shadcn-style) before exposing them to users17- "Is this ready / can we ship / can we hand this off" questions about reusable artifacts18- Verifying exports maps, type declarations, peer dependencies, files whitelists1920**Do NOT use for:**21- Docs/content site deploy checks → see **docs-deploy-readiness**22- Internal cross-package reuse/duplication questions → see **reusability-audit**23- General code quality/architecture → see **code-audit**24- Deep security or a11y review → see **security-review**, **accessibility-compliance** (this skill only checks the *contract exists*)25- Running this audit across many packages with parallel agents → orchestrate via **convergence-loop**2627## How it works28291. **DETECT the artifact and its channels.** Read, in order: root + per-package manifests (`package.json` or ecosystem equivalent — `pyproject.toml`, `Cargo.toml`, `go.mod`), `exports`/`bin`/`files`/`main`/`types` fields, build config (tsup/rollup/vite/esbuild/etc.), any committed registry JSON directories, README + docs install instructions. Classify the artifact as one or more of:30 - **Runtime package** (installed from a registry like npm, imported at runtime)31 - **Copy/source distribution** (code lands in the consumer's repo: shadcn-style registry, template, "copy this folder")32 - **Hosted registry** (committed JSON/index that a CLI or tool resolves; illustrative example only: `public/r/*.json` consumed by a shadcn-compatible or project-specific add CLI)33 - **CLI binary** (`bin` entry, installed globally or via `npx`/`pnpm dlx`)34 - **Template/starter** (cloned, then built by the consumer)352. **Enumerate every ADVERTISED consumption path.** Only what the project documents counts as a channel — README install sections, docs "Installation" pages, registry index files, `bin` entries. Each advertised path becomes a row in the scorecard. An advertised-but-broken path is a blocker; an unadvertised path is out of scope.363. **Apply the universal bar (a–e below) to each channel.** Skip dimensions that don't apply (e.g. exports-map checks for a pure copy distribution) and mark them N/A — never silently.374. **Simulate the consumer journey statically per channel.** Follow the project's own install docs from zero: every referenced file, command, flag, alias, import specifier, and registry item must exist; no orphan imports (files importing siblings that the channel doesn't deliver); CSS/peer/env setup steps documented where required.385. **Run mechanical verifiers where tools exist.** For npm-ecosystem packages, `publint` and `@arethetypeswrong/cli --pack` are the named 2026 baseline; also inspect `pnpm pack` (or `npm pack --dry-run`) output against what runtime actually needs. Use ecosystem equivalents elsewhere (`twine check`, `cargo package --list`). Prefer running tools over eyeballing.396. **Score and report** using the Output format. Order blockers by what breaks the consumer first.4041## Quality bar (universal, per channel)4243### (a) Packaging correctness — runtime packages4445| Check | Pass condition |46|---|---|47| Exports map | Every public subpath present; `types` condition **first** in every condition block |48| Declarations | Real `.d.ts` resolvable for **every** subpath (verify with attw, not by eye) |49| peerDependencies | Honest: frameworks/host libs as peers with ranges matching actual API usage; not duplicated in `dependencies` |50| sideEffects | Correct: `false` (or list) with CSS/global-effect files excepted |51| files whitelist | `pack` output contains everything runtime needs and nothing else (no src-only assumptions, no secrets) |52| Module format | ESM/CJS reality matches declarations; no `workspace:`/path-alias leakage into published output |53| Registry metadata | LICENSE, README (renders on the registry page), CHANGELOG, `repository` (+`directory` in monorepos), provenance where the ecosystem supports it |5455### (b) Public API contract5657- UI value controls: controlled/uncontrolled duality (`value`/`defaultValue`/`onChange`-style pairs); semantic callback names (`onOpenChange`, not `setOpen`/`handleClick2`)58- `ref` handled per current ecosystem norm; stable ids wired via a `useId`-style mechanism, not hardcoded59- The stable public surface is documented; internals are not reachable through public entries60- **No deprecated aliases before the first public release** — rename and update all consumers/docs/registry files instead61- React-specific depth → **react-senior-guide**6263### (c) Division standard (file/component split)6465- Detect the ecosystem norm the artifact targets (e.g. shadcn-style single file, per-part folders, flat one-file-per-component) and judge the split **by-responsibility and ecosystem-compatible**, not by personal taste66- For copy-distributed units: one install yields a complete, buildable unit; one obvious public entry per unit; remove/diff tooling treats the unit as the ownership boundary; docs list the installed file set6768### (d) Installability end-to-end6970- Each channel verified separately; copy mode must rewrite package-only imports to local relative paths71- No dangling references: every documented command, item name, file target, and import specifier resolves72- Peer setup (CSS imports, provider wrapping, config files) is part of the install docs, not tribal knowledge7374### (e) A11y contract (UI libraries only)7576- Each interactive component states its pattern contract (roles, keyboard table, focus behavior) somewhere consumable77- Deep verification is out of scope here → run **accessibility-compliance**7879If the artifact handles user input, secrets, or network listeners (e.g. a CLI that starts a local server), also dispatch **security-review**.8081## Quality bar (2026 snapshot)8283Snapshot dated **2026-06-10**, distilled from researched sources. **Refresh via websearch with the current year before trusting any version number or tool claim below.**8485**Packaging (npm ecosystem):**86- `publint` + `@arethetypeswrong/cli --pack` are the standard mechanical pair; "types condition first in every condition block" is the named rule87- ESM-only is the accepted default for new packages (Node ≥20.19/22.12 can `require()` ESM); dual CJS/ESM only for a concrete consumer need88- `sideEffects: false` with CSS files excepted; `files` verified via `pnpm pack`89- Changesets is the standard versioning tool for pnpm monorepos; npm provenance/trusted publishing (OIDC) increasingly expected for public packages90- 0.x semver is honest pre-release signaling (`^0.x` only patches within the minor), but README/LICENSE/CHANGELOG/`repository.directory` are still required9192**Component libraries (React line):**93- `forwardRef` is deprecated; ref-as-prop is the norm (React 19+). New library code should not contain `forwardRef`94- React Compiler v1.0: npm libraries pre-compile before publishing; **copy-distributed** source still follows "no defensive `useMemo`/`useCallback`/`memo`" since consumer compiler use is unknown95- Consumers assume: controlled/uncontrolled pairs, state exposed as data-attributes (`data-state`, `data-slot`) for Tailwind selectors, composition via `asChild` or a `render` prop, `useId` for ARIA wiring96- Tailwind v4 libs: ship uncompiled source CSS consumers `@import`; never ship `@import "tailwindcss"` in dist CSS; document the `@source "../node_modules/<pkg>"` directive (v4 skips node_modules scanning)97- `"use client"` must survive the build (bundlers strip directives by default) for RSC-host compatibility; peer ranges honest (`>=19` for ref-as-prop, `>=19.2` for `useEffectEvent`/`Activity`)9899**File division / registry distribution:**100- The shadcn registry schema fully supports multi-file items (`files[]` with per-file `path`, `type`, `target`; target placeholders preserve subdirectories) — both single-file (Radix/React Aria/classic shadcn) and per-part folders (Base UI, now a supported shadcn layer) are mainstream101- A multi-file-but-ecosystem-compatible unit MUST: (1) declare every file in the registry item with correct targets so one add is complete and buildable; (2) rewrite package-only imports to local relative paths in copy mode; (3) keep one obvious entry (`index.ts` per unit); (4) have remove/diff treat the unit as the ownership boundary; (5) list the installed file set in docs102- Split by responsibility (part/hook/variants/types), never by line-count ritual — copy readers must still be able to skim103- Registry index (`registry.json`) + per-item (`registry-item.json`); `dependencies` (npm) vs `registryDependencies` (other items); namespaced registries and CLI/MCP installs are current norms104- Copy/registry "published" = the committed public registry JSON is the contract; it must install cleanly via **every** advertised path — same bar as npm publish validation105106## Output107108Produce exactly this report shape:109110```markdown111# Handoff Readiness — <artifact/repo name>112113Detected artifact: <classification, e.g. "npm package + copy registry + CLI binary">114Detected channels (advertised):115- <channel> — evidence: <file path(s)>116117## Per-channel scorecard118| Channel | Packaging | API contract | Division | Installability | A11y contract | Verdict |119|---|---|---|---|---|---|---|120| <channel> | PASS/FAIL/N/A | PASS/FAIL/N/A | PASS/FAIL/N/A | PASS/FAIL/N/A | PASS/FAIL/N/A | READY / BLOCKED |121122## Blockers (ordered: what breaks the consumer first)1231. [BLOCKER] <channel> — <what a real consumer hits> — <file:line> — <concrete fix>124125## Warnings (non-blocking)1261. [WARN] <channel> — <issue> — <file:line>127128## Verification run129- <tool/command> → <result> (e.g. publint, attw --pack, pnpm pack inspection; or "not available: <why>")130131## Verdict: READY | NOT READY (<n> blockers)132```133134A channel is **BLOCKED** if any consumer-facing failure exists on it; the artifact is **NOT READY** if any advertised channel is blocked.135136## Common mistakes137138- Auditing only the npm channel when copy/registry/CLI paths are also advertised — every documented path is a contract139- Eyeballing the exports map instead of running publint/attw; the map can look right and still resolve wrong types140- Treating a green internal monorepo build as proof consumers can build — `workspace:` protocol, tsconfig path aliases, and sibling-source imports all vanish or break outside the repo141- Judging file division by taste instead of the detected ecosystem norm142- Marking READY with undocumented peer/CSS/provider setup ("it works in our app" is not install docs)143- Hardcoding one project's specifics as required checks — a Hono localhost server, a `dgadd`-style CLI, or `--tui-*` tokens are illustrative shapes to *detect*, never assumed to exist144- Skipping the a11y-contract row for UI kits because "accessibility is a separate audit" — the contract's *existence* is part of handoff145- Re-explaining sibling skills inline instead of dispatching to **accessibility-compliance**, **security-review**, **react-senior-guide**, or **reusability-audit**146- Trusting the dated snapshot above without refreshing it against the current year