build-scaffold
Scaffold a blank WordPress installation with Docker MySQL, WP-CLI, SQL export, zip packaging, and build.json manifest
1 finding in 1 files. Read them before installing.
- Asks for elevated privileges or changes permissions broadly · employees/specialized/wordpress-master/diagnostics/build-scaffold/SKILL.md:48
echo " sudo mv wp-cli.phar /usr/local/bin/wp"
This is a pattern scan of the skill folder, not a judgment of intent. Some matches are legitimate (an installer, a quoted warning). Checked on Oct 20, 2026. How the scan works.
npx degit Shaisolaris/solaris-dev-shop/employees/specialized/wordpress-master/diagnostics/build-scaffold .claude/skills/build-scaffold12 alternatives · Best backend skills · Author? Prove this skill
SKILL.md
# Build Scaffold Skill
Complete blank WordPress installation pipeline. Spins up an ephemeral Docker MySQL container, uses WP-CLI to download and install WordPress, exports the database, packages everything as a Local WP importable zip, and writes a build.json manifest.
This skill expects the following variables to be set by the calling command before invocation:
- `MODE` - build mode (e.g. "blank")
- `SLUG` - directory name slug (e.g. "blank-site")
- `WP_VERSION` - WordPress version to install (default: "latest")
- `SITE_TITLE` - Site title string (default: "Blank WordPress Site")
## Section 1: Prerequisite Checks
Check that Docker and WP-CLI are available before proceeding.
```bash
# Check Docker is running
if ! docker info > /dev/null 2>&1; then
echo ""
echo "ERROR: Docker is required for /build. Start Docker Desktop and try again."
echo ""
exit 1
fi
# Check for local WP-CLI first (preferred)
if which wp > /dev/null 2>&1; then
WP_CLI_MODE="local"
echo "[Build] Prerequisites OK - Docker ✓, WP-CLI ✓ (local)"
else
# Fall back to Docker-based WP-CLI
echo "[Build] Local WP-CLI not found. Checking Docker WP-CLI fallback..."
if docker run --rm wordpress:cli wp --version > /dev/null 2>&1; then
WP_CLI_MODE="docker"
echo "[Build] Prerequisites OK - Docker ✓, WP-CLI ✓ (docker)"
else
echo ""
echo "ERROR: WP-CLI is required for /build but was not found."
echo ""
echo "Install WP-CLI:"
echo " curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar"
echo " chmod +x wp-cli.phar"
echo " sudo mv wp-cli.phar /usr/local/bin/wp"
echo ""
echo "Full instructions: https://wp-cli.org"
echo ""
exit 1
fi
fi
```
## Section 2: Build Directory Setup
Create a timestamped build directory in the user's current working directory.
```bash
# Input variables (set by calling command)
# MODE, SLUG, WP_VERSION, SITE_TITLE
# Apply defaults
WP_VERSION="${WP_VERSION:-latest}"
SITE_TITLE="${SITE_TITLE:-Blank WordPress Site}"
SLUG="${SLUG:-blank-site}"
MODE="${MODE:-blank}"
# Generate datestamp and directory name
DATESTAMP=$(date +%Y-%m-%d)
BUILD_DIR_NAME="${DATESTAMP}-${SLUG}"
BUILD_DIR="${PWD}/${BUILD_DIR_NAME}"
# Collision check - append random suffix if directory already exists
if [ -d "$BUILD_DIR" ]; then
SUFFIX=$(openssl rand -hex 2)
BUILD_DIR_NAME="${BUILD_DIR_NAME}-${SUFFIX}"
BUILD_DIR="${PWD}/${BUILD_DIR_NAME}"
fi
# Create the directory
mkdir -p "$BUILD_DIR"
echo "[Build] Directory: $BUILD_DIR"
```
## Section 3: Ephemeral Docker MySQL
Spin up a temporary MySQL 8.0 container on port 3307. Set an EXIT trap so the container is always cleaned up, even if the build fails.
```bash
# Container name using PID for uniqueness
MYSQL_CONTAINER="wpbuild-mysql-$$"
# Generate random passwords (never hardcoded)
MYSQL_ROOT_PASS="wpbuild_root_$(openssl rand -hex 8)"
MYSQL_PASS="$(openssl rand -hex 12)"
# Pre-flight: check port 3307 is free
if lsof -i :3307 > /dev/null 2>&1; then
echo ""
echo "ERROR: Port 3307 is already in use."
echo "Close the conflicting process (check with: lsof -i :3307) and try again."
echo ""
exit 1
fi
# Cleanup trap - runs on EXIT (normal or error)
cleanup_mysql() {
echo "[Build] Cleaning up Docker container..."
docker rm -f "$MYSQL_CONTAINER" 2>/dev/null || true
echo "[Build] Cleanup complete."
}
trap cleanup_mysql EXIT
# Start MySQL container
docker run -d \
--name "$MYSQL_CONTAINER" \
-e MYSQL_ROOT_PASSWORD="$MYSQL_ROOT_PASS" \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wp \
-e MYSQL_PASSWORD="$MYSQL_PASS" \
-p 127.0.0.1:3307:3306 \
mysql:8.0 \
--default-authentication-plugin=mysql_native_password \
> /dev/null
echo "[Build] Starting MySQL container..."
# Wait for MySQL to be ready (up to 30 seconds)
WAIT_COUNT=0
until docker exec "$MYSQL_CONTAINER" mysqladmin ping --silent 2>/dev/null; do
WAIT_COUNT=$((WAIT_COUNT + 1))
if [ "$WAIT_COUNT" -ge 30 ]; then
echo ""
echo "ERROR: MySQL container failed to start within 30 seconds."
echo ""
exit 1
fi
sleep 1
done
echo "[Build] Database ready."
```
## Section 4: WP-CLI Build Pipeline
Download WordPress core, configure it, run the install, and export the database. All steps check for errors and abort with a clear message on failure.
```bash
# Set WP command based on WP_CLI_MODE
if [ "$WP_CLI_MODE" = "local" ]; then
WP="wp --path=$BUILD_DIR"
else
# Docker WP-CLI - mount build directory as WordPress root
WP="docker run --rm -v \"$BUILD_DIR:/var/www/html\" --network host wordpress:cli wp --allow-root"
fi
# Step 1: Download WordPress core
echo "[Build] Downloading WordPress core..."
if ! $WP core download --version="$WP_VERSION" 2>&1; then
echo ""
echo "ERROR: WordPress core download failed. Check your internet connection."
echo ""
exit 1
fi
# Step 2: Create wp-config.php
echo "[Build] Configuring WordPress..."
if ! $WP config create \
--dbname=wordpress \
--dbuser=wp \
--dbpass="$MYSQL_PASS" \
--dbhost=127.0.0.1:3307 \
--skip-check \
--extra-php='
define( "WP_DEBUG", true );
define( "WP_DEBUG_LOG", true );
define( "WP_DEBUG_DISPLAY", false );
' 2>&1; then
echo ""
echo "ERROR: wp-config.php creation failed."
echo ""
exit 1
fi
# Step 3: Run WordPress install
echo "[Build] Installing WordPress..."
# Generate random admin password (displayed in terminal, never stored)
ADMIN_PASS="$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | head -c 16)"
if ! $WP core install \
--url=http://localhost \
--title="$SITE_TITLE" \
--admin_user=admin \
--admin_password="$ADMIN_PASS" \
--admin_email=admin@example.local \
--skip-email 2>&1; then
echo ""
echo "ERROR: WordPress install failed. Check the MySQL container is running."
echo ""
exit 1
fi
# Step 4: Export database
echo "[Build] Exporting database..."
if ! $WP db export "$BUILD_DIR/database.sql" --add-drop-table 2>&1; then
echo ""
echo "ERROR: Database export failed."
echo ""
exit 1
fi
```
## Section 5: Zip Packaging (Local WP Compatible)
Package wp-content/ and database.sql into a zip file at the Local WP importable format. CRITICAL: cd into BUILD_DIR before zipping to avoid nested path prefixes in the archive.
```bash
# Compute absolute zip path BEFORE changing directory
ZIP_PATH="$(dirname "$BUILD_DIR")/${BUILD_DIR_NAME}.zip"
echo "[Build] Packaging for Local WP..."
# cd into build dir so zip uses relative paths (wp-content/ and database.sql at root)
# NOTE: This is the BASE zip command. COMMAND.md pipelines MUST extend this to include
# additional files generated by later skills: README.md, SETUP.md, .git/, .gitignore,
# and scrape.json (URL builds). The COMMAND.md zip step is the canonical command.
(
cd "$BUILD_DIR" && \
zip -r "$ZIP_PATH" wp-content/ database.sql \
$([ -f README.md ] && echo "README.md") \
$([ -f SETUP.md ] && echo "SETUP.md") \
$([ -d .git ] && echo ".git/") \
$([ -f .gitignore ] && echo ".gitignore") \
$([ -f scrape.json ] && echo "scrape.json") \
$([ -f build.json ] && echo "build.json")
)
ZIP_EXIT=$?
if [ $ZIP_EXIT -ne 0 ]; then
echo ""
echo "ERROR: Zip packaging failed (exit code: $ZIP_EXIT)."
echo ""
exit 1
fi
# Verify zip structure (should show wp-content/ and database.sql at root)
echo "[Build] Verifying zip structure..."
unzip -l "$ZIP_PATH" | head -10
echo "[Build] Zip created: $ZIP_PATH"
```
## Section 6: Build Manifest (build.json)
Write a build.json manifest to the build directory. Admin password is NOT included - displayed in terminal only.
```bash
# Generate build ID
BUILD_ID="build-$(date +%Y%m%d%H%M%S)-$(openssl rand -hex 4)"
# Get actual WP version installed
WP_VERSION_ACTUAL=$($WP core version 2>/dev/null || echo "$WP_VERSION")
# Write build.json
cat > "$BUILD_DIR/build.json" << MANIFEST
{
"build_id": "${BUILD_ID}",
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"mode": "${MODE}",
"wp_version": "${WP_VERSION_ACTUAL}",
"build_dir": "${BUILD_DIR}",
"zip_path": "${ZIP_PATH}",
"site_url": "http://localhost",
"admin_user": "admin"
}
MANIFEST
echo "[Build] Manifest written: $BUILD_DIR/build.json"
```
## Section 7: Build Summary Output
Display a formatted build summary. Admin password is displayed here and nowhere else - it is not stored in any file.
```bash
echo ""
echo "Build complete!"
echo ""
echo " Build ID: $BUILD_ID"
echo " Mode: $MODE"
echo " WP Version: $WP_VERSION_ACTUAL"
echo " Build Dir: $BUILD_DIR"
echo " Zip File: $ZIP_PATH"
echo ""
echo " Admin URL: http://localhost/wp-admin"
echo " Admin User: admin"
echo " Admin Password: $ADMIN_PASS"
echo ""
echo "Import $ZIP_PATH into Local WP to get started."
echo ""
```
## Section 8: Cleanup
The EXIT trap set in Section 3 handles Docker container cleanup automatically on script exit (both normal and error paths). No additional cleanup is needed here.
```bash
# Cleanup is handled automatically by the EXIT trap (cleanup_mysql function)
# set in Section 3. The trap fires when the script exits for any reason:
# - Normal completion
# - Error exit
# - User interrupt (Ctrl+C)
# No manual cleanup required here.
# The [Build] Cleanup complete. message is printed by cleanup_mysql.
```
## Implementation Notes
- All progress messages use the `[Build]` prefix for consistent output parsing
- Each WP-CLI step checks the exit code and aborts with a clear error message on failure
- Admin password is generated with `openssl rand` - never hardcoded, never stored in files
- Docker container name includes the shell PID (`$$`) to prevent naming conflicts when running multiple builds simultaneously
- Port 3307 is used for Docker MySQL to avoid conflicts with a locally running MySQL on port 3306
- The `--allow-root` flag is automatically included when using Docker WP-CLI (runs as root inside the container)
- Zip packaging uses a subshell `(cd "$BUILD_DIR" && zip ...)` to preserve cwd for the parent process
- build.json records all metadata EXCEPT admin password - admin password is terminal-onlyShown under the source repo’s MIT license. Read the full folder on GitHub.