claude-code-superkit 0.0.0-stage → 1.5.3
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 +374 -2
- package/bin/cli.js +153 -0
- package/bin/inject-tokens.js +224 -0
- package/bin/measure-tokens.js +17 -0
- package/bin/superkit-counts-verify.sh +30 -0
- package/lib/codex.js +246 -0
- package/lib/docs-scaffold.js +147 -0
- package/lib/installer.js +499 -0
- package/lib/prompts.js +51 -0
- package/lib/settings-builder.js +51 -0
- package/lib/superpowers.js +99 -0
- package/lib/utils.js +117 -0
- package/lib/validator.js +84 -0
- package/package.json +49 -4
- package/packages/codex/AGENTS.md +396 -0
- package/packages/codex/INSTALL.md +342 -0
- package/packages/codex/config.toml +22 -0
- package/packages/codex/hooks/superkit.mjs +203 -0
- package/packages/codex/hooks.json +30 -0
- package/packages/codex/legacy-baseline.json +88 -0
- package/packages/codex/native-skills.txt +65 -0
- package/packages/codex/rules/default.rules +565 -0
- package/packages/codex/skills/ai-slop-cleaner/SKILL.md +44 -0
- package/packages/codex/skills/api-contract-sync/SKILL.md +96 -0
- package/packages/codex/skills/architect/SKILL.md +49 -0
- package/packages/codex/skills/audit-backend/SKILL.md +80 -0
- package/packages/codex/skills/audit-frontend/SKILL.md +82 -0
- package/packages/codex/skills/audit-infra/SKILL.md +87 -0
- package/packages/codex/skills/audit-orchestrator/SKILL.md +114 -0
- package/packages/codex/skills/behavioral-nudge-engine/SKILL.md +110 -0
- package/packages/codex/skills/benchmark/SKILL.md +49 -0
- package/packages/codex/skills/bot-reviewer/SKILL.md +94 -0
- package/packages/codex/skills/code-reviewer/SKILL.md +67 -0
- package/packages/codex/skills/codebase-onboarding-engineer/SKILL.md +46 -0
- package/packages/codex/skills/comment-rot-analyzer/SKILL.md +75 -0
- package/packages/codex/skills/commit-helper/SKILL.md +101 -0
- package/packages/codex/skills/critic/SKILL.md +56 -0
- package/packages/codex/skills/database-reviewer/SKILL.md +79 -0
- package/packages/codex/skills/debug-observer/SKILL.md +107 -0
- package/packages/codex/skills/dependency-checker/SKILL.md +69 -0
- package/packages/codex/skills/design-system-reviewer/SKILL.md +121 -0
- package/packages/codex/skills/dev-orchestrator/SKILL.md +304 -0
- package/packages/codex/skills/docs-reviewer/SKILL.md +86 -0
- package/packages/codex/skills/drizzle-orm-expert/SKILL.md +246 -0
- package/packages/codex/skills/e2e-test-generator/SKILL.md +95 -0
- package/packages/codex/skills/evaluator/SKILL.md +63 -0
- package/packages/codex/skills/frontend-perf-reviewer/SKILL.md +95 -0
- package/packages/codex/skills/frontend-ui-color-reviewer/SKILL.md +68 -0
- package/packages/codex/skills/frontend-ui-design-critic/SKILL.md +99 -0
- package/packages/codex/skills/frontend-ui-interaction-reviewer/SKILL.md +102 -0
- package/packages/codex/skills/frontend-ui-motion-reviewer/SKILL.md +85 -0
- package/packages/codex/skills/frontend-ui-reviewer/SKILL.md +81 -0
- package/packages/codex/skills/frontend-ui-typography-reviewer/SKILL.md +62 -0
- package/packages/codex/skills/gltf-debugging/SKILL.md +128 -0
- package/packages/codex/skills/go-benchmark/SKILL.md +217 -0
- package/packages/codex/skills/go-concurrency-reviewer/SKILL.md +113 -0
- package/packages/codex/skills/go-error-reviewer/SKILL.md +107 -0
- package/packages/codex/skills/go-grpc-patterns/SKILL.md +285 -0
- package/packages/codex/skills/go-modernizer/SKILL.md +111 -0
- package/packages/codex/skills/go-observability-reviewer/SKILL.md +121 -0
- package/packages/codex/skills/go-performance-reviewer/SKILL.md +112 -0
- package/packages/codex/skills/go-reviewer/SKILL.md +109 -0
- package/packages/codex/skills/go-samber-do/SKILL.md +158 -0
- package/packages/codex/skills/go-samber-lo/SKILL.md +178 -0
- package/packages/codex/skills/go-samber-oops/SKILL.md +174 -0
- package/packages/codex/skills/goal-verifier/SKILL.md +53 -0
- package/packages/codex/skills/health-checker/SKILL.md +109 -0
- package/packages/codex/skills/html-to-3d-texture/SKILL.md +153 -0
- package/packages/codex/skills/impeccable-craft/SKILL.md +101 -0
- package/packages/codex/skills/lint-runner/SKILL.md +85 -0
- package/packages/codex/skills/migrate/SKILL.md +60 -0
- package/packages/codex/skills/migration-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/minimal-change-engineer/SKILL.md +44 -0
- package/packages/codex/skills/new-migration/SKILL.md +59 -0
- package/packages/codex/skills/nextjs-supabase-auth/SKILL.md +227 -0
- package/packages/codex/skills/output-enforcement/SKILL.md +71 -0
- package/packages/codex/skills/plan-checker/SKILL.md +53 -0
- package/packages/codex/skills/postgresql-optimization/SKILL.md +159 -0
- package/packages/codex/skills/pre-deploy-validator/SKILL.md +111 -0
- package/packages/codex/skills/presentation-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/product-3d-lighting/SKILL.md +137 -0
- package/packages/codex/skills/project-architecture/SKILL.md +52 -0
- package/packages/codex/skills/py-reviewer/SKILL.md +100 -0
- package/packages/codex/skills/r3f-scene-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/r3f-scroll-driven-3d/SKILL.md +162 -0
- package/packages/codex/skills/reality-checker/SKILL.md +61 -0
- package/packages/codex/skills/redis-patterns/SKILL.md +260 -0
- package/packages/codex/skills/review-orchestrator/SKILL.md +151 -0
- package/packages/codex/skills/rs-reviewer/SKILL.md +98 -0
- package/packages/codex/skills/ru-text/SKILL.md +132 -0
- package/packages/codex/skills/scaffold-endpoint/SKILL.md +44 -0
- package/packages/codex/skills/security-scanner/SKILL.md +94 -0
- package/packages/codex/skills/silent-failure-hunter/SKILL.md +176 -0
- package/packages/codex/skills/telegram-bot-builder/SKILL.md +120 -0
- package/packages/codex/skills/test-generator/SKILL.md +79 -0
- package/packages/codex/skills/test-runner/SKILL.md +101 -0
- package/packages/codex/skills/threejs-color-management/SKILL.md +97 -0
- package/packages/codex/skills/tree-generator/SKILL.md +63 -0
- package/packages/codex/skills/ts-reviewer/SKILL.md +90 -0
- package/packages/codex/skills/ui-design-reviewer/SKILL.md +89 -0
- package/packages/codex/skills/ui-reviewer/SKILL.md +103 -0
- package/packages/codex/skills/visual-reviewer/SKILL.md +85 -0
- package/packages/codex/skills/writing-agents/SKILL.md +165 -0
- package/packages/codex/skills/writing-commands/SKILL.md +173 -0
- package/packages/core/CLAUDE.md +118 -0
- package/packages/core/INTERNAL-FILES +16 -0
- package/packages/core/agents/ai-slop-cleaner.md +187 -0
- package/packages/core/agents/api-contract-sync.md +127 -0
- package/packages/core/agents/architect.md +205 -0
- package/packages/core/agents/audit-backend.md +137 -0
- package/packages/core/agents/audit-frontend.md +129 -0
- package/packages/core/agents/audit-infra.md +182 -0
- package/packages/core/agents/behavioral-nudge-engine.md +170 -0
- package/packages/core/agents/code-reviewer.md +195 -0
- package/packages/core/agents/codebase-onboarding-engineer.md +172 -0
- package/packages/core/agents/comment-rot-analyzer.md +115 -0
- package/packages/core/agents/critic.md +172 -0
- package/packages/core/agents/database-reviewer.md +201 -0
- package/packages/core/agents/debug-observer.md +261 -0
- package/packages/core/agents/dependency-checker.md +199 -0
- package/packages/core/agents/docs-reviewer.md +206 -0
- package/packages/core/agents/e2e-test-generator.md +261 -0
- package/packages/core/agents/evaluator.md +141 -0
- package/packages/core/agents/goal-verifier.md +130 -0
- package/packages/core/agents/health-checker.md +194 -0
- package/packages/core/agents/migration-reviewer.md +161 -0
- package/packages/core/agents/minimal-change-engineer.md +219 -0
- package/packages/core/agents/plan-checker.md +139 -0
- package/packages/core/agents/pre-deploy-validator.md +189 -0
- package/packages/core/agents/reality-checker.md +175 -0
- package/packages/core/agents/scaffold-endpoint.md +162 -0
- package/packages/core/agents/security-scanner.md +236 -0
- package/packages/core/agents/silent-failure-hunter.md +276 -0
- package/packages/core/agents/test-generator.md +146 -0
- package/packages/core/agents/tree-generator.md +141 -0
- package/packages/core/agents/ui-reviewer.md +172 -0
- package/packages/core/agents/visual-reviewer.md +211 -0
- package/packages/core/commands/audit.md +166 -0
- package/packages/core/commands/benchmark.md +130 -0
- package/packages/core/commands/commit.md +148 -0
- package/packages/core/commands/dev.md +302 -0
- package/packages/core/commands/docs-init.md +75 -0
- package/packages/core/commands/lint.md +137 -0
- package/packages/core/commands/migrate.md +146 -0
- package/packages/core/commands/new-migration.md +182 -0
- package/packages/core/commands/pair.md +209 -0
- package/packages/core/commands/review.md +195 -0
- package/packages/core/commands/security-scan.md +142 -0
- package/packages/core/commands/superkit-evolve.md +231 -0
- package/packages/core/commands/superkit-init.md +274 -0
- package/packages/core/commands/test.md +108 -0
- package/packages/core/commands/workflow.md +150 -0
- package/packages/core/docs/guide/01-getting-started.md +41 -0
- package/packages/core/docs-templates/README.md +33 -0
- package/packages/core/docs-templates/adr-template.md +62 -0
- package/packages/core/docs-templates/architecture/api-contracts.md +26 -0
- package/packages/core/docs-templates/architecture/api-reference.md +48 -0
- package/packages/core/docs-templates/architecture/auth-and-sessions.md +38 -0
- package/packages/core/docs-templates/architecture/backend-layers.md +42 -0
- package/packages/core/docs-templates/architecture/data-flow.md +26 -0
- package/packages/core/docs-templates/architecture/database-schema.md +51 -0
- package/packages/core/docs-templates/architecture/deployment.md +41 -0
- package/packages/core/docs-templates/architecture/frontend-state.md +46 -0
- package/packages/core/helpers/statusline.cjs +370 -0
- package/packages/core/hooks/CHAIN-SEMANTICS.md +84 -0
- package/packages/core/hooks/audit-settings-source.sh +98 -0
- package/packages/core/hooks/audit-trail.sh +120 -0
- package/packages/core/hooks/block-dangerous-git.sh +189 -0
- package/packages/core/hooks/bundle-import-check.sh +64 -0
- package/packages/core/hooks/compact-state-inject.sh +84 -0
- package/packages/core/hooks/config-protection.sh +68 -0
- package/packages/core/hooks/console-log-warning.sh +28 -0
- package/packages/core/hooks/context-monitor.sh +35 -0
- package/packages/core/hooks/dev-edit-counter.sh +59 -0
- package/packages/core/hooks/dev-marker-set.sh +55 -0
- package/packages/core/hooks/dev-required-on-commit.sh +426 -0
- package/packages/core/hooks/doc-check-on-commit.sh +396 -0
- package/packages/core/hooks/edit-streak-check.sh +63 -0
- package/packages/core/hooks/evolve-check.sh +78 -0
- package/packages/core/hooks/gateguard-pre-edit.sh +154 -0
- package/packages/core/hooks/gateguard-record-facts.sh +37 -0
- package/packages/core/hooks/intake-classifier.py +449 -0
- package/packages/core/hooks/lib/profile.sh +141 -0
- package/packages/core/hooks/loop-guard.sh +75 -0
- package/packages/core/hooks/migration-safety.sh +56 -0
- package/packages/core/hooks/plan-completion-gate.sh +61 -0
- package/packages/core/hooks/pre-compact-save.sh +89 -0
- package/packages/core/hooks/security-patterns.sh +119 -0
- package/packages/core/hooks/session-context-restore.sh +76 -0
- package/packages/core/hooks/subagent-stop-validate.sh +73 -0
- package/packages/core/hooks/superkit-counts-verify.sh +346 -0
- package/packages/core/hooks/superkit-update.sh +367 -0
- package/packages/core/hooks/tests/README.md +42 -0
- package/packages/core/hooks/tests/audit-trail-chain_test.sh +62 -0
- package/packages/core/hooks/tests/block-dangerous-git_test.sh +144 -0
- package/packages/core/hooks/tests/chain-semantics/h1.sh +11 -0
- package/packages/core/hooks/tests/chain-semantics/h2.sh +9 -0
- package/packages/core/hooks/tests/chain-semantics/h3.sh +11 -0
- package/packages/core/hooks/tests/chain-semantics/run-experiment.sh +65 -0
- package/packages/core/hooks/tests/chain-semantics/settings-experiment.json +15 -0
- package/packages/core/hooks/tests/counts-verify_test.sh +118 -0
- package/packages/core/hooks/tests/dev-required-on-commit_test.sh +207 -0
- package/packages/core/hooks/tests/dev-required-wip-on-main_test.sh +20 -0
- package/packages/core/hooks/tests/doc-check-on-commit_test.sh +122 -0
- package/packages/core/hooks/tests/edit-streak-check_test.sh +106 -0
- package/packages/core/hooks/tests/internal-manifest_test.sh +130 -0
- package/packages/core/hooks/tests/json-path_test.sh +108 -0
- package/packages/core/hooks/tests/mirror-invariants_test.sh +139 -0
- package/packages/core/hooks/tests/nudge-throttle_test.sh +95 -0
- package/packages/core/hooks/tests/profile-helper_test.sh +21 -0
- package/packages/core/hooks/tests/run-all.sh +47 -0
- package/packages/core/hooks/tests/session-key-helper_test.sh +17 -0
- package/packages/core/hooks/tests/superkit-update_test.sh +311 -0
- package/packages/core/hooks/tests/warn-visibility_test.sh +59 -0
- package/packages/core/hooks/user-intent-detect.sh +44 -0
- package/packages/core/hooks/verify-hooks.sh +69 -0
- package/packages/core/rules/auto-commands.md +124 -0
- package/packages/core/rules/coding-style.md +68 -0
- package/packages/core/rules/dev-workflow.md +77 -0
- package/packages/core/rules/documentation.md +106 -0
- package/packages/core/rules/frontend-aesthetics.md +53 -0
- package/packages/core/rules/git-workflow.md +14 -0
- package/packages/core/rules/security.md +29 -0
- package/packages/core/rules/superkit-integrity.md +114 -0
- package/packages/core/settings.json +229 -0
- package/packages/core/skills/drizzle-orm-expert/SKILL.md +260 -0
- package/packages/core/skills/nextjs-supabase-auth/SKILL.md +259 -0
- package/packages/core/skills/postgresql-optimization/SKILL.md +150 -0
- package/packages/core/skills/project-architecture/SKILL.md +31 -0
- package/packages/core/skills/project-scanner/SKILL.md +132 -0
- package/packages/core/skills/redis-patterns/SKILL.md +261 -0
- package/packages/core/skills/ru-text/SKILL.md +156 -0
- package/packages/core/skills/telegram-bot-builder/SKILL.md +145 -0
- package/packages/core/skills/writing-agents/SKILL.md +220 -0
- package/packages/core/skills/writing-commands/SKILL.md +176 -0
- package/packages/core/skills/writing-hooks/SKILL.md +335 -0
- package/packages/extras/bot-reviewer.md +279 -0
- package/packages/extras/design-system-reviewer.md +234 -0
- package/packages/extras/red-blue-auditor/README.md +117 -0
- package/packages/extras/red-blue-auditor/agent.md +128 -0
- package/packages/extras/red-blue-auditor/patterns/agent-config.txt +4 -0
- package/packages/extras/red-blue-auditor/patterns/hook-injection.txt +8 -0
- package/packages/extras/red-blue-auditor/patterns/mcp-risk.txt +5 -0
- package/packages/extras/red-blue-auditor/patterns/permission-abuse.txt +6 -0
- package/packages/extras/red-blue-auditor/patterns/secrets.txt +17 -0
- package/packages/extras/red-blue-auditor/scan.sh +88 -0
- package/packages/extras/skillsmp-search/SKILL.md +134 -0
- package/packages/frontend-3d/README.md +62 -0
- package/packages/frontend-3d/agents/frontend-perf-reviewer.md +164 -0
- package/packages/frontend-3d/agents/presentation-reviewer.md +146 -0
- package/packages/frontend-3d/agents/r3f-scene-reviewer.md +128 -0
- package/packages/frontend-3d/agents/ui-design-reviewer.md +169 -0
- package/packages/frontend-3d/commands/capture-screen.md +166 -0
- package/packages/frontend-3d/hooks/bundle-size-warn.sh +93 -0
- package/packages/frontend-3d/hooks/gsap-pattern-check.sh +74 -0
- package/packages/frontend-3d/hooks/r3f-color-check.sh +76 -0
- package/packages/frontend-3d/hooks/tailwind-version-guard.sh +98 -0
- package/packages/frontend-3d/rules/frontend-aesthetics-3d.md +81 -0
- package/packages/frontend-3d/rules/gsap-conventions.md +129 -0
- package/packages/frontend-3d/rules/threejs-conventions.md +116 -0
- package/packages/frontend-3d/skills/gltf-debugging/SKILL.md +145 -0
- package/packages/frontend-3d/skills/html-to-3d-texture/SKILL.md +183 -0
- package/packages/frontend-3d/skills/output-enforcement/SKILL.md +79 -0
- package/packages/frontend-3d/skills/product-3d-lighting/SKILL.md +166 -0
- package/packages/frontend-3d/skills/r3f-scroll-driven-3d/SKILL.md +209 -0
- package/packages/frontend-3d/skills/threejs-color-management/SKILL.md +111 -0
- package/packages/frontend-ui/NOTICE.md +99 -0
- package/packages/frontend-ui/README.md +59 -0
- package/packages/frontend-ui/agents/ui-color-reviewer.md +174 -0
- package/packages/frontend-ui/agents/ui-design-critic.md +198 -0
- package/packages/frontend-ui/agents/ui-interaction-reviewer.md +259 -0
- package/packages/frontend-ui/agents/ui-motion-reviewer.md +266 -0
- package/packages/frontend-ui/agents/ui-reviewer.md +251 -0
- package/packages/frontend-ui/agents/ui-typography-reviewer.md +222 -0
- package/packages/frontend-ui/hooks/tests/ui-animation-easing-check_test.sh +78 -0
- package/packages/frontend-ui/hooks/tests/ui-banned-fonts-check_test.sh +77 -0
- package/packages/frontend-ui/hooks/tests/ui-color-check_test.sh +75 -0
- package/packages/frontend-ui/hooks/ui-animation-easing-check.sh +86 -0
- package/packages/frontend-ui/hooks/ui-banned-fonts-check.sh +90 -0
- package/packages/frontend-ui/hooks/ui-color-check.sh +102 -0
- package/packages/frontend-ui/rules/color-and-contrast.md +230 -0
- package/packages/frontend-ui/rules/frontend-design-aesthetics.md +124 -0
- package/packages/frontend-ui/rules/interaction-polish.md +335 -0
- package/packages/frontend-ui/rules/motion-and-animation.md +283 -0
- package/packages/frontend-ui/rules/spatial-and-layout.md +212 -0
- package/packages/frontend-ui/rules/typography-guidelines.md +185 -0
- package/packages/frontend-ui/rules/ui-anti-patterns.md +309 -0
- package/packages/frontend-ui/settings.json +24 -0
- package/packages/frontend-ui/skills/impeccable-craft/SKILL.md +187 -0
- package/packages/gan/README.md +232 -0
- package/packages/gan/agents/gan-evaluator.md +214 -0
- package/packages/gan/agents/gan-generator.md +171 -0
- package/packages/gan/agents/gan-planner.md +206 -0
- package/packages/gan/rubrics/functionality.md +66 -0
- package/packages/gan/rubrics/ui-quality.md +77 -0
- package/packages/gan/skills/gan-evaluator/SKILL.md +91 -0
- package/packages/gan/skills/gan-generator/SKILL.md +72 -0
- package/packages/gan/skills/gan-planner/SKILL.md +93 -0
- package/packages/stack-agents/go/go-concurrency-reviewer.md +210 -0
- package/packages/stack-agents/go/go-error-reviewer.md +187 -0
- package/packages/stack-agents/go/go-modernizer.md +160 -0
- package/packages/stack-agents/go/go-observability-reviewer.md +185 -0
- package/packages/stack-agents/go/go-performance-reviewer.md +160 -0
- package/packages/stack-agents/go/go-reviewer.md +277 -0
- package/packages/stack-agents/go/references/benchmark-methodology.md +280 -0
- package/packages/stack-agents/go/references/channel-patterns.md +384 -0
- package/packages/stack-agents/go/references/cli-cobra-viper.md +190 -0
- package/packages/stack-agents/go/references/code-style.md +262 -0
- package/packages/stack-agents/go/references/context-propagation.md +317 -0
- package/packages/stack-agents/go/references/data-structures.md +315 -0
- package/packages/stack-agents/go/references/database-patterns.md +334 -0
- package/packages/stack-agents/go/references/design-patterns.md +411 -0
- package/packages/stack-agents/go/references/di-frameworks.md +146 -0
- package/packages/stack-agents/go/references/error-creation.md +251 -0
- package/packages/stack-agents/go/references/error-inspection.md +348 -0
- package/packages/stack-agents/go/references/error-wrapping.md +230 -0
- package/packages/stack-agents/go/references/gopls-driving.md +62 -0
- package/packages/stack-agents/go/references/goroutine-lifecycle.md +351 -0
- package/packages/stack-agents/go/references/graphql-patterns.md +221 -0
- package/packages/stack-agents/go/references/grpc-patterns.md +373 -0
- package/packages/stack-agents/go/references/modernize-guide.md +522 -0
- package/packages/stack-agents/go/references/module-management.md +191 -0
- package/packages/stack-agents/go/references/naming-conventions.md +176 -0
- package/packages/stack-agents/go/references/observability-pipeline.md +352 -0
- package/packages/stack-agents/go/references/performance-profiling.md +250 -0
- package/packages/stack-agents/go/references/refactoring-mechanics.md +127 -0
- package/packages/stack-agents/go/references/rest-openapi-patterns.md +160 -0
- package/packages/stack-agents/go/references/samber-do.md +201 -0
- package/packages/stack-agents/go/references/samber-libraries.md +363 -0
- package/packages/stack-agents/go/references/samber-lo.md +260 -0
- package/packages/stack-agents/go/references/samber-oops.md +200 -0
- package/packages/stack-agents/go/references/security-checklist.md +441 -0
- package/packages/stack-agents/go/references/standard-stdlib-now.md +181 -0
- package/packages/stack-agents/go/references/stay-updated.md +147 -0
- package/packages/stack-agents/go/references/structs-interfaces.md +312 -0
- package/packages/stack-agents/go/references/sync-primitives.md +395 -0
- package/packages/stack-agents/go/references/testing-patterns.md +483 -0
- package/packages/stack-agents/go/references/troubleshooting.md +98 -0
- package/packages/stack-agents/python/py-reviewer.md +194 -0
- package/packages/stack-agents/rust/rs-reviewer.md +188 -0
- package/packages/stack-agents/typescript/ts-reviewer.md +135 -0
- package/packages/stack-hooks/go/go-context-check-on-edit.sh +56 -0
- package/packages/stack-hooks/go/go-error-check-on-edit.sh +54 -0
- package/packages/stack-hooks/go/go-format-on-edit.sh +32 -0
- package/packages/stack-hooks/go/go-safety-check-on-edit.sh +54 -0
- package/packages/stack-hooks/go/go-vet-on-edit.sh +61 -0
- package/packages/stack-hooks/go/golangci-lint-on-edit.sh +54 -0
- package/packages/stack-hooks/python/ruff-on-edit.sh +67 -0
- package/packages/stack-hooks/rust/cargo-check-on-edit.sh +64 -0
- package/packages/stack-hooks/typescript/typecheck-on-edit.sh +76 -0
- package/packages/stack-rules/go/go-conventions.md +44 -0
- package/packages/stack-rules/go/go-safety.md +35 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Performance Profiling
|
|
2
|
+
|
|
3
|
+
> Reference document for go-performance-reviewer. Loaded on demand via Read tool.
|
|
4
|
+
|
|
5
|
+
## pprof Workflow
|
|
6
|
+
|
|
7
|
+
### Setup
|
|
8
|
+
|
|
9
|
+
```go
|
|
10
|
+
import _ "net/http/pprof" // register handlers on DefaultServeMux
|
|
11
|
+
|
|
12
|
+
func main() {
|
|
13
|
+
// Option 1: Separate debug server
|
|
14
|
+
go func() {
|
|
15
|
+
log.Println(http.ListenAndServe("localhost:6060", nil))
|
|
16
|
+
}()
|
|
17
|
+
|
|
18
|
+
// Option 2: Add to existing mux (Go 1.22+ enhanced ServeMux)
|
|
19
|
+
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
|
|
20
|
+
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
|
|
21
|
+
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
|
|
22
|
+
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
|
|
23
|
+
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Profile Types
|
|
28
|
+
|
|
29
|
+
| Profile | URL / Flag | What It Shows |
|
|
30
|
+
|---------|-----------|---------------|
|
|
31
|
+
| CPU | `/debug/pprof/profile?seconds=30` | Where CPU time is spent |
|
|
32
|
+
| Heap | `/debug/pprof/heap` | Current memory allocations |
|
|
33
|
+
| Allocs | `/debug/pprof/allocs` | All past allocations (even freed) |
|
|
34
|
+
| Goroutine | `/debug/pprof/goroutine` | All goroutine stacks |
|
|
35
|
+
| Block | `/debug/pprof/block` | Where goroutines block on sync |
|
|
36
|
+
| Mutex | `/debug/pprof/mutex` | Mutex contention |
|
|
37
|
+
| Threadcreate | `/debug/pprof/threadcreate` | OS thread creation |
|
|
38
|
+
|
|
39
|
+
### Collection and Analysis
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Collect CPU profile (30 seconds)
|
|
43
|
+
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
|
|
44
|
+
|
|
45
|
+
# Collect heap profile
|
|
46
|
+
go tool pprof http://localhost:6060/debug/pprof/heap
|
|
47
|
+
|
|
48
|
+
# Interactive commands
|
|
49
|
+
(pprof) top 20 # top 20 functions by cost
|
|
50
|
+
(pprof) list funcName # source-level annotation
|
|
51
|
+
(pprof) web # open flame graph in browser
|
|
52
|
+
(pprof) peek funcName # callers and callees
|
|
53
|
+
|
|
54
|
+
# From test
|
|
55
|
+
go test -cpuprofile cpu.prof -memprofile mem.prof -bench .
|
|
56
|
+
go tool pprof cpu.prof
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## benchstat Workflow
|
|
60
|
+
|
|
61
|
+
Statistically rigorous benchmark comparison.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Run benchmarks with multiple iterations
|
|
65
|
+
go test -bench=BenchmarkProcess -count=6 -benchmem > old.txt
|
|
66
|
+
|
|
67
|
+
# Make changes, then run again
|
|
68
|
+
go test -bench=BenchmarkProcess -count=6 -benchmem > new.txt
|
|
69
|
+
|
|
70
|
+
# Compare
|
|
71
|
+
benchstat old.txt new.txt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Output interpretation:**
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
name old time/op new time/op delta
|
|
78
|
+
Process-8 12.3ms ± 2% 8.7ms ± 1% -29.27% (p=0.002 n=6+6)
|
|
79
|
+
|
|
80
|
+
name old alloc/op new alloc/op delta
|
|
81
|
+
Process-8 4.80kB ± 0% 1.20kB ± 0% -75.00% (p=0.002 n=6+6)
|
|
82
|
+
|
|
83
|
+
name old allocs/op new allocs/op delta
|
|
84
|
+
Process-8 45.0 ± 0% 12.0 ± 0% -73.33% (p=0.002 n=6+6)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Field | Meaning |
|
|
88
|
+
|-------|---------|
|
|
89
|
+
| `± N%` | Variation across runs (lower = more stable) |
|
|
90
|
+
| `delta` | Percentage change (negative = improvement) |
|
|
91
|
+
| `p=0.002` | p-value: < 0.05 means statistically significant |
|
|
92
|
+
| `n=6+6` | Sample sizes used |
|
|
93
|
+
|
|
94
|
+
**Rules:**
|
|
95
|
+
- Always use `-count=6` or higher (minimum for statistical significance)
|
|
96
|
+
- If `p > 0.05`, the change is not statistically significant — don't claim improvement
|
|
97
|
+
- Run on quiet machine, no other CPU-heavy processes
|
|
98
|
+
- Use `-benchtime=2s` for fast benchmarks to get stable numbers
|
|
99
|
+
|
|
100
|
+
## Escape Analysis
|
|
101
|
+
|
|
102
|
+
Understand what allocates on the heap vs stack.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
go build -gcflags="-m" ./...
|
|
106
|
+
go build -gcflags="-m -m" ./... # more verbose
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Output examples:**
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
./main.go:15:6: can inline NewUser
|
|
113
|
+
./main.go:20:6: &User{} escapes to heap # heap allocation!
|
|
114
|
+
./main.go:25:6: result does not escape # stays on stack
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Common escape causes:**
|
|
118
|
+
|
|
119
|
+
| Pattern | Escapes? | Fix |
|
|
120
|
+
|---------|----------|-----|
|
|
121
|
+
| Return pointer to local | Yes | Return value if small |
|
|
122
|
+
| Store in interface | Yes | Use concrete type |
|
|
123
|
+
| Closure captures variable | Yes | Pass as parameter |
|
|
124
|
+
| Slice append beyond cap | Yes | Pre-allocate |
|
|
125
|
+
| Send to channel | Yes | Use sync.Pool |
|
|
126
|
+
|
|
127
|
+
```go
|
|
128
|
+
// ESCAPES — pointer returned
|
|
129
|
+
func newUser(name string) *User {
|
|
130
|
+
u := User{Name: name} // escapes to heap
|
|
131
|
+
return &u
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// STAYS ON STACK — value returned
|
|
135
|
+
func newPoint(x, y int) Point {
|
|
136
|
+
return Point{X: x, Y: y} // allocated on stack
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ESCAPES — stored in interface
|
|
140
|
+
func process(v any) { ... }
|
|
141
|
+
func main() {
|
|
142
|
+
n := 42
|
|
143
|
+
process(n) // n escapes to heap (boxed into interface)
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## alloc_objects — Finding Hot Allocators
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
go tool pprof -alloc_objects http://localhost:6060/debug/pprof/heap
|
|
151
|
+
|
|
152
|
+
(pprof) top 10
|
|
153
|
+
Showing nodes accounting for 1523456 allocs
|
|
154
|
+
flat flat% sum% cum cum%
|
|
155
|
+
892340 58.57% 58.57% 892340 58.57% encoding/json.(*Decoder).Token
|
|
156
|
+
234567 15.40% 73.97% 234567 15.40% bytes.(*Buffer).grow
|
|
157
|
+
123456 8.10% 82.07% 123456 8.10% fmt.Sprintf
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Common allocation hot spots and fixes:**
|
|
161
|
+
|
|
162
|
+
| Hot Spot | Fix |
|
|
163
|
+
|----------|-----|
|
|
164
|
+
| `fmt.Sprintf` | `strconv.Itoa`, `strconv.FormatInt`, string concat |
|
|
165
|
+
| `json.Marshal/Unmarshal` | Pre-allocated buffer, `json.NewEncoder`, sonic/jsoniter |
|
|
166
|
+
| `bytes.Buffer.grow` | Pre-sized `bytes.NewBuffer(make([]byte, 0, expectedSize))` |
|
|
167
|
+
| `append` growing | Pre-allocate with `make([]T, 0, n)` |
|
|
168
|
+
| String concatenation in loop | `strings.Builder` |
|
|
169
|
+
|
|
170
|
+
## GC Tuning
|
|
171
|
+
|
|
172
|
+
### GOGC
|
|
173
|
+
|
|
174
|
+
Controls GC frequency. Default: `GOGC=100` means GC triggers when heap doubles.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
GOGC=200 ./myapp # less frequent GC, more memory, less CPU
|
|
178
|
+
GOGC=50 ./myapp # more frequent GC, less memory, more CPU
|
|
179
|
+
GOGC=off ./myapp # disable GC (for short-lived batch jobs only!)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
| GOGC Value | Heap Growth Before GC | Tradeoff |
|
|
183
|
+
|------------|----------------------|----------|
|
|
184
|
+
| 50 | 50% growth | Low memory, high CPU |
|
|
185
|
+
| 100 (default) | 100% growth | Balanced |
|
|
186
|
+
| 200 | 200% growth | High memory, low CPU |
|
|
187
|
+
| 400+ | 400%+ growth | For memory-rich servers |
|
|
188
|
+
|
|
189
|
+
### GOMEMLIMIT (Go 1.19+)
|
|
190
|
+
|
|
191
|
+
Hard ceiling on total Go memory. GC works harder as it approaches the limit.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
GOMEMLIMIT=512MiB ./myapp # GC gets aggressive near 512MB
|
|
195
|
+
GOMEMLIMIT=2GiB ./myapp # for container with 2GB memory limit
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Best practice for containers:**
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Container has 4GB memory
|
|
202
|
+
# Reserve ~20% for non-Go memory (OS, cgo, etc.)
|
|
203
|
+
GOMEMLIMIT=3200MiB GOGC=100 ./myapp
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Runtime Metrics
|
|
207
|
+
|
|
208
|
+
```go
|
|
209
|
+
import "runtime/metrics"
|
|
210
|
+
|
|
211
|
+
func collectGCMetrics() {
|
|
212
|
+
samples := []metrics.Sample{
|
|
213
|
+
{Name: "/gc/cycles/total:gc-cycles"},
|
|
214
|
+
{Name: "/gc/heap/allocs:bytes"},
|
|
215
|
+
{Name: "/gc/heap/goal:bytes"},
|
|
216
|
+
{Name: "/memory/classes/total:bytes"},
|
|
217
|
+
}
|
|
218
|
+
metrics.Read(samples)
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Caching Decision Tree
|
|
223
|
+
|
|
224
|
+
| Scenario | Solution | When |
|
|
225
|
+
|----------|----------|------|
|
|
226
|
+
| Process-local, bounded size | `sync.Map` or samber/hot | Single instance, < 100k entries |
|
|
227
|
+
| Process-local, eviction needed | samber/hot (LRU, LFU, ARC, etc.) | Need TTL or size-based eviction |
|
|
228
|
+
| Distributed, shared across instances | Redis | Multi-instance, needs consistency |
|
|
229
|
+
| Static assets | CDN (Cloudflare, CloudFront) | Images, JS, CSS, fonts |
|
|
230
|
+
| Computed results, cross-request | Process-local + Redis fallback | Expensive computation |
|
|
231
|
+
| Database query results | Application-level cache | Repeated queries, read-heavy |
|
|
232
|
+
|
|
233
|
+
```go
|
|
234
|
+
// samber/hot — in-memory cache with eviction
|
|
235
|
+
import "github.com/samber/hot"
|
|
236
|
+
|
|
237
|
+
cache := hot.NewHotCache[string, *User](hot.LRU, 10000)
|
|
238
|
+
cache.SetWithTTL("user:42", user, 5*time.Minute)
|
|
239
|
+
|
|
240
|
+
if user, ok := cache.Get("user:42"); ok {
|
|
241
|
+
return user, nil
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## When to Use
|
|
246
|
+
|
|
247
|
+
Apply when reviewing performance-sensitive code or investigating performance issues. Flag violations as:
|
|
248
|
+
- **CRITICAL**: Missing pprof endpoint in production service, GOGC=off in long-running service
|
|
249
|
+
- **WARNING**: Benchmark without -count (no statistical rigor), missing GOMEMLIMIT in containers
|
|
250
|
+
- **SUGGESTION**: Could use sync.Pool for hot-path allocations, pre-allocate slices, use strings.Builder
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Refactoring Mechanics (behavior-preserving Go transforms)
|
|
2
|
+
|
|
3
|
+
> Reference document for go-reviewer and go-modernizer. Loaded on demand via Read tool.
|
|
4
|
+
> Upstream: golang.org/x/tools · github.com/uber-go/gopatch · github.com/dave/dst
|
|
5
|
+
|
|
6
|
+
A refactor is a transform that changes structure while provably preserving
|
|
7
|
+
behavior. In Go, "provably" means a construction-guaranteed tool did the edit —
|
|
8
|
+
not a freehand keystroke and not a text substitution. Pick the *weakest* tool
|
|
9
|
+
that can express the change, gate the risk against the blast radius's own test
|
|
10
|
+
coverage (see the safety net in `testing-patterns.md`), and never let a
|
|
11
|
+
refactor and a behavior change share a commit.
|
|
12
|
+
|
|
13
|
+
## Part 1 — The tool-escalation ladder
|
|
14
|
+
|
|
15
|
+
Two rules govern the whole ladder:
|
|
16
|
+
|
|
17
|
+
1. **Least-powerful tool first.** A `gofmt -r` rule you can read in one line is
|
|
18
|
+
safer than a hand-written AST walk. Climb only when the rung below cannot
|
|
19
|
+
express the transform.
|
|
20
|
+
2. **NEVER `sed`/`perl` a structural Go change.** Text tools rewrite *inside*
|
|
21
|
+
string literals and comments, split identifiers that share a prefix, and
|
|
22
|
+
have zero idea what scope a name lives in. Every rung below is
|
|
23
|
+
syntax-aware; a regex is not. This rule has no exceptions.
|
|
24
|
+
|
|
25
|
+
Rungs, weakest first — each with a runnable command and its one-line trap:
|
|
26
|
+
|
|
27
|
+
1. **gopls code actions** — the blessed path for structural edits (Rename,
|
|
28
|
+
Extract function/variable, Inline, "fill struct", organize imports). Drive
|
|
29
|
+
them from the editor or the gopls MCP, not a shell. A CLI form exists —
|
|
30
|
+
`gopls codeaction -kind=refactor.extract -exec ./pkg/file.go` — but it is
|
|
31
|
+
*illustrative/debugging-only*; do not build a migration on it.
|
|
32
|
+
Gotcha: code actions are single-file and cursor-scoped; they do not sweep a package.
|
|
33
|
+
2. **`gofmt -r`** — expression-pattern rewriting from the stdlib, no install.
|
|
34
|
+
`gofmt -r 'fmt.Sprintf("%d", a) -> fmt.Sprint(a)' -w .`
|
|
35
|
+
Gotcha: single-letter names are wildcards, but the rule matches **expressions only** — it cannot rewrite statements, add imports, or restructure control flow.
|
|
36
|
+
3. **`eg`** — example-based rewriting driven by a before/after template.
|
|
37
|
+
`go install golang.org/x/tools/cmd/eg@latest` then `eg -t template.go -w ./...`
|
|
38
|
+
Gotcha: like `gofmt -r` it transforms **expressions only** (a `before`/`after` function pair); it is not a migration engine.
|
|
39
|
+
4. **`gopatch`** — semantic patches (a diff-shaped `@@ ... @@` grammar) that
|
|
40
|
+
*can* touch statements and imports.
|
|
41
|
+
`gopatch -p rewrite.patch ./...`
|
|
42
|
+
Gotcha: **beta, ~80% coverage** — treat it as an escalation rung for a specific pattern, not a whole-codebase migration tool; diff every result.
|
|
43
|
+
5. **go/analysis + `analysistest.RunWithSuggestedFixes`** — when a transform
|
|
44
|
+
*recurs*, write an analyzer that emits a `SuggestedFix` and pin it with a
|
|
45
|
+
golden-fixture test (`RunWithSuggestedFixes` applies the fix and diffs
|
|
46
|
+
against `testdata/.../*.golden`). Ship it via `go vet -vettool=` or
|
|
47
|
+
`go fix -fixtool=`.
|
|
48
|
+
Gotcha: real engineering cost — only worth it above roughly a dozen call sites or a permanent lint.
|
|
49
|
+
6. **`go fix` / `//go:fix inline`** *(Go 1.26+)* — mark a wrapper or moved
|
|
50
|
+
function `//go:fix inline`; `go fix ./...` then inlines every call, in this
|
|
51
|
+
and downstream packages. The canonical low-risk way to retire a deprecated
|
|
52
|
+
API or a v1→v2 import.
|
|
53
|
+
`go fix ./...`
|
|
54
|
+
Gotcha: the `inline` fixer and the `//go:fix` directive land in **Go 1.26** — gate on the toolchain the way go-modernizer gates every rewrite; it is a no-op on older `go`.
|
|
55
|
+
7. **`dave/dst`** — a decorated syntax tree for AST surgery that must survive
|
|
56
|
+
round-tripping. Reach here only when no rung above fits.
|
|
57
|
+
`import "github.com/dave/dst/decorator"` (parse → mutate → `decorator.Print`)
|
|
58
|
+
Gotcha: use `dst`, **not** raw `go/ast` — `go/ast` attaches comments by byte offset and mangles their placement the moment you move a node.
|
|
59
|
+
8. **`deadcode -whylive`** — not a rewriter but the removal companion: proves
|
|
60
|
+
what a deletion orphans and why a symbol is still reachable.
|
|
61
|
+
`go install golang.org/x/tools/cmd/deadcode@latest` then `deadcode -whylive=pkg.Symbol ./...`
|
|
62
|
+
Gotcha: it reasons over a build's reachability; unexported code hit only by reflection or `//go:linkname` can read as dead when it is not.
|
|
63
|
+
|
|
64
|
+
**Always finish with `goimports -w .`** after any mechanical transform — every
|
|
65
|
+
rung above can leave the import block stale, and a clean import list is the
|
|
66
|
+
cheapest signal that the edit type-checks.
|
|
67
|
+
|
|
68
|
+
## Part 2 — Smell → fix → tool → risk catalog
|
|
69
|
+
|
|
70
|
+
For *target shapes*, this table points at `design-patterns.md` rather than
|
|
71
|
+
re-teaching them; only the net-new **move/graft mechanics** are taught below it.
|
|
72
|
+
|
|
73
|
+
| Smell | Go fix (target shape) | Tool rung | Risk |
|
|
74
|
+
|-------|----------------------|-----------|------|
|
|
75
|
+
| Long positional constructor | Options struct — `design-patterns.md` §1 | gopls Extract + `gofmt -r` on call sites | Med |
|
|
76
|
+
| Package binds a concrete dependency | Consumer-side interface — `design-patterns.md` §5 | manual + `type A = B` alias | Med |
|
|
77
|
+
| Deep `if`/`else` nesting | Guard clauses — `design-patterns.md` §14 | gopls Extract / Inline | Low |
|
|
78
|
+
| Embedding for reuse | Composition — `design-patterns.md` §8 | gopls + manual | Low |
|
|
79
|
+
| Deprecated API called everywhere | `//go:fix inline` wrapper | `go fix` (1.26+) | Low |
|
|
80
|
+
| Repeated expression idiom | Template rewrite | `gofmt -r` → `eg` | Low |
|
|
81
|
+
| Type belongs in another package | `type A = B` alias move (below) | manual + `gopatch` for sites | Med |
|
|
82
|
+
| New logic tangled with untested legacy | Sprout (below) | manual + new tests | Low |
|
|
83
|
+
| Legacy call needs pre/post logic | Wrap (below) | gopls Rename + manual | Low |
|
|
84
|
+
|
|
85
|
+
**Move a type across packages via a temporary alias.** Moving `Foo` from
|
|
86
|
+
`pkg/old` to `pkg/new` in one shot breaks every importer. Instead: (1) define
|
|
87
|
+
`Foo` in `pkg/new`; (2) in `pkg/old` leave `type Foo = new.Foo` — an *alias*,
|
|
88
|
+
not a copy, so old importers keep compiling and stay type-identical; (3)
|
|
89
|
+
migrate importers to `pkg/new` (a `gopatch` or `//go:fix inline` job); (4)
|
|
90
|
+
delete the alias. Each step compiles green and is separately committable.
|
|
91
|
+
|
|
92
|
+
**Sprout Method/Class.** When new behavior must land inside a hairy, untested
|
|
93
|
+
function, do not edit that function's guts. Write the new behavior as a *new*
|
|
94
|
+
function or type with its own tests, and call it from the one place the old
|
|
95
|
+
code needs it. The risky legacy body is touched by one line, not rewritten.
|
|
96
|
+
|
|
97
|
+
**Wrap Method.** To add pre/post behavior to an existing call without editing
|
|
98
|
+
its body: rename the original (gopls Rename) to `fooCore`, then add a new `Foo`
|
|
99
|
+
with the original name that does the new work around a call to `fooCore`.
|
|
100
|
+
Callers are unchanged; the old behavior is preserved verbatim inside `fooCore`.
|
|
101
|
+
|
|
102
|
+
## Part 3 — Hard-rule gotchas
|
|
103
|
+
|
|
104
|
+
**After ANY rename, grep beyond the compiler.** gopls Rename guarantees the
|
|
105
|
+
code *compiles* — nothing more. It is blind to string-encoded uses of the name:
|
|
106
|
+
after renaming a field or type, grep the struct tags (`json:`, `db:`, `yaml:`,
|
|
107
|
+
`gorm:`), every `reflect`-based access (`FieldByName`, `MethodByName`,
|
|
108
|
+
`Tag.Get`), and any `text/template`/`html/template` files that name the old
|
|
109
|
+
identifier. Those keep compiling and fail at runtime.
|
|
110
|
+
|
|
111
|
+
**Never mix structural and behavioral changes in one commit.** A commit is
|
|
112
|
+
either a refactor (behavior byte-identical) or a behavior change — never both.
|
|
113
|
+
Reviewers and `git bisect` rely on that line. Concretely: **split a move from
|
|
114
|
+
an optimization.** Move the code in one commit, then optimize it in the next;
|
|
115
|
+
a move buried inside a perf change is unreviewable and un-revertable.
|
|
116
|
+
|
|
117
|
+
**Break import cycles with a consumer-side interface *before* moving code.**
|
|
118
|
+
If relocating a type would create an import cycle, do not fight the move —
|
|
119
|
+
first define the small interface at the *consumer* (`design-patterns.md` §5) so
|
|
120
|
+
the dependency inverts, *then* move. Ordering matters: the seam comes first.
|
|
121
|
+
|
|
122
|
+
Every transform above is only as safe as the tests guarding its blast radius.
|
|
123
|
+
Before touching code, size that blast radius's coverage and pick your caution
|
|
124
|
+
tier per the **Coverage-Adaptive Refactoring Safety Net** in
|
|
125
|
+
`testing-patterns.md` — below 40% you write characterization tests and install
|
|
126
|
+
seams before any transform, and restrict yourself to construction-guaranteed
|
|
127
|
+
tools from the ladder above.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# REST / OpenAPI Patterns (swaggo + oapi-codegen)
|
|
2
|
+
|
|
3
|
+
> Reference document for go-reviewer. Loaded on demand via Read tool.
|
|
4
|
+
> Upstream: https://github.com/swaggo/swag · https://github.com/oapi-codegen/oapi-codegen
|
|
5
|
+
|
|
6
|
+
REST is the dominant Go API surface. There are two honest ways to keep the code
|
|
7
|
+
and the OpenAPI spec in sync, and they pull in opposite directions — pick by who
|
|
8
|
+
owns the contract.
|
|
9
|
+
|
|
10
|
+
## Two paths — pick by who owns the contract
|
|
11
|
+
|
|
12
|
+
**Code-first (swaggo/swag)** — annotations on handlers *generate* the spec. The
|
|
13
|
+
Go code is the source of truth; the spec is a build artifact. Fastest for a team
|
|
14
|
+
that owns both ends and iterates quickly. This is the **primary path** here.
|
|
15
|
+
|
|
16
|
+
- Lead with **swag v1** (stable, OpenAPI 2.0 / Swagger). It is what almost every
|
|
17
|
+
gin/echo/fiber integration targets today.
|
|
18
|
+
- swag **v2 (currently RC)** adds OpenAPI 3.x — treat it as preview, switch when
|
|
19
|
+
it goes GA. Don't put an RC on the critical path of a shipping service.
|
|
20
|
+
|
|
21
|
+
**Spec-first (oapi-codegen)** — hand-write the OpenAPI 3.x document, then
|
|
22
|
+
*generate* server interfaces, request/response types, and clients from it. The
|
|
23
|
+
spec is the source of truth; the code conforms to it. Prefer this when the
|
|
24
|
+
contract is the deliverable — versioned in review, published to other teams, or
|
|
25
|
+
consumed by clients you don't control — because the compiler then enforces that
|
|
26
|
+
handlers match the contract instead of the contract trailing the code.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# spec-first: generate a chi/echo/gin server + models from openapi.yaml
|
|
30
|
+
go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen \
|
|
31
|
+
-generate types,chi-server -package api openapi.yaml > api/gen.go
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You implement the generated `ServerInterface`; a missing or mis-typed handler is
|
|
35
|
+
a compile error, not a silent drift. The rest of this doc covers the code-first
|
|
36
|
+
swag path, since that is where the review footguns cluster.
|
|
37
|
+
|
|
38
|
+
## swag annotation cheatsheet
|
|
39
|
+
|
|
40
|
+
Annotations sit in a `//` comment block directly above the handler. Run
|
|
41
|
+
`swag init` to parse them into `docs/`.
|
|
42
|
+
|
|
43
|
+
| Annotation | Syntax | Gotcha |
|
|
44
|
+
|------------|--------|--------|
|
|
45
|
+
| `@Summary` | `@Summary Create a user` | One line; shows as the operation title. |
|
|
46
|
+
| `@Description` | `@Description Longer prose, may span lines` | Free text; no markup guarantees. |
|
|
47
|
+
| `@Tags` | `@Tags users` | Groups routes in the UI; keep names stable. |
|
|
48
|
+
| `@Param` | `@Param body body CreateUserReq true "payload"` | A **body** param must name a **struct** — a primitive (`string`, `int`) in body silently emits a broken/empty schema. |
|
|
49
|
+
| `@Param` (query/path) | `@Param id path string true "user id"` | `path`/`query`/`header`/`formData` take primitives fine. |
|
|
50
|
+
| `@Success` | `@Success 200 {object} UserResp` | `{object}` / `{array}` must reference a real Go type, not a shape. |
|
|
51
|
+
| `@Failure` | `@Failure 404 {object} ErrResp` | Document the error envelope too, or consumers guess it. |
|
|
52
|
+
| `@Router` | `@Router /users/{id} [get]` | Path + method in brackets; must match the actual route. |
|
|
53
|
+
| `@Security` | `@Security BearerAuth` | Names a scheme from `@securityDefinitions`; see below. |
|
|
54
|
+
|
|
55
|
+
Three traps that produce a spec which *looks* fine but lies:
|
|
56
|
+
|
|
57
|
+
1. **Named body struct.** `@Param body body string true "..."` compiles and runs;
|
|
58
|
+
the generated schema is broken. Body params must reference a named struct.
|
|
59
|
+
2. **The blank-import trap.** `swag init` writes a `docs` package, but nothing
|
|
60
|
+
imports it — so you must add `import _ "yourmodule/docs"` (usually in `main.go`)
|
|
61
|
+
or the UI serves an *empty* spec with no error.
|
|
62
|
+
3. **Stale `docs/`.** Annotations are not checked against `docs/` at build time.
|
|
63
|
+
Re-run `swag init` on **every** annotation change or the published contract
|
|
64
|
+
drifts from the code. Enforce it in CI:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
swag fmt # normalize annotation formatting
|
|
68
|
+
swag init # regenerate docs/
|
|
69
|
+
git diff --exit-code docs/ # fail the build if docs/ is stale
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## UI wiring — one line per router
|
|
73
|
+
|
|
74
|
+
Each framework has a thin adapter that mounts Swagger UI at a route. Import the
|
|
75
|
+
generated `docs` package (blank import) first, then:
|
|
76
|
+
|
|
77
|
+
- **gin** — `r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))` (`swaggo/gin-swagger`)
|
|
78
|
+
- **echo** — `e.GET("/swagger/*", echoSwagger.WrapHandler)` (`swaggo/echo-swagger`)
|
|
79
|
+
- **fiber** — `app.Get("/swagger/*", fiberSwagger.WrapHandler)` (`swaggo/fiber-swagger`)
|
|
80
|
+
- **chi** — `r.Get("/swagger/*", httpSwagger.WrapHandler)` (`swaggo/http-swagger`)
|
|
81
|
+
- **net/http** — `mux.Handle("/swagger/", httpSwagger.WrapHandler)` (`swaggo/http-swagger`)
|
|
82
|
+
|
|
83
|
+
Whichever you use: **gate the route** behind auth middleware in production, or
|
|
84
|
+
compile it out of prod builds. An open `/swagger` endpoint hands attackers a
|
|
85
|
+
complete map of your API surface.
|
|
86
|
+
|
|
87
|
+
## Security schemes
|
|
88
|
+
|
|
89
|
+
Declare schemes once, in the package-level general API comment (usually above
|
|
90
|
+
`main`), then reference them per route with `@Security`:
|
|
91
|
+
|
|
92
|
+
```go
|
|
93
|
+
// @securityDefinitions.apikey BearerAuth
|
|
94
|
+
// @in header
|
|
95
|
+
// @name Authorization
|
|
96
|
+
// @description "Bearer {token}"
|
|
97
|
+
//
|
|
98
|
+
// @securityDefinitions.oauth2.accessCode OAuth2
|
|
99
|
+
// @tokenUrl https://auth.example.com/token
|
|
100
|
+
// @authorizationUrl https://auth.example.com/authorize
|
|
101
|
+
//
|
|
102
|
+
// @securityDefinitions.apikey ApiKeyAuth // @in header, @name X-API-Key
|
|
103
|
+
// @securityDefinitions.basic BasicAuth
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
swag supports `apikey` (used for Bearer/JWT via the `Authorization` header),
|
|
107
|
+
`oauth2` (its `implicit`/`accessCode`/`password`/`application` flows), and
|
|
108
|
+
`basic`. Then, on **every** protected handler:
|
|
109
|
+
|
|
110
|
+
```go
|
|
111
|
+
// @Security BearerAuth
|
|
112
|
+
// @Router /users/{id} [get]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
A missing `@Security` understates auth in the public contract: the route renders
|
|
116
|
+
with no lock icon and consumers reasonably assume it is open. This is a contract
|
|
117
|
+
bug even when the middleware is correctly enforcing auth at runtime.
|
|
118
|
+
|
|
119
|
+
## Struct tags that shape the schema
|
|
120
|
+
|
|
121
|
+
The generated schema reads Go struct tags. Get these right or the spec misleads —
|
|
122
|
+
or leaks:
|
|
123
|
+
|
|
124
|
+
```go
|
|
125
|
+
type User struct {
|
|
126
|
+
ID string `json:"id" example:"u_123"`
|
|
127
|
+
Email string `json:"email" format:"email" example:"a@b.com"`
|
|
128
|
+
CreatedAt string `json:"createdAt" format:"date-time"`
|
|
129
|
+
Password string `json:"-" swaggerignore:"true"` // never in the spec
|
|
130
|
+
internalR string `swaggerignore:"true"` // internal-only field
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- `json:"..."` sets the property name (and `json:"-"` drops it from JSON).
|
|
135
|
+
- `example:"..."` / `format:"..."` populate the schema's example and `format`.
|
|
136
|
+
- **`swaggerignore:"true"`** keeps a field out of the generated spec entirely.
|
|
137
|
+
Put it on every secret or internal field — a password, token, or internal flag
|
|
138
|
+
that isn't ignored leaks straight into the public documentation. `json:"-"`
|
|
139
|
+
hides it from the JSON wire, but swag may still emit it in the schema unless
|
|
140
|
+
`swaggerignore` is also set.
|
|
141
|
+
|
|
142
|
+
## Review Checklist (go-reviewer)
|
|
143
|
+
|
|
144
|
+
- **CRITICAL** — Swagger UI exposed ungated in production (gate it behind auth
|
|
145
|
+
middleware, or disable/compile-out the route in prod builds).
|
|
146
|
+
- **CRITICAL** — Secret or internal field not `swaggerignore:"true"` (leaks into
|
|
147
|
+
the public spec).
|
|
148
|
+
- **WARNING** — Protected route missing `@Security` (contract understates auth;
|
|
149
|
+
no lock icon, consumers assume open).
|
|
150
|
+
- **WARNING** — Stale `docs/` vs annotations (contract drift; add a CI freshness
|
|
151
|
+
gate: `swag init` + `git diff --exit-code docs/`).
|
|
152
|
+
- **WARNING** — Primitive `@Param` body instead of a named struct (silently
|
|
153
|
+
produces a broken spec).
|
|
154
|
+
|
|
155
|
+
## Further Reading
|
|
156
|
+
|
|
157
|
+
- swaggo/swag: https://github.com/swaggo/swag
|
|
158
|
+
- swag annotation reference: https://github.com/swaggo/swag#declarative-comments-format
|
|
159
|
+
- oapi-codegen: https://github.com/oapi-codegen/oapi-codegen
|
|
160
|
+
- OpenAPI Specification: https://spec.openapis.org/
|