When to Use
Decide whether a new page is a Connected (content-type-bound) or Freeform (one-off) template. Connected is the default. Freeform is the very last resort. Hands off to the matching build skill.
Use at the start of authoring a new page, before any template is created. Phrases: “Connected or Freeform?”, “what kind of template”, “should this be a landing page”. Emits a recommendation (Connected default, Freeform only when justified by the Three-AND rule) and the next skill to run. Do NOT use to actually build the template.
Auth preflight: settle the credential before the first API call. Resolve it OAuth-first per authenticate-cma: CS_OAUTH_ACCESS_TOKEN, else the Contentstack MCP’s stored session. Never ask the user for a session authtoken. If nothing resolves, or a refresh fails with 400 invalid_refresh_token, hand them ! CONTENTSTACK_REGION=<code> npx @contentstack/mcp --auth (it needs a TTY and a browser, so it cannot be run for them) and wait. 403 error_code 316 is a valid credential aimed at another org: fix the org or the api_key, do not re-authenticate.
Choose Connected vs Freeform Template
Context
Studio offers two kinds of top-level compositions: Connected templates (bound 1:1 to a content type, so every entry of that CT renders through the same template at a derived URL) and Freeform templates (one-off pages assembled from any mix of sources (Pinned Queries, Pinned Entries, Component Default Data) with no content-type binding).
Default is Connected. Connected scales with content (one template renders unlimited entries), auto-binds template.* against the connected entry, supports {{entry.*}} URL variables, gives authors a content-first workflow (edit the entry and the page updates), and benefits from CT-level governance (validation, locales, variants, publishing workflows). Most pages should be Connected, including pages that only ever have one instance. Model a single-entry content type rather than reaching for Freeform.
Freeform is the very very very last resort. Use it ONLY when ALL THREE are true:
- Short-lived: the page has an expected end date (campaign, splash, takeover, time-boxed promo). Not a “one-off that lives forever.”
- Owns ZERO content of its own: no hero copy, no page-specific title, no subheading, no CTA text, no callouts, no closing message. Literally no copy authored on the page. Hero copy IS content. Throwaway HTML is owned content in disguise. If you find yourself writing copy in JSX, you have a content field. Model it as a single-entry CT and go Connected.
- Visible content is 100% assembled by pinning / pulling from existing entries: pinned entries from existing CTs, pinned queries, references into existing collections. The page is a vitrine, not a source.
If any one of those three is missing, it is not Freeform. Use Connected with the right CT shape (single-entry CT for one-off long-lived pages, multi-entry CT for repeating shapes including recurring campaigns, single-entry CT even for short-lived pages that own any copy).
Examples that do NOT qualify for Freeform (despite tempting at first glance):
- ”Black Friday 2026 landing”: even if short-lived and references existing product entries, it has its own campaign hero copy, headlines, CTA text. That is owned content, so model a single-entry CT or a generic campaign CT and go Connected.
- ”Conference splash”: has its own conference hero, dates copy, sponsor framing. That is owned content, so go Connected.
- ”Marketing landing page”: almost always has page-specific copy. That is owned content, so go Connected.
- Homepage / About / Contact / Pricing: long-lived AND own their content, so model a single-entry CT and go Connected.
Genuine Freeform cases are rare and usually internal-tool-ish: a merchandiser dashboard pinning 12 products in a specific order, a monitoring vitrine of pinned analytics entries, an A/B test variant that’s purely “pinned query, no other content, deleted next week”, pure assembly of existing entries with no surrounding copy.
Task
Ask the user for pageDescription, numberOfPagesOfThisShape, and hasContentTypeMatch if not already provided.
Check for a URL-pattern hard constraint. If the user mentions a URL that needs entry-field variables (e.g. /blog/{{entry.slug}}, /products/{{entry.handle}}), force Connected. Freeform URL patterns only support {{composition_uid}} plus {{environment}} / {{branch}}. They cannot resolve {{entry.*}} or {{content_type_uid}}. ({{locale}} is accepted by the pattern engine but not recommended for either flavor. Locale belongs in your routing layer + the SDK locale query option.)
Otherwise apply the decision tree in order. Bias toward Connected at every branch. Only return Freeform after explicitly confirming ALL THREE Freeform conditions (Step 4 below).
- (a) numberOfPagesOfThisShape = many-with-CT-backing (many pages, each maps to one entry of a single CT) means Connected. Canonical examples: blog posts, products, recipes, author profiles.
- (b) numberOfPagesOfThisShape = one AND hasContentTypeMatch = yes (one-off page that maps cleanly to one entry of a CT) means Connected with a hard-coded URL. Cheaper than Freeform because Connected auto-binds template fields against the connected entry.
- (c) numberOfPagesOfThisShape = many AND hasContentTypeMatch = no or partial, so propose Connected via a new or extended CT. Ask: can a content type be created (or an existing one extended) to back these pages? If yes (which is usually the case), model the CT first, then go Connected.
- (d) numberOfPagesOfThisShape = one AND hasContentTypeMatch = no, so ask: does the page own any copy of its own (hero title, subheading, CTA, callouts)? If YES, choose Connected with a single-entry CT (typical for homepages, about, contact, pricing, campaign landing pages: they all own their copy). The page-specific copy IS content. Model it. If NO (the page owns literally zero copy and purely assembles existing entries), continue to Step 4 (Freeform candidate).
Freeform last-resort check. If (and only if) branch (d) led here with the user confirming the page owns no copy, run the three-AND rule. Re-confirm by asking explicitly:
- (i) Does this page have an expected end date? (Campaign, splash, takeover, not “one-off that lives forever.”)
- (ii) Does the page own ZERO content of its own? No hero copy, no page-specific title, no subheading, no CTA text, no callouts, no closing message, literally nothing the page itself authors. (Hero copy IS content. Throwaway HTML IS content in disguise.)
- (iii) Is the visible content 100% assembled from existing entries: pinned entries, pinned queries, references into existing CTs?
If the user confirms all three, the answer is Freeform. If even one answer wavers or is “yes, but a hero title”, flip back to Connected with a single-entry CT (or a campaign CT for recurring campaign shapes). Hero copy / page-specific copy means owned content. Owned content means Connected.
Print the recommendation in this exact shape:
Recommendation: <Connected | Freeform> template Rationale: <one sentence tying back to the inputs> Next skill: <build-connected-template | build-freeform-template>
If the recommendation is Freeform, append TWO reminder lines:
- Reconsider: did you rule out Connected via a single-entry CT or an extended CT? Freeform is the exception, not the default — re-check before proceeding.
- Before running build-freeform-template, verify the project-level "Enable Freeform Feature" toggle is on (Studio → Settings → Configuration). Many teams keep it OFF deliberately to enforce the every-page-maps-to-a-CT discipline; if your project has it off, the right move is usually to leave it off and model a CT.
Stop. Do not create the template yourself. The user (or the next skill invocation) runs the chosen build skill.
Inputs Needed From the User
- pageDescription: one sentence, free text. Used only for the rationale line.
- numberOfPagesOfThisShape: one of one, many, many-with-CT-backing.
- hasContentTypeMatch: one of yes, no, partial.
If the user volunteers a URL pattern in pageDescription, parse it for {{entry.*}} or {{content_type_uid}} and apply the hard constraint from step 2 before the decision tree.
Acceptance
- Exactly one recommendation is printed (Connected OR Freeform, never both, never “it depends”).
- The rationale references the user’s actual inputs, not generic copy.
- The Next skill line names a real, runnable skill in the docs (build-connected-template or build-freeform-template).
- If the URL needs {{entry.*}}, the output is Connected and the rationale explicitly cites the Freeform URL-variable limitation.
- If the output is Freeform, the Enable Freeform Feature reminder is present.
- No template is created in Studio by this skill.
Common Pitfalls
| Pitfall | Why it bites | Right move |
|---|---|---|
| Recommending Freeform for “many blog posts” because the user said the word “landing” once | Freeform is 1:1. Each blog post would need its own template, exploding maintenance | If many-with-CT-backing, always Connected, regardless of stylistic words |
| Recommending Freeform when the URL contains {{entry.slug}} | Freeform URL patterns only resolve {{composition_uid}}, {{environment}}, {{branch}}. {{entry.*}} and {{content_type_uid}} will not interpolate | Force Connected the moment an entry-field variable appears |
| Treating “partial CT match” as automatic Freeform | A partial match often means the CT just needs one extra field. Connected is still right if the page shape repeats | Ask whether the CT can be extended before falling back to Freeform |
| Recommending Freeform without checking the project toggle | Enable Freeform Feature may be off at the project level. build-freeform-template will not see the option in the create-template modal | Always print the toggle reminder when the answer is Freeform |
| Choosing Freeform for a one-off page that maps to one entry | You lose Connected’s auto-resolution of template.* bindings and have to wire Link Entry / Pinned Queries by hand | A one-off with a clean CT match means Connected with a hard-coded URL |
| Reaching for Freeform on a one-off page because “there’s no obvious CT” | A single-entry CT (one CT, one entry) is almost always cheaper than Freeform for the homepage, about page, contact page, etc. Connected gives you auto-binding, locales, variants, and a content-first edit flow that Freeform doesn’t | If the page has even one stable content shape, model it as a single-entry CT and go Connected |
| Treating Freeform as the default for “marketing / campaign” pages | The label “marketing page” doesn’t decide the question. The data shape does. A “campaign” page that always has hero + promos + CTA can be a single-entry CT (Connected) | Ask what the data on the page looks like, not what the page is called. Connected wins whenever the shape repeats or stabilizes |
| Confusing Repeater iteration bindings with template bindings during the conversation | Inside a Repeater, fields bind as repeater.<field> (RepeaterBindingValue, discriminated by repeaterUID). At the template level they bind as template.<field> (TemplateBindingValue). This skill doesn’t bind (it just chooses) but if the user asks “can I bind X?”, route them to the matching build skill instead of guessing | Defer all binding shape questions to build-connected-template / build-freeform-template |
| Forgetting that references inside a Repeater always need a Condition Block | True for both single-CT and multi-CT reference fields, relevant when the user asks whether their repeater-of-refs page is feasible | Confirm feasibility, then hand off. The build skill handles the Condition Block step |