DynoStaticAdmin sign in
Documentation

Build a CMS website

Build a CMS website

Give an agent the DynoStatic installation URL and this guide. It can build or convert a website using the installed documentation and authenticated APIs; it does not need the DynoStatic source repository or an external skill. Preserve an existing site's design and hosting unless the owner requests a change.

Discover the installation

Read integration.php at the installation root. Its version identifies the installed product; agent is the versioned dynostatic.integration-guide contract. Follow its absolute guide and API links, which include any installation subfolder. The public manifest contains product capabilities, not configured website data or the permissions of a particular user. The optional SKILL.md and llms.txt lead to these same contracts.

For an older installation without agent, use its available CMS and Automation guides and authenticated discovery. Do not assume a newer feature exists. A missing capability is a concrete compatibility gap; do not work around it with raw database writes or an unrestricted remote execution endpoint.

Use physical gateways on hosts without rewrites: append api/?action=… or admin/?page=… to the complete installation URL. Preserve the subfolder. Read these contracts as needed:

Task Contract
Read published content during builds Content API, cms.manifest
Import or manage website resources Automation API, automation.capabilities
Group and refresh translated variants Source-managed translations
Render widget-managed fields in an existing website Website forms
Connect repository builds and Worker hosting Cloudflare website builds
Add runtime interactive widgets Embedding and styling

Choose what DynoStatic manages

Mode Where the visitor's page comes from How an edit becomes visible
Widget embed The host page plus DynoStatic's runtime widget Publish the widget; no host rebuild is normally needed for widget content
Headless website The site's own Astro or other static build Publish CMS content, deliver a build hook, fetch current publications, build and deploy
Native Site publishing DynoStatic's trusted static templates Create an immutable release/export, then deliver that artifact

An existing custom Astro design usually uses the headless mode. Runtime widgets can coexist with it. An editing workspace and an immutable publication capture are useful inputs, but neither automatically fetches later publications. A hook that rebuilds old local files does not create a live CMS connection.

Preserve and map the existing site

Inspect repository instructions, current edits and actual deployment configuration. Inventory the repository/branch, provider account, build command, output directory, routes, redirects, canonical URLs, structured data, locale variants, photographs, shared content, forms and dynamic handlers. Keep user-authored edits. Discover the real host account and deployment mode instead of inferring them from a project name.

Model each human-editable page as a Pages entry with meaningful content, image and SEO fields. Use the pages collection or the page collection selected in Site publishing. Repeated business data, navigation, services and testimonials can remain shared collections/singletons. A site registration or one large copy JSON field does not give editors a useful list of pages. Keep the frontend layout in code when the owner wants content and SEO editing without a section builder.

Declare every supported locale and preserve each localized route. Use native translation groups to link the same page across languages. Derive alternate links from those mappings, not from English path guesses. Preserve explicit display order, image alternatives and translation placeholders such as {city} or {year}. Resolve missing locale content deliberately before import.

Field keys use lowercase ASCII identifiers: map existing camelCase keys in both the import and frontend adapter. Disable native routes for data-only schemas when the frontend owns routing; cms.routes is then not a complete inventory of the external site's pages. Upload originals through supported media operations and retain real media identities and transfer hashes.

Use the existing visual/code editor for formatted text. Text fields declare editor: inline_html for short inline copy or editor: rich_html for block content. Leave plain strings plain. Match the frontend's allowed tags and attributes to the declared contract; do not globally decode entities or render every CMS string as HTML. Reuse DynoStatic's editor rather than adding an unrelated editor dependency.

Import safely through supported operations

Select the exact website and verify its identity. An Automation token manages resources; a Content API token reads build data. They are not interchangeable. Discover installed capabilities and granted actions first. Start with read access; use proposal or write scopes only for the operations needed and authorized.

Preview the inventory and mappings before importing. Use bounded changesets, revision preconditions, supported media uploads and normal publication operations. Discover exact commands and limits instead of guessing payloads. Never insert CMS table rows directly: revisions, publication snapshots, dependencies, audit history and queued events are part of the operation.

Make retries inert and refuse to overwrite later editor changes. When revisiting an imported site, start from its current publications, not the original seed. Verify substantial imports with isolated fixtures before writing live data. Defer enabling the build hook until bulk import completes. Follow the owner's existing deployment and backup instructions; maintenance access is not a routine integration prerequisite.

Organize translations beneath the source

Choose independent editing when humans maintain each language separately. Choose source-managed policies when target variants follow one authored source. The source language is configurable; do not assume English for every installation.

Before activation, link native translation groups and resolve unpublished target drafts. Classify fields as Translate, Copy from source or Keep locale-specific. Keep localized slugs/URLs; copy facts and media where appropriate. Preserve existing AI-written translations. Activation organizes existing variants without rewriting them or pretending their source revision is known.

In source-managed mode, editors work on source entries and see variants and update status beneath them. Publish the source, export queued requests, rewrite only the translation values, then import and publish the completed batch. Preserve all identities, hashes, supported HTML and placeholders. Re-export after a stale-state conflict. Do not bypass read-only generated variants with ordinary entry writes.

