@ketecode/loom 0.0.0-stage → 0.1.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 +516 -2
- package/agents/accessibility-reviewer/AGENT.md +70 -0
- package/agents/accessibility-reviewer/evals/triggers.json +15 -0
- package/agents/agent-evaluator/AGENT.md +74 -0
- package/agents/agent-evaluator/evals/triggers.json +15 -0
- package/agents/architect/AGENT.md +82 -0
- package/agents/architect/evals/triggers.json +17 -0
- package/agents/billing-reviewer/AGENT.md +68 -0
- package/agents/billing-reviewer/evals/triggers.json +16 -0
- package/agents/code-reviewer/AGENT.md +51 -0
- package/agents/code-reviewer/evals/triggers.json +14 -0
- package/agents/code-simplifier/AGENT.md +74 -0
- package/agents/code-simplifier/evals/triggers.json +15 -0
- package/agents/cpp-build-resolver/AGENT.md +73 -0
- package/agents/cpp-build-resolver/evals/triggers.json +16 -0
- package/agents/cpp-reviewer/AGENT.md +59 -0
- package/agents/cpp-reviewer/evals/triggers.json +16 -0
- package/agents/csharp-build-resolver/AGENT.md +84 -0
- package/agents/csharp-build-resolver/evals/triggers.json +17 -0
- package/agents/csharp-reviewer/AGENT.md +88 -0
- package/agents/csharp-reviewer/evals/triggers.json +17 -0
- package/agents/dart-build-resolver/AGENT.md +80 -0
- package/agents/dart-build-resolver/evals/triggers.json +17 -0
- package/agents/dart-reviewer/AGENT.md +66 -0
- package/agents/dart-reviewer/evals/triggers.json +17 -0
- package/agents/database-reviewer/AGENT.md +72 -0
- package/agents/database-reviewer/evals/triggers.json +16 -0
- package/agents/django-reviewer/AGENT.md +61 -0
- package/agents/django-reviewer/evals/triggers.json +15 -0
- package/agents/doc-updater/AGENT.md +92 -0
- package/agents/doc-updater/evals/triggers.json +14 -0
- package/agents/e2e-runner/AGENT.md +88 -0
- package/agents/e2e-runner/evals/triggers.json +16 -0
- package/agents/fastapi-reviewer/AGENT.md +63 -0
- package/agents/fastapi-reviewer/evals/triggers.json +15 -0
- package/agents/flutter-reviewer/AGENT.md +70 -0
- package/agents/flutter-reviewer/evals/triggers.json +15 -0
- package/agents/fsharp-build-resolver/AGENT.md +81 -0
- package/agents/fsharp-build-resolver/evals/triggers.json +15 -0
- package/agents/fsharp-reviewer/AGENT.md +77 -0
- package/agents/fsharp-reviewer/evals/triggers.json +15 -0
- package/agents/go-build-resolver/AGENT.md +85 -0
- package/agents/go-build-resolver/evals/triggers.json +16 -0
- package/agents/go-reviewer/AGENT.md +66 -0
- package/agents/go-reviewer/evals/triggers.json +16 -0
- package/agents/healthcare-reviewer/AGENT.md +65 -0
- package/agents/healthcare-reviewer/evals/triggers.json +16 -0
- package/agents/i18n-reviewer/AGENT.md +64 -0
- package/agents/i18n-reviewer/evals/triggers.json +16 -0
- package/agents/infra-reviewer/AGENT.md +93 -0
- package/agents/infra-reviewer/evals/triggers.json +15 -0
- package/agents/java-build-resolver/AGENT.md +82 -0
- package/agents/java-build-resolver/evals/triggers.json +16 -0
- package/agents/java-reviewer/AGENT.md +64 -0
- package/agents/java-reviewer/evals/triggers.json +16 -0
- package/agents/kotlin-build-resolver/AGENT.md +89 -0
- package/agents/kotlin-build-resolver/evals/triggers.json +16 -0
- package/agents/kotlin-reviewer/AGENT.md +75 -0
- package/agents/kotlin-reviewer/evals/triggers.json +16 -0
- package/agents/mle-reviewer/AGENT.md +68 -0
- package/agents/mle-reviewer/evals/triggers.json +16 -0
- package/agents/network-config-reviewer/AGENT.md +68 -0
- package/agents/network-config-reviewer/evals/triggers.json +17 -0
- package/agents/payments-reviewer/AGENT.md +64 -0
- package/agents/payments-reviewer/evals/triggers.json +16 -0
- package/agents/performance-optimizer/AGENT.md +86 -0
- package/agents/performance-optimizer/evals/triggers.json +16 -0
- package/agents/perl-build-resolver/AGENT.md +84 -0
- package/agents/perl-build-resolver/evals/triggers.json +15 -0
- package/agents/perl-reviewer/AGENT.md +77 -0
- package/agents/perl-reviewer/evals/triggers.json +15 -0
- package/agents/php-build-resolver/AGENT.md +88 -0
- package/agents/php-build-resolver/evals/triggers.json +16 -0
- package/agents/php-reviewer/AGENT.md +61 -0
- package/agents/php-reviewer/evals/triggers.json +15 -0
- package/agents/planner/AGENT.md +75 -0
- package/agents/planner/evals/triggers.json +17 -0
- package/agents/pr-test-analyzer/AGENT.md +82 -0
- package/agents/pr-test-analyzer/evals/triggers.json +16 -0
- package/agents/python-build-resolver/AGENT.md +87 -0
- package/agents/python-build-resolver/evals/triggers.json +16 -0
- package/agents/python-reviewer/AGENT.md +63 -0
- package/agents/python-reviewer/evals/triggers.json +15 -0
- package/agents/rag-reviewer/AGENT.md +71 -0
- package/agents/rag-reviewer/evals/triggers.json +16 -0
- package/agents/react-reviewer/AGENT.md +70 -0
- package/agents/react-reviewer/evals/triggers.json +16 -0
- package/agents/refactor-cleaner/AGENT.md +82 -0
- package/agents/refactor-cleaner/evals/triggers.json +16 -0
- package/agents/ruby-build-resolver/AGENT.md +93 -0
- package/agents/ruby-build-resolver/evals/triggers.json +16 -0
- package/agents/ruby-reviewer/AGENT.md +62 -0
- package/agents/ruby-reviewer/evals/triggers.json +16 -0
- package/agents/rust-build-resolver/AGENT.md +98 -0
- package/agents/rust-build-resolver/evals/triggers.json +16 -0
- package/agents/rust-reviewer/AGENT.md +78 -0
- package/agents/rust-reviewer/evals/triggers.json +15 -0
- package/agents/security-reviewer/AGENT.md +84 -0
- package/agents/security-reviewer/evals/triggers.json +16 -0
- package/agents/silent-failure-hunter/AGENT.md +66 -0
- package/agents/silent-failure-hunter/evals/triggers.json +16 -0
- package/agents/solidity-reviewer/AGENT.md +70 -0
- package/agents/solidity-reviewer/evals/triggers.json +16 -0
- package/agents/swift-build-resolver/AGENT.md +85 -0
- package/agents/swift-build-resolver/evals/triggers.json +15 -0
- package/agents/swift-reviewer/AGENT.md +75 -0
- package/agents/swift-reviewer/evals/triggers.json +15 -0
- package/agents/typescript-build-resolver/AGENT.md +76 -0
- package/agents/typescript-build-resolver/evals/triggers.json +15 -0
- package/agents/typescript-reviewer/AGENT.md +76 -0
- package/agents/typescript-reviewer/evals/triggers.json +15 -0
- package/agents/vue-reviewer/AGENT.md +75 -0
- package/agents/vue-reviewer/evals/triggers.json +15 -0
- package/bin/kete-loom.js +683 -0
- package/commands/aside.md +19 -0
- package/commands/build-fix.md +26 -0
- package/commands/campaign.md +19 -0
- package/commands/changelog.md +36 -0
- package/commands/checkpoint.md +26 -0
- package/commands/codemap.md +25 -0
- package/commands/commit.md +26 -0
- package/commands/deps-audit.md +32 -0
- package/commands/epic-decompose.md +21 -0
- package/commands/explain.md +37 -0
- package/commands/feature-dev.md +22 -0
- package/commands/hookify.md +23 -0
- package/commands/i18n-check.md +39 -0
- package/commands/issue-sync.md +22 -0
- package/commands/jira.md +19 -0
- package/commands/learn.md +23 -0
- package/commands/loom.md +21 -0
- package/commands/loop.md +20 -0
- package/commands/model-route.md +27 -0
- package/commands/onboard.md +35 -0
- package/commands/orchestrate.md +21 -0
- package/commands/plan-feature.md +36 -0
- package/commands/postmortem.md +42 -0
- package/commands/pr-describe.md +39 -0
- package/commands/pr.md +22 -0
- package/commands/prd.md +41 -0
- package/commands/project-init.md +21 -0
- package/commands/refactor-clean.md +24 -0
- package/commands/resume-session.md +22 -0
- package/commands/review.md +35 -0
- package/commands/save-session.md +37 -0
- package/commands/security-scan.md +32 -0
- package/commands/sessions.md +21 -0
- package/commands/skill-create.md +21 -0
- package/commands/tdd.md +36 -0
- package/commands/test-coverage.md +24 -0
- package/commands/threat-model.md +36 -0
- package/commands/update-docs.md +25 -0
- package/commands/verify.md +21 -0
- package/hooks/block-dangerous-commands/HOOK.md +30 -0
- package/hooks/block-dangerous-commands/cases.json +50 -0
- package/hooks/block-dangerous-commands/hook.js +75 -0
- package/hooks/block-no-verify/HOOK.md +25 -0
- package/hooks/block-no-verify/cases.json +30 -0
- package/hooks/block-no-verify/hook.js +43 -0
- package/hooks/format-on-edit/HOOK.md +24 -0
- package/hooks/format-on-edit/hook.js +89 -0
- package/hooks/guard-secrets/HOOK.md +19 -0
- package/hooks/guard-secrets/cases.json +110 -0
- package/hooks/guard-secrets/hook.js +44 -0
- package/hooks/load-session-context/HOOK.md +20 -0
- package/hooks/load-session-context/hook.js +56 -0
- package/hooks/protect-files/HOOK.md +24 -0
- package/hooks/protect-files/cases.json +27 -0
- package/hooks/protect-files/hook.js +39 -0
- package/hooks/run.js +132 -0
- package/mcp/atlassian.json +11 -0
- package/mcp/chrome-devtools.json +18 -0
- package/mcp/cloudflare.json +11 -0
- package/mcp/context7.json +11 -0
- package/mcp/fetch.json +17 -0
- package/mcp/figma.json +11 -0
- package/mcp/git.json +17 -0
- package/mcp/github.json +11 -0
- package/mcp/linear.json +11 -0
- package/mcp/memory.json +18 -0
- package/mcp/notion.json +11 -0
- package/mcp/playwright.json +18 -0
- package/mcp/sentry.json +11 -0
- package/mcp/stripe.json +11 -0
- package/mcp/supabase.json +11 -0
- package/mcp/time.json +17 -0
- package/package.json +59 -4
- package/profiles.json +165 -0
- package/rules/common.md +21 -0
- package/rules/cpp.md +29 -0
- package/rules/csharp.md +25 -0
- package/rules/dart.md +29 -0
- package/rules/fsharp.md +28 -0
- package/rules/git.md +26 -0
- package/rules/go.md +29 -0
- package/rules/java.md +29 -0
- package/rules/kotlin.md +27 -0
- package/rules/perl.md +26 -0
- package/rules/php.md +28 -0
- package/rules/python.md +30 -0
- package/rules/ruby.md +27 -0
- package/rules/rust.md +26 -0
- package/rules/security.md +29 -0
- package/rules/swift.md +28 -0
- package/rules/testing.md +25 -0
- package/rules/typescript.md +29 -0
- package/schemas/skill-frontmatter.schema.json +52 -0
- package/scripts/lib/audit.js +96 -0
- package/scripts/lib/frontmatter.js +65 -0
- package/scripts/lib/hooks-install.js +292 -0
- package/scripts/lib/i18n.js +51 -0
- package/scripts/lib/inventory.js +85 -0
- package/scripts/lib/lint.js +158 -0
- package/scripts/lib/mcp-install.js +284 -0
- package/scripts/lib/profiles.js +128 -0
- package/scripts/lib/render.js +86 -0
- package/scripts/lib/rules-install.js +118 -0
- package/scripts/lib/skills.js +86 -0
- package/scripts/lib/targets.js +113 -0
- package/skills/accounting-api-integration/SKILL.md +81 -0
- package/skills/accounting-api-integration/evals/triggers.json +17 -0
- package/skills/accounting-api-integration/references/quickbooks.md +48 -0
- package/skills/accounting-api-integration/references/xero.md +45 -0
- package/skills/agent-harness-design/SKILL.md +125 -0
- package/skills/agent-harness-design/evals/triggers.json +21 -0
- package/skills/ai-media-generation/SKILL.md +89 -0
- package/skills/ai-media-generation/evals/triggers.json +16 -0
- package/skills/ai-media-generation/references/job-pipeline.md +76 -0
- package/skills/angular-patterns/SKILL.md +122 -0
- package/skills/angular-patterns/evals/triggers.json +16 -0
- package/skills/api-design/SKILL.md +96 -0
- package/skills/api-design/evals/triggers.json +18 -0
- package/skills/api-design/references/conventions.md +133 -0
- package/skills/architecture-decision-records/SKILL.md +98 -0
- package/skills/architecture-decision-records/evals/triggers.json +17 -0
- package/skills/article-writing/SKILL.md +108 -0
- package/skills/article-writing/evals/triggers.json +16 -0
- package/skills/aspnet-core-patterns/SKILL.md +149 -0
- package/skills/aspnet-core-patterns/evals/triggers.json +16 -0
- package/skills/auth-patterns/SKILL.md +104 -0
- package/skills/auth-patterns/evals/triggers.json +17 -0
- package/skills/auth-patterns/references/oauth-oidc.md +64 -0
- package/skills/autonomous-loops/SKILL.md +99 -0
- package/skills/autonomous-loops/evals/triggers.json +14 -0
- package/skills/aws-patterns/SKILL.md +91 -0
- package/skills/aws-patterns/evals/triggers.json +16 -0
- package/skills/azure-patterns/SKILL.md +86 -0
- package/skills/azure-patterns/evals/triggers.json +16 -0
- package/skills/benchmark-methodology/SKILL.md +88 -0
- package/skills/benchmark-methodology/evals/triggers.json +16 -0
- package/skills/benchmark-methodology/references/language-harnesses.md +130 -0
- package/skills/bgp-diagnostics/SKILL.md +84 -0
- package/skills/bgp-diagnostics/evals/triggers.json +18 -0
- package/skills/bgp-diagnostics/references/bgp-reference.md +81 -0
- package/skills/bioinformatics-workflows/SKILL.md +108 -0
- package/skills/bioinformatics-workflows/evals/triggers.json +16 -0
- package/skills/bioinformatics-workflows/references/commands.md +71 -0
- package/skills/bioinformatics-workflows/references/formats.md +24 -0
- package/skills/bioinformatics-workflows/references/workflow-managers.md +107 -0
- package/skills/brand-voice/SKILL.md +112 -0
- package/skills/brand-voice/evals/triggers.json +16 -0
- package/skills/browser-qa/SKILL.md +99 -0
- package/skills/browser-qa/evals/triggers.json +16 -0
- package/skills/bun-runtime/SKILL.md +93 -0
- package/skills/bun-runtime/evals/triggers.json +16 -0
- package/skills/cisco-ios-config/SKILL.md +101 -0
- package/skills/cisco-ios-config/evals/triggers.json +18 -0
- package/skills/cisco-ios-config/references/verification.md +63 -0
- package/skills/clickhouse-patterns/SKILL.md +101 -0
- package/skills/clickhouse-patterns/evals/triggers.json +18 -0
- package/skills/clickhouse-patterns/references/engines-and-views.md +138 -0
- package/skills/clinical-decision-support/SKILL.md +90 -0
- package/skills/clinical-decision-support/evals/triggers.json +16 -0
- package/skills/clinical-decision-support/references/cds-hooks.md +76 -0
- package/skills/clinical-decision-support/references/regulatory-boundaries.md +37 -0
- package/skills/code-tour/SKILL.md +97 -0
- package/skills/code-tour/evals/triggers.json +14 -0
- package/skills/codebase-onboarding/SKILL.md +112 -0
- package/skills/codebase-onboarding/evals/triggers.json +14 -0
- package/skills/cold-outreach-sequences/SKILL.md +90 -0
- package/skills/cold-outreach-sequences/evals/triggers.json +16 -0
- package/skills/content-repurposing/SKILL.md +82 -0
- package/skills/content-repurposing/evals/triggers.json +16 -0
- package/skills/context-budget/SKILL.md +84 -0
- package/skills/context-budget/evals/triggers.json +14 -0
- package/skills/conventional-commits/SKILL.md +144 -0
- package/skills/conventional-commits/evals/triggers.json +16 -0
- package/skills/cpp-patterns/SKILL.md +129 -0
- package/skills/cpp-patterns/evals/triggers.json +16 -0
- package/skills/cpp-patterns/references/cmake-and-tooling.md +88 -0
- package/skills/cpp-patterns/references/undefined-behaviour.md +75 -0
- package/skills/cpp-testing/SKILL.md +131 -0
- package/skills/cpp-testing/evals/triggers.json +16 -0
- package/skills/csharp-patterns/SKILL.md +110 -0
- package/skills/csharp-patterns/evals/triggers.json +17 -0
- package/skills/csharp-patterns/references/analyzers.md +59 -0
- package/skills/csharp-testing/SKILL.md +85 -0
- package/skills/csharp-testing/evals/triggers.json +17 -0
- package/skills/csharp-testing/references/integration-tests.md +77 -0
- package/skills/css-architecture/SKILL.md +143 -0
- package/skills/css-architecture/evals/triggers.json +16 -0
- package/skills/customs-trade-compliance/SKILL.md +95 -0
- package/skills/customs-trade-compliance/evals/triggers.json +16 -0
- package/skills/customs-trade-compliance/references/incoterms-2020.md +42 -0
- package/skills/dart-patterns/SKILL.md +157 -0
- package/skills/dart-patterns/evals/triggers.json +18 -0
- package/skills/dart-testing/SKILL.md +164 -0
- package/skills/dart-testing/evals/triggers.json +18 -0
- package/skills/data-analysis-notebooks/SKILL.md +113 -0
- package/skills/data-analysis-notebooks/evals/triggers.json +16 -0
- package/skills/data-analysis-notebooks/references/dataframe-pitfalls.md +49 -0
- package/skills/data-analysis-notebooks/references/statistics-pitfalls.md +24 -0
- package/skills/data-pipelines/SKILL.md +90 -0
- package/skills/data-pipelines/evals/triggers.json +16 -0
- package/skills/data-pipelines/references/orchestrators.md +64 -0
- package/skills/database-migrations/SKILL.md +102 -0
- package/skills/database-migrations/evals/triggers.json +16 -0
- package/skills/database-migrations/references/recipes.md +98 -0
- package/skills/database-migrations/references/tools.md +21 -0
- package/skills/dbt-patterns/SKILL.md +96 -0
- package/skills/dbt-patterns/evals/triggers.json +16 -0
- package/skills/dbt-patterns/references/yaml-examples.md +114 -0
- package/skills/deep-research/SKILL.md +107 -0
- package/skills/deep-research/evals/triggers.json +14 -0
- package/skills/dependency-audit/SKILL.md +103 -0
- package/skills/dependency-audit/evals/triggers.json +16 -0
- package/skills/dependency-audit/references/tools.md +124 -0
- package/skills/deployment-strategies/SKILL.md +108 -0
- package/skills/deployment-strategies/evals/triggers.json +16 -0
- package/skills/django-patterns/SKILL.md +123 -0
- package/skills/django-patterns/evals/triggers.json +16 -0
- package/skills/docker-patterns/SKILL.md +132 -0
- package/skills/docker-patterns/evals/triggers.json +16 -0
- package/skills/docker-patterns/references/dockerfiles.md +105 -0
- package/skills/e2e-testing-playwright/SKILL.md +94 -0
- package/skills/e2e-testing-playwright/evals/triggers.json +16 -0
- package/skills/e2e-testing-playwright/references/config-and-ci.md +129 -0
- package/skills/ef-core-patterns/SKILL.md +117 -0
- package/skills/ef-core-patterns/evals/triggers.json +16 -0
- package/skills/email-deliverability/SKILL.md +99 -0
- package/skills/email-deliverability/evals/triggers.json +17 -0
- package/skills/email-deliverability/references/dns-records.md +85 -0
- package/skills/error-handling-patterns/SKILL.md +112 -0
- package/skills/error-handling-patterns/evals/triggers.json +18 -0
- package/skills/error-handling-patterns/references/language-idioms.md +49 -0
- package/skills/estimation-and-scoping/SKILL.md +97 -0
- package/skills/estimation-and-scoping/evals/triggers.json +14 -0
- package/skills/evm-dapp-integration/SKILL.md +73 -0
- package/skills/evm-dapp-integration/evals/triggers.json +16 -0
- package/skills/fastapi-patterns/SKILL.md +127 -0
- package/skills/fastapi-patterns/evals/triggers.json +16 -0
- package/skills/ffmpeg-media-processing/SKILL.md +94 -0
- package/skills/ffmpeg-media-processing/evals/triggers.json +16 -0
- package/skills/ffmpeg-media-processing/references/recipes.md +112 -0
- package/skills/fhir-integration/SKILL.md +81 -0
- package/skills/fhir-integration/evals/triggers.json +16 -0
- package/skills/fhir-integration/references/search-and-bundles.md +73 -0
- package/skills/fhir-integration/references/smart-on-fhir.md +50 -0
- package/skills/flask-patterns/SKILL.md +132 -0
- package/skills/flask-patterns/evals/triggers.json +16 -0
- package/skills/flutter-patterns/SKILL.md +99 -0
- package/skills/flutter-patterns/evals/triggers.json +16 -0
- package/skills/flutterwave-integration/SKILL.md +75 -0
- package/skills/flutterwave-integration/evals/triggers.json +16 -0
- package/skills/flutterwave-integration/references/api.md +73 -0
- package/skills/flutterwave-integration/references/webhooks.md +49 -0
- package/skills/fsharp-patterns/SKILL.md +133 -0
- package/skills/fsharp-patterns/evals/triggers.json +16 -0
- package/skills/fsharp-testing/SKILL.md +136 -0
- package/skills/fsharp-testing/evals/triggers.json +16 -0
- package/skills/gcp-patterns/SKILL.md +86 -0
- package/skills/gcp-patterns/evals/triggers.json +16 -0
- package/skills/git-workflow/SKILL.md +114 -0
- package/skills/git-workflow/evals/triggers.json +16 -0
- package/skills/github-actions-ci/SKILL.md +117 -0
- package/skills/github-actions-ci/evals/triggers.json +16 -0
- package/skills/github-api-automation/SKILL.md +101 -0
- package/skills/github-api-automation/evals/triggers.json +17 -0
- package/skills/go-patterns/SKILL.md +118 -0
- package/skills/go-patterns/evals/triggers.json +17 -0
- package/skills/go-patterns/references/concurrency.md +162 -0
- package/skills/go-testing/SKILL.md +154 -0
- package/skills/go-testing/evals/triggers.json +17 -0
- package/skills/hexagonal-architecture/SKILL.md +89 -0
- package/skills/hexagonal-architecture/evals/triggers.json +17 -0
- package/skills/hipaa-compliance/SKILL.md +91 -0
- package/skills/hipaa-compliance/evals/triggers.json +18 -0
- package/skills/hipaa-compliance/references/safeguards.md +68 -0
- package/skills/hl7v2-integration/SKILL.md +69 -0
- package/skills/hl7v2-integration/evals/triggers.json +16 -0
- package/skills/hl7v2-integration/references/messages-and-ack.md +78 -0
- package/skills/homelab-network-setup/SKILL.md +125 -0
- package/skills/homelab-network-setup/evals/triggers.json +18 -0
- package/skills/homelab-network-setup/references/firewall-and-dns.md +45 -0
- package/skills/homelab-network-setup/references/wireguard.md +72 -0
- package/skills/hubtel-integration/SKILL.md +77 -0
- package/skills/hubtel-integration/evals/triggers.json +16 -0
- package/skills/hubtel-integration/references/api.md +92 -0
- package/skills/i18n-localization/SKILL.md +114 -0
- package/skills/i18n-localization/evals/triggers.json +16 -0
- package/skills/i18n-localization/references/libraries.md +52 -0
- package/skills/incident-postmortem/SKILL.md +118 -0
- package/skills/incident-postmortem/evals/triggers.json +14 -0
- package/skills/inventory-demand-planning/SKILL.md +89 -0
- package/skills/inventory-demand-planning/evals/triggers.json +16 -0
- package/skills/inventory-demand-planning/references/formulas.md +62 -0
- package/skills/investor-materials/SKILL.md +127 -0
- package/skills/investor-materials/evals/triggers.json +16 -0
- package/skills/investor-materials/references/templates.md +74 -0
- package/skills/invoicing-and-tax/SKILL.md +84 -0
- package/skills/invoicing-and-tax/evals/triggers.json +17 -0
- package/skills/invoicing-and-tax/references/e-invoicing.md +24 -0
- package/skills/invoicing-and-tax/references/invoice-fields.md +38 -0
- package/skills/invoicing-and-tax/references/rounding.md +26 -0
- package/skills/java-patterns/SKILL.md +141 -0
- package/skills/java-patterns/evals/triggers.json +17 -0
- package/skills/java-testing/SKILL.md +142 -0
- package/skills/java-testing/evals/triggers.json +16 -0
- package/skills/jetpack-compose-patterns/SKILL.md +88 -0
- package/skills/jetpack-compose-patterns/evals/triggers.json +16 -0
- package/skills/jira-integration/SKILL.md +92 -0
- package/skills/jira-integration/evals/triggers.json +17 -0
- package/skills/jpa-hibernate/SKILL.md +92 -0
- package/skills/jpa-hibernate/evals/triggers.json +18 -0
- package/skills/jpa-hibernate/references/mapping.md +99 -0
- package/skills/kotlin-multiplatform/SKILL.md +97 -0
- package/skills/kotlin-multiplatform/evals/triggers.json +16 -0
- package/skills/kotlin-patterns/SKILL.md +128 -0
- package/skills/kotlin-patterns/evals/triggers.json +16 -0
- package/skills/kotlin-testing/SKILL.md +117 -0
- package/skills/kotlin-testing/evals/triggers.json +16 -0
- package/skills/ktor-patterns/SKILL.md +135 -0
- package/skills/ktor-patterns/evals/triggers.json +18 -0
- package/skills/kubernetes-patterns/SKILL.md +106 -0
- package/skills/kubernetes-patterns/evals/triggers.json +16 -0
- package/skills/kubernetes-patterns/references/manifests.md +115 -0
- package/skills/laravel-patterns/SKILL.md +136 -0
- package/skills/laravel-patterns/evals/triggers.json +16 -0
- package/skills/linear-integration/SKILL.md +98 -0
- package/skills/linear-integration/evals/triggers.json +17 -0
- package/skills/literature-review/SKILL.md +109 -0
- package/skills/literature-review/evals/triggers.json +16 -0
- package/skills/literature-review/references/appraisal.md +41 -0
- package/skills/literature-review/references/search-sources.md +39 -0
- package/skills/llm-app-patterns/SKILL.md +97 -0
- package/skills/llm-app-patterns/evals/triggers.json +17 -0
- package/skills/llm-evals/SKILL.md +98 -0
- package/skills/llm-evals/evals/triggers.json +16 -0
- package/skills/llm-evals/references/graders.md +66 -0
- package/skills/logistics-exception-management/SKILL.md +90 -0
- package/skills/logistics-exception-management/evals/triggers.json +16 -0
- package/skills/manim-animations/SKILL.md +106 -0
- package/skills/manim-animations/evals/triggers.json +16 -0
- package/skills/market-research/SKILL.md +117 -0
- package/skills/market-research/evals/triggers.json +16 -0
- package/skills/marketing-campaign/SKILL.md +111 -0
- package/skills/marketing-campaign/evals/triggers.json +16 -0
- package/skills/mcp-server-patterns/SKILL.md +127 -0
- package/skills/mcp-server-patterns/evals/triggers.json +18 -0
- package/skills/mcp-server-patterns/references/protocol-notes.md +68 -0
- package/skills/metrics-dashboards/SKILL.md +113 -0
- package/skills/metrics-dashboards/evals/triggers.json +16 -0
- package/skills/ml-experiment-workflow/SKILL.md +125 -0
- package/skills/ml-experiment-workflow/evals/triggers.json +16 -0
- package/skills/mongodb-patterns/SKILL.md +115 -0
- package/skills/mongodb-patterns/evals/triggers.json +18 -0
- package/skills/mongodb-patterns/references/indexes-and-aggregation.md +94 -0
- package/skills/mpesa-daraja-integration/SKILL.md +70 -0
- package/skills/mpesa-daraja-integration/evals/triggers.json +16 -0
- package/skills/mpesa-daraja-integration/references/api.md +103 -0
- package/skills/mpesa-daraja-integration/references/callbacks.md +74 -0
- package/skills/mtn-momo-integration/SKILL.md +66 -0
- package/skills/mtn-momo-integration/evals/triggers.json +16 -0
- package/skills/mtn-momo-integration/references/api.md +153 -0
- package/skills/mtn-momo-integration/references/callbacks.md +92 -0
- package/skills/mtn-momo-integration/references/sandbox-and-go-live.md +51 -0
- package/skills/mtn-momo-integration/scripts/sandbox-setup.js +79 -0
- package/skills/mysql-patterns/SKILL.md +96 -0
- package/skills/mysql-patterns/evals/triggers.json +16 -0
- package/skills/mysql-patterns/references/explain.md +34 -0
- package/skills/mysql-patterns/references/online-ddl.md +41 -0
- package/skills/nestjs-patterns/SKILL.md +114 -0
- package/skills/nestjs-patterns/evals/triggers.json +16 -0
- package/skills/nestjs-patterns/references/testing.md +68 -0
- package/skills/network-automation/SKILL.md +107 -0
- package/skills/network-automation/evals/triggers.json +18 -0
- package/skills/network-automation/references/tool-snippets.md +153 -0
- package/skills/network-troubleshooting/SKILL.md +152 -0
- package/skills/network-troubleshooting/evals/triggers.json +18 -0
- package/skills/network-troubleshooting/references/commands.md +33 -0
- package/skills/nextjs-patterns/SKILL.md +150 -0
- package/skills/nextjs-patterns/evals/triggers.json +18 -0
- package/skills/nextjs-patterns/references/caching.md +87 -0
- package/skills/node-backend-patterns/SKILL.md +103 -0
- package/skills/node-backend-patterns/evals/triggers.json +16 -0
- package/skills/node-backend-patterns/references/templates.md +122 -0
- package/skills/nuxt-patterns/SKILL.md +103 -0
- package/skills/nuxt-patterns/evals/triggers.json +16 -0
- package/skills/parallel-agent-orchestration/SKILL.md +106 -0
- package/skills/parallel-agent-orchestration/evals/triggers.json +14 -0
- package/skills/paystack-integration/SKILL.md +59 -0
- package/skills/paystack-integration/evals/triggers.json +14 -0
- package/skills/paystack-integration/references/api.md +73 -0
- package/skills/paystack-integration/references/mobile-money.md +50 -0
- package/skills/paystack-integration/references/webhooks.md +80 -0
- package/skills/pci-dss-scope/SKILL.md +103 -0
- package/skills/pci-dss-scope/evals/triggers.json +18 -0
- package/skills/pci-dss-scope/references/saq-and-data.md +36 -0
- package/skills/perl-patterns/SKILL.md +135 -0
- package/skills/perl-patterns/evals/triggers.json +18 -0
- package/skills/perl-testing/SKILL.md +126 -0
- package/skills/perl-testing/evals/triggers.json +17 -0
- package/skills/php-patterns/SKILL.md +116 -0
- package/skills/php-patterns/evals/triggers.json +16 -0
- package/skills/php-testing/SKILL.md +123 -0
- package/skills/php-testing/evals/triggers.json +16 -0
- package/skills/postgres-patterns/SKILL.md +103 -0
- package/skills/postgres-patterns/evals/triggers.json +17 -0
- package/skills/postgres-patterns/references/explain.md +59 -0
- package/skills/postgres-patterns/references/locks.md +53 -0
- package/skills/prd-writing/SKILL.md +124 -0
- package/skills/prd-writing/evals/triggers.json +15 -0
- package/skills/prisma-patterns/SKILL.md +83 -0
- package/skills/prisma-patterns/evals/triggers.json +18 -0
- package/skills/prisma-patterns/references/prisma-8.md +46 -0
- package/skills/prisma-patterns/references/workflow.md +50 -0
- package/skills/privacy-compliance/SKILL.md +121 -0
- package/skills/privacy-compliance/evals/triggers.json +18 -0
- package/skills/privacy-compliance/references/jurisdictions.md +51 -0
- package/skills/production-scheduling/SKILL.md +98 -0
- package/skills/production-scheduling/evals/triggers.json +16 -0
- package/skills/prompt-engineering/SKILL.md +92 -0
- package/skills/prompt-engineering/evals/triggers.json +16 -0
- package/skills/python-patterns/SKILL.md +107 -0
- package/skills/python-patterns/evals/triggers.json +16 -0
- package/skills/python-patterns/references/tooling.md +101 -0
- package/skills/python-testing/SKILL.md +126 -0
- package/skills/python-testing/evals/triggers.json +16 -0
- package/skills/python-testing/references/mocking.md +71 -0
- package/skills/pytorch-patterns/SKILL.md +139 -0
- package/skills/pytorch-patterns/evals/triggers.json +16 -0
- package/skills/pytorch-patterns/references/debugging.md +39 -0
- package/skills/quarkus-patterns/SKILL.md +93 -0
- package/skills/quarkus-patterns/evals/triggers.json +18 -0
- package/skills/rag-pipeline-patterns/SKILL.md +117 -0
- package/skills/rag-pipeline-patterns/evals/triggers.json +18 -0
- package/skills/rag-pipeline-patterns/references/evaluation.md +37 -0
- package/skills/rag-pipeline-patterns/references/retrieval-recipes.md +78 -0
- package/skills/rails-patterns/SKILL.md +132 -0
- package/skills/rails-patterns/evals/triggers.json +16 -0
- package/skills/react-native-patterns/SKILL.md +101 -0
- package/skills/react-native-patterns/evals/triggers.json +16 -0
- package/skills/react-patterns/SKILL.md +140 -0
- package/skills/react-patterns/evals/triggers.json +18 -0
- package/skills/react-performance/SKILL.md +107 -0
- package/skills/react-performance/evals/triggers.json +18 -0
- package/skills/redis-patterns/SKILL.md +109 -0
- package/skills/redis-patterns/evals/triggers.json +18 -0
- package/skills/redis-patterns/references/operations.md +61 -0
- package/skills/refactoring-safely/SKILL.md +107 -0
- package/skills/refactoring-safely/evals/triggers.json +17 -0
- package/skills/release-management/SKILL.md +141 -0
- package/skills/release-management/evals/triggers.json +16 -0
- package/skills/remotion-video/SKILL.md +91 -0
- package/skills/remotion-video/evals/triggers.json +16 -0
- package/skills/remotion-video/references/lambda.md +66 -0
- package/skills/returns-reverse-logistics/SKILL.md +97 -0
- package/skills/returns-reverse-logistics/evals/triggers.json +16 -0
- package/skills/ruby-patterns/SKILL.md +127 -0
- package/skills/ruby-patterns/evals/triggers.json +18 -0
- package/skills/ruby-testing/SKILL.md +113 -0
- package/skills/ruby-testing/evals/triggers.json +18 -0
- package/skills/runbook-writing/SKILL.md +101 -0
- package/skills/runbook-writing/evals/triggers.json +14 -0
- package/skills/rust-patterns/SKILL.md +118 -0
- package/skills/rust-patterns/evals/triggers.json +16 -0
- package/skills/rust-patterns/references/cargo-and-clippy.md +105 -0
- package/skills/rust-patterns/references/errors-and-traits.md +97 -0
- package/skills/rust-testing/SKILL.md +148 -0
- package/skills/rust-testing/evals/triggers.json +16 -0
- package/skills/rust-testing/references/fakes-proptest-async.md +113 -0
- package/skills/search-first/SKILL.md +73 -0
- package/skills/search-first/evals/triggers.json +14 -0
- package/skills/security-review/SKILL.md +58 -0
- package/skills/security-review/evals/triggers.json +14 -0
- package/skills/security-review/references/checklist.md +54 -0
- package/skills/security-review/scripts/scan-secrets.js +79 -0
- package/skills/seo-audit/SKILL.md +111 -0
- package/skills/seo-audit/evals/triggers.json +16 -0
- package/skills/seo-audit/references/checks.md +65 -0
- package/skills/session-handoff/SKILL.md +101 -0
- package/skills/session-handoff/evals/triggers.json +14 -0
- package/skills/skill-authoring/SKILL.md +87 -0
- package/skills/skill-authoring/evals/triggers.json +14 -0
- package/skills/skill-authoring/references/frontmatter.md +40 -0
- package/skills/slack-app-integration/SKILL.md +108 -0
- package/skills/slack-app-integration/evals/triggers.json +17 -0
- package/skills/smart-contract-security/SKILL.md +110 -0
- package/skills/smart-contract-security/evals/triggers.json +16 -0
- package/skills/smart-contract-security/references/vulnerability-checklist.md +79 -0
- package/skills/social-media-publishing/SKILL.md +84 -0
- package/skills/social-media-publishing/evals/triggers.json +17 -0
- package/skills/social-media-publishing/references/platform-apis.md +116 -0
- package/skills/solidity-patterns/SKILL.md +95 -0
- package/skills/solidity-patterns/evals/triggers.json +16 -0
- package/skills/spring-boot-patterns/SKILL.md +128 -0
- package/skills/spring-boot-patterns/evals/triggers.json +18 -0
- package/skills/spring-boot-patterns/references/testing.md +72 -0
- package/skills/stripe-integration/SKILL.md +69 -0
- package/skills/stripe-integration/evals/triggers.json +16 -0
- package/skills/stripe-integration/references/api.md +71 -0
- package/skills/stripe-integration/references/billing.md +58 -0
- package/skills/stripe-integration/references/webhooks.md +76 -0
- package/skills/subscription-billing-ops/SKILL.md +118 -0
- package/skills/subscription-billing-ops/evals/triggers.json +17 -0
- package/skills/subscription-billing-ops/references/proration.md +47 -0
- package/skills/subscription-billing-ops/references/revenue-metrics.md +38 -0
- package/skills/svelte-patterns/SKILL.md +122 -0
- package/skills/svelte-patterns/evals/triggers.json +16 -0
- package/skills/swift-patterns/SKILL.md +113 -0
- package/skills/swift-patterns/evals/triggers.json +16 -0
- package/skills/swift-patterns/references/concurrency-migration.md +40 -0
- package/skills/swift-testing/SKILL.md +121 -0
- package/skills/swift-testing/evals/triggers.json +16 -0
- package/skills/swift-testing/references/swift-testing-cheatsheet.md +81 -0
- package/skills/swiftui-patterns/SKILL.md +102 -0
- package/skills/swiftui-patterns/evals/triggers.json +16 -0
- package/skills/tdd-workflow/SKILL.md +67 -0
- package/skills/tdd-workflow/evals/triggers.json +14 -0
- package/skills/technical-writing/SKILL.md +95 -0
- package/skills/technical-writing/evals/triggers.json +14 -0
- package/skills/terraform-patterns/SKILL.md +122 -0
- package/skills/terraform-patterns/evals/triggers.json +16 -0
- package/skills/terraform-patterns/references/backends.md +67 -0
- package/skills/test-coverage-improvement/SKILL.md +107 -0
- package/skills/test-coverage-improvement/evals/triggers.json +16 -0
- package/skills/threat-modeling/SKILL.md +113 -0
- package/skills/threat-modeling/evals/triggers.json +16 -0
- package/skills/typescript-patterns/SKILL.md +122 -0
- package/skills/typescript-patterns/evals/triggers.json +16 -0
- package/skills/typescript-testing/SKILL.md +101 -0
- package/skills/typescript-testing/evals/triggers.json +16 -0
- package/skills/verification-loop/SKILL.md +70 -0
- package/skills/verification-loop/evals/triggers.json +14 -0
- package/skills/verification-loop/scripts/detect-checks.js +102 -0
- package/skills/vite-patterns/SKILL.md +117 -0
- package/skills/vite-patterns/evals/triggers.json +16 -0
- package/skills/vue-patterns/SKILL.md +104 -0
- package/skills/vue-patterns/evals/triggers.json +16 -0
- package/skills/web-accessibility/SKILL.md +119 -0
- package/skills/web-accessibility/evals/triggers.json +16 -0
- package/skills/web-performance/SKILL.md +107 -0
- package/skills/web-performance/evals/triggers.json +16 -0
- package/skills/web-scraping/SKILL.md +80 -0
- package/skills/web-scraping/evals/triggers.json +16 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ai-media-generation
|
|
3
|
+
description: Product features built on hosted generative image, video, speech and music models, including prompt templates with fixed parameters and seeds, long-running jobs submitted then polled or confirmed by signed webhooks, per-user quotas and cost estimates before submission, input and output moderation, C2PA content credentials and AI-generated labels, and copying results to your own storage before provider URLs expire. Use when adding text-to-image, image editing, text-to-video or text-to-speech generation to an app, wiring up a generation provider's async job API, or controlling the cost, safety and storage of generated media.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Any Agent Skills host. Live calls need network access and an API key for the chosen provider. Examples are provider-neutral; check the provider's current API reference for model names and parameters.
|
|
6
|
+
metadata:
|
|
7
|
+
kete-loom/version: "0.1.0"
|
|
8
|
+
kete-loom/category: ai
|
|
9
|
+
kete-loom/risk: network
|
|
10
|
+
kete-loom/owner: "Kete-org"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# AI media generation
|
|
14
|
+
|
|
15
|
+
Generation APIs are slow, priced per output, change model names often, and can produce content you are responsible for. Build the feature as a job pipeline with limits, moderation and your own storage, not as a single request in a page handler.
|
|
16
|
+
|
|
17
|
+
## 0. Before you start
|
|
18
|
+
|
|
19
|
+
1. Ask the user, or find in the repo: which provider and model, which media (image, edit, video, speech, music), expected volume, and who the end users are (internal staff, logged-in customers, anonymous public).
|
|
20
|
+
2. Read the provider's current API reference and pricing page for that model. Model IDs, sizes, durations and prices change; never copy them from memory or old code. Note: max resolution/duration, whether the call is synchronous or a job, output format (base64 in the response vs a URL), how long output URLs live, rate limits, and whether the provider adds C2PA or a watermark.
|
|
21
|
+
3. **Stop and ask** before building a public, anonymous generation endpoint, any feature that edits images of real people, voice cloning, or anything aimed at children. These need explicit policy decisions.
|
|
22
|
+
|
|
23
|
+
## 1. Prompt and parameter design
|
|
24
|
+
|
|
25
|
+
- Keep a server-side **prompt template** per feature: fixed style instructions plus the user's text in a clearly delimited slot. Users choose from options (style, aspect ratio, length) that map to allowed parameter values; never pass raw user JSON as provider parameters.
|
|
26
|
+
- Pin the **model ID and version** in config, not scattered in code, so an upgrade is a reviewed change. Record it with every output.
|
|
27
|
+
- Store the **full request** (template version, final prompt, parameters, seed if supported) with each job, so results can be reproduced and audited.
|
|
28
|
+
- Validate inputs at the boundary: prompt length, uploaded image type/size/dimensions, audio length. Strip metadata (EXIF GPS) from user uploads before sending them.
|
|
29
|
+
- For edits with masks or reference images, check the provider's format rules (same size, alpha channel, size limit) before submitting, not after a failed job.
|
|
30
|
+
|
|
31
|
+
## 2. Job flow
|
|
32
|
+
|
|
33
|
+
Treat every generation as a job, even if the provider responds synchronously today.
|
|
34
|
+
|
|
35
|
+
1. `POST /generations` in your API: authenticate, check quota (section 3), moderate the input (section 4), insert a `generation_jobs` row (`id`, `user_id`, `status=queued`, `provider`, `model`, `request`, `estimated_cost`), and return `202` with the job ID.
|
|
36
|
+
2. A worker submits to the provider with an idempotency key if the API supports one (otherwise store the provider job ID immediately so a retry doesn't submit twice). Save `provider_job_id`, set `status=running`.
|
|
37
|
+
3. Learn the result by **webhook** when offered: verify the signature on the raw body with the provider's secret and timestamp tolerance, look up the job by provider ID, and treat duplicate or out-of-order deliveries as normal. Back it with a **poll** fallback: exponential backoff (for example 2 s doubling to 30 s), a hard deadline per media type, then mark `timed_out` and cancel at the provider if it supports cancel.
|
|
38
|
+
4. On success: download the output, check type and size, run output moderation, add provenance (section 5), store it (section 6), set `status=succeeded`, record actual cost.
|
|
39
|
+
5. On failure: map provider errors to `failed_safety` (prompt or output refused), `failed_invalid` (bad parameters), `failed_provider` (5xx, timeouts). Retry only `failed_provider`, a bounded number of times. Never retry a safety refusal by rewording the prompt automatically.
|
|
40
|
+
6. The client polls `GET /generations/:id` or subscribes to updates; it never talks to the provider or sees the provider key.
|
|
41
|
+
|
|
42
|
+
See `references/job-pipeline.md` for a table schema, a poll loop and a webhook handler outline.
|
|
43
|
+
|
|
44
|
+
## 3. Cost and latency
|
|
45
|
+
|
|
46
|
+
- Estimate cost **before** submitting (resolution x count, seconds of video, characters of speech, using the provider's price table) and check it against a per-user and a global daily budget. Reject or queue when over.
|
|
47
|
+
- Cap `n` (outputs per request), resolution and duration server-side. Default to the cheapest setting that meets the feature's need; offer "high quality" as an explicit, metered choice.
|
|
48
|
+
- Rate-limit per user and per IP; generation endpoints attract abuse.
|
|
49
|
+
- Cache identical requests (same template, prompt, parameters and seed) when outputs are deterministic enough for the feature.
|
|
50
|
+
- Show realistic progress: images take seconds, video can take minutes. Never hold an HTTP request open for a video job.
|
|
51
|
+
- Log latency and cost per job and alert on spend spikes.
|
|
52
|
+
|
|
53
|
+
## 4. Content safety
|
|
54
|
+
|
|
55
|
+
- Moderate the **input** (prompt text, uploaded images) before paying for a generation, and the **output** before showing it, with the provider's moderation API or your own classifier. Provider-side filters are a floor, not your whole policy.
|
|
56
|
+
- Write down the policy with the user: disallowed content, real-person likeness, logos and trademarks, minors. Block and log; let users report outputs.
|
|
57
|
+
- Keep a reviewable record (prompt, output reference, moderation result, user) for abuse investigations, with a retention period the user agrees to.
|
|
58
|
+
- Don't present generated people, voices or events as real. For voice, require consent records for any cloned voice.
|
|
59
|
+
|
|
60
|
+
## 5. Provenance and labelling
|
|
61
|
+
|
|
62
|
+
- Keep any **C2PA content credentials** or watermark the provider embeds; re-encoding, resizing or stripping metadata can remove the C2PA manifest. If you transform outputs, re-sign with your own C2PA manifest (for example with the open-source `c2patool` or a C2PA SDK) or keep the original alongside.
|
|
63
|
+
- Label generated media as AI-generated in the UI and in alt text or metadata where the media is published.
|
|
64
|
+
- Transparency rules such as Article 50 of the EU AI Act, and platform rules, can require machine-readable marking and visible disclosure. **Ask the user's legal or compliance owner** which apply; this skill does not give legal advice.
|
|
65
|
+
|
|
66
|
+
## 6. Storing outputs
|
|
67
|
+
|
|
68
|
+
- Provider output URLs are often temporary (some expire within an hour). Copy every output to your own object storage as soon as the job succeeds; never store the provider URL as the permanent link.
|
|
69
|
+
- Write with a generated key (`generations/<job_id>/<n>.<ext>`), the right `Content-Type`, private by default, served through signed URLs or a CDN with access checks.
|
|
70
|
+
- Keep metadata in your database: job ID, user, model and version, prompt, parameters, seed, cost, moderation result, checksum, dimensions/duration.
|
|
71
|
+
- Set lifecycle rules for drafts and failed jobs, and delete outputs when the user deletes their account.
|
|
72
|
+
- Post-process with the right tool: resize/convert images with the project's image library; trim, transcode or package video and audio with the ffmpeg-media-processing skill.
|
|
73
|
+
|
|
74
|
+
## Never
|
|
75
|
+
|
|
76
|
+
- Never call a generation API from the browser or mobile app with your provider key.
|
|
77
|
+
- Never submit without a quota and cost check, or let a client choose unbounded `n`, resolution or duration.
|
|
78
|
+
- Never show an output that skipped output moderation, or auto-retry a safety refusal.
|
|
79
|
+
- Never rely on provider URLs for storage.
|
|
80
|
+
|
|
81
|
+
## Stop and ask the user
|
|
82
|
+
|
|
83
|
+
- Provider and model choice when not given, and the monthly budget.
|
|
84
|
+
- Content policy, likeness and voice-cloning rules, and labelling obligations.
|
|
85
|
+
- Data handling: whether prompts and uploads may be used by the provider for training (check the provider's data terms), and retention periods.
|
|
86
|
+
|
|
87
|
+
## Report back
|
|
88
|
+
|
|
89
|
+
Provider and pinned model, the job states and where each transition happens, cost limits set, moderation points, provenance handling, storage location and retention, and anything taken from docs you could not confirm.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"should_trigger": [
|
|
3
|
+
"Add a feature where users type a prompt and get four product mockup images from an image generation API",
|
|
4
|
+
"Our text-to-video jobs take minutes, how should we poll the provider and notify the user when it's done?",
|
|
5
|
+
"Generated images disappear after an hour because we saved the Replicate output URL",
|
|
6
|
+
"Put per-user limits on AI image generation so one customer can't run up a huge bill",
|
|
7
|
+
"Label AI-generated images and keep their C2PA content credentials when we resize them"
|
|
8
|
+
],
|
|
9
|
+
"should_not_trigger": [
|
|
10
|
+
"Add structured JSON output and retries to our chatbot's LLM calls",
|
|
11
|
+
"Rewrite this system prompt so the support bot stops making up refund policies",
|
|
12
|
+
"Compress our product videos to H.264 and make thumbnails every ten seconds",
|
|
13
|
+
"Build a RAG pipeline over our help-centre articles with hybrid search",
|
|
14
|
+
"Make a launch video in React with animated captions"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Generation job pipeline
|
|
2
|
+
|
|
3
|
+
Provider-neutral shapes. Map field names to your provider's API reference.
|
|
4
|
+
|
|
5
|
+
## Table
|
|
6
|
+
|
|
7
|
+
```sql
|
|
8
|
+
CREATE TABLE generation_jobs (
|
|
9
|
+
id uuid PRIMARY KEY,
|
|
10
|
+
user_id uuid NOT NULL,
|
|
11
|
+
status text NOT NULL CHECK (status IN
|
|
12
|
+
('queued','running','succeeded','failed_safety','failed_invalid','failed_provider','timed_out','canceled')),
|
|
13
|
+
provider text NOT NULL,
|
|
14
|
+
model text NOT NULL, -- pinned model ID and version
|
|
15
|
+
template_version text NOT NULL,
|
|
16
|
+
request jsonb NOT NULL, -- final prompt, parameters, seed
|
|
17
|
+
provider_job_id text UNIQUE,
|
|
18
|
+
estimated_cost numeric(12,6) NOT NULL,
|
|
19
|
+
actual_cost numeric(12,6),
|
|
20
|
+
attempts int NOT NULL DEFAULT 0,
|
|
21
|
+
error text,
|
|
22
|
+
outputs jsonb, -- [{ key, content_type, bytes, sha256, width, height, duration_s }]
|
|
23
|
+
moderation jsonb,
|
|
24
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
25
|
+
deadline_at timestamptz NOT NULL,
|
|
26
|
+
finished_at timestamptz
|
|
27
|
+
);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Guard state changes so a webhook and a poller can't both finish a job:
|
|
31
|
+
|
|
32
|
+
```sql
|
|
33
|
+
UPDATE generation_jobs SET status = 'succeeded', finished_at = now()
|
|
34
|
+
WHERE id = $1 AND status = 'running'; -- 0 rows updated means someone else finished it
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Poll loop (worker)
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
async function pollUntilDone(job: Job) {
|
|
41
|
+
let delay = 2_000;
|
|
42
|
+
while (Date.now() < job.deadlineAt.getTime()) {
|
|
43
|
+
const p = await provider.getJob(job.providerJobId); // GET the provider's job/prediction
|
|
44
|
+
if (p.status === 'succeeded') return finish(job, p.output);
|
|
45
|
+
if (['failed', 'canceled', 'aborted'].includes(p.status)) return fail(job, classify(p.error));
|
|
46
|
+
await sleep(delay + Math.random() * 500); // jitter
|
|
47
|
+
delay = Math.min(delay * 2, 30_000);
|
|
48
|
+
}
|
|
49
|
+
await provider.cancel?.(job.providerJobId);
|
|
50
|
+
return markTimedOut(job);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Run polling in a queue worker, not in the request handler. On worker restart, resume every job in `running` from its `provider_job_id`.
|
|
55
|
+
|
|
56
|
+
## Webhook handler
|
|
57
|
+
|
|
58
|
+
1. Read the raw body (before any JSON parser).
|
|
59
|
+
2. Verify the provider's signature headers with its signing secret using a constant-time compare, and reject timestamps outside a few minutes.
|
|
60
|
+
3. Parse, find the job by `provider_job_id`; unknown ID -> `200` and log (don't make the provider retry forever).
|
|
61
|
+
4. Enqueue `finish` / `fail` and return `2xx` quickly; downloading and moderation happen in the worker.
|
|
62
|
+
|
|
63
|
+
Example of one provider's scheme (Replicate, checked against its docs): headers `webhook-id`, `webhook-timestamp`, `webhook-signature`; signed content `${id}.${timestamp}.${rawBody}`; HMAC-SHA256 keyed with the base64-decoded bytes of the part after the `whsec_` prefix (the official JS client's `validateWebhook` helper does this), signature compared as base64, secret fetched from `GET /v1/webhooks/default/secret`; the header can carry several space-separated `v1,<sig>` values. Its prediction statuses are `starting`, `processing`, `succeeded`, `failed`, `canceled` and `aborted`, and API prediction outputs are deleted after one hour by default, so copy them at once.
|
|
64
|
+
|
|
65
|
+
## finish(job, output)
|
|
66
|
+
|
|
67
|
+
1. Download each output with a size limit and timeout; check the content type by magic bytes, not the extension.
|
|
68
|
+
2. Output moderation; on block set `failed_safety`, keep the evidence privately, don't show it.
|
|
69
|
+
3. Keep or add provenance (C2PA manifest, label metadata).
|
|
70
|
+
4. Upload to `generations/<job_id>/<n>.<ext>`, private, with `Content-Type` and checksum.
|
|
71
|
+
5. Guarded `UPDATE` to `succeeded`, record `actual_cost`, notify the client.
|
|
72
|
+
|
|
73
|
+
## Testing
|
|
74
|
+
|
|
75
|
+
- Stub the provider client with recorded responses for success, safety refusal, invalid parameters, 5xx and a job that never finishes.
|
|
76
|
+
- Test duplicate webhooks, a webhook arriving before the submit call returns, a bad signature (rejected), quota exceeded (rejected before any provider call), and a timed-out job (canceled at the provider).
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: angular-patterns
|
|
3
|
+
description: Modern Angular guidance for standalone components, signal state with input(), output(), model(), computed and effect, RxJS subscriptions that cannot leak, OnPush and zoneless change detection, inject()-based dependency injection, typed reactive or signal forms, and TestBed component tests. Use when writing, migrating or debugging an Angular application, such as moving NgModules to standalone, replacing decorators with signals, fixing a view that does not refresh, or stopping a subscription leak.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Any Agent Skills host. Targets Angular 17+ and notes where v20, v21 and v22 changed defaults. Needs the Angular CLI (ng) to build and test.
|
|
6
|
+
metadata:
|
|
7
|
+
kete-loom/version: "0.1.0"
|
|
8
|
+
kete-loom/category: coding
|
|
9
|
+
kete-loom/risk: runs-commands
|
|
10
|
+
kete-loom/requires: "ng"
|
|
11
|
+
kete-loom/owner: "Kete-org"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Angular patterns
|
|
15
|
+
|
|
16
|
+
Write Angular that uses signals for state, RxJS for streams, and lets change detection do as little as possible. Match the version the project is on; do not introduce APIs it does not have.
|
|
17
|
+
|
|
18
|
+
## 0. Orient first
|
|
19
|
+
|
|
20
|
+
1. Read `package.json` for the `@angular/core` major. Read `angular.json` for the builder and test runner (Vitest, Karma or Jest).
|
|
21
|
+
2. Check `main.ts` / `app.config.ts`: `bootstrapApplication` means standalone; `provideZonelessChangeDetection()` or no `zone.js` in `polyfills` means zoneless.
|
|
22
|
+
3. Know the default shifts:
|
|
23
|
+
- Standalone is the default for components, directives and pipes since v19.
|
|
24
|
+
- New apps are zoneless by default since v21, and new projects use Vitest.
|
|
25
|
+
- From v22, components without a `changeDetection` setting are OnPush; the old default is named `ChangeDetectionStrategy.Eager`.
|
|
26
|
+
4. Run the CLI migrations instead of rewriting by hand when moving a codebase: `ng generate @angular/core:standalone`, `@angular/core:control-flow`, `@angular/core:signal-input-migration`, `@angular/core:inject`. Review their diff.
|
|
27
|
+
|
|
28
|
+
## 1. Components
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
@Component({
|
|
32
|
+
selector: 'app-user-card',
|
|
33
|
+
imports: [DatePipe],
|
|
34
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
35
|
+
template: `
|
|
36
|
+
@if (user(); as u) { <h2>{{ u.name }}</h2> } @else { <p>Loading</p> }
|
|
37
|
+
@for (tag of tags(); track tag.id) { <span>{{ tag.label }}</span> } @empty { <p>No tags</p> }
|
|
38
|
+
`,
|
|
39
|
+
})
|
|
40
|
+
export class UserCard {
|
|
41
|
+
user = input.required<User>();
|
|
42
|
+
tags = input<Tag[]>([]);
|
|
43
|
+
selected = output<string>();
|
|
44
|
+
expanded = model(false);
|
|
45
|
+
initials = computed(() => this.user().name.slice(0, 2).toUpperCase());
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- Use built-in control flow (`@if`, `@for`, `@switch`) over `*ngIf`/`*ngFor` in new code. `@for` requires `track`: use a stable id, `$index` only for static lists.
|
|
50
|
+
- Set `OnPush` explicitly on versions before v22 so behaviour is the same after upgrade.
|
|
51
|
+
- Keep templates free of method calls that compute; use `computed` or a pure pipe.
|
|
52
|
+
- Use `@defer` for heavy below-the-fold components.
|
|
53
|
+
|
|
54
|
+
## 2. Signals
|
|
55
|
+
|
|
56
|
+
- `signal()` for local state, `computed()` for anything derived, `input()`/`model()` for component inputs.
|
|
57
|
+
- Update with `.set()` or `.update(v => ...)`. Never mutate an object inside a signal in place; produce a new object or the change is not seen.
|
|
58
|
+
- `effect()` is for syncing to the outside world (localStorage, logging, a non-Angular widget). Do not use it to copy one signal into another; use `computed`, or `linkedSignal` when the derived value must also be writable.
|
|
59
|
+
- For async data, prefer `resource()` / `httpResource()` (stable in v22; check status on older versions) or `toSignal(observable$)` over manual subscribe-and-set.
|
|
60
|
+
- Bridge with `toSignal` and `toObservable` from `@angular/core/rxjs-interop`. `toSignal` needs an injection context and an `initialValue` unless you handle `undefined`.
|
|
61
|
+
|
|
62
|
+
## 3. RxJS without leaks
|
|
63
|
+
|
|
64
|
+
Every `subscribe()` needs a teardown. In order of preference:
|
|
65
|
+
|
|
66
|
+
1. Do not subscribe: use the `async` pipe or `toSignal`.
|
|
67
|
+
2. `takeUntilDestroyed()` in a constructor or field initialiser, or `takeUntilDestroyed(this.destroyRef)` elsewhere.
|
|
68
|
+
3. Explicit `Subscription` cleaned in `DestroyRef.onDestroy`.
|
|
69
|
+
|
|
70
|
+
Rules:
|
|
71
|
+
|
|
72
|
+
- No nested `subscribe` inside `subscribe`. Use `switchMap` (cancel previous, for search and route params), `concatMap` (keep order, for writes), `exhaustMap` (ignore while busy, for submit buttons) or `mergeMap` (parallel).
|
|
73
|
+
- `HttpClient` calls complete on their own, but long-lived sources (`valueChanges`, router events, `interval`, websockets, store selects) never do.
|
|
74
|
+
- Handle errors with `catchError` inside the inner observable so one failure does not kill the outer stream.
|
|
75
|
+
- Use `shareReplay({ bufferSize: 1, refCount: true })` for shared HTTP results, not bare `shareReplay(1)` on infinite sources.
|
|
76
|
+
|
|
77
|
+
## 4. Change detection
|
|
78
|
+
|
|
79
|
+
- With OnPush or zoneless, a view refreshes when a signal it reads changes, an input reference changes, a template event fires, or the `async` pipe emits. Setting a plain field from a `setTimeout` or a third-party callback does not refresh the view: make that field a signal.
|
|
80
|
+
- Never fix a stale view with `ChangeDetectorRef.detectChanges()` sprinkled in callbacks, or `setTimeout(() => ...)`. Convert the state to a signal.
|
|
81
|
+
- `ExpressionChangedAfterItHasBeenCheckedError` means a value changes during the check; move the write into a `computed`, an event handler, or `afterNextRender`.
|
|
82
|
+
- Run DOM-measuring or browser-only code in `afterNextRender` / `afterEveryRender`, which do not run on the server.
|
|
83
|
+
|
|
84
|
+
## 5. Dependency injection
|
|
85
|
+
|
|
86
|
+
- Use `inject(Service)` in field initialisers; constructor injection is still valid in codebases that use it.
|
|
87
|
+
- `@Injectable({ providedIn: 'root' })` for app-wide singletons. Provide per-feature services in route `providers` or a component's `providers` when each instance needs its own state.
|
|
88
|
+
- Use `InjectionToken<T>` for config values, provided in `app.config.ts`.
|
|
89
|
+
- `inject()` only works in an injection context; outside one, pass an `Injector` and use `runInInjectionContext`.
|
|
90
|
+
- Use functional guards, resolvers and interceptors (`CanActivateFn`, `HttpInterceptorFn` with `provideHttpClient(withInterceptors([...]))`).
|
|
91
|
+
|
|
92
|
+
## 6. Forms
|
|
93
|
+
|
|
94
|
+
- Use typed reactive forms (`FormBuilder.nonNullable.group`, `FormControl<string>`) for new forms on versions before v22. Avoid `UntypedFormGroup` in new code.
|
|
95
|
+
- On v22+, signal forms (`form()` with the `[formField]` directive) are stable; use them for new forms if the codebase has adopted them, and do not mix both styles inside one form.
|
|
96
|
+
- Put validation in validators, not in submit handlers. Show errors from the control's state (`invalid && touched`).
|
|
97
|
+
- Disable the submit button while pending and use `exhaustMap` (or a pending signal) to stop double submits.
|
|
98
|
+
|
|
99
|
+
## 7. Tests
|
|
100
|
+
|
|
101
|
+
1. Run the project's test command (`ng test`, which uses Vitest in new v21+ projects or Karma in older ones). Do not switch runners as a side effect.
|
|
102
|
+
2. Standalone components: `TestBed.configureTestingModule({ imports: [UserCard] })`, then `const fixture = TestBed.createComponent(UserCard)`.
|
|
103
|
+
3. Set signal inputs with `fixture.componentRef.setInput('user', user)`, then `await fixture.whenStable()` (or `fixture.detectChanges()` in zone-based tests).
|
|
104
|
+
4. Use `provideHttpClient()` plus `provideHttpClientTesting()` and `HttpTestingController` to assert requests; call `httpMock.verify()` after each test.
|
|
105
|
+
5. Query by role, text or `data-testid`, and assert what the user sees.
|
|
106
|
+
|
|
107
|
+
## Stop and ask the user
|
|
108
|
+
|
|
109
|
+
- Moving the app from zone.js to zoneless, or from Karma to Vitest.
|
|
110
|
+
- A migration schematic touches more than the files you were asked to change.
|
|
111
|
+
- Upgrading the Angular major is the simplest fix.
|
|
112
|
+
|
|
113
|
+
## Never
|
|
114
|
+
|
|
115
|
+
- Never leave a `subscribe()` on a long-lived observable without teardown.
|
|
116
|
+
- Never mutate inputs or objects held in signals in place.
|
|
117
|
+
- Never call `detectChanges()` or `setTimeout` to paper over a state that is not reactive.
|
|
118
|
+
- Never bypass sanitisation with `bypassSecurityTrustHtml` on user content.
|
|
119
|
+
|
|
120
|
+
## Report back
|
|
121
|
+
|
|
122
|
+
List the files changed, the Angular version assumptions you relied on, the build and test commands you ran with their results, and any migration left for later.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"should_trigger": [
|
|
3
|
+
"Convert this Angular NgModule feature to standalone components",
|
|
4
|
+
"My Angular component subscribes to valueChanges and never unsubscribes, fix the leak",
|
|
5
|
+
"Replace the @Input decorators in this Angular component with signal inputs",
|
|
6
|
+
"The Angular view doesn't refresh after the websocket callback sets a field, using OnPush",
|
|
7
|
+
"Write a TestBed test for the Angular user card component that sets a signal input"
|
|
8
|
+
],
|
|
9
|
+
"should_not_trigger": [
|
|
10
|
+
"Fix the TypeScript strict null errors in our Express server",
|
|
11
|
+
"Write a Vue 3 composable that wraps a websocket connection",
|
|
12
|
+
"My Svelte 5 $effect runs in an infinite loop",
|
|
13
|
+
"Set up Playwright end-to-end tests for the checkout flow",
|
|
14
|
+
"Review this Nuxt change for hydration mismatches"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-design
|
|
3
|
+
description: HTTP API contract design covering resource modelling, REST versus RPC-style endpoints, status codes and RFC 9457 problem details, cursor pagination, filtering, versioning and deprecation headers, Idempotency-Key retries, OpenAPI-first contracts, and when GraphQL is worth it. Use when designing a new HTTP or GraphQL API, adding endpoints to an existing one, reviewing an API contract or OpenAPI file before it ships, or planning a breaking change.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Any Agent Skills host. Language and framework neutral; examples are HTTP and OpenAPI YAML.
|
|
6
|
+
metadata:
|
|
7
|
+
kete-loom/version: "0.1.0"
|
|
8
|
+
kete-loom/category: coding
|
|
9
|
+
kete-loom/risk: writes-files
|
|
10
|
+
kete-loom/owner: "Kete-org"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# API design
|
|
14
|
+
|
|
15
|
+
Design the contract first, then the code. A published API is a promise: every field, status code and default you ship is something a client will depend on.
|
|
16
|
+
|
|
17
|
+
## Before you design
|
|
18
|
+
|
|
19
|
+
1. Find what already exists: search the codebase for an OpenAPI/Swagger file, GraphQL schema, route definitions and an existing error format. **Match the house conventions** (casing, error shape, pagination style) even where this skill would choose differently; consistency beats local perfection.
|
|
20
|
+
2. Name the consumers: browser app, mobile app (slow to update, so breaking changes hurt for months), partners, internal services.
|
|
21
|
+
3. **Stop and ask the user** when you don't know: who the clients are, whether the API is public or internal, the auth model, or whether a breaking change is acceptable.
|
|
22
|
+
|
|
23
|
+
## Choose the style
|
|
24
|
+
|
|
25
|
+
| Situation | Choose |
|
|
26
|
+
|---|---|
|
|
27
|
+
| CRUD-ish domain, many clients, caching matters | REST (resources + HTTP methods) |
|
|
28
|
+
| Actions that don't map to a resource (`send`, `recalculate`) | REST with a sub-resource or action resource (`POST /invoices/{id}/send`), not a verb in every path |
|
|
29
|
+
| Internal service-to-service, strict schemas, streaming | gRPC or another RPC framework |
|
|
30
|
+
| Many client shapes over a graph of data, one team owns the schema | GraphQL, if you accept the costs below |
|
|
31
|
+
|
|
32
|
+
GraphQL costs: HTTP caching mostly lost, query cost limits and depth limits needed, N+1 resolvers (needs batching such as DataLoader), errors returned with `200`, and authorization per field. Don't choose it only to avoid writing endpoints.
|
|
33
|
+
|
|
34
|
+
## Resource modelling (REST)
|
|
35
|
+
|
|
36
|
+
1. Nouns, plural, lowercase, hyphenated: `/orders`, `/orders/{orderId}/line-items`. Nest at most one level; beyond that, link by id.
|
|
37
|
+
2. Methods mean what HTTP says: `GET` safe, `PUT` and `DELETE` idempotent, `PATCH` partial update, `POST` create or action.
|
|
38
|
+
3. IDs are opaque strings to clients. Never expose auto-increment IDs on public APIs if enumeration matters.
|
|
39
|
+
4. One casing for JSON fields across the whole API (pick `camelCase` or `snake_case`, match what exists).
|
|
40
|
+
5. Timestamps in RFC 3339 / ISO 8601 UTC (`2026-03-01T12:00:00Z`). Money as integer minor units plus a currency code, or a decimal string; never a float.
|
|
41
|
+
6. Return the created resource and `Location` header on `201`. Return `204` only when there is truly nothing to say.
|
|
42
|
+
7. Design for additive change: clients must ignore unknown fields, and enums must tolerate new values.
|
|
43
|
+
|
|
44
|
+
## Errors
|
|
45
|
+
|
|
46
|
+
- Use the status code that matches the failure (table in `references/conventions.md`). `400` malformed, `401` unauthenticated, `403` not allowed, `404` not found (also for "exists but you can't see it"), `409` conflict, `422` validation, `429` rate limited, `5xx` server fault.
|
|
47
|
+
- Body uses **Problem Details (RFC 9457)** with `Content-Type: application/problem+json`: `type`, `title`, `status`, `detail`, `instance`, plus extension members such as `errors` for field-level validation.
|
|
48
|
+
- Never leak stack traces, SQL or internal hostnames in `detail`.
|
|
49
|
+
- Error `type` URIs and machine-readable codes are part of the contract. Clients branch on them, not on `detail` text.
|
|
50
|
+
|
|
51
|
+
## Pagination, filtering, sorting
|
|
52
|
+
|
|
53
|
+
1. Default to **cursor pagination** for anything that grows: `?limit=50&cursor=<opaque>`, respond with `next_cursor` (null at the end). Offset pagination is fine for small, stable admin lists.
|
|
54
|
+
2. Always enforce a maximum `limit`, and a default when it is absent.
|
|
55
|
+
3. Cursors are opaque (encode the sort key and id); never let clients build them.
|
|
56
|
+
4. Filtering via plain query params (`?status=paid&created_after=...`). Sorting via `?sort=-created_at,id`, always with a unique tiebreaker so pages are stable.
|
|
57
|
+
5. Only add filters someone needs. Each one is an index and a promise.
|
|
58
|
+
|
|
59
|
+
## Idempotency and concurrency
|
|
60
|
+
|
|
61
|
+
- Make retryable `POST`s safe with an `Idempotency-Key` request header: store key + request fingerprint + response for a retention window; replay the stored response on a repeat; return `422` or `409` if the same key arrives with a different body. Required for payments and anything that sends messages or moves money.
|
|
62
|
+
- Prevent lost updates with `ETag` + `If-Match` on `PUT`/`PATCH`; return `412 Precondition Failed` on mismatch.
|
|
63
|
+
- Rate limit with `429` and a `Retry-After` header.
|
|
64
|
+
|
|
65
|
+
## Versioning and deprecation
|
|
66
|
+
|
|
67
|
+
1. Prefer evolving one version additively. A breaking change is: removing or renaming a field, changing a type or meaning, adding a required input, tightening validation, changing a default or status code.
|
|
68
|
+
2. When you must break, pick one scheme and keep it: URL major version (`/v2/...`, simplest for public APIs) or a header/media-type version. Don't mix.
|
|
69
|
+
3. Deprecate before removing: announce, send the `Deprecation` header (RFC 9745) and a `Sunset` header (RFC 8594) with the removal date, and a `Link` with `rel="deprecation"` to the migration guide. Measure usage before switching off.
|
|
70
|
+
4. **Stop and ask** before shipping any breaking change to a public or mobile-facing API.
|
|
71
|
+
|
|
72
|
+
## OpenAPI contract
|
|
73
|
+
|
|
74
|
+
1. Write or update the OpenAPI document (3.1 or later; 3.2 was published in September 2025, so check what your generators and linters support before adopting it) **before** the handler code, and review it as the source of truth.
|
|
75
|
+
2. Every operation has an `operationId`, request/response schemas under `components/schemas`, and documented error responses using a shared problem-details schema.
|
|
76
|
+
3. Lint it (for example Spectral or Redocly CLI, whichever the repo already uses) and validate requests/responses against it in tests where possible.
|
|
77
|
+
4. See `references/conventions.md` for a skeleton.
|
|
78
|
+
|
|
79
|
+
## Never
|
|
80
|
+
|
|
81
|
+
- Verbs in resource paths (`/getUser`), or `200` with `{"error": ...}` on REST endpoints.
|
|
82
|
+
- Unbounded list endpoints.
|
|
83
|
+
- Accepting a price, role or owner id from the client when the server can derive it.
|
|
84
|
+
- Silent breaking changes in a "minor" release.
|
|
85
|
+
|
|
86
|
+
## Report back
|
|
87
|
+
|
|
88
|
+
When you design or review an API, return:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Style: REST | RPC | GraphQL, and why (one line)
|
|
92
|
+
Endpoints: METHOD path → status codes (one line each)
|
|
93
|
+
Contract file: path to OpenAPI/schema written or changed
|
|
94
|
+
Breaking changes: none | list
|
|
95
|
+
Open questions: what the user must decide
|
|
96
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"should_trigger": [
|
|
3
|
+
"Design the REST endpoints for a bookings service: create, list, cancel, reschedule",
|
|
4
|
+
"What should our error response body look like? Right now every endpoint returns something different",
|
|
5
|
+
"Our /transactions list endpoint times out with big accounts, how should we paginate it?",
|
|
6
|
+
"We need to rename the customer_name field in the public API without breaking the mobile app",
|
|
7
|
+
"Review this openapi.yaml before we publish it to partners",
|
|
8
|
+
"Should we build the partner API in GraphQL or REST?"
|
|
9
|
+
],
|
|
10
|
+
"should_not_trigger": [
|
|
11
|
+
"Integrate Stripe checkout into our Node backend",
|
|
12
|
+
"Restructure the service so the domain logic doesn't import Express or the ORM",
|
|
13
|
+
"Write an ADR recording why we picked gRPC for internal services",
|
|
14
|
+
"Write the SQL migration that adds an index on orders.created_at",
|
|
15
|
+
"Add JWT authentication with refresh tokens to the login endpoint",
|
|
16
|
+
"Break the reporting feature into an ordered implementation plan"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# API conventions reference
|
|
2
|
+
|
|
3
|
+
Read this when choosing a status code, writing an error body, or starting an OpenAPI file.
|
|
4
|
+
|
|
5
|
+
## Status codes
|
|
6
|
+
|
|
7
|
+
| Code | Use for |
|
|
8
|
+
|---|---|
|
|
9
|
+
| 200 OK | Successful read, or update that returns the resource |
|
|
10
|
+
| 201 Created | Resource created; include `Location` and the body |
|
|
11
|
+
| 202 Accepted | Work queued; return a status resource to poll |
|
|
12
|
+
| 204 No Content | Success with no body (for example `DELETE`) |
|
|
13
|
+
| 304 Not Modified | Conditional `GET` with matching `If-None-Match` |
|
|
14
|
+
| 400 Bad Request | Malformed syntax, unparsable JSON, wrong types |
|
|
15
|
+
| 401 Unauthorized | Missing or invalid credentials; send `WWW-Authenticate` |
|
|
16
|
+
| 403 Forbidden | Authenticated but not allowed |
|
|
17
|
+
| 404 Not Found | No such resource, or caller may not know it exists |
|
|
18
|
+
| 405 Method Not Allowed | Method not supported on this path; send `Allow` |
|
|
19
|
+
| 409 Conflict | State conflict (duplicate, wrong state transition) |
|
|
20
|
+
| 412 Precondition Failed | `If-Match` ETag mismatch |
|
|
21
|
+
| 415 Unsupported Media Type | Wrong `Content-Type` |
|
|
22
|
+
| 422 Unprocessable Content | Well-formed but fails validation |
|
|
23
|
+
| 429 Too Many Requests | Rate limited; send `Retry-After` |
|
|
24
|
+
| 500 Internal Server Error | Unexpected server fault |
|
|
25
|
+
| 503 Service Unavailable | Overloaded or down for maintenance; send `Retry-After` |
|
|
26
|
+
|
|
27
|
+
## Problem details (RFC 9457)
|
|
28
|
+
|
|
29
|
+
```http
|
|
30
|
+
HTTP/1.1 422 Unprocessable Content
|
|
31
|
+
Content-Type: application/problem+json
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
"type": "https://api.example.com/problems/validation-error",
|
|
35
|
+
"title": "Request validation failed",
|
|
36
|
+
"status": 422,
|
|
37
|
+
"detail": "2 fields are invalid.",
|
|
38
|
+
"instance": "/orders/req_7f3a",
|
|
39
|
+
"errors": [
|
|
40
|
+
{ "pointer": "#/email", "detail": "must be a valid email address" },
|
|
41
|
+
{ "pointer": "#/quantity", "detail": "must be at least 1" }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`type` defaults to `about:blank` when no specific type exists. `errors` is an extension member (RFC 9457 shows this shape, with `pointer` as a JSON Pointer into the request body); keep its shape identical everywhere.
|
|
47
|
+
|
|
48
|
+
## Cursor pagination
|
|
49
|
+
|
|
50
|
+
```http
|
|
51
|
+
GET /orders?limit=2&cursor=eyJjIjoiMjAyNi0wMy0wMVQxMjowMDowMFoiLCJpZCI6Im9yZF85In0
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"data": [ { "id": "ord_8" }, { "id": "ord_7" } ],
|
|
57
|
+
"next_cursor": "eyJjIjoiMjAyNi0wMi0yOFQwOTowMDowMFoiLCJpZCI6Im9yZF83In0"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Server side: decode the cursor to `(created_at, id)` and query `WHERE (created_at, id) < (:c, :id) ORDER BY created_at DESC, id DESC LIMIT :limit + 1`. Fetching one extra row tells you whether `next_cursor` is null. Back it with an index on the sort columns.
|
|
62
|
+
|
|
63
|
+
## Idempotency-Key flow
|
|
64
|
+
|
|
65
|
+
1. Client sends `Idempotency-Key: <uuid>` on `POST`.
|
|
66
|
+
2. Server looks up the key scoped to the caller.
|
|
67
|
+
- Not found: insert a row (key, fingerprint of method+path+body, status `processing`), run the operation, store the response.
|
|
68
|
+
- Found, same fingerprint, finished: return the stored response unchanged.
|
|
69
|
+
- Found, same fingerprint, still processing: return `409`.
|
|
70
|
+
- Found, different fingerprint: return `422`.
|
|
71
|
+
3. Expire keys after a documented window (24 hours is common).
|
|
72
|
+
|
|
73
|
+
The `Idempotency-Key` header is specified in an IETF HTTPAPI working-group Internet-Draft; Stripe and other payment APIs use the same pattern.
|
|
74
|
+
|
|
75
|
+
## Deprecation headers
|
|
76
|
+
|
|
77
|
+
```http
|
|
78
|
+
Deprecation: @1767225599
|
|
79
|
+
Sunset: Thu, 31 Dec 2026 23:59:59 GMT
|
|
80
|
+
Link: <https://api.example.com/docs/migrate-v2>; rel="deprecation"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`Deprecation` (RFC 9745) carries a structured-field date (`@` + Unix seconds). `Sunset` (RFC 8594) carries an HTTP-date.
|
|
84
|
+
|
|
85
|
+
## OpenAPI skeleton
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
openapi: 3.1.0
|
|
89
|
+
info: { title: Orders API, version: 1.0.0 }
|
|
90
|
+
paths:
|
|
91
|
+
/orders:
|
|
92
|
+
get:
|
|
93
|
+
operationId: listOrders
|
|
94
|
+
parameters:
|
|
95
|
+
- { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 50 } }
|
|
96
|
+
- { name: cursor, in: query, schema: { type: string } }
|
|
97
|
+
responses:
|
|
98
|
+
"200":
|
|
99
|
+
description: A page of orders
|
|
100
|
+
content:
|
|
101
|
+
application/json:
|
|
102
|
+
schema: { $ref: "#/components/schemas/OrderPage" }
|
|
103
|
+
default:
|
|
104
|
+
description: Error
|
|
105
|
+
content:
|
|
106
|
+
application/problem+json:
|
|
107
|
+
schema: { $ref: "#/components/schemas/Problem" }
|
|
108
|
+
components:
|
|
109
|
+
schemas:
|
|
110
|
+
Problem:
|
|
111
|
+
type: object
|
|
112
|
+
properties:
|
|
113
|
+
type: { type: string, format: uri-reference }
|
|
114
|
+
title: { type: string }
|
|
115
|
+
status: { type: integer }
|
|
116
|
+
detail: { type: string }
|
|
117
|
+
instance: { type: string, format: uri-reference }
|
|
118
|
+
Order:
|
|
119
|
+
type: object
|
|
120
|
+
required: [id, status, total_minor, currency, created_at]
|
|
121
|
+
properties:
|
|
122
|
+
id: { type: string }
|
|
123
|
+
status: { type: string, enum: [pending, paid, cancelled] }
|
|
124
|
+
total_minor: { type: integer }
|
|
125
|
+
currency: { type: string, minLength: 3, maxLength: 3 }
|
|
126
|
+
created_at: { type: string, format: date-time }
|
|
127
|
+
OrderPage:
|
|
128
|
+
type: object
|
|
129
|
+
required: [data, next_cursor]
|
|
130
|
+
properties:
|
|
131
|
+
data: { type: array, items: { $ref: "#/components/schemas/Order" } }
|
|
132
|
+
next_cursor: { type: [string, "null"] }
|
|
133
|
+
```
|