| name | build-setup |
| description | Generate SETUP.md with priority-ordered plugin configuration and content replacement guidance, and update build.json with NL-specific metadata |
| requires | [] |
| runs-after | ["build-content"] |
| runs-before | ["zip-packaging"] |
Build Setup Skill
Generate SETUP.md — the user's post-import configuration and content replacement guide — and update build.json with NL-specific metadata. This skill runs after build-content and before zip packaging.
Input variables (set by build-theme and build-content):
| Variable | Source | Description |
|---|
BUILD_DIR | build-scaffold | Absolute path to the build working directory |
NL_PROMPT | COMMAND.md Section 1 | Original natural language site description |
THEME_SLUG | build-theme | Installed theme slug |
THEME_NAME | build-theme | Human-readable theme name |
THEME_VERSION | build-theme | Installed theme version string |
THEME_INSTALLED | build-theme | Boolean — true if theme installed successfully |
INSTALLED_PLUGINS | build-content | Array of slug:name:version for successfully installed plugins |
FAILED_PLUGINS | build-content | Array of slugs that failed to install or activate |
PAGES_CREATED | build-content | Integer count of pages created |
POSTS_CREATED | build-content | Integer count of posts created |
MENU_ASSIGNED | build-content | Boolean — true if navigation menu was assigned to a theme location |
MENU_LOCATION | build-content | The theme location name used (or empty string if unassigned) |
Section 1: SETUP.md Generation
Write $BUILD_DIR/SETUP.md using the full context available — installed plugins, theme, page count, and NL prompt — to produce a priority-ordered setup guide the user can follow immediately after importing the site into Local WP.
echo "[Build] Generating SETUP.md..."
SETUP_FILE="$BUILD_DIR/SETUP.md"
cat > "$SETUP_FILE" << 'SETUP_HEADER'
This guide walks you through configuring your new WordPress site after importing
it into Local WP. Items are ordered by priority — complete the Critical steps
first, then work through Important and Optional at your own pace.
---
SETUP_HEADER
echo "- **Theme:** ${THEME_NAME} (v${THEME_VERSION})" >> "$SETUP_FILE"
echo "" >> "$SETUP_FILE"
if [ ${#INSTALLED_PLUGINS[@]} -gt 0 ]; then
echo "- **Plugins:**" >> "$SETUP_FILE"
for plugin_entry in "${INSTALLED_PLUGINS[@]}"; do
PLUGIN_SLUG=$(echo "$plugin_entry" | cut -d: -f1)
PLUGIN_NAME=$(echo "$plugin_entry" | cut -d: -f2)
PLUGIN_VER=$(echo "$plugin_entry" | cut -d: -f3)
PLUGIN_PURPOSE="<one-line description of what ${PLUGIN_NAME} does — generated by Claude from knowledge of the plugin>"
echo " - **${PLUGIN_NAME}** (v${PLUGIN_VER}) — ${PLUGIN_PURPOSE}" >> "$SETUP_FILE"
done
echo "" >> "$SETUP_FILE"
fi
if [ ${#FAILED_PLUGINS[@]} -gt 0 ]; then
echo "- **Plugins That Failed to Install:**" >> "$SETUP_FILE"
for slug in "${FAILED_PLUGINS[@]}"; do
echo " - ${slug} — installation was attempted but failed during build" >> "$SETUP_FILE"
done
echo "" >> "$SETUP_FILE"
fi
Next, write the priority-ordered action list. This is an AI judgment task — Claude generates the actual step-by-step instructions for each plugin based on Claude's knowledge of that plugin's settings workflow, using the NL prompt context to determine what matters most for this particular site.
cat >> "$SETUP_FILE" << 'SETUP_NEXT'
---
SETUP_NEXT
echo "### Critical" >> "$SETUP_FILE"
echo "" >> "$SETUP_FILE"
STEP_NUM=1
echo "${STEP_NUM}. **Replace Contact page placeholder info**" >> "$SETUP_FILE"
cat >> "$SETUP_FILE" << 'CONTACT_STEP'
Go to: **Pages > Contact > Edit**
Replace the following placeholder content with your real details:
- The fictional business name in the page heading
- The fictional street address (e.g., "123 Example Street, Sample City")
- The fictional phone number
- The fictional email address
- Any fictional business hours or location details
CONTACT_STEP
STEP_NUM=$((STEP_NUM + 1))
echo "" >> "$SETUP_FILE"
echo "### Important" >> "$SETUP_FILE"
echo "" >> "$SETUP_FILE"
echo "${STEP_NUM}. **Update About page content**" >> "$SETUP_FILE"
cat >> "$SETUP_FILE" << 'ABOUT_STEP'
Go to: **Pages > About > Edit**
Replace the following placeholder content:
- The fictional business/person name and biography
- Any fictional team member descriptions
- The placeholder headshot or profile image (upload your own via the Media block)
- Any fictional credentials, history, or origin story
ABOUT_STEP
STEP_NUM=$((STEP_NUM + 1))
echo "${STEP_NUM}. **Update Home page hero and intro content**" >> "$SETUP_FILE"
cat >> "$SETUP_FILE" << 'HOME_STEP'
Go to: **Pages > Home > Edit**
Replace the following placeholder content:
- The hero heading and tagline (make it specific to your business or offer)
- The hero background or featured image (upload via the Cover/Image block)
- The introductory paragraph describing what you do
- Any call-to-action button labels and links
HOME_STEP
STEP_NUM=$((STEP_NUM + 1))
echo "" >> "$SETUP_FILE"
echo "### Optional" >> "$SETUP_FILE"
echo "" >> "$SETUP_FILE"
echo "${STEP_NUM}. **Add your own blog posts to replace sample content**" >> "$SETUP_FILE"
cat >> "$SETUP_FILE" << 'POSTS_STEP'
The sample posts demonstrate how your theme renders blog content. They use
realistic but fictional topics related to your site's subject matter.
Go to: **Posts > All Posts** to edit the existing samples or add new ones.
You can delete the sample posts once you have published your own content.
POSTS_STEP
STEP_NUM=$((STEP_NUM + 1))
# Placeholder image replacement
echo "${STEP_NUM}. **Replace placeholder images with your own photos**" >> "$SETUP_FILE"
cat >> "$SETUP_FILE" << 'IMAGES_STEP'
Solid-color placeholder images were generated during the build to show
layout intent. Replace them with your own images:
Go to: **Media > Add New** to upload your photos
Then edit each page/post and swap the placeholder image blocks for your uploads.
IMAGES_STEP
STEP_NUM=$((STEP_NUM + 1))
# Menu assignment if not automatically assigned (FSE block theme edge case)
if [ "$MENU_ASSIGNED" = "false" ] || [ "$MENU_ASSIGNED" = "" ]; then
echo "${STEP_NUM}. **Assign navigation menu in the Site Editor**" >> "$SETUP_FILE"
cat >> "$SETUP_FILE" << 'MENU_STEP'
Your navigation menu was created during the build but could not be assigned
to a theme location automatically (this is expected for block themes).
Go to: **Appearance > Editor > Navigation**
Select "Primary Menu" and place it in your header navigation area.
MENU_STEP
STEP_NUM=$((STEP_NUM + 1))
fi
# Finalize SETUP.md
echo "---" >> "$SETUP_FILE"
echo "" >> "$SETUP_FILE"
echo "*Generated by WordPress Expert Plugin — CoWork Build System*" >> "$SETUP_FILE"
SETUP_ITEM_COUNT=$((STEP_NUM - 1))
echo "[Build] SETUP.md generated (${SETUP_ITEM_COUNT} setup items)"
Implementation notes for Claude:
- Plugin instructions are an AI judgment task. For each plugin in
INSTALLED_PLUGINS, Claude generates verbose, step-by-step instructions using its knowledge of that plugin's settings workflow. Instructions must include full WP admin navigation paths (e.g., "Go to WPForms > Add New > Select Contact Form template > Save > Copy shortcode > Edit Contact page > Add shortcode block").
- Context drives priority. Claude reads
NL_PROMPT to determine which setup items are Critical vs Important. For a photography portfolio site, replacing portfolio images is Critical. For a restaurant, configuring a reservation plugin is Critical.
- Page-by-page coverage. Every page created by build-content gets a dedicated entry with specific guidance on what placeholder content it contains.
- No generic instructions. All guidance is specific to the plugin and site type — not generic "configure your plugins" advice.
Section 2: build.json NL Metadata Update
Read the existing build.json (created by build-scaffold Section 6) and add NL-specific fields. Uses the same Python3 JSON parsing pattern established in build-mcp Section 4.
echo "[Build] Updating build.json with NL metadata..."
BUILD_JSON="$BUILD_DIR/build.json"
INSTALLED_JSON=""
for plugin_entry in "${INSTALLED_PLUGINS[@]}"; do
PLUGIN_SLUG=$(echo "$plugin_entry" | cut -d: -f1)
PLUGIN_NAME=$(echo "$plugin_entry" | cut -d: -f2)
PLUGIN_VER=$(echo "$plugin_entry" | cut -d: -f3)
if [ -n "$INSTALLED_JSON" ]; then
INSTALLED_JSON="${INSTALLED_JSON},"
fi
INSTALLED_JSON="${INSTALLED_JSON}{\"slug\":\"${PLUGIN_SLUG}\",\"name\":\"${PLUGIN_NAME}\",\"version\":\"${PLUGIN_VER}\",\"installed\":true}"
done
FAILED_JSON=""
for slug in "${FAILED_PLUGINS[@]}"; do
if [ -n "$FAILED_JSON" ]; then
FAILED_JSON="${FAILED_JSON},"
fi
FAILED_JSON="${FAILED_JSON}\"${slug}\""
done
NL_META_SCRIPT="/tmp/update_build_json_$$.py"
cat > "$NL_META_SCRIPT" << PYEOF
import json, sys
build_file = sys.argv[1]
nl_prompt = sys.argv[2]
theme_slug = sys.argv[3]
theme_name = sys.argv[4]
theme_version = sys.argv[5]
theme_installed = sys.argv[6] == 'true'
pages_created = int(sys.argv[7])
posts_created = int(sys.argv[8])
menu_assigned = sys.argv[9] == 'true'
installed_json = sys.argv[10]
failed_json = sys.argv[11]
with open(build_file) as f:
data = json.load(f)
data['mode'] = 'nl'
data['nl_prompt'] = nl_prompt
data['theme'] = {
'slug': theme_slug,
'name': theme_name,
'version': theme_version,
'installed': theme_installed
}
data['plugins'] = json.loads('[' + installed_json + ']') if installed_json else []
data['content'] = {
'pages_created': pages_created,
'posts_created': posts_created,
'menu_assigned': menu_assigned
}
if failed_json:
data['failed_plugins'] = json.loads('[' + failed_json + ']')
with open(build_file, 'w') as f:
json.dump(data, f, indent=2)
print('[Build] build.json updated with NL metadata')
PYEOF
python3 "$NL_META_SCRIPT" \
"$BUILD_JSON" \
"$NL_PROMPT" \
"$THEME_SLUG" \
"$THEME_NAME" \
"$THEME_VERSION" \
"${THEME_INSTALLED:-true}" \
"$PAGES_CREATED" \
"$POSTS_CREATED" \
"${MENU_ASSIGNED:-false}" \
"$INSTALLED_JSON" \
"$FAILED_JSON"
rm -f "$NL_META_SCRIPT"
build.json after NL metadata update:
{
"build_id": "nl-photography-portfolio-20260220-143022",
"mode": "nl",
"nl_prompt": "a portfolio site for a freelance photographer",
"wp_version": "6.7",
"php_version": "8.2",
"site_url": "http://localhost",
"site_title": "a portfolio site for a freelance photographer",
"created_at": "2026-02-20T14:30:22Z",
"theme": {
"slug": "blocksy",
"name": "Blocksy",
"version": "2.0.50",
"installed": true
},
"plugins": [
{ "slug": "envira-gallery-lite", "name": "Envira Gallery Lite", "version": "1.9.0", "installed": true },
{ "slug": "wpforms-lite", "name": "WPForms Lite", "version": "1.9.0", "installed": true }
],
"content": {
"pages_created": 4,
"posts_created": 3,
"menu_assigned": false
},
"failed_plugins": [],
"mcp_adapter": {
"included": true,
"activated": true,
"version": "0.4.1"
}
}
Section 3: Build Summary Extension
Append NL-specific lines to the build summary output. This runs after build-scaffold Section 7 (base summary) and build-mcp Section 5 (MCP extension) to add NL build details.
INSTALLED_COUNT=${#INSTALLED_PLUGINS[@]}
FAILED_COUNT=${#FAILED_PLUGINS[@]}
if [ "$MENU_ASSIGNED" = "true" ] && [ -n "$MENU_LOCATION" ]; then
MENU_STATUS="assigned to '${MENU_LOCATION}'"
else
MENU_STATUS="created but not assigned (see SETUP.md)"
fi
echo ""
echo "[Build] ── NL Build Details ──────────────────"
echo "[Build] Prompt: \"${NL_PROMPT}\""
echo "[Build] Theme: ${THEME_NAME} (${THEME_SLUG} v${THEME_VERSION})"
echo "[Build] Plugins: ${INSTALLED_COUNT} installed, ${FAILED_COUNT} failed"
echo "[Build] Content: ${PAGES_CREATED} pages, ${POSTS_CREATED} posts"
echo "[Build] Menu: ${MENU_STATUS}"
echo "[Build] Guide: SETUP.md included in zip"
echo ""
Example output for a photography portfolio build:
[Build] ── NL Build Details ──────────────────
[Build] Prompt: "a portfolio site for a freelance photographer"
[Build] Theme: Blocksy (blocksy v2.0.50)
[Build] Plugins: 2 installed, 0 failed
[Build] Content: 4 pages, 3 posts
[Build] Menu: created but not assigned (see SETUP.md)
[Build] Guide: SETUP.md included in zip