Manual and external AI rewriting use the same translation contract. This release does not execute translation-service APIs. Future provider adapters can fulfill that contract; documenting it does not configure a provider. Existing page translations remain published while refreshes are prepared. Website forms apply the stricter completeness rule described below.

Fetch current publications on every build

Use a private website-bound content:read token in the local protected environment and the host's build secrets. Never prefix it with PUBLIC_ or place it in browser JavaScript, generated HTML, URLs, logs or deployment receipts. Do not send browser Origin headers to the Content API.

The build adapter must:

  1. Fetch cms.manifest, verify its site_id against the configured website, and check the needed schemas/actions/locales.
  2. Read required singletons and every collection page for every required locale. Follow opaque cursors until exhausted; validate expected inventory, routes, ordering, field shapes, formatting, placeholders and media identities.
  3. Include published translation groups and any required cms.form responses. Fetch referenced media from the trusted same-origin Content API. Do not forward a bearer token to arbitrary media URLs or across redirects.
  4. Validate a complete candidate before replacing generated build input. Fail on missing credentials, HTTP errors, unpublished required content, duplicates, incomplete translations or inconsistent reads. Production must not silently fall back to migration seeds or yesterday's content.
  5. Run the fresh-content step in the actual host build command. If it is an npm prebuild step, use npm run build; invoking Astro directly bypasses it.

Content collections have best-effort pagination. A maximum content_version or a single ETag does not prove a multi-request atomic capture. Compare complete publication inventories/captures and refuse observed changes. This detects races but does not create transaction-wide snapshot semantics. Use a supported immutable release when an atomic snapshot is required.

Escape normal text and serialize JSON-LD with < escaped. Validate allowed formatting before using Astro set:html. Leave the last successful deployment serving when a new build fails.

Choose where images are served

An image URL in CMS content, or an embedded gallery, does not automatically become a Cloudflare asset. Choose and verify the delivery path:

  • Remote URLs: the page uses the published media URL and that URL's host serves the bytes. Keep the origin dependency explicit.
  • Build assets: download verified originals, optimize them during the site's build and deploy the outputs with the website. The website's asset host serves those bytes; CMS originals remain available for future edits/builds.

Use MIME/size limits, hashes and deterministic filenames for downloads. Remove unused generated images only after validating the new capture. For Astro, verify that generated imports include the downloaded directory. With Vite versions that skip hidden directories, a narrow glob with exhaustive: true is needed. Set both the primary image width and responsive widths; a srcset alone does not bound the fallback image. Check the actual emitted URLs, dimensions and file sizes.

Photo galleries support adding and ordering items. Connecting a gallery widget's ordered items to an external static build still requires a site adapter; widget catalog readiness is not a generic export API. Do not invent cms.gallery or claim every widget has a Content API equivalent. A CMS collection of image refs is another supported model for an Astro gallery. Native static exports have their own media options described in the CMS guide.

Let the widget manage fields and the website handle submissions

Select the contact widget's Website Worker mode when the site should retain its renderer, /api/contact, Turnstile, Resend/MXRoute or other existing transport. The widget supplies the published form definition; it does not move mail secrets or submissions into DynoStatic's inbox.

Follow the website's Pages languages. The builder displays inherited language names and a link to shared language settings; a separate comma-separated list is unnecessary. Without Pages, use the named source selector and target checkboxes. Edit the source form, publish, and complete its queued translation batches.

Fetch cms.form using content:read. Bundle the same complete definition and revision into the frontend and server validator. Share field keys, option values and validation rules; translate labels, help, captions and feedback, never visitor answers. Reject unsupported form features rather than silently dropping them. HTTP 409 form_translations_pending must fail the build and retain the previous deployment. An old browser revision must receive stale_form before provider calls.

Use the form contract and its dependency-free runtime example. Validate server-side before spam checks and sending mail. Keep provider credentials in Worker runtime secrets. Verify failure paths with mocked delivery; sending real contact messages is a separate authorized action.

Prove automatic publishing

The complete path is publish → queued webhook → delivery → host build → fresh CMS capture → deployment → public result. Configure the selected website's hook for required content publication, removal, translation, schema and media events. Read the installed event catalog and subscribe to changes consumed by the adapter. For Cloudflare-specific steps, use Cloudflare website builds.

Verify a functioning job runner. The optional probabilistic web runner is best-effort; a hosting cron running bin/dynostatic cron is recommended for timely delivery. A successful hook response proves delivery, not a completed build. Check the provider's final result and the public artifact. A credential-free receipt with fetch time, publication digest and form revision can make this proof inspectable without exposing tokens or content bodies.

Before completion, verify editable Pages, source/target organization, locale routes and SEO, representative desktop/mobile rendering, built images and existing form behavior. Exercise safe import retries and refusal of later-edit overwrites when an import is involved. Use focused checks appropriate to the change.

Report separately what is imported, built locally, deployed, and proven to update automatically. Record concrete remaining provider access, cron or DNS work. Keep a site-specific conversion log with mappings, configuration names, validation and open items. Product defect history belongs in the product log, not in reusable instructions that tell every future site to patch the CMS.