voidmachine 0.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +123 -4
- package/bin/void-harness.mjs +12 -0
- package/bin/void-machine.mjs +12 -0
- package/core-assets/.claude-plugin/plugin.json +253 -0
- package/core-assets/.gitkeep +0 -0
- package/core-assets/PHILOSOPHY.md +218 -0
- package/core-assets/PROJECT-DOCTRINE.template.md +14 -0
- package/core-assets/adapters/security/manifest.yaml +96 -0
- package/core-assets/agents/.gitkeep +0 -0
- package/core-assets/agents/accessibility-specialist.md +59 -0
- package/core-assets/agents/api-integration-engineer.md +59 -0
- package/core-assets/agents/code-explorer.md +94 -0
- package/core-assets/agents/code-explorer.source +7 -0
- package/core-assets/agents/data-migration-engineer.md +59 -0
- package/core-assets/agents/devex-docs-engineer.md +57 -0
- package/core-assets/agents/doctrine-critic.md +91 -0
- package/core-assets/agents/doctrine-critic.source +11 -0
- package/core-assets/agents/domain-architect.md +56 -0
- package/core-assets/agents/experience-designer.md +59 -0
- package/core-assets/agents/frontend-engineer.md +60 -0
- package/core-assets/agents/independent-code-reviewer.md +61 -0
- package/core-assets/agents/migration-planner.md +97 -0
- package/core-assets/agents/migration-planner.source +7 -0
- package/core-assets/agents/observability-sre-engineer.md +59 -0
- package/core-assets/agents/pdf-specialist.md +58 -0
- package/core-assets/agents/performance-engineer.md +58 -0
- package/core-assets/agents/product-challenger.md +55 -0
- package/core-assets/agents/security-engineer.md +66 -0
- package/core-assets/agents/silent-failure-hunter.md +94 -0
- package/core-assets/agents/silent-failure-hunter.source +8 -0
- package/core-assets/agents/solution-architect.md +57 -0
- package/core-assets/agents/test-qa-engineer.md +60 -0
- package/core-assets/agents/type-design-analyzer.md +93 -0
- package/core-assets/agents/type-design-analyzer.source +8 -0
- package/core-assets/agents/visual-craft-director.md +62 -0
- package/core-assets/codex/hooks.json +157 -0
- package/core-assets/contract-history/visual-craft-director/v2.yaml +43 -0
- package/core-assets/data/catalog.v3.json +10479 -0
- package/core-assets/data/certification.json +1800 -0
- package/core-assets/data/identity.json +8 -0
- package/core-assets/data/model.json +4226 -0
- package/core-assets/enforce/ci-enforce.sh +183 -0
- package/core-assets/hooks/_checks.sh +145 -0
- package/core-assets/hooks/_hooklib.sh +163 -0
- package/core-assets/hooks/_syntax-worker.cjs +503 -0
- package/core-assets/hooks/_void-hook.mjs +5459 -0
- package/core-assets/hooks/activation-meter.sh +13 -0
- package/core-assets/hooks/anti-ai-slop-grep.sh +38 -0
- package/core-assets/hooks/auto-format.sh +9 -0
- package/core-assets/hooks/axe-precommit.sh +35 -0
- package/core-assets/hooks/block-dangerous-bash.sh +10 -0
- package/core-assets/hooks/block-protected-push.sh +81 -0
- package/core-assets/hooks/boundary-direction-check.sh +10 -0
- package/core-assets/hooks/control-character-grep.sh +10 -0
- package/core-assets/hooks/fowler-refactors.txt +71 -0
- package/core-assets/hooks/large-cl-grep.sh +9 -0
- package/core-assets/hooks/llm-cost-precommit.sh +55 -0
- package/core-assets/hooks/migration-lint.sh +58 -0
- package/core-assets/hooks/migration-pr-template.sh +55 -0
- package/core-assets/hooks/no-ai-design-slop.sh +10 -0
- package/core-assets/hooks/no-any-grep.sh +10 -0
- package/core-assets/hooks/no-as-cast-grep.sh +10 -0
- package/core-assets/hooks/no-console-log-grep.sh +10 -0
- package/core-assets/hooks/no-null-grep.sh +10 -0
- package/core-assets/hooks/no-only-no-skip.sh +10 -0
- package/core-assets/hooks/outcome-meter.sh +13 -0
- package/core-assets/hooks/pre-PR-review-evidence.sh +47 -0
- package/core-assets/hooks/protect-sensitive-files.sh +10 -0
- package/core-assets/hooks/refactor-named-grep.sh +49 -0
- package/core-assets/hooks/secret-in-content.sh +10 -0
- package/core-assets/hooks/sessionstart-context.sh +9 -0
- package/core-assets/hooks/stop-typecheck.sh +9 -0
- package/core-assets/hooks/tdd-guard.md +90 -0
- package/core-assets/hooks/tdd-guard.sh +10 -0
- package/core-assets/hooks/test-name-lint.sh +10 -0
- package/core-assets/hooks/tidying-commit-prefix.sh +37 -0
- package/core-assets/hooks/trim-large-output.sh +9 -0
- package/core-assets/hooks/tsc-noemit-precommit.sh +22 -0
- package/core-assets/hooks/ubiquitous-language-lint.sh +58 -0
- package/core-assets/hooks/viewport-screenshot-gate.sh +48 -0
- package/core-assets/modules/.gitkeep +0 -0
- package/core-assets/packs/pack-mobile/skills/void-eas-build-profile/.source +7 -0
- package/core-assets/packs/pack-mobile/skills/void-eas-build-profile/SKILL.md +164 -0
- package/core-assets/packs/pack-mobile/skills/void-eas-build-profile/harness.yaml +14 -0
- package/core-assets/packs/pack-mobile/skills/void-expo-config-plugins/.source +7 -0
- package/core-assets/packs/pack-mobile/skills/void-expo-config-plugins/SKILL.md +178 -0
- package/core-assets/packs/pack-mobile/skills/void-expo-config-plugins/harness.yaml +14 -0
- package/core-assets/packs/pack-mobile/skills/void-expo-router-pattern/.source +8 -0
- package/core-assets/packs/pack-mobile/skills/void-expo-router-pattern/SKILL.md +209 -0
- package/core-assets/packs/pack-mobile/skills/void-expo-router-pattern/harness.yaml +14 -0
- package/core-assets/packs/pack-mobile/skills/void-ota-update-strategy/.source +7 -0
- package/core-assets/packs/pack-mobile/skills/void-ota-update-strategy/SKILL.md +194 -0
- package/core-assets/packs/pack-mobile/skills/void-ota-update-strategy/harness.yaml +14 -0
- package/core-assets/packs/pack-monorepo/skills/void-dependency-direction/.source +5 -0
- package/core-assets/packs/pack-monorepo/skills/void-dependency-direction/SKILL.md +160 -0
- package/core-assets/packs/pack-monorepo/skills/void-dependency-direction/harness.yaml +14 -0
- package/core-assets/packs/pack-monorepo/skills/void-package-extraction/.source +5 -0
- package/core-assets/packs/pack-monorepo/skills/void-package-extraction/SKILL.md +70 -0
- package/core-assets/packs/pack-monorepo/skills/void-package-extraction/harness.yaml +14 -0
- package/core-assets/packs/pack-monorepo/skills/void-service-package/.source +5 -0
- package/core-assets/packs/pack-monorepo/skills/void-service-package/SKILL.md +122 -0
- package/core-assets/packs/pack-monorepo/skills/void-service-package/harness.yaml +14 -0
- package/core-assets/packs/pack-monorepo/skills/void-turbo-pipeline-tuning/.source +7 -0
- package/core-assets/packs/pack-monorepo/skills/void-turbo-pipeline-tuning/SKILL.md +116 -0
- package/core-assets/packs/pack-monorepo/skills/void-turbo-pipeline-tuning/harness.yaml +14 -0
- package/core-assets/packs/pack-nextjs/skills/void-cache-component-pattern/.source +5 -0
- package/core-assets/packs/pack-nextjs/skills/void-cache-component-pattern/SKILL.md +162 -0
- package/core-assets/packs/pack-nextjs/skills/void-cache-component-pattern/harness.yaml +14 -0
- package/core-assets/packs/pack-nextjs/skills/void-instrumentation-setup/.source +5 -0
- package/core-assets/packs/pack-nextjs/skills/void-instrumentation-setup/SKILL.md +161 -0
- package/core-assets/packs/pack-nextjs/skills/void-instrumentation-setup/harness.yaml +14 -0
- package/core-assets/packs/pack-nextjs/skills/void-loading-error-boundaries/.source +5 -0
- package/core-assets/packs/pack-nextjs/skills/void-loading-error-boundaries/SKILL.md +176 -0
- package/core-assets/packs/pack-nextjs/skills/void-loading-error-boundaries/harness.yaml +14 -0
- package/core-assets/packs/pack-nextjs/skills/void-parallel-routes-slots/.source +5 -0
- package/core-assets/packs/pack-nextjs/skills/void-parallel-routes-slots/SKILL.md +129 -0
- package/core-assets/packs/pack-nextjs/skills/void-parallel-routes-slots/harness.yaml +14 -0
- package/core-assets/packs/pack-nextjs/skills/void-route-group-decision/.source +5 -0
- package/core-assets/packs/pack-nextjs/skills/void-route-group-decision/SKILL.md +107 -0
- package/core-assets/packs/pack-nextjs/skills/void-route-group-decision/harness.yaml +14 -0
- package/core-assets/packs/pack-pwa/skills/void-install-prompt-ux/.source +5 -0
- package/core-assets/packs/pack-pwa/skills/void-install-prompt-ux/SKILL.md +153 -0
- package/core-assets/packs/pack-pwa/skills/void-install-prompt-ux/harness.yaml +14 -0
- package/core-assets/packs/pack-pwa/skills/void-manifest-checklist/.source +5 -0
- package/core-assets/packs/pack-pwa/skills/void-manifest-checklist/SKILL.md +204 -0
- package/core-assets/packs/pack-pwa/skills/void-manifest-checklist/harness.yaml +14 -0
- package/core-assets/packs/pack-pwa/skills/void-offline-first-mutation/.source +8 -0
- package/core-assets/packs/pack-pwa/skills/void-offline-first-mutation/SKILL.md +266 -0
- package/core-assets/packs/pack-pwa/skills/void-offline-first-mutation/harness.yaml +14 -0
- package/core-assets/packs/pack-pwa/skills/void-service-worker-strategy/.source +5 -0
- package/core-assets/packs/pack-pwa/skills/void-service-worker-strategy/SKILL.md +178 -0
- package/core-assets/packs/pack-pwa/skills/void-service-worker-strategy/harness.yaml +14 -0
- package/core-assets/packs/pack-react/skills/void-accessibility-check/.source +8 -0
- package/core-assets/packs/pack-react/skills/void-accessibility-check/SKILL.md +136 -0
- package/core-assets/packs/pack-react/skills/void-accessibility-check/harness.yaml +14 -0
- package/core-assets/packs/pack-react/skills/void-client-vs-server-component/.source +5 -0
- package/core-assets/packs/pack-react/skills/void-client-vs-server-component/SKILL.md +116 -0
- package/core-assets/packs/pack-react/skills/void-client-vs-server-component/harness.yaml +14 -0
- package/core-assets/packs/pack-react/skills/void-form-pattern/.source +7 -0
- package/core-assets/packs/pack-react/skills/void-form-pattern/SKILL.md +157 -0
- package/core-assets/packs/pack-react/skills/void-form-pattern/harness.yaml +14 -0
- package/core-assets/packs/pack-react/skills/void-state-architecture/.source +5 -0
- package/core-assets/packs/pack-react/skills/void-state-architecture/SKILL.md +160 -0
- package/core-assets/packs/pack-react/skills/void-state-architecture/harness.yaml +14 -0
- package/core-assets/packs/pack-server/skills/void-background-job-pattern/.source +6 -0
- package/core-assets/packs/pack-server/skills/void-background-job-pattern/SKILL.md +214 -0
- package/core-assets/packs/pack-server/skills/void-background-job-pattern/harness.yaml +14 -0
- package/core-assets/packs/pack-server/skills/void-drizzle-migration-safe/.source +6 -0
- package/core-assets/packs/pack-server/skills/void-drizzle-migration-safe/SKILL.md +168 -0
- package/core-assets/packs/pack-server/skills/void-drizzle-migration-safe/harness.yaml +14 -0
- package/core-assets/packs/pack-server/skills/void-env-validation/.source +6 -0
- package/core-assets/packs/pack-server/skills/void-env-validation/SKILL.md +131 -0
- package/core-assets/packs/pack-server/skills/void-env-validation/harness.yaml +14 -0
- package/core-assets/packs/pack-server/skills/void-rate-limit-strategy/.source +6 -0
- package/core-assets/packs/pack-server/skills/void-rate-limit-strategy/SKILL.md +149 -0
- package/core-assets/packs/pack-server/skills/void-rate-limit-strategy/harness.yaml +14 -0
- package/core-assets/packs/pack-server/skills/void-server-action/.source +7 -0
- package/core-assets/packs/pack-server/skills/void-server-action/SKILL.md +181 -0
- package/core-assets/packs/pack-server/skills/void-server-action/harness.yaml +14 -0
- package/core-assets/packs/pack-server/skills/void-testing-server-modules/.source +7 -0
- package/core-assets/packs/pack-server/skills/void-testing-server-modules/SKILL.md +73 -0
- package/core-assets/packs/pack-server/skills/void-testing-server-modules/harness.yaml +14 -0
- package/core-assets/packs/pack-server/skills/void-webhook-handler-pattern/.source +7 -0
- package/core-assets/packs/pack-server/skills/void-webhook-handler-pattern/SKILL.md +205 -0
- package/core-assets/packs/pack-server/skills/void-webhook-handler-pattern/harness.yaml +14 -0
- package/core-assets/policies/core.yaml +95 -0
- package/core-assets/policies/ui.yaml +23 -0
- package/core-assets/profiles/base.yaml +29 -0
- package/core-assets/profiles/expo-config.yaml +36 -0
- package/core-assets/profiles/expo.yaml +35 -0
- package/core-assets/profiles/monorepo.yaml +33 -0
- package/core-assets/profiles/nextjs-config.yaml +31 -0
- package/core-assets/profiles/nextjs.yaml +31 -0
- package/core-assets/profiles/node-server.yaml +31 -0
- package/core-assets/profiles/pwa.yaml +33 -0
- package/core-assets/profiles/react.yaml +39 -0
- package/core-assets/profiles/sql.yaml +39 -0
- package/core-assets/profiles/typescript.yaml +39 -0
- package/core-assets/skills/.gitkeep +0 -0
- package/core-assets/skills/void-accessibility/.source +15 -0
- package/core-assets/skills/void-accessibility/SKILL.md +275 -0
- package/core-assets/skills/void-accessibility/harness.yaml +17 -0
- package/core-assets/skills/void-api-and-interface-design/.source +13 -0
- package/core-assets/skills/void-api-and-interface-design/SKILL.md +231 -0
- package/core-assets/skills/void-api-and-interface-design/harness.yaml +16 -0
- package/core-assets/skills/void-async-safety/.source +13 -0
- package/core-assets/skills/void-async-safety/SKILL.md +287 -0
- package/core-assets/skills/void-async-safety/harness.yaml +16 -0
- package/core-assets/skills/void-audit/.source +15 -0
- package/core-assets/skills/void-audit/SKILL.md +83 -0
- package/core-assets/skills/void-audit/harness.yaml +14 -0
- package/core-assets/skills/void-autopilot/.source +21 -0
- package/core-assets/skills/void-autopilot/SKILL.md +358 -0
- package/core-assets/skills/void-autopilot/harness.yaml +14 -0
- package/core-assets/skills/void-brainstorm/.source +14 -0
- package/core-assets/skills/void-brainstorm/SKILL.md +271 -0
- package/core-assets/skills/void-brainstorm/harness.yaml +14 -0
- package/core-assets/skills/void-checkpoint/.source +39 -0
- package/core-assets/skills/void-checkpoint/SKILL.md +227 -0
- package/core-assets/skills/void-checkpoint/harness.yaml +14 -0
- package/core-assets/skills/void-claude-md/.source +15 -0
- package/core-assets/skills/void-claude-md/SKILL.md +180 -0
- package/core-assets/skills/void-claude-md/harness.yaml +14 -0
- package/core-assets/skills/void-code-review/.source +14 -0
- package/core-assets/skills/void-code-review/SKILL.md +232 -0
- package/core-assets/skills/void-code-review/harness.yaml +15 -0
- package/core-assets/skills/void-commit-discipline/.source +9 -0
- package/core-assets/skills/void-commit-discipline/SKILL.md +211 -0
- package/core-assets/skills/void-commit-discipline/harness.yaml +15 -0
- package/core-assets/skills/void-context/.source +15 -0
- package/core-assets/skills/void-context/SKILL.md +167 -0
- package/core-assets/skills/void-context/harness.yaml +14 -0
- package/core-assets/skills/void-debug/.source +11 -0
- package/core-assets/skills/void-debug/SKILL.md +211 -0
- package/core-assets/skills/void-debug/harness.yaml +14 -0
- package/core-assets/skills/void-decide/.source +9 -0
- package/core-assets/skills/void-decide/SKILL.md +147 -0
- package/core-assets/skills/void-decide/harness.yaml +14 -0
- package/core-assets/skills/void-devex-audit/.source +8 -0
- package/core-assets/skills/void-devex-audit/SKILL.md +113 -0
- package/core-assets/skills/void-devex-audit/harness.yaml +15 -0
- package/core-assets/skills/void-doctor/.source +15 -0
- package/core-assets/skills/void-doctor/SKILL.md +83 -0
- package/core-assets/skills/void-doctor/harness.yaml +14 -0
- package/core-assets/skills/void-domain-driven-design/.source +13 -0
- package/core-assets/skills/void-domain-driven-design/SKILL.md +292 -0
- package/core-assets/skills/void-domain-driven-design/harness.yaml +15 -0
- package/core-assets/skills/void-frontend-design/.source +19 -0
- package/core-assets/skills/void-frontend-design/SKILL.md +274 -0
- package/core-assets/skills/void-frontend-design/harness.yaml +17 -0
- package/core-assets/skills/void-functional/.source +14 -0
- package/core-assets/skills/void-functional/SKILL.md +312 -0
- package/core-assets/skills/void-functional/harness.yaml +15 -0
- package/core-assets/skills/void-graph/.source +15 -0
- package/core-assets/skills/void-graph/SKILL.md +80 -0
- package/core-assets/skills/void-graph/harness.yaml +14 -0
- package/core-assets/skills/void-hexagonal-architecture/.source +12 -0
- package/core-assets/skills/void-hexagonal-architecture/SKILL.md +276 -0
- package/core-assets/skills/void-hexagonal-architecture/harness.yaml +15 -0
- package/core-assets/skills/void-implement/.source +39 -0
- package/core-assets/skills/void-implement/SKILL.md +183 -0
- package/core-assets/skills/void-implement/harness.yaml +14 -0
- package/core-assets/skills/void-learn/.source +13 -0
- package/core-assets/skills/void-learn/SKILL.md +226 -0
- package/core-assets/skills/void-learn/harness.yaml +14 -0
- package/core-assets/skills/void-llm-cost-discipline/.source +13 -0
- package/core-assets/skills/void-llm-cost-discipline/SKILL.md +299 -0
- package/core-assets/skills/void-llm-cost-discipline/harness.yaml +15 -0
- package/core-assets/skills/void-make-pdf/.source +9 -0
- package/core-assets/skills/void-make-pdf/SKILL.md +52 -0
- package/core-assets/skills/void-make-pdf/harness.yaml +15 -0
- package/core-assets/skills/void-merge/.source +8 -0
- package/core-assets/skills/void-merge/SKILL.md +111 -0
- package/core-assets/skills/void-merge/harness.yaml +14 -0
- package/core-assets/skills/void-migrations/.source +13 -0
- package/core-assets/skills/void-migrations/SKILL.md +264 -0
- package/core-assets/skills/void-migrations/harness.yaml +17 -0
- package/core-assets/skills/void-observability/.source +12 -0
- package/core-assets/skills/void-observability/SKILL.md +245 -0
- package/core-assets/skills/void-observability/harness.yaml +15 -0
- package/core-assets/skills/void-plan/.source +15 -0
- package/core-assets/skills/void-plan/SKILL.md +239 -0
- package/core-assets/skills/void-plan/harness.yaml +14 -0
- package/core-assets/skills/void-plan-review/.source +12 -0
- package/core-assets/skills/void-plan-review/SKILL.md +128 -0
- package/core-assets/skills/void-plan-review/harness.yaml +15 -0
- package/core-assets/skills/void-qa/.source +15 -0
- package/core-assets/skills/void-qa/SKILL.md +103 -0
- package/core-assets/skills/void-qa/harness.yaml +15 -0
- package/core-assets/skills/void-refactor/.source +9 -0
- package/core-assets/skills/void-refactor/SKILL.md +220 -0
- package/core-assets/skills/void-refactor/harness.yaml +15 -0
- package/core-assets/skills/void-retrospective/.source +9 -0
- package/core-assets/skills/void-retrospective/SKILL.md +71 -0
- package/core-assets/skills/void-retrospective/harness.yaml +15 -0
- package/core-assets/skills/void-security-audit/.source +12 -0
- package/core-assets/skills/void-security-audit/SKILL.md +138 -0
- package/core-assets/skills/void-security-audit/harness.yaml +15 -0
- package/core-assets/skills/void-security-guidance/.source +12 -0
- package/core-assets/skills/void-security-guidance/SKILL.md +255 -0
- package/core-assets/skills/void-security-guidance/harness.yaml +15 -0
- package/core-assets/skills/void-source-driven-development/.source +12 -0
- package/core-assets/skills/void-source-driven-development/SKILL.md +158 -0
- package/core-assets/skills/void-source-driven-development/harness.yaml +15 -0
- package/core-assets/skills/void-tdd/.source +15 -0
- package/core-assets/skills/void-tdd/SKILL.md +394 -0
- package/core-assets/skills/void-tdd/harness.yaml +15 -0
- package/core-assets/skills/void-testing/.source +19 -0
- package/core-assets/skills/void-testing/SKILL.md +301 -0
- package/core-assets/skills/void-testing/harness.yaml +17 -0
- package/core-assets/skills/void-ticket/.source +18 -0
- package/core-assets/skills/void-ticket/SKILL.md +239 -0
- package/core-assets/skills/void-ticket/harness.yaml +14 -0
- package/core-assets/skills/void-typescript-strict/.source +10 -0
- package/core-assets/skills/void-typescript-strict/SKILL.md +294 -0
- package/core-assets/skills/void-typescript-strict/harness.yaml +17 -0
- package/core-assets/skills/void-ui-review/.source +12 -0
- package/core-assets/skills/void-ui-review/SKILL.md +97 -0
- package/core-assets/skills/void-ui-review/harness.yaml +15 -0
- package/core-assets/skills/void-verify/.source +12 -0
- package/core-assets/skills/void-verify/SKILL.md +184 -0
- package/core-assets/skills/void-verify/harness.yaml +15 -0
- package/core-assets/specialists/accessibility-specialist.source +11 -0
- package/core-assets/specialists/accessibility-specialist.yaml +30 -0
- package/core-assets/specialists/api-integration-engineer.source +11 -0
- package/core-assets/specialists/api-integration-engineer.yaml +30 -0
- package/core-assets/specialists/data-migration-engineer.source +11 -0
- package/core-assets/specialists/data-migration-engineer.yaml +30 -0
- package/core-assets/specialists/devex-docs-engineer.source +11 -0
- package/core-assets/specialists/devex-docs-engineer.yaml +29 -0
- package/core-assets/specialists/domain-architect.source +11 -0
- package/core-assets/specialists/domain-architect.yaml +28 -0
- package/core-assets/specialists/experience-designer.source +15 -0
- package/core-assets/specialists/experience-designer.yaml +38 -0
- package/core-assets/specialists/frontend-engineer.source +11 -0
- package/core-assets/specialists/frontend-engineer.yaml +32 -0
- package/core-assets/specialists/independent-code-reviewer.source +10 -0
- package/core-assets/specialists/independent-code-reviewer.yaml +37 -0
- package/core-assets/specialists/migrations.json +15 -0
- package/core-assets/specialists/observability-sre-engineer.source +11 -0
- package/core-assets/specialists/observability-sre-engineer.yaml +30 -0
- package/core-assets/specialists/pdf-specialist.source +11 -0
- package/core-assets/specialists/pdf-specialist.yaml +29 -0
- package/core-assets/specialists/performance-engineer.source +11 -0
- package/core-assets/specialists/performance-engineer.yaml +29 -0
- package/core-assets/specialists/product-challenger.source +10 -0
- package/core-assets/specialists/product-challenger.yaml +27 -0
- package/core-assets/specialists/security-engineer.source +13 -0
- package/core-assets/specialists/security-engineer.yaml +41 -0
- package/core-assets/specialists/solution-architect.source +13 -0
- package/core-assets/specialists/solution-architect.yaml +32 -0
- package/core-assets/specialists/test-qa-engineer.source +14 -0
- package/core-assets/specialists/test-qa-engineer.yaml +35 -0
- package/core-assets/specialists/visual-craft-director.source +17 -0
- package/core-assets/specialists/visual-craft-director.yaml +60 -0
- package/core-assets/templates/github/dependency-audit.mjs +54 -0
- package/core-assets/templates/github/void-dependency-audit.yml +35 -0
- package/core-assets/templates/github/void-security.yml +85 -0
- package/dist/main.js +57001 -0
- package/package.json +66 -4
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
schemaVersion: 1
|
|
2
|
+
id: core:typescript
|
|
3
|
+
version: 2
|
|
4
|
+
name: typescript
|
|
5
|
+
technologies:
|
|
6
|
+
- id: typescript
|
|
7
|
+
versionIndependent: true
|
|
8
|
+
detectors:
|
|
9
|
+
always: false
|
|
10
|
+
technologies: [typescript]
|
|
11
|
+
files:
|
|
12
|
+
extensions: [.ts, .tsx, .mts, .cts]
|
|
13
|
+
names: [tsconfig.json]
|
|
14
|
+
pathSegments: []
|
|
15
|
+
sources:
|
|
16
|
+
- title: TypeScript documentation
|
|
17
|
+
url: https://www.typescriptlang.org/docs/
|
|
18
|
+
reviewedAt: 2026-07-27
|
|
19
|
+
expiresAfterDays: 180
|
|
20
|
+
invariants:
|
|
21
|
+
- Keep strict type checking enabled and validate untrusted runtime input.
|
|
22
|
+
- Prefer narrow types and pure helpers over assertions and ambient mutation.
|
|
23
|
+
patterns:
|
|
24
|
+
- id: typed-source
|
|
25
|
+
appliesWhen:
|
|
26
|
+
technologies: [typescript]
|
|
27
|
+
files:
|
|
28
|
+
extensions: [.ts, .tsx, .mts, .cts]
|
|
29
|
+
names: []
|
|
30
|
+
pathSegments: []
|
|
31
|
+
guidance: Model domain states explicitly and keep unsafe narrowing at named boundaries.
|
|
32
|
+
- id: compiler-config
|
|
33
|
+
appliesWhen:
|
|
34
|
+
technologies: [typescript]
|
|
35
|
+
files:
|
|
36
|
+
extensions: []
|
|
37
|
+
names: [tsconfig.json]
|
|
38
|
+
pathSegments: []
|
|
39
|
+
guidance: Preserve strictness and verify the effective compiler configuration.
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Sources for `void-accessibility` skill (see `docs/plans/skill-audits/void-accessibility.md` for full audit):
|
|
2
|
+
|
|
3
|
+
- WCAG 2.2 AA — https://www.w3.org/WAI/WCAG22/quickref/ — target level
|
|
4
|
+
- Radix UI primitives — https://www.radix-ui.com — no hand-rolled a11y
|
|
5
|
+
- Apple HIG touch targets — https://developer.apple.com/design/human-interface-guidelines — ≥ 44×44 minimum
|
|
6
|
+
- WAI-ARIA Authoring Practices — https://www.w3.org/WAI/ARIA/apg/ — reference for custom widgets
|
|
7
|
+
- axe-core — https://www.deque.com/axe/ — static analysis baseline
|
|
8
|
+
- Folpe mobile-first dual-quality — PHILOSOPHY.md (this repo)
|
|
9
|
+
- citypaul/.dotfiles a11y notes
|
|
10
|
+
|
|
11
|
+
Strategy: distill. Compose with frontend-design (separate skill, vendored from Vercel plugin).
|
|
12
|
+
|
|
13
|
+
Companion hooks: axe-precommit, viewport-screenshot-gate (shared with frontend-design).
|
|
14
|
+
|
|
15
|
+
Stack-specific Tappable helper + Radix-wrapped @repo/ui + axe-core integration in pack-nextjs-pwa.
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: void-accessibility
|
|
3
|
+
description: WCAG 2.2 AA floor. Radix primitives only, touch >=44x44, keyboard parity, semantic HTML, form labels, aria-live errors, mobile-first dual-quality. Use when building or modifying UI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# accessibility — voidcorp craftsman edition
|
|
7
|
+
|
|
8
|
+
A11y is not a launch-time audit. It is the default at every interactive surface. Radix handles the hard parts; we honor the rules. Mobile-first dual-quality means both viewports ship at first-class quality.
|
|
9
|
+
|
|
10
|
+
**Attribution**: see `.source`. Foundation: WCAG 2.2 AA + Radix UI + Apple HIG + WAI-ARIA APG + Folpe mobile-first dual-quality.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## The floor
|
|
15
|
+
|
|
16
|
+
WCAG 2.2 AA is the minimum. Not the goal — the floor. Specific projects (regulated, public-sector) may target AAA via `voidcorp.config.json` `wcag_level: 'AAA'`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Interactive primitives — wrap Radix
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
// banned
|
|
24
|
+
<div onClick={handleClick} role="button" tabIndex={0}>
|
|
25
|
+
Submit
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
// allowed (Radix base)
|
|
29
|
+
<button onClick={handleClick}>Submit</button>
|
|
30
|
+
|
|
31
|
+
// preferred (shadcn-style via @repo/ui, wraps Radix)
|
|
32
|
+
import { Button } from '@repo/ui';
|
|
33
|
+
<Button onClick={handleClick}>Submit</Button>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Radix provides focus management, keyboard nav, ARIA wiring. Hand-rolling these is the #1 source of subtle a11y bugs.
|
|
37
|
+
|
|
38
|
+
For composite widgets (dropdown, dialog, popover, tooltip, tabs, accordion, slider, switch, toggle group, navigation menu) — use the Radix primitive. Period.
|
|
39
|
+
|
|
40
|
+
The companion `void-code-review` flag catches raw `<div onClick>` / `<span onClick>` on interactive surfaces.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Semantic HTML over ARIA
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// banned
|
|
48
|
+
<div role="navigation">...</div>
|
|
49
|
+
<div role="heading" aria-level={2}>Title</div>
|
|
50
|
+
|
|
51
|
+
// allowed
|
|
52
|
+
<nav>...</nav>
|
|
53
|
+
<h2>Title</h2>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
ARIA is the escape hatch for cases semantic HTML cannot express. The rule of least power: use HTML if it fits; reach for ARIA only when nothing else works.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Contrast — AA minimum
|
|
61
|
+
|
|
62
|
+
| Type | Minimum ratio |
|
|
63
|
+
|---|---|
|
|
64
|
+
| Normal text | 4.5:1 |
|
|
65
|
+
| Large text (18pt+ or 14pt+ bold) | 3:1 |
|
|
66
|
+
| UI components / graphical objects | 3:1 |
|
|
67
|
+
|
|
68
|
+
The design system palette (in `pack-nextjs`) documents contrast ratios for every token combination. Tokens that fail AA are marked and not used for text.
|
|
69
|
+
|
|
70
|
+
The companion hook `axe-precommit` runs axe-core on staged UI changes and flags AA violations.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Touch targets — Apple HIG floor
|
|
75
|
+
|
|
76
|
+
Every interactive element ≥ **44×44px**, regardless of viewport. Small icons are wrapped in a padded tap area.
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
// banned
|
|
80
|
+
<button className="p-1"><Icon size={16} /></button>
|
|
81
|
+
|
|
82
|
+
// allowed (via @repo/ui Tappable)
|
|
83
|
+
<Tappable onClick={...}><Icon size={16} /></Tappable>
|
|
84
|
+
// Tappable enforces min-h-11 min-w-11 (44px) regardless of icon size
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The `Tappable` helper (provided by `pack-nextjs`) enforces minimum dimensions via Tailwind classes.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Keyboard navigation — parity with touch
|
|
92
|
+
|
|
93
|
+
For every UI interaction reachable by touch, there is a keyboard equivalent:
|
|
94
|
+
|
|
95
|
+
| Key | Action |
|
|
96
|
+
|---|---|
|
|
97
|
+
| Tab | Move focus forward |
|
|
98
|
+
| Shift+Tab | Move focus backward |
|
|
99
|
+
| Enter | Activate primary action |
|
|
100
|
+
| Space | Toggle / activate (per native semantics) |
|
|
101
|
+
| Escape | Close modal, popover, menu |
|
|
102
|
+
| Arrow keys | Navigate inside composite widgets (Radix handles this for Tabs, Menu, Slider, etc.) |
|
|
103
|
+
|
|
104
|
+
### Focus visible
|
|
105
|
+
|
|
106
|
+
Every focusable element shows a focus ring. Tailwind: `focus-visible:ring-2 focus-visible:ring-primary` (or design-system token).
|
|
107
|
+
|
|
108
|
+
### Banned
|
|
109
|
+
|
|
110
|
+
```css
|
|
111
|
+
/* banned */
|
|
112
|
+
outline: none;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
without an alternative focus indicator (`focus-visible:ring-*` or equivalent).
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Skip-to-content
|
|
120
|
+
|
|
121
|
+
Every page with > 3 nav items has a skip-to-content link at the top:
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
<a href="#main" className="sr-only focus:not-sr-only focus:fixed focus:top-2 focus:left-2 ...">
|
|
125
|
+
Skip to content
|
|
126
|
+
</a>
|
|
127
|
+
<main id="main">...</main>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The companion `@repo/ui` `Layout` component provides this by default.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Forms
|
|
135
|
+
|
|
136
|
+
### Labels associated
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// banned (placeholder as label)
|
|
140
|
+
<input type="email" placeholder="Email address" />
|
|
141
|
+
|
|
142
|
+
// allowed
|
|
143
|
+
<label htmlFor="email">Email address</label>
|
|
144
|
+
<input id="email" type="email" />
|
|
145
|
+
|
|
146
|
+
// or, when label is visually hidden
|
|
147
|
+
<label htmlFor="search" className="sr-only">Search</label>
|
|
148
|
+
<input id="search" type="search" placeholder="Search..." />
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Placeholder is NOT a label — it disappears on input, often fails AA contrast, and is handled inconsistently by screen readers.
|
|
152
|
+
|
|
153
|
+
### Errors announced
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
<label htmlFor="email">Email address</label>
|
|
157
|
+
<input id="email" aria-describedby="email-error" />
|
|
158
|
+
{error && (
|
|
159
|
+
<p id="email-error" role="alert" aria-live="polite">
|
|
160
|
+
{error.message}
|
|
161
|
+
</p>
|
|
162
|
+
)}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Screen readers receive the update. Visual users see it too.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Color is not the only signal
|
|
170
|
+
|
|
171
|
+
Success / error / warning indicators combine COLOR + ICON + TEXT:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
// banned (color only)
|
|
175
|
+
<span className="text-red-500">Failed</span>
|
|
176
|
+
|
|
177
|
+
// allowed
|
|
178
|
+
<span className="text-red-500 flex items-center gap-1">
|
|
179
|
+
<XCircleIcon className="h-4 w-4" aria-hidden="true" />
|
|
180
|
+
Failed
|
|
181
|
+
</span>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Colorblind users get parity. The aria-hidden on the icon prevents it from being announced redundantly.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Mobile-first dual-quality
|
|
189
|
+
|
|
190
|
+
Every UI is designed mobile-first AND must reach first-class quality on both viewports simultaneously. (Folpe rule, documented in `.void/installed/PHILOSOPHY.md`.)
|
|
191
|
+
|
|
192
|
+
### Concrete invariants
|
|
193
|
+
|
|
194
|
+
- Layout starts at **360–390px** (iPhone 12 mini → iPhone 15 Pro), progressively enhanced wider.
|
|
195
|
+
- Touch targets ≥ 44×44 on every interactive element regardless of viewport.
|
|
196
|
+
- Keyboard navigation parity with touch.
|
|
197
|
+
- Performance budget: LCP < 2.5s on slow 4G mobile AND on desktop fiber (measure with the project's perf tooling — Lighthouse CI, WebPageTest, bundlesize).
|
|
198
|
+
- No mobile-only nor desktop-only features without an explicit decision recorded through the `void-decide` skill.
|
|
199
|
+
- Both viewports screenshot-reviewed before merge.
|
|
200
|
+
|
|
201
|
+
The companion `viewport-screenshot-gate` hook (shared with `void-frontend-design`) fails PRs lacking both screenshots.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Reduced motion
|
|
206
|
+
|
|
207
|
+
```css
|
|
208
|
+
@media (prefers-reduced-motion: reduce) {
|
|
209
|
+
* { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The design system handles this by default in `pack-nextjs`. Specific animations may override with a reduced-motion variant.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Banned
|
|
218
|
+
|
|
219
|
+
- `<div onClick>` / `<span onClick>` on interactive elements
|
|
220
|
+
- `outline: none` without a focus alternative
|
|
221
|
+
- Placeholder text as label
|
|
222
|
+
- Color as only indicator
|
|
223
|
+
- Custom dropdown / modal / tooltip implementations (use Radix)
|
|
224
|
+
- Auto-playing media with sound
|
|
225
|
+
- `tabIndex="-1"` to remove from tab order without a reason (rare legitimate cases: programmatically focused after user action)
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Companion hooks
|
|
230
|
+
|
|
231
|
+
- `axe-precommit` (pre-commit on UI changes) — axe-core static analysis, blocks on AA violations. ≤ 80 LOC.
|
|
232
|
+
- `viewport-screenshot-gate` (pre-PR on UI changes, shared with `void-frontend-design`) — fails PRs lacking both mobile and desktop screenshots. ≤ 60 LOC.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Composition with other skills
|
|
237
|
+
|
|
238
|
+
- **With `void-frontend-design`**: shared mobile-first dual-quality invariant. `void-frontend-design` decides density / hierarchy / motion; this skill enforces a11y across them.
|
|
239
|
+
- **With `void-code-review`**: dimension `correctness` includes a11y at the UI surface.
|
|
240
|
+
- **With `pack-nextjs`**: provides `@repo/ui` (Radix-wrapped) + `Tappable` + axe-core integration + design system palette tokens.
|
|
241
|
+
- **With `void-ui-review`**: its technical-audit pass includes the a11y dimension (contrast, keyboard, focus, 44px) — composes with this skill. Live-URL visual a11y audit is deferred to Vague 4.
|
|
242
|
+
- **With `DESIGN.md`**: the design-system contract incorporates a11y constraints (produced by `impeccable document`/`init` or by hand).
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Anti-rules
|
|
247
|
+
|
|
248
|
+
- MUST NOT decide visual design (color, typography, motion language).
|
|
249
|
+
- MUST NOT silently allow `<div onClick>` on interactive surfaces.
|
|
250
|
+
- MUST NOT permit `outline: none` without alternative.
|
|
251
|
+
- MUST NOT skip dual-viewport verification.
|
|
252
|
+
- MUST NOT permit color-only indicators.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## When you are stuck
|
|
257
|
+
|
|
258
|
+
| Problem | Solution |
|
|
259
|
+
|---|---|
|
|
260
|
+
| Need a custom widget Radix does not have | Check WAI-ARIA APG patterns. Implement carefully. Add to design-system docs. |
|
|
261
|
+
| Contrast token fails AA | Adjust the palette OR use a token marked for non-text usage only. |
|
|
262
|
+
| Cannot tab into composite widget | Verify Radix primitive is used. Hand-rolled focus management is the #1 bug source. |
|
|
263
|
+
| Touch target too small | Wrap in `Tappable`. |
|
|
264
|
+
| Reduced-motion conflicts with critical animation | Document the exception + provide a non-motion alternative. |
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Final rule
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
Every UI → Radix primitive, AA contrast, ≥ 44px touch, keyboard parity, semantic HTML, form labels, dual-viewport verified.
|
|
272
|
+
Otherwise → it is not voidcorp accessibility.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
A11y is not a tax. It is the floor. Build on it; do not negotiate with it.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Harness metadata for this skill. Not part of the Agent Skills
|
|
2
|
+
# specification, and never copied into a consumer project: the SKILL.md
|
|
3
|
+
# beside it stays portable and validates against the official six fields.
|
|
4
|
+
# Read by this repository's graph, and by the installer for `runtimes`.
|
|
5
|
+
kind: standard
|
|
6
|
+
activation: always
|
|
7
|
+
triggers:
|
|
8
|
+
extensions: ["tsx"]
|
|
9
|
+
owner: folpe
|
|
10
|
+
runtimes: [claude, codex]
|
|
11
|
+
enforcement:
|
|
12
|
+
floor: ci
|
|
13
|
+
inline:
|
|
14
|
+
claude: pretooluse
|
|
15
|
+
codex: pretooluse
|
|
16
|
+
hermes: ci-only
|
|
17
|
+
eval_targets: [claude/anthropic/opus]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Sources for `void-api-and-interface-design` skill (see `docs/plans/skill-audits/void-api-and-interface-design.md` for full audit):
|
|
2
|
+
|
|
3
|
+
- David Parnas "On the Criteria To Be Used in Decomposing Systems into Modules" (1972) — https://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf — information hiding: a module exposes an interface and hides its design decisions; the contract is the stable surface, the implementation is replaceable.
|
|
4
|
+
- Joshua Bloch "How to Design a Good API and Why It Matters" — https://www.infoq.com/presentations/effective-api-design/ (slides: https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/32713.pdf) — "when in doubt, leave it out"; minimal public surface; make it hard to misuse; public APIs are forever.
|
|
5
|
+
- Contract-first / API-first design with OpenAPI — https://swagger.io/resources/articles/adopting-an-api-first-approach/ — write the contract (spec) before the implementation; the spec is reviewable and consumable on its own.
|
|
6
|
+
- Semantic Versioning 2.0.0 — https://semver.org/ — MAJOR breaks, MINOR adds, PATCH fixes; encodes the backward-compatibility promise and the deprecation discipline.
|
|
7
|
+
- void-machine `void-hexagonal-architecture` skill — ports are interfaces the domain owns; this skill shapes those ports as seen from outside (it does not decide where the boundary sits).
|
|
8
|
+
|
|
9
|
+
Strategy: distill. Parnas (information hiding) + Bloch (minimal, misuse-resistant surface) + contract-first (spec before code) + SemVer (versioning + deprecation cycle), rewritten for void-machine and composed with hexagonal-architecture, domain-driven-design, typescript-strict, functional, security-guidance, async-safety.
|
|
10
|
+
|
|
11
|
+
Boundary: narrower than hexagonal-architecture (no layering / dependency direction) and DDD (no domain vocabulary). Owns only the design of a public contract: shape, misuse-resistance, boundary types, error contract, versioning.
|
|
12
|
+
|
|
13
|
+
Companion hooks: none in v1 (versioning/compat discipline is guidance + code-review surface; a future contract-diff hook is an open question).
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: void-api-and-interface-design
|
|
3
|
+
description: Contract-first design of any public interface — package exports, HTTP/REST, RPC/tRPC, SDK, module boundary. Minimal surface, stable boundary types, versioning. Use when shaping a public API.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# api-and-interface-design — voidcorp craftsman edition
|
|
7
|
+
|
|
8
|
+
A public interface is a promise. The contract is the promise; the implementation is replaceable. Once a consumer depends on a signature, that signature costs you forever — every shape you expose is a shape you must keep working or deprecate on a schedule. This skill governs how you draw the contract of anything other code consumes: what it accepts, what it returns, how it fails, how it changes.
|
|
9
|
+
|
|
10
|
+
Design the contract before the implementation. The implementation is private and free to churn; the contract is public and expensive to change.
|
|
11
|
+
|
|
12
|
+
**Attribution**: see `.source` in this directory. Foundation: Parnas "information hiding," Bloch "How to Design a Good API," contract-first / OpenAPI, SemVer.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Boundary with neighboring skills
|
|
17
|
+
|
|
18
|
+
This skill is narrow. It does NOT cover layered architecture or domain vocabulary.
|
|
19
|
+
|
|
20
|
+
| Concern | Owner |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Where the boundary sits physically, dependency direction, ports vs adapters | `void-hexagonal-architecture` |
|
|
23
|
+
| What the domain IS — bounded contexts, aggregates, ubiquitous language | `void-domain-driven-design` |
|
|
24
|
+
| **The shape, stability, and versioning of a public contract — viewed from the outside** | **this skill** |
|
|
25
|
+
|
|
26
|
+
A port (hex) is an interface the domain owns. This skill says how to draw that port well *as seen by its consumer*: minimal, hard to misuse, stable, versioned. Hex decides the port exists and which side owns it; DDD supplies the words inside it; this skill shapes the contract.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Contract-first — the order of operations
|
|
31
|
+
|
|
32
|
+
Before writing the implementation, write the contract down:
|
|
33
|
+
|
|
34
|
+
1. **Signature** — the operations, their names (ubiquitous-language words, per `void-domain-driven-design`).
|
|
35
|
+
2. **Input type** — exactly what is accepted, validated at the boundary.
|
|
36
|
+
3. **Output type** — a dedicated boundary type, never an internal/DB row.
|
|
37
|
+
4. **Error set** — the failures a consumer must handle, as values.
|
|
38
|
+
5. **Invariants** — what the contract guarantees (idempotency, ordering, pagination).
|
|
39
|
+
|
|
40
|
+
The contract is reviewable on its own, before a single line of logic. For HTTP/RPC this is the OpenAPI / schema spec; for a package it is the exported `.d.ts`; for a module it is the interface. Implementation-first design (writing logic, then "extracting" an API from whatever leaked out) is the anti-pattern this skill exists to prevent.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Minimal surface — when in doubt, leave it out
|
|
45
|
+
|
|
46
|
+
Everything public is a liability. You cannot un-ship a method without breaking someone.
|
|
47
|
+
|
|
48
|
+
- Expose the smallest set of operations that satisfies the use case. Internal helpers stay un-exported.
|
|
49
|
+
- A capability you are unsure about: keep it private. Adding later is non-breaking; removing later is breaking.
|
|
50
|
+
- One way to do a thing, not three. Redundant entry points multiply the contract you must keep stable.
|
|
51
|
+
|
|
52
|
+
Bloch's rule: *when in doubt, leave it out.* You can always add; you can rarely remove.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Make it hard to misuse
|
|
57
|
+
|
|
58
|
+
The best contract makes the invalid call fail to compile, not fail at runtime. Composes with `void-typescript-strict`.
|
|
59
|
+
|
|
60
|
+
### Illegal states unrepresentable
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// BAD — caller can pass a window that ends before it starts
|
|
64
|
+
function schedule(input: { startsAt: IsoDate; endsAt: IsoDate }): Result<Booking, ScheduleError>;
|
|
65
|
+
|
|
66
|
+
// BETTER — a validated value object can only exist if valid
|
|
67
|
+
function schedule(input: { window: TimeWindow }): Result<Booking, ScheduleError>;
|
|
68
|
+
// TimeWindow's smart constructor (per domain-driven-design) refuses end < start
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### No positional booleans, no bare primitives
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// BAD — call site reads createUser('a@b.co', true, false); nobody knows what true/false mean
|
|
75
|
+
function createUser(email: string, isAdmin: boolean, sendWelcome: boolean): User;
|
|
76
|
+
|
|
77
|
+
// GOOD — named options object + branded input types
|
|
78
|
+
function createUser(input: {
|
|
79
|
+
email: Email; // branded, validated (domain-driven-design)
|
|
80
|
+
role: 'admin' | 'member'; // discriminated, not a boolean
|
|
81
|
+
welcome?: { send: boolean };
|
|
82
|
+
}): Result<User, CreateUserError>;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Named parameters survive reordering and additions; positional booleans rot the moment a third flag appears.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Stable boundary types — never leak the inside
|
|
90
|
+
|
|
91
|
+
The types crossing a public boundary are part of the contract. Internal and DB types are not.
|
|
92
|
+
|
|
93
|
+
- **No leaking ORM rows / DB models / framework request objects** across a public boundary. A schema change must not silently break a consumer.
|
|
94
|
+
- **Dedicated boundary types (DTOs / branded types)**. They are mapped to/from internal types in the adapter (per `void-hexagonal-architecture`), exactly where translation already lives.
|
|
95
|
+
- **Validate input at the boundary**. External input is untrusted; parse it into the boundary type with a schema (Zod) before anything else touches it. Composes with `void-security-guidance`.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// boundary input parsed before it reaches the use-case
|
|
99
|
+
const parsed = createUserRequestSchema.safeParse(req.body);
|
|
100
|
+
if (!parsed.success) return badRequest(parsed.error); // 400, no internal detail leaked
|
|
101
|
+
const result = await createUser(deps, toCreateUserInput(parsed.data));
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The boundary type is a wall: internal churn stays internal, external input stays validated.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Errors are part of the contract
|
|
109
|
+
|
|
110
|
+
What can go wrong is as much a promise as what goes right. Consumers branch on failures; surprise failures are bugs you shipped.
|
|
111
|
+
|
|
112
|
+
- **Typed results at the boundary** — return `Result<T, E>` where `E` is a closed, named set of failures. Composes with `void-functional`.
|
|
113
|
+
- **Stable error identity** — a stable `code` (and a stable HTTP status for network APIs). Consumers match on the code, not on the message string.
|
|
114
|
+
- **Non-sensitive messages** — never leak stack traces, internal IDs, SQL, or PII across the boundary. Messages are for humans; codes are for machines.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
type CreateUserError =
|
|
118
|
+
| { code: 'email_taken'; status: 409 }
|
|
119
|
+
| { code: 'invalid_email'; status: 400 }
|
|
120
|
+
| { code: 'rate_limited'; status: 429; retryAfterSec: number };
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Adding a new error variant is additive only if consumers already have a default branch; otherwise it is a breaking change (see versioning).
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Versioning and backward compatibility
|
|
128
|
+
|
|
129
|
+
A breaking change to a published contract is a broken promise to every consumer. SemVer encodes the promise: MAJOR breaks, MINOR adds, PATCH fixes.
|
|
130
|
+
|
|
131
|
+
**Additive-first.** New optional field, new operation, new error variant behind a default branch — non-breaking, ship as MINOR.
|
|
132
|
+
|
|
133
|
+
**Breaking requires a new version or a deprecation cycle.** Removing a field, renaming an operation, narrowing an input, tightening an output, changing an error code — all breaking. Either ship a new version (`/v2`, major bump) or run a deprecation cycle: **deprecate before you remove.**
|
|
134
|
+
|
|
135
|
+
Deprecation cycle:
|
|
136
|
+
|
|
137
|
+
1. Mark the old surface deprecated (`@deprecated` JSDoc / `Deprecation` header / changelog), point to the replacement.
|
|
138
|
+
2. Ship the replacement alongside. Both work.
|
|
139
|
+
3. Give consumers a window (a release count or a date).
|
|
140
|
+
4. Remove in the next MAJOR only.
|
|
141
|
+
|
|
142
|
+
Never shorten the cycle silently. A consumer that wakes up to a 410 they were never warned about is the failure mode this rule prevents.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Network APIs — idempotency and pagination
|
|
147
|
+
|
|
148
|
+
For interfaces crossing the wire, two contract terms earn their place when relevant. Composes with `void-async-safety`.
|
|
149
|
+
|
|
150
|
+
- **Idempotency** — any non-`GET` a client may retry (a payment, a create) accepts an idempotency key, and the server guarantees one effect per key. Retries are inevitable on a network; the contract must make them safe.
|
|
151
|
+
- **Pagination** — any collection that can grow is paginated from day one, with a stable cursor contract. Returning an unbounded list is a promise you cannot keep at scale, and adding pagination later is breaking.
|
|
152
|
+
|
|
153
|
+
Both are decided at contract time. Retrofitting either breaks consumers.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Rationalizations
|
|
158
|
+
|
|
159
|
+
| Rationalization | Reality |
|
|
160
|
+
|---|---|
|
|
161
|
+
| "I'll design the API once the implementation works." | The implementation will leak its shape into the contract. Design the contract first; it is reviewable alone. |
|
|
162
|
+
| "Expose it now, someone might need it." | Public surface is forever. Add when a real consumer appears; removing is the breaking change you cannot take back. |
|
|
163
|
+
| "Returning the DB row is faster." | The row is your schema. A migration now silently breaks every consumer. Map to a boundary type. |
|
|
164
|
+
| "A boolean flag is simpler than an enum." | Until the third flag. `fn(x, true, false)` is unreadable and reorder-fragile. Named options + unions. |
|
|
165
|
+
| "Throwing is fine, callers can catch." | Thrown errors are invisible in the type. Consumers forget the catch. Typed `Result` makes failure part of the signature. |
|
|
166
|
+
| "It's a small rename, no big deal." | A rename is a breaking change. Deprecate the old name, add the new, remove next major. |
|
|
167
|
+
| "We'll add pagination when the list gets big." | By then consumers depend on the array shape. Adding pagination is breaking. Paginate from day one. |
|
|
168
|
+
| "Internal API, compatibility doesn't matter." | If another module imports it, it has consumers. The promise still holds across the module boundary. |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Verification
|
|
173
|
+
|
|
174
|
+
Before a public interface is considered designed:
|
|
175
|
+
|
|
176
|
+
- [ ] The contract (signatures, input types, output types, error set, invariants) was written and reviewed **before** the implementation.
|
|
177
|
+
- [ ] Public surface is minimal — every exported symbol has a current consumer; helpers are un-exported.
|
|
178
|
+
- [ ] No internal / ORM / framework type crosses the boundary; boundary uses dedicated DTOs or branded types.
|
|
179
|
+
- [ ] All external input is validated at the boundary with a schema before use (composes with `void-security-guidance`).
|
|
180
|
+
- [ ] Failures are a closed, typed `Result` set with stable codes (and stable HTTP statuses for network APIs); messages carry no sensitive detail.
|
|
181
|
+
- [ ] No positional booleans; multi-arg calls use a named options object; primitives with semantics are branded.
|
|
182
|
+
- [ ] The contract is versioned; any breaking change is gated behind a new version or a documented deprecation cycle (deprecate → coexist → remove next major).
|
|
183
|
+
- [ ] For network APIs: retryable mutations accept an idempotency key; growable collections are paginated with a stable cursor.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Composition with other skills
|
|
188
|
+
|
|
189
|
+
- **`void-hexagonal-architecture`**: the domain owns ports (interfaces). Hex says the port exists and who owns it; this skill says how to draw that port well as seen from outside — minimal, misuse-resistant, versioned. Boundary types map to internal types in the adapter.
|
|
190
|
+
- **`void-domain-driven-design`**: contract names come from the ubiquitous language. Input/output types reuse value objects (branded types) and aggregate identities. DDD names; this skill shapes the public face.
|
|
191
|
+
- **`void-typescript-strict`**: branded types at the boundary, discriminated unions for inputs and error sets, `satisfies` for response shapes, exhaustive handling of the error union.
|
|
192
|
+
- **`void-functional`**: `Result<T, E>` is the boundary return; the error set is a closed ADT.
|
|
193
|
+
- **`void-security-guidance`**: external input parsed/validated at the boundary (Zod); errors carry no sensitive payload.
|
|
194
|
+
- **`void-async-safety`**: idempotency keys and retry semantics for network mutations; pagination for growable reads.
|
|
195
|
+
- **`void-devex-audit`**: this skill is the build-time floor (design a minimal, misuse-resistant, versioned contract); `void-devex-audit` is the audit-time ceiling that measures the shipped contract's developer experience (TTHW, error paths, docs, upgrade) after it deploys.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Anti-rules
|
|
200
|
+
|
|
201
|
+
- MUST NOT decide where the boundary sits physically or the dependency direction — `void-hexagonal-architecture`'s call.
|
|
202
|
+
- MUST NOT define the domain model, bounded contexts, or aggregates — `void-domain-driven-design`'s call.
|
|
203
|
+
- MUST NOT expose internal, ORM, or framework types across a public boundary.
|
|
204
|
+
- MUST NOT break a published contract without a new version or a documented deprecation cycle.
|
|
205
|
+
- MUST NOT design the API after the implementation (implementation-first).
|
|
206
|
+
- MUST NOT decide the transport / framework / serialization library — pack concern.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## When you are stuck
|
|
211
|
+
|
|
212
|
+
| Problem | Solution |
|
|
213
|
+
|---|---|
|
|
214
|
+
| Should this be public? | If no current consumer needs it, keep it private. Add later; never break later. |
|
|
215
|
+
| Class, options object, or positional args? | More than one argument, or any boolean → named options object. |
|
|
216
|
+
| How should failures surface? | Typed `Result` with a closed error set and stable codes. No throwing across the boundary. |
|
|
217
|
+
| Is this change breaking? | Removing / renaming / narrowing input / widening required output / changing a code = breaking. Additive = safe. |
|
|
218
|
+
| Need to remove a field consumers use? | Deprecate, coexist, remove next major. Never silent. |
|
|
219
|
+
| DB type or boundary type? | Always a boundary type. The DB shape is private. |
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Final rule
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
Contract before implementation. Minimal surface. Stable boundary types.
|
|
227
|
+
Errors typed. Breaking change → new version or deprecation cycle.
|
|
228
|
+
Otherwise → it is not a voidcorp public interface.
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The implementation is yours to change. The contract belongs to everyone who calls it. Treat it like a promise, because it is one.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Harness metadata for this skill. Not part of the Agent Skills
|
|
2
|
+
# specification, and never copied into a consumer project: the SKILL.md
|
|
3
|
+
# beside it stays portable and validates against the official six fields.
|
|
4
|
+
# Read by this repository's graph, and by the installer for `runtimes`.
|
|
5
|
+
kind: standard
|
|
6
|
+
triggers:
|
|
7
|
+
globs: ["**/src/index.ts", "**/openapi*.{yaml,yml,json}", "**/*.openapi.ts", "**/trpc/**/router.ts"]
|
|
8
|
+
owner: folpe
|
|
9
|
+
runtimes: [claude, codex]
|
|
10
|
+
enforcement:
|
|
11
|
+
floor: ci
|
|
12
|
+
inline:
|
|
13
|
+
claude: active
|
|
14
|
+
codex: active
|
|
15
|
+
hermes: ci-only
|
|
16
|
+
eval_targets: [claude/anthropic/opus]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Sources for `void-async-safety` skill (see `docs/plans/skill-audits/void-async-safety.md` for full audit):
|
|
2
|
+
|
|
3
|
+
- Stripe "Designing robust webhook handlers" — https://stripe.com/blog/idempotency — foundation, idempotency keys, replay protection
|
|
4
|
+
- Stripe webhook signing docs — https://docs.stripe.com/webhooks#verify-events — signature + timestamp window pattern
|
|
5
|
+
- Outbox pattern (Microservices.io) — https://microservices.io/patterns/data/transactional-outbox.html — DB write + external notify in one transaction
|
|
6
|
+
- Pat Helland "Life Beyond Distributed Transactions" — https://queue.acm.org/detail.cfm?id=3025012 — entity/activity/contracts framing
|
|
7
|
+
- Bryan Cantrill talks on distributed-systems failure modes — mental model: assume re-delivery
|
|
8
|
+
- GitHub webhook redelivery docs — https://docs.github.com/en/webhooks
|
|
9
|
+
- n8n / BullMQ / Inngest docs — tactical references for queue / job patterns
|
|
10
|
+
|
|
11
|
+
Strategy: distill. Principles from Stripe + Outbox + Pat Helland. Stack-specific implementations (BullMQ vs Inngest vs Trigger.dev) live in packs (pack-monorepo / pack-nextjs-pwa).
|
|
12
|
+
|
|
13
|
+
Companion: pack wrappers (withWebhookSafety, withJobSafety, withCronSafety). domain_events outbox table schema in pack-monorepo. No new core hooks; code-review flags surface violations.
|