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.jsonor ecosystem equivalent —pyproject.toml,Cargo.toml,go.mod),exports/bin/files/main/typesfields, 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/*.jsonconsumed by a shadcn-compatible or project-specific add CLI) - CLI binary (
binentry, installed globally or vianpx/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,
binentries. 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,
publintand@arethetypeswrong/cli --packare the named 2026 baseline; also inspectpnpm pack(ornpm 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, notsetOpen/handleClick2) refhandled per current ecosystem norm; stable ids wired via auseId-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 --packare 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: falsewith CSS files excepted;filesverified viapnpm 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.xonly patches within the minor), but README/LICENSE/CHANGELOG/repository.directoryare still required
Component libraries (React line):
forwardRefis deprecated; ref-as-prop is the norm (React 19+). New library code should not containforwardRef- 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 viaasChildor arenderprop,useIdfor 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 (>=19for ref-as-prop,>=19.2foruseEffectEvent/Activity)
File division / registry distribution:
- The shadcn registry schema fully supports multi-file items (
files[]with per-filepath,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.tsper 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) vsregistryDependencies(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