add_component_variant
ChatGPTPlan (default) or apply adding a variant dimension and/or a named preset to a component's .weblooks.json sidecar. Dimensions map to same-named enum/boolean params; the merged result is validated against the interface before any plan is produced.
add_native_field
ChatGPTAdd a field to an EXISTING native-CMS collection without touching its entries: new fields are optional by construction, so all existing entries stay valid and published. This replaces the old delete-collection-and-rebuild workaround. Field types as in create_native_collection; localized:true stores per-locale values.
attach_managed_domain
ChatGPTConnect ONE exact hostname to a Weblooks-managed project. SIDE EFFECT: reserves the hostname for this project and QUEUES creation of its Cloudflare custom hostname and certificate, which the scheduled provisioning pass performs (refresh_managed_domain runs a pass now). Attaching a hostname the project already has is refused as a duplicate (409), so a repeat never creates a second connection. Returns required: the DNS records, each tagged purpose routing or ownership. The ownership (validation) records arrive once provisioning has run and do NOT move traffic, so publish them as they appear. The routing records are included from the start, but publishing them IS the cutover, so hold them until preflight_managed_domain passes. For a ROOT domain the plain A/AAAA addresses come back as apexIps, so providers that cannot store an apex CNAME (Loopia, GoDaddy, one.com) work fine. BE AWARE that when this hostname eventually reaches active, it starts serving immediately: a domain with no release pin yet inherits its siblings' pin, or the CURRENT LIVE BUILD if it has none. Check what staging is holding before you attach a domain to a project with unreviewed work on it. Next: publish the validation records, then refresh_managed_domain.
cancel_deployment
ChatGPTCancel a deploy that is queued, running, or stuck pending. A running deploy stops at its next heartbeat (within ~30s). Cannot cancel a deployment that is already live or failed.
cancel_scheduled_publish
ChatGPTCancel the project's pending scheduled publish. Nothing will fire at the scheduled time. If the schedule has ALREADY fired, the publish is in flight. Stop that with cancel_deployment instead. Returns 404 when nothing is scheduled.
configure_deploy_target
ChatGPTCreate or update a project's portable-deployment target (Cloudflare Pages). Records the provider, production branch, and build settings, replaces the environment-variable NAMES when env is passed (never values: secrets are entered at the provider), and with write_doc=true also writes the advisory weblooks.deploy.json + DEPLOYMENT.md recipe into the project: TWO commits (one per file) on the DEFAULT branch of a GitHub project, or an overwrite with no history on an uploaded-folder project. Weblooks stores no provider credentials. Set status="connected" when guided setup is complete. SIDE EFFECT, ONE-WAY: once a project has a target, whatever its status, a push to its default branch no longer triggers a Weblooks staging deploy (the user's own host is meant to deploy from the repo instead), so a commit reaches staging only when something else starts a deploy, such as the deploy tool. No tool removes a target.
configure_plugin
ChatGPTEnable, disable, or configure one front-end library plugin (Swiper, GSAP, Three.js, Lottie or AOS) in the project’s weblooks.plugins.json. Pass enabled:false to turn a library off. options carries library-specific settings (sanitised server-side to the plugin’s schema). Only the fields you pass are changed; the rest are kept. Use get_plugins for valid ids and current config. There is NO branch option: on a GitHub project every call is ONE commit to the DEFAULT branch, which triggers a deploy through the push webhook; on an uploaded-folder project the file is overwritten with no history.
convert_native_asset
ChatGPTRe-encode and/or downscale a native-CMS asset IN PLACE, keeping its id: every binding and its alt text survive (re-uploading instead would mint a new id and break both). format omitted = keep the current format (pure resize/recompress); max_width caps the width and NEVER upscales; the next deploy regenerates variants from the new bytes automatically. Returns before/after size, dimensions and content type. Refused for animated images and SVG.
create_asset_folder
ChatGPTCreate a folder in the native-CMS asset library (intermediate levels are created too: photos/gallery/2026 makes all three). Folders are ORGANISATIONAL METADATA ONLY: they never appear in a published URL, a data-cms binding, or page markup, so nothing in a deployed site can depend on them. Idempotent: creating an existing folder returns it with created: false. Paths are a/b/c form: no leading/trailing slash, no '..', max depth 8.
create_branch
ChatGPTCreate a new branch from an existing one (defaults to default branch)
create_cms_entry
ChatGPTCreate a new entry in a CMS collection. data is the field payload (names from get_cms_schema), sent to the provider as is. On Shopify this creates the item in the live store.
create_component
ChatGPTCreate a component definition at components/<name>/<name>.html. content must contain a <wl-interface> block declaring every param, then the markup. On a GitHub project the new file is ONE commit, and a commit to the default branch triggers a deploy through the push webhook; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project it is saved to Weblooks storage with no commit and no deploy; uploaded projects refuse branch.
create_native_collection
ChatGPTCreate a collection in the native Weblooks CMS, optionally with its full field schema in the same call. Pass fields[] so entries can be created immediately (without it the collection is field-less and every create_native_entry is rejected as "unknown field"). Returns the collection and its persisted fields[].
create_native_entries
ChatGPTCreate UP TO 50 entries in ONE native-CMS collection in one call: the way to seed a site's content (a 32-entry seed used to cost 32 round trips). PARTIAL FAILURE IS PER ITEM, never all-or-nothing (the ingest_native_assets_from_urls contract): returns results[] in the order given, each { index, ok, entry?, error?, code?, field? }, plus succeeded / failed counts. Successful items are committed even when others fail, so retrying only the failed items is always enough. Each item's data is validated against the collection schema exactly like create_native_entry; publish applies to the whole batch (never per item: a per-item publication is refused), and a published batch queues a staging deploy exactly as create_native_entry does. RETRIES: give each item an idempotency_key (any stable per-row string, e.g. a source-row id) and a retry is EXACT: an item whose key already created an entry comes back as that entry with replayed:true instead of a duplicate, so re-sending the WHOLE batch after a lost response is safe. Without keys there is no dedupe: if the call itself errors with no results[], re-sending duplicates the committed items, so call list_native_entries first.
create_native_entry
ChatGPTCreate ONE entry in a native Weblooks CMS collection. For several at once, create_native_entries does the same work in one call. data is validated against the collection schema; note that a plain text field renders LITERALLY (HTML entities such as & are rejected on write, so store the character itself), while richtext stores HTML. Entries are DRAFTS by default and only PUBLISHED entries appear on the rendered site and in the editor canvas preview. Pass publish:true to create it already published (the common case when populating content programmatically). Creating it published also QUEUES A STAGING DEPLOY when the project has staging and auto-deploy on publish is on (the default), so the entry goes live on the staging site without a separate deploy call; custom domains keep their released build until release_to_domains. A draft queues nothing.
create_page
ChatGPTCreate a new HTML page. PASS THE PAGE YOU WANT. With neither html nor content, this writes a placeholder stub (an empty <h1>) and reports success, which is how stub pages reach production. On a GitHub project the new page is ONE commit, and a commit to the default branch triggers a deploy through the push webhook; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project it is saved to Weblooks storage with no commit and no deploy, reaching the site at the next deploy; uploaded projects refuse branch.
create_project
ChatGPTCreate a new Weblooks project. THREE modes: (1) template="minimal"|"marketing": Weblooks mints a fresh PRIVATE GitHub repo in the user's account, seeds it with starter files, and links it (Sync plan, requires connected GitHub). This is the recommended path for "build me a site from scratch" requests. (2) source="github" with githubOwner+githubRepo: link an existing repo (Sync plan). (3) Omit both: an empty project stored by Weblooks, no GitHub needed (Sync plan). It is seeded with the minimal starter page so it opens with something to edit, and returns { projectId, files }; url is recorded if given. SIDE EFFECT in both GitHub modes: Weblooks also installs a push webhook on that repository (best effort; it needs admin access to the repo), so from then on every push to its default branch triggers a deploy. Next: call get_project_status, which ranks the steps from here (run the launch checks, build the pages, publish with deploy).
create_redirect
ChatGPTAdd ONE redirect rule. For more than a handful, use set_redirects instead: it is one write for the whole table rather than one per rule.
delete_asset_folder
ChatGPTDelete a native-CMS asset folder. REFUSES by default while the folder (or any descendant) still holds assets, telling you how many; pass strategy 'move_to_root' to move those assets to the library root instead. The response reports what moved. Deleting a folder never deletes assets and never changes a published URL.
delete_branch
ChatGPTDelete a branch (refuses to delete the default branch)
delete_cms_entry
ChatGPTDelete a CMS entry by id. On Shopify this deletes the item from the live store.
delete_component
ChatGPTDelete ONLY the definition file components/<name>/<name>.html. There is NO in-use check: any page still instantiating the component will FAIL the next deploy, so run list_component_instances first. A leftover components/<name>/<name>.css or .js also fails every later deploy (a stylesheet or script needs a matching definition), so remove those with delete_file too. On an uploaded-folder project the deletion is permanent. Pass branch to commit on a feature branch.
delete_component_variant
ChatGPTPlan (default) or apply removing a named preset. REFUSED while any page still references the preset, while it is the default, or while another preset extends it. Migrate those first.
delete_file
ChatGPTDelete ONE file from the project. On a GitHub project this is a deletion commit: on the default branch it triggers a deploy, and the file can only come back by restoring it from git history (pass branch to delete on a feature branch instead). On an uploaded-folder project the deletion is PERMANENT: there is no history and no undo, and uploaded projects refuse branch.
delete_native_asset
ChatGPTDelete a native-CMS asset permanently (bytes and metadata). REFUSED while CMS entries still reference the asset: published pages bind it by id through those entries, so deleting would 404 them at the next deploy; the refusal names the referencing collections and entries. Pass force:true to delete anyway. The response then reports exactly what will break. Prefer unbinding (update the entries) first.
delete_native_collection
ChatGPTDelete a native Weblooks CMS collection, cascading its fields and entries. Irreversible: any data-cms bindings to its slug on published pages stop resolving.
delete_native_entry
ChatGPTDelete a native Weblooks CMS entry by id, PERMANENTLY: its saved version history is deleted with it and there is no undo. Every delete, of a draft or a published entry, also QUEUES A STAGING DEPLOY when the project has staging and auto-deploy on publish is on (the default), so a published entry and any page generated from it leave the staging site; custom domains keep their released build until release_to_domains.
delete_native_field
ChatGPTDelete a native-CMS field by its UUID. REFUSED (nothing written) when entries hold data in the field unless confirm:true is passed. The refusal names how many entries would lose data. Published data-cms bindings to the field render their fallback afterwards.
delete_redirect
ChatGPTRemove one redirect rule by id. To disable a rule without losing it, use update_redirect with enabled=false.
deploy
ChatGPTPublish the site to STAGING on Weblooks managed hosting: the deployment goes live at <slug>.weblooks.site only. Connected custom domains keep serving their released build until you call release_to_domains: two-tier by design, so you can verify on staging first. Verify with get_deployment or by fetching the staging URL, NOT by loading the custom domain: it will still show the previous build, and that is correct, not a failed deploy. TWO THINGS DO GO LIVE ON CUSTOM DOMAINS WITHOUT release_to_domains: schedule_publish (its promise is "live at that time"), and a domain REACHING ACTIVE for the first time: a newly attached hostname with no release pin yet inherits its siblings' pin, or the current live build if it has none, because an "active" domain serving nothing would read as an outage. So attaching a domain to a project whose staging holds unreviewed work publishes that work. Pass wait:true to hold the call until the publish finishes (up to ~25s) and get the final status in one round-trip; without it you get a job id to poll with get_deployment. The response lists the staging hostname plus releaseTargets (the custom domains a follow-up release would update). If a build is already RUNNING, this publish is queued behind it (behind names that job); if a follow-up is already QUEUED, this request coalesces onto it (deduped: true, coalesced: true) and that one build reads the newest commit. Never a 409, never a third build.
deploy_to_vercel
ChatGPTDeploy the project to Vercel (production by default). Requires a Vercel connection in Workspace Settings → Production hosting. Runs the component-expansion and CMS render stages before upload (same as staging deploys), so <wl-use> and data-cms markup ships rendered; a component validation error fails the deploy with a 422 naming each issue.
disable_managed_domain
ChatGPTDESTRUCTIVE: stops this hostname serving, so the site becomes unavailable on it. The Cloudflare hostname and certificate are RETAINED, but NOTHING turns a disabled domain back on today: retry_managed_domain accepts only failed domains, and the app has no re-enable action either. Serving the site on this hostname again means release_managed_domain and attaching it afresh, which issues a new certificate. Requires confirm_hostname to equal the domain exactly. Use this to take a site offline; use release_managed_domain only to give the hostname up entirely.
disconnect_cms
ChatGPTDisconnect the project's OWN external CMS connection (e.g. remove Payload after migrating to the native Weblooks CMS). Irreversible; deletes the stored connection. removed is false when the project had no connection of its own, so nothing changed. It never removes a workspace-level connection, and the CMS tools fall back to one when it exists: effective in the response is what they use from now on, and null means no external CMS is left. If effective is not null, tell the user the CMS tools still reach that workspace connection. Connecting a CMS stays UI-only because it handles secrets.
generate_sitemap
ChatGPTWrite a real sitemap.xml into the project's files, REPLACING any existing one, a hand-written one included: every page, xhtml:link hreflang alternates for locale siblings (en/about.html ↔ sv/about.html), and on a GitHub project lastmod from each file's last commit (an uploaded-folder project keeps no history, so its entries carry no lastmod). Pages carrying a noindex robots meta, draft pages and pages flagged password-protected with set_page_protection (whatever the protection scope) are excluded, and every exclusion is reported with its reason so a missing URL is never a mystery. Emits NO changefreq and NO priority, because search engines ignore both. REFUSED when the project has no active custom domain: there is no correct absolute URL to write, and the staging host is deliberately noindexed. The deploy generates a minimal flat sitemap by itself when the project has none; this is the richer one, and being a project file it wins from the next deploy on. On a GitHub project the save is ONE commit, and a commit to the default branch triggers that deploy through the push webhook; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project the file is overwritten with no history and nothing deploys until the next deploy; uploaded projects refuse branch. x-default alternates follow the registry's x_default (set_project_locales), and a root-locale page (nyheter.html with <html lang="sv">) pairs with its prefixed sibling (en/nyheter.html). For a project with an enabled collection route the file carries <!-- weblooks:collection-urls -->, which every deploy replaces with one <url> per generated page (lastmod = the entry's change date); bracket templates themselves are never listed.
get_alt_text_issues
ChatGPTScan all HTML files for missing or incorrect alt text
get_build_guidelines
ChatGPTWeblooks' best-practice guide for building sites, by topic. With no topic: the core rules every page follows (tokens, accessibility, metadata, components first, fluid units, container queries, reserved paths) and the main workflows, plus an index of topics. With topic: one chapter (site-structure, components, css, responsive, sections, interactive, cms-modelling, cms-binding, assets, search, forms, performance, hosting), or "all" for every chapter at once. Call it BEFORE building or restructuring pages, and with the matching topic before working on that part (for example topic "cms-modelling" before creating collections, "site-structure" before planning pages). Pass an optional project_id to also get STACK-SPECIFIC guidance for that project (its framework, styling system, and component model: where style edits should go and what can't be moved).
get_canonical_host
ChatGPTThe project's canonical hostname, if set, plus every active domain and which of them are currently being redirected. Read this before set_canonical_host to see what the change would affect.
get_cms_connection
ChatGPTGet the project's external CMS connection metadata (Payload, Strapi, Sanity and the rest). Never returns secrets. connection is the project's OWN connection, or null if it has none. effective is the connection the CMS tools (list_cms_collections, list_cms_entries and the rest) actually use: scope "project" for the project's own, scope "workspace" for a workspace-level connection they fall back to when the project has none, or null when there is no external CMS at all. A null connection does not mean the CMS tools are unavailable; read effective.
get_cms_entry
ChatGPTGet a single CMS entry by id
get_cms_schema
ChatGPTDescribe the fields on a CMS collection
get_collection_route
ChatGPTOne collection route, by its template path, as stored on the project's DEFAULT branch (a route set on a feature branch is not visible here). Reports the collection, slug field, filter, sort, noindex_filter, enabled flag and whether the template file actually exists. Read this before set_collection_route so an edit does not silently drop a filter.
get_component
ChatGPTGet one component definition's full source (interface + markup). Path is components/<name>/<name>.html. Read live, never a cached copy: if GitHub cannot be reached it answers 503, so try again in a minute.
get_component_asset
ChatGPTRead a component's co-located stylesheet or script: components/<name>/<name>.css or .js. Read live, never a cached copy: if GitHub cannot be reached it answers 503, so try again in a minute.
get_component_capabilities
ChatGPTReport the detected component adapters and what each can SAFELY do, before any mutation is requested. Key actions off these capability booleans, never off adapter ids. The HTML adapter lists every plan/apply operation the engine supports, but only four are tools here: add_component_variant, update_component_variant, delete_component_variant and instantiate_component. Creating, updating or deleting a whole component has no plan step: create_component, update_component and delete_component write the definition file directly.
get_consent_banner
ChatGPTWhether this project ships the BUILT-IN Weblooks cookie-consent banner, plus its configuration (locale fallback, offered purposes, copy overrides, Google Consent Mode wiring as effectiveMode) and the policy version consent is recorded against. Weblooks HAS a GDPR consent system: a banner that keeps non-essential scripts from running until the visitor chooses, and an append-only consent log holding the Art. 7(1) evidence, so do NOT hand-roll one, and do NOT hand-write gtag('consent', …) calls: the mode setting emits them. Read this before set_consent_banner.
get_css_variables
ChatGPTExtract all CSS custom properties from a project
get_deploy_readiness
ChatGPTScan a project's source (GitHub repo OR uploaded source, both work) for portable deployment to a host the USER owns (Pattern 1). Returns the detected framework + build settings, a recommended provider (Cloudflare Pages by default; Shopify Hydrogen → Oxygen), the environment-variable NAMES the site needs, any connected CMS/storage, and warnings. Read-only. Paid Sync only.
get_deploy_target
ChatGPTGet the current portable-deployment target for a project (provider, production branch, build settings, status, live URL, last verification) plus its environment-variable requirements. Returns target=null if hosting has not been set up.
get_deployment
ChatGPTGet deployment status, queue stage, attempts, heartbeat timestamps, commitSha (the commit the build read), and metadata, including cms.warnings, cms.optionalUnresolved and seo.urlCount.
get_hsts
ChatGPTThe project's HSTS opt-ins, the exact header the edge is sending, and (the reason to call this first) would_bind: the apex domains whose ENTIRE subdomain tree include_subdomains would commit to https for a year. Read this before set_hsts.
get_managed_domain_status
ChatGPTONE managed domain: its stored status, certificate state, the DNS records the customer must publish and the failure reason, plus a LIVE DNS lookup made on every call: observed (what the hostname resolves to right now, against the Weblooks target) and pending (what is not satisfied yet), with dnsError when the lookup fails. Changes nothing and makes no Cloudflare call; call refresh_managed_domain to reconcile with Cloudflare now. Accepts the hostname or the domain id.
get_metadata
ChatGPTGet SEO metadata for a page
get_my_permissions
ChatGPTWhat YOU may do, as the person this credential acts for. Without project_id: your workspace role. With project_id: your role on that project, the exact capability list, and whether this project requires you to confirm changes before write tools run (confirmRequired). Call this when a tool was refused, or before a batch of edits, instead of discovering limits one 403 at a time. The response also carries server: the running release plus toolManifestHash/toolCount for the tool list this server would serve you RIGHT NOW: if toolCount differs from the number of tools in your own list, your session's manifest is stale (a deploy landed after your client cached it), so tell the user to reconnect the MCP server rather than concluding a tool does not exist.
get_native_asset
ChatGPTRead a native-CMS asset's BYTES, base64-encoded, along with its contentType and size. Use list_native_assets to find the id. Pass include_content:false to get contentType and size WITHOUT the base64 body. Always do this when you only need to confirm the asset exists or check its size.
get_native_entry
ChatGPTGet a single native Weblooks CMS entry by id. data is what an editor sees: on a published entry with unsaved-to-the-site edits (hasUnpublishedChanges: true) it is the working copy, and publishedData holds the values the site serves. version is the value to pass as expected_version to update_native_entry.
get_page_source
ChatGPTRead the current text of ONE project file by path. Any text file works, not only HTML pages: CSS, JS, JSON, XML, SVG, robots.txt. Binary files (images other than SVG, fonts, PDF, audio, video, archives) come back as { binary: true, ext } with no content. Read live, never a cached copy: if GitHub cannot be reached it answers 503, so try again in a minute.
get_plugins
ChatGPTList the front-end library "plugins" Weblooks detected in a project (Swiper, GSAP, three.js, Lottie, AOS …) with each one's CONFIGURED defaults from the project's weblooks.plugins.json. When you write code that uses one of these libraries, HONOR the configured version + options (e.g. Swiper loop/autoplay/slidesPerView, GSAP ease/duration/stagger, Lottie loop/speed, AOS duration/easing) instead of inventing your own: that's what the user set in the Plugins panel.
get_project
ChatGPTGet details for a specific project, plus YOUR role and capabilities on it (yourRole, yourCapabilities), so you can tell before calling a tool whether it will be refused. url is the LIVE production URL (a connected custom domain when one is active). hosting says how the site is served: state (live | domain_pending | staging_only | not_published), liveUrl, canonicalHost, stagingUrl, and every attached custom domain with its status, certificate and the build it serves. Publishing is two-tier: staging (stagingDeploymentId) and each domain's releasedDeploymentId may legitimately differ. behindStaging: true means a release is pending, NOT that the domain is disconnected. A domain with status: 'active' IS connected and verified; do not report otherwise. The project's own status column (draft/live/review) is a workflow label and says nothing about whether a domain serves.
get_project_config
ChatGPTGet a project’s effective configuration: storage bucket + public base (own override or workspace default), storage readiness, and Vercel project id. Read this before update_project_config or before a deploy that needs storage.
get_project_locales
ChatGPTThe project's LOCALE REGISTRY: which locales localized content may use, the DEFAULT the renderer falls back to, and the X-DEFAULT that collection-page hreflang links and generate_sitemap advertise as the language-neutral page. READ THIS BEFORE ANY LOCALIZED WORK: the registry defaults to ['en'] at provisioning, every localized write (entry values, asset alt maps) validates against it, and the renderer resolves each page's <html lang> against it: a lang the registry doesn't contain silently renders the DEFAULT locale, which is how an <html lang="sv"> site ships entirely in English. Returns { projectId, status, defaultLocale, xDefault, locales, settings, shard }, where settings holds one entry per locale: { hreflang (the tag emitted for it, e.g. sv-SE), published (false = a DRAFT locale: its collection routes generate no pages and nothing links to it with hreflang), displayName }.
get_project_status
ChatGPTWhere this project stands and what to do next, in order. Built for someone new to building websites: call it at the start of a session, after create_project, whenever the user asks what to do next, and after each fix or deploy to see what changed. Returns stage (check, publish, launch, handoff, launched or handed_off), a one-sentence summary to repeat to the user, milestones (readyForReview, readyToLaunch, handedOff), and nextSteps, ranked: each has a plain-language why, the tool to call first with suggested args (null when only a person can do it, in the editor panel named by panel), and blocking (true when it stands between the project and launch). Also returns the launch checklist and the hosting summary it was built from, so it never disagrees with get_project or the domain tools. Read-only; needs edit access to the project, like the launch checklist in the editor. On a plan without the full checklist only the launch checks are assessed (limited: true) and the first step says what the plan lacks.
get_pull_request
ChatGPTEverything needed to answer "is it safe to merge this?" in ONE call: mergeability, review decision, CI checks, and a safeToMerge verdict with a blockers list naming anything in the way. Call this BEFORE merge_pull_request. mergeable: null means GitHub has not finished computing it yet: that is UNKNOWN, not "no"; call again in a moment. safeToMerge is null in that same case.
get_robots
ChatGPTThe project's robots.txt and WHERE it comes from. source is "repo" (a robots.txt in the project's own files, which wins on every domain and means the platform does not manage it), "generated" (no repo file, so the deploy writes a permissive one pointing at the canonical host), or "none" (no repo file AND no active custom domain, so /robots.txt 404s). precedence says the same thing in a sentence. It reads the project's files, not the live site, so it describes what the NEXT deploy serves. The bytes do NOT differ between <slug>.weblooks.site and a custom domain serving the same build: staging is noindexed by an X-Robots-Tag HEADER instead, because a blocked crawl never sees a noindex and would leave staging URLs indexed but uncrawlable. Read live, never a cached copy: if GitHub cannot be reached it answers 503, so try again in a minute.
get_scan_results
ChatGPTGet the latest scan results. Pass category to read that one category; omit it to read every category plus a summary (overall launch verdict, and the blocking categories that are failing, warning or not scanned yet). Each category has counts by severity and blocking (true for the nine that gate launch). Each warn or fail finding the server knows how to fix carries fix: the tool to call first (null when only a person can do it), any then tools in order, the editor panel, and how, one plain sentence. Passing findings are left out of the lists unless include_passed is true; the counts still include them. A category that has never been scanned reports status "idle" with no findings (call run_scan first). An unknown category is refused with the list of valid ones.
get_site_protection
ChatGPTRead the site's password protection: { scope: 'off'|'site'|'pages', hasPassword, entitled, protectedPages }. protectedPages are the pages flagged with set_page_protection. Never returns the password or its hash.
ingest_asset_from_url
ChatGPTFetch a file from an https URL server-side and save it INTO THE PROJECT'S SOURCE REPO at a path you choose, so an ordinary <img src="/assets/gallery/hero.jpg"> works with no binding. The bytes never pass through your context, so migrating a whole media library costs about as much as one sentence. CHOOSING BETWEEN THE TWO INGEST TOOLS: use THIS one when the page references the file by PATH; use ingest_native_asset_from_url when the image belongs in the CMS Assets library and the page resolves it by id through a data-cms binding. Picking wrong puts the bytes somewhere the markup cannot see them. This tool does NOT edit any page: compose it with update_page_source or instantiate_component as separate steps. path is repo-relative (no leading slash, no ..) and its extension must match what the URL actually serves; a mismatch is refused rather than silently renamed, because your markup is already pointing at the path you chose. A file already at path is OVERWRITTEN without warning. In the repo (the default destination), a GitHub project gets the file as a commit, and a commit to the default branch triggers a deploy (pass branch to write to a feature branch), while an uploaded-folder project saves it to Weblooks storage with no history, so an overwritten file cannot be recovered. Accepts images, SVG (sanitised on the way in), video, audio, fonts, PDF and zip, up to 25 MiB. The URL must be https and resolve to a public address. Private, loopback and cloud-metadata addresses are refused, including via redirect. Requires a paid Weblooks plan.
ingest_assets_from_urls
ChatGPTFetch UP TO 20 URLs server-side and save them into the project's SOURCE REPO: the way to migrate a site's images off an old CDN in one call. Same rules, security and path handling as ingest_asset_from_url, including that a file already at a path is OVERWRITTEN. On a GitHub project EACH file is its own commit, so a batch on the default branch is up to 20 commits, which the deploy queue coalesces rather than building once per file. PARTIAL FAILURE IS PER ITEM, never all-or-nothing: returns results[] in the order given, each { url, path, ok, key?, assetUrl?, provider?, error?, code? }, plus succeeded / failed counts. Successful items are committed even when others fail, so retrying only the failures is always enough. Two items may not target the same path, since that would race and silently lose one. Each item costs one URL-ingest slot against a budget of 300 per hour for each caller on each project (the counter is keyed by your credential and the project, not the project alone). Requires a paid Weblooks plan.
ingest_native_asset_from_url
ChatGPTPREFERRED WAY TO ADD AN ASSET. Weblooks fetches the URL server-side and stores the result in the project's native CMS assets. The bytes never pass through your context, so a whole photo library costs about as much as one sentence. Use it for any source with an https URL (a CDN you are migrating off, the project's own staging deployment, an export endpoint), and fall back to upload_native_asset only for bytes you hold with no URL. Takes the same alt, convert and filename options and returns the same asset, so the two are interchangeable. Omit filename and it is derived from the URL path with the extension corrected to the file's real type. IDEMPOTENT: re-ingesting bytes the project already has returns the EXISTING asset (deduplicated: true) instead of a duplicate id. The existing description wins on dedupe: an undescribed asset adopts your alt, a differing one keeps its own and the response flags altConflict: true with your discardedAlt (overwrite deliberately via update_native_asset_alt if yours is right). The URL must be https and resolve to a public address (private, loopback and cloud-metadata addresses are refused, including via redirect, and so is a URL carrying credentials such as user:password@), at most 25 MiB, and must actually BE an image, PDF, video, audio, font or zip: the type is read from the file's own bytes, so a .jpg URL that serves an HTML error page is rejected rather than stored. SVG is not accepted here; upload it with upload_native_asset.
ingest_native_assets_from_urls
ChatGPTIngest UP TO 20 URLs into the project's native CMS assets in ONE call: the way to populate a photo library or migrate a site's images. Same fetching, security and dedupe rules as ingest_native_asset_from_url. PARTIAL FAILURE IS PER ITEM, never all-or-nothing: returns results[] in the order given, each { url, ok, asset?, deduplicated?, altConflict?, discardedAlt?, error?, code? }, plus succeeded / failed counts. Successful items are committed even when others fail, so a retry of the failed URLs is all that is ever needed, and because ingest is idempotent, re-running the WHOLE batch is safe too. Each item costs one URL-ingest slot against a budget of 300 per hour for each caller on each project (the counter is keyed by your credential and the project, not the project alone), so a 300-image migration is 15 batches and spends the whole hour's budget. Re-running a batch is safe but NOT free: dedupe returns the existing assets without re-storing them, yet the budget is charged before the fetch, so a re-run still spends its slots.
insert_html
ChatGPTInsert an HTML fragment into ONE page next to or inside one element, without rewriting the page: the way to build a page piece by piece (a new section, a card, a heading, a paragraph), which an open Weblooks editor shows arriving one change at a time. Aim it with element_id (an id on the page) OR selector (a CSS selector that must match exactly one element, for example "main > section:nth-of-type(2)"). position: before or after the element (as a sibling), prepend or append (as its first or last child), or end of body (no target needed). The fragment goes INSIDE the page: no doctype, html, head or body tags, at most 64 KB, balanced tags, and no id the page already uses. Read the page with get_page_source first so the target exists; a target that matches nothing or several elements is refused with the reason and nothing is written. The write is refused (409) if the page changed while it was applied, so re-read and retry. WHAT A SAVE DOES is the same as update_page_source: on a GitHub project each call is ONE commit, and a commit to the default branch triggers a deploy, so pass branch for a series of edits you want reviewed; on an uploaded-folder project the page is overwritten in Weblooks storage with no history. To change many pages at once use update_files.
inspect_domain_dns
ChatGPTREAD a domain's live DNS and report what a cutover would break. Works on ANY domain, attached or not. Flags, worst first: DNSSEC (a nameserver change without a DS rollover returns SERVFAIL and makes the domain COMPLETELY unreachable, and it is cached); a CAA record that stops the certificate ever issuing; an apex needing a CNAME at a provider that cannot store one; TTLs above 300 (which make the ROLLBACK slow, not just the cutover); an AAAA that keeps sending IPv6 visitors to the old host; a separate www record; and MX/SPF/DMARC/verification TXT a nameserver change would destroy along with the customer's email. Returns a rollback snapshot. Reads only. Call this BEFORE attach_managed_domain on any domain that is currently live.
instantiate_component
ChatGPTPlan (default) or apply inserting a linked <wl-use> instance on a page, with validated params, an optional variant preset, and optional slot fills. The instance is proven to expand BEFORE the plan is produced, so an accepted plan cannot fail the deploy's component stage; the deploy's other stages still check the page, data-cms markup in the fills included. Inserts before </body> unless before_marker names an existing literal in the page. Applying writes the page on the project's DEFAULT branch (there is no branch option): ONE commit on a GitHub project, which triggers a deploy through the push webhook, or an overwrite with no history on an uploaded-folder project.
list_assets
ChatGPTList all non-HTML assets in the project (images, CSS, JS, fonts, video, audio)
list_branches
ChatGPTList all branches in the project's GitHub repo
list_cms_assets
ChatGPTThe CMS content-image LIBRARY, listed by id (alias of list_native_assets: same result, unambiguous name, including the folder/recursive filters). CMS assets are bound into pages BY ID through data-cms attributes and carry alt text. For plain repo files referenced BY PATH, use list_repo_assets / list_assets.
list_cms_collections
ChatGPTList CMS collections of the project's connected CMS: Sanity, Directus, Strapi, Payload, EmDash (experimental), or a Shopify store, whose collections are its products, pages, articles and product-collections. Uses the project's own CMS connection, else the workspace-level one (see get_cms_connection). 422 if neither exists.
list_cms_entries
ChatGPTList entries in a CMS collection (paginated)
list_collection_routes
ChatGPTEvery collection route in the project, read from its DEFAULT branch: which templates generate pages, from which collection, and whether each template file still exists. Empty means this project hand-writes its detail pages; set_collection_route replaces that. To see what a build actually generated (and which URLs it STOPPED generating), read the deployment record with get_deployment.
list_component_instances
ChatGPTEvery page instantiating a component, with the params each one passes. Use before changing or deleting a definition to see what a rename would break.
list_components
ChatGPTList component definitions in a project, with their declared params, slots and locales. A definition that fails to parse is listed with an error rather than omitted.
list_deployments
ChatGPTList recent deployments (most recent first, up to 50). Each carries commitSha (the commit the build read) for GitHub projects; null for uploaded folders.
list_managed_domains
ChatGPTList the Weblooks-managed domains on a project: for each, hostname, lifecycle status, certificate state, the DNS records to publish, the failure reason if any, and the build it serves (releasedDeploymentId, to compare with liveDeploymentId). Reads the stored records and makes no Cloudflare call and no lookup of the customer's domains; its one network step is a DNS lookup of Weblooks' own hosting address, which fills in the apex A/AAAA targets (apexIps). get_project already summarises these (url, hosting.domains). For one domain checked against its live DNS, call get_managed_domain_status.
list_native_assets
ChatGPTList the images and files stored in the project's NATIVE Weblooks CMS (the Assets tab of the CMS). Distinct from list_assets, which lists files in the project's source repo. Returns ONE PAGE (default 100, max 200): assets plus total, limit and offset, so a library of 340 answers total:340. Pass offset to read the rest; never assume the first page is everything. Each asset carries id, filename, contentType, size, alt, createdAt and folder. Use the id as the value of an image field. Pass folder to list one level ('' = the root; exact match unless recursive: true); the response's folders array names the sub-folders directly under the level listed. Folders are organisational only: they never appear in a published URL or a binding.
list_native_collections
ChatGPTList collections in the project's native Weblooks CMS (hosted content).
list_native_entries
ChatGPTList entries in a native Weblooks CMS collection, ONE PAGE at a time. Returns { entries, total, limit, offset }: total is the whole collection, so a 101-entry collection answers total:101 with the first 50. Read the rest with offset (page until offset + entries.length reaches total) and never treat the first page as the whole set. sort is created | updated (default, newest first) | field:<name> for any field the collection has (a localized field sorts on locale, falling back to the project default); dir asc | desc. q searches every text and number value of an entry across all locales (ASCII case-insensitive, substring). To find one entry before an update, search for it. Do not page through the collection. pending:true lists only entries with work that is not live: drafts, published entries with a working copy (hasUnpublishedChanges), and queued publishes.
list_pages
ChatGPTList the pages in a project, together with the other files that make them up, each with its path and size. The pages are the paths ending in .html; the same listing also returns the CSS, JS, images, fonts, config files and component templates they depend on, so one call shows the whole project. Draft pages (set_page_draft) are included and carry "draft": true, and pages flagged with set_page_protection carry "protected": true; pass include_drafts:false to leave draft pages out.
list_projects
ChatGPTList all projects in your Weblooks workspace
list_pull_requests
ChatGPTList pull requests (default state: open)
list_redirects
ChatGPTList the project's URL redirect rules and its trailing-slash policy. Rules live in the project file weblooks.redirects.json (on a GitHub project a committed file, reviewable in a PR). The LIVE table is the default branch's copy; on a GitHub project branch reads another branch's copy, which is not live until that branch is merged and the default branch is deployed. Returns rules in no particular order. Precedence is order ascending, then exact > placeholder > wildcard.
list_repo_assets
ChatGPTThe SOURCE-REPO files, listed by path (alias of list_assets: same result, unambiguous name). Repo files are what markup and CSS url() reference BY PATH (/assets/…). For the CMS content-image library that pages bind BY ID, use list_cms_assets / list_native_assets.
merge_pull_request
ChatGPTMerge a pull request: the last step of the branch workflow, and the safe way to land a big change: prepare it on a branch, review it, then land it in one merge. Re-checks the pull request first and refuses with a sentence naming the blocker (draft, closed, already merged, conflicted) rather than a bare failure. The head SHA is pinned, so a push that lands between the check and the merge is refused rather than merged unreviewed. The commits land on the pull request's BASE branch: when that is the project's default branch, the merge triggers ONE deploy through the push webhook; a merge into any other branch deploys nothing. Requires confirm_token from EVERYONE, owners and admins included, unless the project has turned confirmations off: a merge is undone only by a revert commit (and, on the default branch, another deploy). deploymentId is null because any deploy is triggered asynchronously by the merge commit; poll list_deployments.
move_native_asset
ChatGPTMove a native-CMS asset into a folder ('' = the library root). PURE METADATA: the id, bytes, alt text, bindings and published URL are all unchanged, so a move can never break a live page and needs no redeploy. The target folder (with intermediates) is created if missing. Moving an asset to the folder it is already in is a no-op success.
open_pull_request
ChatGPTOpen a pull request from head → base (default base is the project default branch)
preflight_managed_domain
ChatGPTPROVE THE CUTOVER WILL WORK BEFORE ANY DNS CHANGES. Reaches the Weblooks edge by address while presenting the real hostname (SNI + Host), so the edge answers exactly as it will after cutover, while the customer's current site keeps serving, untouched. Asserts a certificate covering the domain and not expiring, 200 text/html, the served build is the one released to this domain (staging may be ahead; that is correct), sampled redirects fire, that plain http 301s to https and HSTS is served, and that x-robots-tag: noindex is ABSENT (staging serves it; if it follows a domain to production the whole site is invisible to Google while looking fine in a browser). A hostname that is not the project's canonical host passes with a 301 to the canonical host's home page instead of a 200; its build is checked by the canonical host's own pre-flight. On success the domain becomes ready_for_cutover and the routing records are returned as the human's next step. Changes no DNS.
promote_deployment
ChatGPTRoll back STAGING by promoting a previous deployment to live at <slug>.weblooks.site. Custom domains are unaffected: they keep their released build; use release_to_domains (with a deployment_id) to move them.
refresh_managed_domain
ChatGPTReconcile ONE domain against Cloudflare and DNS now, instead of waiting for the scheduled pass. Runs at most one claimed pass. If another is already running it returns that status rather than starting a second. Waiting for validation is a SUCCESS, not an error. Do not busy-poll: honour the returned next action.
release_managed_domain
ChatGPTDESTRUCTIVE AND PERMANENT: stops serving, deletes the Cloudflare hostname and its certificate, and once cleanup is confirmed frees the hostname for any other project to claim. Reconnecting means issuing a new certificate. TWO STEPS: call without confirmation_token to get a one-time token plus the consequences, then call again with it within ten minutes. Requires workspace owner/admin. Success means teardown STARTED: the hostname stays reserved until Cloudflare and edge cleanup are confirmed; poll get_managed_domain_status until it reports released.
release_to_domains
ChatGPTPut a build live on the project's connected custom domains (two-tier publishing: deploy updates staging; this is the go-live step for the domains). With no deployment_id it releases the build staging is currently showing. Pass an older completed deployment_id to roll the domains back. Staging is unaffected either way. Returns the hostnames now serving the build. After the first release to a domain, pick the one hostname the site answers on with set_canonical_host and write a full sitemap with generate_sitemap.
rename_asset_folder
ChatGPTRename/move a native-CMS asset folder atomically, carrying every descendant folder and asset with it. Pure metadata: no bytes move, no asset id changes, no published URL changes, so live pages are unaffected and no redeploy is needed. Refuses to rename onto an existing folder (no silent merge) and to move a folder inside itself.
rename_project
ChatGPTSet the project's display name: the label shown in the dashboard, project lists and the editor (a fresh upload-source project is otherwise literally "Untitled project" forever). This is a UI label: it does NOT rename a linked GitHub repo or a local folder. Pass an empty display_name to clear the override and fall back to the original name.
render_component_preview
ChatGPTRender one fixture of one component through the REAL expansion path, optionally with a variant preset (wl-preset). Returns the fragment HTML, the component's scoped stylesheet (css, the same rules the deploy bundles), plus basic accessibility findings (missing img alt, duplicate ids).
replace_element
ChatGPTReplace ONE element (with everything inside it) on one page with an HTML fragment, without rewriting the page: the way to rework a single section, card or heading. Aim it with element_id OR selector (a CSS selector that must match exactly one element). html, head and body themselves cannot be replaced. The fragment follows the same rules as insert_html (no document-level tags, at most 64 KB, balanced tags, no id used elsewhere on the page; it may keep the replaced element's own ids). The replaced markup is gone from the page once saved: on an uploaded-folder project there is no history to recover it from, and on a GitHub project only the commit history has it. Read the page with get_page_source first. Refused targets and a page that changed mid-write are reported and write nothing. On a GitHub project each call is ONE commit and a commit to the default branch triggers a deploy; pass branch to commit elsewhere.
retry_managed_domain
ChatGPTRetry a FAILED domain without removing and re-adding it (which would destroy its certificate and briefly free the hostname for anyone else to claim). Clears only the reviewed failure fields and re-queues the existing Cloudflare resource. Only a domain whose status is failed can be retried: any other status, disabled included, is refused (409). If the failure was a Weblooks platform incident rather than the customer's DNS, this returns the escalation action instead: retrying our own outage does not help.
run_scan
ChatGPTTrigger a new scan for a category (accessibility | metadata | structured_data | variables | components | scripts | analytics | animations | seo | performance | contrast | images | links | gdpr). The response lists the findings, with fix on each warn or fail finding the server knows how to fix. Read them again later with get_scan_results and the same category; get_project_status shows what is left across all of them.
scan_legacy_site
ChatGPTPoint this at the site being REPLACED and it enumerates every URL the old site publishes (robots.txt → sitemap → sitemap indexes; Yoast splits into several) and classifies each against the CURRENT build using the same routing code the edge runs: already_ok / already_redirected / would_404 / asset. Proposes a redirect rule for each broken page with a confidence score, and collapses whole dead sections into wildcard rules so ninety guesses become one decision. Non-HTML files (.kml, .pdf, feeds) are reported as assets and never given an HTML target. Emits rules in exactly the shape set_redirects consumes. It does NOT apply them; review first, then call set_redirects.
schedule_publish
ChatGPTSchedule a ONE-TIME publish at a future time. Fires WHATEVER THE DRAFT IS at run_at: editing stays open until then, and the publish runs the ordinary deploy pipeline (entitlement and content are checked at fire time). Unlike a manual deploy, a scheduled publish GOES LIVE everywhere: it releases to the connected custom domains automatically, because its promise is 'live at that time'. One pending schedule per project: scheduling again returns the existing one as a conflict; cancel it first to pick a new time. Fires within a few minutes of run_at, never before.
set_canonical_host
ChatGPTMake ONE hostname the site's address: every other ACTIVE domain on the project 301s to it, preserving path and query, in a single hop. Use this when the apex and www are both attached and both serving. Without it every page is live on two hostnames, which is duplicate content and splits ranking signals between two addresses. set_redirects cannot express this: its from must start with "/", so rules match paths only. Do NOT disable the other domain instead: a www hostname usually carries years of inbound links, and disabling turns each into a dead end while redirecting keeps them working. REFUSED if hostname is not an active domain on the project, because a canonical host naming a hostname you do not serve sends every visitor nowhere. Composed with the redirect table, so a request matching both gets one 301 to the final target rather than a chain. Live at the edge within about a minute, without a deploy. Pass hostname:null to clear. Verify with test_redirect, which reports these as via:"host".
set_collection_route
ChatGPTONE TEMPLATE, ONE PAGE PER CMS ENTRY. Point a template whose path has a bracket segment ("events/[slug].html") at a native collection, and every deploy publishes one page per entry: /events/midsommar, /events/julbord, … Use this INSTEAD of hand-writing a file per entry: a new entry then needs no new file, and an edit to the template updates every page. Inside the template the matched entry is the implicit context, so BARE field names bind to it (data-cms="titel"), exactly like the rows of a data-cms-repeat, while DOTTED names still read another collection's singleton (data-cms="settings.epost"). Bind the <head> too. That is the point: <title data-cms="titel">, <meta name="description" data-cms-content="ingress">, <meta property="og:image" data-cms-content="bild">, and <link rel="canonical" data-cms-href="$url"> where $url is the generated page's own address. ONCE A ROUTE EXISTS, THE LISTING CAN LINK TO IT: inside data-cms-repeat, <a data-cms-href="$url"> resolves per row to that entry's generated page in the page's own locale. Never store a full URL on an entry for this. Draft entries get no page (they get an unguessable preview URL instead); the generated pages are in sitemap.xml, a real file at a generated path always wins, and a template binding a field the collection lacks FAILS the deploy naming the field. ONE LOCALE PER ROUTE: register a second route with its own prefix for another language and Weblooks links them with hreflang (x-default = the registry's x_default, see set_project_locales). $url.<locale> is the SAME entry's page in another locale (data-cms-href="$url.en"; exact route or unresolved), TEMPLATES compose text around a value (<title data-cms="AniMed | {title}">), and a leading ? makes a binding optional (data-cms-href="?$url.en" in a shared header keeps the authored href silently on pages with no entry). Together, a language toggle with no new component params. A hand-authored sitemap.xml lists the generated pages where it carries <!-- weblooks:collection-urls -->. Takes effect at the NEXT deploy. Stored in weblooks.collections.json: on a GitHub project the save is ONE commit, so the route survives clone/branch and shows in a diff, and a commit to the default branch triggers that deploy through the push webhook (with branch it stays on that branch and deploys nothing); on an uploaded-folder project the file is overwritten with no history, nothing deploys until the next deploy, and branch is refused. Read get_build_guidelines for the binding vocabulary.
set_consent_banner
ChatGPTTurn the built-in Weblooks cookie-consent banner on or off for this project, and configure it. Use this INSTEAD of building a consent banner by hand: the platform ships one, and it is wired to the consent log that makes consent demonstrable. OFF by default, because Weblooks never injects anything into a site automatically, so a site with trackers and no banner is usually a project that never turned this on, not a missing feature. Takes effect on the NEXT DEPLOY, not immediately. Consent-gated tags must be authored as <script type="text/plain" data-consent="analytics" src="…">. The banner rewrites those into real scripts once that purpose is accepted, and a plain <script> runs before any choice is made, which no banner can fix. Copy is built in for en/sv/de/fr/es and is picked PER PAGE from <html lang>, so a multi-locale site needs no per-page setup; locale is only the fallback for pages with no usable lang, and text overrides individual strings on top. CHANGING purposes bumps the policy version, which re-asks every visitor who already chose. This is deliberate, because consent given for a narrower set of purposes cannot cover a wider one. A site that keeps its OWN consent manager should leave this off and POST each decision to /api/consent/<project_id> with source:"custom", so the log still holds the evidence. GOOGLE CONSENT MODE is a per-project mode: weblooks (default) gates scripts and says nothing to Google; google_basic gates scripts AND pushes gtag consent default/update signals mapped from the visitor's choice (analytics→analytics_storage, marketing→ad_storage+ad_user_data+ad_personalization, preferences→functionality_storage+personalization_storage); google_advanced additionally injects a consent-default bootstrap at the top of <head> so the Google tag can be authored as a PLAIN script that loads on every page with everything denied until consent: Google's modelling mode, which sends cookieless pings before consent and is the posture some EU regulators dispute, so choose it deliberately. In both Google modes never hand-write gtag('consent', …): the banner emits it. Never paywalled.
set_hsts
ChatGPTTurn on HSTS includeSubDomains / preload. Every managed hostname ALREADY sends max-age=31536000; max-age is a platform constant and is not settable. THINK BEFORE ENABLING include_subdomains: it commits every subdomain of the customer's apex (a webmail, an intranet, anything Weblooks does not host) to https-only for a year, enforced inside each visitor's browser, and NO Weblooks action can release it early. Call get_hsts first and check would_bind. preload needs include_subdomains (the browser preload list rejects it otherwise) and only advertises eligibility; submitting the domain stays a human act.
set_og_image
ChatGPTPoint one page, several pages, or EVERY page at an Open Graph social-preview image. Pass url as an absolute http(s) URL, since crawlers cannot resolve a relative path. To use a local image file, first call upload_asset with the image bytes (it returns { url }), then pass that url here; there is no separate og-image upload tool. Target with file, files, or all_pages: true. Also writes twitter:image, and sets twitter:card to the large-image card, unless also_twitter is false. Ideal image is 1200x630 (1.91:1); under 200x200 is rejected by most networks. Returns { ok, url, updated, skipped, failed, truncated }: skipped pages already carried the image or have no <head>. Check failed and truncated: a partial result is reported rather than thrown. On a GitHub project every change is ONE commit, so a failed write changes no page. An uploaded-folder project writes the pages one by one, so a write that fails partway leaves the earlier pages changed, with no history: they are listed in updated, and only the rest in failed.
set_page_draft
ChatGPTMark a page as a DRAFT (or publish it again). A draft page stays in the project, editable in the canvas, validated by every deploy (a broken <wl-use> in a draft still fails the build; finding out before publishing is the point), but is OMITTED from the published output entirely: its URL returns the site's normal 404, it is excluded from sitemap.xml, and a link to it from a published page becomes a deploy warning. While drafted, the page is reachable at a stable, unguessable preview URL (previewUrl in the response, under /__weblooks/preview/, X-Robots-Tag: noindex) that survives redeploys and is revoked when the page is published or deleted. Setting the flag never edits the page's own bytes: it lives in weblooks.pages.json. Takes effect at the NEXT deploy, on staging; a custom domain keeps serving its released build, draft page included, until release_to_domains. On a GitHub project the save is ONE commit, so the flag survives clone/branch/merge and shows in a diff, and a commit to the default branch triggers that deploy through the push webhook; with branch it stays on that branch and deploys nothing. On an uploaded-folder project the file is overwritten with no history and nothing deploys until the next deploy; uploaded projects refuse branch. A missing path is a not_found error naming it, never a silent no-op.
set_page_protection
ChatGPTFlag one page PASSWORD-PROTECTED (or clear the flag). Stored in weblooks.pages.json next to the draft flag. NOTHING CHANGES AT THE EDGE UNTIL A DEPLOY: the edge enforces the flags a deployment shipped, and only while the site's protection scope is 'pages' (set_site_protection), so a change reaches staging at the next deploy and a custom domain only once that build is released to it (release_to_domains). Whatever the scope, that deploy also leaves a flagged page out of site search and out of the sitemap the deploy generates. A sitemap.xml in the project is kept as written, so a hand-written one, or one generate_sitemap wrote before the page was flagged, still lists it until you run generate_sitemap again, which leaves flagged pages out. On a GitHub project the save is ONE commit, so the flag survives clone/branch and shows in a diff, and a commit to the default branch triggers that deploy through the push webhook; with branch it stays on that branch and deploys nothing. On an uploaded-folder project the file is overwritten with no history and nothing deploys until the next deploy; uploaded projects refuse branch. A missing path is a not_found error, never a silent no-op.
set_project_locales
ChatGPTReplace the project's locale registry (owner/admin). Call this BEFORE any localized work (localized fields, translated pages, per-locale alt text): every localized write is checked against this registry, and an unregistered <html lang> silently renders in the default locale. default_locale must be in locales and is what every missing translation falls back to. For a Swedish-first site: locales ["sv","en"], default_locale "sv". x_default (optional, defaults to default_locale) is the locale whose page carries hreflang="x-default" on generated collection pages and in generate_sitemap, split from the fallback so a site provisioned as ['en'] can keep English as the readable fallback while its Swedish root URLs are the default for search engines: locales ["en","sv"], default_locale "en", x_default "sv". Omitting x_default keeps the stored value. settings (optional) sets per-locale options and MERGES per locale. An absent key keeps the stored value, null clears it: hreflang (the tag published for the locale, e.g. sv-SE or zh-Hant-TW; must be unique across the set), published (false = a DRAFT locale: translate first, publish later; its collection routes generate no pages and no hreflang names it; the default and x_default locales must stay published), display_name (editor label, max 64 chars). Set this BEFORE creating localized fields (a localized:true field against a single-locale registry is refused, naming this tool). Narrowing the set does not delete stored values (they stop rendering until the locale is re-added), but it does drop that locale's settings.
set_redirects
ChatGPTBULK-LOAD redirect rules. Use this for a site migration, not repeated create_redirect calls: the whole table is ONE write (one commit on a GitHub project), however many rules it holds. mode="replace" swaps the whole table; mode="merge" upserts by from and leaves other rules alone. Validates the WHOLE resulting table before writing anything and reports every problem at once (loops, cycles, duplicates, reserved targets, non-https off-site targets), so nothing is saved until it is all correct. Saved on the default branch, the table is live at the edge within about a minute; it does not wait for the deploy a GitHub commit may also trigger. Saved with branch, it is committed to that branch ONLY and is not live until the branch is merged and the default branch is deployed.
set_robots
ChatGPTWrite robots.txt into the project's files. This TAKES OVER permanently: a robots.txt in the project wins on every domain and the platform stops generating one, so you also own keeping the Sitemap: line correct. Call get_robots first to see which case the project is in. Warns (but does not refuse) on "Disallow: /": blocking a crawl does NOT deindex, because a crawler that cannot fetch the page never sees a noindex either. The new file is served from the NEXT deploy on staging, and on a custom domain once that build is released to it (release_to_domains). On a GitHub project the save is ONE commit, and a commit to the default branch triggers that deploy through the push webhook; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project the file is overwritten with NO history, so the previous robots.txt cannot be recovered, and nothing deploys until the next deploy; uploaded projects refuse branch.
set_site_protection
ChatGPTPASSWORD-PROTECT THE PUBLISHED SITE (owner/admin; settings:manage). scope: 'site' locks every page of the site (plus the search index and sitemap.xml), 'pages' locks only pages flagged with set_page_protection, 'off' makes the site public. Visitors see a password page (the site's own 401.html, or one Weblooks generates at publish) and, after the right password, a 7-day session cookie. The scope and password are LIVE AT THE EDGE WITHIN A MINUTE, no deploy needed. The list of flagged pages is NOT: under 'pages' the edge enforces the flags that the deployment serving each hostname shipped, so a flag saved since then needs a deploy to reach staging and release_to_domains to reach a custom domain. Enforced on Weblooks hosting only (the staging link and connected custom domains): deploy_to_vercel omits protected pages instead, and your own CI protects nothing. password: between 8 and 200 characters, stored only as a salted PBKDF2 hash and NEVER returned; setting one signs everyone out. sign_out_all:true ends every visitor session without changing the password. Turning protection on needs a paid workspace or a paid site; turning it off or signing visitors out never does. Do not build a client-side password page instead: on a static site it protects nothing. Returns { scope, hasPassword, entitled }.
set_trailing_slash
ChatGPTSet how the site treats trailing slashes. "never" (default) 301s /x/ to /x; "always" 301s /x to /x/; "ignore" serves both, which splits ranking signals between two URLs and should be a last resort. Applies to extensionless paths only and never to the site root. Evaluated AFTER the redirect table, so an explicit rule always wins.
setup_custom_domain
ChatGPTFor USER-OWNED hosting (the Cloudflare Pages target set up with configure_deploy_target) only, NOT Weblooks-managed hosting: use attach_managed_domain for a Weblooks-hosted site. Refused until the project has a deploy target. Weblooks makes NO Cloudflare call and never edits DNS: this saves the domain on the project's deploy target and returns the DNS record(s) to add at the user's DNS provider, plus the steps and a dashboard link for adding the domain to their own Cloudflare Pages project, which the user does themselves. It then runs live DNS lookups and an HTTPS request against the domain to check whether it is live and served by the provider; a live domain marks the target verified. Call again after the records and the domain are added to re-check. Paid Sync only.
test_redirect
ChatGPTDRY-RUN one or more URLs against the CURRENTLY SAVED redirect table without deploying anything. Returns, per URL, which rule matched and where it lands: via: "host" when the canonical-host rule answers it (only for a FULL URL, since a bare path names no host), via: "canonical" when the platform's own .html/trailing-slash normalisation does, or via: "none" when nothing does. Use this to verify a migration BEFORE cutting DNS over. Accepts full URLs or bare paths. Answers with the exact code the edge runs, so the result is what visitors will get.
update_alt_text
ChatGPTUpdate the alt attribute on a specific <img> by its src
update_cms_entry
ChatGPTPartially update a CMS entry: only the fields in patch change, the rest are left as they are. On Shopify the change goes straight to the live store.
update_component
ChatGPTOverwrite a component definition. Use get_component first, edit, then save here. Changing or removing a param breaks every page that passes it, so check list_component_instances first. On a GitHub project each save is ONE commit, and a commit to the default branch triggers a deploy through the push webhook; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project the file is overwritten with NO history, so the previous definition cannot be recovered; uploaded projects refuse branch.
update_component_asset
ChatGPTWrite a component's co-located stylesheet or script at components/<name>/<name>.<kind>. THIS IS THE FIX for component "x" ships a .js file but its template has more than one root element: a component that ships a .js must have exactly ONE root element, so a <style> block sitting as a sibling of the markup breaks EVERY deploy until it moves into a sibling .css, which is what this writes. A component's styles and behaviour belong here rather than inline in the template, and both are bundled at publish. On a GitHub project each save is ONE commit, and a commit to the default branch triggers a deploy through the push webhook; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project the file is overwritten with NO history, so the previous version cannot be recovered; uploaded projects refuse branch.
update_component_variant
ChatGPTPlan (default) or apply replacing a named preset. Run list_component_instances first to see which pages the preset change will restyle: a preset edit updates every instance that references it (spec §11).
update_files
ChatGPTWrite MANY files in ONE call: the tool for any sitewide change. On a GitHub project the batch is ONE commit (all or nothing), and on the default branch the push webhook turns it into ONE deploy; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project there is no commit and no deploy: each file is overwritten in Weblooks storage with NO history (previous versions cannot be recovered), the batch is not atomic (atomic: false), and the change reaches the site at the next deploy. Validates EVERY file before writing ANY of them and reports all failures at once, so a 41-file batch with one bad file writes nothing and names that file. The checks are the DEPLOY's own (component single-root rule, <wl-use> params, data-cms binding structure), so a batch that passes here cannot fail the deploy's component stage, which is the gap that let a bad component be accepted and then break every deploy for five days. Those are the ONLY deploy stages it runs: reserved-path refusal (/admin, /api/cms, /__weblooks/*), asset hashing/media variants and the post-publish smoke checks still happen at deploy time and can still fail a publish. Accepts ANY text path, not just HTML: sitemap.xml, robots.txt and config files are all valid targets. deploymentId is always null: on GitHub the deploy is triggered asynchronously by the commit, so poll list_deployments for it. IF A WRITE FAILS PARTWAY on an uploaded-folder project, the 502 names the files that did land: written lists them and perFile marks each file ok or not written. Those files ARE changed, so retry only the rest. Any other write failure wrote nothing.
update_metadata
ChatGPTUpdate SEO metadata fields on a page (only fields you pass are changed). Covers title, description, canonical, robots, Open Graph and twitter_card. Afterwards run_scan with category metadata (and seo) confirms it; set_og_image sets one preview image on several pages at once.
update_native_asset
ChatGPTRename a native-CMS asset IN PLACE, keeping its id, so every data-cms binding and its alt text survive (re-uploading would mint a new id and break both). This is the fix for the CDN-mangled names assets arrive with from the web uploader, e.g. https-__cdn.prod.website-files.com_6875f..._tures-2.jpg → dog-in-clinic.jpg. The asset's PUBLISHED URL is /cms-assets/<id>/<contentHash>.<ext>, so a pure rename changes NO URL (the response reports previousUrl and url so you can see nothing moved); only replacing the bytes (convert) does, and stale URLs 301 to the current one. Use update_native_asset_alt for the description and convert_native_asset for the bytes.
update_native_asset_alt
ChatGPTSet a native-CMS asset's alt text (accessibility description). Alt is LOCALIZABLE: on a multilingual site, pass locale to set one language's description (merges with the others), or pass alt as a { locale: string } map to replace all of them at once. Rendering picks the page's locale (<html lang>) with fallback to the project default, so an asset described only in the default language never renders an empty alt. Per locale: a string is a description, "" marks it DECORATIVE, and omitted/cleared is undescribed. All three are preserved. Without locale, a plain string replaces the whole value (the original single-language behavior). Alt is PLAIN TEXT and renders literally: HTML entities such as & are rejected on write exactly like entry text fields (write the & itself). When ONE asset serves TWO contexts (dedupe does this), don't fight over its single alt. Override per placement with data-cms-alt="<field>" on the <img> (see get_build_guidelines).
update_native_collection
ChatGPTRename a native-CMS collection's label and/or slug. Renaming the SLUG breaks every data-cms="<slug>.<field>" binding on already-published pages until they are re-pointed and redeployed. The label is display-only and always safe.
update_native_entry
ChatGPTUpdate a native Weblooks CMS entry. patch changes ONLY the fields it names and keeps every other field: null clears a field, a localized field merges per locale ({ "rubrik": { "en": "..." } } changes English only), and a list or repeater is replaced whole. data instead REPLACES the entry's field values as a whole (validated against the schema): a field left out is cleared and a missing required one is refused, so read the entry with get_native_entry and send every field back. Send patch or data, not both. Omit data and patch to change only the publication state and leave the content as it is. WORKING COPIES: a save to a PUBLISHED entry is held as a private working copy and the site keeps serving the published values until the entry is published again, so one person's unfinished edit never ships with somebody else's publish (get_native_entry shows hasUnpublishedChanges and the live publishedData). publish:true publishes (a draft goes live; a live entry's working copy replaces its published values); publish:false unpublishes (the working copy becomes the draft); omit to leave the publication state unchanged. publish:true and publish:false each QUEUE A STAGING DEPLOY when the project has staging and auto-deploy on publish is on (the default); a save that omits publish queues no deploy and changes nothing on the site. publish_at (ISO 8601, future) QUEUES the publish instead: at that time a draft goes live or a live entry's working copy replaces its values, and the staging deploy runs then, so each person can schedule their own entries without shipping anyone else's work. release_to_domains:true (with publish:true or publish_at; needs deploy permission) also moves the custom domains to that build once it succeeds, never to an older build than they serve. Without it custom domains keep their released build until the release_to_domains tool. discard_changes:true drops a live entry's working copy; cancel_schedule:true cancels a queued publish and keeps the edits; send either alone. expected_version (with data) refuses the save when someone else saved after you read that version.
update_native_field
ChatGPTEdit a native-CMS field by its UUID (from get_cms_schema / the fields listing). label/required/position/localized are attribute edits. name and type are DATA MIGRATIONS that rewrite every entry in place, saving no entry versions: rename moves the key in every entry; retype converts every stored value and REFUSES entirely (nothing written), naming how many entries block it, when any value cannot convert (text that is not a number, anything retyped to boolean, text that is not already a valid slug). An accepted retype can still change stored text: text to number parses each value, so "007" becomes 7 and "1.50" becomes 1.5, losing leading zeros and formatting. Renaming a field breaks published data-cms bindings to the old name.
update_page_source
ChatGPTWrite the FULL content of ONE file: usually a page, but any text path works, and a missing file is created. Use get_page_source first, edit, then save here; the whole file is replaced, last write wins. Changing MORE THAN ONE file? Use update_files instead. WHAT A SAVE DOES depends on the project. On a GitHub project each call is ONE commit, and a commit to the default branch triggers a deploy through the push webhook, so a sitewide edit made with this tool becomes one commit per page and staging can publish it half applied; pass branch to commit on a feature branch, which deploys nothing. On an uploaded-folder project there is no commit and no deploy: the file is overwritten in Weblooks storage with NO history, so the previous content cannot be recovered, and the change reaches the site at the next deploy. Uploaded projects refuse branch.
update_project_config
ChatGPTUpdate project-level deployment/storage settings: storage bucket, storage public base, Vercel project id. Pass an empty string "" to CLEAR an override (fall back to the workspace default). Only the fields you pass are changed.
update_redirect
ChatGPTChange one existing rule by id. Only the fields you pass are changed. The whole table is re-validated before the write.
upload_asset
ChatGPTUpload a binary asset (base64). Returns { url, key, provider }. Check provider: it tells you where the bytes actually went. destination:"repo" writes the file into the source repo at path: it appears in list_assets, pages and CSS url() reference it as /<path>, and this is what you want for ANYTHING markup references by path (favicons, fonts, textures). destination:"storage" writes to the workspace's connected storage bucket under key <project_id>/<path> and returns its public URL: the file does NOT appear in list_assets and a page referencing /<path> will NOT find it. Default when destination is omitted: "storage" if a provider is connected, else "repo". Pass it explicitly instead of relying on the workspace's connection state. PREFER ingest_asset_from_url when the file has an https URL (no base64 through your context).
upload_native_asset
ChatGPTUpload an image or file INTO the project's native Weblooks CMS assets (the CMS Assets tab) by sending its BYTES, returning the stored asset. Bytes the library already holds are NOT stored twice: the EXISTING asset comes back with deduplicated: true, keeping its own filename and description (an undescribed asset adopts your alt; a differing one is kept and the response flags altConflict: true with your discardedAlt). PREFER ingest_native_asset_from_url whenever the file has an addressable https URL. This tool moves every byte through your context (a 177 KB image costs ~120K tokens round-trip and one mistyped base64 character corrupts it silently), so use it only for bytes you hold with no URL to point at. Distinct from upload_asset, which writes a file into the project's source repo. Set alt at upload time so the image is described from the start. Set convert to 'webp' or 'avif' to convert the image BEFORE it is stored (this rewrites the stored file and its extension); omit it to store the original untouched. Published pages get WebP/AVIF automatically at deploy time regardless.
validate_component
ChatGPTValidate one component (or all) without writing: the same derivation the catalog and the deploy run, returned as per-component status + diagnostics. Broken definitions are reported with their diagnostics, never omitted.
verify_deployment
ChatGPTVerify a project's live deployment and run the independence check: confirms the site is up, serving HTML, served by the hosting provider (Cloudflare) and NOT by Weblooks, then evaluates whether it is fully independent of Weblooks (own domain, deploy recipe committed, content + assets on the user's own services, no Weblooks env vars). Provide live_url the first time (the *.pages.dev URL or custom domain).
verify_managed_domain_cutover
ChatGPTRun immediately AFTER the human changes the routing record. Everything preflight asserts, plus the three things only answerable once traffic moved: that www (or the apex sibling) resolves to Weblooks and not the old host, that no stray AAAA still sends IPv6 visitors to the old site, and that MX/SPF still match the pre-cutover snapshot. On full success the domain becomes active. Partial propagation is a SUCCESS with a wait action. Verify again shortly, do not treat it as failure. Pass mail_snapshot from the earlier inspect_domain_dns; without it mail is only a presence check and the result says so.