{"id":10442,"plugin_id":"plugin_asdk_app_69fe16bb7a048191af54574d5986aab2","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T22:57:11.939Z","digest":"6f176ec5a4367bfbb5f5fd0a8845e278b2d59ad0e0e81b6b8875d4925e958199","against":null,"payload":{"name":"staging-redesign","description":"Build a BrightSite redesign or large change safely on a staging site, preview it, then promote it live in one atomic flip — instead of editing the live site directly. Use when the user wants a \"staging site,\" \"redesign safely,\" \"build a new version without breaking the live site,\" \"preview before it goes live,\" \"rebuild the homepage,\" \"flip the whole site at once,\" \"a safe place to work,\" or is doing a full visual rebuild (new fonts/layout/multiple pages) they don't want visitors to see until it's ready. For per-entity staged edits on the live site (a single page's unpublished draft), the normal `*_staged` + `publish_page` flow is enough — use this skill only when you want a full isolated copy.","included_files":[],"skill_md_contents":"---\nname: staging-redesign\ndescription: Build a BrightSite redesign or large change safely on a staging site, preview it, then promote it live in one atomic flip — instead of editing the live site directly. Use when the user wants a \"staging site,\" \"redesign safely,\" \"build a new version without breaking the live site,\" \"preview before it goes live,\" \"rebuild the homepage,\" \"flip the whole site at once,\" \"a safe place to work,\" or is doing a full visual rebuild (new fonts/layout/multiple pages) they don't want visitors to see until it's ready. For per-entity staged edits on the live site (a single page's unpublished draft), the normal `*_staged` + `publish_page` flow is enough — use this skill only when you want a full isolated copy.\n---\n\n# Build a Redesign on a Staging Site, Then Promote\n\nA **staging site** is a full, independent, editable copy of the live site's content\n(pages, layouts, components, forms, blog, media, global CSS/JS, Tailwind config, site\nidentity, redirects) that lives under the same account. You build the redesign on it\ninvisibly, preview it at a gated subdomain, then **promote** it — one atomic flip that\nmakes the staging content live and archives the old live site (restorable). Account-level\ndata (custom domain, analytics, form submissions, team, billing, tracking IDs) is shared\nand never touched by a promote.\n\nUse this instead of editing the live site directly whenever the change is big enough that\nyou don't want visitors seeing a half-finished state, or you need to flip several entities\n(global code + a layout swap + N pages) at the same moment.\n\n## When to use this vs. the normal staged-fields flow\n\n| Situation | Use |\n|---|---|\n| One page's copy tweak, a new draft page, a blog post | Normal flow: `update_page` writes `*_staged`, `publish_page` ships it. Live stays as-is until you publish. |\n| Full redesign, new global fonts/layout, multi-page rebuild, \"flip it all at once\", \"let me preview the whole thing first\" | **This skill** — a staging site. |\n\nThe staged-fields flow only stages *content* fields (`heex_staged`, `css_staged`, …).\nStructural fields — `layout_id`, `slug`, `status`, `is_home_page`, `meta_*`, and anything\n`update_site_identity` sets — take effect on the **live** site immediately, with no staged\nvariant. A staging site stages *everything*, which is why it's the right tool for a rebuild.\n\n## Key mechanic: the `site` param\n\nEvery content tool (`create_page`, `update_page`, `update_layout`, `update_global_code`,\n`create_component`, `request_upload`, `update_site_identity`, `list_pages`, `get_page`, …)\ntakes an optional **`site`** param:\n\n- **omitted** or `\"live\"` → the live site (default, backwards-compatible).\n- `\"staging\"` → the account's staging site.\n- an explicit **site ID** (from `list_staging_sites`) → that specific site, as long as it's\n  **active** (`live` or `staging`). Archived sites (rollback snapshots) are rejected —\n  they're immutable history; `restore_staging_site` first if you need to edit one.\n\nAuthorization is still by `account_id` — you must be a member of the org, and the target\nsite must belong to it. Passing a staging site ID as `account_id` does **not** work (it's a\nsite, not an account); always pass `account_id` = the org and select the site with `site`.\n\n## Workflow\n\n### 1. Create the staging site\n\n```\nmcp__brightsite__create_staging_site { account_id: \"<ORG_ID>\" }\n  → { id, name, slug, type: \"staging\", preview_url, ... }\n```\n\nThis clones the live site synchronously (content + media). It is **plan-gated** — it fails\nwith a \"plan\" / \"limit\" message if staging isn't on the account's plan or a staging site\nalready exists. If one already exists, either reuse it or `discard_staging_site` first.\n\nKeep the returned `id` and `preview_url`. You can also fetch them any time with\n`mcp__brightsite__list_staging_sites` or `mcp__brightsite__get_staging_status`.\n\n### 2. Author into staging — pass `site: \"staging\"` on every write\n\nBuild the redesign exactly as you normally would, but add `site: \"staging\"` (or the site\nID) to each call. The live site is untouched.\n\n```\nmcp__brightsite__update_global_code { account_id, site: \"staging\", css_staged: \"...\", tailwind_config_staged: \"...\" }\nmcp__brightsite__update_layout      { account_id, site: \"staging\", id: \"<layout_id>\", heex_staged: \"...\" }\nmcp__brightsite__create_page        { account_id, site: \"staging\", title, slug, heex, params_schema, ... }\nmcp__brightsite__request_upload     { account_id, site: \"staging\", file_name, content_type }  # media lands on staging\n```\n\nIf you're building editable content, load the **visual-editor-authoring** skill and apply\nit — `site: \"staging\"` composes with everything there.\n\n> Reads honor `site` too. `list_pages`/`get_page` with `site: \"staging\"` show the staging\n> copy; without it, they show live. Use this to diff-by-eye or verify your writes landed.\n\n### 3. Preview before promoting\n\nThe staging site is served at its own gated subdomain — the `preview_url` returned by\n`create_staging_site` / `list_staging_sites`. Open it (or screenshot it) and confirm the\nredesign looks right. Tracking (GA/GTM/Pixel) is suppressed on staging previews, so you\nwon't pollute analytics.\n\n### 4. Review the diff\n\n```\nmcp__brightsite__staging_diff { account_id: \"<ORG_ID>\" }\n  → { has_changes, totals: {added, modified, removed}, by_type, drift }\n```\n\n`drift` = live items that were edited *after* the staging copy was made — a promote would\noverwrite them with the staging version. If `drift` is non-empty and you didn't intend it,\nreconcile before promoting (re-apply that live edit on staging, or accept the overwrite).\n\n### 5. Promote (atomic flip)\n\n```\nmcp__brightsite__promote_staging { account_id: \"<ORG_ID>\" }\n```\n\nRuns in the **background**: it validates the staging content and takes a full backup of the\ncurrent live site first, then flips `live_site_id`. It returns immediately with\n`status: \"promoting\"`. **Poll `get_staging_status`** until the staging site is gone and the\nlive site is the former staging site.\n\nThe previously-live site is archived and restorable:\n\n```\nmcp__brightsite__restore_staging_site { account_id }                    # undo the last promotion\nmcp__brightsite__restore_staging_site { account_id, site_id: \"<archived_id>\" }  # restore a specific archived site\n```\n\n### 6. (Optional) Discard instead of promoting\n\nIf the redesign is abandoned:\n\n```\nmcp__brightsite__discard_staging_site { account_id }   # permanently deletes staging content + media, frees the slot\n```\n\n## Anti-patterns to avoid\n\n- **Passing the staging site ID as `account_id`.** It's a site, not an account —\n  authorization is by org. Always pass `account_id` = the org and select the site with the\n  `site` param. (`account_id: \"<staging_site_id>\"` returns \"Access denied\".)\n- **Forgetting `site: \"staging\"` on a write during a redesign.** The call silently targets\n  the LIVE site (that's the default). If a change you meant for staging shows up in\n  `staging_diff` as live `drift`, you wrote to the wrong site — reverse it and redo with\n  `site: \"staging\"`.\n- **Using a staging site for a one-line copy fix.** Overkill. Use `update_page` +\n  `publish_page` on the live site instead.\n- **Promoting without previewing.** Always open the `preview_url` (or screenshot it) and\n  run `staging_diff` first — a promote flips the public site.\n- **Assuming promote is instant.** It's backgrounded (it backs up live first). Poll\n  `get_staging_status` to confirm; don't report \"done\" off the immediate `\"promoting\"`.\n- **Expecting analytics/form submissions/tracking IDs to move.** They're account-level and\n  shared — a promote never touches them. Only site content moves.\n\n## MCP tools used\n\n- `mcp__brightsite__create_staging_site` — clone live → new staging site (plan-gated, sync).\n- `mcp__brightsite__list_staging_sites` / `mcp__brightsite__get_staging_status` — find the\n  staging site ID + `preview_url`; check whether one exists.\n- `mcp__brightsite__staging_diff` — added/modified/removed counts + `drift` vs. live.\n- `mcp__brightsite__promote_staging` — flip staging → live (background; poll to confirm).\n- `mcp__brightsite__restore_staging_site` — undo a promotion / restore an archived site.\n- `mcp__brightsite__discard_staging_site` — delete the staging site and its content.\n- Every content tool (`create_page`, `update_page`, `update_layout`, `update_global_code`,\n  `create_component`, `update_component`, `request_upload`, `update_site_identity`, …) with\n  the optional `site` param to target `\"staging\"` (or a site ID) instead of live.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}