@specdest/devkit
v0.4.8
Published
`@specdest/devkit` is the canonical Devkit CLI for Specdest repositories.
Downloads
2,326
Readme
@specdest/devkit
@specdest/devkit is the canonical Devkit CLI for Specdest repositories.
The CLI/core source is strict TypeScript. Development uses Node 24 directly; npm packaging uses plain tsc emit because Node does not strip TypeScript inside node_modules. No bundler or alternate runtime is used.
The npm package contains only the CLI/core runtime. Canonical rules stay in the private Devkit GitHub repository and are fetched with normal Git/SSH transport into a local machine cache when needed. Rule changes therefore do not require an npm release.
The root package API is intentionally small: runCli, COMMAND_NAMES, createCanonicalSource, createFlowCommandHandler, and createFuzzCommandHandler. Installer, state, sync, and canonical orchestration modules are internal implementation details.
modules/** is the canonical rule/module source. catalog/** is compatibility/test fixture data only; production CLI and release catalog generation do not read it.
Commands
npx @specdest/devkit status
npx @specdest/devkit add vite
npx @specdest/devkit sync
npx @specdest/devkit check [--refresh]
npx @specdest/devkit check --staged
npx @specdest/devkit check --files src/path/file.ts
npx @specdest/devkit rules
npx @specdest/devkit ai-instruction
npx @specdest/devkit doctor
npx @specdest/devkit fuzz
npx @specdest/devkit flow status
npx @specdest/devkit flow start --mode feature --goal "Add password reset" --task auth-reset
npx @specdest/devkit flow checkpoint --phase implement
npx @specdest/devkit flow verify
npx @specdest/devkit flow completestatusreads the cached canonical catalog and reports applicable/current/missing/outdated rules plus registered predefined packages. Use--refreshto refresh the catalog from GitHub and--jsonfor machine-readable output.add <package>applies or adopts a predefined package recipe. Package recipes use only three relationship primitives:requires,conflicts, and environment-selectedvariants.requiresis evaluated against packages registered in Devkit state; conflicts and variant selection also consider packages physically detected in the project. Status/doctor report stale package state, while sync/check/rules refuse to run against invalid package metadata. The supported foundational packages arevite,expo,supabase, andconvex. Additional predefined packages areauth,multi-tenancy,abac,sentry,logging,payments,shadcn,tanstack-router,tanstack-query,tanstack-form,storybook,playwright,vitest,local-logging,firebase-hosting,zod,tailwind,husky,nps,oxlint,oxfmt, andstryker. Create-or-adopt recipes include the foundations (vite,expo,supabase,convex) and deterministic self-contained tooling (zod,vitest,oxlint,oxfmt,husky,nps,tanstack-form,playwright,stryker). They create minimal local dependencies/configuration when absent, then runpnpm install; when an integration already exists they adopt it without rewriting project-owned application files. Runtime-wired or product-specific recipes remain adoption-only until Devkit has a deterministic, product-neutral installation contract. Recipes record the recipe version separately from any detected dependency version in.spd/installed.json; Devkit does not invent product-specific auth, tenancy, authorization, logging, or payment architecture. Generated/adopted application code remains project-owned. Package lifecycle is deliberately fire-and-forget: there is no packageremoveorupgradecommand. Developers remove packages manually; to update a recipe, re-runadd <package>. Re-adding applies only the current recipe and does not remove files/settings that existed only in an older recipe. Seedocs/package-model.md.syncrefreshes the canonical catalog, downloads only missing rule-cache entries, installs missing applicable rules, and updates outdated ones.checkexecutes each distinct canonical checker implementation once from the local Devkit cache and projects that result onto every rule backed by that checker. Use--refreshto refresh the canonical catalog/checker cache first without reconciling project files.--stagedresolves target paths/content from the Git index;--filessupplies explicit project-relative paths. Repository-scoped checkers still run globally. Targeted checks are ephemeral and do not update.spd/state.json; only a full check records canonical project status.rulesloads AI-facing guidance without dumping the whole catalog. Use--id <rule>,--category <category>,--failed, or--json; with no selector it returns only rules markedai.load = "always".doctorreports project-stack/cache setup problems.fuzzdynamically exercises Zod boundary contracts withfast-checkplus Specdest semantic amplifiers for nullish, blank-string, numeric/boolean, and array edge cases. It is separate from staticcheckand from Stryker mutation testing.flowmanages local, resumable development state under.spd/. Canonical workflows are fixed: Feature/Fix useplan → implement → verify → complete; Inspect usesplan → complete. Use--task <id>when multiple tasks exist and--context-file flow-notes/<task>.mdonly when rich working context is needed.flow verifyruns the repository's existing.husky/pre-pushgate when present, otherwise its packagecheckscript; completion requires a successful, still-current verification. Runtime state is local-only and removed on completion.
AI usage
npx @specdest/devkit ai-instruction prints the minimal, tool-agnostic bootstrap for coding agents. Agents should inspect DevKit Flow state before repository work, while semantic task classification and worktree choice remain agent-policy decisions. DevKit Flow owns persisted task state, phase transitions, verification, and completion; DevKit rules/checks own deterministic repository enforcement. Agent-specific policy such as ChatGPT's @specdest-development skill belongs outside DevKit rather than being duplicated in the CLI.
The CLI resolves a project stack from supported Expo/Vite + Convex/Supabase package dependencies when possible; otherwise it uses the single committed requested stack-* root in .spd/installed.json. Explicit predefined-package registrations are committed as requested kind: "package" entries with separate recipeVersion and detectedVersion fields, and are preserved by canonical rule sync. Foundational adapters such as Vite use the same recipe mechanism as feature packages; role metadata distinguishes frontend/backend/foundation intent without a separate installer architecture. Canonical rules may declare requiredPackages (for example vite or supabase) instead of enumerating every compatible stack; legacy stack applicability remains supported during migration. Optional .spd/rules.json adds the project type/capabilities plus explicit rule includes/exclusions; every exclusion requires a reason. .spd/installed.json and .spd/state.json remain the committed project status used by the Base rules matrix.
.spd/ is the canonical local Specdest metadata namespace. Normal DevKit usage automatically renames a legacy .specdest/ directory to .spd/ when no canonical directory exists. If both directories exist, .spd/ wins only when every legacy file has an identical canonical counterpart; legacy-only or differing files fail with an explicit metadata namespace conflict instead of being overwritten. During sync, legacy managed-markdown ownership records are normalized to the current section format only after their recorded hash still matches the project content, preserving conflict protection while allowing older adopted repositories to migrate.
See docs/operations.md for cache, dashboard, CI, and release behavior.
Contract fuzzing
npx @specdest/devkit fuzz runs against the current repository. By default it discovers the boundary filenames already used by the canonical architecture rules: *.input.schema.ts, *.output.schema.ts, *.form.schema.ts, and *.callbackInput.schema.ts under src/ and supabase/functions/. It loads the project's own Zod schemas; Devkit does not require or bundle a second runtime Zod instance.
The v1 adapter supports Zod objects, strings, numbers, booleans, arrays, enums, optional, nullable/nullish wrappers, and practical min/max boundaries. It amplifies values such as null, undefined, omitted properties, empty/whitespace strings, 0, false, NaN, empty arrays, nullish array items, duplicates, reordering, and item removal. Accepted empty/whitespace strings are reported as semantic failures because they are commonly indistinguishable from absent user input at Specdest boundaries. Failures include the fast-check seed/path when applicable.
If default discovery is not appropriate, add .spd/fuzz.json:
{
"schemaVersion": 1,
"targets": [
{ "module": "src/application/user/update.input.schema.ts", "exports": ["userUpdateInputSchema"] }
]
}Current module loading supports Node 24 TypeScript, extensionless relative imports, and the Specdest @/* -> src/* alias convention. Unsupported schema constructs or unloadable modules are reported explicitly as SKIP; they are never silently interpreted.
Canonical cache runtime
Canonical authoring lives under modules/**. The CLI refreshes a single-branch bare Git source and hydrates required modules from the same catalog revision into the local Devkit cache and materializes their .agents/skills/** target layout inside the cache so checker-relative imports keep working without copying canonical skills/checkers into project repositories. catalog/** is compatibility/test data, not a rule-authoring source.
Project state has one runtime owner: src/state.ts reads, validates, formats, and atomically writes .spd/installed.json and .spd/state.json. Sync/install/check code must use that module rather than implementing state IO independently.
Project applicability has one runtime owner: src/project-context.ts detects the stack, reads .spd/rules.json, resolves project type/capabilities, validates overrides, and selects applicable canonical rules.
Project operations are split by behavior: project-status.ts, project-sync.ts, project-check.ts, and project-rules.ts; commands.ts is only the CLI adapter, while canonical-project-operations.ts remains a compatibility re-export.
The canonical installer intentionally supports only managed file copies, create-once scaffold files, and managed Markdown sections. Canonical manifests must not rely on generic JSON/YAML/env mutation, directory-copy, delete, or lifecycle-script operations.
The legacy generic sync planner (sync-core.js), shared-file mutation runtime, and setup-requirement evaluator have been removed from the shipped CLI. Compatibility catalog validation for those historical manifest shapes lives only under test/support.
