@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.1
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/CHANGELOG.md +919 -1
- package/README.md +104 -81
- package/README.tr.md +103 -62
- package/docs/FIGMA_PIPELINE.md +35 -35
- package/docs/adr/0006-skills-core-external-split.md +1 -1
- package/docs/adr/0007-multi-tool-adapter-framework.md +6 -0
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +7 -0
- package/docs/architecture.md +50 -14
- package/docs/best-practices.md +1 -1
- package/docs/ecosystem.md +56 -32
- package/docs/facts.json +10 -10
- package/docs/features.md +97 -5
- package/docs/recovery-guide.md +7 -14
- package/docs/server-readiness.md +31 -24
- package/index.js +1 -1
- package/install/_common.mjs +3 -5
- package/install/_platform-filter.mjs +23 -1
- package/install/_unattended-profile.mjs +321 -75
- package/install/claude.mjs +51 -10
- package/install/codex.mjs +2 -0
- package/install/copilot.mjs +2 -0
- package/install/index.mjs +30 -17
- package/install/templates/claude-hooks.json +16 -5
- package/install/templates/copilot-instructions.md +1 -1
- package/install/templates/multi-agent-autopilot-awake.plist.template +48 -0
- package/install/templates/multi-agent-autopilot.plist.template +12 -5
- package/install/unattended-profile-legacy.json +80 -0
- package/manifest.json +617 -483
- package/package.json +8 -3
- package/pipeline/agents/code-reviewer.md +10 -0
- package/pipeline/agents/plan-critic.md +98 -0
- package/pipeline/agents/security-auditor.md +10 -0
- package/pipeline/agents/task-clarifier.md +10 -0
- package/pipeline/commands/multi-agent/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/analysis/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +12 -1
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/autopilot-off/SKILL.md +36 -6
- package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +77 -12
- package/pipeline/commands/multi-agent/autopilot-status/SKILL.md +29 -8
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/channels/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/design-check/SKILL.md +16 -11
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/doctor/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/feedback/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/forget/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/graph/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/help/SKILL.md +37 -39
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/issue/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/jira/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/kill/SKILL.md +9 -3
- package/pipeline/commands/multi-agent/language/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/log/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/model/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/purge/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/refactor/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/research/SKILL.md +49 -0
- package/pipeline/commands/multi-agent/resume/SKILL.md +29 -6
- package/pipeline/commands/multi-agent/review/SKILL.md +28 -9
- package/pipeline/commands/multi-agent/review-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/review-issue/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/review-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-off/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-on/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-status/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/routines/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/save/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/scaffold/SKILL.md +47 -0
- package/pipeline/commands/multi-agent/scan/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/search/SKILL.md +12 -8
- package/pipeline/commands/multi-agent/security-review/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/serve/SKILL.md +62 -0
- package/pipeline/commands/multi-agent/setup/SKILL.md +27 -36
- package/pipeline/commands/multi-agent/stack/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/status/SKILL.md +10 -9
- package/pipeline/commands/multi-agent/steer/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +13 -13
- package/pipeline/commands/multi-agent/test/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-accessibility/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dark-mode/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dynamic-type/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-screenshots/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/update/SKILL.md +4 -0
- package/pipeline/contract/CHANGELOG.md +74 -0
- package/pipeline/contract/README.md +126 -0
- package/pipeline/contract/build.mjs +427 -0
- package/pipeline/contract/fixtures/answer-result.json +11 -0
- package/pipeline/contract/fixtures/error-invalid-request.json +8 -0
- package/pipeline/contract/fixtures/error-unauthorized.json +5 -0
- package/pipeline/contract/fixtures/error-unsigned.json +5 -0
- package/pipeline/contract/fixtures/issues-empty.json +18 -0
- package/pipeline/contract/fixtures/launch-plan.json +31 -0
- package/pipeline/contract/fixtures/runs-awaiting-question.json +70 -0
- package/pipeline/contract/fixtures/runs-empty.json +6 -0
- package/pipeline/contract/fixtures/runs-failed.json +84 -0
- package/pipeline/contract/fixtures/runs-old-schema.json +70 -0
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +101 -0
- package/pipeline/contract/fixtures/runs-pr-opened.json +106 -0
- package/pipeline/contract/fixtures/runs-running.json +84 -0
- package/pipeline/contract/fixtures/worktrees-empty.json +4 -0
- package/pipeline/contract/frozen/toolbox.json +107 -0
- package/pipeline/contract/manifest.json +263 -0
- package/pipeline/contract/types/index.d.ts +343 -0
- package/pipeline/lib/_jira-auth.sh +6 -2
- package/pipeline/lib/account-resolver.sh +1 -1
- package/pipeline/lib/autopilot-state.sh +19 -0
- package/pipeline/lib/context-link-extractor.sh +12 -5
- package/pipeline/lib/credential-inventory.sh +12 -5
- package/pipeline/lib/credential-store.sh +116 -185
- package/pipeline/lib/fetch-confluence.sh +44 -3
- package/pipeline/lib/fetch-document.sh +3 -4
- package/pipeline/lib/fetch-fortify.sh +1 -1
- package/pipeline/lib/figma-mcp-refresh.sh +2 -2
- package/pipeline/lib/figma-token.sh +5 -1
- package/pipeline/lib/issue-fetcher.sh +233 -16
- package/pipeline/lib/json-file-lock.mjs +172 -0
- package/pipeline/lib/model-dispatch.sh +21 -12
- package/pipeline/lib/model-rung.sh +6 -1
- package/pipeline/lib/multi-repo-pipeline.sh +1 -1
- package/pipeline/lib/outbound-gate.mjs +46 -16
- package/pipeline/lib/parse-complaints.sh +14 -7
- package/pipeline/lib/plan-todos.sh +3 -3
- package/pipeline/lib/post-pr-review.sh +9 -9
- package/pipeline/lib/pr-request-location.mjs +85 -0
- package/pipeline/lib/regular-file.mjs +153 -0
- package/pipeline/lib/repo-hygiene.sh +17 -0
- package/pipeline/lib/route-state.sh +5 -1
- package/pipeline/lib/run-paths.sh +3 -2
- package/pipeline/lib/stack-detect.sh +19 -1
- package/pipeline/lib/unattended-profile-check.mjs +178 -0
- package/pipeline/lib/unattended-settings-location.mjs +28 -0
- package/pipeline/lib/unattended.mjs +76 -0
- package/pipeline/lib/unattended.sh +32 -0
- package/pipeline/lib/untrusted.mjs +76 -0
- package/pipeline/lib/usage-endpoint.mjs +33 -0
- package/pipeline/lib/user-facing.mjs +82 -0
- package/pipeline/lib/user-facing.sh +58 -0
- package/pipeline/multi-agent-refs/_dev-context.md +1 -1
- package/pipeline/multi-agent-refs/analysis/evidence.md +4 -0
- package/pipeline/multi-agent-refs/analysis/locked.md +2 -2
- package/pipeline/multi-agent-refs/analysis/render.md +4 -3
- package/pipeline/multi-agent-refs/analysis/resolve.md +3 -1
- package/pipeline/multi-agent-refs/analysis/synthesis.md +4 -5
- package/pipeline/multi-agent-refs/analysis-template.md +10 -17
- package/pipeline/multi-agent-refs/channels/jira.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
- package/pipeline/multi-agent-refs/conventions-defaults.md +32 -32
- package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -17
- package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +37 -9
- package/pipeline/multi-agent-refs/features/autopilot-operations.md +277 -0
- package/pipeline/multi-agent-refs/features/constitution.md +196 -0
- package/pipeline/multi-agent-refs/features/doctor.md +6 -3
- package/pipeline/multi-agent-refs/features/external-context-injection.md +6 -1
- package/pipeline/multi-agent-refs/features/jira-context.md +1 -1
- package/pipeline/multi-agent-refs/features/maturity-followup.md +43 -23
- package/pipeline/multi-agent-refs/features/model-fallback.md +9 -0
- package/pipeline/multi-agent-refs/features/phone-api.md +306 -0
- package/pipeline/multi-agent-refs/features/plan-critic.md +159 -0
- package/pipeline/multi-agent-refs/features/research.md +150 -0
- package/pipeline/multi-agent-refs/features/review-decision.md +185 -0
- package/pipeline/multi-agent-refs/features/scaffold.md +160 -0
- package/pipeline/multi-agent-refs/features/security-audit.md +6 -2
- package/pipeline/multi-agent-refs/features/skill-conformance.md +4 -1
- package/pipeline/multi-agent-refs/features/stack-adapters.md +116 -0
- package/pipeline/multi-agent-refs/features/unattended-gates.md +316 -0
- package/pipeline/multi-agent-refs/features/unattended-security.md +731 -0
- package/pipeline/multi-agent-refs/features/url-enrichment.md +2 -2
- package/pipeline/multi-agent-refs/features/usage-reporting.md +127 -35
- package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
- package/pipeline/multi-agent-refs/features/visual-evidence.md +7 -7
- package/pipeline/multi-agent-refs/keychain.md +6 -11
- package/pipeline/multi-agent-refs/payload-contracts.md +2 -2
- package/pipeline/multi-agent-refs/phases/log-format.md +2 -3
- package/pipeline/multi-agent-refs/phases/modes.md +10 -12
- package/pipeline/multi-agent-refs/phases/operations.md +11 -5
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +73 -81
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +22 -22
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +42 -66
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +45 -79
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +28 -38
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +27 -25
- package/pipeline/multi-agent-refs/phases.md +1 -1
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/progress-contract.md +13 -16
- package/pipeline/multi-agent-refs/readiness-review.md +1 -1
- package/pipeline/multi-agent-refs/research/engine.md +91 -0
- package/pipeline/multi-agent-refs/rules.md +6 -4
- package/pipeline/multi-agent-refs/setup/repo-discovery.md +2 -2
- package/pipeline/multi-agent-refs/tracker-contract.md +2 -2
- package/pipeline/multi-agent-refs/unattended-contract.md +68 -16
- package/pipeline/rules/figma-pipeline.md +12 -12
- package/pipeline/schemas/agent-state.schema.json +480 -18
- package/pipeline/schemas/analysis-spec.schema.json +4 -4
- package/pipeline/schemas/answer-request.schema.json +24 -0
- package/pipeline/schemas/answer-result.schema.json +28 -0
- package/pipeline/schemas/autopilot-config.schema.json +111 -13
- package/pipeline/schemas/command-parameters.schema.json +99 -0
- package/pipeline/schemas/constitution.schema.json +56 -0
- package/pipeline/schemas/contract-error.schema.json +52 -0
- package/pipeline/schemas/design-check-config.schema.json +5 -1
- package/pipeline/schemas/issues.schema.json +61 -0
- package/pipeline/schemas/launch-plan.schema.json +46 -0
- package/pipeline/schemas/launch-request.schema.json +45 -0
- package/pipeline/schemas/launch.json +61 -0
- package/pipeline/schemas/launch.schema.json +84 -0
- package/pipeline/schemas/phases.json +2 -2
- package/pipeline/schemas/phases.schema.json +68 -0
- package/pipeline/schemas/phone-devices.schema.json +61 -0
- package/pipeline/schemas/phone-signed-request.schema.json +67 -0
- package/pipeline/schemas/plan-critique.schema.json +99 -0
- package/pipeline/schemas/plan-todos.schema.json +7 -7
- package/pipeline/schemas/planning-output.schema.json +5 -0
- package/pipeline/schemas/pr-request.schema.json +46 -0
- package/pipeline/schemas/prefs.schema.json +79 -8
- package/pipeline/schemas/research-output.schema.json +118 -0
- package/pipeline/schemas/review-file-exclusions.schema.json +25 -0
- package/pipeline/schemas/reviewer-output.schema.json +40 -4
- package/pipeline/schemas/run-questions.json +392 -0
- package/pipeline/schemas/run-questions.schema.json +118 -0
- package/pipeline/schemas/runs-index.schema.json +189 -0
- package/pipeline/schemas/scaffold-manifest.schema.json +43 -0
- package/pipeline/schemas/secret-patterns.schema.json +28 -0
- package/pipeline/schemas/stack-adapters.json +527 -0
- package/pipeline/schemas/stack-adapters.schema.json +184 -0
- package/pipeline/schemas/token-budget.json +1 -1
- package/pipeline/schemas/token-budget.schema.json +26 -0
- package/pipeline/schemas/triage-output.schema.json +64 -3
- package/pipeline/schemas/unattended-policy.json +139 -0
- package/pipeline/schemas/unattended-policy.schema.json +73 -0
- package/pipeline/schemas/unattended-profile.json +248 -0
- package/pipeline/schemas/unattended-profile.schema.json +198 -0
- package/pipeline/schemas/worktrees.schema.json +51 -0
- package/pipeline/scripts/README.md +1 -0
- package/pipeline/scripts/_autopilot-config.mjs +130 -0
- package/pipeline/scripts/_autopilot-ops.mjs +567 -0
- package/pipeline/scripts/_autopilot-outcomes.mjs +174 -0
- package/pipeline/scripts/_command-contract.mjs +384 -0
- package/pipeline/scripts/_cost.mjs +40 -0
- package/pipeline/scripts/_notices.mjs +160 -0
- package/pipeline/scripts/_phone-auth.mjs +485 -0
- package/pipeline/scripts/_pre-existing.mjs +294 -0
- package/pipeline/scripts/_redact.mjs +77 -0
- package/pipeline/scripts/_run-paths.mjs +4 -2
- package/pipeline/scripts/_stack-adapter.mjs +678 -0
- package/pipeline/scripts/_stack-routing.mjs +1 -1
- package/pipeline/scripts/agent-guard.py +348 -37
- package/pipeline/scripts/agent-guard.sh +41 -13
- package/pipeline/scripts/analysis-story-tree.mjs +79 -3
- package/pipeline/scripts/answer-question.mjs +181 -0
- package/pipeline/scripts/audit-log-rotate.sh +1 -4
- package/pipeline/scripts/audit-log.sh +4 -4
- package/pipeline/scripts/autopilot-arming.mjs +389 -21
- package/pipeline/scripts/autopilot-awake.mjs +255 -0
- package/pipeline/scripts/autopilot-intake.mjs +137 -36
- package/pipeline/scripts/autopilot-menubar.swift +156 -44
- package/pipeline/scripts/autopilot-publish.mjs +1625 -0
- package/pipeline/scripts/autopilot-runner.mjs +1678 -222
- package/pipeline/scripts/autopilot-status.sh +198 -33
- package/pipeline/scripts/build-lock.sh +120 -0
- package/pipeline/scripts/build-references.mjs +4 -1
- package/pipeline/scripts/build-stack-plugins.mjs +59 -22
- package/pipeline/scripts/capture-flush.sh +1 -1
- package/pipeline/scripts/capture-resume.sh +13 -9
- package/pipeline/scripts/check-derived-drift.mjs +52 -11
- package/pipeline/scripts/commands.mjs +88 -0
- package/pipeline/scripts/constitution.mjs +362 -0
- package/pipeline/scripts/contract-server.mjs +776 -0
- package/pipeline/scripts/cost-analyze.mjs +89 -39
- package/pipeline/scripts/diff-explain.mjs +12 -1
- package/pipeline/scripts/doctor.mjs +77 -28
- package/pipeline/scripts/evidence-gate.mjs +192 -12
- package/pipeline/scripts/feedback-send.mjs +4 -2
- package/pipeline/scripts/gate-ledger.mjs +449 -0
- package/pipeline/scripts/gc-abandoned.sh +132 -13
- package/pipeline/scripts/gen-facts.mjs +31 -15
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/github-ssh-setup.sh +140 -29
- package/pipeline/scripts/graph-mermaid.mjs +4 -1
- package/pipeline/scripts/issues.mjs +236 -0
- package/pipeline/scripts/jira-attach.sh +6 -2
- package/pipeline/scripts/jira-search.sh +4 -3
- package/pipeline/scripts/keychain-save.sh +125 -24
- package/pipeline/scripts/keychain.py +63 -93
- package/pipeline/scripts/launch-request.mjs +747 -0
- package/pipeline/scripts/localize-commands.mjs +4 -10
- package/pipeline/scripts/log-metric.sh +6 -5
- package/pipeline/scripts/maturity-followup.mjs +13 -4
- package/pipeline/scripts/memory-save.sh +25 -0
- package/pipeline/scripts/migrate-prefs.mjs +4 -3
- package/pipeline/scripts/open-questions-gate.mjs +276 -0
- package/pipeline/scripts/phase-tracker.sh +41 -27
- package/pipeline/scripts/phase0-exit-gate.mjs +22 -4
- package/pipeline/scripts/phone-devices.mjs +224 -0
- package/pipeline/scripts/plan-coverage-gate.mjs +200 -66
- package/pipeline/scripts/plan-critique-gate.mjs +591 -0
- package/pipeline/scripts/pr-request.mjs +188 -0
- package/pipeline/scripts/pre-commit-check.sh +115 -4
- package/pipeline/scripts/probe-evidence-capability.sh +44 -5
- package/pipeline/scripts/record-phase.mjs +71 -0
- package/pipeline/scripts/render-agent-log-cost.sh +17 -2
- package/pipeline/scripts/render-cost-summary.sh +1 -1
- package/pipeline/scripts/render-work-summary.sh +1 -1
- package/pipeline/scripts/require-supported-version.sh +4 -1
- package/pipeline/scripts/research-gate.mjs +704 -0
- package/pipeline/scripts/review-decision-gate.mjs +403 -0
- package/pipeline/scripts/routine-registry.mjs +5 -2
- package/pipeline/scripts/runs-index.mjs +135 -27
- package/pipeline/scripts/scaffold-gate.mjs +393 -0
- package/pipeline/scripts/skill-conformance.mjs +25 -8
- package/pipeline/scripts/skill-siblings.mjs +2 -1
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +32 -6
- package/pipeline/scripts/smoke-schema-validation.sh +6 -2
- package/pipeline/scripts/spec-consistency-gate.mjs +469 -0
- package/pipeline/scripts/symbol-existence-gate.mjs +450 -0
- package/pipeline/scripts/test-gap-scan.mjs +40 -2
- package/pipeline/scripts/test-integrity-gate.mjs +20 -4
- package/pipeline/scripts/test-strength.mjs +484 -0
- package/pipeline/scripts/test-summary.mjs +651 -0
- package/pipeline/scripts/triage-memory.mjs +49 -9
- package/pipeline/scripts/unattended_policy.py +2786 -0
- package/pipeline/scripts/uninstall.mjs +10 -10
- package/pipeline/scripts/update-issue-progress.sh +1 -1
- package/pipeline/scripts/usage-identity.mjs +288 -0
- package/pipeline/scripts/usage-register.mjs +187 -67
- package/pipeline/scripts/usage-report.mjs +232 -67
- package/pipeline/scripts/validate-complaint-doc.mjs +28 -10
- package/pipeline/scripts/validate-planning.mjs +6 -0
- package/pipeline/scripts/verify-citations.mjs +151 -38
- package/pipeline/scripts/verify.mjs +58 -18
- package/pipeline/scripts/worktree-prepare.sh +126 -0
- package/pipeline/scripts/worktrees.mjs +124 -0
- package/pipeline/scripts/write-state.mjs +48 -17
- package/pipeline/skills/.skill-manifest.json +222 -226
- package/pipeline/skills/.skills-index.json +77 -88
- package/pipeline/skills/shared/README.md +44 -45
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -9
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +6 -5
- package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +11 -3
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-autopilot-off/SKILL.md +32 -6
- package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +66 -8
- package/pipeline/skills/shared/core/multi-agent-autopilot-status/SKILL.md +27 -9
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-feedback/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-research/SKILL.md +35 -0
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +7 -3
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-review-analysis/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-scaffold/SKILL.md +30 -0
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +60 -0
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +8 -8
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +7 -8
- package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +10 -10
- package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -1
- package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +46 -0
- package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +9 -3
- package/pipeline/skills/shared/external/NOTICE-paul-hudson-skills.md +54 -0
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +9 -11
- package/pipeline/skills/shared/external/NOTICE-vibeship-spawner-skills.md +203 -0
- package/pipeline/skills/shared/external/NOTICE-xcode-build-skills.md +10 -3
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +131 -25
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -3
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +85 -76
- package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +51 -3
- package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +9 -0
- package/pipeline/skills/shared/external/android-datastore/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +106 -181
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +147 -0
- package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +45 -4
- package/pipeline/skills/shared/external/android-performance/SKILL.md +27 -2
- package/pipeline/skills/shared/external/android-performance/references/patterns.md +37 -37
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +111 -67
- package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +128 -0
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +136 -186
- package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +140 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +207 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/operations.md +66 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +175 -0
- package/pipeline/skills/shared/external/app-clips/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-intents/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +4 -3
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +2 -0
- package/pipeline/skills/shared/external/architecture/SKILL.md +106 -39
- package/pipeline/skills/shared/external/architecture/references/adr-and-review.md +76 -0
- package/pipeline/skills/shared/external/authentication/SKILL.md +2 -0
- package/pipeline/skills/shared/external/avkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/background-processing/SKILL.md +2 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +3 -2
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +2 -0
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +3 -2
- package/pipeline/skills/shared/external/clean-code/SKILL.md +192 -90
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/compose-components/SKILL.md +4 -4
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +22 -22
- package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +10 -10
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +13 -6
- package/pipeline/skills/shared/external/compose-testing/references/patterns.md +59 -59
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/context-compression/SKILL.md +118 -250
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-data/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-motion/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +2 -0
- package/pipeline/skills/shared/external/coreml/SKILL.md +2 -1
- package/pipeline/skills/shared/external/council/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/css-modern/SKILL.md +3 -2
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +2 -0
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +130 -20
- package/pipeline/skills/shared/external/debugging-strategies/references/hard-cases.md +54 -0
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +2 -0
- package/pipeline/skills/shared/external/docker-expert/SKILL.md +137 -381
- package/pipeline/skills/shared/external/docker-expert/references/patterns.md +98 -0
- package/pipeline/skills/shared/external/energykit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +3 -1
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +116 -185
- package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +235 -0
- package/pipeline/skills/shared/external/fastapi-pro/references/testing-and-deployment.md +69 -0
- package/pipeline/skills/shared/external/firebase/SKILL.md +4 -3
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +151 -293
- package/pipeline/skills/shared/external/github-actions-templates/references/patterns.md +96 -0
- package/pipeline/skills/shared/external/healthkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +69 -72
- package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +111 -0
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +77 -86
- package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +98 -0
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +150 -78
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +76 -97
- package/pipeline/skills/shared/external/hig-components-system/references/surfaces.md +98 -0
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +48 -76
- package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +132 -0
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +147 -106
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +61 -77
- package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +92 -0
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +147 -77
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +61 -121
- package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +108 -0
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +2 -0
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +3 -2
- package/pipeline/skills/shared/external/humanizer/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +14 -2
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
- package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +4 -3
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +8 -6
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +11 -11
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +102 -193
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +103 -0
- package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -2
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +7 -9
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +2 -2
- package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +4 -3
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +5 -3
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +2 -0
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +2 -0
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +149 -46
- package/pipeline/skills/shared/external/monorepo-architect/references/patterns.md +70 -0
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +2 -0
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/natural-language/SKILL.md +2 -0
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +3 -2
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +91 -21
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +247 -0
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/testing-and-frameworks.md +57 -0
- package/pipeline/skills/shared/external/observability-engineer/SKILL.md +155 -232
- package/pipeline/skills/shared/external/observability-engineer/references/patterns.md +75 -0
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +2 -0
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +18 -18
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +2 -1
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +2 -0
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +3 -2
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +2 -2
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +3 -2
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +7 -7
- package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +69 -69
- package/pipeline/skills/shared/external/room-database/references/patterns.md +126 -126
- package/pipeline/skills/shared/external/search-first/SKILL.md +2 -1
- package/pipeline/skills/shared/external/security-review/SKILL.md +4 -3
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +2 -2
- package/pipeline/skills/shared/external/signal-community/SKILL.md +1 -1
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +2 -1
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +2 -1
- package/pipeline/skills/shared/external/spm-build-analysis/SKILL.md +2 -0
- package/pipeline/skills/shared/external/storekit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-security/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +10 -0
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +4 -3
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +3 -2
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +3 -2
- package/pipeline/skills/shared/external/tipkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +3 -2
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-performance/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-testing/SKILL.md +3 -2
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +1 -1
- package/pipeline/skills/shared/external/xcode-build-benchmark/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-fixer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-orchestrator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-compilation-analyzer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-project-analyzer/SKILL.md +2 -0
- package/pipeline/skills/skills-index.md +40 -41
- package/docs/token-budget-history.md +0 -24
- package/pipeline/skills/shared/external/agentflow/SKILL.md +0 -199
- package/pipeline/skills/shared/external/android-ui-verification/SKILL.md +0 -66
- package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +0 -299
- package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +0 -255
- package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +0 -167
- package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +0 -116
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -216
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eventkit-calendar
|
|
3
3
|
description: "Create, read, and manage calendar events and reminders using EventKit and EventKitUI. Use when adding events to the user's calendar, creating reminders, setting recurrence rules, requesting calendar or reminders access, presenting event editors, choosing calendars, handling alarms, observing calendar changes, or working with EKEventStore, EKEvent, EKReminder, EKCalendar, EKRecurrenceRule, EKEventEditViewController, EKCalendarChooser, or EventKitUI views."
|
|
4
|
+
metadata:
|
|
5
|
+
source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# EventKit
|
|
@@ -71,7 +73,7 @@ read, edit, delete, or fetch calendar events.
|
|
|
71
73
|
|
|
72
74
|
### Write-Only Access to Events
|
|
73
75
|
|
|
74
|
-
Use when your app only creates events (e.g., saving
|
|
76
|
+
Use when your app only creates events (e.g., saving an appointment) and does not
|
|
75
77
|
need to read existing events.
|
|
76
78
|
|
|
77
79
|
Call `try await eventStore.requestWriteOnlyAccessToEvents()` before direct
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"skill_name": "eventkit",
|
|
2
|
+
"skill_name": "eventkit-calendar",
|
|
3
3
|
"evals": [
|
|
4
4
|
{
|
|
5
5
|
"id": 1,
|
|
6
|
-
"prompt": "Review this iOS 26 calendar integration plan: the app asks for `NSCalendarsUsageDescription`, calls `requestAccess(to: .event)`, requests write-only access, then fetches the user's existing events to avoid conflicts before saving
|
|
6
|
+
"prompt": "Review this iOS 26 calendar integration plan: the app asks for `NSCalendarsUsageDescription`, calls `requestAccess(to: .event)`, requests write-only access, then fetches the user's existing events to avoid conflicts before saving an appointment. The team also wants an Add to Calendar button where the user can edit the event in the system sheet. Give corrected guidance with Swift API names where useful.",
|
|
7
7
|
"expected_output": "A review that fixes iOS 17+ calendar authorization, Info.plist keys, write-only read limitations, full-access requirements for fetching, and EventKitUI no-authorization creation.",
|
|
8
8
|
"files": [],
|
|
9
9
|
"assertions": [
|
|
@@ -1,189 +1,120 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fastapi-pro
|
|
3
|
-
description: "
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
description: "FastAPI with Pydantic v2: lifespan, settings, Annotated dependencies, async SQLAlchemy 2.0 sessions, error handlers, background work, httpx tests. Use when building or reviewing a FastAPI service."
|
|
4
|
+
metadata:
|
|
5
|
+
risk: safe
|
|
6
|
+
source: multi-agent-pipeline
|
|
7
|
+
date_added: "2026-09-25"
|
|
7
8
|
---
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
|
|
121
|
-
### Integration Patterns
|
|
122
|
-
|
|
123
|
-
- Message queues (RabbitMQ, Kafka, Redis Pub/Sub)
|
|
124
|
-
- Task queues with Celery or Dramatiq
|
|
125
|
-
- gRPC service integration
|
|
126
|
-
- External API integration with httpx
|
|
127
|
-
- Webhook implementation and processing
|
|
128
|
-
- Server-Sent Events (SSE)
|
|
129
|
-
- GraphQL subscriptions
|
|
130
|
-
- File storage (S3, MinIO, local)
|
|
131
|
-
|
|
132
|
-
### Advanced Features
|
|
133
|
-
|
|
134
|
-
- Dependency injection with advanced patterns
|
|
135
|
-
- Custom response classes
|
|
136
|
-
- Request validation with complex schemas
|
|
137
|
-
- Content negotiation
|
|
138
|
-
- API documentation customization
|
|
139
|
-
- Lifespan events for startup/shutdown
|
|
140
|
-
- Custom exception handlers
|
|
141
|
-
- Request context and state management
|
|
142
|
-
|
|
143
|
-
## Behavioral Traits
|
|
144
|
-
|
|
145
|
-
- Writes async-first code by default
|
|
146
|
-
- Emphasizes type safety with Pydantic and type hints
|
|
147
|
-
- Follows API design best practices
|
|
148
|
-
- Implements comprehensive error handling
|
|
149
|
-
- Uses dependency injection for clean architecture
|
|
150
|
-
- Writes testable and maintainable code
|
|
151
|
-
- Documents APIs thoroughly with OpenAPI
|
|
152
|
-
- Considers performance implications
|
|
153
|
-
- Implements proper logging and monitoring
|
|
154
|
-
- Follows 12-factor app principles
|
|
155
|
-
|
|
156
|
-
## Knowledge Base
|
|
157
|
-
|
|
158
|
-
- FastAPI official documentation
|
|
159
|
-
- Pydantic V2 migration guide
|
|
160
|
-
- SQLAlchemy 2.0 async patterns
|
|
161
|
-
- Python async/await best practices
|
|
162
|
-
- Microservices design patterns
|
|
163
|
-
- REST API design guidelines
|
|
164
|
-
- OAuth2 and JWT standards
|
|
165
|
-
- OpenAPI 3.1 specification
|
|
166
|
-
- Container orchestration with Kubernetes
|
|
167
|
-
- Modern Python packaging and tooling
|
|
168
|
-
|
|
169
|
-
## Response Approach
|
|
170
|
-
|
|
171
|
-
1. **Analyze requirements** for async opportunities
|
|
172
|
-
2. **Design API contracts** with Pydantic models first
|
|
173
|
-
3. **Implement endpoints** with proper error handling
|
|
174
|
-
4. **Add comprehensive validation** using Pydantic
|
|
175
|
-
5. **Write async tests** covering edge cases
|
|
176
|
-
6. **Optimize for performance** with caching and pooling
|
|
177
|
-
7. **Document with OpenAPI** annotations
|
|
178
|
-
8. **Consider deployment** and scaling strategies
|
|
179
|
-
|
|
180
|
-
## Example Interactions
|
|
181
|
-
|
|
182
|
-
- "Create a FastAPI microservice with async SQLAlchemy and Redis caching"
|
|
183
|
-
- "Implement JWT authentication with refresh tokens in FastAPI"
|
|
184
|
-
- "Design a scalable WebSocket chat system with FastAPI"
|
|
185
|
-
- "Optimize this FastAPI endpoint that's causing performance issues"
|
|
186
|
-
- "Set up a complete FastAPI project with Docker and Kubernetes"
|
|
187
|
-
- "Implement rate limiting and circuit breaker for external API calls"
|
|
188
|
-
- "Create a GraphQL endpoint alongside REST in FastAPI"
|
|
189
|
-
- "Build a file upload system with progress tracking"
|
|
10
|
+
# FastAPI Pro
|
|
11
|
+
|
|
12
|
+
FastAPI makes the happy path short: type-hint a function and you get parsing,
|
|
13
|
+
validation and an OpenAPI document. The hard parts are the ones the tutorial
|
|
14
|
+
skips: where resources are created and closed, how a session maps to a
|
|
15
|
+
transaction, what happens when someone calls blocking code inside `async def`,
|
|
16
|
+
and how to test all of it without a real network.
|
|
17
|
+
|
|
18
|
+
Language-level guidance (typing, dataclasses, Pydantic basics) is in
|
|
19
|
+
`python-patterns`; schema and migrations in `database-patterns`; test strategy
|
|
20
|
+
in `testing-backend`.
|
|
21
|
+
|
|
22
|
+
## 1. Layout
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
app/
|
|
26
|
+
main.py # create_app(): routers, middleware, handlers, lifespan
|
|
27
|
+
settings.py # pydantic-settings
|
|
28
|
+
db.py # engine, session factory, get_session dependency
|
|
29
|
+
errors.py # domain exceptions and handlers
|
|
30
|
+
notes/
|
|
31
|
+
router.py # HTTP only: parse, call service, return schema
|
|
32
|
+
schemas.py # NoteCreate, NoteUpdate, NoteRead
|
|
33
|
+
models.py # SQLAlchemy ORM classes
|
|
34
|
+
service.py # business rules
|
|
35
|
+
repository.py # queries
|
|
36
|
+
tests/
|
|
37
|
+
conftest.py
|
|
38
|
+
test_notes.py
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Keep routers thin. A router function that contains query logic and business
|
|
42
|
+
rules cannot be reused by a CLI command or a worker.
|
|
43
|
+
|
|
44
|
+
## 2. Core wiring
|
|
45
|
+
|
|
46
|
+
Load `references/app-structure.md` for the full code. The rules it implements:
|
|
47
|
+
|
|
48
|
+
- **Settings**: one `pydantic-settings` class read from the environment, cached
|
|
49
|
+
behind `get_settings()` so tests can override it; the app fails to start on a
|
|
50
|
+
missing or malformed value.
|
|
51
|
+
- **Lifespan**: `create_app()` builds routers, middleware and handlers; engines,
|
|
52
|
+
HTTP clients and caches are created in the `lifespan` context and closed on
|
|
53
|
+
shutdown, stored on `app.state`, never at import time.
|
|
54
|
+
- **Session per request**: a `get_session` dependency opens an `AsyncSession`
|
|
55
|
+
from an `async_sessionmaker(expire_on_commit=False)` and wraps it in
|
|
56
|
+
`session.begin()`, so the request commits on success and rolls back on any
|
|
57
|
+
exception. Relationships are loaded explicitly (`selectinload`), never lazily.
|
|
58
|
+
- **Schemas**: separate input models (`NoteCreate`, `NoteUpdate` with
|
|
59
|
+
`extra="forbid"`, no server-owned fields) from output models (`NoteRead`,
|
|
60
|
+
`from_attributes=True`); endpoints declare `response_model`.
|
|
61
|
+
- **Dependencies**: `Annotated` aliases (`SessionDep`, `CurrentUser`) compose
|
|
62
|
+
authentication, services and scoping; every query filters by the principal.
|
|
63
|
+
- **Errors**: services raise domain exceptions; one handler module maps them,
|
|
64
|
+
and `RequestValidationError`, to RFC 9457 problem details.
|
|
65
|
+
|
|
66
|
+
## 3. async def versus def
|
|
67
|
+
|
|
68
|
+
- `async def` endpoints run on the event loop. Any blocking call inside them
|
|
69
|
+
(a sync database driver, `requests`, `time.sleep`, heavy CPU work) stalls every
|
|
70
|
+
concurrent request.
|
|
71
|
+
- Plain `def` endpoints run in a thread pool. Use them when the code is
|
|
72
|
+
synchronous and you cannot change it.
|
|
73
|
+
- Offload blocking calls from async code with `await anyio.to_thread.run_sync(fn, ...)`;
|
|
74
|
+
CPU-bound work belongs in a process pool or a job queue.
|
|
75
|
+
- Use async clients throughout: `asyncpg` or `psycopg` 3 async under SQLAlchemy,
|
|
76
|
+
`httpx.AsyncClient`, `redis.asyncio`.
|
|
77
|
+
|
|
78
|
+
## 4. Background work
|
|
79
|
+
|
|
80
|
+
- `BackgroundTasks` runs after the response in the same process. It is fine for
|
|
81
|
+
best-effort, short work (an audit log line). It is lost on crash or deploy.
|
|
82
|
+
- Anything that must happen (emails, webhooks, report generation, retries) goes
|
|
83
|
+
to a durable queue: Celery, Dramatiq, arq, Taskiq, or a cloud queue. Make jobs
|
|
84
|
+
idempotent and keyed.
|
|
85
|
+
- Enqueue in the same transaction as the domain change using an outbox table
|
|
86
|
+
when losing the job would be a bug.
|
|
87
|
+
|
|
88
|
+
## 5. Testing and deployment
|
|
89
|
+
|
|
90
|
+
Tests create the app with `create_app()`, override dependencies such as
|
|
91
|
+
`get_current_user` and `get_settings`, and call it through `httpx.AsyncClient`
|
|
92
|
+
with `ASGITransport`. The transport does not run the lifespan, so wrap the app
|
|
93
|
+
in `asgi_lifespan.LifespanManager`. Fixtures, example tests and production
|
|
94
|
+
server settings (Uvicorn, proxy headers, instrumentation) are in
|
|
95
|
+
`references/testing-and-deployment.md`, together with notes on streaming
|
|
96
|
+
responses and WebSockets.
|
|
97
|
+
|
|
98
|
+
## Review checklist
|
|
99
|
+
|
|
100
|
+
- [ ] Resources are created in `lifespan` and closed on shutdown.
|
|
101
|
+
- [ ] One session per request, transaction committed or rolled back by the dependency.
|
|
102
|
+
- [ ] No blocking calls inside `async def`; relationships loaded explicitly.
|
|
103
|
+
- [ ] Input models forbid unknown and server-owned fields; responses use output models.
|
|
104
|
+
- [ ] Every query is scoped by the current principal.
|
|
105
|
+
- [ ] Domain exceptions map to problem details in one place.
|
|
106
|
+
- [ ] Durable work uses a queue, not `BackgroundTasks`.
|
|
107
|
+
- [ ] Tests use `AsyncClient` with lifespan and dependency overrides.
|
|
108
|
+
|
|
109
|
+
## References
|
|
110
|
+
|
|
111
|
+
- `references/app-structure.md`: settings, lifespan, session dependency, models, schemas, routers and error handlers in full.
|
|
112
|
+
- `references/testing-and-deployment.md`: test fixtures, dependency overrides, Uvicorn in production, streaming and WebSockets.
|
|
113
|
+
|
|
114
|
+
## Related skills
|
|
115
|
+
|
|
116
|
+
- `python-patterns`: typing, Pydantic, async fundamentals.
|
|
117
|
+
- `api-patterns`, `rest-api-design`: contract design.
|
|
118
|
+
- `api-security-best-practices`: authentication and authorization dependencies.
|
|
119
|
+
- `database-patterns`: schema, indexes, Alembic migrations.
|
|
120
|
+
- `testing-backend`: fixtures and test pyramid.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# FastAPI app structure
|
|
2
|
+
|
|
3
|
+
Worked code for the settings, app factory, per-request session, schemas, dependencies and error handlers summarised in SKILL.md.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Settings
|
|
8
|
+
- App factory and lifespan
|
|
9
|
+
- Database session per request
|
|
10
|
+
- Schemas: separate in from out
|
|
11
|
+
- Dependencies
|
|
12
|
+
- Errors
|
|
13
|
+
|
|
14
|
+
## Settings
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
# app/settings.py
|
|
18
|
+
from functools import lru_cache
|
|
19
|
+
from pydantic import PostgresDsn, SecretStr
|
|
20
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
21
|
+
|
|
22
|
+
class Settings(BaseSettings):
|
|
23
|
+
model_config = SettingsConfigDict(env_file=".env", env_prefix="APP_", extra="ignore")
|
|
24
|
+
|
|
25
|
+
environment: str = "development"
|
|
26
|
+
database_url: PostgresDsn
|
|
27
|
+
jwt_audience: str = "notes-api"
|
|
28
|
+
signing_key: SecretStr
|
|
29
|
+
db_pool_size: int = 10
|
|
30
|
+
|
|
31
|
+
@lru_cache
|
|
32
|
+
def get_settings() -> Settings:
|
|
33
|
+
return Settings()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`SecretStr` keeps secrets out of `repr` and logs. Because `get_settings` is a
|
|
37
|
+
dependency, tests override it instead of patching environment variables.
|
|
38
|
+
|
|
39
|
+
## App factory and lifespan
|
|
40
|
+
|
|
41
|
+
Create shared resources once per process in the lifespan and close them on
|
|
42
|
+
shutdown. Module-level engines and clients make tests and workers awkward.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
# app/main.py
|
|
46
|
+
from contextlib import asynccontextmanager
|
|
47
|
+
import httpx
|
|
48
|
+
from fastapi import FastAPI
|
|
49
|
+
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
50
|
+
|
|
51
|
+
from app.settings import get_settings
|
|
52
|
+
from app.errors import register_error_handlers
|
|
53
|
+
from app.notes.router import router as notes_router
|
|
54
|
+
|
|
55
|
+
@asynccontextmanager
|
|
56
|
+
async def lifespan(app: FastAPI):
|
|
57
|
+
settings = get_settings()
|
|
58
|
+
engine = create_async_engine(
|
|
59
|
+
str(settings.database_url), pool_size=settings.db_pool_size, pool_pre_ping=True
|
|
60
|
+
)
|
|
61
|
+
app.state.sessionmaker = async_sessionmaker(engine, expire_on_commit=False)
|
|
62
|
+
app.state.http = httpx.AsyncClient(timeout=httpx.Timeout(5.0))
|
|
63
|
+
try:
|
|
64
|
+
yield
|
|
65
|
+
finally:
|
|
66
|
+
await app.state.http.aclose()
|
|
67
|
+
await engine.dispose()
|
|
68
|
+
|
|
69
|
+
def create_app() -> FastAPI:
|
|
70
|
+
app = FastAPI(title="Notes API", lifespan=lifespan)
|
|
71
|
+
register_error_handlers(app)
|
|
72
|
+
app.include_router(notes_router, prefix="/notes", tags=["notes"])
|
|
73
|
+
return app
|
|
74
|
+
|
|
75
|
+
app = create_app()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The old `@app.on_event("startup")` hooks are deprecated; use `lifespan`.
|
|
79
|
+
|
|
80
|
+
## Database session per request
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
# app/db.py
|
|
84
|
+
from collections.abc import AsyncIterator
|
|
85
|
+
from typing import Annotated
|
|
86
|
+
from fastapi import Depends, Request
|
|
87
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
88
|
+
|
|
89
|
+
async def get_session(request: Request) -> AsyncIterator[AsyncSession]:
|
|
90
|
+
async with request.app.state.sessionmaker() as session:
|
|
91
|
+
async with session.begin():
|
|
92
|
+
yield session
|
|
93
|
+
|
|
94
|
+
SessionDep = Annotated[AsyncSession, Depends(get_session)]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- `session.begin()` commits when the request succeeds and rolls back when any
|
|
98
|
+
exception escapes, so handlers never call `commit()` themselves.
|
|
99
|
+
- `expire_on_commit=False` lets you return ORM objects after commit without
|
|
100
|
+
triggering lazy loads, which fail in async code.
|
|
101
|
+
- Lazy loading of relationships raises in async; load what you need explicitly
|
|
102
|
+
with `selectinload` or `joinedload`, or declare `lazy="raise"` to catch it in
|
|
103
|
+
tests.
|
|
104
|
+
|
|
105
|
+
Models with SQLAlchemy 2.0 typing:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# app/notes/models.py
|
|
109
|
+
from datetime import datetime
|
|
110
|
+
from sqlalchemy import ForeignKey, String, func
|
|
111
|
+
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
112
|
+
|
|
113
|
+
class Base(DeclarativeBase):
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
class Note(Base):
|
|
117
|
+
__tablename__ = "notes"
|
|
118
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
119
|
+
owner_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
|
|
120
|
+
title: Mapped[str] = mapped_column(String(200))
|
|
121
|
+
body: Mapped[str]
|
|
122
|
+
created_at: Mapped[datetime] = mapped_column(server_default=func.now())
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Migrations: Alembic with the async template (`alembic init -t async`), run as a
|
|
126
|
+
deploy step, never from the app's lifespan.
|
|
127
|
+
|
|
128
|
+
## Schemas: separate in from out
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# app/notes/schemas.py
|
|
132
|
+
from datetime import datetime
|
|
133
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
134
|
+
|
|
135
|
+
class NoteCreate(BaseModel):
|
|
136
|
+
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
|
137
|
+
title: str = Field(min_length=1, max_length=200)
|
|
138
|
+
body: str = Field(max_length=20_000)
|
|
139
|
+
|
|
140
|
+
class NoteUpdate(BaseModel):
|
|
141
|
+
model_config = ConfigDict(extra="forbid")
|
|
142
|
+
title: str | None = Field(default=None, min_length=1, max_length=200)
|
|
143
|
+
body: str | None = Field(default=None, max_length=20_000)
|
|
144
|
+
|
|
145
|
+
class NoteRead(BaseModel):
|
|
146
|
+
model_config = ConfigDict(from_attributes=True)
|
|
147
|
+
id: int
|
|
148
|
+
title: str
|
|
149
|
+
body: str
|
|
150
|
+
created_at: datetime
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- Input models forbid unknown fields and never include `id` or `owner_id`.
|
|
154
|
+
- Output models are what the client may see; set `response_model` (or the return
|
|
155
|
+
annotation) so FastAPI filters the ORM object through it.
|
|
156
|
+
- For PATCH, apply only fields the client sent: `data.model_dump(exclude_unset=True)`.
|
|
157
|
+
|
|
158
|
+
## Dependencies
|
|
159
|
+
|
|
160
|
+
Dependencies are FastAPI's composition tool: authentication, sessions, settings,
|
|
161
|
+
pagination, feature flags.
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# app/notes/router.py
|
|
165
|
+
from typing import Annotated
|
|
166
|
+
from fastapi import APIRouter, Depends, Query, status
|
|
167
|
+
|
|
168
|
+
from app.db import SessionDep
|
|
169
|
+
from app.auth import CurrentUser
|
|
170
|
+
from app.notes import service
|
|
171
|
+
from app.notes.schemas import NoteCreate, NoteRead
|
|
172
|
+
|
|
173
|
+
router = APIRouter()
|
|
174
|
+
|
|
175
|
+
class Page:
|
|
176
|
+
def __init__(self, limit: Annotated[int, Query(ge=1, le=100)] = 20, after: int | None = None):
|
|
177
|
+
self.limit, self.after = limit, after
|
|
178
|
+
|
|
179
|
+
@router.get("", response_model=list[NoteRead])
|
|
180
|
+
async def list_notes(user: CurrentUser, session: SessionDep, page: Annotated[Page, Depends()]):
|
|
181
|
+
return await service.list_for_owner(session, user.id, page.limit, page.after)
|
|
182
|
+
|
|
183
|
+
@router.post("", response_model=NoteRead, status_code=status.HTTP_201_CREATED)
|
|
184
|
+
async def create_note(data: NoteCreate, user: CurrentUser, session: SessionDep):
|
|
185
|
+
return await service.create(session, owner_id=user.id, data=data)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- Declare reusable aliases with `Annotated[..., Depends(...)]` (`SessionDep`,
|
|
189
|
+
`CurrentUser`) instead of repeating `Depends` in every signature.
|
|
190
|
+
- Dependencies are cached per request: two dependencies that both need the
|
|
191
|
+
session get the same one.
|
|
192
|
+
- Dependencies with `yield` run their cleanup after the response is produced; use
|
|
193
|
+
them for anything that must be released.
|
|
194
|
+
- Router-level `dependencies=[Depends(require_scope("notes:write"))]` applies
|
|
195
|
+
authorization to a whole group of routes.
|
|
196
|
+
|
|
197
|
+
Scope every query by the current user (`WHERE owner_id = :user_id`); see
|
|
198
|
+
`api-security-best-practices` for object-level authorization.
|
|
199
|
+
|
|
200
|
+
## Errors
|
|
201
|
+
|
|
202
|
+
Raise domain exceptions from services and translate them once.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
# app/errors.py
|
|
206
|
+
from fastapi import FastAPI, Request
|
|
207
|
+
from fastapi.exceptions import RequestValidationError
|
|
208
|
+
from fastapi.responses import JSONResponse
|
|
209
|
+
|
|
210
|
+
class DomainError(Exception):
|
|
211
|
+
status = 400
|
|
212
|
+
code = "bad-request"
|
|
213
|
+
def __init__(self, detail: str):
|
|
214
|
+
self.detail = detail
|
|
215
|
+
|
|
216
|
+
class NotFound(DomainError):
|
|
217
|
+
status, code = 404, "not-found"
|
|
218
|
+
|
|
219
|
+
def _problem(status: int, code: str, title: str, request: Request, **extra) -> JSONResponse:
|
|
220
|
+
body = {"type": f"https://api.example.com/problems/{code}", "title": title,
|
|
221
|
+
"status": status, "instance": str(request.url.path), **extra}
|
|
222
|
+
return JSONResponse(body, status_code=status, media_type="application/problem+json")
|
|
223
|
+
|
|
224
|
+
def register_error_handlers(app: FastAPI) -> None:
|
|
225
|
+
@app.exception_handler(DomainError)
|
|
226
|
+
async def domain(request: Request, exc: DomainError):
|
|
227
|
+
return _problem(exc.status, exc.code, exc.detail, request)
|
|
228
|
+
|
|
229
|
+
@app.exception_handler(RequestValidationError)
|
|
230
|
+
async def validation(request: Request, exc: RequestValidationError):
|
|
231
|
+
errors = [{"loc": e["loc"], "detail": e["msg"]} for e in exc.errors()]
|
|
232
|
+
return _problem(422, "validation", "Request is invalid", request, errors=errors)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Services then stay free of HTTP: `raise NotFound("note not found")`.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Testing, Deployment and Streaming
|
|
2
|
+
|
|
3
|
+
Companion to the FastAPI skill: testing an app built with `create_app()` and a lifespan, and running it in production.
|
|
4
|
+
|
|
5
|
+
## Testing
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
# tests/conftest.py
|
|
9
|
+
import pytest
|
|
10
|
+
from asgi_lifespan import LifespanManager
|
|
11
|
+
from httpx import ASGITransport, AsyncClient
|
|
12
|
+
|
|
13
|
+
from app.main import create_app
|
|
14
|
+
from app.auth import get_current_user
|
|
15
|
+
|
|
16
|
+
@pytest.fixture
|
|
17
|
+
async def client(test_user):
|
|
18
|
+
app = create_app()
|
|
19
|
+
app.dependency_overrides[get_current_user] = lambda: test_user
|
|
20
|
+
async with LifespanManager(app):
|
|
21
|
+
transport = ASGITransport(app=app)
|
|
22
|
+
async with AsyncClient(transport=transport, base_url="http://test") as c:
|
|
23
|
+
yield c
|
|
24
|
+
app.dependency_overrides.clear()
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# tests/test_notes.py
|
|
29
|
+
async def test_create_rejects_unknown_fields(client):
|
|
30
|
+
res = await client.post("/notes", json={"title": "a", "body": "b", "owner_id": 9})
|
|
31
|
+
assert res.status_code == 422
|
|
32
|
+
|
|
33
|
+
async def test_create_then_read(client):
|
|
34
|
+
created = await client.post("/notes", json={"title": "Shopping", "body": "milk"})
|
|
35
|
+
assert created.status_code == 201
|
|
36
|
+
note_id = created.json()["id"]
|
|
37
|
+
fetched = await client.get(f"/notes/{note_id}")
|
|
38
|
+
assert fetched.json()["title"] == "Shopping"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- `ASGITransport` does not run the lifespan; wrap the app in
|
|
42
|
+
`asgi_lifespan.LifespanManager` (or use the sync `TestClient` as a context
|
|
43
|
+
manager) so resources exist.
|
|
44
|
+
- Run async tests with `pytest-asyncio` (`asyncio_mode = "auto"`) or AnyIO's
|
|
45
|
+
pytest plugin.
|
|
46
|
+
- Override dependencies (`get_settings`, `get_current_user`, `get_session`)
|
|
47
|
+
rather than monkeypatching modules.
|
|
48
|
+
- For database tests, run Postgres in Testcontainers and wrap each test in a
|
|
49
|
+
transaction that is rolled back, or truncate between tests.
|
|
50
|
+
|
|
51
|
+
## Running in production
|
|
52
|
+
|
|
53
|
+
- `fastapi run` (Uvicorn under the hood) or Uvicorn directly behind a reverse
|
|
54
|
+
proxy; one process per container and scale horizontally, or use
|
|
55
|
+
`--workers` on a single VM.
|
|
56
|
+
- Set `--proxy-headers` and `--forwarded-allow-ips` to your load balancer so
|
|
57
|
+
client IPs and schemes are correct.
|
|
58
|
+
- Disable or protect `/docs` and `/openapi.json` on internal-only APIs if
|
|
59
|
+
exposure is a concern.
|
|
60
|
+
- Instrument with OpenTelemetry (`opentelemetry-instrumentation-fastapi`,
|
|
61
|
+
`-sqlalchemy`, `-httpx`) and emit structured JSON logs.
|
|
62
|
+
|
|
63
|
+
## Streaming and WebSockets
|
|
64
|
+
|
|
65
|
+
- `StreamingResponse` with an async generator for large exports; server-sent
|
|
66
|
+
events for one-way live updates.
|
|
67
|
+
- WebSockets: authenticate during the handshake (token in a query parameter or
|
|
68
|
+
subprotocol, since browsers cannot set headers), handle `WebSocketDisconnect`,
|
|
69
|
+
and use a broker (Redis pub/sub) when more than one process must broadcast.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: firebase
|
|
3
3
|
description: "You're a developer who has shipped dozens of Firebase projects. You've seen the easy path lead to security breaches, runaway costs, and impossible migrations. You know Firebase is powerful, but you also know its sharp edges. Use when integrating or reviewing Firebase: auth, Firestore, functions, or its cost and scaling traps."
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
metadata:
|
|
5
|
+
risk: unknown
|
|
6
|
+
source: "vibeforge1111/vibeship-spawner-skills (Apache 2.0)"
|
|
7
|
+
date_added: "2026-02-27"
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# Firebase
|