generating-weaverse-project-json — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited generating-weaverse-project-json (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Generate valid, import-ready Weaverse project export JSON files.
This skill produces JSON files that conform to the Weaverse import contract. It works independently — you can use it from a site migration, a design spec, a verbal description, or any other input that describes what pages and sections should exist.
The output is a single JSON file matching the schema in references/project-json-schema.md, with a real-world example in references/demo.json.
This skill accepts any of these as input:
cloning-websites-to-weaverse (website migration flow)figma-to-weaverse (Figma design flow)The only hard requirement: you need to know which section types to use. Read app/weaverse/components.ts to get the list of registered sections and blocks.
This skill produces an import JSON that establishes the project structure — pages, sections, and initial content. That JSON is imported once into the Weaverse Studio editor to create the project.
After the structure exists, ongoing content edits (copy, images, localization, bulk updates) should go through the `weaverse-content-api` skill, not by re-importing. Keep the item ids stable between the two so later patches target the same items.
When the project already exists (the usual case for adding pages to a live store), you don't have to import at all: create the page with POST /projects/:projectId/pages and send the JSON's items in one PATCH (see "Populate a new or empty page" in weaverse-content-api). Keep the JSON file in the repo as the record of what was pushed, and sync it back if you change the live page afterwards.
references/project-json-schema.md for the contract and references/demo.json for a complete real-world exampleapp/weaverse/components.ts to know which section and block types are availableapp/sections/ or app/components/ to learn valid schema fields, enum values, and defaultspython3 scripts/validate.py <output-file> (works on Python 3.8+) to catch structural errors{
"version": "1.0.0",
"exportedAt": "<ISO timestamp>",
"project": { "name": "<name>", "config": {} },
"pages": [],
"pageAssignments": []
}Contains theme settings, locale, and colors. Accepted keys:
| Key | Type | Purpose |
|---|---|---|
previewHost | string | Dev server URL, usually http://localhost:3456 |
theme | object | Storefront-wide design tokens (colors, typography, layout) |
defaultLocale | object | { label, language, country, currency, pathPrefix } |
recentColors | string[] | Editor color picker recent colors |
For theme, refer to references/demo.json → project.config.theme for the full set of valid keys. Key categories:
colorPrimary, colorText, colorBackground, colorLine, colorTextSubtle, colorLineSubtle, colorTextInverse, colorForegroundbodyBaseSize, bodyBaseLineHeight, bodyBaseSpacing, h1BaseSize, headingBaseLineHeight, headingBaseSpacingpageWidth, footerWidth, headerWidth, navHeightDesktop, navHeightTablet, navHeightMobileheaderBgColor, headerText, footerBgColor, footerText, topbarBgColor, topbarTextColor, topbarHeightbuttonPrimaryBg, buttonPrimaryColor, buttonSecondaryBg, buttonSecondaryColor, btnCornerRadiuspcardAlignment, pcardImageRatio, pcardBorderRadius, pcardShowVendor, pcardShowReviews, pcardShowSalePrice, etc.newBadgeText, newBadgeColor, saleBadgeText, saleBadgeColor, soldOutBadgeText, soldOutBadgeColor, bestSellerBadgeText, bestSellerBadgeColorsocialFacebook, socialInstagram, socialLinkedIn, socialXnewsletterTitle, newsletterDescription, newsletterButtonText, newsletterPlaceholder, newsletterPopupEnabled, etc.Only include theme keys you understand and intend to set. Do not copy the entire demo theme blindly.
Each page has id, name, rootId, and a flat items array:
{
"id": "b98mnnqmv3tmce7wmw3l7vw4",
"name": "Homepage",
"rootId": "019b917a-f48f-72d4-aee7-3b1eae6b7dca",
"items": [
{ "id": "019b917a-f48f-72d4-aee7-3b1eae6b7dca", "type": "main", "data": {}, "children": [{ "id": "019b917a-f48f-72d4-aee7-3b1f5ca586c1" }] },
{ "id": "019b917a-f48f-72d4-aee7-3b1f5ca586c1", "type": "hero-image", "data": { "height": "small" }, "children": [{ "id": "019b917a-f48f-72d4-aee7-3b22cd55e21b" }] },
{ "id": "019b917a-f48f-72d4-aee7-3b22cd55e21b", "type": "heading", "data": { "content": "Welcome" }, "children": [] }
]
}Key rules:
items array, hierarchy is expressed through children id-referencesrootId[] for leaf items, [{ "id": "<item-id>" }] for parents{} when no non-default values are neededapp/weaverse/components.tsCRITICAL: The Weaverse importer expects both data and children to be present on EVERY item. Omitting them causes silent import failures (empty page renders). Always include "data": {} and "children": [] even when empty.
Maps pages to routes:
{ "pageId": "b98mnnqmv3tmce7wmw3l7vw4", "type": "INDEX", "handle": "", "locale": "en-us" }Common types: INDEX, PRODUCT, COLLECTION, ALL_PRODUCTS, COLLECTION_LIST, PAGE, BLOG, ARTICLE, CUSTOM.
For CUSTOM pages, set handle to the route slug (e.g., "reseller"). For standard template pages, handle is usually empty "".
Standard pages (product, collection, blog, article) that aren't being customized should be empty stubs:
{
"id": "qa8xa47ou35atbo1ik4w7v6y",
"name": "Default product",
"rootId": "019b917a-f490-794d-95d0-82a578d7cdfc",
"items": [{ "id": "019b917a-f490-794d-95d0-82a578d7cdfc", "type": "main", "data": {}, "children": [] }]
}Before writing any select, toggle-group, or position value, read the section source code. Common mistakes:
| Wrong | Correct | Field |
|---|---|---|
"custom" | "small", "medium", "large", "full" | height |
"stretch" | "full", "fixed" | width |
"right" / "left" | "start", "end" | desktopMediaPosition |
"white" / "black" | "light", "dark" | arrowsColor |
If a field matches the schema default, omit it. The Weaverse editor strips defaults on save. Including them creates noise.
Schema presets are not defaults: a value a section's presets turn on (e.g. enableOverlay: true) is only applied when a merchant adds the section in Studio, not on import or Content API writes. Compare against the input's defaultValue, and write any preset value you actually want explicitly.
Collections and products use object format, not bare strings:
// Collections
"collections": [{ "id": 456905851102, "handle": "covers" }]
// Products
"product": { "id": 123456789, "handle": "my-product" }If real Shopify IDs are unknown, omit the field or use []. Do not invent fake IDs.
External images use a bare URL string. Shopify-hosted images use the media object:
// External
"backgroundImage": "https://example.com/image.jpg"
// Shopify media
"backgroundImage": {
"id": "gid://shopify/MediaImage/12345",
"url": "https://cdn.shopify.com/...",
"width": 1920, "height": 1080, "altText": "Description"
}For anything that will go live, use Shopify media. Figma MCP asset URLs (figma.com/api/mcp/asset/...) expire after about 7 days and some storefront image transforms block them; upload the files to Shopify first (weaverse-content-api → upload) and use the returned objects. SVGs upload as generic files and come back as a plain CDN URL string.
Page IDs and item IDs use different formats:
| Entity | Format | Example |
|---|---|---|
| Page `id` | CUID (25-char alphanumeric) | b98mnnqmv3tmce7wmw3l7vw4 |
Item `id` (and rootId) | UUID v7 (hyphenated) | 019b917a-f48f-72d4-aee7-3b1eae6b7dca |
Integrity rules:
id must be unique across the exportid must be unique across the exportrootId must match the root main item's id exactly019b9400-… for the homepage, 019b9500-… for the next page) so items never collide when pages are pushed to the same projectAfter generating the JSON, run the bundled validator:
python3 scripts/validate.py <path-to-output.json>The validator checks:
id, name, rootId, itemsrootId resolves to an item with type: "main"data and children fields (both required)pageAssignment.pageId values resolve to existing pagesFix any reported errors and re-run until clean. Do not deliver JSON that fails validation.
| Mistake | Fix |
|---|---|
Missing data or children on items | Both are REQUIRED on every item — use "data": {} and "children": [] even when empty |
Nesting full items inside children | Use { "id": "..." } references only |
rootId doesn't match any item | Ensure root main item's id equals rootId |
| Using unregistered section types | Read app/weaverse/components.ts first |
| Duplicate IDs | Page IDs = CUIDs, item IDs = UUIDs — every id must be unique |
Including default values in data | Omit fields that match schema defaults |
| Guessing enum values | Read the section source for valid options |
| Copying entire demo theme blindly | Only include keys you understand and intend |
Missing pageAssignments | Every page needs a route assignment |
| Fake Shopify IDs | Omit unknown IDs, let user select in editor |
| Leaving Figma asset URLs in a live export | Upload to Shopify and use media objects — Figma asset URLs expire |
| Relying on preset values | Presets aren't applied on import/API writes; set those values explicitly |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.