@skill-graph/cli 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +247 -0
- package/LICENSE +200 -0
- package/NOTICE +62 -0
- package/README.md +398 -0
- package/SKILL_GRAPH.md +443 -0
- package/bin/skill-graph.js +374 -0
- package/docs/ADOPTION.md +117 -0
- package/docs/CONFORMANCE.md +66 -0
- package/docs/PRIMER.md +384 -0
- package/docs/QUICKSTART-30MIN.md +333 -0
- package/docs/ROUTING-METRICS.md +120 -0
- package/docs/SKILL-MD-FORMAT-COMPATIBILITY.md +127 -0
- package/docs/SKILL_AUDIT_CHECKLIST.md +199 -0
- package/docs/SKILL_AUDIT_LOOP.md +195 -0
- package/docs/SKILL_METADATA_PROTOCOL.md +609 -0
- package/docs/_archived/marketplace-publication-priority-2026-05-18.md +239 -0
- package/docs/adr/0001-predicate-set.md +69 -0
- package/docs/adr/0002-json-ld-context.md +82 -0
- package/docs/adr/0003-ontoclean-rigidity-tags.md +65 -0
- package/docs/adr/0004-persistent-identifiers.md +74 -0
- package/docs/adr/0005-freshness-consolidation.md +70 -0
- package/docs/adr/0006-revise-predicate-rename.md +105 -0
- package/docs/adr/0007-audit-loop-cadence.md +99 -0
- package/docs/adr/0008-skill-surface-split-and-curation-policy.md +93 -0
- package/docs/category-consumers.md +168 -0
- package/docs/concept-map.md +194 -0
- package/docs/diagrams/drift-states.mmd +21 -0
- package/docs/diagrams/manifest-pipeline.mmd +25 -0
- package/docs/diagrams/routing-harness.mmd +41 -0
- package/docs/diagrams/starter-graph.mmd +53 -0
- package/docs/field-decision-guide.md +315 -0
- package/docs/field-rationale.md +211 -0
- package/docs/field-reference.generated.md +624 -0
- package/docs/field-reference.md +1426 -0
- package/docs/glossary.md +190 -0
- package/docs/head-noun-glossary.md +63 -0
- package/docs/images/audit-phases.png +0 -0
- package/docs/images/drift-states.png +0 -0
- package/docs/images/graded-mode.png +0 -0
- package/docs/images/manifest-pipeline.png +0 -0
- package/docs/images/routing-harness.png +0 -0
- package/docs/images/skill-anatomy.png +0 -0
- package/docs/images/starter-graph.png +0 -0
- package/docs/images/system-model.png +0 -0
- package/docs/integrations/github-actions.md +155 -0
- package/docs/manifest-field-mapping.md +443 -0
- package/docs/marketplace-publication-queue.generated.md +240 -0
- package/docs/marketplace-release-agent-prompt.md +82 -0
- package/docs/marketplace-skill-candidate-list.md +272 -0
- package/docs/marketplace-syndication.md +222 -0
- package/docs/migration-sample-review.md +155 -0
- package/docs/migrations/v4-to-v5.md +168 -0
- package/docs/migrations/v5-to-v6.md +221 -0
- package/docs/name-exceptions.yaml +37 -0
- package/docs/plans/marketplace-p1-public-migration-plan.md +41 -0
- package/docs/plans/multi-root-workspace.md +148 -0
- package/docs/plans/scripts-roadmap.md +107 -0
- package/docs/plans/v4-schema-bump.md +160 -0
- package/docs/plans/wave-2-extraction.md +122 -0
- package/docs/positioning-vs-marketplaces.md +175 -0
- package/docs/proposals/skill-audit-loop-positioning.md +160 -0
- package/docs/quality-doctrine.md +138 -0
- package/docs/recommended-skills.md +150 -0
- package/docs/research/skill-comprehension-eval-research.md +1830 -0
- package/docs/research/skill-retrieval-evidence.md +66 -0
- package/docs/skill-metadata-protocol.md +471 -0
- package/docs/skills-sh-maintainer-cleanup-request.md +80 -0
- package/examples/audits/a11y/findings.md +52 -0
- package/examples/audits/a11y/scorecard.md +21 -0
- package/examples/audits/a11y/verdict.md +44 -0
- package/examples/audits/debugging/findings.md +59 -0
- package/examples/audits/debugging/scorecard.md +22 -0
- package/examples/audits/debugging/verdict.md +33 -0
- package/examples/audits/documentation/findings.md +59 -0
- package/examples/audits/documentation/scorecard.md +22 -0
- package/examples/audits/documentation/verdict.md +33 -0
- package/examples/evals/a11y.json +140 -0
- package/examples/evals/api-design.json +52 -0
- package/examples/evals/code-review.json +52 -0
- package/examples/evals/data-modeling.json +52 -0
- package/examples/evals/database-migration.json +52 -0
- package/examples/evals/debugging.json +118 -0
- package/examples/evals/dependency-architecture.json +52 -0
- package/examples/evals/design-system-architecture.json +52 -0
- package/examples/evals/error-tracking.json +52 -0
- package/examples/evals/event-contract-design.json +52 -0
- package/examples/evals/form-ux-architecture.json +52 -0
- package/examples/evals/framework-fit-analysis.json +52 -0
- package/examples/evals/graph-audit.json +139 -0
- package/examples/evals/information-architecture.json +52 -0
- package/examples/evals/interaction-feedback.json +52 -0
- package/examples/evals/interaction-patterns.json +52 -0
- package/examples/evals/layout-composition.json +52 -0
- package/examples/evals/lint-overlay.json +117 -0
- package/examples/evals/microcopy.json +52 -0
- package/examples/evals/observability-modeling.json +52 -0
- package/examples/evals/pattern-recognition.json +96 -0
- package/examples/evals/performance-engineering.json +52 -0
- package/examples/evals/refactor.json +128 -0
- package/examples/evals/semiotics.json +52 -0
- package/examples/evals/skill-infrastructure.json +96 -0
- package/examples/evals/skill-router.json +140 -0
- package/examples/evals/skill-router.routing.json +113 -0
- package/examples/evals/system-interface-contracts.json +52 -0
- package/examples/evals/task-analysis.json +52 -0
- package/examples/evals/testing-strategy.json +118 -0
- package/examples/evals/type-safety.json +249 -0
- package/examples/evals/visual-design-foundations.json +52 -0
- package/examples/evals/webhook-integration.json +52 -0
- package/examples/exports/a11y.skill-md.md +80 -0
- package/examples/exports/debugging.skill-md.md +80 -0
- package/examples/exports/refactor.skill-md.md +78 -0
- package/examples/exports/testing-strategy.skill-md.md +81 -0
- package/examples/projects/markdown-static-site/README.md +115 -0
- package/examples/projects/markdown-static-site/skills/content-source-router/SKILL.md +131 -0
- package/examples/projects/markdown-static-site/skills/image-optimization-pipeline-config/SKILL.md +132 -0
- package/examples/projects/markdown-static-site/skills/link-rot-detection/SKILL.md +103 -0
- package/examples/projects/markdown-static-site/skills/markdown-post-frontmatter-validation/SKILL.md +133 -0
- package/examples/projects/markdown-static-site/skills/migrate-posts-to-v2-frontmatter/SKILL.md +140 -0
- package/examples/projects/saas-stripe-postgres/README.md +208 -0
- package/examples/projects/saas-stripe-postgres/db/migrations/0004_canonicalize_orders.sql +37 -0
- package/examples/projects/saas-stripe-postgres/db/schema.sql +112 -0
- package/examples/projects/saas-stripe-postgres/skills/migrate-orders-to-canonical-schema/SKILL.md +149 -0
- package/examples/projects/saas-stripe-postgres/skills/nextjs-server-action-validation/SKILL.md +154 -0
- package/examples/projects/saas-stripe-postgres/skills/payment-provider-router/SKILL.md +153 -0
- package/examples/projects/saas-stripe-postgres/skills/postgres-rls-pattern/SKILL.md +163 -0
- package/examples/projects/saas-stripe-postgres/skills/stripe-webhook-signature-verification/SKILL.md +137 -0
- package/examples/protocol/skill-metadata-template.md +301 -0
- package/examples/protocol/skills.manifest.sample.json +13245 -0
- package/examples/skill-metadata-template.md +317 -0
- package/examples/skills.manifest.sample.json +13519 -0
- package/examples/tests/v3-1-skos-fixture/SKILL.md +93 -0
- package/marketplace/README.md +17 -0
- package/marketplace/skills/a11y/SKILL.md +66 -0
- package/marketplace/skills/acid-fundamentals/SKILL.md +106 -0
- package/marketplace/skills/agent-engineering/SKILL.md +386 -0
- package/marketplace/skills/agent-eval-design/SKILL.md +55 -0
- package/marketplace/skills/ai-native-development/SKILL.md +294 -0
- package/marketplace/skills/api-design/SKILL.md +60 -0
- package/marketplace/skills/architecture-decision-records/SKILL.md +55 -0
- package/marketplace/skills/background-jobs/SKILL.md +265 -0
- package/marketplace/skills/bounded-context-mapping/SKILL.md +55 -0
- package/marketplace/skills/cap-theorem-tradeoffs/SKILL.md +127 -0
- package/marketplace/skills/client-server-boundary/SKILL.md +187 -0
- package/marketplace/skills/code-review/SKILL.md +120 -0
- package/marketplace/skills/color-system-design/SKILL.md +43 -0
- package/marketplace/skills/component-architecture/SKILL.md +126 -0
- package/marketplace/skills/compression/SKILL.md +112 -0
- package/marketplace/skills/conceptual-modeling/SKILL.md +181 -0
- package/marketplace/skills/connection-pooling/SKILL.md +105 -0
- package/marketplace/skills/constraint-awareness/SKILL.md +287 -0
- package/marketplace/skills/content-monitor/SKILL.md +209 -0
- package/marketplace/skills/context-engineering/SKILL.md +320 -0
- package/marketplace/skills/context-graph/SKILL.md +174 -0
- package/marketplace/skills/context-management/SKILL.md +174 -0
- package/marketplace/skills/context-window/SKILL.md +239 -0
- package/marketplace/skills/contract-testing/SKILL.md +120 -0
- package/marketplace/skills/cron-scheduling/SKILL.md +223 -0
- package/marketplace/skills/dark-mode-implementation/SKILL.md +47 -0
- package/marketplace/skills/data-modeling/SKILL.md +59 -0
- package/marketplace/skills/data-modeling-fundamentals/SKILL.md +117 -0
- package/marketplace/skills/database-migration/SKILL.md +429 -0
- package/marketplace/skills/debugging/SKILL.md +67 -0
- package/marketplace/skills/dependency-architecture/SKILL.md +58 -0
- package/marketplace/skills/design-module-composition/SKILL.md +43 -0
- package/marketplace/skills/design-system-architecture/SKILL.md +61 -0
- package/marketplace/skills/design-thinking/SKILL.md +44 -0
- package/marketplace/skills/diagnosis/SKILL.md +296 -0
- package/marketplace/skills/diff-analysis/SKILL.md +188 -0
- package/marketplace/skills/e2e-test-design/SKILL.md +113 -0
- package/marketplace/skills/entity-relationship-modeling/SKILL.md +218 -0
- package/marketplace/skills/epistemic-grounding/SKILL.md +112 -0
- package/marketplace/skills/error-boundary/SKILL.md +235 -0
- package/marketplace/skills/error-tracking/SKILL.md +261 -0
- package/marketplace/skills/eval-driven-development/SKILL.md +147 -0
- package/marketplace/skills/evaluation/SKILL.md +113 -0
- package/marketplace/skills/event-contract-design/SKILL.md +60 -0
- package/marketplace/skills/event-storming/SKILL.md +56 -0
- package/marketplace/skills/form-ux-architecture/SKILL.md +60 -0
- package/marketplace/skills/framework-fit-analysis/SKILL.md +59 -0
- package/marketplace/skills/frontend-architecture/SKILL.md +43 -0
- package/marketplace/skills/generative-ui/SKILL.md +118 -0
- package/marketplace/skills/graph-audit/SKILL.md +81 -0
- package/marketplace/skills/guardrails/SKILL.md +118 -0
- package/marketplace/skills/hooks-patterns/SKILL.md +185 -0
- package/marketplace/skills/http-semantics/SKILL.md +136 -0
- package/marketplace/skills/ideation/SKILL.md +41 -0
- package/marketplace/skills/indexing-strategy/SKILL.md +108 -0
- package/marketplace/skills/information-architecture/SKILL.md +59 -0
- package/marketplace/skills/integration-test-design/SKILL.md +111 -0
- package/marketplace/skills/intent-recognition/SKILL.md +136 -0
- package/marketplace/skills/interaction-feedback/SKILL.md +59 -0
- package/marketplace/skills/interaction-patterns/SKILL.md +59 -0
- package/marketplace/skills/journey-mapping/SKILL.md +41 -0
- package/marketplace/skills/keywords/SKILL.md +213 -0
- package/marketplace/skills/knowledge-modeling/SKILL.md +232 -0
- package/marketplace/skills/layout-composition/SKILL.md +59 -0
- package/marketplace/skills/linguistics/SKILL.md +429 -0
- package/marketplace/skills/lint-overlay/SKILL.md +76 -0
- package/marketplace/skills/mental-models/SKILL.md +126 -0
- package/marketplace/skills/merge-queue/SKILL.md +94 -0
- package/marketplace/skills/methodology/SKILL.md +317 -0
- package/marketplace/skills/microcopy/SKILL.md +232 -0
- package/marketplace/skills/middleware-patterns/SKILL.md +363 -0
- package/marketplace/skills/mobile-responsive-ux/SKILL.md +287 -0
- package/marketplace/skills/mutation-testing/SKILL.md +112 -0
- package/marketplace/skills/naming-conventions/SKILL.md +112 -0
- package/marketplace/skills/observability-modeling/SKILL.md +59 -0
- package/marketplace/skills/ontology-modeling/SKILL.md +67 -0
- package/marketplace/skills/owasp-security/SKILL.md +153 -0
- package/marketplace/skills/pattern-recognition/SKILL.md +472 -0
- package/marketplace/skills/performance-budgets/SKILL.md +185 -0
- package/marketplace/skills/performance-engineering/SKILL.md +58 -0
- package/marketplace/skills/performance-testing/SKILL.md +125 -0
- package/marketplace/skills/printify/SKILL.md +42 -0
- package/marketplace/skills/prioritization/SKILL.md +118 -0
- package/marketplace/skills/problem-framing/SKILL.md +41 -0
- package/marketplace/skills/problem-locating-solving/SKILL.md +203 -0
- package/marketplace/skills/project-knowledge-extraction/SKILL.md +54 -0
- package/marketplace/skills/prompt-craft/SKILL.md +134 -0
- package/marketplace/skills/prompt-injection-defense/SKILL.md +132 -0
- package/marketplace/skills/property-based-testing/SKILL.md +100 -0
- package/marketplace/skills/prototyping/SKILL.md +43 -0
- package/marketplace/skills/query-optimization/SKILL.md +144 -0
- package/marketplace/skills/real-time-updates/SKILL.md +324 -0
- package/marketplace/skills/ref-patterns/SKILL.md +284 -0
- package/marketplace/skills/refactor/SKILL.md +65 -0
- package/marketplace/skills/rendering-models/SKILL.md +142 -0
- package/marketplace/skills/replication-patterns/SKILL.md +110 -0
- package/marketplace/skills/research-synthesis/SKILL.md +41 -0
- package/marketplace/skills/route-handler-design/SKILL.md +347 -0
- package/marketplace/skills/schema-evolution/SKILL.md +140 -0
- package/marketplace/skills/security-fundamentals/SKILL.md +139 -0
- package/marketplace/skills/semantic-center/SKILL.md +194 -0
- package/marketplace/skills/semantic-relations/SKILL.md +250 -0
- package/marketplace/skills/semantics/SKILL.md +366 -0
- package/marketplace/skills/semiotics/SKILL.md +230 -0
- package/marketplace/skills/seo-strategy/SKILL.md +260 -0
- package/marketplace/skills/server-actions-design/SKILL.md +243 -0
- package/marketplace/skills/server-components-design/SKILL.md +190 -0
- package/marketplace/skills/sharding-strategy/SKILL.md +123 -0
- package/marketplace/skills/shopify/SKILL.md +42 -0
- package/marketplace/skills/skill-infrastructure/SKILL.md +320 -0
- package/marketplace/skills/skill-router/SKILL.md +71 -0
- package/marketplace/skills/skill-scaffold/SKILL.md +105 -0
- package/marketplace/skills/snapshot-testing/SKILL.md +120 -0
- package/marketplace/skills/spec-driven-development/SKILL.md +148 -0
- package/marketplace/skills/state-machine-modeling/SKILL.md +56 -0
- package/marketplace/skills/state-management/SKILL.md +134 -0
- package/marketplace/skills/streaming-architecture/SKILL.md +194 -0
- package/marketplace/skills/summarization/SKILL.md +156 -0
- package/marketplace/skills/suspense-patterns/SKILL.md +265 -0
- package/marketplace/skills/system-interface-contracts/SKILL.md +59 -0
- package/marketplace/skills/task-analysis/SKILL.md +201 -0
- package/marketplace/skills/taxonomy-design/SKILL.md +66 -0
- package/marketplace/skills/test-coverage-strategy/SKILL.md +108 -0
- package/marketplace/skills/test-doubles-design/SKILL.md +98 -0
- package/marketplace/skills/test-driven-development/SKILL.md +96 -0
- package/marketplace/skills/testing-strategy/SKILL.md +67 -0
- package/marketplace/skills/theme-system-design/SKILL.md +43 -0
- package/marketplace/skills/tool-call-flow/SKILL.md +229 -0
- package/marketplace/skills/tool-call-strategy/SKILL.md +292 -0
- package/marketplace/skills/transaction-isolation/SKILL.md +98 -0
- package/marketplace/skills/type-safety/SKILL.md +177 -0
- package/marketplace/skills/typography-system/SKILL.md +43 -0
- package/marketplace/skills/usability-testing/SKILL.md +43 -0
- package/marketplace/skills/user-research/SKILL.md +43 -0
- package/marketplace/skills/vercel-composition-patterns/SKILL.md +157 -0
- package/marketplace/skills/version-control/SKILL.md +233 -0
- package/marketplace/skills/visual-design-foundations/SKILL.md +59 -0
- package/marketplace/skills/visual-hierarchy/SKILL.md +43 -0
- package/marketplace/skills/webhook-integration/SKILL.md +331 -0
- package/marketplace/skills/writing-humanizer/SKILL.md +380 -0
- package/package.json +67 -0
- package/schemas/manifest.schema.json +811 -0
- package/schemas/manifest.v2.schema.json +164 -0
- package/schemas/manifest.v3.schema.json +758 -0
- package/schemas/manifest.v4.schema.json +755 -0
- package/schemas/manifest.v5.schema.json +755 -0
- package/schemas/manifest.v6.schema.json +811 -0
- package/schemas/skill.context.jsonld +279 -0
- package/schemas/skill.schema.json +919 -0
- package/schemas/skill.v2.schema.json +201 -0
- package/schemas/skill.v3.schema.json +827 -0
- package/schemas/skill.v4.schema.json +822 -0
- package/schemas/skill.v5.schema.json +830 -0
- package/schemas/skill.v6.schema.json +946 -0
- package/schemas/vocabulary/keywords.json +180 -0
- package/schemas/vocabulary/workspace_tags.json +23 -0
- package/scripts/__tests__/migrate-skill-v2-to-v3.test.js +161 -0
- package/scripts/__tests__/migrate-skill-v3-to-v4.test.js +158 -0
- package/scripts/__tests__/test-export-parser-drift.js +149 -0
- package/scripts/__tests__/test-marketplace-export.js +114 -0
- package/scripts/__tests__/test-router-paths.js +82 -0
- package/scripts/__tests__/test-stability-promotion.js +244 -0
- package/scripts/__tests__/test-v3-1-alias-contract.js +109 -0
- package/scripts/__tests__/test-v3-1-skos-runtime.js +116 -0
- package/scripts/backfill-schema-version.js +198 -0
- package/scripts/build-field-reference.js +160 -0
- package/scripts/build-retrieval-baseline.js +511 -0
- package/scripts/check-markdown-links.js +211 -0
- package/scripts/check-protocol-consistency.js +979 -0
- package/scripts/export-marketplace-skills.js +610 -0
- package/scripts/export-skill.js +374 -0
- package/scripts/generate-manifest.js +787 -0
- package/scripts/lib/alias-contract.js +83 -0
- package/scripts/lib/audit-prompt-builder.js +771 -0
- package/scripts/lib/mock-grader.js +134 -0
- package/scripts/lib/parse-frontmatter.js +429 -0
- package/scripts/lib/roots.js +119 -0
- package/scripts/lint/check-archetype-sections.js +185 -0
- package/scripts/lint/check-category-enum.js +83 -0
- package/scripts/lint/check-routing-eval.js +146 -0
- package/scripts/lint/check-routing-quality.js +211 -0
- package/scripts/lint/check-stability-promotion.js +220 -0
- package/scripts/lint/format-code-frame.js +206 -0
- package/scripts/marketplace-install.js +125 -0
- package/scripts/migrate-category-to-enum.js +169 -0
- package/scripts/migrate-skill-v2-to-v3.js +424 -0
- package/scripts/migrate-skill-v3-to-v4.js +200 -0
- package/scripts/migrate-skill-v5-to-v6.js +304 -0
- package/scripts/restructure-by-category.js +85 -0
- package/scripts/seed-publication-classification.js +282 -0
- package/scripts/skill-audit.js +893 -0
- package/scripts/skill-graph-drift.js +483 -0
- package/scripts/skill-graph-route.js +766 -0
- package/scripts/skill-graph-routing-eval.js +393 -0
- package/scripts/skill-lint.js +1317 -0
- package/scripts/skill-overlap.js +213 -0
- package/scripts/verify-skill-md-export.js +201 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: seo-strategy
|
|
3
|
+
description: "SEO implementation strategy for building pages that rank -- covering content strategy, programmatic SEO at scale, marketplace-specific SEO, and AI search optimization."
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: "Markdown, Git, agent-skill runtimes"
|
|
6
|
+
allowed-tools: Read Grep Bash
|
|
7
|
+
metadata:
|
|
8
|
+
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"capability\",\"category\":\"quality\",\"domain\":\"quality/display\",\"scope\":\"portable\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-03-28\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-03-28\\\\\\\"}\",\"eval_artifacts\":\"planned\",\"eval_state\":\"unverified\",\"routing_eval\":\"absent\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"seo strategy\\\\\\\",\\\\\\\"programmatic seo\\\\\\\",\\\\\\\"content strategy\\\\\\\",\\\\\\\"comparison page\\\\\\\",\\\\\\\"alternative page\\\\\\\",\\\\\\\"schema markup\\\\\\\",\\\\\\\"structured data\\\\\\\",\\\\\\\"ai seo\\\\\\\",\\\\\\\"marketplace seo\\\\\\\",\\\\\\\"etsy seo\\\\\\\",\\\\\\\"amazon seo\\\\\\\",\\\\\\\"shopify seo\\\\\\\",\\\\\\\"product page seo\\\\\\\",\\\\\\\"e-e-a-t\\\\\\\",\\\\\\\"topical authority\\\\\\\",\\\\\\\"blog cluster\\\\\\\",\\\\\\\"ai overview\\\\\\\"]\",\"triggers\":\"[\\\\\\\"seo-strategy-skill\\\\\\\",\\\\\\\"seo-skill\\\\\\\",\\\\\\\"programmatic-seo-skill\\\\\\\"]\",\"relations\":\"{\\\\\\\"related\\\\\\\":[\\\\\\\"keywords\\\\\\\"]}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"scripted\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"lifecycle\":\"{\\\\\\\"stale_after_days\\\\\\\":90,\\\\\\\"review_cadence\\\\\\\":\\\\\\\"quarterly\\\\\\\"}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/seo-strategy/SKILL.md\"}"
|
|
9
|
+
skill_graph_source_repo: "https://github.com/jacob-balslev/skill-graph"
|
|
10
|
+
skill_graph_protocol: Skill Metadata Protocol v4
|
|
11
|
+
skill_graph_project: Skill Graph
|
|
12
|
+
skill_graph_canonical_skill: skills/seo-strategy/SKILL.md
|
|
13
|
+
---
|
|
14
|
+
# SEO Strategy Skill
|
|
15
|
+
|
|
16
|
+
## Domain Context
|
|
17
|
+
|
|
18
|
+
**What is this skill?** SEO implementation strategy for building pages that rank -- covering content strategy, programmatic SEO at scale, marketplace-specific SEO, and AI search optimization.
|
|
19
|
+
|
|
20
|
+
## Key Files
|
|
21
|
+
|
|
22
|
+
| File | Purpose |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `skills/seo-strategy/references/marketplace-seo-differences.md` | See for detailed algorithm breakdowns. |
|
|
25
|
+
## Philosophy
|
|
26
|
+
|
|
27
|
+
Auditing finds problems; this skill builds solutions. The distinction matters because agents conflate the two and either run a diagnostic when they should be building pages, or build pages without a strategy. SEO strategy is proactive — choosing the right page types, content structures, and schema markup before traffic data exists. The marketplace-specific sections exist because applying Google SEO assumptions to Etsy or Amazon actively hurts rankings: Etsy rewards recency and conversion rate, Amazon rewards sales velocity, and neither cares about backlinks. Without this skill, agents default to generic "add keywords" advice that misses the structural decisions (programmatic templates, hub-and-spoke linking, schema choice) that create ranking power at scale.
|
|
28
|
+
|
|
29
|
+
## Coverage
|
|
30
|
+
|
|
31
|
+
E-commerce SEO (product page optimization, collection page strategy, cross-selling internal links), SaaS SEO (comparison/alternative pages, feature pages, documentation SEO, blog cluster strategy), marketplace SEO algorithm differences (Shopify Google organic, Etsy recency and Category Relevance Score, Amazon A9/COSMO), programmatic SEO template patterns (comparison pages, integration pages, location pages), schema markup implementation (Product, FAQ, HowTo, BreadcrumbList, SoftwareApplication), and AI search optimization (AEO, GEO, LLMO for AI Overviews and chatbot citations).
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
> seo-audit finds problems. This skill builds solutions.
|
|
35
|
+
|
|
36
|
+
## When to Use This Skill
|
|
37
|
+
|
|
38
|
+
Load this skill when:
|
|
39
|
+
- Building new pages optimized for organic search
|
|
40
|
+
- Planning content strategy for organic growth (blog clusters, comparison pages)
|
|
41
|
+
- Implementing programmatic SEO at scale (100+ templated pages)
|
|
42
|
+
- Optimizing product listings for marketplace search algorithms
|
|
43
|
+
- Adding schema markup (JSON-LD structured data)
|
|
44
|
+
- Adapting content for AI search (AI Overviews, chatbot citations)
|
|
45
|
+
|
|
46
|
+
Do NOT use for:
|
|
47
|
+
- Diagnosing existing SEO problems (use **seo-audit**)
|
|
48
|
+
- Keyword research and clustering (use **keywords**)
|
|
49
|
+
- Page hierarchy and navigation design (use **site-architecture**)
|
|
50
|
+
- Conversion rate optimization (use **page-cro**)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 1. Content Strategy by Site Type
|
|
55
|
+
|
|
56
|
+
### Decision Tree
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
What type of site?
|
|
60
|
+
├── E-commerce (Shopify/Etsy/Amazon)
|
|
61
|
+
│ ├── Collection pages → target generic keywords (higher volume)
|
|
62
|
+
│ ├── Product pages → target specific long-tail keywords
|
|
63
|
+
│ └── Blog → build topical authority, link to collections
|
|
64
|
+
├── SaaS
|
|
65
|
+
│ ├── Comparison pages → "[product] vs [competitor]" at scale
|
|
66
|
+
│ ├── Alternative pages → "[competitor] alternatives"
|
|
67
|
+
│ ├── Feature pages → one page per feature, deep content
|
|
68
|
+
│ ├── Integration pages → "[product] + [integration]" at scale
|
|
69
|
+
│ └── Blog → educational content linking to product pages
|
|
70
|
+
└── Content/Blog
|
|
71
|
+
├── Pillar pages → comprehensive guides on core topics
|
|
72
|
+
├── Cluster pages → specific subtopics linking to pillar
|
|
73
|
+
└── FAQ pages → question-based content for featured snippets
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### E-Commerce SEO Strategy
|
|
77
|
+
|
|
78
|
+
**Collection pages rank higher than product pages.** Prioritize collection page optimization:
|
|
79
|
+
- Unique H1 with primary keyword
|
|
80
|
+
- 200+ words of original descriptive content above and below the product grid
|
|
81
|
+
- Internal links to related collections
|
|
82
|
+
- Breadcrumb navigation with schema markup
|
|
83
|
+
|
|
84
|
+
**Product pages target specific long-tail:**
|
|
85
|
+
- Title: `[Brand] [Product Name] [Key Attribute] | [Store Name]`
|
|
86
|
+
- Original description (never manufacturer copy)
|
|
87
|
+
- All image alt tags descriptive and keyword-relevant
|
|
88
|
+
- Related products section for internal linking
|
|
89
|
+
- Product schema markup with price, availability, reviews
|
|
90
|
+
|
|
91
|
+
### SaaS SEO Strategy
|
|
92
|
+
|
|
93
|
+
**Comparison and alternative pages are highest-ROI for SaaS:**
|
|
94
|
+
- Template: `[Your Product] vs [Competitor]: [Honest Comparison]`
|
|
95
|
+
- Structure: feature table, pricing comparison, use case recommendations
|
|
96
|
+
- Honest tone — acknowledge where competitors excel (builds E-E-A-T trust)
|
|
97
|
+
- CTA at the end, not the beginning
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 2. Programmatic SEO
|
|
102
|
+
|
|
103
|
+
### When to Use Programmatic SEO
|
|
104
|
+
|
|
105
|
+
Use when you can generate 100+ unique pages from structured data with genuine value per page. Each page must pass the "would a human find this useful?" test.
|
|
106
|
+
|
|
107
|
+
### Template Architecture
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
Data Source (DB/Spreadsheet/API)
|
|
111
|
+
↓
|
|
112
|
+
Template Engine (Next.js dynamic routes)
|
|
113
|
+
↓
|
|
114
|
+
Unique Page = Template + Dynamic Data + Unique Content Blocks
|
|
115
|
+
↓
|
|
116
|
+
Internal Linking (category → subcategory → page → related pages)
|
|
117
|
+
↓
|
|
118
|
+
XML Sitemap (auto-generated, all pages included)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Programmatic SEO Patterns
|
|
122
|
+
|
|
123
|
+
| Pattern | URL Structure | Example | Data Source |
|
|
124
|
+
|---------|-------------|---------|-------------|
|
|
125
|
+
| **Comparison** | `/compare/[a]-vs-[b]` | `/compare/printify-vs-printful` | Product database |
|
|
126
|
+
| **Location** | `/[service]-in-[city]` | `/pod-suppliers-in-london` | City database |
|
|
127
|
+
| **Integration** | `/integrations/[platform]` | `/integrations/shopify` | Integration catalog |
|
|
128
|
+
| **Alternative** | `/alternatives/[competitor]` | `/alternatives/printful` | Competitor list |
|
|
129
|
+
| **Template/Tool** | `/tools/[calculator-type]` | `/tools/profit-margin-calculator` | Tool catalog |
|
|
130
|
+
|
|
131
|
+
### Thin Content Guardrails
|
|
132
|
+
|
|
133
|
+
Every programmatic page MUST have:
|
|
134
|
+
1. Unique title and H1 (not just variable swapped)
|
|
135
|
+
2. At least one paragraph of unique descriptive content
|
|
136
|
+
3. Unique data points (stats, features, pricing) not found on other pages
|
|
137
|
+
4. Internal links to related pages in the same programmatic set
|
|
138
|
+
5. No duplicate meta descriptions across pages
|
|
139
|
+
|
|
140
|
+
**Red flags that trigger Google thin content penalties:**
|
|
141
|
+
- 95%+ identical content across pages (only city name swapped)
|
|
142
|
+
- No unique data — just template with variable substitution
|
|
143
|
+
- Boilerplate FAQ repeated across all pages
|
|
144
|
+
- Missing internal linking between related pages
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 3. Marketplace SEO Differences
|
|
149
|
+
|
|
150
|
+
See `references/marketplace-seo-differences.md` for detailed algorithm breakdowns.
|
|
151
|
+
|
|
152
|
+
### Quick Comparison
|
|
153
|
+
|
|
154
|
+
| Factor | Shopify (Google) | Etsy | Amazon |
|
|
155
|
+
|--------|-----------------|------|--------|
|
|
156
|
+
| **Primary algorithm** | Google organic | Etsy search (proprietary) | A9 / COSMO |
|
|
157
|
+
| **Ranking signal #1** | Backlinks + content quality | Recency + conversion rate | Sales velocity + conversion |
|
|
158
|
+
| **Title optimization** | 50-60 chars, keyword at start | 140 chars, front-load keywords | 80 chars optimal, keyword-rich |
|
|
159
|
+
| **Content depth** | Critical (500+ words ideal) | Less important (tags matter more) | Bullet points + A+ content |
|
|
160
|
+
| **Reviews impact** | Indirect (trust signal) | Direct ranking factor | Direct ranking factor |
|
|
161
|
+
| **Freshness** | Moderate (evergreen can rank) | High (recent listings boosted) | Moderate (sales velocity matters more) |
|
|
162
|
+
| **External links** | Critical | Helpful (drives external traffic signal) | Not applicable |
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 4. Schema Markup Implementation
|
|
167
|
+
|
|
168
|
+
### Which Schema for Which Page
|
|
169
|
+
|
|
170
|
+
| Page Type | Schema Types | Priority |
|
|
171
|
+
|-----------|-------------|----------|
|
|
172
|
+
| Product page | `Product`, `AggregateRating`, `Offer`, `BreadcrumbList` | Critical |
|
|
173
|
+
| Collection page | `CollectionPage`, `BreadcrumbList`, `ItemList` | High |
|
|
174
|
+
| FAQ page | `FAQPage`, `Question`, `Answer` | High (enables rich results) |
|
|
175
|
+
| How-to guide | `HowTo`, `Step`, `BreadcrumbList` | Medium |
|
|
176
|
+
| SaaS pricing | `SoftwareApplication`, `Offer`, `AggregateRating` | High |
|
|
177
|
+
| Blog post | `Article`, `Person` (author), `BreadcrumbList` | Medium |
|
|
178
|
+
| Local business | `LocalBusiness`, `PostalAddress`, `GeoCoordinates` | Critical for local |
|
|
179
|
+
|
|
180
|
+
### JSON-LD Implementation Pattern
|
|
181
|
+
|
|
182
|
+
Always use JSON-LD (not Microdata or RDFa). Place in `<head>` or at end of `<body>`.
|
|
183
|
+
|
|
184
|
+
```html
|
|
185
|
+
<script type="application/ld+json">
|
|
186
|
+
{
|
|
187
|
+
"@context": "https://schema.org",
|
|
188
|
+
"@type": "Product",
|
|
189
|
+
"name": "Product Name",
|
|
190
|
+
"description": "...",
|
|
191
|
+
"image": "https://...",
|
|
192
|
+
"offers": {
|
|
193
|
+
"@type": "Offer",
|
|
194
|
+
"price": "29.99",
|
|
195
|
+
"priceCurrency": "USD",
|
|
196
|
+
"availability": "https://schema.org/InStock"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
</script>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Detection limitation:** `web_fetch` and `curl` cannot detect JS-injected schema. Use Google Rich Results Test or browser DevTools to verify. See `seo-audit` skill for details.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 5. AI Search Optimization
|
|
207
|
+
|
|
208
|
+
### AEO (Answer Engine Optimization)
|
|
209
|
+
|
|
210
|
+
Optimize for AI Overviews (Google), ChatGPT, Perplexity, and Claude citations.
|
|
211
|
+
|
|
212
|
+
**Key patterns:**
|
|
213
|
+
1. **Concise answer paragraphs:** Start sections with a direct, 2-3 sentence answer before elaborating
|
|
214
|
+
2. **Entity clarity:** Use proper nouns, define terms, be specific (not "the tool" but "Printify's production API")
|
|
215
|
+
3. **Structured data:** Tables, lists, and clear headings that AI can parse
|
|
216
|
+
4. **Citation-worthy statements:** Include specific numbers, dates, and verifiable facts
|
|
217
|
+
5. **FAQ format:** Question-answer pairs that directly match search queries
|
|
218
|
+
|
|
219
|
+
### What AI Search Engines Cite
|
|
220
|
+
|
|
221
|
+
| Signal | Why It Gets Cited |
|
|
222
|
+
|--------|------------------|
|
|
223
|
+
| Specific data points | "Printify charges $12.50 per standard tee" — concrete, verifiable |
|
|
224
|
+
| Step-by-step instructions | Procedural knowledge that AI can relay as guidance |
|
|
225
|
+
| Comparison tables | Structured data AI can extract and present |
|
|
226
|
+
| Expert attribution | Named author with credentials increases citation likelihood |
|
|
227
|
+
| Recency | AI prefers recently-updated pages for rapidly-changing topics |
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Related Skills
|
|
232
|
+
|
|
233
|
+
- **seo-audit** — Diagnose existing SEO problems (this skill builds, seo-audit audits)
|
|
234
|
+
- **keywords** — Research and choose the right keywords before building pages
|
|
235
|
+
- **site-architecture** — Plan page hierarchy and URL structure
|
|
236
|
+
- **page-cro** — Optimize pages for conversion (not just ranking)
|
|
237
|
+
- **copywriting** — Write the content that goes on SEO-optimized pages
|
|
238
|
+
|
|
239
|
+
## Verification
|
|
240
|
+
|
|
241
|
+
After applying this skill, verify:
|
|
242
|
+
- [ ] Content strategy matches the correct site type (e-commerce, SaaS, content/blog)
|
|
243
|
+
- [ ] Programmatic SEO pages pass the thin content guardrails (unique title, unique content, unique data)
|
|
244
|
+
- [ ] Marketplace SEO uses platform-specific factors (not Google SEO assumptions)
|
|
245
|
+
- [ ] Schema markup uses JSON-LD format with correct @type for the page type
|
|
246
|
+
- [ ] AI search optimization includes concise answer paragraphs and entity clarity
|
|
247
|
+
- [ ] Internal linking follows hub-and-spoke pattern where applicable
|
|
248
|
+
|
|
249
|
+
## Do NOT Use When
|
|
250
|
+
|
|
251
|
+
| Instead of this skill | Use | Why |
|
|
252
|
+
|---|---|---|
|
|
253
|
+
| Diagnosing existing SEO problems or traffic drops | `seo-audit` | seo-audit diagnoses; seo-strategy builds |
|
|
254
|
+
| Keyword research and clustering | `keywords` | keywords owns research methodology |
|
|
255
|
+
| Page hierarchy and navigation design | `site-architecture` | site-architecture owns IA structure |
|
|
256
|
+
| Conversion rate optimization | `page-cro` | page-cro owns conversion, not ranking |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
*Version 1.1.0 — 2026-03-28. Added Philosophy, Verification, Do NOT Use When.*
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: server-actions-design
|
|
3
|
+
description: "Use when designing or reviewing Server Actions: the 'use server' directive contract, how a server-side function becomes invokable from the browser without an API route, form integration via the `action` attribute, the React 19 hooks useActionState / useFormStatus, progressive enhancement (works without JS), server-side validation and authorization as mandatory rather than optional, revalidation primitives (revalidatePath, revalidateTag, redirect), error handling and bound arguments, and the security boundary that makes Server Actions a public endpoint despite their function-like syntax. Covers Next.js App Router as the canonical implementation. Do NOT use for read-path data fetching with RSC (use server-components-design), for the broader 'use client' / 'use server' boundary semantics (use client-server-boundary), for designing externally-facing API contracts (use api-design), or for form UX patterns at the component level (use form-ux-architecture)."
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: Read Grep
|
|
6
|
+
metadata:
|
|
7
|
+
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"capability\",\"category\":\"engineering\",\"domain\":\"engineering/frontend\",\"scope\":\"reference\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-05-16\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-05-16\\\\\\\"}\",\"eval_artifacts\":\"planned\",\"eval_state\":\"unverified\",\"routing_eval\":\"absent\",\"comprehension_state\":\"present\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"Server Actions\\\\\\\",\\\\\\\"Server Function declaration\\\\\\\",\\\\\\\"form action attribute\\\\\\\",\\\\\\\"useActionState\\\\\\\",\\\\\\\"useFormStatus\\\\\\\",\\\\\\\"forms that work without JavaScript\\\\\\\",\\\\\\\"revalidatePath\\\\\\\",\\\\\\\"revalidateTag\\\\\\\",\\\\\\\"server mutation Next.js\\\\\\\",\\\\\\\"validate Server Action inputs\\\\\\\",\\\\\\\"bound arguments Server Action\\\\\\\",\\\\\\\"redirect after action\\\\\\\"]\",\"triggers\":\"[\\\\\\\"how do I submit a form to the server\\\\\\\",\\\\\\\"do I need an API route for this mutation\\\\\\\",\\\\\\\"how do I call a server function from a button\\\\\\\",\\\\\\\"why is my Server Action exposed as an endpoint\\\\\\\",\\\\\\\"useActionState vs useFormState\\\\\\\",\\\\\\\"how do I revalidate after mutation\\\\\\\",\\\\\\\"can Server Actions run in event handlers\\\\\\\"]\",\"examples\":\"[\\\\\\\"design a 'create comment' form using Server Actions plus useActionState so it works without JavaScript and reports server-side validation errors\\\\\\\",\\\\\\\"decide whether a delete button should call a Server Action or an API route\\\\\\\",\\\\\\\"audit a Server Action for missing authorization (the function looks like a normal call but is publicly invokable)\\\\\\\",\\\\\\\"design the revalidation strategy for a mutation that affects multiple cached routes\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"design a Server Component that reads data on render (use server-components-design)\\\\\\\",\\\\\\\"design a public REST API consumed by mobile clients (use api-design)\\\\\\\",\\\\\\\"choose between SSR and SSG (use rendering-models)\\\\\\\",\\\\\\\"design the visual UX of a form's validation states (use form-ux-architecture)\\\\\\\",\\\\\\\"design the visual states and accessibility of a form (use form-ux-architecture)\\\\\\\",\\\\\\\"design a public HTTP contract for mobile, third-party, or server-to-server callers (use api-design)\\\\\\\"]\",\"relations\":\"{\\\\\\\"related\\\\\\\":[\\\\\\\"server-components-design\\\\\\\",\\\\\\\"client-server-boundary\\\\\\\",\\\\\\\"form-ux-architecture\\\\\\\",\\\\\\\"api-design\\\\\\\",\\\\\\\"hooks-patterns\\\\\\\"],\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"server-components-design\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"server-components-design owns the read path — Server Components fetch data on render; server-actions-design owns the write path — Server Actions execute mutations triggered from the client. They share infrastructure (RSC, 'use server') but solve distinct problems.\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"client-server-boundary\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"client-server-boundary owns the serialization and directive mechanics of the boundary itself; server-actions-design owns the discipline of using the 'use server' side of that boundary for mutations.\\\\\\\"}],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"code-review\\\\\\\",\\\\\\\"api-design\\\\\\\"]}\",\"mental_model\":\"|\",\"purpose\":\"|\",\"boundary\":\"|\",\"analogy\":\"Server Actions are to React mutations what stored procedures are to database access — the function looks like an ordinary call in client code, but the work happens on the privileged side of a trust boundary, with the same security implications: the caller controls the arguments, but cannot see the implementation; the implementation must validate every input and authorize every call as if the caller were a hostile script with curl, because functionally they could be.\",\"misconception\":\"|\",\"concept\":\"{\\\\\\\"definition\\\\\\\":\\\\\\\"A Server Action is a JavaScript function marked with 'use server' (either at the module level or as the first line of the function body) that executes on the server but is invokable from the client. The bundler turns calls to it from Client Components into a network round-trip: arguments are serialized, the function runs server-side, the return value is serialized back. The function itself looks like an ordinary import in client code, which is the design's main strength and its main security trap — what looks like a function call is a public POST endpoint.\\\\\\\",\\\\\\\"mental_model\\\\\\\":\\\\\\\"|\\\\\\\",\\\\\\\"purpose\\\\\\\":\\\\\\\"|\\\\\\\",\\\\\\\"boundary\\\\\\\":\\\\\\\"|\\\\\\\",\\\\\\\"taxonomy\\\\\\\":\\\\\\\"|\\\\\\\",\\\\\\\"analogy\\\\\\\":\\\\\\\"|\\\\\\\",\\\\\\\"misconception\\\\\\\":\\\\\\\"|\\\\\\\"}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/server-actions-design/SKILL.md\"}"
|
|
8
|
+
skill_graph_source_repo: "https://github.com/jacob-balslev/skill-graph"
|
|
9
|
+
skill_graph_protocol: Skill Metadata Protocol v4
|
|
10
|
+
skill_graph_project: Skill Graph
|
|
11
|
+
skill_graph_canonical_skill: skills/server-actions-design/SKILL.md
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Server Actions Design
|
|
15
|
+
|
|
16
|
+
## Coverage
|
|
17
|
+
|
|
18
|
+
The discipline of designing Server Actions: what `'use server'` actually does (turns a function into a public POST endpoint with serialized arguments), how Server Actions integrate with HTML forms via the `action` attribute, how `useActionState` and `useFormStatus` give React-aware state and pending UI, why progressive enhancement (form works without JavaScript) is the design's load-bearing feature, why server-side validation and authorization are not optional, how `revalidatePath` / `revalidateTag` / `redirect` participate in the mutation pipeline, how bound arguments propagate state across action calls, and the central security insight: a Server Action that looks like a function call is a publicly-reachable endpoint and must be treated as one.
|
|
19
|
+
|
|
20
|
+
## Philosophy
|
|
21
|
+
|
|
22
|
+
Before Server Actions, a "mutation from the browser" required two parallel structures: a client-side function that called `fetch('/api/foo', { method: 'POST', body: JSON.stringify({...}) })`, and a server-side route handler that parsed the body, validated, authorized, executed the mutation, and serialized a response. The two had to agree on a wire format, type contracts had to be duplicated or shared via a runtime validator, and CSRF tokens had to be plumbed through.
|
|
23
|
+
|
|
24
|
+
Server Actions collapse that into one declaration. A function with `'use server'` at its top is invokable from Client Components as if it were imported normally. The bundler rewrites the call site to a network round-trip; the function executes server-side. There is no manual wire format, no client-side fetch boilerplate, no separate API route to keep in sync.
|
|
25
|
+
|
|
26
|
+
The collapse is *syntactic*, not *semantic*. The function is still invoked over the network, by anyone who finds the action's identifier, with arguments they control. The server has none of the type guarantees the call site appears to provide. **The discipline of Server Actions is to treat the function as a public endpoint disguised as a function**: validate every input, authorize every call, fail loudly on any assumption that the caller is your own UI rather than an attacker with curl.
|
|
27
|
+
|
|
28
|
+
The second principle of Server Actions is **progressive enhancement**. A Server Action attached to an HTML form via `<form action={serverAction}>` works without JavaScript: the browser performs a native POST to the action's endpoint, the server returns a redirect, the page navigates. With JavaScript, React intercepts the submission, runs the action, applies the result without a full page reload, and updates `useFormStatus` while the action is in flight. The form does not have two code paths — it has one path that gracefully upgrades when JS arrives. Designing actions that rely on JS-only state defeats the architecture; designing actions that work form-first and JS-second uses it well.
|
|
29
|
+
|
|
30
|
+
## The `'use server'` Contract
|
|
31
|
+
|
|
32
|
+
Three ways to declare a Server Action:
|
|
33
|
+
|
|
34
|
+
1. **Module-level directive**: a file with `'use server'` at the top exports only Server Actions.
|
|
35
|
+
```ts
|
|
36
|
+
// app/actions/comments.ts
|
|
37
|
+
'use server'
|
|
38
|
+
export async function createComment(formData: FormData) { ... }
|
|
39
|
+
export async function deleteComment(id: string) { ... }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2. **Inline directive in a Server Component**: a function defined inside a Server Component, with `'use server'` as its first statement.
|
|
43
|
+
```tsx
|
|
44
|
+
// app/posts/[id]/page.tsx (Server Component)
|
|
45
|
+
export default async function Post({ params }) {
|
|
46
|
+
async function addComment(formData: FormData) {
|
|
47
|
+
'use server'
|
|
48
|
+
// runs on the server, can close over server-side state
|
|
49
|
+
}
|
|
50
|
+
return <form action={addComment}>...</form>
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. **Re-exported from a `'use server'` module to a Client Component**: client code imports the function and invokes it directly.
|
|
55
|
+
|
|
56
|
+
The bundler treats `'use server'`-marked functions specially: it strips the function body from the client bundle, replacing it with a reference that the runtime resolves to a network call. The function's *signature* (name, parameter types) is preserved at the call site; the function's *implementation* never reaches the client.
|
|
57
|
+
|
|
58
|
+
Arguments and return values must be serializable across the boundary — strings, numbers, plain objects, arrays, FormData, Date, Map, Set, typed arrays, Promise (React 19). Functions, class instances, and DOM nodes cannot cross.
|
|
59
|
+
|
|
60
|
+
## The Form Integration Pattern
|
|
61
|
+
|
|
62
|
+
The canonical Server Action consumes a `FormData` object via the `action` prop on a `<form>`:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
'use server'
|
|
66
|
+
import { z } from 'zod'
|
|
67
|
+
import { db } from '@/db'
|
|
68
|
+
import { revalidatePath } from 'next/cache'
|
|
69
|
+
import { auth } from '@/auth'
|
|
70
|
+
|
|
71
|
+
const CommentSchema = z.object({
|
|
72
|
+
postId: z.string().uuid(),
|
|
73
|
+
body: z.string().min(1).max(1000),
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
export async function addComment(formData: FormData) {
|
|
77
|
+
const session = await auth()
|
|
78
|
+
if (!session) throw new Error('Unauthorized') // public endpoint — must check
|
|
79
|
+
|
|
80
|
+
const parsed = CommentSchema.safeParse({
|
|
81
|
+
postId: formData.get('postId'),
|
|
82
|
+
body: formData.get('body'),
|
|
83
|
+
})
|
|
84
|
+
if (!parsed.success) return { error: parsed.error.flatten() }
|
|
85
|
+
|
|
86
|
+
await db.comment.create({
|
|
87
|
+
data: { ...parsed.data, authorId: session.userId },
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
revalidatePath(`/posts/${parsed.data.postId}`)
|
|
91
|
+
return { success: true }
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
// In a Server Component (or Client Component):
|
|
97
|
+
<form action={addComment}>
|
|
98
|
+
<input type="hidden" name="postId" value={postId} />
|
|
99
|
+
<textarea name="body" required />
|
|
100
|
+
<button type="submit">Post</button>
|
|
101
|
+
</form>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The form posts to the action. Without JavaScript, the browser navigates to the action's endpoint and back. With JavaScript, React handles the submission inline. Either way, `revalidatePath` instructs Next.js to invalidate the cached version of the post page, so the new comment appears on next render.
|
|
105
|
+
|
|
106
|
+
## `useActionState` and `useFormStatus`
|
|
107
|
+
|
|
108
|
+
These two React 19 hooks let Client Components observe action state without imperative wiring.
|
|
109
|
+
|
|
110
|
+
**`useActionState`** wraps an action and returns the action's last result alongside a wrapper function:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
'use client'
|
|
114
|
+
import { useActionState } from 'react'
|
|
115
|
+
import { addComment } from '@/app/actions/comments'
|
|
116
|
+
|
|
117
|
+
export function CommentForm({ postId }) {
|
|
118
|
+
const [state, formAction, isPending] = useActionState(addComment, { error: null })
|
|
119
|
+
return (
|
|
120
|
+
<form action={formAction}>
|
|
121
|
+
<input type="hidden" name="postId" value={postId} />
|
|
122
|
+
<textarea name="body" />
|
|
123
|
+
{state?.error && <p className="error">{state.error.body?.[0]}</p>}
|
|
124
|
+
<button disabled={isPending}>{isPending ? 'Posting…' : 'Post'}</button>
|
|
125
|
+
</form>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The first argument is the action; the second is the initial state. `formAction` is what you pass to the form's `action` prop. `state` is whatever the action last returned. `isPending` tracks the in-flight status.
|
|
131
|
+
|
|
132
|
+
**`useFormStatus`** is read from inside a `<form>`'s descendant components — it gives the pending status without prop drilling:
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
'use client'
|
|
136
|
+
import { useFormStatus } from 'react-dom'
|
|
137
|
+
|
|
138
|
+
export function SubmitButton({ label }) {
|
|
139
|
+
const { pending } = useFormStatus()
|
|
140
|
+
return <button disabled={pending}>{pending ? 'Saving…' : label}</button>
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`useFormStatus` only reads the status of the nearest ancestor `<form>` — it cannot observe arbitrary form state. It is for the submit button's UI, not for global form state.
|
|
145
|
+
|
|
146
|
+
## Revalidation — `revalidatePath`, `revalidateTag`, `redirect`
|
|
147
|
+
|
|
148
|
+
A mutation that the user sees must invalidate the cached read paths it affects. Three primitives:
|
|
149
|
+
|
|
150
|
+
| Primitive | What it does |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `revalidatePath('/posts/123')` | Invalidates the cached Server Component output for the path; next request re-renders it |
|
|
153
|
+
| `revalidatePath('/posts/[id]', 'page')` | Invalidates the dynamic route pattern (all `/posts/*` pages) |
|
|
154
|
+
| `revalidateTag('comments')` | Invalidates all `fetch` calls or `cache(...)` reads tagged `'comments'`; finer-grained than path-based |
|
|
155
|
+
| `redirect('/posts/123')` | Throws a special redirect signal that becomes a `Location:` header in the response |
|
|
156
|
+
|
|
157
|
+
Design rule: every action that mutates state visible to a Server Component must call `revalidatePath` or `revalidateTag` to update the cache. Forgetting to revalidate produces stale UI after submission — the mutation succeeded server-side, but the page still shows the pre-mutation data.
|
|
158
|
+
|
|
159
|
+
`redirect` is for actions that should navigate after success (e.g., create-and-redirect-to-detail-page). It cannot be inside a try/catch — `redirect` throws, and catching swallows the redirect signal.
|
|
160
|
+
|
|
161
|
+
## Bound Arguments
|
|
162
|
+
|
|
163
|
+
`.bind()` (the JavaScript built-in) pre-fills action arguments at the server side — useful for passing IDs without exposing them as form fields:
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
// Server Component
|
|
167
|
+
export default async function Post({ params }) {
|
|
168
|
+
const deletePost = deletePostAction.bind(null, params.id)
|
|
169
|
+
return (
|
|
170
|
+
<form action={deletePost}>
|
|
171
|
+
<button type="submit">Delete</button>
|
|
172
|
+
</form>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 'use server' module
|
|
177
|
+
export async function deletePostAction(id: string, formData: FormData) {
|
|
178
|
+
// id is bound; formData comes from the form
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Bound arguments do not need to be serialized at submission time because they were captured server-side. They are also not user-controllable from the form, so they are safer than `<input type="hidden">` for IDs that the user must not change. But they are still visible to anyone reading the network request — never bind a secret.
|
|
183
|
+
|
|
184
|
+
## Security Discipline
|
|
185
|
+
|
|
186
|
+
| Concern | Reality | Required action |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| Authorization | The function is publicly invokable by anyone who finds its identifier | Check the session in every action; reject anonymous calls explicitly |
|
|
189
|
+
| Authentication of the *acting user* | The function does not know who's calling unless you check | Read the session from cookies/headers; do not trust client-supplied user IDs |
|
|
190
|
+
| Input validation | The function receives FormData / serialized arguments; the server has no type guarantee from the call-site types | Validate every input with a runtime schema (Zod, Valibot, ArkType) |
|
|
191
|
+
| Authorization of the *operation* | Even authenticated users may not be allowed to delete this post | Check ownership / permission inside the action body before mutating |
|
|
192
|
+
| CSRF | Server Actions in Next.js include built-in same-origin checks; cross-origin POSTs are rejected | Default protection is on; configure `serverActions.allowedOrigins` only when explicitly proxying |
|
|
193
|
+
| Rate limiting | The endpoint is public; spam is possible | Implement per-action rate limits in middleware or inside the action |
|
|
194
|
+
| Bound arguments | Visible in the network request despite not being a form field | Never bind secrets, even via `.bind()` |
|
|
195
|
+
|
|
196
|
+
The single most common Server Action bug: forgetting that the function is publicly reachable. A function called `deletePost(postId: string)` is a `POST` that any browser can craft with any `postId` — the type signature does not protect the server. Treat actions like API routes that happen to share types with your UI.
|
|
197
|
+
|
|
198
|
+
## Common Anti-Patterns
|
|
199
|
+
|
|
200
|
+
| Anti-pattern | Why it's wrong | Fix |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| Trusting client-supplied user ID as the actor | Anyone can submit any ID | Read user ID from the server-side session, not from form fields |
|
|
203
|
+
| Validating only on the client | Server has no guarantee of client-side validation | Mandatory server-side validation; client-side is UX, not security |
|
|
204
|
+
| Calling fetch('/api/...') instead of a Server Action for an internal mutation | Duplicate code, type drift between client and server | Use a Server Action — one declaration, one wire format |
|
|
205
|
+
| Forgetting `revalidatePath` / `revalidateTag` | Cached Server Component shows stale data after mutation | Call the appropriate revalidation primitive in every mutation |
|
|
206
|
+
| Wrapping `redirect` in try/catch | The redirect signal is swallowed | Place `redirect` outside the try block, or rethrow caught redirect signals |
|
|
207
|
+
| Server Action that returns a non-serializable value (Date object with methods, function, class instance) | Cannot cross the boundary back to the client | Return plain objects only |
|
|
208
|
+
| Form that doesn't work without JavaScript (e.g., requires a click handler that calls the action) | Defeats progressive enhancement | Use `<form action={serverAction}>`, not `<button onClick={() => serverAction()}>` |
|
|
209
|
+
| Action that performs side effects regardless of validation result | Partial failure with database state changed and error returned | Validate before any mutation; structure as parse-then-mutate |
|
|
210
|
+
|
|
211
|
+
## Verification
|
|
212
|
+
|
|
213
|
+
After applying this skill, verify:
|
|
214
|
+
|
|
215
|
+
- [ ] Every Server Action checks authentication before any mutation.
|
|
216
|
+
- [ ] Every Server Action validates inputs with a runtime schema, not just TypeScript types.
|
|
217
|
+
- [ ] Every Server Action that mutates Server-Component-visible state calls `revalidatePath` or `revalidateTag`.
|
|
218
|
+
- [ ] No action trusts client-supplied user IDs, role flags, or permission claims.
|
|
219
|
+
- [ ] Forms work without JavaScript: native browser submission to the action's endpoint produces the same result as the React-intercepted path.
|
|
220
|
+
- [ ] No `redirect` is inside a try/catch (or, if it must be, redirect signals are explicitly rethrown).
|
|
221
|
+
- [ ] Bound arguments via `.bind()` carry only non-secret data.
|
|
222
|
+
- [ ] Rate limiting exists for actions that can be invoked frequently or anonymously.
|
|
223
|
+
- [ ] Server Actions return only serializable values to Client Components.
|
|
224
|
+
|
|
225
|
+
## Grounding Sources
|
|
226
|
+
|
|
227
|
+
- React docs — [`'use server'`](https://react.dev/reference/rsc/use-server). The directive contract.
|
|
228
|
+
- React docs — [`useActionState`](https://react.dev/reference/react/useActionState) and [`useFormStatus`](https://react.dev/reference/react-dom/hooks/useFormStatus). The React 19 hooks for action state and pending UI.
|
|
229
|
+
- Next.js docs — [Server Actions and Mutations](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations). The canonical implementation reference.
|
|
230
|
+
- Next.js docs — [`revalidatePath`](https://nextjs.org/docs/app/api-reference/functions/revalidatePath) and [`revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag). Cache invalidation primitives.
|
|
231
|
+
- Next.js docs — [`redirect`](https://nextjs.org/docs/app/api-reference/functions/redirect). The redirect-as-throw mechanism.
|
|
232
|
+
- Vercel — [Server Actions security model and the Same-Origin Check](https://nextjs.org/blog/security-nextjs-server-components-actions). The framework's security defaults and what they don't cover.
|
|
233
|
+
- Wieruch, R. — [Server Actions in Next.js](https://www.robinwieruch.de/next-server-actions/). Comprehensive walkthrough with progressive-enhancement and form-state patterns.
|
|
234
|
+
|
|
235
|
+
## Do NOT Use When
|
|
236
|
+
|
|
237
|
+
| Instead of this skill | Use | Why |
|
|
238
|
+
|---|---|---|
|
|
239
|
+
| Designing the read path (fetching data on render with Server Components) | `server-components-design` | server-components-design owns the read path; this skill owns the write path. They share infrastructure but solve different problems. |
|
|
240
|
+
| The serialization mechanics of the `'use client'` / `'use server'` boundary | `client-server-boundary` | client-server-boundary owns the boundary semantics; this skill applies them to mutations specifically. |
|
|
241
|
+
| Designing a public REST API consumed by mobile clients or third parties | `api-design` | api-design owns HTTP contracts intended for external consumption. Server Actions are internal to one app's UI. |
|
|
242
|
+
| Form UX patterns (validation states, layout, accessibility, microcopy) | `form-ux-architecture` | form-ux-architecture owns the visual/interaction design of the form; this skill owns the server execution model. |
|
|
243
|
+
| Hook discipline (Rules of Hooks, dependency arrays, custom hooks) | `hooks-patterns` | hooks-patterns covers Client Component hook usage. `useActionState` is a hook called inside Client Components but governed by hooks-patterns' rules. |
|