Install
$ agentstack add skill-kurtschmidt-storyblok-skill-storyblok ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Storyblok Engineering
Model: Sonnet for schema authoring, script writing, component implementation, and debugging. Opus only when designing a content model from scratch — the taxonomy and content-type split is the one decision that is expensive to reverse once editors have made content.
Storyblok engineering mechanics for Next.js and Astro. Brand, design-system, and project-specific compliance rules live in their own scoped skills and project rules — do not pull them in here.
Read first, before writing anything
Storyblok's own docs lag the shipping packages, sometimes by a major version. When the docs and the installed package disagree, the package wins. Check node_modules/@storyblok/*/package.json and the actual exports before following a doc example. Two of the traps in this skill exist because a doc sample was correct for the previous major.
The one distinction everything hangs on
Storyblok is two separate APIs with separate hosts, separate auth, and separate rate limits. Conflating them is the most common source of wasted time.
| | Delivery (CDA) | Management (MAPI) | |---|---|---| | Host | api.storyblok.com/v2/cdn | mapi.storyblok.com/v1/spaces/ | | Purpose | Read content to render | Read/write schemas, stories, assets | | Auth | token= query param | Authorization: header, no Bearer | | Tokens | public (published only) / preview (reads drafts) | personal access token | | Rate limit | tiered by query shape | ~6 req/s (plan ceiling, not raisable) | | Ever in browser | public token, yes | never |
A preview token in client-side code leaks every unpublished draft. A management token in client-side code is a full write compromise. Neither belongs in NEXT_PUBLIC_* or any bundled Astro client script.
Details: [references/delivery-api.md](references/delivery-api.md) and [references/management-api.md](references/management-api.md).
Non-negotiables
These five hold on every Storyblok project. Each one fails silently when violated, which is why they are rules rather than preferences.
- Scripts never auto-publish. Omit the
publishparam on every MAPI write.POSTwithout it creates a draft;PUTwithout it saves a draft and leaves the live version serving unchanged. A human publishes. A bulk import that publishes dozens of stories onto a live site is not undoable with a button.
- Taxonomy fields live at the ROOT of the content type, never inside a blok.
filter_queryonly works cleanly on root fields. A reference buried inbodyis invisible to every cross-index query, and indexed paths intobodybreak the moment an editor reorders the page.bodyis for humans arranging a page; anything a query needs is a typed root field.
- Back-links are computed, never authored. Declare the relationship in one direction on the spoke, compute the inverse with a reverse
filter_queryat build time. A mirrored "related posts" field on the hub is the classic trap: two fields to keep in sync, and nobody will.
- The component schema is the contract, for both editors and code. Constrain in the schema —
component_whitelist,customize_toolbar, required fields, option lists — rather than relying on discipline. An editor, or an agent writing through the MAPI, should be structurally unable to produce a broken page, not merely discouraged from it.
- Every page composes from the component library. No page-specific components. If a page needs something the library lacks, add it to the library, then compose. The test: if a non-developer could not later rebuild that page in the Storyblok UI, it was built wrong. That capability is the point of using a CMS at all.
Component completeness contract
A component is not done when it renders. It is done when a non-developer can find it, recognize it, and fill it in correctly. Every one of these is a build task, not a nicety:
- Schema pushed, and the schema filename matches
schema.name - Registered in the framework's component map (a missing entry renders nothing, with no error)
storyblokEditablespread on the outermost element (missing = the block is unclickable in the Visual Editor, with no error anywhere)component_whiteliston everybloksfield — an unrestricted picker is how unrelated components end up nested- Preview image — without one the block picker is a wall of identical grey rows
preview_fieldso a collapsed block reads like its content, not like its type namedisplay_nameplus one sentence of help text on every field- Preset where a block has an obvious default state
Skipping the last four ships a CMS the people who have to run it cannot actually use. Enforce them with a CI check — see [references/quality-gates.md](references/quality-gates.md).
Working on an existing project
Before changing anything:
- Read the schemas, not the docs.
storyblok/components/*.json, or wherever the repo keeps them, is the live contract. - Field technical names are effectively immutable once content exists — including typos. If the schema says
subheadling, the code sayssubheadling. Renaming means a content migration. - Renaming a component silently breaks
resolve_relations, which usescomponent_name.field_namestrings. Keep every one of those strings in a single module. - Check whether the project has a decision log. URL shapes and content-model choices that look like bugs are often deliberate and load-bearing. Confirm before "fixing" one.
Route by task
| Task | Read | |---|---| | Fetching content, versions, filter_query, resolve_relations, rate limits | [references/delivery-api.md](references/delivery-api.md) | | Pushing schemas, importing content, assets, migration scripts | [references/management-api.md](references/management-api.md) | | Designing content types, taxonomy, heading hierarchy, rich text | [references/content-modeling.md](references/content-modeling.md) | | Next.js App Router: draft mode, revalidation, image loader, preview routes | [references/nextjs.md](references/nextjs.md) | | Astro: integration config, version selection, bridge, rich text | [references/astro.md](references/astro.md) | | CI checks that catch the silent failures | [references/quality-gates.md](references/quality-gates.md) |
Environment variables
Namespace-prefix every Storyblok env var per project (ACME_STORYBLOK_*), and never use bare STORYBLOK_* on a machine that works on more than one Storyblok site. Shell environment beats .env.local, so a globally-exported STORYBLOK_MANAGEMENT_TOKEN from another project will silently target the wrong space — and a management token pointed at the wrong space does real damage before anyone notices.
Five roles, kept distinct:
| Role | Reads drafts | Safe in browser | |---|---|---| | CDA public token | no | yes | | CDA preview token | yes | no | | Management PAT | n/a (write) | no | | Space ID | n/a | yes | | Webhook signing secret | n/a | no |
Before concluding a token is missing, check the environment and the project's credential store — and test the credential against the endpoint you actually need. A token that authenticates is not necessarily a token scoped for the write you are about to attempt.
Plan ceilings worth designing inside
Verify against the space's actual plan before relying on any number; they move. The two that bite in practice: asset count (a content-heavy site with a real design burns through a few thousand faster than anyone expects — track it from day one) and scheduled stories (low single digits on mid tiers, so an editor cannot queue a month of posts; tell them before they discover it). Also check component count, locales, webhook count, and version-history retention against what the build assumes.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: kurtschmidt
- Source: kurtschmidt/storyblok-skill
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.