From 434258209ad82089836a9930d0d6bb819f6212b0 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Fri, 9 Oct 2026 10:44:35 -0400 Subject: [PATCH] init: Add pre-existing skills --- .github/skills/absurd/SKILL.md | 256 + .github/skills/blume-migrate/SKILL.md | 182 + .../blume-migrate/assets/oxfmt@0.67.0.patch | 49 + .../blume-migrate/references/docusaurus.md | 98 + .../blume-migrate/references/fumadocs.md | 107 + .../blume-migrate/references/mintlify.md | 190 + .../blume-migrate/references/monorepo.md | 225 + .../skills/blume-migrate/references/nextra.md | 79 + .../blume-migrate/references/starlight.md | 119 + .../scripts/mintlify-codemod.mjs | 529 + .github/skills/blume-update-docs/SKILL.md | 53 + .../references/audit-checklist.md | 46 + .github/skills/blume/SKILL.md | 91 + .../skills/cloudflare-email-service/SKILL.md | 73 + .../references/cli-and-mcp.md | 125 + .../references/deliverability.md | 285 + .../references/rest-api.md | 17 + .../references/routing.md | 199 + .../references/sending.md | 19 + .github/skills/cloudflare/SKILL.md | 139 + .../references/ai-gateway/README.md | 27 + .../references/ai-gateway/configuration.md | 18 + .../references/ai-gateway/dynamic-routing.md | 15 + .../references/ai-gateway/features.md | 22 + .../references/ai-gateway/sdk-integration.md | 19 + .../references/ai-gateway/troubleshooting.md | 16 + .../cloudflare/references/ai-search/README.md | 25 + .../cloudflare/references/ai-search/api.md | 13 + .../references/ai-search/configuration.md | 16 + .../references/ai-search/gotchas.md | 13 + .../references/ai-search/patterns.md | 15 + .../references/analytics-engine/README.md | 94 + .../references/analytics-engine/api.md | 112 + .../analytics-engine/configuration.md | 112 + .../references/analytics-engine/gotchas.md | 85 + .../references/analytics-engine/patterns.md | 83 + .../references/api-shield/README.md | 44 + .../cloudflare/references/api-shield/api.md | 141 + .../references/api-shield/configuration.md | 192 + .../references/api-shield/gotchas.md | 125 + .../references/api-shield/patterns.md | 180 + .../cloudflare/references/api/README.md | 66 + .../skills/cloudflare/references/api/api.md | 204 + .../references/api/configuration.md | 160 + .../cloudflare/references/api/gotchas.md | 225 + .../cloudflare/references/api/patterns.md | 204 + .../references/argo-smart-routing/README.md | 90 + .../references/argo-smart-routing/api.md | 240 + .../argo-smart-routing/configuration.md | 197 + .../references/argo-smart-routing/gotchas.md | 111 + .../references/argo-smart-routing/patterns.md | 104 + .../cloudflare/references/artifacts/README.md | 79 + .../cloudflare/references/artifacts/api.md | 128 + .../references/artifacts/configuration.md | 92 + .../cloudflare/references/bindings/README.md | 16 + .../cloudflare/references/bindings/api.md | 19 + .../references/bindings/configuration.md | 20 + .../cloudflare/references/bindings/gotchas.md | 18 + .../references/bindings/patterns.md | 20 + .../references/bot-management/README.md | 94 + .../references/bot-management/api.md | 169 + .../bot-management/configuration.md | 163 + .../references/bot-management/gotchas.md | 114 + .../references/bot-management/patterns.md | 182 + .../references/browser-rendering/README.md | 18 + .../references/browser-rendering/api.md | 12 + .../browser-rendering/configuration.md | 12 + .../references/browser-rendering/gotchas.md | 15 + .../references/browser-rendering/patterns.md | 12 + .../skills/cloudflare/references/c3/README.md | 112 + .../skills/cloudflare/references/c3/api.md | 70 + .../cloudflare/references/c3/configuration.md | 81 + .../cloudflare/references/c3/gotchas.md | 92 + .../cloudflare/references/c3/patterns.md | 80 + .../references/cache-reserve/README.md | 147 + .../references/cache-reserve/api.md | 194 + .../references/cache-reserve/configuration.md | 169 + .../references/cache-reserve/gotchas.md | 132 + .../references/cache-reserve/patterns.md | 197 + .../references/containers/README.md | 23 + .../cloudflare/references/containers/api.md | 13 + .../references/containers/configuration.md | 15 + .../references/containers/gotchas.md | 16 + .../references/containers/patterns.md | 18 + .../references/cron-triggers/README.md | 20 + .../references/cron-triggers/api.md | 16 + .../references/cron-triggers/configuration.md | 16 + .../references/cron-triggers/gotchas.md | 17 + .../references/cron-triggers/patterns.md | 18 + .../skills/cloudflare/references/d1/README.md | 15 + .../skills/cloudflare/references/d1/api.md | 18 + .../cloudflare/references/d1/configuration.md | 18 + .../cloudflare/references/d1/gotchas.md | 18 + .../cloudflare/references/d1/patterns.md | 20 + .../cloudflare/references/ddos/README.md | 41 + .../skills/cloudflare/references/ddos/api.md | 164 + .../references/ddos/configuration.md | 93 + .../cloudflare/references/ddos/gotchas.md | 107 + .../cloudflare/references/ddos/patterns.md | 174 + .../references/do-storage/README.md | 16 + .../cloudflare/references/do-storage/api.md | 14 + .../references/do-storage/configuration.md | 16 + .../references/do-storage/gotchas.md | 15 + .../references/do-storage/patterns.md | 15 + .../references/do-storage/testing.md | 13 + .../references/email-routing/README.md | 19 + .../references/email-routing/api.md | 13 + .../references/email-routing/configuration.md | 13 + .../references/email-routing/gotchas.md | 15 + .../references/email-routing/patterns.md | 13 + .../references/email-workers/README.md | 18 + .../references/email-workers/api.md | 15 + .../references/email-workers/configuration.md | 16 + .../references/email-workers/gotchas.md | 15 + .../references/email-workers/patterns.md | 16 + .../cloudflare/references/flagship/README.md | 59 + .../cloudflare/references/flagship/api.md | 390 + .../references/flagship/configuration.md | 202 + .../cloudflare/references/flagship/gotchas.md | 178 + .../references/flagship/patterns.md | 469 + .../references/graphql-api/README.md | 147 + .../cloudflare/references/graphql-api/api.md | 175 + .../references/graphql-api/configuration.md | 118 + .../references/graphql-api/gotchas.md | 110 + .../references/graphql-api/patterns.md | 225 + .../references/hyperdrive/README.md | 27 + .../cloudflare/references/hyperdrive/api.md | 26 + .../references/hyperdrive/configuration.md | 27 + .../references/hyperdrive/gotchas.md | 20 + .../references/hyperdrive/patterns.md | 15 + .../cloudflare/references/images/README.md | 12 + .../cloudflare/references/images/api.md | 13 + .../references/images/configuration.md | 17 + .../cloudflare/references/images/gotchas.md | 16 + .../cloudflare/references/images/patterns.md | 16 + .../skills/cloudflare/references/kv/README.md | 15 + .../skills/cloudflare/references/kv/api.md | 18 + .../cloudflare/references/kv/configuration.md | 16 + .../cloudflare/references/kv/gotchas.md | 17 + .../cloudflare/references/kv/patterns.md | 21 + .../cloudflare/references/miniflare/README.md | 22 + .../cloudflare/references/miniflare/api.md | 16 + .../references/miniflare/configuration.md | 16 + .../references/miniflare/gotchas.md | 15 + .../references/miniflare/patterns.md | 19 + .../references/network-interconnect/README.md | 99 + .../references/network-interconnect/api.md | 199 + .../network-interconnect/configuration.md | 114 + .../network-interconnect/gotchas.md | 165 + .../network-interconnect/patterns.md | 166 + .../references/observability/README.md | 27 + .../references/observability/api.md | 20 + .../references/observability/configuration.md | 23 + .../references/observability/gotchas.md | 25 + .../references/observability/patterns.md | 14 + .../references/pages-functions/README.md | 20 + .../references/pages-functions/api.md | 13 + .../pages-functions/configuration.md | 14 + .../references/pages-functions/gotchas.md | 17 + .../references/pages-functions/patterns.md | 16 + .../cloudflare/references/pages/README.md | 20 + .../skills/cloudflare/references/pages/api.md | 13 + .../references/pages/configuration.md | 16 + .../cloudflare/references/pages/gotchas.md | 19 + .../cloudflare/references/pages/patterns.md | 15 + .../cloudflare/references/pipelines/README.md | 90 + .../cloudflare/references/pipelines/api.md | 124 + .../references/pipelines/configuration.md | 155 + .../references/pipelines/gotchas.md | 58 + .../references/pipelines/patterns.md | 130 + .../cloudflare/references/pulumi/README.md | 100 + .../cloudflare/references/pulumi/api.md | 200 + .../references/pulumi/configuration.md | 198 + .../cloudflare/references/pulumi/gotchas.md | 181 + .../cloudflare/references/pulumi/patterns.md | 191 + .../cloudflare/references/queues/README.md | 24 + .../cloudflare/references/queues/api.md | 16 + .../references/queues/configuration.md | 20 + .../cloudflare/references/queues/gotchas.md | 18 + .../cloudflare/references/queues/patterns.md | 21 + .../references/r2-data-catalog/README.md | 16 + .../references/r2-data-catalog/api.md | 47 + .../r2-data-catalog/configuration.md | 17 + .../references/r2-data-catalog/gotchas.md | 18 + .../references/r2-data-catalog/patterns.md | 17 + .../cloudflare/references/r2-sql/README.md | 64 + .../cloudflare/references/r2-sql/api.md | 121 + .../references/r2-sql/configuration.md | 50 + .../cloudflare/references/r2-sql/gotchas.md | 39 + .../cloudflare/references/r2-sql/patterns.md | 118 + .../skills/cloudflare/references/r2/README.md | 26 + .../skills/cloudflare/references/r2/api.md | 16 + .../cloudflare/references/r2/configuration.md | 19 + .../cloudflare/references/r2/gotchas.md | 17 + .../cloudflare/references/r2/patterns.md | 18 + .../references/realtime-sfu/README.md | 65 + .../cloudflare/references/realtime-sfu/api.md | 158 + .../references/realtime-sfu/configuration.md | 137 + .../references/realtime-sfu/gotchas.md | 133 + .../references/realtime-sfu/patterns.md | 174 + .../references/realtimekit/README.md | 113 + .../cloudflare/references/realtimekit/api.md | 212 + .../references/realtimekit/configuration.md | 203 + .../references/realtimekit/gotchas.md | 169 + .../references/realtimekit/patterns.md | 223 + .../references/secrets-store/README.md | 22 + .../references/secrets-store/api.md | 21 + .../references/secrets-store/configuration.md | 25 + .../references/secrets-store/gotchas.md | 19 + .../references/secrets-store/patterns.md | 27 + .../references/smart-placement/README.md | 138 + .../references/smart-placement/api.md | 183 + .../smart-placement/configuration.md | 196 + .../references/smart-placement/gotchas.md | 174 + .../references/smart-placement/patterns.md | 183 + .../cloudflare/references/snippets/README.md | 68 + .../cloudflare/references/snippets/api.md | 198 + .../references/snippets/configuration.md | 227 + .../cloudflare/references/snippets/gotchas.md | 86 + .../references/snippets/patterns.md | 135 + .../cloudflare/references/spectrum/README.md | 52 + .../cloudflare/references/spectrum/api.md | 181 + .../references/spectrum/configuration.md | 194 + .../cloudflare/references/spectrum/gotchas.md | 145 + .../references/spectrum/patterns.md | 196 + .../references/static-assets/README.md | 21 + .../references/static-assets/api.md | 16 + .../references/static-assets/configuration.md | 16 + .../references/static-assets/gotchas.md | 18 + .../references/static-assets/patterns.md | 17 + .../cloudflare/references/stream/README.md | 22 + .../cloudflare/references/stream/api-live.md | 18 + .../cloudflare/references/stream/api.md | 21 + .../references/stream/configuration.md | 18 + .../cloudflare/references/stream/gotchas.md | 18 + .../cloudflare/references/stream/patterns.md | 22 + .../references/tail-workers/README.md | 21 + .../cloudflare/references/tail-workers/api.md | 13 + .../references/tail-workers/configuration.md | 15 + .../references/tail-workers/gotchas.md | 16 + .../references/tail-workers/patterns.md | 15 + .../cloudflare/references/terraform/README.md | 102 + .../cloudflare/references/terraform/api.md | 178 + .../references/terraform/configuration.md | 197 + .../references/terraform/gotchas.md | 150 + .../references/terraform/patterns.md | 174 + .../cloudflare/references/tunnel/README.md | 20 + .../cloudflare/references/tunnel/api.md | 14 + .../references/tunnel/configuration.md | 14 + .../cloudflare/references/tunnel/gotchas.md | 15 + .../references/tunnel/networking.md | 14 + .../cloudflare/references/tunnel/patterns.md | 15 + .../cloudflare/references/turn/README.md | 82 + .../skills/cloudflare/references/turn/api.md | 239 + .../references/turn/configuration.md | 179 + .../cloudflare/references/turn/gotchas.md | 231 + .../cloudflare/references/turn/patterns.md | 213 + .../cloudflare/references/vectorize/README.md | 22 + .../cloudflare/references/vectorize/api.md | 18 + .../references/vectorize/configuration.md | 19 + .../references/vectorize/gotchas.md | 15 + .../references/vectorize/patterns.md | 24 + .../cloudflare/references/waf/README.md | 21 + .../skills/cloudflare/references/waf/api.md | 17 + .../references/waf/configuration.md | 18 + .../cloudflare/references/waf/gotchas.md | 19 + .../cloudflare/references/waf/patterns.md | 17 + .../references/web-analytics/README.md | 141 + .../references/web-analytics/configuration.md | 76 + .../references/web-analytics/gotchas.md | 82 + .../references/web-analytics/integration.md | 60 + .../references/web-analytics/patterns.md | 91 + .../cloudflare/references/workerd/README.md | 78 + .../cloudflare/references/workerd/api.md | 185 + .../references/workerd/configuration.md | 183 + .../cloudflare/references/workerd/gotchas.md | 139 + .../cloudflare/references/workerd/patterns.md | 192 + .../references/workers-ai/README.md | 24 + .../cloudflare/references/workers-ai/api.md | 13 + .../references/workers-ai/configuration.md | 16 + .../references/workers-ai/gotchas.md | 15 + .../references/workers-ai/patterns.md | 14 + .../workers-for-platforms/README.md | 89 + .../references/workers-for-platforms/api.md | 196 + .../workers-for-platforms/configuration.md | 167 + .../workers-for-platforms/gotchas.md | 134 + .../workers-for-platforms/patterns.md | 188 + .../references/workers-playground/README.md | 127 + .../references/workers-playground/api.md | 101 + .../workers-playground/configuration.md | 163 + .../references/workers-playground/gotchas.md | 88 + .../references/workers-playground/patterns.md | 132 + .../references/workers-vpc/README.md | 127 + .../cloudflare/references/workers-vpc/api.md | 202 + .../references/workers-vpc/configuration.md | 147 + .../references/workers-vpc/gotchas.md | 167 + .../references/workers-vpc/patterns.md | 209 + .../cloudflare/references/workflows/README.md | 23 + .../cloudflare/references/workflows/api.md | 17 + .../references/workflows/configuration.md | 18 + .../references/workflows/gotchas.md | 19 + .../references/workflows/patterns.md | 30 + .../zaraz/IMPLEMENTATION_SUMMARY.md | 121 + .../cloudflare/references/zaraz/README.md | 111 + .../skills/cloudflare/references/zaraz/api.md | 112 + .../references/zaraz/configuration.md | 90 + .../cloudflare/references/zaraz/gotchas.md | 81 + .../cloudflare/references/zaraz/patterns.md | 74 + .github/skills/codebase-design/DEEPENING.md | 37 + .../skills/codebase-design/DESIGN-IT-TWICE.md | 44 + .github/skills/codebase-design/SKILL.md | 114 + .../skills/codebase-design/agents/openai.yaml | 3 + .github/skills/deepinit/SKILL.md | 344 + .github/skills/design-taste-frontend/SKILL.md | 1206 + .github/skills/durable-objects/SKILL.md | 180 + .../durable-objects/references/rules.md | 19 + .../durable-objects/references/testing.md | 23 + .../durable-objects/references/workers.md | 346 + .github/skills/find-skills/SKILL.md | 141 + .github/skills/golang-pro/SKILL.md | 124 + .../golang-pro/references/concurrency.md | 329 + .../skills/golang-pro/references/generics.md | 442 + .../golang-pro/references/interfaces.md | 432 + .../references/project-structure.md | 477 + .../skills/golang-pro/references/testing.md | 451 + .github/skills/grill-me/SKILL.md | 7 + .github/skills/grill-me/agents/openai.yaml | 5 + .github/skills/grill-with-docs/SKILL.md | 7 + .../skills/grill-with-docs/agents/openai.yaml | 5 + .github/skills/grilling/SKILL.md | 28 + .github/skills/grilling/agents/openai.yaml | 3 + .github/skills/gum/.skillfish.json | 10 + .github/skills/gum/SKILL.md | 125 + .github/skills/gum/agents/openai.yaml | 4 + .github/skills/gum/references/commands.md | 427 + .github/skills/gum/references/recipes.md | 278 + .../skills/high-end-visual-design/SKILL.md | 98 + .../HTML-REPORT.md | 123 + .../improve-codebase-architecture/SKILL.md | 71 + .../agents/openai.yaml | 5 + .github/skills/interface-design/SKILL.md | 320 + .../interface-design/agents/openai.yaml | 6 + .github/skills/laws-of-ux/SKILL.md | 979 + .github/skills/minimalist-ui/SKILL.md | 85 + .github/skills/no-ai-slop/SKILL.md | 97 + .github/skills/no-ai-slop/agents/openai.yaml | 4 + .github/skills/no-ai-slop/eval.md | 43 + .github/skills/obscura/SKILL.md | 130 + .github/skills/obsidian-vault/SKILL.md | 59 + .github/skills/openlogs-server-logs/SKILL.md | 56 + .../openlogs-server-logs/agents/openai.yaml | 4 + .github/skills/pr-lens/LICENSE | 21 + .github/skills/pr-lens/SKILL.md | 382 + .github/skills/pr-lens/references/config.md | 100 + .../pr-lens/references/example.graph.json | 685 + .../pr-lens/references/graph-document.md | 311 + .github/skills/prototype/LOGIC.md | 67 + .github/skills/prototype/SKILL.md | 26 + .github/skills/prototype/UI.md | 112 + .github/skills/prototype/agents/openai.yaml | 3 + .github/skills/qa/SKILL.md | 130 + .github/skills/react-email/SKILL.md | 175 + .github/skills/react/SKILL.md | 298 + .../skills/remotion-best-practices/SKILL.md | 100 + .../agents/openai.yaml | 7 + .../assets/remotion-icon.svg | 4 + .../remotion-captions/REFERENCE.md | 42 + .../remotion-captions/agents/openai.yaml | 7 + .../assets/remotion-icon.svg | 4 + .../remotion-captions/display-captions.md | 102 + .../remotion-captions/import-srt-captions.md | 73 + .../remotion-captions/transcribe-captions.md | 170 + .../remotion-create/REFERENCE.md | 71 + .../remotion-create/agents/openai.yaml | 7 + .../remotion-create/assets/remotion-icon.svg | 4 + .../remotion-create/tailwind.md | 11 + .../remotion-create/video-layout.md | 9 + .../remotion-docs/REFERENCE.md | 46 + .../remotion-docs/agents/openai.yaml | 7 + .../remotion-docs/assets/remotion-icon.svg | 4 + .../remotion-interactivity/REFERENCE.md | 344 + .../remotion-interactivity/agents/openai.yaml | 7 + .../assets/remotion-icon.svg | 4 + .../remotion-maps/REFERENCE.md | 36 + .../remotion-maps/agents/openai.yaml | 7 + .../remotion-maps/assets/remotion-icon.svg | 4 + .../techniques/cesium/TECHNIQUE.md | 89 + .../cesium/assets/CesiumFlythrough.tsx | 284 + .../techniques/cesium/assets/cesium-path.json | 299 + .../techniques/cesium/assets/city-path.json | 12 + .../techniques/cesium/assets/example-Root.tsx | 39 + .../techniques/cesium/assets/flight-path.ts | 35 + .../cesium/assets/sample-river.geojson | 215 + .../cesium/references/3d-data-sources.md | 43 + .../references/3d-flyover-architecture.md | 128 + .../cesium/references/3d-troubleshooting.md | 57 + .../cesium/scripts/prep-cesium-path.mjs | 161 + .../techniques/mapbox/TECHNIQUE.md | 449 + .../mapbox/references/render-stability.md | 64 + .../techniques/maplibre/TECHNIQUE.md | 484 + .../maplibre/references/render-stability.md | 64 + .../techniques/maptiler/TECHNIQUE.md | 80 + .../maptiler/assets/CountryLabel.tsx | 70 + .../maptiler/assets/MapTilerVectorElement.ts | 80 + .../maptiler/assets/RiverReveal.tsx | 363 + .../maptiler/assets/example-Root.tsx | 22 + .../assets/sample-data/country-meta.json | 7535 ++++ .../assets/sample-data/yarlung-flow.json | 605 + .../techniques/maptiler/assets/tokens.ts | 34 + .../maptiler/references/map-data-sources.md | 91 + .../references/map-explainer-architecture.md | 129 + .../maptiler/references/map-geo-prep.md | 85 + .../maptiler/references/render-stability.md | 64 + .../techniques/maptiler/scripts/prep-geo.mjs | 202 + .../techniques/static-map/TECHNIQUE.md | 37 + .../remotion-markup/3d.md | 86 + .../remotion-markup/REFERENCE.md | 391 + .../remotion-markup/agents/openai.yaml | 7 + .../remotion-markup/assets/remotion-icon.svg | 4 + .../remotion-markup/audio-visualization.md | 198 + .../remotion-markup/audio.md | 180 + .../remotion-markup/calculate-metadata.md | 136 + .../remotion-markup/compositions.md | 175 + .../remotion-markup/connected-compositions.md | 85 + .../remotion-markup/cropping.md | 34 + .../remotion-markup/effects.md | 252 + .../remotion-markup/embedding-videos.md | 175 + .../remotion-markup/ffmpeg.md | 38 + .../remotion-markup/gifs.md | 187 + .../remotion-markup/google-fonts.md | 76 + .../remotion-markup/html-in-canvas.md | 128 + .../remotion-markup/images.md | 71 + .../remotion-markup/light-leaks.md | 106 + .../remotion-markup/local-fonts.md | 69 + .../remotion-markup/lottie.md | 73 + .../remotion-markup/measuring-dom-nodes.md | 38 + .../remotion-markup/measuring-text.md | 146 + .../remotion-markup/motion-blur.md | 60 + .../remotion-markup/multi-scene-video.md | 88 + .../remotion-markup/parameters.md | 111 + .../remotion-maps/REFERENCE.md | 36 + .../remotion-maps/agents/openai.yaml | 7 + .../remotion-maps/assets/remotion-icon.svg | 4 + .../techniques/cesium/TECHNIQUE.md | 89 + .../cesium/assets/CesiumFlythrough.tsx | 284 + .../techniques/cesium/assets/cesium-path.json | 299 + .../techniques/cesium/assets/city-path.json | 12 + .../techniques/cesium/assets/example-Root.tsx | 39 + .../techniques/cesium/assets/flight-path.ts | 35 + .../cesium/assets/sample-river.geojson | 215 + .../cesium/references/3d-data-sources.md | 43 + .../references/3d-flyover-architecture.md | 128 + .../cesium/references/3d-troubleshooting.md | 57 + .../cesium/scripts/prep-cesium-path.mjs | 161 + .../techniques/mapbox/TECHNIQUE.md | 449 + .../mapbox/references/render-stability.md | 64 + .../techniques/maplibre/TECHNIQUE.md | 484 + .../maplibre/references/render-stability.md | 64 + .../techniques/maptiler/TECHNIQUE.md | 80 + .../maptiler/assets/CountryLabel.tsx | 70 + .../maptiler/assets/MapTilerVectorElement.ts | 80 + .../maptiler/assets/RiverReveal.tsx | 363 + .../maptiler/assets/example-Root.tsx | 22 + .../assets/sample-data/country-meta.json | 7535 ++++ .../assets/sample-data/yarlung-flow.json | 605 + .../techniques/maptiler/assets/tokens.ts | 34 + .../maptiler/references/map-data-sources.md | 91 + .../references/map-explainer-architecture.md | 129 + .../maptiler/references/map-geo-prep.md | 85 + .../maptiler/references/render-stability.md | 64 + .../techniques/maptiler/scripts/prep-geo.mjs | 202 + .../techniques/static-map/TECHNIQUE.md | 37 + .../remotion-markup/sequencing.md | 169 + .../remotion-markup/sfx.md | 51 + .../remotion-markup/silence-detection.md | 71 + .../remotion-markup/text-highlights.md | 56 + .../remotion-markup/timing.md | 111 + .../remotion-markup/transitions.md | 239 + .../remotion-markup/video-editing.md | 135 + .../remotion-markup/voiceover.md | 99 + .../remotion-multimedia/REFERENCE.md | 20 + .../remotion-multimedia/agents/openai.yaml | 7 + .../assets/remotion-icon.svg | 4 + .../remotion-multimedia/get-audio-duration.md | 61 + .../get-video-dimensions.md | 72 + .../remotion-multimedia/get-video-duration.md | 61 + .../remotion-render/REFERENCE.md | 35 + .../remotion-render/agents/openai.yaml | 7 + .../remotion-render/assets/remotion-icon.svg | 4 + .../remotion-render/transparent-videos.md | 106 + .../remotion-saas/REFERENCE.md | 33 + .../remotion-saas/agents/openai.yaml | 7 + .../remotion-saas/assets/remotion-icon.svg | 4 + .../remotion-saas/framework.md | 19 + .../remotion-saas/player.md | 33 + .../remotion-saas/rendering.md | 69 + .../remotion-studio/REFERENCE.md | 24 + .../remotion-studio/agents/openai.yaml | 7 + .../remotion-studio/assets/remotion-icon.svg | 4 + .../remotion-upgrade/REFERENCE.md | 31 + .../remotion-upgrade/agents/openai.yaml | 7 + .../remotion-upgrade/assets/remotion-icon.svg | 4 + .github/skills/remotion-captions/SKILL.md | 42 + .../remotion-captions/agents/openai.yaml | 7 + .../assets/remotion-icon.svg | 4 + .../remotion-captions/display-captions.md | 102 + .../remotion-captions/import-srt-captions.md | 73 + .../remotion-captions/transcribe-captions.md | 170 + .github/skills/remotion-create/SKILL.md | 71 + .../skills/remotion-create/agents/openai.yaml | 7 + .../remotion-create/assets/remotion-icon.svg | 4 + .github/skills/remotion-create/tailwind.md | 11 + .../skills/remotion-create/video-layout.md | 9 + .github/skills/remotion-docs/SKILL.md | 46 + .../skills/remotion-docs/agents/openai.yaml | 7 + .../remotion-docs/assets/remotion-icon.svg | 4 + .../skills/remotion-interactivity/SKILL.md | 344 + .../remotion-interactivity/agents/openai.yaml | 7 + .../assets/remotion-icon.svg | 4 + .github/skills/remotion-maps/SKILL.md | 36 + .../skills/remotion-maps/agents/openai.yaml | 7 + .../remotion-maps/assets/remotion-icon.svg | 4 + .../techniques/cesium/TECHNIQUE.md | 89 + .../cesium/assets/CesiumFlythrough.tsx | 284 + .../techniques/cesium/assets/cesium-path.json | 299 + .../techniques/cesium/assets/city-path.json | 12 + .../techniques/cesium/assets/example-Root.tsx | 39 + .../techniques/cesium/assets/flight-path.ts | 35 + .../cesium/assets/sample-river.geojson | 215 + .../cesium/references/3d-data-sources.md | 43 + .../references/3d-flyover-architecture.md | 128 + .../cesium/references/3d-troubleshooting.md | 57 + .../cesium/scripts/prep-cesium-path.mjs | 161 + .../techniques/mapbox/TECHNIQUE.md | 449 + .../mapbox/references/render-stability.md | 64 + .../techniques/maplibre/TECHNIQUE.md | 484 + .../maplibre/references/render-stability.md | 64 + .../techniques/maptiler/TECHNIQUE.md | 80 + .../maptiler/assets/CountryLabel.tsx | 70 + .../maptiler/assets/MapTilerVectorElement.ts | 80 + .../maptiler/assets/RiverReveal.tsx | 363 + .../maptiler/assets/example-Root.tsx | 22 + .../assets/sample-data/country-meta.json | 7535 ++++ .../assets/sample-data/yarlung-flow.json | 605 + .../techniques/maptiler/assets/tokens.ts | 34 + .../maptiler/references/map-data-sources.md | 91 + .../references/map-explainer-architecture.md | 129 + .../maptiler/references/map-geo-prep.md | 85 + .../maptiler/references/render-stability.md | 64 + .../techniques/maptiler/scripts/prep-geo.mjs | 202 + .../techniques/static-map/TECHNIQUE.md | 37 + .github/skills/remotion-markup/3d.md | 86 + .github/skills/remotion-markup/SKILL.md | 358 + .../skills/remotion-markup/agents/openai.yaml | 7 + .../remotion-markup/assets/remotion-icon.svg | 4 + .../remotion-markup/audio-visualization.md | 198 + .github/skills/remotion-markup/audio.md | 169 + .../remotion-markup/calculate-metadata.md | 136 + .../skills/remotion-markup/compositions.md | 123 + .../remotion-markup/connected-compositions.md | 79 + .github/skills/remotion-markup/cropping.md | 34 + .github/skills/remotion-markup/effects.md | 251 + .../remotion-markup/embedding-videos.md | 171 + .github/skills/remotion-markup/ffmpeg.md | 38 + .github/skills/remotion-markup/gifs.md | 187 + .../skills/remotion-markup/google-fonts.md | 76 + .../skills/remotion-markup/html-in-canvas.md | 128 + .github/skills/remotion-markup/images.md | 73 + .github/skills/remotion-markup/light-leaks.md | 106 + .github/skills/remotion-markup/local-fonts.md | 69 + .github/skills/remotion-markup/lottie.md | 73 + .../remotion-markup/measuring-dom-nodes.md | 38 + .../skills/remotion-markup/measuring-text.md | 146 + .github/skills/remotion-markup/motion-blur.md | 60 + .../remotion-markup/multi-scene-video.md | 81 + .github/skills/remotion-markup/parameters.md | 111 + .../remotion-maps/REFERENCE.md | 36 + .../remotion-maps/agents/openai.yaml | 7 + .../remotion-maps/assets/remotion-icon.svg | 4 + .../techniques/cesium/TECHNIQUE.md | 89 + .../cesium/assets/CesiumFlythrough.tsx | 284 + .../techniques/cesium/assets/cesium-path.json | 299 + .../techniques/cesium/assets/city-path.json | 12 + .../techniques/cesium/assets/example-Root.tsx | 39 + .../techniques/cesium/assets/flight-path.ts | 35 + .../cesium/assets/sample-river.geojson | 215 + .../cesium/references/3d-data-sources.md | 43 + .../references/3d-flyover-architecture.md | 128 + .../cesium/references/3d-troubleshooting.md | 57 + .../cesium/scripts/prep-cesium-path.mjs | 161 + .../techniques/mapbox/TECHNIQUE.md | 449 + .../mapbox/references/render-stability.md | 64 + .../techniques/maplibre/TECHNIQUE.md | 484 + .../maplibre/references/render-stability.md | 64 + .../techniques/maptiler/TECHNIQUE.md | 80 + .../maptiler/assets/CountryLabel.tsx | 70 + .../maptiler/assets/MapTilerVectorElement.ts | 80 + .../maptiler/assets/RiverReveal.tsx | 363 + .../maptiler/assets/example-Root.tsx | 22 + .../assets/sample-data/country-meta.json | 7535 ++++ .../assets/sample-data/yarlung-flow.json | 605 + .../techniques/maptiler/assets/tokens.ts | 34 + .../maptiler/references/map-data-sources.md | 91 + .../references/map-explainer-architecture.md | 129 + .../maptiler/references/map-geo-prep.md | 85 + .../maptiler/references/render-stability.md | 64 + .../techniques/maptiler/scripts/prep-geo.mjs | 202 + .../techniques/static-map/TECHNIQUE.md | 37 + .github/skills/remotion-markup/sequencing.md | 169 + .github/skills/remotion-markup/sfx.md | 51 + .../remotion-markup/silence-detection.md | 71 + .../skills/remotion-markup/text-highlights.md | 56 + .github/skills/remotion-markup/timing.md | 111 + .github/skills/remotion-markup/transitions.md | 239 + .../skills/remotion-markup/video-editing.md | 90 + .github/skills/remotion-markup/voiceover.md | 99 + .github/skills/remotion-multimedia/SKILL.md | 20 + .../remotion-multimedia/agents/openai.yaml | 7 + .../assets/remotion-icon.svg | 4 + .../remotion-multimedia/get-audio-duration.md | 61 + .../get-video-dimensions.md | 72 + .../remotion-multimedia/get-video-duration.md | 61 + .github/skills/remotion-render/SKILL.md | 35 + .../skills/remotion-render/agents/openai.yaml | 7 + .../remotion-render/assets/remotion-icon.svg | 4 + .../remotion-render/transparent-videos.md | 106 + .github/skills/remotion-saas/SKILL.md | 33 + .../skills/remotion-saas/agents/openai.yaml | 7 + .../remotion-saas/assets/remotion-icon.svg | 4 + .github/skills/remotion-saas/framework.md | 19 + .github/skills/remotion-saas/player.md | 33 + .github/skills/remotion-saas/rendering.md | 69 + .github/skills/remotion-studio/SKILL.md | 24 + .../skills/remotion-studio/agents/openai.yaml | 7 + .../remotion-studio/assets/remotion-icon.svg | 4 + .github/skills/remotion-upgrade/SKILL.md | 31 + .../remotion-upgrade/agents/openai.yaml | 7 + .../remotion-upgrade/assets/remotion-icon.svg | 4 + .github/skills/request-refactor-plan/SKILL.md | 68 + .../skills/resolving-merge-conflicts/SKILL.md | 14 + .../agents/openai.yaml | 3 + .github/skills/rust-async-patterns/SKILL.md | 95 + .../rust-async-patterns/references/details.md | 423 + .github/skills/rust-best-practices/SKILL.md | 94 + .../references/chapter_01.md | 657 + .../references/chapter_02.md | 117 + .../references/chapter_03.md | 211 + .../references/chapter_04.md | 181 + .../references/chapter_05.md | 390 + .../references/chapter_06.md | 161 + .../references/chapter_07.md | 222 + .../references/chapter_08.md | 252 + .../references/chapter_09.md | 256 + .../rust-skills/.github/workflows/ci.yml | 29 + .github/skills/rust-skills/AGENTS.md | 499 + .github/skills/rust-skills/CHANGELOG.md | 89 + .github/skills/rust-skills/CLAUDE.md | 499 + .github/skills/rust-skills/CONTRIBUTING.md | 87 + .github/skills/rust-skills/LICENSE | 21 + .github/skills/rust-skills/README.md | 302 + .github/skills/rust-skills/SKILL.md | 499 + .github/skills/rust-skills/checks/.gitignore | 6 + .github/skills/rust-skills/checks/Cargo.lock | 1685 + .github/skills/rust-skills/checks/Cargo.toml | 52 + .github/skills/rust-skills/checks/README.md | 63 + .github/skills/rust-skills/checks/analyze.py | 151 + .../skills/rust-skills/checks/baseline.txt | 124 + .github/skills/rust-skills/checks/check.sh | 33 + .github/skills/rust-skills/checks/gen.py | 84 + .../skills/rust-skills/checks/gen_index.py | 129 + .../rust-skills/checks/rust-toolchain.toml | 5 + .github/skills/rust-skills/checks/src/lib.rs | 2 + .github/skills/rust-skills/checks/validate.py | 58 + .../rust-skills/rules/anti-clone-excessive.md | 124 + .../rules/anti-collect-intermediate.md | 131 + .../rust-skills/rules/anti-empty-catch.md | 132 + .../rust-skills/rules/anti-expect-lazy.md | 95 + .../rust-skills/rules/anti-format-hot-path.md | 144 + .../rust-skills/rules/anti-index-over-iter.md | 125 + .../rules/anti-lock-across-await.md | 127 + .../rules/anti-over-abstraction.md | 120 + .../rust-skills/rules/anti-panic-expected.md | 131 + .../rules/anti-premature-optimize.md | 158 + .../rust-skills/rules/anti-string-for-str.md | 122 + .../rust-skills/rules/anti-stringly-typed.md | 167 + .../rust-skills/rules/anti-type-erasure.md | 140 + .../rust-skills/rules/anti-unwrap-abuse.md | 143 + .../rust-skills/rules/anti-vec-for-slice.md | 121 + .../rust-skills/rules/api-builder-must-use.md | 143 + .../rust-skills/rules/api-builder-pattern.md | 187 + .../rust-skills/rules/api-common-traits.md | 166 + .../rust-skills/rules/api-default-impl.md | 190 + .../rust-skills/rules/api-extension-trait.md | 164 + .../rust-skills/rules/api-from-not-into.md | 148 + .../rust-skills/rules/api-impl-asref.md | 142 + .../rules/api-impl-fromiterator.md | 118 + .../skills/rust-skills/rules/api-impl-into.md | 160 + .../skills/rust-skills/rules/api-must-use.md | 125 + .../rust-skills/rules/api-newtype-safety.md | 162 + .../rust-skills/rules/api-non-exhaustive.md | 177 + .../rules/api-operator-overload.md | 109 + .../rules/api-parse-dont-validate.md | 186 + .../rust-skills/rules/api-sealed-trait.md | 168 + .../rust-skills/rules/api-serde-optional.md | 184 + .../skills/rust-skills/rules/api-typestate.md | 199 + .../rules/async-async-fn-bounds.md | 101 + .../rules/async-bounded-channel.md | 175 + .../rules/async-broadcast-pubsub.md | 185 + .../rust-skills/rules/async-cancel-safety.md | 112 + .../rules/async-cancellation-token.md | 203 + .../rules/async-clone-before-await.md | 171 + .../rust-skills/rules/async-fn-in-trait.md | 105 + .../rust-skills/rules/async-join-parallel.md | 158 + .../rules/async-joinset-structured.md | 195 + .../rust-skills/rules/async-mpsc-queue.md | 171 + .../rust-skills/rules/async-no-lock-await.md | 153 + .../rules/async-oneshot-response.md | 191 + .../rust-skills/rules/async-select-racing.md | 198 + .../rust-skills/rules/async-spawn-blocking.md | 154 + .../rust-skills/rules/async-tokio-fs.md | 167 + .../rust-skills/rules/async-tokio-runtime.md | 175 + .../rust-skills/rules/async-try-join.md | 172 + .../rust-skills/rules/async-watch-latest.md | 189 + .../rules/closure-disjoint-capture.md | 85 + .../rules/closure-fn-trait-bounds.md | 89 + .../rules/closure-impl-fn-return.md | 115 + .../rust-skills/rules/closure-move-capture.md | 70 + .../rules/closure-static-vs-dyn.md | 96 + .../rust-skills/rules/coll-binaryheap.md | 108 + .../rust-skills/rules/coll-map-choice.md | 109 + .../rust-skills/rules/coll-seq-choice.md | 85 + .../rust-skills/rules/coll-set-membership.md | 87 + .../rust-skills/rules/conc-atomic-ordering.md | 106 + .../rust-skills/rules/conc-rayon-par-iter.md | 67 + .../rust-skills/rules/conc-scoped-threads.md | 73 + .../rust-skills/rules/conc-thread-local.md | 81 + .../skills/rust-skills/rules/const-block.md | 77 + .github/skills/rust-skills/rules/const-fn.md | 63 + .../rust-skills/rules/const-generics.md | 90 + .../rust-skills/rules/const-vs-static.md | 78 + .../rust-skills/rules/conv-asmut-mutable.md | 67 + .../rust-skills/rules/conv-fromstr-parsing.md | 82 + .../rules/conv-tryfrom-fallible.md | 80 + .../rust-skills/rules/doc-all-public.md | 113 + .../rust-skills/rules/doc-cargo-metadata.md | 147 + .../rust-skills/rules/doc-crate-readme.md | 75 + .../rust-skills/rules/doc-errors-section.md | 122 + .../rust-skills/rules/doc-examples-section.md | 161 + .../rust-skills/rules/doc-hidden-setup.md | 149 + .../rust-skills/rules/doc-intra-links.md | 138 + .../rust-skills/rules/doc-link-types.md | 169 + .../rust-skills/rules/doc-module-inner.md | 116 + .../rust-skills/rules/doc-panics-section.md | 128 + .../rust-skills/rules/doc-question-mark.md | 136 + .../rust-skills/rules/doc-safety-section.md | 131 + .../rust-skills/rules/err-anyhow-app.md | 179 + .../rust-skills/rules/err-context-chain.md | 144 + .../rust-skills/rules/err-custom-type.md | 152 + .../rust-skills/rules/err-doc-errors.md | 145 + .../rust-skills/rules/err-expect-bugs-only.md | 133 + .../skills/rust-skills/rules/err-from-impl.md | 153 + .../rust-skills/rules/err-lowercase-msg.md | 124 + .../rust-skills/rules/err-no-unwrap-prod.md | 115 + .../rust-skills/rules/err-question-mark.md | 151 + .../rules/err-result-over-panic.md | 130 + .../rust-skills/rules/err-source-chain.md | 155 + .../rust-skills/rules/err-thiserror-lib.md | 171 + .../rust-skills/rules/lint-cargo-metadata.md | 138 + .../rust-skills/rules/lint-cfg-check.md | 69 + .../rules/lint-clippy-nursery-selected.md | 75 + .../rules/lint-deny-correctness.md | 107 + .../rust-skills/rules/lint-missing-docs.md | 154 + .../rules/lint-pedantic-selective.md | 118 + .../rust-skills/rules/lint-rustfmt-check.md | 157 + .../rust-skills/rules/lint-unsafe-doc.md | 133 + .../rust-skills/rules/lint-warn-complexity.md | 131 + .../rust-skills/rules/lint-warn-perf.md | 136 + .../rust-skills/rules/lint-warn-style.md | 135 + .../rust-skills/rules/lint-warn-suspicious.md | 122 + .../rust-skills/rules/lint-workspace-lints.md | 172 + .../rules/macro-export-crate-path.md | 87 + .../rules/macro-fragment-specifiers.md | 81 + .../rules/macro-prefer-functions.md | 61 + .../rules/macro-private-helpers.md | 98 + .../rules/macro-proc-error-spans.md | 118 + .../rust-skills/rules/macro-proc-syn-quote.md | 110 + .../rust-skills/rules/macro-proc-two-crate.md | 143 + .../rust-skills/rules/macro-rules-hygiene.md | 98 + .../rust-skills/rules/mem-arena-allocator.md | 171 + .../skills/rust-skills/rules/mem-arrayvec.md | 143 + .../rust-skills/rules/mem-assert-type-size.md | 168 + .../rust-skills/rules/mem-avoid-format.md | 147 + .../rules/mem-box-large-variant.md | 158 + .../rust-skills/rules/mem-boxed-slice.md | 139 + .../rust-skills/rules/mem-clone-from.md | 147 + .../rust-skills/rules/mem-compact-string.md | 151 + .../rust-skills/rules/mem-drop-order.md | 128 + .../rules/mem-reuse-collections.md | 174 + .../rust-skills/rules/mem-smaller-integers.md | 161 + .../skills/rust-skills/rules/mem-smallvec.md | 138 + .../rust-skills/rules/mem-take-replace.md | 121 + .../skills/rust-skills/rules/mem-thinvec.md | 142 + .../rust-skills/rules/mem-with-capacity.md | 157 + .../rules/mem-write-over-format.md | 179 + .../skills/rust-skills/rules/mem-zero-copy.md | 166 + .../rust-skills/rules/name-acronym-word.md | 99 + .../skills/rust-skills/rules/name-as-free.md | 104 + .../rules/name-consts-screaming.md | 94 + .../rust-skills/rules/name-crate-no-rs.md | 78 + .../rust-skills/rules/name-funcs-snake.md | 76 + .../rust-skills/rules/name-into-ownership.md | 123 + .../rust-skills/rules/name-is-has-bool.md | 127 + .../rust-skills/rules/name-iter-convention.md | 129 + .../rust-skills/rules/name-iter-method.md | 131 + .../rust-skills/rules/name-iter-type-match.md | 142 + .../rust-skills/rules/name-lifetime-short.md | 86 + .../rust-skills/rules/name-no-get-prefix.md | 154 + .../rust-skills/rules/name-to-expensive.md | 118 + .../rules/name-type-param-single.md | 92 + .../rust-skills/rules/name-types-camel.md | 65 + .../rust-skills/rules/name-variants-camel.md | 101 + .../rust-skills/rules/num-cast-try-from.md | 95 + .../rust-skills/rules/num-float-compare.md | 91 + .../skills/rust-skills/rules/num-nonzero.md | 94 + .../rules/num-overflow-explicit.md | 87 + .../rust-skills/rules/num-saturating-clamp.md | 91 + .../rust-skills/rules/obs-error-chain.md | 92 + .../rust-skills/rules/obs-instrument-spans.md | 81 + .../rust-skills/rules/obs-levels-filter.md | 83 + .../rust-skills/rules/obs-library-facade.md | 73 + .../rules/obs-no-sensitive-data.md | 87 + .../rules/obs-structured-fields.md | 71 + .../rust-skills/rules/obs-tracing-over-log.md | 55 + .../rust-skills/rules/opt-bounds-check.md | 163 + .../rust-skills/rules/opt-cache-friendly.md | 187 + .../rust-skills/rules/opt-codegen-units.md | 142 + .../rust-skills/rules/opt-cold-unlikely.md | 152 + .../rules/opt-inline-always-rare.md | 141 + .../rules/opt-inline-never-cold.md | 182 + .../rust-skills/rules/opt-inline-small.md | 164 + .../rust-skills/rules/opt-likely-hint.md | 187 + .../rust-skills/rules/opt-lto-release.md | 135 + .../rust-skills/rules/opt-pgo-profile.md | 167 + .../rust-skills/rules/opt-simd-portable.md | 143 + .../rust-skills/rules/opt-target-cpu.md | 159 + .../rust-skills/rules/own-arc-shared.md | 143 + .../rules/own-borrow-over-clone.md | 96 + .../rust-skills/rules/own-clone-explicit.md | 135 + .../rust-skills/rules/own-copy-small.md | 124 + .../rust-skills/rules/own-cow-conditional.md | 135 + .../rust-skills/rules/own-lifetime-elision.md | 134 + .../rust-skills/rules/own-move-large.md | 134 + .../rust-skills/rules/own-mutex-interior.md | 106 + .../rust-skills/rules/own-rc-single-thread.md | 97 + .../rust-skills/rules/own-refcell-interior.md | 116 + .../rust-skills/rules/own-rwlock-readers.md | 122 + .../rust-skills/rules/own-slice-over-vec.md | 119 + .../rust-skills/rules/pat-at-bindings.md | 99 + .../rust-skills/rules/pat-exhaustive-enum.md | 89 + .../rust-skills/rules/pat-if-let-chains.md | 81 + .../skills/rust-skills/rules/pat-let-else.md | 69 + .../rust-skills/rules/pat-matches-macro.md | 107 + .../skills/rust-skills/rules/perf-ahash.md | 79 + .../rust-skills/rules/perf-black-box-bench.md | 153 + .../rust-skills/rules/perf-chain-avoid.md | 136 + .../rust-skills/rules/perf-collect-into.md | 142 + .../rust-skills/rules/perf-collect-once.md | 120 + .../rust-skills/rules/perf-drain-reuse.md | 137 + .../rust-skills/rules/perf-entry-api.md | 135 + .../rust-skills/rules/perf-extend-batch.md | 150 + .../rust-skills/rules/perf-io-buffering.md | 98 + .../rust-skills/rules/perf-iter-lazy.md | 123 + .../rust-skills/rules/perf-iter-over-index.md | 114 + .../rust-skills/rules/perf-profile-first.md | 175 + .../rust-skills/rules/perf-release-profile.md | 149 + .../skills/rust-skills/rules/proj-bin-dir.md | 142 + .../rules/proj-build-rs-minimal.md | 70 + .../rules/proj-feature-additive.md | 70 + .../rust-skills/rules/proj-flat-small.md | 133 + .../rust-skills/rules/proj-lib-main-split.md | 148 + .../rust-skills/rules/proj-mod-by-feature.md | 130 + .../rust-skills/rules/proj-mod-rs-dir.md | 120 + .../rust-skills/rules/proj-msrv-declare.md | 57 + .../rust-skills/rules/proj-prelude-module.md | 155 + .../rules/proj-pub-crate-internal.md | 139 + .../rules/proj-pub-super-parent.md | 135 + .../rules/proj-pub-use-reexport.md | 162 + .../rust-skills/rules/proj-workspace-deps.md | 186 + .../rust-skills/rules/proj-workspace-large.md | 162 + .../rust-skills/rules/serde-custom-with.md | 80 + .../rust-skills/rules/serde-default-compat.md | 71 + .../rules/serde-deny-unknown-fields.md | 74 + .../rules/serde-enum-representation.md | 85 + .../skills/rust-skills/rules/serde-flatten.md | 86 + .../rust-skills/rules/serde-rename-all.md | 72 + .../rust-skills/rules/serde-skip-empty.md | 76 + .../rules/serde-try-from-validate.md | 114 + .../rules/test-arrange-act-assert.md | 160 + .../rust-skills/rules/test-cfg-test-module.md | 151 + .../rust-skills/rules/test-criterion-bench.md | 171 + .../rules/test-descriptive-names.md | 142 + .../rules/test-doctest-examples.md | 168 + .../rust-skills/rules/test-fixture-raii.md | 154 + .../rust-skills/rules/test-integration-dir.md | 144 + .../rules/test-loom-concurrency.md | 102 + .../rust-skills/rules/test-mock-traits.md | 189 + .../rust-skills/rules/test-mockall-mocking.md | 226 + .../rules/test-proptest-properties.md | 161 + .../rust-skills/rules/test-should-panic.md | 130 + .../rules/test-snapshot-testing.md | 91 + .../rust-skills/rules/test-tokio-async.md | 154 + .../rust-skills/rules/test-use-super.md | 127 + .../rules/trait-associated-type-vs-generic.md | 111 + .../rust-skills/rules/trait-blanket-impl.md | 80 + .../rules/trait-coherence-newtype.md | 85 + .../rules/trait-default-methods.md | 117 + .../rust-skills/rules/trait-dyn-vs-generic.md | 99 + .../rust-skills/rules/trait-object-safety.md | 109 + .../rust-skills/rules/type-deref-coercion.md | 91 + .../rules/type-display-vs-debug.md | 79 + .../rust-skills/rules/type-enum-states.md | 156 + .../rust-skills/rules/type-generic-bounds.md | 144 + .../rust-skills/rules/type-never-diverge.md | 153 + .../rust-skills/rules/type-newtype-ids.md | 161 + .../rules/type-newtype-validated.md | 161 + .../rust-skills/rules/type-no-stringly.md | 144 + .../rust-skills/rules/type-numeric-fmt.md | 87 + .../rust-skills/rules/type-option-nullable.md | 137 + .../rust-skills/rules/type-phantom-marker.md | 188 + .../rules/type-repr-transparent.md | 143 + .../rust-skills/rules/type-result-fallible.md | 131 + .../rust-skills/rules/unsafe-extern-block.md | 72 + .../rust-skills/rules/unsafe-maybeuninit.md | 71 + .../rules/unsafe-minimize-scope.md | 78 + .../rust-skills/rules/unsafe-miri-ci.md | 65 + .../rules/unsafe-no-mangle-unsafe.md | 65 + .../rules/unsafe-safety-comment.md | 72 + .../rules/unsafe-send-sync-manual.md | 99 + .github/skills/rust-testing/SKILL.md | 501 + .../skills/setup-matt-pocock-skills/SKILL.md | 116 + .../agents/openai.yaml | 5 + .../skills/setup-matt-pocock-skills/domain.md | 51 + .../issue-tracker-github.md | 45 + .../issue-tracker-gitlab.md | 46 + .../issue-tracker-local.md | 30 + .../setup-matt-pocock-skills/triage-labels.md | 15 + .github/skills/shadcn/SKILL.md | 277 + .github/skills/shadcn/agents/openai.yml | 5 + .github/skills/shadcn/assets/shadcn-small.png | Bin 0 -> 1049 bytes .github/skills/shadcn/assets/shadcn.png | Bin 0 -> 3852 bytes .github/skills/shadcn/cli.md | 290 + .github/skills/shadcn/customization.md | 209 + .github/skills/shadcn/evals/evals.json | 77 + .github/skills/shadcn/mcp.md | 105 + .github/skills/shadcn/registry.md | 277 + .github/skills/shadcn/rules/base-vs-radix.md | 306 + .github/skills/shadcn/rules/chat.md | 250 + .github/skills/shadcn/rules/composition.md | 213 + .github/skills/shadcn/rules/forms.md | 192 + .github/skills/shadcn/rules/icons.md | 101 + .github/skills/shadcn/rules/styling.md | 185 + .github/skills/stop-slop/CHANGELOG.md | 24 + .github/skills/stop-slop/LICENSE | 21 + .github/skills/stop-slop/README.md | 62 + .github/skills/stop-slop/SKILL.md | 68 + .../skills/stop-slop/references/examples.md | 59 + .../skills/stop-slop/references/phrases.md | 128 + .../skills/stop-slop/references/structures.md | 134 + .github/skills/tanstack-form/SKILL.md | 416 + .../SKILL.md | 68 + .../rules/cache-single-source.md | 187 + .../rules/flow-loader-query-pattern.md | 178 + .../rules/setup-query-client-context.md | 173 + .../rules/ssr-dehydrate-hydrate.md | 206 + .../tanstack-query-best-practices/SKILL.md | 114 + .../rules/cache-defaults.md | 70 + .../rules/cache-gc-time.md | 93 + .../rules/cache-invalidation.md | 116 + .../rules/cache-placeholder-vs-initial.md | 156 + .../rules/cache-stale-time.md | 80 + .../rules/err-error-boundaries.md | 150 + .../rules/err-fallback-data.md | 94 + .../rules/err-retry-config.md | 81 + .../rules/inf-loading-guards.md | 103 + .../rules/inf-max-pages.md | 67 + .../rules/inf-page-params.md | 132 + .../rules/mut-error-handling.md | 88 + .../rules/mut-invalidate-queries.md | 118 + .../rules/mut-loading-states.md | 80 + .../rules/mut-mutation-state.md | 169 + .../rules/mut-optimistic-updates.md | 137 + .../rules/mut-rollback-context.md | 108 + .../rules/network-mode.md | 179 + .../rules/parallel-use-queries.md | 152 + .../rules/perf-notify-change-props.md | 96 + .../rules/perf-placeholder-data.md | 98 + .../rules/perf-select-transform.md | 144 + .../rules/perf-structural-sharing.md | 72 + .../rules/persist-queries.md | 194 + .../rules/pf-ensure-query-data.md | 71 + .../rules/pf-intent-prefetch.md | 143 + .../rules/pf-route-prefetch.md | 99 + .../rules/pf-stale-time-config.md | 82 + .../rules/qk-array-structure.md | 50 + .../rules/qk-factory-pattern.md | 102 + .../rules/qk-hierarchical-organization.md | 76 + .../rules/qk-include-dependencies.md | 62 + .../rules/qk-serializable.md | 93 + .../rules/query-cancellation.md | 171 + .../rules/ssr-client-per-request.md | 101 + .../rules/ssr-dehydration.md | 158 + .../rules/ssr-hydration-boundary.md | 117 + .../rules/ssr-stale-time-server.md | 94 + .../tanstack-router-best-practices/SKILL.md | 113 + .../rules/ctx-before-load.md | 119 + .../rules/ctx-dependency-injection.md | 125 + .../rules/ctx-root-context.md | 172 + .../rules/err-not-found.md | 194 + .../rules/load-deferred-data.md | 113 + .../rules/load-ensure-query-data.md | 153 + .../rules/load-error-handling.md | 122 + .../rules/load-loader-deps.md | 83 + .../rules/load-parallel.md | 190 + .../rules/load-use-loaders.md | 148 + .../rules/nav-active-states.md | 129 + .../rules/nav-link-component.md | 178 + .../rules/nav-relative-paths.md | 107 + .../rules/nav-route-masks.md | 197 + .../rules/nav-use-navigate.md | 122 + .../rules/org-file-based-routing.md | 105 + .../rules/org-index-routes.md | 100 + .../rules/org-pathless-layouts.md | 99 + .../rules/org-route-tree-structure.md | 97 + .../rules/org-virtual-routes.md | 133 + .../rules/preload-intent.md | 133 + .../rules/preload-manual.md | 113 + .../rules/preload-stale-time.md | 74 + .../rules/router-default-options.md | 163 + .../rules/search-custom-serializer.md | 198 + .../rules/search-defaults.md | 110 + .../rules/search-middleware.md | 123 + .../rules/search-type-inheritance.md | 95 + .../rules/search-validation.md | 158 + .../rules/split-auto-splitting.md | 106 + .../rules/split-critical-path.md | 95 + .../rules/split-lazy-routes.md | 148 + .../rules/ts-query-options-loader.md | 92 + .../rules/ts-register-router.md | 113 + .../rules/ts-route-context-typing.md | 70 + .../rules/ts-use-from-param.md | 130 + .../tanstack-start-best-practices/SKILL.md | 109 + .../rules/api-routes.md | 235 + .../rules/auth-cookie-security.md | 109 + .../rules/auth-route-protection.md | 192 + .../rules/auth-server-functions.md | 110 + .../rules/auth-session-management.md | 191 + .../rules/deploy-adapters.md | 153 + .../rules/deploy-env-config.md | 142 + .../rules/env-functions.md | 211 + .../rules/err-not-found.md | 128 + .../rules/err-redirects.md | 123 + .../rules/err-server-errors.md | 187 + .../rules/file-functions-file.md | 108 + .../rules/file-separation.md | 152 + .../rules/file-shared-validation.md | 116 + .../rules/mw-composability.md | 152 + .../rules/mw-context-flow.md | 113 + .../rules/mw-function-middleware.md | 121 + .../rules/mw-request-middleware.md | 166 + .../rules/sec-auth-middleware.md | 135 + .../rules/sec-csrf-protection.md | 105 + .../rules/sec-sensitive-data.md | 105 + .../rules/sec-validate-inputs.md | 104 + .../rules/sf-create-server-fn.md | 146 + .../rules/sf-error-handling.md | 104 + .../rules/sf-input-validation.md | 158 + .../rules/sf-method-selection.md | 74 + .../rules/sf-response-headers.md | 89 + .../rules/ssr-data-loading.md | 111 + .../rules/ssr-hydration-safety.md | 187 + .../rules/ssr-prerender.md | 189 + .../rules/ssr-selective.md | 120 + .../rules/ssr-streaming.md | 201 + .github/skills/tanstack-table/SKILL.md | 582 + .github/skills/tdd/SKILL.md | 38 + .github/skills/tdd/agents/openai.yaml | 3 + .github/skills/tdd/mocking.md | 59 + .github/skills/tdd/tests.md | 77 + .github/skills/typescript-expert/SKILL.md | 138 + .../typescript-expert/agents/openai.yaml | 4 + .github/skills/ui-ux-pro-max/SKILL.md | 214 + .../ui-ux-pro-max/data/app-interface.csv | 33 + .../ui-ux-pro-max/data/catalog-summary.json | 78 + .github/skills/ui-ux-pro-max/data/charts.csv | 26 + .github/skills/ui-ux-pro-max/data/colors.csv | 193 + .../ui-ux-pro-max/data/data-provenance.json | 1348 + .../data/google-font-licenses.json | 20185 ++++++++++ .../ui-ux-pro-max/data/google-fonts.csv | 1935 + .github/skills/ui-ux-pro-max/data/icons.csv | 106 + .github/skills/ui-ux-pro-max/data/landing.csv | 35 + .github/skills/ui-ux-pro-max/data/motion.csv | 18 + .../data/phosphor-icons-upstream.json | 32582 ++++++++++++++++ .../skills/ui-ux-pro-max/data/products.csv | 193 + .../ui-ux-pro-max/data/react-performance.csv | 45 + .../ui-ux-pro-max/data/stacks/angular.csv | 51 + .../ui-ux-pro-max/data/stacks/astro.csv | 54 + .../ui-ux-pro-max/data/stacks/avalonia.csv | 57 + .../ui-ux-pro-max/data/stacks/flutter.csv | 53 + .../data/stacks/html-tailwind.csv | 60 + .../ui-ux-pro-max/data/stacks/javafx.csv | 76 + .../data/stacks/jetpack-compose.csv | 53 + .../ui-ux-pro-max/data/stacks/laravel.csv | 51 + .../ui-ux-pro-max/data/stacks/nextjs.csv | 62 + .../ui-ux-pro-max/data/stacks/nuxt-ui.csv | 77 + .../ui-ux-pro-max/data/stacks/nuxtjs.csv | 68 + .../data/stacks/react-native.csv | 52 + .../ui-ux-pro-max/data/stacks/react.csv | 67 + .../ui-ux-pro-max/data/stacks/shadcn.csv | 69 + .../ui-ux-pro-max/data/stacks/svelte.csv | 56 + .../ui-ux-pro-max/data/stacks/swiftui.csv | 51 + .../ui-ux-pro-max/data/stacks/threejs.csv | 54 + .../skills/ui-ux-pro-max/data/stacks/uno.csv | 60 + .../skills/ui-ux-pro-max/data/stacks/uwp.csv | 56 + .../skills/ui-ux-pro-max/data/stacks/vue.csv | 50 + .../ui-ux-pro-max/data/stacks/winui.csv | 60 + .../skills/ui-ux-pro-max/data/stacks/wpf.csv | 57 + .github/skills/ui-ux-pro-max/data/styles.csv | 89 + .../skills/ui-ux-pro-max/data/typography.csv | 75 + .../ui-ux-pro-max/data/ui-reasoning.csv | 193 + .../ui-ux-pro-max/data/ux-guidelines.csv | 120 + .../ui-ux-pro-max/references/pro-rules.md | 117 + .../references/quick-reference.md | 256 + .github/skills/ui-ux-pro-max/scripts/core.py | 993 + .../ui-ux-pro-max/scripts/design_system.py | 1668 + .../scripts/reasoning_contract.py | 123 + .../skills/ui-ux-pro-max/scripts/search.py | 177 + .../tests/fixtures/catalogs/google-api.json | 36 + .../fixtures/catalogs/google-catalog.json | 33 + .../fixtures/catalogs/google-existing.csv | 3 + .../fixtures/catalogs/google-metadata.json | 17 + .../fixtures/catalogs/google-overrides.json | 7 + .../tests/fixtures/catalogs/icons-curated.csv | 4 + .../fixtures/catalogs/phosphor-core.json | 23 + .../fixtures/catalogs/phosphor-package.json | 13 + .../catalogs/phosphor-react-exports.json | 4 + .../catalogs/phosphor-react-package.json | 5 + .../tests/fixtures/relevance-baseline.json | 3366 ++ .../tests/fixtures/relevance-cases.json | 111 + .../tests/fixtures/relevance-thresholds.json | 100 + .../scripts/tests/test_catalog_refresh.py | 354 + .../test_catalog_summary_line_endings.py | 78 + .../ui-ux-pro-max/scripts/tests/test_core.py | 343 + .../scripts/tests/test_core_data_quality.py | 198 + .../scripts/tests/test_data_contracts.py | 421 + .../scripts/tests/test_design_system_mode.py | 233 + .../scripts/tests/test_design_system_stack.py | 61 + .../test_native_desktop_stack_freshness.py | 179 + .../scripts/tests/test_relevance_evaluator.py | 182 + .../scripts/tests/test_skill_script_paths.py | 82 + .../scripts/tests/test_style_taxonomy.py | 175 + .../tests/test_text_layout_resilience.py | 120 + .../scripts/tests/test_web_stack_freshness.py | 177 + .../ui-ux-pro-max/scripts/validate_data.py | 1095 + .github/skills/uv-package-manager/SKILL.md | 345 + .../references/advanced-patterns.md | 473 + .github/skills/web-design-guidelines/SKILL.md | 39 + .github/skills/web-perf/SKILL.md | 201 + .../skills/workers-best-practices/SKILL.md | 60 + .../references/configuration.md | 139 + .../references/platform-apis.md | 51 + .../references/runtime-patterns.md | 339 + .github/skills/wrangler/SKILL.md | 69 + README.md | 4 + 1173 files changed, 225805 insertions(+) create mode 100644 .github/skills/absurd/SKILL.md create mode 100644 .github/skills/blume-migrate/SKILL.md create mode 100644 .github/skills/blume-migrate/assets/oxfmt@0.67.0.patch create mode 100644 .github/skills/blume-migrate/references/docusaurus.md create mode 100644 .github/skills/blume-migrate/references/fumadocs.md create mode 100644 .github/skills/blume-migrate/references/mintlify.md create mode 100644 .github/skills/blume-migrate/references/monorepo.md create mode 100644 .github/skills/blume-migrate/references/nextra.md create mode 100644 .github/skills/blume-migrate/references/starlight.md create mode 100644 .github/skills/blume-migrate/scripts/mintlify-codemod.mjs create mode 100644 .github/skills/blume-update-docs/SKILL.md create mode 100644 .github/skills/blume-update-docs/references/audit-checklist.md create mode 100644 .github/skills/blume/SKILL.md create mode 100644 .github/skills/cloudflare-email-service/SKILL.md create mode 100644 .github/skills/cloudflare-email-service/references/cli-and-mcp.md create mode 100644 .github/skills/cloudflare-email-service/references/deliverability.md create mode 100644 .github/skills/cloudflare-email-service/references/rest-api.md create mode 100644 .github/skills/cloudflare-email-service/references/routing.md create mode 100644 .github/skills/cloudflare-email-service/references/sending.md create mode 100644 .github/skills/cloudflare/SKILL.md create mode 100644 .github/skills/cloudflare/references/ai-gateway/README.md create mode 100644 .github/skills/cloudflare/references/ai-gateway/configuration.md create mode 100644 .github/skills/cloudflare/references/ai-gateway/dynamic-routing.md create mode 100644 .github/skills/cloudflare/references/ai-gateway/features.md create mode 100644 .github/skills/cloudflare/references/ai-gateway/sdk-integration.md create mode 100644 .github/skills/cloudflare/references/ai-gateway/troubleshooting.md create mode 100644 .github/skills/cloudflare/references/ai-search/README.md create mode 100644 .github/skills/cloudflare/references/ai-search/api.md create mode 100644 .github/skills/cloudflare/references/ai-search/configuration.md create mode 100644 .github/skills/cloudflare/references/ai-search/gotchas.md create mode 100644 .github/skills/cloudflare/references/ai-search/patterns.md create mode 100644 .github/skills/cloudflare/references/analytics-engine/README.md create mode 100644 .github/skills/cloudflare/references/analytics-engine/api.md create mode 100644 .github/skills/cloudflare/references/analytics-engine/configuration.md create mode 100644 .github/skills/cloudflare/references/analytics-engine/gotchas.md create mode 100644 .github/skills/cloudflare/references/analytics-engine/patterns.md create mode 100644 .github/skills/cloudflare/references/api-shield/README.md create mode 100644 .github/skills/cloudflare/references/api-shield/api.md create mode 100644 .github/skills/cloudflare/references/api-shield/configuration.md create mode 100644 .github/skills/cloudflare/references/api-shield/gotchas.md create mode 100644 .github/skills/cloudflare/references/api-shield/patterns.md create mode 100644 .github/skills/cloudflare/references/api/README.md create mode 100644 .github/skills/cloudflare/references/api/api.md create mode 100644 .github/skills/cloudflare/references/api/configuration.md create mode 100644 .github/skills/cloudflare/references/api/gotchas.md create mode 100644 .github/skills/cloudflare/references/api/patterns.md create mode 100644 .github/skills/cloudflare/references/argo-smart-routing/README.md create mode 100644 .github/skills/cloudflare/references/argo-smart-routing/api.md create mode 100644 .github/skills/cloudflare/references/argo-smart-routing/configuration.md create mode 100644 .github/skills/cloudflare/references/argo-smart-routing/gotchas.md create mode 100644 .github/skills/cloudflare/references/argo-smart-routing/patterns.md create mode 100644 .github/skills/cloudflare/references/artifacts/README.md create mode 100644 .github/skills/cloudflare/references/artifacts/api.md create mode 100644 .github/skills/cloudflare/references/artifacts/configuration.md create mode 100644 .github/skills/cloudflare/references/bindings/README.md create mode 100644 .github/skills/cloudflare/references/bindings/api.md create mode 100644 .github/skills/cloudflare/references/bindings/configuration.md create mode 100644 .github/skills/cloudflare/references/bindings/gotchas.md create mode 100644 .github/skills/cloudflare/references/bindings/patterns.md create mode 100644 .github/skills/cloudflare/references/bot-management/README.md create mode 100644 .github/skills/cloudflare/references/bot-management/api.md create mode 100644 .github/skills/cloudflare/references/bot-management/configuration.md create mode 100644 .github/skills/cloudflare/references/bot-management/gotchas.md create mode 100644 .github/skills/cloudflare/references/bot-management/patterns.md create mode 100644 .github/skills/cloudflare/references/browser-rendering/README.md create mode 100644 .github/skills/cloudflare/references/browser-rendering/api.md create mode 100644 .github/skills/cloudflare/references/browser-rendering/configuration.md create mode 100644 .github/skills/cloudflare/references/browser-rendering/gotchas.md create mode 100644 .github/skills/cloudflare/references/browser-rendering/patterns.md create mode 100644 .github/skills/cloudflare/references/c3/README.md create mode 100644 .github/skills/cloudflare/references/c3/api.md create mode 100644 .github/skills/cloudflare/references/c3/configuration.md create mode 100644 .github/skills/cloudflare/references/c3/gotchas.md create mode 100644 .github/skills/cloudflare/references/c3/patterns.md create mode 100644 .github/skills/cloudflare/references/cache-reserve/README.md create mode 100644 .github/skills/cloudflare/references/cache-reserve/api.md create mode 100644 .github/skills/cloudflare/references/cache-reserve/configuration.md create mode 100644 .github/skills/cloudflare/references/cache-reserve/gotchas.md create mode 100644 .github/skills/cloudflare/references/cache-reserve/patterns.md create mode 100644 .github/skills/cloudflare/references/containers/README.md create mode 100644 .github/skills/cloudflare/references/containers/api.md create mode 100644 .github/skills/cloudflare/references/containers/configuration.md create mode 100644 .github/skills/cloudflare/references/containers/gotchas.md create mode 100644 .github/skills/cloudflare/references/containers/patterns.md create mode 100644 .github/skills/cloudflare/references/cron-triggers/README.md create mode 100644 .github/skills/cloudflare/references/cron-triggers/api.md create mode 100644 .github/skills/cloudflare/references/cron-triggers/configuration.md create mode 100644 .github/skills/cloudflare/references/cron-triggers/gotchas.md create mode 100644 .github/skills/cloudflare/references/cron-triggers/patterns.md create mode 100644 .github/skills/cloudflare/references/d1/README.md create mode 100644 .github/skills/cloudflare/references/d1/api.md create mode 100644 .github/skills/cloudflare/references/d1/configuration.md create mode 100644 .github/skills/cloudflare/references/d1/gotchas.md create mode 100644 .github/skills/cloudflare/references/d1/patterns.md create mode 100644 .github/skills/cloudflare/references/ddos/README.md create mode 100644 .github/skills/cloudflare/references/ddos/api.md create mode 100644 .github/skills/cloudflare/references/ddos/configuration.md create mode 100644 .github/skills/cloudflare/references/ddos/gotchas.md create mode 100644 .github/skills/cloudflare/references/ddos/patterns.md create mode 100644 .github/skills/cloudflare/references/do-storage/README.md create mode 100644 .github/skills/cloudflare/references/do-storage/api.md create mode 100644 .github/skills/cloudflare/references/do-storage/configuration.md create mode 100644 .github/skills/cloudflare/references/do-storage/gotchas.md create mode 100644 .github/skills/cloudflare/references/do-storage/patterns.md create mode 100644 .github/skills/cloudflare/references/do-storage/testing.md create mode 100644 .github/skills/cloudflare/references/email-routing/README.md create mode 100644 .github/skills/cloudflare/references/email-routing/api.md create mode 100644 .github/skills/cloudflare/references/email-routing/configuration.md create mode 100644 .github/skills/cloudflare/references/email-routing/gotchas.md create mode 100644 .github/skills/cloudflare/references/email-routing/patterns.md create mode 100644 .github/skills/cloudflare/references/email-workers/README.md create mode 100644 .github/skills/cloudflare/references/email-workers/api.md create mode 100644 .github/skills/cloudflare/references/email-workers/configuration.md create mode 100644 .github/skills/cloudflare/references/email-workers/gotchas.md create mode 100644 .github/skills/cloudflare/references/email-workers/patterns.md create mode 100644 .github/skills/cloudflare/references/flagship/README.md create mode 100644 .github/skills/cloudflare/references/flagship/api.md create mode 100644 .github/skills/cloudflare/references/flagship/configuration.md create mode 100644 .github/skills/cloudflare/references/flagship/gotchas.md create mode 100644 .github/skills/cloudflare/references/flagship/patterns.md create mode 100644 .github/skills/cloudflare/references/graphql-api/README.md create mode 100644 .github/skills/cloudflare/references/graphql-api/api.md create mode 100644 .github/skills/cloudflare/references/graphql-api/configuration.md create mode 100644 .github/skills/cloudflare/references/graphql-api/gotchas.md create mode 100644 .github/skills/cloudflare/references/graphql-api/patterns.md create mode 100644 .github/skills/cloudflare/references/hyperdrive/README.md create mode 100644 .github/skills/cloudflare/references/hyperdrive/api.md create mode 100644 .github/skills/cloudflare/references/hyperdrive/configuration.md create mode 100644 .github/skills/cloudflare/references/hyperdrive/gotchas.md create mode 100644 .github/skills/cloudflare/references/hyperdrive/patterns.md create mode 100644 .github/skills/cloudflare/references/images/README.md create mode 100644 .github/skills/cloudflare/references/images/api.md create mode 100644 .github/skills/cloudflare/references/images/configuration.md create mode 100644 .github/skills/cloudflare/references/images/gotchas.md create mode 100644 .github/skills/cloudflare/references/images/patterns.md create mode 100644 .github/skills/cloudflare/references/kv/README.md create mode 100644 .github/skills/cloudflare/references/kv/api.md create mode 100644 .github/skills/cloudflare/references/kv/configuration.md create mode 100644 .github/skills/cloudflare/references/kv/gotchas.md create mode 100644 .github/skills/cloudflare/references/kv/patterns.md create mode 100644 .github/skills/cloudflare/references/miniflare/README.md create mode 100644 .github/skills/cloudflare/references/miniflare/api.md create mode 100644 .github/skills/cloudflare/references/miniflare/configuration.md create mode 100644 .github/skills/cloudflare/references/miniflare/gotchas.md create mode 100644 .github/skills/cloudflare/references/miniflare/patterns.md create mode 100644 .github/skills/cloudflare/references/network-interconnect/README.md create mode 100644 .github/skills/cloudflare/references/network-interconnect/api.md create mode 100644 .github/skills/cloudflare/references/network-interconnect/configuration.md create mode 100644 .github/skills/cloudflare/references/network-interconnect/gotchas.md create mode 100644 .github/skills/cloudflare/references/network-interconnect/patterns.md create mode 100644 .github/skills/cloudflare/references/observability/README.md create mode 100644 .github/skills/cloudflare/references/observability/api.md create mode 100644 .github/skills/cloudflare/references/observability/configuration.md create mode 100644 .github/skills/cloudflare/references/observability/gotchas.md create mode 100644 .github/skills/cloudflare/references/observability/patterns.md create mode 100644 .github/skills/cloudflare/references/pages-functions/README.md create mode 100644 .github/skills/cloudflare/references/pages-functions/api.md create mode 100644 .github/skills/cloudflare/references/pages-functions/configuration.md create mode 100644 .github/skills/cloudflare/references/pages-functions/gotchas.md create mode 100644 .github/skills/cloudflare/references/pages-functions/patterns.md create mode 100644 .github/skills/cloudflare/references/pages/README.md create mode 100644 .github/skills/cloudflare/references/pages/api.md create mode 100644 .github/skills/cloudflare/references/pages/configuration.md create mode 100644 .github/skills/cloudflare/references/pages/gotchas.md create mode 100644 .github/skills/cloudflare/references/pages/patterns.md create mode 100644 .github/skills/cloudflare/references/pipelines/README.md create mode 100644 .github/skills/cloudflare/references/pipelines/api.md create mode 100644 .github/skills/cloudflare/references/pipelines/configuration.md create mode 100644 .github/skills/cloudflare/references/pipelines/gotchas.md create mode 100644 .github/skills/cloudflare/references/pipelines/patterns.md create mode 100644 .github/skills/cloudflare/references/pulumi/README.md create mode 100644 .github/skills/cloudflare/references/pulumi/api.md create mode 100644 .github/skills/cloudflare/references/pulumi/configuration.md create mode 100644 .github/skills/cloudflare/references/pulumi/gotchas.md create mode 100644 .github/skills/cloudflare/references/pulumi/patterns.md create mode 100644 .github/skills/cloudflare/references/queues/README.md create mode 100644 .github/skills/cloudflare/references/queues/api.md create mode 100644 .github/skills/cloudflare/references/queues/configuration.md create mode 100644 .github/skills/cloudflare/references/queues/gotchas.md create mode 100644 .github/skills/cloudflare/references/queues/patterns.md create mode 100644 .github/skills/cloudflare/references/r2-data-catalog/README.md create mode 100644 .github/skills/cloudflare/references/r2-data-catalog/api.md create mode 100644 .github/skills/cloudflare/references/r2-data-catalog/configuration.md create mode 100644 .github/skills/cloudflare/references/r2-data-catalog/gotchas.md create mode 100644 .github/skills/cloudflare/references/r2-data-catalog/patterns.md create mode 100644 .github/skills/cloudflare/references/r2-sql/README.md create mode 100644 .github/skills/cloudflare/references/r2-sql/api.md create mode 100644 .github/skills/cloudflare/references/r2-sql/configuration.md create mode 100644 .github/skills/cloudflare/references/r2-sql/gotchas.md create mode 100644 .github/skills/cloudflare/references/r2-sql/patterns.md create mode 100644 .github/skills/cloudflare/references/r2/README.md create mode 100644 .github/skills/cloudflare/references/r2/api.md create mode 100644 .github/skills/cloudflare/references/r2/configuration.md create mode 100644 .github/skills/cloudflare/references/r2/gotchas.md create mode 100644 .github/skills/cloudflare/references/r2/patterns.md create mode 100644 .github/skills/cloudflare/references/realtime-sfu/README.md create mode 100644 .github/skills/cloudflare/references/realtime-sfu/api.md create mode 100644 .github/skills/cloudflare/references/realtime-sfu/configuration.md create mode 100644 .github/skills/cloudflare/references/realtime-sfu/gotchas.md create mode 100644 .github/skills/cloudflare/references/realtime-sfu/patterns.md create mode 100644 .github/skills/cloudflare/references/realtimekit/README.md create mode 100644 .github/skills/cloudflare/references/realtimekit/api.md create mode 100644 .github/skills/cloudflare/references/realtimekit/configuration.md create mode 100644 .github/skills/cloudflare/references/realtimekit/gotchas.md create mode 100644 .github/skills/cloudflare/references/realtimekit/patterns.md create mode 100644 .github/skills/cloudflare/references/secrets-store/README.md create mode 100644 .github/skills/cloudflare/references/secrets-store/api.md create mode 100644 .github/skills/cloudflare/references/secrets-store/configuration.md create mode 100644 .github/skills/cloudflare/references/secrets-store/gotchas.md create mode 100644 .github/skills/cloudflare/references/secrets-store/patterns.md create mode 100644 .github/skills/cloudflare/references/smart-placement/README.md create mode 100644 .github/skills/cloudflare/references/smart-placement/api.md create mode 100644 .github/skills/cloudflare/references/smart-placement/configuration.md create mode 100644 .github/skills/cloudflare/references/smart-placement/gotchas.md create mode 100644 .github/skills/cloudflare/references/smart-placement/patterns.md create mode 100644 .github/skills/cloudflare/references/snippets/README.md create mode 100644 .github/skills/cloudflare/references/snippets/api.md create mode 100644 .github/skills/cloudflare/references/snippets/configuration.md create mode 100644 .github/skills/cloudflare/references/snippets/gotchas.md create mode 100644 .github/skills/cloudflare/references/snippets/patterns.md create mode 100644 .github/skills/cloudflare/references/spectrum/README.md create mode 100644 .github/skills/cloudflare/references/spectrum/api.md create mode 100644 .github/skills/cloudflare/references/spectrum/configuration.md create mode 100644 .github/skills/cloudflare/references/spectrum/gotchas.md create mode 100644 .github/skills/cloudflare/references/spectrum/patterns.md create mode 100644 .github/skills/cloudflare/references/static-assets/README.md create mode 100644 .github/skills/cloudflare/references/static-assets/api.md create mode 100644 .github/skills/cloudflare/references/static-assets/configuration.md create mode 100644 .github/skills/cloudflare/references/static-assets/gotchas.md create mode 100644 .github/skills/cloudflare/references/static-assets/patterns.md create mode 100644 .github/skills/cloudflare/references/stream/README.md create mode 100644 .github/skills/cloudflare/references/stream/api-live.md create mode 100644 .github/skills/cloudflare/references/stream/api.md create mode 100644 .github/skills/cloudflare/references/stream/configuration.md create mode 100644 .github/skills/cloudflare/references/stream/gotchas.md create mode 100644 .github/skills/cloudflare/references/stream/patterns.md create mode 100644 .github/skills/cloudflare/references/tail-workers/README.md create mode 100644 .github/skills/cloudflare/references/tail-workers/api.md create mode 100644 .github/skills/cloudflare/references/tail-workers/configuration.md create mode 100644 .github/skills/cloudflare/references/tail-workers/gotchas.md create mode 100644 .github/skills/cloudflare/references/tail-workers/patterns.md create mode 100644 .github/skills/cloudflare/references/terraform/README.md create mode 100644 .github/skills/cloudflare/references/terraform/api.md create mode 100644 .github/skills/cloudflare/references/terraform/configuration.md create mode 100644 .github/skills/cloudflare/references/terraform/gotchas.md create mode 100644 .github/skills/cloudflare/references/terraform/patterns.md create mode 100644 .github/skills/cloudflare/references/tunnel/README.md create mode 100644 .github/skills/cloudflare/references/tunnel/api.md create mode 100644 .github/skills/cloudflare/references/tunnel/configuration.md create mode 100644 .github/skills/cloudflare/references/tunnel/gotchas.md create mode 100644 .github/skills/cloudflare/references/tunnel/networking.md create mode 100644 .github/skills/cloudflare/references/tunnel/patterns.md create mode 100644 .github/skills/cloudflare/references/turn/README.md create mode 100644 .github/skills/cloudflare/references/turn/api.md create mode 100644 .github/skills/cloudflare/references/turn/configuration.md create mode 100644 .github/skills/cloudflare/references/turn/gotchas.md create mode 100644 .github/skills/cloudflare/references/turn/patterns.md create mode 100644 .github/skills/cloudflare/references/vectorize/README.md create mode 100644 .github/skills/cloudflare/references/vectorize/api.md create mode 100644 .github/skills/cloudflare/references/vectorize/configuration.md create mode 100644 .github/skills/cloudflare/references/vectorize/gotchas.md create mode 100644 .github/skills/cloudflare/references/vectorize/patterns.md create mode 100644 .github/skills/cloudflare/references/waf/README.md create mode 100644 .github/skills/cloudflare/references/waf/api.md create mode 100644 .github/skills/cloudflare/references/waf/configuration.md create mode 100644 .github/skills/cloudflare/references/waf/gotchas.md create mode 100644 .github/skills/cloudflare/references/waf/patterns.md create mode 100644 .github/skills/cloudflare/references/web-analytics/README.md create mode 100644 .github/skills/cloudflare/references/web-analytics/configuration.md create mode 100644 .github/skills/cloudflare/references/web-analytics/gotchas.md create mode 100644 .github/skills/cloudflare/references/web-analytics/integration.md create mode 100644 .github/skills/cloudflare/references/web-analytics/patterns.md create mode 100644 .github/skills/cloudflare/references/workerd/README.md create mode 100644 .github/skills/cloudflare/references/workerd/api.md create mode 100644 .github/skills/cloudflare/references/workerd/configuration.md create mode 100644 .github/skills/cloudflare/references/workerd/gotchas.md create mode 100644 .github/skills/cloudflare/references/workerd/patterns.md create mode 100644 .github/skills/cloudflare/references/workers-ai/README.md create mode 100644 .github/skills/cloudflare/references/workers-ai/api.md create mode 100644 .github/skills/cloudflare/references/workers-ai/configuration.md create mode 100644 .github/skills/cloudflare/references/workers-ai/gotchas.md create mode 100644 .github/skills/cloudflare/references/workers-ai/patterns.md create mode 100644 .github/skills/cloudflare/references/workers-for-platforms/README.md create mode 100644 .github/skills/cloudflare/references/workers-for-platforms/api.md create mode 100644 .github/skills/cloudflare/references/workers-for-platforms/configuration.md create mode 100644 .github/skills/cloudflare/references/workers-for-platforms/gotchas.md create mode 100644 .github/skills/cloudflare/references/workers-for-platforms/patterns.md create mode 100644 .github/skills/cloudflare/references/workers-playground/README.md create mode 100644 .github/skills/cloudflare/references/workers-playground/api.md create mode 100644 .github/skills/cloudflare/references/workers-playground/configuration.md create mode 100644 .github/skills/cloudflare/references/workers-playground/gotchas.md create mode 100644 .github/skills/cloudflare/references/workers-playground/patterns.md create mode 100644 .github/skills/cloudflare/references/workers-vpc/README.md create mode 100644 .github/skills/cloudflare/references/workers-vpc/api.md create mode 100644 .github/skills/cloudflare/references/workers-vpc/configuration.md create mode 100644 .github/skills/cloudflare/references/workers-vpc/gotchas.md create mode 100644 .github/skills/cloudflare/references/workers-vpc/patterns.md create mode 100644 .github/skills/cloudflare/references/workflows/README.md create mode 100644 .github/skills/cloudflare/references/workflows/api.md create mode 100644 .github/skills/cloudflare/references/workflows/configuration.md create mode 100644 .github/skills/cloudflare/references/workflows/gotchas.md create mode 100644 .github/skills/cloudflare/references/workflows/patterns.md create mode 100644 .github/skills/cloudflare/references/zaraz/IMPLEMENTATION_SUMMARY.md create mode 100644 .github/skills/cloudflare/references/zaraz/README.md create mode 100644 .github/skills/cloudflare/references/zaraz/api.md create mode 100644 .github/skills/cloudflare/references/zaraz/configuration.md create mode 100644 .github/skills/cloudflare/references/zaraz/gotchas.md create mode 100644 .github/skills/cloudflare/references/zaraz/patterns.md create mode 100644 .github/skills/codebase-design/DEEPENING.md create mode 100644 .github/skills/codebase-design/DESIGN-IT-TWICE.md create mode 100644 .github/skills/codebase-design/SKILL.md create mode 100644 .github/skills/codebase-design/agents/openai.yaml create mode 100644 .github/skills/deepinit/SKILL.md create mode 100644 .github/skills/design-taste-frontend/SKILL.md create mode 100644 .github/skills/durable-objects/SKILL.md create mode 100644 .github/skills/durable-objects/references/rules.md create mode 100644 .github/skills/durable-objects/references/testing.md create mode 100644 .github/skills/durable-objects/references/workers.md create mode 100644 .github/skills/find-skills/SKILL.md create mode 100644 .github/skills/golang-pro/SKILL.md create mode 100644 .github/skills/golang-pro/references/concurrency.md create mode 100644 .github/skills/golang-pro/references/generics.md create mode 100644 .github/skills/golang-pro/references/interfaces.md create mode 100644 .github/skills/golang-pro/references/project-structure.md create mode 100644 .github/skills/golang-pro/references/testing.md create mode 100644 .github/skills/grill-me/SKILL.md create mode 100644 .github/skills/grill-me/agents/openai.yaml create mode 100644 .github/skills/grill-with-docs/SKILL.md create mode 100644 .github/skills/grill-with-docs/agents/openai.yaml create mode 100644 .github/skills/grilling/SKILL.md create mode 100644 .github/skills/grilling/agents/openai.yaml create mode 100644 .github/skills/gum/.skillfish.json create mode 100644 .github/skills/gum/SKILL.md create mode 100644 .github/skills/gum/agents/openai.yaml create mode 100644 .github/skills/gum/references/commands.md create mode 100644 .github/skills/gum/references/recipes.md create mode 100644 .github/skills/high-end-visual-design/SKILL.md create mode 100644 .github/skills/improve-codebase-architecture/HTML-REPORT.md create mode 100644 .github/skills/improve-codebase-architecture/SKILL.md create mode 100644 .github/skills/improve-codebase-architecture/agents/openai.yaml create mode 100644 .github/skills/interface-design/SKILL.md create mode 100644 .github/skills/interface-design/agents/openai.yaml create mode 100644 .github/skills/laws-of-ux/SKILL.md create mode 100644 .github/skills/minimalist-ui/SKILL.md create mode 100644 .github/skills/no-ai-slop/SKILL.md create mode 100644 .github/skills/no-ai-slop/agents/openai.yaml create mode 100644 .github/skills/no-ai-slop/eval.md create mode 100644 .github/skills/obscura/SKILL.md create mode 100644 .github/skills/obsidian-vault/SKILL.md create mode 100644 .github/skills/openlogs-server-logs/SKILL.md create mode 100644 .github/skills/openlogs-server-logs/agents/openai.yaml create mode 100644 .github/skills/pr-lens/LICENSE create mode 100644 .github/skills/pr-lens/SKILL.md create mode 100644 .github/skills/pr-lens/references/config.md create mode 100644 .github/skills/pr-lens/references/example.graph.json create mode 100644 .github/skills/pr-lens/references/graph-document.md create mode 100644 .github/skills/prototype/LOGIC.md create mode 100644 .github/skills/prototype/SKILL.md create mode 100644 .github/skills/prototype/UI.md create mode 100644 .github/skills/prototype/agents/openai.yaml create mode 100644 .github/skills/qa/SKILL.md create mode 100644 .github/skills/react-email/SKILL.md create mode 100644 .github/skills/react/SKILL.md create mode 100644 .github/skills/remotion-best-practices/SKILL.md create mode 100644 .github/skills/remotion-best-practices/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-captions/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-captions/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-captions/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-captions/display-captions.md create mode 100644 .github/skills/remotion-best-practices/remotion-captions/import-srt-captions.md create mode 100644 .github/skills/remotion-best-practices/remotion-captions/transcribe-captions.md create mode 100644 .github/skills/remotion-best-practices/remotion-create/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-create/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-create/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-create/tailwind.md create mode 100644 .github/skills/remotion-best-practices/remotion-create/video-layout.md create mode 100644 .github/skills/remotion-best-practices/remotion-docs/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-docs/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-docs/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-interactivity/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-interactivity/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-interactivity/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-maps/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-maps/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/cesium-path.json create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/city-path.json create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/example-Root.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/flight-path.ts create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/sample-river.geojson create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-data-sources.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-troubleshooting.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/mapbox/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/mapbox/references/render-stability.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maplibre/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maplibre/references/render-stability.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/example-Root.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/tokens.ts create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-data-sources.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-geo-prep.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/render-stability.md create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs create mode 100644 .github/skills/remotion-best-practices/remotion-maps/techniques/static-map/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/3d.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-markup/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-markup/audio-visualization.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/audio.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/calculate-metadata.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/compositions.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/connected-compositions.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/cropping.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/effects.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/embedding-videos.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/ffmpeg.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/gifs.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/google-fonts.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/html-in-canvas.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/images.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/light-leaks.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/local-fonts.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/lottie.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/measuring-dom-nodes.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/measuring-text.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/motion-blur.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/multi-scene-video.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/parameters.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/cesium-path.json create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/city-path.json create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/example-Root.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/flight-path.ts create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/sample-river.geojson create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-data-sources.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-troubleshooting.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/mapbox/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/mapbox/references/render-stability.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maplibre/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maplibre/references/render-stability.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/example-Root.tsx create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/tokens.ts create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-data-sources.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-geo-prep.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/render-stability.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs create mode 100644 .github/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/static-map/TECHNIQUE.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/sequencing.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/sfx.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/silence-detection.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/text-highlights.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/timing.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/transitions.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/video-editing.md create mode 100644 .github/skills/remotion-best-practices/remotion-markup/voiceover.md create mode 100644 .github/skills/remotion-best-practices/remotion-multimedia/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-multimedia/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-multimedia/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-multimedia/get-audio-duration.md create mode 100644 .github/skills/remotion-best-practices/remotion-multimedia/get-video-dimensions.md create mode 100644 .github/skills/remotion-best-practices/remotion-multimedia/get-video-duration.md create mode 100644 .github/skills/remotion-best-practices/remotion-render/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-render/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-render/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-render/transparent-videos.md create mode 100644 .github/skills/remotion-best-practices/remotion-saas/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-saas/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-saas/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-saas/framework.md create mode 100644 .github/skills/remotion-best-practices/remotion-saas/player.md create mode 100644 .github/skills/remotion-best-practices/remotion-saas/rendering.md create mode 100644 .github/skills/remotion-best-practices/remotion-studio/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-studio/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-studio/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-best-practices/remotion-upgrade/REFERENCE.md create mode 100644 .github/skills/remotion-best-practices/remotion-upgrade/agents/openai.yaml create mode 100644 .github/skills/remotion-best-practices/remotion-upgrade/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-captions/SKILL.md create mode 100644 .github/skills/remotion-captions/agents/openai.yaml create mode 100644 .github/skills/remotion-captions/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-captions/display-captions.md create mode 100644 .github/skills/remotion-captions/import-srt-captions.md create mode 100644 .github/skills/remotion-captions/transcribe-captions.md create mode 100644 .github/skills/remotion-create/SKILL.md create mode 100644 .github/skills/remotion-create/agents/openai.yaml create mode 100644 .github/skills/remotion-create/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-create/tailwind.md create mode 100644 .github/skills/remotion-create/video-layout.md create mode 100644 .github/skills/remotion-docs/SKILL.md create mode 100644 .github/skills/remotion-docs/agents/openai.yaml create mode 100644 .github/skills/remotion-docs/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-interactivity/SKILL.md create mode 100644 .github/skills/remotion-interactivity/agents/openai.yaml create mode 100644 .github/skills/remotion-interactivity/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-maps/SKILL.md create mode 100644 .github/skills/remotion-maps/agents/openai.yaml create mode 100644 .github/skills/remotion-maps/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-maps/techniques/cesium/TECHNIQUE.md create mode 100644 .github/skills/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx create mode 100644 .github/skills/remotion-maps/techniques/cesium/assets/cesium-path.json create mode 100644 .github/skills/remotion-maps/techniques/cesium/assets/city-path.json create mode 100644 .github/skills/remotion-maps/techniques/cesium/assets/example-Root.tsx create mode 100644 .github/skills/remotion-maps/techniques/cesium/assets/flight-path.ts create mode 100644 .github/skills/remotion-maps/techniques/cesium/assets/sample-river.geojson create mode 100644 .github/skills/remotion-maps/techniques/cesium/references/3d-data-sources.md create mode 100644 .github/skills/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md create mode 100644 .github/skills/remotion-maps/techniques/cesium/references/3d-troubleshooting.md create mode 100644 .github/skills/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs create mode 100644 .github/skills/remotion-maps/techniques/mapbox/TECHNIQUE.md create mode 100644 .github/skills/remotion-maps/techniques/mapbox/references/render-stability.md create mode 100644 .github/skills/remotion-maps/techniques/maplibre/TECHNIQUE.md create mode 100644 .github/skills/remotion-maps/techniques/maplibre/references/render-stability.md create mode 100644 .github/skills/remotion-maps/techniques/maptiler/TECHNIQUE.md create mode 100644 .github/skills/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx create mode 100644 .github/skills/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts create mode 100644 .github/skills/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx create mode 100644 .github/skills/remotion-maps/techniques/maptiler/assets/example-Root.tsx create mode 100644 .github/skills/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json create mode 100644 .github/skills/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json create mode 100644 .github/skills/remotion-maps/techniques/maptiler/assets/tokens.ts create mode 100644 .github/skills/remotion-maps/techniques/maptiler/references/map-data-sources.md create mode 100644 .github/skills/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md create mode 100644 .github/skills/remotion-maps/techniques/maptiler/references/map-geo-prep.md create mode 100644 .github/skills/remotion-maps/techniques/maptiler/references/render-stability.md create mode 100644 .github/skills/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs create mode 100644 .github/skills/remotion-maps/techniques/static-map/TECHNIQUE.md create mode 100644 .github/skills/remotion-markup/3d.md create mode 100644 .github/skills/remotion-markup/SKILL.md create mode 100644 .github/skills/remotion-markup/agents/openai.yaml create mode 100644 .github/skills/remotion-markup/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-markup/audio-visualization.md create mode 100644 .github/skills/remotion-markup/audio.md create mode 100644 .github/skills/remotion-markup/calculate-metadata.md create mode 100644 .github/skills/remotion-markup/compositions.md create mode 100644 .github/skills/remotion-markup/connected-compositions.md create mode 100644 .github/skills/remotion-markup/cropping.md create mode 100644 .github/skills/remotion-markup/effects.md create mode 100644 .github/skills/remotion-markup/embedding-videos.md create mode 100644 .github/skills/remotion-markup/ffmpeg.md create mode 100644 .github/skills/remotion-markup/gifs.md create mode 100644 .github/skills/remotion-markup/google-fonts.md create mode 100644 .github/skills/remotion-markup/html-in-canvas.md create mode 100644 .github/skills/remotion-markup/images.md create mode 100644 .github/skills/remotion-markup/light-leaks.md create mode 100644 .github/skills/remotion-markup/local-fonts.md create mode 100644 .github/skills/remotion-markup/lottie.md create mode 100644 .github/skills/remotion-markup/measuring-dom-nodes.md create mode 100644 .github/skills/remotion-markup/measuring-text.md create mode 100644 .github/skills/remotion-markup/motion-blur.md create mode 100644 .github/skills/remotion-markup/multi-scene-video.md create mode 100644 .github/skills/remotion-markup/parameters.md create mode 100644 .github/skills/remotion-markup/remotion-maps/REFERENCE.md create mode 100644 .github/skills/remotion-markup/remotion-maps/agents/openai.yaml create mode 100644 .github/skills/remotion-markup/remotion-maps/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/TECHNIQUE.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/assets/cesium-path.json create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/assets/city-path.json create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/assets/example-Root.tsx create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/assets/flight-path.ts create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/assets/sample-river.geojson create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-data-sources.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-troubleshooting.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/mapbox/TECHNIQUE.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/mapbox/references/render-stability.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maplibre/TECHNIQUE.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maplibre/references/render-stability.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/TECHNIQUE.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/example-Root.tsx create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/tokens.ts create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-data-sources.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-geo-prep.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/references/render-stability.md create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs create mode 100644 .github/skills/remotion-markup/remotion-maps/techniques/static-map/TECHNIQUE.md create mode 100644 .github/skills/remotion-markup/sequencing.md create mode 100644 .github/skills/remotion-markup/sfx.md create mode 100644 .github/skills/remotion-markup/silence-detection.md create mode 100644 .github/skills/remotion-markup/text-highlights.md create mode 100644 .github/skills/remotion-markup/timing.md create mode 100644 .github/skills/remotion-markup/transitions.md create mode 100644 .github/skills/remotion-markup/video-editing.md create mode 100644 .github/skills/remotion-markup/voiceover.md create mode 100644 .github/skills/remotion-multimedia/SKILL.md create mode 100644 .github/skills/remotion-multimedia/agents/openai.yaml create mode 100644 .github/skills/remotion-multimedia/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-multimedia/get-audio-duration.md create mode 100644 .github/skills/remotion-multimedia/get-video-dimensions.md create mode 100644 .github/skills/remotion-multimedia/get-video-duration.md create mode 100644 .github/skills/remotion-render/SKILL.md create mode 100644 .github/skills/remotion-render/agents/openai.yaml create mode 100644 .github/skills/remotion-render/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-render/transparent-videos.md create mode 100644 .github/skills/remotion-saas/SKILL.md create mode 100644 .github/skills/remotion-saas/agents/openai.yaml create mode 100644 .github/skills/remotion-saas/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-saas/framework.md create mode 100644 .github/skills/remotion-saas/player.md create mode 100644 .github/skills/remotion-saas/rendering.md create mode 100644 .github/skills/remotion-studio/SKILL.md create mode 100644 .github/skills/remotion-studio/agents/openai.yaml create mode 100644 .github/skills/remotion-studio/assets/remotion-icon.svg create mode 100644 .github/skills/remotion-upgrade/SKILL.md create mode 100644 .github/skills/remotion-upgrade/agents/openai.yaml create mode 100644 .github/skills/remotion-upgrade/assets/remotion-icon.svg create mode 100644 .github/skills/request-refactor-plan/SKILL.md create mode 100644 .github/skills/resolving-merge-conflicts/SKILL.md create mode 100644 .github/skills/resolving-merge-conflicts/agents/openai.yaml create mode 100644 .github/skills/rust-async-patterns/SKILL.md create mode 100644 .github/skills/rust-async-patterns/references/details.md create mode 100644 .github/skills/rust-best-practices/SKILL.md create mode 100644 .github/skills/rust-best-practices/references/chapter_01.md create mode 100644 .github/skills/rust-best-practices/references/chapter_02.md create mode 100644 .github/skills/rust-best-practices/references/chapter_03.md create mode 100644 .github/skills/rust-best-practices/references/chapter_04.md create mode 100644 .github/skills/rust-best-practices/references/chapter_05.md create mode 100644 .github/skills/rust-best-practices/references/chapter_06.md create mode 100644 .github/skills/rust-best-practices/references/chapter_07.md create mode 100644 .github/skills/rust-best-practices/references/chapter_08.md create mode 100644 .github/skills/rust-best-practices/references/chapter_09.md create mode 100644 .github/skills/rust-skills/.github/workflows/ci.yml create mode 100644 .github/skills/rust-skills/AGENTS.md create mode 100644 .github/skills/rust-skills/CHANGELOG.md create mode 100644 .github/skills/rust-skills/CLAUDE.md create mode 100644 .github/skills/rust-skills/CONTRIBUTING.md create mode 100644 .github/skills/rust-skills/LICENSE create mode 100644 .github/skills/rust-skills/README.md create mode 100644 .github/skills/rust-skills/SKILL.md create mode 100644 .github/skills/rust-skills/checks/.gitignore create mode 100644 .github/skills/rust-skills/checks/Cargo.lock create mode 100644 .github/skills/rust-skills/checks/Cargo.toml create mode 100644 .github/skills/rust-skills/checks/README.md create mode 100644 .github/skills/rust-skills/checks/analyze.py create mode 100644 .github/skills/rust-skills/checks/baseline.txt create mode 100755 .github/skills/rust-skills/checks/check.sh create mode 100644 .github/skills/rust-skills/checks/gen.py create mode 100644 .github/skills/rust-skills/checks/gen_index.py create mode 100644 .github/skills/rust-skills/checks/rust-toolchain.toml create mode 100644 .github/skills/rust-skills/checks/src/lib.rs create mode 100644 .github/skills/rust-skills/checks/validate.py create mode 100644 .github/skills/rust-skills/rules/anti-clone-excessive.md create mode 100644 .github/skills/rust-skills/rules/anti-collect-intermediate.md create mode 100644 .github/skills/rust-skills/rules/anti-empty-catch.md create mode 100644 .github/skills/rust-skills/rules/anti-expect-lazy.md create mode 100644 .github/skills/rust-skills/rules/anti-format-hot-path.md create mode 100644 .github/skills/rust-skills/rules/anti-index-over-iter.md create mode 100644 .github/skills/rust-skills/rules/anti-lock-across-await.md create mode 100644 .github/skills/rust-skills/rules/anti-over-abstraction.md create mode 100644 .github/skills/rust-skills/rules/anti-panic-expected.md create mode 100644 .github/skills/rust-skills/rules/anti-premature-optimize.md create mode 100644 .github/skills/rust-skills/rules/anti-string-for-str.md create mode 100644 .github/skills/rust-skills/rules/anti-stringly-typed.md create mode 100644 .github/skills/rust-skills/rules/anti-type-erasure.md create mode 100644 .github/skills/rust-skills/rules/anti-unwrap-abuse.md create mode 100644 .github/skills/rust-skills/rules/anti-vec-for-slice.md create mode 100644 .github/skills/rust-skills/rules/api-builder-must-use.md create mode 100644 .github/skills/rust-skills/rules/api-builder-pattern.md create mode 100644 .github/skills/rust-skills/rules/api-common-traits.md create mode 100644 .github/skills/rust-skills/rules/api-default-impl.md create mode 100644 .github/skills/rust-skills/rules/api-extension-trait.md create mode 100644 .github/skills/rust-skills/rules/api-from-not-into.md create mode 100644 .github/skills/rust-skills/rules/api-impl-asref.md create mode 100644 .github/skills/rust-skills/rules/api-impl-fromiterator.md create mode 100644 .github/skills/rust-skills/rules/api-impl-into.md create mode 100644 .github/skills/rust-skills/rules/api-must-use.md create mode 100644 .github/skills/rust-skills/rules/api-newtype-safety.md create mode 100644 .github/skills/rust-skills/rules/api-non-exhaustive.md create mode 100644 .github/skills/rust-skills/rules/api-operator-overload.md create mode 100644 .github/skills/rust-skills/rules/api-parse-dont-validate.md create mode 100644 .github/skills/rust-skills/rules/api-sealed-trait.md create mode 100644 .github/skills/rust-skills/rules/api-serde-optional.md create mode 100644 .github/skills/rust-skills/rules/api-typestate.md create mode 100644 .github/skills/rust-skills/rules/async-async-fn-bounds.md create mode 100644 .github/skills/rust-skills/rules/async-bounded-channel.md create mode 100644 .github/skills/rust-skills/rules/async-broadcast-pubsub.md create mode 100644 .github/skills/rust-skills/rules/async-cancel-safety.md create mode 100644 .github/skills/rust-skills/rules/async-cancellation-token.md create mode 100644 .github/skills/rust-skills/rules/async-clone-before-await.md create mode 100644 .github/skills/rust-skills/rules/async-fn-in-trait.md create mode 100644 .github/skills/rust-skills/rules/async-join-parallel.md create mode 100644 .github/skills/rust-skills/rules/async-joinset-structured.md create mode 100644 .github/skills/rust-skills/rules/async-mpsc-queue.md create mode 100644 .github/skills/rust-skills/rules/async-no-lock-await.md create mode 100644 .github/skills/rust-skills/rules/async-oneshot-response.md create mode 100644 .github/skills/rust-skills/rules/async-select-racing.md create mode 100644 .github/skills/rust-skills/rules/async-spawn-blocking.md create mode 100644 .github/skills/rust-skills/rules/async-tokio-fs.md create mode 100644 .github/skills/rust-skills/rules/async-tokio-runtime.md create mode 100644 .github/skills/rust-skills/rules/async-try-join.md create mode 100644 .github/skills/rust-skills/rules/async-watch-latest.md create mode 100644 .github/skills/rust-skills/rules/closure-disjoint-capture.md create mode 100644 .github/skills/rust-skills/rules/closure-fn-trait-bounds.md create mode 100644 .github/skills/rust-skills/rules/closure-impl-fn-return.md create mode 100644 .github/skills/rust-skills/rules/closure-move-capture.md create mode 100644 .github/skills/rust-skills/rules/closure-static-vs-dyn.md create mode 100644 .github/skills/rust-skills/rules/coll-binaryheap.md create mode 100644 .github/skills/rust-skills/rules/coll-map-choice.md create mode 100644 .github/skills/rust-skills/rules/coll-seq-choice.md create mode 100644 .github/skills/rust-skills/rules/coll-set-membership.md create mode 100644 .github/skills/rust-skills/rules/conc-atomic-ordering.md create mode 100644 .github/skills/rust-skills/rules/conc-rayon-par-iter.md create mode 100644 .github/skills/rust-skills/rules/conc-scoped-threads.md create mode 100644 .github/skills/rust-skills/rules/conc-thread-local.md create mode 100644 .github/skills/rust-skills/rules/const-block.md create mode 100644 .github/skills/rust-skills/rules/const-fn.md create mode 100644 .github/skills/rust-skills/rules/const-generics.md create mode 100644 .github/skills/rust-skills/rules/const-vs-static.md create mode 100644 .github/skills/rust-skills/rules/conv-asmut-mutable.md create mode 100644 .github/skills/rust-skills/rules/conv-fromstr-parsing.md create mode 100644 .github/skills/rust-skills/rules/conv-tryfrom-fallible.md create mode 100644 .github/skills/rust-skills/rules/doc-all-public.md create mode 100644 .github/skills/rust-skills/rules/doc-cargo-metadata.md create mode 100644 .github/skills/rust-skills/rules/doc-crate-readme.md create mode 100644 .github/skills/rust-skills/rules/doc-errors-section.md create mode 100644 .github/skills/rust-skills/rules/doc-examples-section.md create mode 100644 .github/skills/rust-skills/rules/doc-hidden-setup.md create mode 100644 .github/skills/rust-skills/rules/doc-intra-links.md create mode 100644 .github/skills/rust-skills/rules/doc-link-types.md create mode 100644 .github/skills/rust-skills/rules/doc-module-inner.md create mode 100644 .github/skills/rust-skills/rules/doc-panics-section.md create mode 100644 .github/skills/rust-skills/rules/doc-question-mark.md create mode 100644 .github/skills/rust-skills/rules/doc-safety-section.md create mode 100644 .github/skills/rust-skills/rules/err-anyhow-app.md create mode 100644 .github/skills/rust-skills/rules/err-context-chain.md create mode 100644 .github/skills/rust-skills/rules/err-custom-type.md create mode 100644 .github/skills/rust-skills/rules/err-doc-errors.md create mode 100644 .github/skills/rust-skills/rules/err-expect-bugs-only.md create mode 100644 .github/skills/rust-skills/rules/err-from-impl.md create mode 100644 .github/skills/rust-skills/rules/err-lowercase-msg.md create mode 100644 .github/skills/rust-skills/rules/err-no-unwrap-prod.md create mode 100644 .github/skills/rust-skills/rules/err-question-mark.md create mode 100644 .github/skills/rust-skills/rules/err-result-over-panic.md create mode 100644 .github/skills/rust-skills/rules/err-source-chain.md create mode 100644 .github/skills/rust-skills/rules/err-thiserror-lib.md create mode 100644 .github/skills/rust-skills/rules/lint-cargo-metadata.md create mode 100644 .github/skills/rust-skills/rules/lint-cfg-check.md create mode 100644 .github/skills/rust-skills/rules/lint-clippy-nursery-selected.md create mode 100644 .github/skills/rust-skills/rules/lint-deny-correctness.md create mode 100644 .github/skills/rust-skills/rules/lint-missing-docs.md create mode 100644 .github/skills/rust-skills/rules/lint-pedantic-selective.md create mode 100644 .github/skills/rust-skills/rules/lint-rustfmt-check.md create mode 100644 .github/skills/rust-skills/rules/lint-unsafe-doc.md create mode 100644 .github/skills/rust-skills/rules/lint-warn-complexity.md create mode 100644 .github/skills/rust-skills/rules/lint-warn-perf.md create mode 100644 .github/skills/rust-skills/rules/lint-warn-style.md create mode 100644 .github/skills/rust-skills/rules/lint-warn-suspicious.md create mode 100644 .github/skills/rust-skills/rules/lint-workspace-lints.md create mode 100644 .github/skills/rust-skills/rules/macro-export-crate-path.md create mode 100644 .github/skills/rust-skills/rules/macro-fragment-specifiers.md create mode 100644 .github/skills/rust-skills/rules/macro-prefer-functions.md create mode 100644 .github/skills/rust-skills/rules/macro-private-helpers.md create mode 100644 .github/skills/rust-skills/rules/macro-proc-error-spans.md create mode 100644 .github/skills/rust-skills/rules/macro-proc-syn-quote.md create mode 100644 .github/skills/rust-skills/rules/macro-proc-two-crate.md create mode 100644 .github/skills/rust-skills/rules/macro-rules-hygiene.md create mode 100644 .github/skills/rust-skills/rules/mem-arena-allocator.md create mode 100644 .github/skills/rust-skills/rules/mem-arrayvec.md create mode 100644 .github/skills/rust-skills/rules/mem-assert-type-size.md create mode 100644 .github/skills/rust-skills/rules/mem-avoid-format.md create mode 100644 .github/skills/rust-skills/rules/mem-box-large-variant.md create mode 100644 .github/skills/rust-skills/rules/mem-boxed-slice.md create mode 100644 .github/skills/rust-skills/rules/mem-clone-from.md create mode 100644 .github/skills/rust-skills/rules/mem-compact-string.md create mode 100644 .github/skills/rust-skills/rules/mem-drop-order.md create mode 100644 .github/skills/rust-skills/rules/mem-reuse-collections.md create mode 100644 .github/skills/rust-skills/rules/mem-smaller-integers.md create mode 100644 .github/skills/rust-skills/rules/mem-smallvec.md create mode 100644 .github/skills/rust-skills/rules/mem-take-replace.md create mode 100644 .github/skills/rust-skills/rules/mem-thinvec.md create mode 100644 .github/skills/rust-skills/rules/mem-with-capacity.md create mode 100644 .github/skills/rust-skills/rules/mem-write-over-format.md create mode 100644 .github/skills/rust-skills/rules/mem-zero-copy.md create mode 100644 .github/skills/rust-skills/rules/name-acronym-word.md create mode 100644 .github/skills/rust-skills/rules/name-as-free.md create mode 100644 .github/skills/rust-skills/rules/name-consts-screaming.md create mode 100644 .github/skills/rust-skills/rules/name-crate-no-rs.md create mode 100644 .github/skills/rust-skills/rules/name-funcs-snake.md create mode 100644 .github/skills/rust-skills/rules/name-into-ownership.md create mode 100644 .github/skills/rust-skills/rules/name-is-has-bool.md create mode 100644 .github/skills/rust-skills/rules/name-iter-convention.md create mode 100644 .github/skills/rust-skills/rules/name-iter-method.md create mode 100644 .github/skills/rust-skills/rules/name-iter-type-match.md create mode 100644 .github/skills/rust-skills/rules/name-lifetime-short.md create mode 100644 .github/skills/rust-skills/rules/name-no-get-prefix.md create mode 100644 .github/skills/rust-skills/rules/name-to-expensive.md create mode 100644 .github/skills/rust-skills/rules/name-type-param-single.md create mode 100644 .github/skills/rust-skills/rules/name-types-camel.md create mode 100644 .github/skills/rust-skills/rules/name-variants-camel.md create mode 100644 .github/skills/rust-skills/rules/num-cast-try-from.md create mode 100644 .github/skills/rust-skills/rules/num-float-compare.md create mode 100644 .github/skills/rust-skills/rules/num-nonzero.md create mode 100644 .github/skills/rust-skills/rules/num-overflow-explicit.md create mode 100644 .github/skills/rust-skills/rules/num-saturating-clamp.md create mode 100644 .github/skills/rust-skills/rules/obs-error-chain.md create mode 100644 .github/skills/rust-skills/rules/obs-instrument-spans.md create mode 100644 .github/skills/rust-skills/rules/obs-levels-filter.md create mode 100644 .github/skills/rust-skills/rules/obs-library-facade.md create mode 100644 .github/skills/rust-skills/rules/obs-no-sensitive-data.md create mode 100644 .github/skills/rust-skills/rules/obs-structured-fields.md create mode 100644 .github/skills/rust-skills/rules/obs-tracing-over-log.md create mode 100644 .github/skills/rust-skills/rules/opt-bounds-check.md create mode 100644 .github/skills/rust-skills/rules/opt-cache-friendly.md create mode 100644 .github/skills/rust-skills/rules/opt-codegen-units.md create mode 100644 .github/skills/rust-skills/rules/opt-cold-unlikely.md create mode 100644 .github/skills/rust-skills/rules/opt-inline-always-rare.md create mode 100644 .github/skills/rust-skills/rules/opt-inline-never-cold.md create mode 100644 .github/skills/rust-skills/rules/opt-inline-small.md create mode 100644 .github/skills/rust-skills/rules/opt-likely-hint.md create mode 100644 .github/skills/rust-skills/rules/opt-lto-release.md create mode 100644 .github/skills/rust-skills/rules/opt-pgo-profile.md create mode 100644 .github/skills/rust-skills/rules/opt-simd-portable.md create mode 100644 .github/skills/rust-skills/rules/opt-target-cpu.md create mode 100644 .github/skills/rust-skills/rules/own-arc-shared.md create mode 100644 .github/skills/rust-skills/rules/own-borrow-over-clone.md create mode 100644 .github/skills/rust-skills/rules/own-clone-explicit.md create mode 100644 .github/skills/rust-skills/rules/own-copy-small.md create mode 100644 .github/skills/rust-skills/rules/own-cow-conditional.md create mode 100644 .github/skills/rust-skills/rules/own-lifetime-elision.md create mode 100644 .github/skills/rust-skills/rules/own-move-large.md create mode 100644 .github/skills/rust-skills/rules/own-mutex-interior.md create mode 100644 .github/skills/rust-skills/rules/own-rc-single-thread.md create mode 100644 .github/skills/rust-skills/rules/own-refcell-interior.md create mode 100644 .github/skills/rust-skills/rules/own-rwlock-readers.md create mode 100644 .github/skills/rust-skills/rules/own-slice-over-vec.md create mode 100644 .github/skills/rust-skills/rules/pat-at-bindings.md create mode 100644 .github/skills/rust-skills/rules/pat-exhaustive-enum.md create mode 100644 .github/skills/rust-skills/rules/pat-if-let-chains.md create mode 100644 .github/skills/rust-skills/rules/pat-let-else.md create mode 100644 .github/skills/rust-skills/rules/pat-matches-macro.md create mode 100644 .github/skills/rust-skills/rules/perf-ahash.md create mode 100644 .github/skills/rust-skills/rules/perf-black-box-bench.md create mode 100644 .github/skills/rust-skills/rules/perf-chain-avoid.md create mode 100644 .github/skills/rust-skills/rules/perf-collect-into.md create mode 100644 .github/skills/rust-skills/rules/perf-collect-once.md create mode 100644 .github/skills/rust-skills/rules/perf-drain-reuse.md create mode 100644 .github/skills/rust-skills/rules/perf-entry-api.md create mode 100644 .github/skills/rust-skills/rules/perf-extend-batch.md create mode 100644 .github/skills/rust-skills/rules/perf-io-buffering.md create mode 100644 .github/skills/rust-skills/rules/perf-iter-lazy.md create mode 100644 .github/skills/rust-skills/rules/perf-iter-over-index.md create mode 100644 .github/skills/rust-skills/rules/perf-profile-first.md create mode 100644 .github/skills/rust-skills/rules/perf-release-profile.md create mode 100644 .github/skills/rust-skills/rules/proj-bin-dir.md create mode 100644 .github/skills/rust-skills/rules/proj-build-rs-minimal.md create mode 100644 .github/skills/rust-skills/rules/proj-feature-additive.md create mode 100644 .github/skills/rust-skills/rules/proj-flat-small.md create mode 100644 .github/skills/rust-skills/rules/proj-lib-main-split.md create mode 100644 .github/skills/rust-skills/rules/proj-mod-by-feature.md create mode 100644 .github/skills/rust-skills/rules/proj-mod-rs-dir.md create mode 100644 .github/skills/rust-skills/rules/proj-msrv-declare.md create mode 100644 .github/skills/rust-skills/rules/proj-prelude-module.md create mode 100644 .github/skills/rust-skills/rules/proj-pub-crate-internal.md create mode 100644 .github/skills/rust-skills/rules/proj-pub-super-parent.md create mode 100644 .github/skills/rust-skills/rules/proj-pub-use-reexport.md create mode 100644 .github/skills/rust-skills/rules/proj-workspace-deps.md create mode 100644 .github/skills/rust-skills/rules/proj-workspace-large.md create mode 100644 .github/skills/rust-skills/rules/serde-custom-with.md create mode 100644 .github/skills/rust-skills/rules/serde-default-compat.md create mode 100644 .github/skills/rust-skills/rules/serde-deny-unknown-fields.md create mode 100644 .github/skills/rust-skills/rules/serde-enum-representation.md create mode 100644 .github/skills/rust-skills/rules/serde-flatten.md create mode 100644 .github/skills/rust-skills/rules/serde-rename-all.md create mode 100644 .github/skills/rust-skills/rules/serde-skip-empty.md create mode 100644 .github/skills/rust-skills/rules/serde-try-from-validate.md create mode 100644 .github/skills/rust-skills/rules/test-arrange-act-assert.md create mode 100644 .github/skills/rust-skills/rules/test-cfg-test-module.md create mode 100644 .github/skills/rust-skills/rules/test-criterion-bench.md create mode 100644 .github/skills/rust-skills/rules/test-descriptive-names.md create mode 100644 .github/skills/rust-skills/rules/test-doctest-examples.md create mode 100644 .github/skills/rust-skills/rules/test-fixture-raii.md create mode 100644 .github/skills/rust-skills/rules/test-integration-dir.md create mode 100644 .github/skills/rust-skills/rules/test-loom-concurrency.md create mode 100644 .github/skills/rust-skills/rules/test-mock-traits.md create mode 100644 .github/skills/rust-skills/rules/test-mockall-mocking.md create mode 100644 .github/skills/rust-skills/rules/test-proptest-properties.md create mode 100644 .github/skills/rust-skills/rules/test-should-panic.md create mode 100644 .github/skills/rust-skills/rules/test-snapshot-testing.md create mode 100644 .github/skills/rust-skills/rules/test-tokio-async.md create mode 100644 .github/skills/rust-skills/rules/test-use-super.md create mode 100644 .github/skills/rust-skills/rules/trait-associated-type-vs-generic.md create mode 100644 .github/skills/rust-skills/rules/trait-blanket-impl.md create mode 100644 .github/skills/rust-skills/rules/trait-coherence-newtype.md create mode 100644 .github/skills/rust-skills/rules/trait-default-methods.md create mode 100644 .github/skills/rust-skills/rules/trait-dyn-vs-generic.md create mode 100644 .github/skills/rust-skills/rules/trait-object-safety.md create mode 100644 .github/skills/rust-skills/rules/type-deref-coercion.md create mode 100644 .github/skills/rust-skills/rules/type-display-vs-debug.md create mode 100644 .github/skills/rust-skills/rules/type-enum-states.md create mode 100644 .github/skills/rust-skills/rules/type-generic-bounds.md create mode 100644 .github/skills/rust-skills/rules/type-never-diverge.md create mode 100644 .github/skills/rust-skills/rules/type-newtype-ids.md create mode 100644 .github/skills/rust-skills/rules/type-newtype-validated.md create mode 100644 .github/skills/rust-skills/rules/type-no-stringly.md create mode 100644 .github/skills/rust-skills/rules/type-numeric-fmt.md create mode 100644 .github/skills/rust-skills/rules/type-option-nullable.md create mode 100644 .github/skills/rust-skills/rules/type-phantom-marker.md create mode 100644 .github/skills/rust-skills/rules/type-repr-transparent.md create mode 100644 .github/skills/rust-skills/rules/type-result-fallible.md create mode 100644 .github/skills/rust-skills/rules/unsafe-extern-block.md create mode 100644 .github/skills/rust-skills/rules/unsafe-maybeuninit.md create mode 100644 .github/skills/rust-skills/rules/unsafe-minimize-scope.md create mode 100644 .github/skills/rust-skills/rules/unsafe-miri-ci.md create mode 100644 .github/skills/rust-skills/rules/unsafe-no-mangle-unsafe.md create mode 100644 .github/skills/rust-skills/rules/unsafe-safety-comment.md create mode 100644 .github/skills/rust-skills/rules/unsafe-send-sync-manual.md create mode 100644 .github/skills/rust-testing/SKILL.md create mode 100644 .github/skills/setup-matt-pocock-skills/SKILL.md create mode 100644 .github/skills/setup-matt-pocock-skills/agents/openai.yaml create mode 100644 .github/skills/setup-matt-pocock-skills/domain.md create mode 100644 .github/skills/setup-matt-pocock-skills/issue-tracker-github.md create mode 100644 .github/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md create mode 100644 .github/skills/setup-matt-pocock-skills/issue-tracker-local.md create mode 100644 .github/skills/setup-matt-pocock-skills/triage-labels.md create mode 100644 .github/skills/shadcn/SKILL.md create mode 100644 .github/skills/shadcn/agents/openai.yml create mode 100644 .github/skills/shadcn/assets/shadcn-small.png create mode 100644 .github/skills/shadcn/assets/shadcn.png create mode 100644 .github/skills/shadcn/cli.md create mode 100644 .github/skills/shadcn/customization.md create mode 100644 .github/skills/shadcn/evals/evals.json create mode 100644 .github/skills/shadcn/mcp.md create mode 100644 .github/skills/shadcn/registry.md create mode 100644 .github/skills/shadcn/rules/base-vs-radix.md create mode 100644 .github/skills/shadcn/rules/chat.md create mode 100644 .github/skills/shadcn/rules/composition.md create mode 100644 .github/skills/shadcn/rules/forms.md create mode 100644 .github/skills/shadcn/rules/icons.md create mode 100644 .github/skills/shadcn/rules/styling.md create mode 100644 .github/skills/stop-slop/CHANGELOG.md create mode 100644 .github/skills/stop-slop/LICENSE create mode 100644 .github/skills/stop-slop/README.md create mode 100644 .github/skills/stop-slop/SKILL.md create mode 100644 .github/skills/stop-slop/references/examples.md create mode 100644 .github/skills/stop-slop/references/phrases.md create mode 100644 .github/skills/stop-slop/references/structures.md create mode 100644 .github/skills/tanstack-form/SKILL.md create mode 100644 .github/skills/tanstack-integration-best-practices/SKILL.md create mode 100644 .github/skills/tanstack-integration-best-practices/rules/cache-single-source.md create mode 100644 .github/skills/tanstack-integration-best-practices/rules/flow-loader-query-pattern.md create mode 100644 .github/skills/tanstack-integration-best-practices/rules/setup-query-client-context.md create mode 100644 .github/skills/tanstack-integration-best-practices/rules/ssr-dehydrate-hydrate.md create mode 100644 .github/skills/tanstack-query-best-practices/SKILL.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/cache-defaults.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/cache-gc-time.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/cache-invalidation.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/cache-placeholder-vs-initial.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/cache-stale-time.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/err-error-boundaries.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/err-fallback-data.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/err-retry-config.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/inf-loading-guards.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/inf-max-pages.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/inf-page-params.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/mut-error-handling.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/mut-invalidate-queries.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/mut-loading-states.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/mut-mutation-state.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/mut-optimistic-updates.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/mut-rollback-context.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/network-mode.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/parallel-use-queries.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/perf-notify-change-props.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/perf-placeholder-data.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/perf-select-transform.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/perf-structural-sharing.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/persist-queries.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/pf-ensure-query-data.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/pf-intent-prefetch.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/pf-route-prefetch.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/pf-stale-time-config.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/qk-array-structure.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/qk-factory-pattern.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/qk-hierarchical-organization.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/qk-include-dependencies.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/qk-serializable.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/query-cancellation.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/ssr-client-per-request.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/ssr-dehydration.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/ssr-hydration-boundary.md create mode 100644 .github/skills/tanstack-query-best-practices/rules/ssr-stale-time-server.md create mode 100644 .github/skills/tanstack-router-best-practices/SKILL.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/ctx-before-load.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/ctx-dependency-injection.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/ctx-root-context.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/err-not-found.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/load-deferred-data.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/load-ensure-query-data.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/load-error-handling.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/load-loader-deps.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/load-parallel.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/load-use-loaders.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/nav-active-states.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/nav-link-component.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/nav-relative-paths.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/nav-route-masks.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/nav-use-navigate.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/org-file-based-routing.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/org-index-routes.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/org-pathless-layouts.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/org-route-tree-structure.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/org-virtual-routes.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/preload-intent.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/preload-manual.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/preload-stale-time.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/router-default-options.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/search-custom-serializer.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/search-defaults.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/search-middleware.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/search-type-inheritance.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/search-validation.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/split-auto-splitting.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/split-critical-path.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/split-lazy-routes.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/ts-query-options-loader.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/ts-register-router.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/ts-route-context-typing.md create mode 100644 .github/skills/tanstack-router-best-practices/rules/ts-use-from-param.md create mode 100644 .github/skills/tanstack-start-best-practices/SKILL.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/api-routes.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/auth-cookie-security.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/auth-route-protection.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/auth-server-functions.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/auth-session-management.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/deploy-adapters.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/deploy-env-config.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/env-functions.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/err-not-found.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/err-redirects.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/err-server-errors.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/file-functions-file.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/file-separation.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/file-shared-validation.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/mw-composability.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/mw-context-flow.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/mw-function-middleware.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/mw-request-middleware.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sec-auth-middleware.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sec-csrf-protection.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sec-sensitive-data.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sec-validate-inputs.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sf-create-server-fn.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sf-error-handling.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sf-input-validation.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sf-method-selection.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/sf-response-headers.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/ssr-data-loading.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/ssr-hydration-safety.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/ssr-prerender.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/ssr-selective.md create mode 100644 .github/skills/tanstack-start-best-practices/rules/ssr-streaming.md create mode 100644 .github/skills/tanstack-table/SKILL.md create mode 100644 .github/skills/tdd/SKILL.md create mode 100644 .github/skills/tdd/agents/openai.yaml create mode 100644 .github/skills/tdd/mocking.md create mode 100644 .github/skills/tdd/tests.md create mode 100644 .github/skills/typescript-expert/SKILL.md create mode 100644 .github/skills/typescript-expert/agents/openai.yaml create mode 100644 .github/skills/ui-ux-pro-max/SKILL.md create mode 100644 .github/skills/ui-ux-pro-max/data/app-interface.csv create mode 100644 .github/skills/ui-ux-pro-max/data/catalog-summary.json create mode 100644 .github/skills/ui-ux-pro-max/data/charts.csv create mode 100644 .github/skills/ui-ux-pro-max/data/colors.csv create mode 100644 .github/skills/ui-ux-pro-max/data/data-provenance.json create mode 100644 .github/skills/ui-ux-pro-max/data/google-font-licenses.json create mode 100644 .github/skills/ui-ux-pro-max/data/google-fonts.csv create mode 100644 .github/skills/ui-ux-pro-max/data/icons.csv create mode 100644 .github/skills/ui-ux-pro-max/data/landing.csv create mode 100644 .github/skills/ui-ux-pro-max/data/motion.csv create mode 100644 .github/skills/ui-ux-pro-max/data/phosphor-icons-upstream.json create mode 100644 .github/skills/ui-ux-pro-max/data/products.csv create mode 100644 .github/skills/ui-ux-pro-max/data/react-performance.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/angular.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/astro.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/avalonia.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/flutter.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/javafx.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/laravel.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/nextjs.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/react-native.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/react.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/shadcn.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/svelte.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/swiftui.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/threejs.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/uno.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/uwp.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/vue.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/winui.csv create mode 100644 .github/skills/ui-ux-pro-max/data/stacks/wpf.csv create mode 100644 .github/skills/ui-ux-pro-max/data/styles.csv create mode 100644 .github/skills/ui-ux-pro-max/data/typography.csv create mode 100644 .github/skills/ui-ux-pro-max/data/ui-reasoning.csv create mode 100644 .github/skills/ui-ux-pro-max/data/ux-guidelines.csv create mode 100644 .github/skills/ui-ux-pro-max/references/pro-rules.md create mode 100644 .github/skills/ui-ux-pro-max/references/quick-reference.md create mode 100644 .github/skills/ui-ux-pro-max/scripts/core.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/design_system.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/reasoning_contract.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/search.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-api.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-catalog.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-existing.csv create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-metadata.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-overrides.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/icons-curated.csv create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-core.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-package.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-exports.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-package.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-baseline.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-cases.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-thresholds.json create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_catalog_refresh.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_catalog_summary_line_endings.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_core.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_core_data_quality.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_data_contracts.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_design_system_mode.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_design_system_stack.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_native_desktop_stack_freshness.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_relevance_evaluator.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_skill_script_paths.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_style_taxonomy.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_text_layout_resilience.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/tests/test_web_stack_freshness.py create mode 100644 .github/skills/ui-ux-pro-max/scripts/validate_data.py create mode 100644 .github/skills/uv-package-manager/SKILL.md create mode 100644 .github/skills/uv-package-manager/references/advanced-patterns.md create mode 100644 .github/skills/web-design-guidelines/SKILL.md create mode 100644 .github/skills/web-perf/SKILL.md create mode 100644 .github/skills/workers-best-practices/SKILL.md create mode 100644 .github/skills/workers-best-practices/references/configuration.md create mode 100644 .github/skills/workers-best-practices/references/platform-apis.md create mode 100644 .github/skills/workers-best-practices/references/runtime-patterns.md create mode 100644 .github/skills/wrangler/SKILL.md create mode 100644 README.md diff --git a/.github/skills/absurd/SKILL.md b/.github/skills/absurd/SKILL.md new file mode 100644 index 0000000..a2dcf62 --- /dev/null +++ b/.github/skills/absurd/SKILL.md @@ -0,0 +1,256 @@ +--- +name: absurd +description: Debug and operate Absurd durable workflows with absurdctl. Use when working with Absurd queues, tasks, runs, events, retries, schema setup, or when a user wants to inspect, spawn, retry, cancel, or wake workflows. +license: Apache-2.0 +--- + +# Absurd + +Use this skill when the project uses **Absurd**, the Postgres-native durable workflow engine, or when the user mentions **`absurdctl`**, queues, durable tasks, runs, retries, sleeping tasks, or events. + +## Tiny mental model + +- A **queue** is a namespace of Absurd tables (`t_`, `r_`, `c_`, `e_`, `w_`). +- A **task** is the durable workflow instance. +- A **run** is one execution attempt of a task. +- A **step** is a checkpoint. Completed step results are stored as JSON. +- **Sleeping** tasks are usually waiting for time or an event. +- **Events** wake waiting tasks. Event payloads are cached; first emit wins. + +Important distinction: + +- `task_id` = the whole workflow across all attempts +- `run_id` = one specific execution attempt + +## First: make sure `absurdctl` works + +If `absurdctl` is not on `PATH`, check whether you are inside a repo checkout and, if so, use: + +```bash +export PATH="$PWD:$PATH" +``` + +Absurd connection precedence is: + +```text +--database > ABSURD_DATABASE_URL > PGDATABASE > postgresql://localhost/absurd +``` + +For non-URI connections, `PGHOST`, `PGPORT`, `PGUSER`, and `PGPASSWORD` are also honored. + +## Default debugging workflow + +Prefer **`absurdctl` state inspection before source inspection**. Usually you do **not** need to read application code first. + +If the user explicitly asks you to use **`absurdctl`** to inspect or fix a workflow, do that first instead of starting with `rg` / source browsing. + +When the user wants to debug a task, start with these commands in order: + +### 1) Discover queues + +```bash +absurdctl list-queues +``` + +### 2) Inspect recent activity in the likely queue + +```bash +absurdctl list-tasks --queue=default --limit=20 +``` + +Notes: +- `list-tasks` defaults to 50 rows if `--limit` is omitted. +- Useful statuses: `pending`, `running`, `sleeping`, `completed`, `failed`, `cancelled`. + +### 3) Focus on failures or sleepers + +```bash +absurdctl list-tasks --queue=default --status=failed --limit=20 +absurdctl list-tasks --queue=default --status=sleeping --limit=20 +``` + +### 4) Inspect one workflow or one attempt in detail + +```bash +absurdctl dump-task --task-id= +absurdctl dump-task --run-id= +``` + +`dump-task` is the most important inspection command. It shows things like: +- task name, params, and headers +- retry settings and attempts +- checkpointed step state +- waits / events / sleep state +- final result or failure + +## How to reason about common states + +### If a task is `failed` + +1. `dump-task --task-id=` +2. Read the failure and the last successful checkpoints. +3. If needed, inspect the most recent attempt with `--run-id`. +4. Search the code for the task implementation by task name. +5. Only then decide whether to retry. + +### If a task is `sleeping` + +1. `dump-task --task-id=` +2. Look for the wait reason: + - sleeping until a timestamp + - waiting for an event name +3. If it is waiting for an event and the user wants it resumed, emit that event. + +### If a task is `running` + +1. `dump-task --task-id=` +2. Look at existing checkpoints to see how far it got. +3. If the user suspects a stuck worker, inspect the worker process / application logs too. + +### About workers + +Do not assume you need to start or modify a worker. + +- If a spawned task moves from `pending` to `sleeping`, `running`, or `completed`, a worker is already active. +- If tasks remain `pending`, then investigate whether a worker for that queue is actually running. +- Only inspect Python / TypeScript runtime details when the task state suggests a worker problem or the user asks for code changes. + +### If you need the implementation + +After you know the task name, search the codebase for its registration. + +TypeScript / JavaScript: + +```bash +rg -n "registerTask\(|name:\s*['\"]['\"]" . +``` + +Python: + +```bash +rg -n "register_task\(|@.*register_task|['\"]['\"]" . +``` + +If the task is waiting for an event, also search for the event name. + +## Common actions + +### Spawn work + +Use `-P key=value` for strings and `-P key:=json` for typed JSON values. + +```bash +absurdctl spawn-task my-task -q default -P foo=bar +absurdctl spawn-task my-task -q default -P count:=42 -P enabled:=true +absurdctl spawn-task my-task -q default -P user.name=Alice -P user.age:=30 +``` + +Use `--params` when the user already has a JSON object: + +```bash +absurdctl spawn-task my-task -q default --params '{"foo":"bar","count":42}' +``` + +### Retry failed work + +```bash +absurdctl retry-task +absurdctl retry-task --max-attempts 5 +absurdctl retry-task -q default --spawn-new +``` + +Guidance: +- plain `retry-task` retries the existing task +- `--spawn-new` creates a brand-new task with the original inputs +- prefer understanding the failure before retrying + +### Cancel work + +```bash +absurdctl cancel-task +absurdctl cancel-task -q default +``` + +### Wake waiting tasks by emitting an event + +```bash +absurdctl emit-event order.completed -q default -P orderId=123 +absurdctl emit-event approval.granted:42 -q default -P approved:=true +``` + +If the event payload should be structured JSON: + +```bash +absurdctl emit-event shipment.packed:42 -q default --payload '{"trackingNumber":"XYZ"}' +``` + +### Schema setup / migrations + +Use these on a blank or controlled database, or when the user explicitly asks: + +```bash +absurdctl init +absurdctl schema-version +absurdctl migrate +absurdctl create-queue default +``` + +## Safe operating rules + +Be careful with state-changing commands. Unless the user clearly wants them, avoid running these blindly on a shared or production database: + +- `init` +- `migrate` +- `create-queue` +- `drop-queue` +- `cleanup` +- `cancel-task` +- `retry-task` +- `emit-event` +- `spawn-task` + +If the environment is ambiguous, ask which database / queue is safe to operate on. + +## Good copy-paste playbooks + +### Debug the latest failures in `default` + +```bash +absurdctl list-queues +absurdctl list-tasks --queue=default --status=failed --limit=20 +absurdctl dump-task --task-id= +``` + +### Find sleepers and wake one + +```bash +absurdctl list-tasks --queue=default --status=sleeping --limit=20 +absurdctl dump-task --task-id= +absurdctl emit-event -q default -P key=value +``` + +### Reproduce by spawning a task, then inspect it + +```bash +absurdctl spawn-task my-task -q default -P foo=bar +absurdctl list-tasks --queue=default --task-name=my-task --limit=5 +absurdctl dump-task --task-id= +``` + +Fast path when the user says “spawn a task and debug it”: + +```bash +absurdctl spawn-task my-task -q default -P foo=bar +absurdctl list-tasks --queue=default --task-name=my-task --limit=5 +absurdctl dump-task --task-id= +# then either: +absurdctl emit-event -q default -P key=value +# or: +absurdctl retry-task +``` + +## Extra reference + +- Use `absurdctl --help` for full options. +- `dump-task --task-id` is usually the best starting point once you know the task. +- Checkpointed step results are durable JSON state; code outside steps may execute multiple times across retries. diff --git a/.github/skills/blume-migrate/SKILL.md b/.github/skills/blume-migrate/SKILL.md new file mode 100644 index 0000000..db1c2ae --- /dev/null +++ b/.github/skills/blume-migrate/SKILL.md @@ -0,0 +1,182 @@ +--- +name: blume-migrate +description: Migrate an existing documentation site (Mintlify, Docusaurus, Fumadocs, Nextra, Starlight, or any docs framework) to Blume, the markdown-first docs framework on Astro. Translate the source config to blume.config.ts, restructure content into Blume's filesystem-derived navigation, rewrite JSX callouts to directives, convert icons to Lucide, and inline snippets. Use when the user asks to migrate/convert/port a docs repo to Blume, or when the repo has a docs.json/mint.json, docusaurus.config.*, meta.json with fumadocs, _meta.* with nextra, or an astro.config.* with starlight(). +--- + +# Migrate to Blume + +Blume is a **markdown-first** documentation framework on Astro/Vite. You drop Markdown/MDX into a folder and get navigation, search, theming, Open Graph images, and a component library with no app boilerplate — **the framework is the template**. There is no starter to clone; the only thing a project owns is its content and a `blume.config.ts`. + +Your job is to convert a source docs repo into an **idiomatic** Blume project — not a 1:1 transliteration. Read this file, detect the source framework, open the matching `references/.md` for the exact mappings, and work the loop below. Report everything you drop or approximate. + +Throughout this skill (including the `references/` files), **`` means the absolute path of the directory containing this SKILL.md** — resolve it from wherever you read this file (e.g. `node_modules/blume/skills/blume-migrate` or `.claude/skills/blume-migrate`). It is a placeholder to substitute, never a literal path. + +## Migration philosophy + +- **Target idiomatic Blume, not a mechanical port.** Prefer filesystem-derived navigation over an exhaustive explicit `navigation.sidebar`. Prefer `:::` directives over JSX callouts. Prefer Blume defaults over restating them in config. +- **Every field has a default; `{}` is a valid config.** Map only what the source _declares_. If the source uses a framework default, don't write it. +- **Drop chrome that has no Blume equivalent — and say so.** Navbar CTAs, footer copyright text, custom theming, conditional redirects, and unmappable icons get reported to the user, not silently discarded or faked. +- **Convert, don't preserve.** Blume's page frontmatter schema is **strict** — unknown keys are build errors. A source-only frontmatter key must be mapped to a Blume key or removed (and reported), never left to "maybe validate." + +## Migration workflow + +1. **Detect the source framework** and read its reference file: + - `docs.json` / `mint.json` → **Mintlify** (`references/mintlify.md`) — the deepest, config-declared nav. + - `docusaurus.config.*` → **Docusaurus** (`references/docusaurus.md`). + - `meta.json` + `fumadocs-*` deps (content under `content/docs/`) → **Fumadocs** (`references/fumadocs.md`). + - `_meta.{js,ts,json}` + `nextra` deps → **Nextra** (`references/nextra.md`). + - `astro.config.*` calling `starlight({…})` → **Starlight** (`references/starlight.md`). + - Anything else → apply this file's mental model directly; there's no framework-specific reference, so inventory by hand. + - **Also note the host repo, independent of source framework:** a pnpm/Turbo workspace, a non-`docs/` content layout, or a Vercel deploy each need integration steps (`content.root` scoping, `minimumReleaseAge`, lockfile, `vercel.json`, an Astro/Vite patch) — all in `references/monorepo.md`. Read it whenever the target isn't a bare single-package docs folder. +2. **Inventory the repo** before changing anything: the config file(s), the content tree, the nav definition, snippets/partials/includes, static assets, OpenAPI/AsyncAPI specs and GraphQL schemas, redirects, i18n locales, custom components, and icon usage. Note what's declared vs. defaulted. +3. **Write `blume.config.ts`** with `defineConfig` from `blume`. Map only declared fields (see the reference's mapping table); rely on defaults everywhere else. A minimal result is `defineConfig({ title: "…" })`. +4. **Restructure content.** Choose `content.root` (default `docs`) — **detect where `.md`/`.mdx` actually live, don't assume a `docs/` folder.** Many repos keep content directly under an app dir (`apps/docs/api/`, `.../getting-started/`) with no `docs/` subfolder; when so, set `content.root` to that dir and scope `content.include` to the real content folders rather than leaving a bare `content.root: "."` that scans everything (see `references/monorepo.md` §1). Order with numeric prefixes (`01-intro.mdx`), group without a URL segment via `(group)/` folders, and add a `meta.ts` (`defineMeta`) only where filesystem order isn't enough. **A source that already declares per-folder navigation in a sidecar file — Fumadocs `meta.json`, Nextra `_meta.*` — _is_ that case: convert each one to a `meta.ts`, carrying over its title/icon/order/collapse, rather than dropping it and hoping filenames reproduce the intent. Filesystem inference is the fallback for folders that declare no per-folder nav, never a reason to discard one that does.** Reach for an explicit `navigation.sidebar` only when the source nav genuinely can't be expressed by files. **Reshaping into folder-per-tab moves URLs** — track every old→new path as you go; you'll turn them into `redirects` in step 5. +5. **Rewrite pages.** Map frontmatter to Blume's strict schema; convert callout JSX to `:::` directives — **directives (and math/mermaid/package-install fences) are MDX-only, so rename any `.md` page that needs them to `.mdx`**; rename components; turn snippets/partials into `` statements or inline them (Blume has no import-based includes: `import Snippet from "…"` plus `` has to become one or the other); fix asset paths; **rewrite internal links** to their new routes (including OpenAPI/GraphQL operation links — see the API-reference sections, their slugs differ from most sources); **add a `redirects` entry for every route you moved** in step 4; **convert every icon name to Lucide** (Blume is Lucide-only — no FontAwesome/Tabler). Remove any duplicated H1 in the body (`title` renders the H1; bodies start at `##`). **If the source has a hand-maintained changelog and the repo is open source on GitHub, offer to swap it for the `githubReleases()` source** (see "Changelogs" below) rather than porting the entries. For **Mintlify**, run the bundled codemod first — `node /scripts/mintlify-codemod.mjs --write ` deterministically remaps icons and drops/renames unsupported frontmatter keys, and reports the rest (unknown icons, OpenAPI-stub flags) for you to finish by hand (see `references/mintlify.md`). +6. **Adopt `package.json`.** Repoint `dev`/`build`/`start` → `blume dev`/`blume build`/`blume preview`, remove the old framework's deps, add `blume`. A config-only source (e.g. a bare Mintlify `docs.json`) has no manifest — scaffold one. **In a pnpm workspace:** if `pnpm-workspace.yaml`/`.npmrc` sets `minimumReleaseAge`, add **only** `blume` to `minimumReleaseAgeExclude` (don't disable the guard) so the just-published version installs. **Always regenerate the lockfile in the same change:** after editing deps run a plain `pnpm install` (from the workspace root) and commit `pnpm-lock.yaml` alongside `package.json` — CI/Vercel use `--frozen-lockfile`, so a stale lockfile fails the build before it starts. **If the repo uses (or the user wants) [Ultracite](https://www.ultracite.ai) for formatting:** its oxfmt formatter mangles the `:::` directives you just wrote unless you ship the bundled `assets/oxfmt@0.67.0.patch` and register it under `patchedDependencies` — see `references/monorepo.md` §6. See `references/monorepo.md` §2–3. +7. **Wire up the host repo & deploy (non-trivial repos).** For a monorepo on Vercel, emit the root-aware install/build recipe and `apps/docs/vercel.json`, and tell the user the two settings you can't commit (Vercel Root Directory, Node 22). If the workspace pins Vite and `blume build` crashes inside Astro/Vite, apply the pnpm-patch workaround. All copy-pasteable in `references/monorepo.md` §4–5. +8. **Verify.** Run `blume build` (frontmatter schema, duplicate routes, config — it fails on any error diagnostic by default; **never pass `--no-strict`**, which builds anyway and silently drops invalid pages) and `blume validate --strict` (internal links, heading anchors, assets — the link checker lives in `validate`, not `build`), fix diagnostics, then `blume dev` for a visual pass. End with a written summary of what was migrated, dropped, and approximated — **and every repo-specific edit you made** (pnpm-workspace, vercel.json, config globs) with the reason, plus any manual step left to the user (the Astro patch, Vercel dashboard settings). + +## The Blume mental model + +The single biggest shift for most sources — especially Mintlify — is that **navigation is derived from the filesystem**, not declared in config. + +### Navigation is the file tree + +- **Folders become groups, files become pages.** A page's sidebar label is its frontmatter `title`; a group's label is the humanized folder name. +- **Ordering resolves highest-priority-first:** an explicit `navigation.sidebar` (replaces the whole tree) → a folder's `meta.ts` `pages` array → a page's frontmatter `sidebar.order` → the filesystem (`index` first, then numeric filename prefix like `01-`, then alphabetical). +- **`meta.ts` refines one folder** (`defineMeta({ title, icon, order, collapsed, pages, display, directory })`). The `pages` array lists children by slug (numeric prefix and parentheses stripped); children you omit fall back to their own `sidebar.order`, then filesystem order (`index` still sorts first) — so a partial `pages` list is safe, but list every child when the source declared a complete order. +- **Sidebar render mode: a global default with per-folder overrides.** `navigation.sidebar.display` in `blume.config.ts` is `"flat"` (default), `"group"` (collapsible), or `"page"` (drill-in sub-panel) and sets the mode for every group at once. A folder can override its **own** group: `display` in its `meta.ts`, or — sugar when the folder has an `index` page — `sidebar.display` in that index page's frontmatter. Precedence: index frontmatter → `meta.ts` → global config → `flat`; an override applies to that one group only (nested subgroups resolve their own chain). So a source's per-category collapse/drill-in modes migrate per folder — only reach for the global mode when the whole sidebar changes. Under an explicit `navigation.sidebar`, the config item's own `display` field is the only per-group control (frontmatter/meta `display` is ignored there, with a `BLUME_SIDEBAR_DISPLAY_IGNORED` warning). +- **An explicit `navigation.sidebar` replaces filesystem generation entirely.** Use it only for a nav shape files can't express. Its items are a page route string, a group (`{ label, items }`), or a link (`{ label, href }`). +- **Config-declared nesting has no on-disk counterpart — materialize it or it flattens silently.** When a source (Mintlify `groups`, Nextra `_meta`, a Docusaurus sidebar…) declares a nested group, its pages usually sit **flat in one folder** and the grouping lives only in config. Filesystem-derived nav sees the flat folder and drops the inner group. To keep the nesting you must **either** move those pages into a real subfolder (`meta.ts` for label/`collapsed`) — which changes their URLs, so add `redirects` — **or** declare the group in an explicit `navigation.sidebar`, which nests the existing routes without moving a file. Walk config `pages`/nav arrays **recursively** during inventory and record where config nesting depth exceeds on-disk depth; that gap is exactly what gets lost. + +### Tabs and selectors + +- **`navigation.tabs`** (`{ label, path, icon? }`) render top-of-header sections and **scope the sidebar by route** — the folder at a tab's `path` becomes the section, so this needs no config beyond the tabs themselves; structure content as **one folder per tab**. **A source's top-level tabs (Mintlify `navigation.tabs`, a top-level product/section switcher) map to these header tabs — keep them as tabs; don't flatten them into a single global `navigation.sidebar`.** Blume picks the active tab by **URL prefix** (longest tab `path` that prefixes the route), so every page in a tab must live under that tab's single `path`; a source tab that mixes arbitrary routes isn't portable as-is — either move its pages under one prefix (route change → add `redirects`) or accept the closest shape, and say which in the report (details in `references/mintlify.md`). The filtering runs both ways: on a route **under** a tab's `path`, the sidebar shows **only** that tab's folder (a tab also highlights when the current route is under it); on a **root or untabbed** route (or a tab whose `path` is `/`), the tab folders are **hidden** and the sidebar shows only the loose pages that belong to no tab (full tree as a fallback, so it's never blank). Consequence for migrations: once you add tabs, the landing sidebar automatically drops the sectioned content — that's intended, not lost pages; don't hand-build excludes for it. +- **`navigation.selectors`** (`{ kind, label, items: [{ label, path, icon?, description?, tag? }] }`, `kind` = `dropdown`/`product`/`version`/`language`) partition a whole site (products, versions) via a header dropdown keyed on the current route. +- **`navigation.actions`** (`[{ label, href }]`) puts plain links in the **header**, left of the icon buttons, and **`navigation.cta`** (`{ label, href }`, singular) is the header's one filled call-to-action button. This is the home for a source's header bar — a "Log in"/"Status" link goes in `actions`, a "Sign up"/"Get started" button in `cta`. An `http(s)` href opens in a new tab; an internal route is validated against your pages at build time, so a route served by another app on the same host must be written as an absolute URL. Both hide on phones (below `sm`), except `cta` on a page with no navigation toggle; a link that must survive on a phone on docs pages belongs in `featured`. +- **`navigation.featured`** (`{ label, href, icon? }`) pins links to the **top of the sidebar, above every section** — a blog, changelog, or support page that should always be one click away. These are the **exception to tab scoping**: unlike the generated tree, featured links show on **every** route and breakpoint. `href` points anywhere — an external URL opens in a new tab, an internal route (`/contact`) is validated against your pages at build time. `icon` is a Lucide name (or image path/URL/inline SVG), as everywhere else. This is the home for a source's always-visible header/utility links (Mintlify anchors, Blog/Contact links) — see `references/mintlify.md`. + +### Routes and pathing + +- A route is the content path relative to `content.root`, with **numeric prefixes stripped** (`01-intro.mdx` → `/intro`) and **`(group)/` folders adding no segment**. An `index` file maps to its folder's route. Frontmatter `slug` overrides the generated route. + +### `blume.config.ts` shape + +`defineConfig({...})` — every field optional, all with defaults: + +- **Site:** `title`, `description`, `logo` (string SVG, or `{ image: string | { light, dark, alt }, text, href }`), `banner` (a string, or `{ content, link: { href, text }, dismissible, id }` — no color/type). A logo renders beside `title` in the header, so a **wordmark logo doubles the brand** ("Acme Acme") — set `text: ""` to render the mark alone. **Prefer the string form over `{ light, dark }`:** if you have the logo SVG locally and it's monochrome (solid black or white), rewrite its `fill`/`stroke` to `currentColor` and use `logo: "/logo.svg"` — it then inherits the theme's text color and adapts to light/dark automatically, so you don't need separate light/dark files. +- **`theme`:** `accent` (a color string for both modes, or `{ light, dark }` per mode), `action` (color), `mode` (`light`/`dark`/`system`), `radius`, `fonts` (`{ body, display, mono }` — each a curated Google-font slug, a `{ name, provider?, weights? }` object for any Google/Fontsource/Bunny/Fontshare family, or `{ name, variants: [{ src, weight?, style? }] }` for local font files), `background` and `backgroundImage` (each a string, or `{ light, dark }` per mode). The old `accentDark`/`backgroundDark`/`backgroundImageDark` fields were **merged into these per-mode objects** — a bare string still applies to both modes, so only reach for `{ light, dark }` when the two modes differ. There is **no** `theme.strict` and **no** `theme.css` config field — custom CSS goes in a project-root **`theme.css` file** (auto-picked-up), and a source's "strict appearance" flags drop. +- **`content`:** `root` (default `"docs"`, relative to the project dir where `blume` runs), `include`/`exclude` (arrays of globs **relative to `content.root`**; defaults `["**/*.{md,mdx}"]` / `["**/_*", "**/.*"]`), `sources` (an array of **adapters imported from `blume/sources`**: `filesystem({ root, include, exclude })`, `obsidian({ vault })`, `githubReleases({ owner, repo })`, `notion({ database })`, `sanity({ projectId, dataset, query })`, `contentful({ space, contentType })`, `payload({ url, collection })`, `strapi({ url, contentType })`, `mdxRemote({ github })`, `custom(source)`; every factory with an options object also takes `prefix` and `pollInterval`, while `custom(source)` takes a `ContentSource` instance that sets its own `prefix`. The 1.x `{ type: "…" }` objects were removed — rename `type` to the factory call and pass the other fields as its options — except `{ type: "custom", source }`, which becomes `custom(source)` with the instance as the only argument. `root`/`include`/`exclude` are shorthand for a single `filesystem()` and are **rejected beside `sources`** — move them into the `filesystem()` entry. OpenAPI/AsyncAPI/GraphQL are **not** among these; they're adapters in the top-level `reference` list), `pages` (custom `.astro` dir), `defaultType`. When docs sit directly under the project dir (no `docs/` subfolder), set `root` there and **scope `include` to the real content folders** instead of scanning everything — `references/monorepo.md` §1. +- **`basePath`** (top-level): a site-wide mount point (e.g. `"/docs"`) prepended to **every** route while staying invisible to the sidebar (no wrapper group). This is the right target for a source that served all docs under a prefix (Docusaurus `routeBasePath`, a Fumadocs `baseUrl` of `/docs`) — distinct from a per-source `prefix` (which adds a nav group) and from `deployment.base` (host subdirectory). +- **`navigation`:** `tabs`, `selectors`, `actions` and `cta` (header links and the one filled button), `featured` (links pinned above the sidebar on every route), `sidebar` (`{ display, items }` — `display` is the global render mode above; `items` is an explicit tree), `repo` (`true`/`false`, or an absolute GitHub URL for the header mark when the docs repo is private and `github` must stay unset). **Avoid an explicit `navigation.sidebar` unless you have to** — lean on the filesystem-derived sidebar. It only works when the file tree roughly matches the intended sidebar layout, so reshape folders to match first; reach for `sidebar.items` only for a shape files genuinely can't express (see "Config-declared nesting" above). +- **`search`** — an adapter imported from `blume/search`: `orama()` (default, so omit `search` entirely for it), `flexsearch()`, `pagefind()`, `algolia({ appId, apiKey, indexName })`, `oramaCloud({ endpoint, apiKey, indexId? })`, `typesense({ host, collection, apiKey })`, `mixedbread({ storeId })`, or `false` to disable. Pass the adapter directly (`search: algolia({…})`) or as `search: { provider, popular, indexing }` when you also set curated links or indexing options. **Blume 1.x's `search.provider` string and its `search.algolia`/`oramaCloud`/`typesense`/`mixedbread` credential blocks are gone** — when a source config (or an older `blume.config.ts`) has `provider: "algolia", algolia: { appId, indexName, searchApiKey }`, rewrite it as `search: algolia({ appId, indexName, apiKey: searchApiKey })` (the search-only key is now `apiKey` in every adapter that takes one; admin keys stay in env vars). **`ai`** (the assistant, Open in chat — `ai.assistant.provider` takes an **adapter descriptor** imported from `blume/ai`: `gateway({ model })` (the default, `openai/gpt-5.5`), `openai({ model })` (or `openai({ baseUrl, name, model, apiKeyEnv })` for any OpenAI-compatible endpoint), `anthropic({ model })`, `gemini({ model })`, `grok({ model })`, `openrouter({ model, reasoning })`, `llmgateway({ model })`, or `inkeep({ model })`. Every adapter takes `model`, `apiKeyEnv`, `headers`, and a verbatim `providerOptions` passthrough (`headers` values are written into the generated route source as-is, so they are for non-secret static headers only — a bearer token or any other credential belongs in the env var `apiKeyEnv` names, never in `headers`). Every adapter except `inkeep()` also takes `reasoning`: Inkeep runs its own answer pipeline, so `inkeep({ reasoning })` fails validation with an unrecognized key — drop a source's reasoning setting there and report it. There are **no** flat `provider`/`model`/`apiKeyEnv`/`baseUrl`/`headers`/`reasoning` fields on `ai.assistant` — a source that configured an AI assistant that way (Blume < 2.0 included) maps onto one adapter call. `enabled`, `instructions`, `retrieval`, `suggestions`, `cors`, and `endpoint` sit on `ai.assistant` itself; there is **no** `ai.ask` — Blume 2.0.0 and earlier used that name, so an older `blume.config.ts` moves the whole block to `ai.assistant`), **`agents`** (llms.txt, the JSON API, the MCP server, published skills, discovery manifests, robots content signals), **`reference`** (a list of adapters imported from `blume/reference` — `openapi({ spec | sources, route, … })`, `asyncapi({ … })`, `graphql({ spec, endpoint, … })` — never the 1.x `openapi`/`asyncapi`/`graphql` blocks), **`redirects`**, **`seo`**, **`markdown`**, **`analytics`** (a list of adapters imported from `blume/analytics` — one factory per provider (`posthog({ key, host })`, `googleAnalytics({ id })`, `plausible({ domain, host })`, `mixpanel({ token, region })`, `segment({ key })`, …; the docs page lists them all), `vercel()`, and `script({ src | content, strategy, attributes })` for anything without one — never an object keyed by provider), **`deployment`**, **`i18n`**, **`toc`**, **`lastModified`**, **`github`** (`{ owner, repo, branch?, dir?, host?, api? }` — set `host` whenever the source's edit URL is on a GitHub Enterprise origin rather than `github.com`). +- **`deployment`** is a host adapter from `blume/deploy` — `vercel()`, `netlify()`, `cloudflare()`, or `node()` — or a plain `{ site, base }` for a static build on any host (the default is a static build). Naming a host adapter switches the build to **server output** on that host (pass `output: "static"` to stay static there); `site`, `base`, and `output` are the named options, and anything else is forwarded verbatim to the underlying `@astrojs/*` adapter. There is **no** `deployment.adapter` string and **no** `deployment.output` field: a source that needs server rendering (the assistant, the MCP server, Mixedbread search, the API playground proxy) gets `import { vercel } from "blume/deploy"` and `deployment: vercel()`; a static source gets nothing — unless it served its docs under a subpath, which becomes `deployment: { base: "/docs" }` (see below for when to add `site`). Note that `cloudflare` and `vercel` are also exported from `blume/analytics` — alias one (`import { cloudflare as cloudflareDeploy } from "blume/deploy"`) when a config uses both. +- **Keep the source's site URL as `deployment.site` unless the target host is one Blume auto-detects.** Blume fills `site` in from the platform's build environment only on **Vercel, Netlify, and Cloudflare Pages**, and uses the dev server's `localhost` URL during `blume dev`; on those three hosts leave it unset and let detection pick the deployed URL. Everywhere else — GitHub Pages, S3 or another static host, a custom CDN, Cloudflare Workers, a `node()` server — nothing detects it, and an unset `site` silently drops the sitemap, OG images, RSS feeds, the AI catalog, and absolute canonical URLs. So when the source config had a `url`/`site` field and the target isn't one of those three hosts, carry it over: `deployment: { site: "https://…" }` for a static build, or the `site` option of a host adapter (`node({ site })`). If you can't tell where the site will deploy, keep it and say so in the report. +- **Favicon is a filename convention, not config.** Drop `icon.{svg,png,ico}` or `favicon.{svg,png,ico}` (and `apple-icon.png`) in the project root or `public/` — Blume auto-detects it. There is **no** `favicon` config field. A source favicon given as `{ light, dark }` maps to a filename pair: copy the light file to a conventional name (e.g. `public/icon.png`) and the dark file to its `-dark` sibling — same directory and extension, `-dark` before the extension (`public/icon-dark.png`). If the two files have different formats, convert one so the extensions match; only an exact sibling of the resolved icon is picked up. + +The schema is exported from `blume/schema`; the full field reference is in the `docs/configuration/` directory of the installed `blume` package (see "Full documentation" below for how to locate it). + +### Icons are Lucide, period + +Blume resolves **bare kebab-case [Lucide](https://lucide.dev) names** everywhere an icon is accepted — frontmatter `icon`, `sidebar.icon`, `meta.ts` `icon`, `navigation.tabs`/`selectors` icons, and `Card`/`Step`/`Icon`/etc. props. There is **no** FontAwesome or Tabler support and **no** `iconType` prop. Names must be **kebab-case** (`book-open`, not `BookOpen`) — a PascalCase React-component name (common in Fumadocs/lucide-react sources) does not resolve and renders nothing. When migrating a source that uses another icon set (Mintlify defaults to FontAwesome), **map each name to its closest Lucide equivalent**; where none exists, drop the icon and report it. Verify a name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. + +### Page frontmatter (strict — unknown keys are build errors) + +```yaml +--- +title: Install # renders as the page H1 — remove any duplicate H1 in the body +description: Install Blume and scaffold your first project. +type: doc # doc (default); blog and changelog drive feeds, other values only mean something under content.types +sidebar: + label: Install # overrides title in the sidebar + order: 2 + icon: download + badge: New + hidden: false +seo: + title: … + description: … + image: /og/install.png + canonical: https://… + noindex: false +search: + exclude: false + tags: [api] +slug: install # override the generated route +draft: false +lastModified: 2026-06-20 # pin the "last updated" date +--- +``` + +Also valid: `date`/`authors` (blog/changelog feeds), `changelog` (changelog metadata), `deprecated`, `hidden`, `noindex`. + +### Authoring features (no imports needed in `.mdx`) + +- **The rich features are MDX-only.** Directives, `package-install`, mermaid, and math are wired into the MDX processor; in a plain `.md` file a `:::note` stays **literal text** — and the build stays green. **Rename any `.md` file that uses (or should use) these to `.mdx` during migration.** This bites hardest on Docusaurus/Starlight sources, whose `.md` content is full of `:::` admonitions. Plain Markdown (headings, tables, fenced code with titles/highlighting) is fine in `.md`. +- **Callouts as directives:** `:::note`, `:::tip`, `:::warning`, `:::danger`, `:::info`, `:::success`, with an optional title in brackets: `:::warning[Heads up]`. Aliases `caution`→warning, `error`→danger, `important`→note, `warn`→warning. +- **No-import MDX components:** `Callout`, `Card`/`CardGroup`, `Columns`/`Column`, `Steps`/`Step`, `Tabs`/`Tab`, `Accordion`/`AccordionItem`, `Expandable`, `FileTree`, `Tree`/`Tree.Folder`/`Tree.File`, `CodeGroup`, `Frame`, `Panel`, `Tooltip`, `Tile`, `Badge`, `Icon`, `TypeTable`/`AutoTypeTable`, `Color`, `YouTube`, `Visibility`, `GithubInfo`, `Component`, `CodeBlock`, `Diff`, `Prompt`, `Math`. (**Not** shipped — convert away: `` → the `:::warning` directive, and the `ParamField`/`ResponseField`/`RequestField` field family → `TypeTable` rows or the OpenAPI reference. See the reference files for targets.) +- **Fenced-code superpowers:** ` ```package-install ` → package-manager tabs; ` ```mermaid ` → a rendered diagram; code-block titles (` ```ts server.ts `), line numbers (`lineNumbers`), and highlighting (`{1,4-5}`, `// [!code ++]`). +- **Math:** `$$…$$` renders in `.mdx` with **no config** (there is no `markdown.math` field) — as a block on lines of its own, or inline within a sentence. A single `$` always stays literal text, so convert each inline `$…$` to `$$…$$` in place, inside its sentence (not onto a line of its own), checking every pair is math and not currency or a shell variable. + +### OpenAPI + +`reference: [openapi({ sources: [{ spec, label?, route? }] })]` — the `openapi()` adapter imported from `blume/reference` (`spec` is the single-source shorthand) — generates **one real page per operation** — with routing, sidebar, search, and OG images for free. **The reference does not get a header tab automatically** — add a `navigation.tabs` entry pointing at the adapter's `route` (reference routes are valid tab targets) or the API reference is unreachable from the header. **Never hand-migrate generated API-reference pages** (per-endpoint stub pages in the source): delete them and point `openapi()` at the spec. To keep a source's **Scalar embed** instead, list `scalar({ spec, theme?, …scalarOptions })` (also from `blume/reference`) in `reference` in place of `openapi()`: it renders an OpenAPI or AsyncAPI document as one embedded page per source, forwards every key it doesn't name verbatim to Scalar, and doesn't take the native display options (`codeSamples`, `expandSchemas`, `playground`). There is **no** `renderer` option on `openapi()`/`asyncapi()` — it fails validation. **Blume 1.x's top-level `openapi`/`asyncapi`/`graphql` blocks are gone** — when a source config (or an older `blume.config.ts`) has `openapi: { enabled: true, ... }`, rewrite it as an entry in `reference` and drop `enabled`; a 1.x block with `renderer: "scalar"` becomes its own `scalar({ … })` entry instead, keeping the block's `route`, `sources`, and `noindex`, with its `theme` and the keys of its `scalar: { … }` object passed straight to `scalar()` (`scalar({ spec, theme: "purple", localization })`). + +- **Vendor the spec by default.** A remote `spec:` URL makes every build depend on fetching it at build time — a single point of failure in CI, offline, or behind a proxy, and a failed fetch skips the whole reference. Prefer committing the spec into the repo (`openapi/.json`) and pointing `spec` at the local path; if you keep the URL, say so and consider a `prebuild` step that refreshes the local copy with a fallback. +- **Operation routes have their own slug scheme** — `//` (e.g. tag `Models`, id `listModels` → `/api-reference/models/list-models`). A camelCase operation id is split at its word boundaries into kebab-case before slugifying (`getHTTPResponse` → `get-http-response`), so don't just lowercase it; an operation with no `operationId` takes its method and path instead (`GET /pets/{id}` → `get-pets-id`). This rarely matches the source's endpoint links (Mintlify/others kebab-case differently), so **rewrite every inbound link to an operation**. `blume validate` resolves operation pages like any other route, so it catches the ones you miss. +- **Keep hand-written conceptual pages.** Sources often pair a written "Introduction/Authentication" page with the endpoint group in the same tab. A normal content page placed under the `openapi()` adapter's `route` merges into the reference tab's sidebar — so keep those (auth, errors, rate limits) and delete only the per-endpoint stubs. + +### GraphQL + +`reference: [graphql({ spec, endpoint? })]` is the GraphQL counterpart: Blume lowers a schema — SDL text or an introspection JSON result, local path or URL — into **one real page per root field** (grouped as Queries/Mutations/Subscriptions) plus **one page per named type** (Objects, Input Objects, Enums, Interfaces, Unions, custom Scalars). Every OpenAPI rule above carries over: never hand-migrate a source's generated GraphQL reference pages (delete them and point `spec` at the schema), vendor a remote schema locally, keep hand-written conceptual pages under the `route` (default `/graphql`), add the `navigation.tabs` entry, and rewrite inbound links — routes are `//` (e.g. `/graphql/queries/pets`, `/graphql/objects/pet`), which `blume validate` resolves like any other page. Differences from the `openapi()` adapter: + +- **Set `endpoint` to the live GraphQL URL.** A schema, unlike an OpenAPI document, names no server — `endpoint` is what the Try It playground and code samples target (without it they render a placeholder URL, and `playground: { proxy: true }` warns at build time because the proxy has no origin to allow). Multiple schemas use `sources: [{ spec, endpoint?, label?, route? }]`; a per-source `endpoint` overrides the adapter-level one. +- **No Scalar embed** — there is no `scalar()` counterpart for a GraphQL schema (and `graphql()` takes no `expandSchemas`); the reference is always Blume-rendered (the Scalar embed reads OpenAPI and AsyncAPI documents only). A source's GraphQL playground/explorer embed (GraphiQL, Apollo Explorer) has no direct equivalent beyond the built-in Try It panel; report anything it did that the panel doesn't. +- **Only SDL and introspection JSON are accepted.** A source that builds its schema programmatically (a `GraphQLSchema` instance in code) must be printed to SDL (`printSchema` from `graphql`) and committed; report that conversion. + +### Changelogs + +If the source ships a **hand-maintained changelog** (a `changelog.mdx`, a folder of dated entries, Mintlify `` blocks) **and the project is open source on GitHub**, offer to replace it with the **`githubReleases()`** content source — release notes become the changelog automatically, with no files to maintain. It's an offer, not an automatic rewrite: some teams keep a curated changelog that doesn't map 1:1 to GitHub releases, so confirm the release notes are the source of truth before deleting their pages. + +Add it under `content.sources` alongside the filesystem source (both imported from `blume/sources`; with `sources` present, the content root moves into `filesystem()`): + +```ts +import { filesystem, githubReleases } from "blume/sources"; + +content: { + sources: [ + filesystem({ include: ["docs/**/*.mdx"], root: "." }), + githubReleases({ + owner: "haydenbleasel", + repo: "ultracite", + prefix: "changelog", + }), + ], +}, +``` + +- Each release materializes as a `type: changelog` page under `//` (`prefix: "changelog"` → `/changelog/…`); omit `prefix` to mount at the root. +- Optional fields: `limit` (cap materialized releases, newest-first, default 100), `prereleases` (include prereleases), `drafts` (include drafts — needs a token with repo write access), `pollInterval` (dev polling seconds; omit to freeze for the session). +- A **private** repo reads a token from `GITHUB_TOKEN`; it is never inlined in config. The adapter declares it, so `blume dev`/`build` warn when it is unset; a public repo still works without it. +- **Delete the old changelog pages** once the source is wired (and add `redirects` from their old routes to the new `//…` slugs). Pin a header/sidebar link with `navigation.featured` if the source had one. + +### Redirects are static + +A `redirects: [{ from, to, status? }]` array **in `blume.config.ts`** maps old URLs when you restructure routes — Blume serves these itself, so any reorganization that moves a page (folder-per-tab, materialized nested groups, renamed slugs, index promotion) is fixed by adding an entry there; no host config needed. **Restructuring is the main source of these:** every page you moved in step 4 (folder-per-tab, renamed slugs, index promotion) needs an entry, or old URLs 404. `status` defaults to **301 (permanent — browsers cache it indefinitely)**; that's correct for genuine moves, but never use 301/308 for redirects you might reverse. Patterns carry over as written: `:name` for one segment, `:name*` or a trailing `*` for the rest of the path (`{ from: "/beta/:slug*", to: "/v2/:slug*" }`). A pattern can't also match a page, so the build fails (`BLUME_REDIRECT_MATCHES_PAGE`) if one covers a page you kept; narrow it. Rules a pattern can't express (regex params, header or cookie conditions) move to host-level config (`_redirects`, `vercel.json`); report them. + +## Verification & reporting + +1. Run **`blume build`** — it validates the frontmatter schema, duplicate routes, and config, and fails on any error diagnostic by default (**don't pass `--no-strict`**: that builds anyway and silently drops invalid pages). Then run **`blume validate --strict`** — links, heading anchors, and assets live here, not in `build` (add `--external` to also check outbound HTTP links). OpenAPI operation pages are real routes to `validate`, so dead links to them are caught too. Iterate until both are clean. +2. Run `blume dev` and review the site visually — nav structure, tabs, theme, rendered components. +3. **Write a migration summary** covering: what was migrated (config, N pages, nav, API references), what was **dropped** (navbar CTAs, footer copyright text, custom theming, conditional redirects, unmappable icons, unsupported components), and suggested follow-ups (`blume eject` for full control, `blume add` to vendor a component for customization). + +## Full documentation + +The mapping details live in `references/`: one file per source framework (`mintlify.md`, `docusaurus.md`, `fumadocs.md`, `nextra.md`, `starlight.md`), plus **`monorepo.md`** for host-repo integration (content-layout detection, pnpm `minimumReleaseAge`, frozen-lockfile regeneration, the Vercel monorepo recipe, and the Astro/Vite patch). The Mintlify icon + frontmatter pass is automated by **`scripts/mintlify-codemod.mjs`** (zero-dependency, deterministic, idempotent; `--write` to apply). The authoritative Blume docs are bundled in the installed package's **`docs/` directory** — not necessarily at the repository root: in a workspace monorepo (pnpm especially) the package lives in the depending workspace's `node_modules` (e.g. `apps/docs/node_modules/blume/docs`); `node -e "console.log(require.resolve('blume/package.json'))"` run from the depending package prints the exact location. (In a repo checkout of Blume itself, the docs source is `apps/docs/content/docs`.) The most relevant pages: + +- `configuration/index.mdx` — every `blume.config.ts` field. +- `content/navigation.mdx` — the sidebar/tabs/selectors model. +- `content/meta.mdx` — `meta.ts` and display modes. +- `content/syntax.mdx` — directives, code features, math. +- `content/components.mdx` — the component library and APIs. +- `content/frontmatter.mdx` — the strict page schema. diff --git a/.github/skills/blume-migrate/assets/oxfmt@0.67.0.patch b/.github/skills/blume-migrate/assets/oxfmt@0.67.0.patch new file mode 100644 index 0000000..190f375 --- /dev/null +++ b/.github/skills/blume-migrate/assets/oxfmt@0.67.0.patch @@ -0,0 +1,49 @@ +diff --git a/dist/markdown-BMigo7Hm.js b/dist/markdown-BMigo7Hm.js +index bc9037f6c0de5516b139d8cdb195b1e25cd33bc0..a02c284e28bb535f9964a8a086ebb6549657e416 100644 +--- a/dist/markdown-BMigo7Hm.js ++++ b/dist/markdown-BMigo7Hm.js +@@ -4872,7 +4872,43 @@ function lu(e, t, r) { + case "sentence": return Oh(e, r); + case "word": return t.parser !== "mdx" ? zh(e, t) : Uh(e); + case "whitespace": { +- let { next: a } = e, u = a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !NE(e) && !(t.proseWrap === "preserve" && RE(e)) ? "never" : t.proseWrap; ++ let { next: a, previous: oxfmtFencePrev } = e; ++ // Preserve line breaks that sit directly against a `:::` container ++ // directive fence, so `proseWrap: "never"` keeps the opening/closing ++ // fence on their own lines instead of joining them into the prose (which ++ // breaks the directive). Ordinary prose still wraps per proseWrap. ++ // See prettier/prettier#19040. ++ let oxfmtIsFence = (w) => w != null && typeof w.value === "string" && w.value.startsWith(":::"); ++ // A titled directive (`:::warning[Heads up]`) parses its `[title]` as a ++ // linkReference between two sentence nodes at the paragraph level: the ++ // fence word ends the sentence before the reference, and the body's ++ // leading newline opens the sentence after it. So when this whitespace ++ // starts its sentence, climb to the paragraph and check whether the two ++ // preceding siblings are a (link) reference and a sentence ending in a ++ // `:::` fence word. ++ let oxfmtPrevIsTitledFence = !1; ++ if (oxfmtFencePrev == null && e.index === 0 && e.grandparent != null && Array.isArray(e.grandparent.children)) { ++ let oxfmtSibs = e.grandparent.children, oxfmtSentIdx = oxfmtSibs.indexOf(e.parent); ++ if (oxfmtSentIdx >= 2) { ++ let oxfmtLink = oxfmtSibs[oxfmtSentIdx - 1], oxfmtBefore = oxfmtSibs[oxfmtSentIdx - 2]; ++ let oxfmtLastWord = oxfmtBefore && oxfmtBefore.type === "sentence" && Array.isArray(oxfmtBefore.children) ? oxfmtBefore.children[oxfmtBefore.children.length - 1] : null; ++ oxfmtPrevIsTitledFence = oxfmtLink != null && (oxfmtLink.type === "linkReference" || oxfmtLink.type === "link") && oxfmtIsFence(oxfmtLastWord); ++ } ++ } ++ // The plain-markdown parser keeps a titled fence's `[title]` as literal ++ // words, so the whole directive is one sentence. For a newline ++ // whitespace, walk back to the start of its visual line within the ++ // sentence; a line led by a `:::` word is a fence whose break must stay. ++ if (!oxfmtPrevIsTitledFence && e.node.value.includes("\n") && e.parent != null && Array.isArray(e.parent.children)) { ++ let oxfmtLineFirst = null; ++ for (let oxfmtJ = e.index - 1; oxfmtJ >= 0; oxfmtJ--) { ++ let oxfmtSib = e.parent.children[oxfmtJ]; ++ if (oxfmtSib.type === "whitespace" && typeof oxfmtSib.value === "string" && oxfmtSib.value.includes("\n")) break; ++ oxfmtLineFirst = oxfmtSib; ++ } ++ oxfmtPrevIsTitledFence = oxfmtIsFence(oxfmtLineFirst); ++ } ++ let u = oxfmtIsFence(oxfmtFencePrev) || oxfmtPrevIsTitledFence || oxfmtIsFence(a) ? "preserve" : a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !NE(e) && !(t.proseWrap === "preserve" && RE(e)) ? "never" : t.proseWrap; + return ou(e, n.value, u, !1, t); + } + case "emphasis": { diff --git a/.github/skills/blume-migrate/references/docusaurus.md b/.github/skills/blume-migrate/references/docusaurus.md new file mode 100644 index 0000000..11b2404 --- /dev/null +++ b/.github/skills/blume-migrate/references/docusaurus.md @@ -0,0 +1,98 @@ +# Docusaurus → Blume + +Docusaurus is a React site; navigation comes from `sidebars.js` (explicit or autogenerated) plus per-folder `_category_.json`. Admonitions are already directive syntax, which eases the content transform — **but note the source major version**: v2 (MDX v1) and v3 (MDX v3) have different content hazards, called out below. + +## Detect + +- **`docusaurus.config.{js,ts}`** at the root; a **`sidebars.{js,ts}`** file and per-folder **`_category_.json`** files. +- Content under **`docs/`** (often plus `blog/`, `src/pages/`, `static/`, `versioned_docs/`); `@docusaurus/*` deps. +- v2 vs v3: check the `@docusaurus/core` major in `package.json`. + +## Config: `docusaurus.config` → `blume.config.ts` + +Read `themeConfig`, `presets`, and `plugins`: + +| Docusaurus | Blume | +| --- | --- | +| `title` | `title` | +| `tagline` | `description` | +| `themeConfig.navbar.title` / `.logo` | `title` / `logo` (move the image into `public/`) | +| `themeConfig.navbar.items` (doc items) | `navigation.tabs` (for section links) | +| `themeConfig.navbar.items` (external/utility links — Blog, Discord…) | **`navigation.actions`** (`[{ label, href }]`, plain header links) to keep them in the header, or **`navigation.featured`** (`{ label, href, icon? }`, pinned above the sidebar on every route) if they should survive on phones; the GitHub link → the `github` config instead (it renders in the footer) | +| `themeConfig.navbar.items` (a `className`-styled button — "Get started", "Sign up") | **`navigation.cta`** (`{ label, href }`, the header's one filled button; a route the docs don't serve must be an absolute URL) | +| `themeConfig.colorMode.defaultMode` | `theme.mode` (`respectPrefersColorScheme: true` → `"system"`) | +| `themeConfig.prism.theme` / `.darkTheme` | `markdown.code.theme: { light, dark }` (map Prism theme names to Shiki themes, e.g. `github`/`github-dark`) | +| `themeConfig.metadata` / `themeConfig.image` | per-page `seo` frontmatter / `seo.og`; report what doesn't fit | +| `url` + `baseUrl` | **`url` → `deployment.site`**, unless the target host is Vercel, Netlify, or Cloudflare Pages, which Blume auto-detects (see SKILL.md — GitHub Pages, a common Docusaurus host, is not one of them); `baseUrl` (when not `/`) → `deployment: { base: "/…" }`, or the `base` option of a host adapter (`vercel({ base })`) when the site also needs one | +| preset `docs.routeBasePath` — **including the default!** | Docusaurus serves docs at **`/docs/…` by default**; the "map only declared fields" rule does **not** apply here because the _URLs_ are load-bearing. Either keep them with top-level **`basePath: "/docs"`** (invisible to the sidebar), or intentionally move to root and emit a `redirects` entry per page. Decide explicitly and say which. (`routeBasePath: '/'` = docs-only mode — nothing to do.) | +| preset `docs.editUrl` | `github` (owner/repo/branch; a path after the branch → `github.dir`; **an origin other than `https://github.com` → `github.host`** — a GitHub Enterprise repo's edit links and header mark point at the public site without it) | +| `themeConfig.footer` | `footer.links`, one row of `{ label, href }`: every column's items flatten into it in order (an item's `to`, a route, is its `href`); column `title`s, `copyright`, `logo`, and `style` drop (report), or keep the whole footer as a Footer override (`defineComponents` layout slot) | +| `themeConfig.announcementBar` | `banner` (`{ content, dismissible, id }` — `isCloseable` → `dismissible`; colors drop) | +| `i18n.locales` / `defaultLocale` | `i18n` — translated files live at `i18n//docusaurus-plugin-content-docs/current/…`; move them to `/…` under `content.root` | +| `themeConfig.algolia` | drop — Blume ships built-in search (Orama); remove the Algolia dep. To keep the index, `search: algolia({ appId, apiKey, indexName })` from `blume/search` (the DocSearch `apiKey` is the search-only key) | +| `@docusaurus/plugin-client-redirects` | **static `redirects: [{from, to}]` arrays convert 1:1** to Blume `redirects` (a `from` array = one entry per item); only `createRedirects` functions are truly dynamic → host rules | +| `@docusaurus/theme-mermaid` | delete the dep — ` ```mermaid ` renders natively (in `.mdx`) | +| OpenAPI doc plugins (`docusaurus-plugin-openapi-docs`, `redocusaurus`) | delete the plugin **and its generated pages** — add `openapi({ spec })` (from `blume/reference`) to the top-level `reference` list; `redocusaurus` `specs[].route` → the adapter's `route`, one `openapi()` entry (or source) per spec (see SKILL.md "OpenAPI") | +| GraphQL doc generators (`@graphql-markdown/docusaurus`, `@edno/docusaurus2-graphql-doc-generator`) | delete the plugin **and its generated pages** — add `graphql({ spec, endpoint })` (from `blume/reference`) to the top-level `reference` list instead (see SKILL.md "GraphQL") | +| `remark-math` + `rehype-katex` | delete — `$$…$$` renders in `.mdx` with no config (no `markdown.math` field exists), as a block or inline within a sentence; a single `$` stays literal, so convert each inline `$…$` to `$$…$$` inside its sentence | +| Multi-instance docs plugins (`plugin-content-docs` with `id`) | one folder (and usually one `navigation.tabs` entry) per instance | + +## Static assets — required move + +Every Docusaurus repo serves **`static/`** at the site root (`static/img/foo.png` → `/img/foo.png`). Blume serves **`public/`**. **Move `static/*` (and any extra `staticDirectories`) into `public/`** — all root-relative references then keep resolving unchanged. Without this, every image and download 404s. + +## Navigation: `sidebars.js` + `_category_.json` + +- **Autogenerated sidebar** (`{ type: 'autogenerated', dirName: '...' }`) → Blume's default filesystem navigation. Docusaurus strips numeric prefixes (`01-`) exactly like Blume, so the convention round-trips; no config needed. +- **Explicit sidebar** (arrays of doc IDs, categories, links) → restructure into folders where possible; use `navigation.sidebar` only for shapes files can't express. A category `{ type: 'category', label, items }` → a folder (label → `meta.ts` `title`); `collapsed` → `meta.ts` `collapsed`, and collapsible rendering → that folder's `meta.ts` `display: "group"` (or `navigation.sidebar.display: "group"` once in config when every category collapses). +- **`_category_.json`** (also `.yml`) (`{ label, position, collapsed, collapsible, link, className, customProps }`) → a folder `meta.ts`: `label`→`title`, `position`→`order`, `collapsed`→`collapsed`. `link.type: 'generated-index'` → an `index` page in the folder (its `title`/`description` from `link.title`/`link.description`) plus `directory: "card"` in the folder's `meta.ts`, which lists the folder's pages below it as the generated index did — **and the old URL was `/docs/category/`**, so add a redirect and rewrite inbound links. `link.type: 'doc'` → make that doc the folder's `index`. `collapsible: false` → that folder's `meta.ts` `display: "flat"`, so it stays a plain heading even under a global `"group"` mode. `className`/`customProps` → drop (report). +- **`src/pages/` — inventory, don't nuke.** Nearly every repo has a React landing page (`src/pages/index.tsx`) and often extra Markdown pages. Markdown pages → content pages; the React home page → rebuild as a docs index or a custom `.astro` page under `content.pages` — report either way. + +## Versioned docs + +Docusaurus `versioned_docs/version-X/` + `versions.json` (+ `versioned_sidebars/`) → **recommend migrating the latest released version only**. Mind the URL scheme: by default the **latest release** serves at `/docs/` and the work-in-progress `docs/` folder serves at `/docs/next` (`lastVersion: 'current'` flips this) — pick the folder that matches what users see at `/docs/`. If older versions must stay, use Blume's native versioning rather than a hand-built `navigation.selectors` dropdown: move each `versioned_docs/version-X/` into a top-level folder under `content.root` named for its id, and list that id in `versions.archived` (newest first), with `versions.current` labeling the live tree. Ids must start with a letter, so `version-1.0/` becomes `v1.0/`. Blume then adds the version switcher, the old-version notice, version-scoped search, and canonicals to the latest itself. A version-shaped folder left out of `versions.archived` only warns (`BLUME_VERSIONS_UNCONFIGURED_VERSION`) and publishes as ordinary current content. Snapshot routes become `//…`, so rewrite root-absolute links inside each snapshot to stay in it (`/guides/x` → `/v1.0/guides/x`) and add `redirects` from the old version URLs. Full reference: `docs/content/versioning.mdx` in the installed package. + +## Blog + +A Docusaurus `blog/` → Blume `type: blog` pages. **Dates come from filenames/folders** (`2024-01-31-foo.md`) — extract each into `date` frontmatter and strip the date from the filename (the old dated URLs `/blog/2024/01/31/foo` need `redirects`). Strip `` / `{/* truncate */}` markers. `authors.yml` refs → inline author objects in each post's `authors` frontmatter. RSS stays at `/blog/rss.xml` on both sides. Blume generates **no** blog index, tag, author, or archive pages: write a `blog/index.mdx` whose `CardGroup` links each post (see `docs/advanced/blog.mdx` in the installed package), and report the tag, author, and archive pages as dropped. + +## Content & components + +- **`.md` vs `.mdx` — both majors need renames, for opposite reasons.** Blume parses `.md` as plain Markdown: no directives, no JSX, no `$$` math, no mermaid/package-install fences. **v3** treats `.md` as MDX (so a `.md` with imports/JSX/`{}` renders them as literal text in Blume); **v2** content is looser MDX v1. Rule: **rename any `.md` that contains admonitions, JSX, imports, or math to `.mdx`** — for typical Docusaurus repos that is most files. +- **Admonitions are directives — but check the version.** v3: `:::note`, `:::tip`, `:::info`, `:::warning`, `:::danger` pass through; `:::caution` → `:::warning` (or rely on Blume's alias); titles `:::note[Title]` work. **v2:** titles are space-separated (`:::note Your Title`) — rewrite to brackets or the title is silently lost; and v2's `:::warning` rendered **red/danger** — audit whether it should become `:::danger`. +- **Tabs:** ``/`` → ``/``. Drop `groupId`/`queryString`/`value`; strip the `@theme/Tabs` imports. +- **Theme JSX in content:** `` (standard on category index pages) → delete it and set `directory: "card"` in that folder's `meta.ts`: Blume then lists the folder's pages as cards below the `index` page's content and keeps the list current (nested folders inherit the setting; give one `directory: "none"` to opt out). A hand-written `CardGroup` is only for a curated subset; `` → drop (report); `` JSX → a fenced code block; `` → the matching directive; `
`/`` → ``/`` or leave as raw HTML. +- **`@theme/*` / `@site/*` imports** — strip `@theme/*` (Blume injects components globally); rewrite `@site/` asset/module paths to `/public` URLs or inline. **MDX partials** (`_partial.mdx` imports) → inline the partial's body (Blume's default `**/_*` exclude already hides the partial files themselves). +- **Code blocks:** `title="file.js"` → works as-is; `showLineNumbers` → `lineNumbers`; **magic comments** (`// highlight-next-line`, `highlight-start`/`end`) → `{ranges}` or `// [!code highlight]` — unconverted they ship as literal comments in every sample; ` ```bash npm2yarn ` → ` ```package-install `. +- **MDX v1 (v2 sources) pitfalls:** unescaped `<`/`{` in prose, HTML comments `` (→ `{/* */}`), string `style="…"` attributes (→ objects). Fix as build errors surface. + +## Frontmatter + +| Docusaurus | Blume | +| --- | --- | +| `title` / `description` | pass through | +| `id` | **not a safe drop** — Docusaurus builds a doc's URL from its ID, so `id: part1` in `guides/hello.md` serves `/docs/guides/part1`. Where the `id` differs from the filename (and no `slug` is set), replace it with `slug: guides/part1` (the folder path plus the id) or rename the file to match; otherwise drop it. Sidebar and `link.type: 'doc'` references name docs by this ID too | +| `slug` | `slug` as a **full path from the content root**: Blume's `slug` replaces the page's whole route, while Docusaurus resolves a relative slug (no leading `/`) against the doc's folder. So `guides/intro.md` with `slug: start` → `slug: guides/start`; an absolute slug (`/start`) is already a full path | +| `sidebar_label` | `sidebar.label` | +| `sidebar_position` | `sidebar.order` | +| `unlisted` | `hidden: true` + `noindex: true` | +| `last_update.date` | `lastModified` | +| `draft` | `draft` | +| `tags` | `search.tags` (or drop if only used for the blog tag index) | +| `image` | `seo.image` | +| `keywords` | drop → use `seo` | +| `sidebar_class_name` / `sidebar_custom_props` / `pagination_next` / `pagination_prev` / `pagination_label` / `hide_title` / `hide_table_of_contents` / `toc_min_heading_level` / `toc_max_heading_level` / `displayed_sidebar` / `custom_edit_url` | drop (report) | + +Remove any duplicated H1 in the body — `title` renders the H1. + +## Icons + +Docusaurus has no built-in icon-name system (icons are usually inline SVG/emoji/CSS). Where you add sidebar/tab icons, use Lucide names. Convert any FontAwesome/react-icons usage in content to Lucide `` or drop it. + +## Teardown + +Remove `@docusaurus/*` and Algolia deps; delete `docusaurus.config.*`, `sidebars.*`, `babel.config.js`, and `src/` theme customizations (after the `src/pages/` inventory above; re-implement what matters via `defineComponents` layout slots or `blume eject`). Repoint `start`/`build`/`serve` scripts → `blume dev`/`blume build`/`blume preview`; add `blume`. + +## Dropped — report these + +Custom/swizzled theme components (layout slots or `blume eject`), the footer's copyright, logo, and HTML items, the blog's generated tag, author, and archive pages, Algolia config, `sidebar_custom_props` and the other dropped frontmatter keys, `createRedirects` functions (→ host rules), React pages under `src/pages/`, ``, per-category `className`/`customProps`, and any `@theme/*` component with no Blume equivalent. diff --git a/.github/skills/blume-migrate/references/fumadocs.md b/.github/skills/blume-migrate/references/fumadocs.md new file mode 100644 index 0000000..895c10d --- /dev/null +++ b/.github/skills/blume-migrate/references/fumadocs.md @@ -0,0 +1,107 @@ +# Fumadocs → Blume + +Fumadocs is code-first: navigation comes from the folder tree + per-folder `meta.json`. This maps cleanly to Blume — most content passes through, and `meta.json` becomes `meta.ts`. Fumadocs v16 runs on Next.js, React Router, TanStack Start, Astro, or Waku — detect by the Fumadocs files, not by Next.js files, and adjust the teardown list to whichever host framework is present. + +## Detect + +- Content under **`content/docs/`** (the Fumadocs convention). +- Per-folder **`meta.json`** files. +- `fumadocs-ui` / `fumadocs-core` / `fumadocs-mdx` deps, and collections declared either in a `source.config.ts` (the Config API) or, in newer scaffolds, with `defineDocs` from `fumadocs-mdx/macro` inside `lib/source.ts` (no `source.config.ts` at all). +- A `loader({ baseUrl })` call in `lib/source.ts` (or `app/source.ts`, `src/lib/source.ts`, `source.ts`). Newer scaffolds pass a constant (`baseUrl: docsRoute`) defined in `lib/shared.ts` — resolve it there. + +## Config + +Fumadocs declares little Blume needs — read the loader and the shared layout options: + +- **Title** — the header title: `nav.title` in `baseOptions` (`lib/layout.shared.tsx`, or `app/layout.config.tsx` in older scaffolds; often the `appName` constant from `lib/shared.ts`; extract the text if it's JSX). Without one, read `package.json` `name`, prettified (drop scope, split on `-_`, Title-Case); for a generic monorepo name (`web`, `app`, `docs`…), use the repo-root directory name instead. +- **Header settings** (the same `baseOptions`): `githubUrl` → `github: { owner, repo }` (the repository and edit links; when it's built from a `gitConfig` constant in `lib/shared.ts`, `{ user, repo, branch }` → `{ owner: user, repo, branch }`); `links` entries → `navigation.actions` (`{ label: text, href: url }`), except a `type: "icon"` link to a platform `footer.socials` knows (Discord, X, …), which goes there instead. Menus, custom items, and JSX in `nav` → report. +- **Route prefix** — the `baseUrl` in the source loader (required in Fumadocs, so it's always declared). If it's a real prefix (e.g. `/docs`), set top-level **`basePath: "/docs"`** — it prefixes every route while staying invisible to the sidebar, which matches Fumadocs' behavior. (A `content.sources` `prefix` also works but adds a wrapping nav group — only use it when you _want_ the group.) If `baseUrl` is `"/"`, serve from the site root (nothing to set). + +Everything else is Blume defaults. + +**Also read the MDX options** — remark/rehype plugins live in `source.config.ts` `mdxOptions`, or, with the macro API, in the collection options passed to `defineDocs` (a macro project may still keep a `source.config.ts` for global options): + +- `remark-math`/`rehype-katex` → nothing to configure: `$$…$$` renders in `.mdx` out of the box (there is **no** `markdown.math` field), as a block or inline within a sentence. A single `$` stays literal, so convert each inline `$…$` to `$$…$$` inside its sentence. +- A Twoslash transformer → Blume supports the `twoslash` fence meta natively; drop the plugin. +- Custom Shiki transformers/themes or other plugins → report. + +## Navigation: `meta.json` → `meta.ts` + +**Every `meta.json` becomes a `meta.ts` — this is the primary navigation carry-over for Fumadocs, always required, never optional.** `meta.json` is Fumadocs' canonical nav source; no filesystem-only shortcut reproduces its ordering, icons, and collapse state, so don't skip it in favor of filename inference. Move content from `content/docs/` to your chosen `content.root` (e.g. `docs/`), then convert each `meta.json` to a `meta.ts` (`defineMeta`): + +| Fumadocs `meta.json` | Blume `meta.ts` | +| --- | --- | +| `title` | `title` | +| `icon` | `icon` — **convert the casing** (see Icons below) | +| `defaultOpen: false` | `collapsed: true` | +| `defaultOpen: true` | `collapsed: false` | +| `root: true` | a **`navigation.tabs` entry** (see below) — **not** a `meta.ts` field | +| `pages: [...]` slugs | `pages: [...]` (ordering) | +| `description` | **drop** (folders have no description) | +| `collapsible: false` | that folder's `display: "flat"` (a plain heading, even under a global `"group"` mode) | + +`meta.ts` accepts **only** `title`, `icon`, `order`, `collapsed`, `pages`, `display`, `directory` (`"card"`/`"accordion"` lists the folder's pages below its `index` page — the replacement for a hand-written card list of the folder's children). Render mode is per-folder or global: a folder that needs collapsible rendering sets its own `meta.ts` `display: "group"` (drill-in is `"page"`); when the whole sidebar should collapse, set `navigation.sidebar.display: "group"` once in `blume.config.ts` instead of repeating it per folder. + +**Numeric filename prefixes move URLs.** Fumadocs builds slugs from the file path as written, so `01-intro.mdx` serves `/docs/01-intro`; Blume reads a `01-` prefix on a file or folder as sort order and drops it from the route (`/docs/intro`). Add a `redirects` entry for every prefixed file or folder (or pin the old path with frontmatter `slug`, a full path from the content root), and write `pages` entries without the prefix (`"intro"`, not `"01-intro"`). + +**`root: true` folders are Fumadocs' tab mechanism** — Fumadocs UI renders them as layout tabs and scopes the sidebar to the active one. That is exactly Blume's `navigation.tabs`: add `{ label, path, icon? }` per root folder (label/icon from its `meta.json`), pointing at the folder's route. Blume then scopes the sidebar by URL prefix the same way. Don't try to model root folders inside `meta.ts`. + +Handle the `pages` array items: + +- **`"..."`** (rest marker) / `""` → drop; Blume appends unlisted pages automatically. **`"z...a"`** (reversed rest) → no equivalent; list the pages explicitly in the intended order. +- **A `pages` list with no `"..."`** → Fumadocs shows **only** the listed items; every page and folder it leaves out is hidden from the sidebar (still served by URL). Blume appends unlisted children, so each one **resurfaces** — set `sidebar.hidden: true` in each left-out page's frontmatter (for a left-out folder, in every page under it — a folder with no visible page drops out of the sidebar). +- **`"!page"`** (exclusion from `"..."`) → the same trap: Blume _appends_ unlisted pages, so a dropped `!page` **resurfaces in the sidebar**. Set that page's frontmatter `sidebar.hidden: true` instead. +- **`"---Section---"`** (separator; also the `---[Icon]Label---` variant) → Blume has no flat separator. Turn each section into a **`(Section)/` group folder** (route-transparent — the `(…)` segment is stripped from URLs), and move the section's pages into it. If a section wraps a single existing folder, leave it in place and set that folder's `meta.ts` `title` instead. +- **`"...folder"`** (extract) → Blume can't flatten a folder inline; keep it as a normal group at that ordering position and report it. +- **`"[Text](url)"`** (link; also `[Icon][Text](url)` and `external:` variants) → a top-level/utility link belongs in **`navigation.featured`** (`{ label, href, icon? }` — pinned above the sidebar on every route). A link buried deep in one folder has no folder-meta home — drop and report (or model that one folder via an explicit `navigation.sidebar`). +- **`pagesIndex`** → make that page the folder's `index` (rename the file); report the route change and add a redirect. + +## Frontmatter + +Fumadocs' core frontmatter (`title`, `description`, `icon`) matches Blume — but **convert `icon` casing** (see Icons). **`full: true`** (full width, TOC folded into a popover) → `mode: wide` (full column width, no TOC — the closest match; report); **`_openapi`** marks a generated API stub — delete the whole page (see OpenAPI). Any other non-schema key is a build error, so drop and report. + +## Icons: lucide-react names → kebab-case + +Fumadocs icons are strings resolved by the repo's own `icon` handler in `loader()` — in practice **PascalCase lucide-react export names** (`"BookOpen"`, `"HomeIcon"`). Blume resolves **kebab-case** Lucide names and silently renders nothing on a miss, so pass-through loses every icon. Read the loader's icon handler to confirm the scheme, then convert each name: strip any `Icon` suffix, kebab-case it (`BookOpen` → `book-open`, `HomeIcon` → `home`), and verify it exists at [lucide.dev/icons](https://lucide.dev/icons). + +## Components + +- **Callouts:** `` → `:::` directive. Fumadocs types are `info` (the default), `warn`, `warning`, `error`, `success`, `idea`: `warn`/`warning`→`:::warning`, `error`→`:::danger`, `success`→`:::success`, `idea`→`:::tip`, `info` and **bare ``** → `:::info`. `title` → `:::type[Title]`; drop `icon`. +- **Cards:** `` → ``. `` needs **prop surgery**, not pass-through: Fumadocs `icon` is a JSX element (`icon={}` imported from `lucide-react`) → Blume takes a string name (`icon="cpu"`); Fumadocs `description="…"` → Blume has no `description` prop — move the text into the card body. +- **Accordions (container/item inversion):** `` → `` (container); `` → `` (item). +- **File trees:** `` → **``** (the JSX container for `Tree.*` children — _not_ ``, which wraps a Markdown list); `` → `` (`defaultOpen` carries over); `` → ``. Or convert the whole block to a list-driven ``. +- **Tabs:** Fumadocs declares labels on the parent (``) and selects with ``. Blume's `` carries its own `title`. Strip `items={[…]}` from `` and give each child `` a `title` (from its `value`, or the positional `items` entry). +- **Pass through unchanged:** ``/``, `` (Blume's was modeled on Fumadocs' — identical `type` record shape), ``. +- **``** (layout-mounted, not per-page) → the `banner` config field (`{ content, link: { href, text }, dismissible, id }`). +- **`./partial.mdx`** — Blume uses the same include syntax. **Pass through unchanged**: paths resolve relative to the including file, a leading `/` resolves from the content root, and nested includes work. Keep partials in `_`-prefixed files or folders so they stay out of routing and the sidebar. +- **No equivalent — report:** ``, `` (Blume zooms content images by default), ``. +- **Strip or convert every import** — not just `fumadocs-*`: `lucide-react` imports (icon JSX → string names), `next/image`/`next/link` (→ Markdown image/link), and local components. **Inventory the MDX components file before deleting it** — `components/mdx.tsx` (`getMDXComponents`) in newer scaffolds, `mdx-components.tsx` in older ones; components registered there are used import-free in MDX bodies; port or inline each usage first. + +## Headings + +Trailing heading markers — `[#custom-id]` (pinned anchor), `[!toc]` (hide from the TOC), `[toc]` (TOC-only entry) — use the same syntax in Blume. **Pass through unchanged.** One exception: Fumadocs' looser grammar accepts an id containing whitespace (`[#two words]`); Blume does not parse that as a marker, so rewrite such an id to a hyphenated one and update every link that targets it. + +## Code fences + +- ` ```npm ` fences (Fumadocs' remark-npm accepts both) → ` ```package-install `. +- Adjacent fences sharing `tab="…"` meta render as grouped tabs in Fumadocs → wrap them in a Blume `` and drop the `tab=` attrs. + +## OpenAPI + +`fumadocs-openapi` writes **generated MDX stubs into the content tree** (`generateFiles()` output: pages containing ``/`` with `_openapi` frontmatter), plus `lib/openapi.ts` (`createOpenAPI`) and a generate script. Treat these exactly like Mintlify endpoint stubs: **delete the generated pages**, add `openapi({ spec })` (from `blume/reference`) to the top-level `reference` list (vendor the spec locally), add a `navigation.tabs` entry for the reference route, and remove `fumadocs-openapi`, `lib/openapi.ts`, and the generate script. Keep hand-written conceptual pages (intro/auth) under the reference route. + +## GraphQL + +`@fumadocs/graphql` works differently from the OpenAPI flow: **no stub files** — pages are virtual, served through the Loader API. The artifacts to harvest and tear down: `lib/graphql.ts` (`createGraphQL()` — read its `input` for the schema and any per-source routes/labels), the `graphql.staticSource()`/`graphql.loaderPlugin()` wiring in the source config, the `GraphQLPage` component (`createGraphQLPage()`, usually `components/api-page.tsx` — read its playground `endpoint`), and the `@fumadocs/graphql/css/preset.css` import. Map to a `graphql({ spec, endpoint })` entry in the top-level `reference` list (see SKILL.md "GraphQL"): SDL files/text and introspection results carry over as `spec` (vendor a URL input locally); a programmatic `GraphQLSchema` instance must be printed to SDL and committed (report); the `createGraphQLPage` playground endpoint becomes `endpoint`. When `createGraphQL()` takes several inputs, or sources carry their own routes, labels, or endpoints, map each one to an entry in the adapter's `sources` (`{ spec, route, label, endpoint }`) instead of the single `spec` shorthand — otherwise a schema is dropped or mounted on the wrong route. Blume groups routes the same way (`/queries/`, `/objects/`), but slugs are re-derived — rewrite inbound links and let `blume validate` catch strays. Then remove `@fumadocs/graphql`, the two lib/component files, and the CSS import. Since there are no generated pages, there is nothing to delete from the content tree — but keep any hand-written conceptual pages under the reference route. + +## i18n + +A `loader({ i18n })` setup (locale-suffixed files or locale dirs) → Blume `i18n: { defaultLocale, locales: [{ code, label }] }`. Locale **directories** match Blume's default `dir` parser as-is; locale **file suffixes** (`page.cn.mdx` beside an unsuffixed default-locale `page.mdx`) match the `dot` parser as-is — add `parser: "dot"`, no file moves. Under `dot` a folder's `meta.ts` serves every locale, so build it from the default locale's `meta.json` and report any translated folder titles in `meta..json`. Report whichever transform you apply. + +## Package.json & teardown + +Repoint scripts (`dev`→`blume dev`, `build`→`blume build`, `start`→`blume preview`), remove the `fumadocs-*`/`@fumadocs/*` deps and the host framework's deps (`next`, `react-router`, `@tanstack/*`…), add `blume`. Safe to delete after harvesting (see above for what to read first): `source.config.*`, `lib/source.ts`, `lib/shared.ts`, `lib/layout.shared.tsx` (or `app/layout.config.tsx`), `components/mdx.tsx` / `mdx-components.tsx`, the app/route dir, and host-framework config (`next.config.*`, `next-env.d.ts`, the `next` tsconfig plugin — or the React Router/TanStack equivalents). + +## Dropped — report these + +Folder `description` and `collapsible: false`; reversed rest (`z...a`) ordering; the extract (`...folder`) flatten semantics; deep-folder sidebar links; frontmatter `full` (approximated as `mode: wide`); header settings from `lib/layout.shared.tsx` with no Blume home; ``/``; custom Shiki transformers; any icon with no Lucide equivalent after casing conversion. diff --git a/.github/skills/blume-migrate/references/mintlify.md b/.github/skills/blume-migrate/references/mintlify.md new file mode 100644 index 0000000..aa9dbec --- /dev/null +++ b/.github/skills/blume-migrate/references/mintlify.md @@ -0,0 +1,190 @@ +# Mintlify → Blume + +The deepest migration. Mintlify declares its **entire navigation in `docs.json`**; Blume derives navigation from the filesystem. The bulk of the work is reshaping content into folders + tabs and translating config, callouts, and icons. + +## Detect + +- `docs.json` (current) or `mint.json` (legacy) at the repo root — the config file. +- A `mintlify` dependency / `mintlify dev` script. +- Content is `.mdx` under the repo root (Mintlify has no `content.root` — pages live at the top level), with a `/snippets` folder and image dirs like `/images`. + +Read `docs.json` first; it drives everything. + +## Config: `docs.json`/`mint.json` → `blume.config.ts` + +Resolve `$ref` includes first (Mintlify splits config across files). Map only what's set: + +| Mintlify | Blume | Notes | +| --- | --- | --- | +| `name` / `title` | `title` | | +| `description` | `description` | | +| `logo` (string or `{ light, dark, href }`) | `logo` (string, or `{ image: { light, dark, alt }, text, href }`) | Mintlify's `light`/`dark` nest under Blume's `image`; ensure files land in `public/`. **If the SVG is local and monochrome** (a solid black or white mark), rewrite its `fill`/`stroke` to `currentColor` and collapse `{ light, dark }` to the string shorthand `logo: "/logo.svg"` — one file that inherits the theme text color and flips with light/dark automatically. If the logo is a **wordmark** (brand name baked in), set `text: ""` so it doesn't render twice beside `title` | +| `favicon` (string **or `{ light, dark }`**) | **drop the field** — copy the file(s) into `public/` under conventional names (`favicon.svg`/`icon.png`) | Blume auto-detects by filename; there is **no** favicon config field. A `{ light, dark }` source maps to a filename pair: light file → `public/icon.png`, dark file → its `-dark` sibling `public/icon-dark.png` (same directory and extension — convert if the formats differ) | +| `colors.primary` + `colors.light` | `theme.accent` (`{ light, dark }`) | accent is now **per-mode**: `accent: { light: , dark: }`. If Mintlify sets only `primary`, collapse to the string shorthand `accent: ""` (applies to both modes) | +| `colors.dark` | `theme.action` | | +| `appearance.default` | `theme.mode` (`light`/`dark`/`system`) | | +| `appearance.strict` | **drop** | `theme.strict` was removed — writing it is a config error | +| `background.color.{light,dark}` | `theme.background` (`{ light, dark }`) | one field now: `background: { light: …, dark: … }` (a bare string applies to both) | +| `background.image` | `theme.backgroundImage` (`{ light, dark }`) | same per-mode shape as `background` | +| `background.decoration` | **drop** | no Blume equivalent | +| `fonts.family` / `fonts.{heading,body}.family` | `theme.fonts.{display,body}` | a curated slug (kebab-case, e.g. `space-grotesk`) maps directly; any other Google family maps to the object form `{ name: "Family Name" }`; a self-hosted font (`fonts.*.src` URLs) maps to `{ name, variants: [{ src, weight }] }` after downloading the files into the project | +| `banner` | `banner` (`{ content, dismissible, id, link: { href, text } }`) | **only** those keys — drop `banner.color`/`banner.type` | +| `styling.latex: true` | **drop the field** — block math `$$…$$` renders in `.mdx` with no config | there is **no** `markdown.math` field; Blume writes inline math with two dollar signs too — convert each inline `$…$` to `$$…$$` inside the sentence, checking every pair is math and not currency or a shell variable | +| `styling.codeblocks.theme` | `markdown.code.theme` (`{ light, dark }`) | | +| `search.prompt` | **drop** | no equivalent | +| `seo.metatags` | `seo.metatags`, minus the tags Blume writes itself | keep verification tokens, `theme-color`, and the like as written; Blume refuses `description`, `robots`, `og:title`/`og:description`/`og:image`/`og:url`/`og:type`/`og:site_name`, `twitter:*` card tags, and `article:*` dates, so move those to their settings (`og:image` → `seo.og` or a page's `seo.image`, `twitter:site` → `seo.x.handle`) and drop the rest. `seo.paths` (folder tags) has no equivalent: set per-page `seo` frontmatter | +| `seo.indexing: "all"` | `search.indexing.includeHiddenPages: true` | | +| `variables` (`{{name}}`) | `variables` | same syntax and names (letters, digits, `_`, `-`); pages keep their `{{name}}` references unchanged | +| `integrations.posthog` (`{ apiKey, apiHost, sessionRecording }`) | `posthog({ key, host })` in the `analytics` list | preserve the host verbatim (e.g. `us.posthog.com` — Blume's default is `us.i.posthog.com`); `sessionRecording: false` → `disable_session_recording: true`; every adapter is imported from `blume/analytics` | +| `integrations.ga4` (`{ measurementId }`) | `googleAnalytics({ id })` | | +| `integrations.gtm` (`{ tagId }`) | `googleTagManager({ id })` | | +| `integrations.plausible` (`{ domain, server }`) | `plausible({ domain, host })` | `server` is a bare hostname; `host` is an origin — prepend `https://` | +| `integrations.fathom` (`{ siteId }`) | `fathom({ site })` | | +| `integrations.pirsch` (`{ id }`) | `pirsch({ code })` | | +| `integrations.mixpanel` (`{ projectToken, region }`) | `mixpanel({ token, region })` | | +| `integrations.amplitude` (`{ apiKey }`) | `amplitude({ key })` | | +| `integrations.segment` (`{ key, cdnUrl }`) | `segment({ key, cdn })` | | +| `integrations.hightouch` (`{ writeKey, apiHost }`) | `hightouch({ key, host })` | | +| `integrations.heap` (`{ appId }`) | `heap({ id })` | | +| `integrations.hotjar` (`{ hjid, hjsv }`) | `hotjar({ id, version })` | both numbers | +| `integrations.clarity` (`{ projectId }`) | `clarity({ id })` | | +| `integrations.logrocket` (`{ apiKey }`) | `logrocket({ id })` | | +| `integrations.clearbit` (`{ publicApiKey }`) | `clearbit({ key })` | | +| `integrations.adobe` (`{ launchUrl }`) | `adobe({ url })` | | +| any other `integrations` script | `script({ src, strategy, attributes })` / `vercel()` in the `analytics` list | one `script()` adapter per provider without a factory | +| `telemetry` (`{ enabled: false }`) | `feedback: false` | Mintlify's switch also turned off its feedback widgets; Blume sends no telemetry of its own, so only the rating needs turning off | +| Feedback toggles in the Mintlify dashboard (not in `docs.json`) | `feedback: { comments: true }` for contextual (written) feedback | ask whether the site collected written feedback; Blume sends comments through the `analytics` adapters as `feedback_comment` events. Code-snippet feedback, edit suggestions, and raise-issue have no equivalent: report them | +| `integrations.cookies` (`{ key, value }`), or a content-folder `.js` file that injects Osano or Ethyca/Fides | `consent`, imported from `blume/consent`: `osano({ customerId, configId })` (both IDs from the `cmp.osano.com///osano.js` URL), `ethyca({ privacyCenter })` (the origin that serves `fides.js`), or `native()` for Blume's own banner | Mintlify's `cookies` pair only switched off its own telemetry for readers whose localStorage lacked the value; under `consent`, every `analytics` adapter waits for the reader instead. Delete the injector script. Another consent manager (Transcend, OneTrust, …) has no adapter: report it | +| A root `skill.md`, or `.mintlify/skills//SKILL.md` | move each into a `skills//` folder and set `agents.skills: "./skills"`; drop Mintlify-only frontmatter (`groups`) | Blume already generates a skill for the site at `/skill.md` (`agents.skillMd`, on when `deployment.site` is set); a root `skill.md` replaces it only if its `name` matches the site's title slug (`Acme Docs` → `acme-docs`), so set that name | +| `contextual` (`["copy","chatgpt","claude",…]`) | **mostly free** | Copy-as-Markdown and Open-in-chat are default page actions; `mcp` needs `agents.mcp.enabled` + server output (report as a follow-up) | +| `footer` (`{ socials, links }`) | `footer: { socials, links }` | `socials` keeps its keys, except `twitter`/`x-twitter` → `x` and `earth-americas` → `website`; a key outside Blume's list drops (report); `links` is one row of `{ label, href }`: every column's `items` flatten into it in order, and each column's `header` drops (report) | +| `api.mdx` (`{ server, auth: { method, name } }`) | `api: { server, auth: { method, name } }` | the defaults for `api`-frontmatter pages | +| `api.playground` (`{ display, proxy }`) | `api: { playground }` | `display: "none"` → `playground: false`; `"simple"` has no site-wide form, so set `playground: simple` in each page's frontmatter; `proxy` (on by default in Mintlify) → `playground: { proxy: true }`, which needs a server-output adapter, or leave it off to send directly | +| `redirects` (`{ source, destination, permanent }`) | `redirects: [{ from, to, status }]` | `source` → `from`, `destination` → `to` as written, patterns included (`/beta/:slug*`, `/old/article-*`); `permanent: false` → `status: 307`, otherwise `status: 308` | +| `navigation.languages` | `i18n` | see i18n below | + +A minimal result is often just `defineConfig({ title, logo, theme: { accent } })`. + +## Icons: FontAwesome → Lucide (required) + +Mintlify defaults to **FontAwesome**; Blume is **Lucide-only**. Convert every icon reference — frontmatter `icon`, nav-group `icon`, ``, `` — to the closest Lucide name. Discard Mintlify's `iconType` (solid/regular/brands) entirely. + +**Automate the frontmatter pass — don't hand-edit it.** `scripts/mintlify-codemod.mjs` (in this skill, zero-dependency) remaps every **frontmatter** `icon:` using the table below, drops brand/no-equivalent icons, and — in the same pass — drops/renames unsupported frontmatter keys (see [Frontmatter](#frontmatter)). It's deterministic and idempotent, and reports what it changed per file plus what it couldn't (unknown icons, OpenAPI-stub flags): + +```bash +# = this skill's directory (the one containing SKILL.md); dry run first (report only), then apply: +node /scripts/mintlify-codemod.mjs +node /scripts/mintlify-codemod.mjs --write +``` + +The codemod touches **only frontmatter**. Icons in MDX **body** (``, ``, nav-group icons in `docs.json`) it does not see — convert those by hand using the same table. Common mappings: + +| FontAwesome | Lucide | | FontAwesome | Lucide | +| --- | --- | --- | --- | --- | +| `bolt` | `zap` | | `gear`/`cog` | `settings` | +| `circle-info`/`info` | `info` | | `wand-magic-sparkles`/`magic` | `sparkles` | +| `house` | `house` | | `magnifying-glass` | `search` | +| `gauge`/`gauge-high` | `gauge` | | `puzzle-piece` | `puzzle` | +| `envelope` | `mail` | | `file-lines` | `file-text` | +| `pen-to-square` | `square-pen` | | `trash-can` | `trash-2` | +| `xmark`/`times` | `x` | | `circle-check` | `circle-check` | +| `triangle-exclamation` | `triangle-alert` | | `circle-exclamation` | `circle-alert` | +| `arrow-right-from-bracket` | `log-out` | | `right-to-bracket` | `log-in` | +| `location-dot`/`map-marker` | `map-pin` | | `comments` | `messages-square` | +| `cube` | `box` | | `cubes`/`boxes` | `boxes` | +| `layer-group` | `layers` | | `diagram-project`/`sitemap` | `workflow`/`network` | +| `chart-line` | `chart-line` | | `chart-simple`/`chart-column` | `chart-column` | +| `flask` | `flask-conical` | | `robot` | `bot` | +| `screwdriver-wrench`/`toolbox` | `wrench` | | `circle-question`/`question` | `circle-help` | +| `life-ring` | `life-buoy` | | `shield-halved` | `shield` | +| `rocket`/`book`/`book-open`/`code`/`terminal`/`key`/`lock`/`user`/`users`/`database`/`server`/`cloud`/`bell`/`calendar`/`star`/`heart`/`tag`/`folder`/`globe`/`link`/`download`/`upload`/`check`/`copy`/`play`/`filter` | _(same name — verify)_ | + +**Rules:** verify each Lucide name exists at [lucide.dev/icons](https://lucide.dev/icons) before writing it. **Brand icons** (`fa6-brands:*` — github, discord, x, slack, linkedin…) mostly have **no** Lucide equivalent: for GitHub use the `github` config (renders the footer's repo link); for other socials, use `footer.socials`. Where no Lucide counterpart exists, **drop the icon and report it**. The build won't catch a wrong name for you: an unknown icon renders nothing, and it's only a warning (`BLUME_UNKNOWN_ICON`) for navigation icons — an icon prop on a component like `` fails silently — so check every name. + +## Navigation: `docs.json` `navigation` → filesystem + tabs + +Mintlify's `navigation` object (`tabs`/`anchors`/`dropdowns`/`products`/`versions`/`languages`/`groups`/`pages`) is fully config-declared. **Prefer restructuring content into folders**, not porting the config verbatim: + +- **`groups`** (`{ group, pages: [...] }`) → a folder per group. The `group` name → the folder's humanized name or a `meta.ts` `title`. Nested groups → nested folders. `expanded: false` → `meta.ts` `collapsed: true` (inverted). `tag` → the folder/page `sidebar.badge`. `directory` (`card`/`accordion`/`none`, on a group, tab, or the navigation itself) → `meta.ts` `directory` on that folder, or on the content root's `meta.ts` for the whole navigation; it inherits down the tree the same way, and lists the pages on the group's `root`/`index` page. **Folder metadata is a `meta.ts` module** (`export default defineMeta({ title, icon, order, collapsed, pages, display, directory })`), a TypeScript file — **not** JSON. Blume does not read a `meta.json`, so any folder-level config you carry over from the source (or hand-write to preserve a group's label/order/collapse) must be authored as `meta.ts`. (Render mode — flat/group/page — defaults to the global `navigation.sidebar.display` in `blume.config.ts`; a folder overrides its own group with `meta.ts` `display`, or `sidebar.display` in its `index` page's frontmatter.) +- **Config-only nested groups don't exist on disk — you must materialize them, or they flatten silently.** A nested `{ group, pages }` almost never has a matching subfolder: its pages sit **flat in the parent directory** (e.g. `platform/analytics/getting-started.mdx`, `…/quick-reference.mdx`) and the grouping lives **only** in the `docs.json` `pages` array. If you leave the files where they are, filesystem-derived nav sees one flat folder and the inner group vanishes — Mintlify's `Analytics → Reference → {…}` becomes a flat `Analytics → {…}`. To preserve it you must **either** move those pages into a real subfolder (`platform/analytics/reference/`, with a `meta.ts` for the label/`collapsed`), **or** declare the shape in an explicit `navigation.sidebar`. Walk **every** `pages` array recursively and treat any nested `group` object as a folder-move to plan, not files already in place. When inventorying the nav (workflow step 2), record the config nesting depth separately from the on-disk depth — they diverge exactly here. +- **This is the canonical case for `navigation.sidebar` over folders.** Materializing a purely-presentational nested group as a subfolder changes URLs (`/platform/analytics/getting-started` → `/platform/analytics/reference/getting-started`) for no reason other than a visual grouping, forcing a `redirects` entry per page. When you want to keep the nesting **and** the URLs, an explicit `navigation.sidebar` group (`{ label, items }`) is the better trade — it nests the existing routes without moving any file. Pick per group; don't reflexively flatten. +- **`pages`** entries are page refs (paths without extension) → files at the corresponding path. An entry that's `"GET /path"` is an OpenAPI endpoint stub → **delete it** (Blume generates these; see OpenAPI). +- **`tabs`** (top-level `navigation.tabs`, e.g. `App` / `API` / `API reference`) → Blume's **header tabs** `navigation.tabs` (`{ label, path, icon? }`). **Keep them as tabs — do not flatten them into `navigation.sidebar` groups or sections.** Flattening is the easy translation error: it collapses the site's top-level structure into one global sidebar and loses the header tab bar entirely. A Mintlify top-level tab is a header tab; map it to one. Put each tab's pages in **one folder** and point the tab's `path` at it — the tab then scopes the sidebar automatically (under the tab's `path`, the sidebar shows only that folder). **Blume resolves the active tab by URL prefix** (the tab whose `path` is the longest prefix of the current route), so every page in a tab must live under that tab's single `path`. Mintlify tabs freely mix pages from any folder / arbitrary routes; Blume tabs scope by prefix, so a tab that pulls in routes from all over is **not portable as-is**. You have two choices, per tab: + - **Move the pages under one prefix** so they share the tab's `path` (a route change → add a `redirects` entry for each moved page). This preserves the exact tab grouping. + - **Accept the closest shape** — assign each shared/cross-cutting page to one tab's folder and link to it from the others — when moving routes isn't worth the churn. + + Call this trade out explicitly in the migration report; don't silently pick one. **The scoping is bidirectional:** on the root/landing route Blume _hides_ every tab folder and lists only untabbed top-level pages — so a Mintlify home whose single sidebar showed everything becomes a lean root list plus one sidebar per tab. That's automatic; don't try to exclude tab folders from the root by hand. + +- **`dropdowns`/`products`/`versions`** → `navigation.selectors` (`{ kind, label, items: [{ label, path, icon?, description?, tag? }] }`). Use `kind` `dropdown`/`product`/`version` accordingly. +- **`anchors` / `navigation.global.anchors`** (persistent sidebar-top links — Blog, Changelog, Community, Contact/Support) → **`navigation.featured`** (`{ label, href, icon? }`). These pin to the **top of the sidebar, above every section, on every route** (not tab-scoped) — the right home for Mintlify's always-visible utility links. An external `href` opens in a new tab; an internal one (`/contact`) is build-time validated against your pages. Convert the FontAwesome `icon` to Lucide as usual. (This replaces the old "drop and report" for anchors.) +- **`navbar.links`** (plain header links — Log in, Status, Support) → **`navigation.actions`** (`[{ label, href }]`), rendered in the header left of the icon buttons. A GitHub link → the `github` config (or `navigation.repo` as a URL when the docs repo is private) instead; it renders in the footer, the only place Blume links a repository. Header links hide on phones; a link that must survive there belongs in `featured`. +- **`navbar.primary`** (the header **CTA button** — "Get Started"/"Sign Up", `type: "button"`) → **`navigation.cta`** (`{ label, href }`, singular: Blume renders exactly one filled button). A `type: "github"` primary → the `github` config instead. A route the docs don't serve (the product's own `/signup`) must be an absolute URL, or it raises `BLUME_NAV_MISSING_PAGE`. +- **`languages`** → `i18n`, not a selector (see below). +- Only fall back to an explicit `navigation.sidebar` for a shape the filesystem genuinely can't express. + +This reshaping **changes URLs** — a page moved from `getting-started/quickstart` into the API tab's folder becomes `/api/…`, an `index` promotion drops a segment, etc. Record each old→new path and add a `redirects` entry for it (see below); otherwise every existing link and bookmark 404s. + +## Content & component transforms + +Rewrite each page's MDX: + +- **Callouts → directives** (directives are **MDX-only** — Mintlify content is already `.mdx`, so this just works; never rename a page to `.md`): ``→`:::note`, ``→`:::tip`, ``→`:::warning`, ``→`:::info`, ``→`:::success`, ``/``→`:::danger`. `` maps by type (`caution`→warning, `check`→success). A `title` attr → `:::type[Title]`. Drop `icon`/color props. +- **Accordions — container/item inversion!** Mintlify nests `` inside ``. Blume inverts: ``→`` (container), and each Mintlify ``→`` (item). +- **`` → ``.** Mintlify renders tabs **borderless** — a strip on a full-width rule with the content flowing beneath as prose — while Blume's `` defaults to a bordered box. Add `inline` to each `` to preserve Mintlify's appearance; every child `` is unchanged. Don't add `param` — Mintlify tabs switch in place and don't deep-link to the URL, so plain `inline` is the faithful mapping. +- **These pass through — Blume ships them natively:** ``/``, ``, ``, ``, ``, ``/``, ``, ``/``, `` (its `title` becomes an option in the page's view picker, as on Mintlify; remap its `icon` with the table below and drop `iconType`). Keep them as-is. +- **Multi-word code-block titles need quotes.** Mintlify reads everything after the language as the title (` ```ts Acme SDK `); Blume reads one bare word, so write ` ```ts title="Acme SDK" `. One-word titles (` ```bash cURL `) stay as they are. +- **``/`` pass through.** Top-level ones pin to a column beside the page on wide screens, request above response, as on Mintlify; `dropdown` works the same. +- **Hand-written endpoint pages pass through.** `api: "POST /v1/users"` frontmatter, with `authMethod` (`bearer`/`basic`/`key`/`none`) and `playground` (`interactive`/`simple`/`none`), works as on Mintlify: the page's ``s build its Try it panel and request samples. Keep them as written. +- **API fields pass through.** `` (`path`/`query`/`header`/`body`, `type`, `required`, `deprecated`, `default`, `placeholder`) and `` (`name`, `type`, `required`, `deprecated`, `default`, `pre`, `post`) render natively, nested `` fields included. Keep them as written. An older `` isn't supported: rewrite it as a ``. +- **``** (a Mintlify changelog entry) has no component form → convert to a `type: changelog` page, or use the `githubReleases()` source. +- **Snippets become includes.** Blume has no `/snippets` import mechanism; its reuse is ``. Move each snippet into the content folder as a `_`-prefixed partial (`_snippets/x.mdx`, which never renders as a page), and replace `import X from "/snippets/x.mdx"` + `` with `./_snippets/x.mdx` on its own line. In the partial, rewrite each `{prop}` placeholder to `{{prop}}`: include attributes are props read with the variables syntax. Named string imports (`import { foo } from "/snippets/vars.mdx"`) → a site-wide `variables` entry read as `{{foo}}`, or inline the value. + +## Frontmatter + +Mintlify page frontmatter → Blume's strict schema. **`scripts/mintlify-codemod.mjs --write` does the mechanical rows automatically** (rename, drop, icon-remap) and flags the judgment rows (`openapi`/`asyncapi`) for you — see [Icons](#icons-fontawesome--lucide-required) for the invocation. The table is both the mapping reference and a description of exactly what the codemod does: + +| Mintlify | Blume | Codemod | +| --- | --- | --- | +| `title` / `description` | pass through | — | +| `sidebarTitle` | `sidebar.label` | renames | +| `icon` | remapped to a Lucide name in place (top-level `icon` is valid Blume frontmatter; keep it there) | remaps | +| `tag` | `sidebar.badge` | renames | +| `canonical` | `seo.canonical` | renames | +| `og:image` | `seo.image` | renames | +| `hidden: true` | valid top-level in Blume — **kept as-is**; add `noindex: true` yourself if the page must also leave the search index | left (do by hand) | +| `openapi`/`asyncapi` | usually an endpoint stub → **delete the page** (Blume generates operation pages); else drop the key and keep it as a normal page | **flags** for review — never auto-deletes a page | +| `api`, `authMethod`, `playground` | kept as written (a hand-written endpoint page, see above) | left | +| `related` (a list) | kept as written: root-relative paths, URLs, and `{ Title: link }` entries render as Related pages cards | left; `related: true` has no equivalent (Blume has no automatic related pages), so drop it (report) | +| `mode` | `mode`, as written | `default`, `wide`, `center`, `custom`, and `frame` carry over; `assistant` has no equivalent → drop (report) | +| `hideFooterPagination: true` | `pagination: false` | renames (`false` drops, since the links show by default) | +| `keywords`, `boost` | `search.keywords`, `search.boost` | renames | +| `searchable: false` | `search.exclude: true` | renames (`searchable: true` drops, since pages are searchable by default) | +| `public`, `rss`, `groups`, `hideApiMarker`, `iconType` | **drop** (report) | drops | + +The codemod leaves the source key in place and reports a conflict rather than clobbering data when a rename target already exists (e.g. a page already has `sidebar.label`) or the value is too structured to move safely — resolve those by hand. Remove any duplicate H1 in the body — `title` renders the H1. (The codemod only edits frontmatter; it never touches the body.) + +## OpenAPI + +Top-level `openapi`, `api.openapi`, or a per-group/per-tab `openapi` → `reference: [openapi({ sources: [{ spec, label?, route? }] })]`, with `openapi` imported from `blume/reference` (`spec` alone is the single-source shorthand; several per-tab specs become several sources, or several `openapi()` entries when they need different routes; a spec the source embedded with Scalar becomes a `scalar({ spec })` entry). A Mintlify `{ source, directory }` object: `directory` → the source's `route`. An `asyncapi` field maps the same way to `asyncapi({ … })` in the list. **Delete every per-endpoint stub page** (frontmatter `openapi: "GET /path"`, `openapi: "spec.json webhook name"`, or a `"GET /path"` nav entry) — Blume's native renderer generates one real page per operation and per webhook, and shows callbacks on their operation's page. **Add a `navigation.tabs` entry pointing at the reference `route` yourself** (Mintlify's API tab maps to it); the reference does not create a header tab automatically. + +- **Vendor the spec.** Mintlify usually points at a spec **URL**. Copying that straight into `spec:` makes every build fetch it at build time — a single point of failure in CI/offline/behind a proxy, and a failed fetch silently drops the reference (leaving the tab pointing at a route that 404s). Prefer downloading it into the repo (`curl … -o openapi/.json`) and pointing `spec` at that local path. If you keep the URL, report the dependency and consider a `prebuild` refresh-with-fallback. +- **Fix endpoint links.** Blume operation routes are `//` (tag `Models` + id `listModels` → `/api-reference/models/list-models`: a camelCase id is split into kebab-case, not just lowercased — see SKILL.md "OpenAPI") — this differs from Mintlify's endpoint URLs, so **rewrite every inbound link to an operation**. `blume validate` resolves operation pages like any other route and flags the ones you miss. +- **Overlays carry over.** An `openapi: { source, overlays: [...] }` object → that source's `overlays` (`openapi({ spec, overlays })`, or `overlays` on each entry in `sources`), in the same order; Blume applies Overlay 1.0 and 1.1 the same way. An overlay Mintlify found only through its `extends` field (auto-discovered, not listed in `docs.json`) must be listed explicitly: Blume doesn't scan for overlays. +- **Code samples carry over.** `api.examples.languages` → `openapi({ codeSamples: [...] })`; Blume generates the same 18 languages and accepts Mintlify's keys and aliases (`bash`, `javascript`, `node`, `csharp`, `dotnet`, `c++`, …) as written. `api.examples.autogenerate: false` → `codeSamples: false`. `x-codeSamples` in the spec needs nothing: Blume renders them ahead of the generated samples. +- **Keep the "Introduction" page.** Mintlify commonly has a written intro/auth page in an "Introduction" group beside the "Endpoints" (openapi) group in the same tab. Keep it: a normal content page placed under the `openapi()` adapter's `route` (e.g. `/api-reference/introduction.mdx`) merges into the reference tab's sidebar alongside the generated operations. Delete only the per-endpoint stubs, not the conceptual pages. + +## Assets + +Mintlify serves every top-level dir (e.g. `/images`) at the site root. Blume serves `public/` at the site root. **Move root asset dirs into `public/`** (`mv images public/images`) — every `/images/...` reference still resolves, unchanged. Move loose root files (`logo.png`, `favicon.png`) under `public/` too. + +## i18n + +`navigation.languages` (≥2) → `i18n: { defaultLocale, locales: [{ code, label }] }`. The `default: true` language → `defaultLocale`. Translated content already lives in ISO-code directories, which match Blume's `dir` parser — no file moves. Remove any language selector; language switching is handled by i18n. + +Per-language `banner`, `navbar`, and `footer` (on `navigation.languages[]`) merge into the one site-wide config, with each label as a map of language code to that language's text: `banner: { content: { en: "…", fr: "…" } }` (and `link.text`), `navigation.actions`/`cta` labels, and `footer` link labels. Hrefs stay single — Blume moves an internal link into the reader's language itself. A language without an entry shows the default language's text. Report what doesn't merge: a banner or link set for only some languages, or one whose href differs per language. + +## Dropped — report these + +- **A group's `boost`** (on a `navigation` group, inherited by its pages) → no inherited boost; set `search.boost` on the pages that need it. +- **Authentication** (password or SSO, set in the Mintlify dashboard) → Blume has none of its own; point the user at host-level protection (Vercel Deployment Protection, Netlify password protection, Cloudflare Access), per the deployment docs' **Private docs** section. It covers the whole site, so a mix of public and private pages needs two sites. +- **``** changelog components, `iconType`, `background.decoration`, `search.prompt`. diff --git a/.github/skills/blume-migrate/references/monorepo.md b/.github/skills/blume-migrate/references/monorepo.md new file mode 100644 index 0000000..e4cfa2a --- /dev/null +++ b/.github/skills/blume-migrate/references/monorepo.md @@ -0,0 +1,225 @@ +# Migrating into a real repo (monorepos, pnpm, Vercel) + +The framework references (`mintlify.md`, etc.) cover translating _content and config_. This file covers the **host repo** the docs live in — the concerns that surface when the target isn't a bare docs folder but a pnpm/Turbo workspace deployed on Vercel. All six were real failures in a production migration; none are Blume bugs, they're integration steps. + +**Golden rule for this whole file: detect, then edit surgically, then say what you changed and why.** Every edit here touches a file the repo owns (`pnpm-workspace.yaml`, `vercel.json`, `package.json`, the lockfile). Never guess a path depth or a workspace name — read it out of the repo first. Where a step can't be fully automated (the Astro patch, the Vercel Root Directory setting), leave a copy-pasteable manual instruction rather than a half-applied change. + +--- + +## 1. Non-standard content layout → scope `content.root` + `include` + +`content.root` defaults to `"docs"`, and `blume` runs from the directory that holds `blume.config.ts` (in a monorepo, that's the docs _package_, e.g. `apps/docs/`). Many repos **don't** have a `docs/` subfolder — the content sits directly under the app dir in topic folders (`apps/docs/api/`, `apps/docs/getting-started/`). With the default root, Blume looks for `apps/docs/docs/` and finds nothing. + +**Detect by finding where `.md`/`.mdx` actually live** — never assume `docs/`. From the docs package dir: + +```bash +# top two path segments of every content file, deduped — your content folders +find . -path ./node_modules -prune -o \( -name '*.md' -o -name '*.mdx' \) -print \ + | sed 's|^\./||' | cut -d/ -f1 | sort -u +``` + +If that lists a real `docs` folder, keep the default. If it lists content folders directly (`api`, `getting-started`, `guides`), the content root is the package dir itself. + +**Set `content.root` to the package dir and scope with explicit `include` globs — do _not_ use `content.root: "."` alone.** A bare `.` root scans the whole package: `src/`, `public/`, `README.md`, config files, and (in a monorepo) anything a loose glob reaches. That's slow and pulls non-content Markdown into the site. Instead pin `root` and list the real content folders in `content.include`: + +```ts blume.config.ts +import { defineConfig } from "blume"; + +export default defineConfig({ + content: { + root: ".", // content sits directly under this package (apps/docs/), no docs/ subfolder + // include/exclude globs are relative to `content.root`. List the actual + // content folders so the scan never wanders into src/, public/, etc. + include: [ + "api/**/*.{md,mdx}", + "getting-started/**/*.{md,mdx}", + "guides/**/*.{md,mdx}", + ], + exclude: ["**/node_modules/**", "**/_*", "**/.*"], + }, +}); +``` + +Schema field names, exactly: **`content.root`** (string, relative to the project/cwd), **`content.include`** (array of globs, relative to `content.root`, default `["**/*.{md,mdx}"]`), **`content.exclude`** (array of globs, relative to `content.root`, default `["**/_*", "**/.*"]`). Singular `include`/`exclude`, both arrays. + +Report to the user: the detected content root, the folders you scoped `include` to, and anything Markdown you deliberately left out (a top-level `README.md`, a `CHANGELOG.md`) so they can confirm it isn't content. + +--- + +## 2. pnpm `minimumReleaseAge` blocks installing fresh Blume + +pnpm's supply-chain guard (`minimumReleaseAge`, often set to `1440` = 24h) refuses to install any package version published more recently than the window. Right after Blume publishes, that's **every** Blume release — so `pnpm add blume` / the workspace install fails or silently pins an older version. + +**Do not disable the policy globally** — that removes the guard for the whole dependency tree. Add **only `blume`** to the exclude list. + +**Detect** in `pnpm-workspace.yaml` (pnpm 10+, the primary location) and, for older setups, `.npmrc`: + +```bash +grep -rn "minimumReleaseAge\|minimum-release-age" pnpm-workspace.yaml .npmrc 2>/dev/null +``` + +**Fix — `pnpm-workspace.yaml`** (surgical add; create the key if the policy is set but no exclude exists): + +```yaml +minimumReleaseAge: 1440 +minimumReleaseAgeExclude: + - blume +``` + +**Fix — `.npmrc`** form (if the policy lives there instead): + +```ini +minimum-release-age=1440 +minimum-release-age-exclude[]=blume +``` + +Report: "Added `blume` to `minimumReleaseAgeExclude` so the just-published version installs; the release-age guard still applies to everything else." + +--- + +## 3. Frozen lockfile — regenerate and commit `pnpm-lock.yaml` in the same change + +CI and Vercel install with `--frozen-lockfile` (pnpm's default in CI): if `package.json` and `pnpm-lock.yaml` disagree by even one dependency, the install **fails immediately** — before any build step runs. A migration always edits dependencies (add `blume`, drop the old framework), so the lockfile is guaranteed stale. + +**After every dependency edit, regenerate the lockfile and stage it with the manifest:** + +```bash +pnpm install # NOT --frozen-lockfile — this rewrites pnpm-lock.yaml +git add package.json apps/docs/package.json pnpm-lock.yaml +``` + +Rules: + +- Run `pnpm install` (plain) from the **workspace root**, not the docs package, so the single root lockfile updates. +- The lockfile change belongs in the **same commit** as the `package.json` change. A commit that edits deps without the matching lockfile is a broken build for anyone who pulls it. +- Verify locally the way CI will: `pnpm install --frozen-lockfile` should succeed with no diff. If it errors "lockfile not up to date," you forgot the plain install. + +--- + +## 4. Vercel monorepo recipe (root-aware install + build) + +A plain `blume build` works locally, but Vercel in a workspace needs three things aligned: the install must run at the **workspace root** (so pnpm resolves the whole graph under a frozen lockfile), the build must run in the **docs package**, and Vercel must be pointed at the built `dist/`. `blume build` emits a static site to `dist/` **relative to where it runs** — so building in `apps/docs/` produces `apps/docs/dist/`. + +This is a **copyable template**, not prose. Three pieces: + +**a) Docs package `apps/docs/package.json`** — the standard Blume scripts: + +```json +{ + "scripts": { + "dev": "blume dev", + "build": "blume build", + "preview": "blume preview" + }, + "dependencies": { + "blume": "^2" + } +} +``` + +**b) `apps/docs/vercel.json`** — root-aware install, local build, `dist` output: + +```json +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "framework": null, + "installCommand": "cd ../.. && pnpm install --frozen-lockfile", + "buildCommand": "pnpm run build", + "outputDirectory": "dist" +} +``` + +**c) The one setting `vercel.json` can't hold — set it in the Vercel project (dashboard → Settings → General, or `vercel` CLI):** + +- **Root Directory** = `apps/docs`. This makes install/build/output paths resolve from the docs package, which is what the `vercel.json` above assumes. +- **Node version** = 22 or newer (Blume requires it). Or pin it in the docs package: `"engines": { "node": ">=22" }`. + +How the pieces fit, with Root Directory = `apps/docs`: + +- `installCommand` does `cd ../..` to reach the **workspace root** and runs a frozen install of the whole graph. **Adjust `../..` to the app's actual depth** — an app at `packages/web/docs/` needs `cd ../../..`. Read the path; don't assume two levels. +- `buildCommand` runs in `apps/docs/` and invokes `blume build` (via the package's `build` script) → emits `apps/docs/dist/`. +- `outputDirectory: "dist"` is relative to the Root Directory (`apps/docs`), so it points at `apps/docs/dist/`. +- `framework: null` stops Vercel from auto-detecting Astro and overriding your build/output with its Astro preset (which expects a different output path). Blume's static output is plain files — Vercel just serves the folder. + +If the repo uses **Turborepo**, you can instead build through the root pipeline — `"buildCommand": "cd ../.. && pnpm turbo build --filter=docs"` — for remote-cache reuse. Keep `outputDirectory: "dist"` and Root Directory `apps/docs`. + +Report every piece you wrote and the two dashboard settings the user must set by hand (Root Directory, Node version) — those can't be committed. + +**Redirect caveat on this deploy path:** a static build emits `vercel.json` redirect rules into `dist/`, but Vercel's **git-integration** builds read `vercel.json` only from the project's Root Directory — the copy inside `dist/` is honored only when the dist folder is deployed directly via the Vercel CLI. On the §4 setup, `blume.config.ts` redirects still work (Blume also emits per-route meta-refresh pages), but they're soft redirects, not real 3xx. If real 3xx responses matter (SEO for a large moved site), copy the generated redirect rules from `dist/vercel.json` after a build into the committed `apps/docs/vercel.json`'s `redirects` array, and note they must be re-synced when `redirects` change. (Most migrations are fine with the soft fallback — say which you chose.) + +--- + +## 5. Astro/Vite version mismatch → pnpm patch (manual) + +Blume pins **`astro ^7`**. If the workspace forces a specific **Vite** version — a root `pnpm.overrides` / `resolutions` entry, or a `vite` in the workspace catalog — that pinned Vite can diverge from the version Astro 7 expects, and Astro's internal build behavior mismatches. The symptom is a **build-time crash inside Astro/Vite** (a Rollup/Vite internal error, a missing-export or hook-signature error deep in `astro`/`vite` during `blume build`) that doesn't reproduce in a clean, override-free project. + +**Detect the risk factor** before it bites: + +```bash +grep -rn "\"vite\"\|vite@\| vite:" pnpm-workspace.yaml package.json 2>/dev/null | grep -i "override\|resolution\|catalog\|vite" +``` + +Blume is adding early version validation separately, so a future release will flag this at startup. Until then, **recognize the symptom and apply a pinned patch** — pnpm's `patch` workflow writes a committed diff that pnpm reapplies on every install (survives CI and frozen installs): + +```bash +# 1. Open the offending version in an editable temp dir (use the exact version +# pnpm resolved — check `pnpm why astro`): +pnpm patch astro@7.0.6 + +# 2. Edit files in the printed temp path to reconcile the Astro/Vite interface +# (the exact edit depends on the mismatch; the crash's stack trace names the +# file and call site). Then commit the patch: +pnpm patch-commit '' +``` + +`patch-commit` writes `patches/astro@7.0.6.patch` and registers it under `patchedDependencies` in `pnpm-workspace.yaml` (pnpm 10+) or root `package.json` (`pnpm.patchedDependencies` on pnpm 9): + +```yaml +# pnpm-workspace.yaml +patchedDependencies: + astro@7.0.6: patches/astro@7.0.6.patch +``` + +Commit **both** `patches/astro@7.0.6.patch` and the `patchedDependencies` entry, then re-run `pnpm install` and `blume build`. + +This is a **manual step — do not fabricate the patch contents.** Leave the user this exact recipe plus the crash's stack trace, and tell them: the cleaner long-term fix is to relax the workspace's Vite pin so Astro 7 resolves its own compatible Vite, and drop the patch once Blume ships version validation. Don't fail silently — if a build crashes inside Astro/Vite and a Vite override exists, name this as the likely cause. + +--- + +## 6. Ultracite / oxfmt formatting → oxfmt patch (ship the bundled patch) + +If the repo uses (or the user wants to adopt) **[Ultracite](https://www.ultracite.ai)** for formatting — an `ultracite check` / `ultracite fix` script, an `ultracite` dev dep, or oxlint/oxfmt in the toolchain — it will format the migrated `.md`/`.mdx` **and break Blume's `:::` directives.** Ultracite's formatter is **oxfmt**, and under `proseWrap` oxfmt joins the opening/closing `:::` fence line into the surrounding prose, which invalidates the directive (`:::note` … `:::` callouts, titled fences like `:::warning[Heads up]`, tabs, steps — the exact syntax you convert callouts _into_ in step 5). Blume's own repo hits this and pins a patched oxfmt; a migrated repo needs the same patch or every directive silently degrades to literal text on the next `ultracite fix`. + +The fix is a committed **pnpm patch** (`patches/oxfmt@0.67.0.patch`), shipped with this skill at `assets/oxfmt@0.67.0.patch` — the same diff Blume's own repo applies, covering titled fences as well as bare ones. Unlike the Astro/Vite patch, this one is a **known, deterministic diff** — copy it in, don't regenerate it: + +```bash +# 1. Copy the shipped patch into the target repo's patches/ dir (keep the exact filename; +# = this skill's directory, the one containing SKILL.md): +mkdir -p patches +cp "/assets/oxfmt@0.67.0.patch" patches/oxfmt@0.67.0.patch +``` + +Then register it under `patchedDependencies` — `pnpm-workspace.yaml` on pnpm 10+, or root `package.json` (`pnpm.patchedDependencies`) on pnpm 9: + +```yaml +# pnpm-workspace.yaml +patchedDependencies: + oxfmt@0.67.0: patches/oxfmt@0.67.0.patch +``` + +Commit **both** the patch file and the `patchedDependencies` entry, then re-run `pnpm install`. + +- **The patch is pinned to `oxfmt@0.67.0`** (the version Blume's own repo pins). pnpm requires an exact version match, and the diff targets a file whose name is hashed per oxfmt release (`dist/markdown-*.js`), so it won't apply to any other version. If `pnpm why oxfmt` reports a different one, pin `oxfmt` to `0.67.0` as a direct dev dependency (Ultracite accepts any `oxfmt` ≥ 0.40 as a peer). If the repo can't take that pin, tell the user and fall back to keeping directive-heavy files out of the formatter's globs. +- **Not on pnpm?** The patch mechanism is pnpm-specific. For npm/yarn, either pin oxfmt and apply the diff with `patch-package`, or exclude `.md`/`.mdx` from Ultracite formatting so it never touches the directives — report whichever you chose. + +--- + +## Checklist for a workspace migration + +- [ ] Located real content folders (not assumed `docs/`); set `content.root` + scoped `content.include`. +- [ ] `minimumReleaseAge` present? Added `blume` to `minimumReleaseAgeExclude` only. +- [ ] Ran plain `pnpm install`; committed `pnpm-lock.yaml` with the `package.json` change; verified `pnpm install --frozen-lockfile` is clean. +- [ ] Wrote `apps/docs/vercel.json` + package scripts; told the user to set Root Directory + Node 22 in the Vercel project. +- [ ] Checked for a workspace Vite override; if the build crashes inside Astro/Vite, gave the pnpm-patch recipe. +- [ ] Uses Ultracite/oxfmt? Shipped `patches/oxfmt@0.67.0.patch` + registered it under `patchedDependencies` so formatting doesn't mangle `:::` directives. +- [ ] Reported every repo-specific edit and every manual step left to the user. diff --git a/.github/skills/blume-migrate/references/nextra.md b/.github/skills/blume-migrate/references/nextra.md new file mode 100644 index 0000000..af513e3 --- /dev/null +++ b/.github/skills/blume-migrate/references/nextra.md @@ -0,0 +1,79 @@ +# Nextra → Blume + +Nextra (on Next.js) declares navigation and per-page labels in `_meta` files — and crucially, **a folder's title and its pages' sidebar labels live in the _parent_ `_meta`**. Reconciling that cross-file inheritance is the main task. Nextra 4 was a near-rewrite, so **fingerprint the generation first** — it decides where config lives, where content lives, and what the components are called. + +## Detect & fingerprint the generation + +- **`_meta.{js,mjs,cjs,ts,jsx,tsx,json}`** files — the strongest fingerprint (v4 also has a single-file `_meta.global.*` variant). +- **v2/v3 (Pages Router):** content in `pages/`, `_meta.json` (v2) or `_meta.{js,ts}` (v3), a `theme.config.{js,jsx,ts,tsx}`, components from `nextra-theme-docs` (v2) or `nextra/components` (v3). +- **v4 (App Router):** **no `theme.config`** — config lives as component props in `app/layout.{jsx,tsx}` (``, ``, ``, `