Generated banner for Wix Replatform
Generated logo for Wix Replatform

Wix Replatform

WixOfficialPublished by Wix

  • Skill
  • Workflow
  • Automation and integrations
  • MIT
  • Low risk
  • Has scripts

From the author

Routes RePlatform source-to-Wix migrations to the next required workflow module by inspecting authoritative migration artifacts. Use when starting, resuming, or recovering a migration run.
— the description by Wix

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

wix-replatform acts as a central orchestrator for migrating data and websites to Wix. It ensures migration integrity by using a state-based routing system that inspects authoritative artifacts to determine the next required step. The skill enforces strict adherence to migration stages, handles resumability, and manages delivery modes ranging from backend-only management to full website integration. It prioritizes data safety, idempotency, and clear state tracking, ensuring that migrations are neither duplicated nor prematurely declared complete.

What it does

  • Routes migration tasks to specific modules based on current project state.
  • Supports resumable migrations by inspecting authoritative artifacts.
  • Enforces strict execution gates and approval requirements before data writes.
  • Manages different delivery modes including management-only and integrated website migrations.
  • Provides a 1-click automation mode for streamlined, non-interactive execution.
  • Handles recovery for tool-resolution or path failures using interactive shell retries.

When to use it

  • When initiating a new source-to-Wix migration project.
  • When resuming a migration that was previously interrupted or halted.
  • When managing complex migrations requiring both backend data and frontend website handoff.
  • When performing quick, bounded public-data imports from supported platforms.

Advantages

  • Prevents data loss through idempotent writes and deduplication.
  • Ensures consistency by routing based on deterministic artifact state rather than memory.
  • Provides clear visibility into migration progress and blockers.
  • Automates complex multi-stage workflows while maintaining safety gates.

Usage examples

“Start a new migration for my project in ./migrations/my-store.”
The agent initializes the project, loads the orchestration artifacts, and routes to the intake module to begin the migration process.
“Resume the migration for my-store.”
The agent inspects the existing artifacts in the project directory, determines the last completed stage, and routes to the next required module.
“Run a 1-click migration for my-store.”
The agent enters 1-click mode, automatically collecting missing intake values and proceeding through the migration stages without pausing for routine approvals.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/wix/wix-replatform/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip wix-replatform.zip -d .agents/skills

Documentation by Wix

wix-replatform

wix-replatform is the compact supervisor for a resumable source-to-Wix migration. It selects one internal module for the active stage; it does not carry every stage procedure in its own context.

Always-active contract

  • Resolve the active project under migrations/<project>/ (or REPLATFORM_MIGRATIONS_DIR) before inspecting or creating anything. Only that project's artifacts are authoritative.

  • Start/resume resources/rp-telemetry/ at the beginning of every run and finalize it at a terminal state. Never hand-write telemetry events.

  • Use orchestration JSON plus validated stage artifacts as resume authority. Logs and chat history are diagnostic context only.

  • Preserve user data: write idempotently, dedupe by source identity, resume rather than restart, and never create a second destination site for a migration.

  • Never print secrets, secret-bearing config contents, tokens, or credentials. Report only key names and present/blank/missing status.

  • Do not declare a migration complete from prose or a single artifact. The deterministic router and aggregate completion artifact own terminal completion.

Pipeline

intake → destination → source inputs → preflight → (standard: discovery → mapping → codegen;
quick: adapter preflight → quick plan) → setup discovery → website handoff
→ safety review/approval → setup → import
→ storefront continuation (website only) → aggregate finalization

Delivery modes are management (backend only), website (frontend only), and management_and_website (the integrated flow above). Accept user input both as management_and_website and persist the canonical value.

For deliveryMode=management, aggregate finalization requires valid backend import accounting. For deliveryMode=management_and_website, it additionally requires a current website/completion.json with completed screenshot review, no unresolved critical/high gaps, and release evidence. execution/completion-report.json is backend accounting, never website-migration completion by itself.

Route before acting

On every new or resumed turn:

  1. Resolve the project and initialize/load its orchestration artifacts.

  2. Run node skills/wix-replatform/scripts/orchestration-route.js <projectDir>.

  3. Load only the nextResource returned by the route, then follow that resource until it writes its required output or a durable blocker.

  4. Route again after every stage boundary. Never decide the next stage from memory.

If an artifact is malformed, partial, stale, or fails its validator, treat its producing stage as incomplete and route to the producer. Do not make parallel replacement artifacts.

Demand-loaded module map

Router situationLoad
project, delivery mode, source mode, or grouped intake is unresolvedresources/rp-project-intake/
destination is absent, conflicting, or needs creation/adoptionresources/rp-destination/
source URL/files/config/acquisition mode/credentials are requiredresources/rp-source-inputs/
deterministic preflight is missing or blockedresources/rp-preflight/
quick mode needs platform resolution, endpoint preflight, plan, extraction, or importselected resources/rp-quick-<platform>/
source schema is missingresources/rp-discovery/ and its selected source adapter
mapping is missing or needs reviewresources/rp-mapper/
Wix requirements are missingresources/rp-setup-discovery/
import code/review is missing or staleresources/rp-import-codegen/
setup verification is missingresources/rp-execute-setup/
backend completion report is missingresources/rp-execute-import/
frontend-only work, or integrated website handoff/build/gap loop/release receipt is incompleteresources/rp-website-continuation/
aggregate completion is missingresources/rp-execution-policy/

The resource named by the route is the complete stage contract. Do not load source-file, secret, scaffolding, or storefront procedures for a stage where they are irrelevant.

Interaction policy

Normal mode asks only for a missing required input, a genuinely ambiguous active project, or a mandatory write approval. Ask one question at a time unless a module says otherwise.

Before writes, preserve the mandatory execution-plan approval gate. Read-only discovery, mapping, setup verification, code generation, and review happen before it.

Quick management import mode

When managementImportMode=quick, select the platform adapter only after the deterministic source probe identifies a compatible platform. Quick mode is a bounded public-data import: the adapter's versioned quick-mode.json owns its source routes, entity graph, field matrix, and exclusions. Do not run agentic discovery, mapping, or project-specific code generation for the quick backend branch. Still run destination setup, application installation, Catalog-V3 and notification safety checks, execution approval, shared write runtime, crosswalks, and completion accounting. If no adapter qualifies, persist the unsupported-mode result and ask the user to select standard mode; never silently fall back.

Halt only for missing/invalid required input, a manual action with no API, or a systemic failure/data-loss risk. A halt must persist the code, evidence, owner, and exact unblock action; never silently stop.

1-click mode

When explicitly requested by the user, record automationMode=one_click with source=user and apply the following. A missing mode or a one_click value recorded as deterministic_inference/prior_artifact is normal interactive mode and must not skip a checkpoint:

  • collect all still-missing intake values in one grouped request; then do not pause for routine approvals;

  • record mapping and execution approvals as approved, decidedBy=agent; skipping a pause without state is invalid;

  • for CSV/file-only runs, validate and accept the required sample preview as the agent; without explicit user-authored one-click, pause for the normal mapping review, sample preview validation, and execution approval;

  • default to a new isolated site unless an existing destination is explicitly supplied or already pinned; choose website scope deterministically from discovered route families;

  • retry PATH/tool-resolution failures under the operator's compatible interactive login shell; request required browser/network sandbox escalation and retry before calling it blocked;

  • retry the obvious recovery before stopping: aligned shell first for PATH/tool failures, then the required escalation retry for sandboxed browser or network/API failures;

  • continue through the complete selected deliverable. In management_and_website mode that includes frontend build, post-build gap analysis, bounded fix loop, and release receipt; when the user selected facelift at intake, it also includes the separate post-clone facelift review;

  • before yielding, re-route. A 1-click run is only completed with completion/migration-completion.json, or blocked with a typed durable blocker.

Use the operator's compatible local Node/Yarn shell when recovering from a PATH or tool resolution failure. Machine-specific shell paths belong only in local, git-excluded agent instructions.

Repo-local interactive shell contract: a PATH/tool-resolution failure on first attempt may mean the command ran under a plain, non-interactive shell that never sourced the operator's Node/Yarn profile. Resolve the operator's compatible login shell from the local environment or git-excluded agent instructions, verify that it is executable, and retry the exact same command through that shell in interactive login mode so the profile that resolves node/yarn/npx loads. Do not hardcode a machine-specific shell path in this public skill. Only escalate to a durable blocker if the compatible-shell retry itself fails.

Guardrails

  • Never bypass a validator, approval-state update, verified notification mute, or Catalog-V3 gate to make a stage appear finished.

  • website means frontend only; management_and_website means the integrated backend and frontend migration. Never hand the integrated migration destination to the frontend skill or create a second frontend site in that mode.

  • Do not implement a storefront manually when wix-headless-replatform is unavailable; persist a blocker with the exact required runtime capability.

  • In management mode, still generate website/handoff.* after setup discovery so a later storefront can start without repeating backend discovery.

Files

scripts/wix-headless-scaffold.js

#!/usr/bin/env node
'use strict';

const { spawn } = require('node:child_process');
const fs = require('node:fs/promises');
const path = require('node:path');
const { readEnvFile, upsertEnvFile, statEnvKeys } = require('../lib/config-env.js');

function usage() {
  return [
    'Usage:',
    '  node scripts/wix-headless-scaffold.js --business-name <name> [--folder-name frontend] [--site-template commerce] [--project-dir <dir>]',
    '',
    'Runs the Wix headless scaffold non-interactively through npm create.',
    'Idempotent: safe to re-invoke against the same project (spec 0085) — adopts an',
    'existing destination receipt instead of re-scaffolding, and never spawns a second',
    'site when config/wix.env or frontend/wix.config.json already name one.',
  ].join('\n');
}

function parseArgs(argv) {
  const args = {
    folderName: 'frontend',
    siteTemplate: 'blank',
    projectDir: process.cwd(),
  };
  for (let i = 0; i < argv.length; i += 1) {
    const token = argv[i];
    switch (token) {
      case '--business-name':
        args.businessName = argv[i + 1];
        i += 1;
        break;
      case '--folder-name':
        args.folderName = argv[i + 1];
        i += 1;
        break;
      case '--site-template':
        args.siteTemplate = argv[i + 1];
        i += 1;
        break;
      case '--project-dir':
        args.projectDir = argv[i + 1];
        i += 1;
        break;
      case '--help':
      case '-h':
        args.help = true;
        break;
      default:
        throw new Error(`Unknown argument: ${token}`);
    }
  }
  return args;
}

async function readWixConfig(frontendDir) {
  try {
    const raw = await fs.readFile(path.join(frontendDir, 'wix.config.json'), 'utf8');
    const parsed = JSON.parse(raw);
    if (parsed && typeof parsed.siteId === 'string' && parsed.siteId.trim() !== '') {
      return parsed;
    }
    return null;
  } catch (error) {
    if (error && (error.code === 'ENOENT' || error instanceof SyntaxError)) {
      return null;
    }
    throw error;
  }
}

async function readWixEnvValues(wixEnvPath) {
  try {
    return await readEnvFile(wixEnvPath);
  } catch (error) {
    if (error && error.code === 'ENOENT') {
      return {};
    }
    throw error;
  }
}

async function isNonEmptyDir(dir) {
  try {
    const entries = await fs.readdir(dir);
    return entries.length > 0;
  } catch (error) {
    if (error && error.code === 'ENOENT') {
      return false;
    }
    throw error;
  }
}

async function defaultSpawnScaffold(args) {
  return new Promise((resolve, reject) => {
    const child = spawn('npm', [
      '--yes',
      'create',
      '@wix/new@latest',
      '--',
      'headless',
      '--business-name',
      args.businessName,
      '--folder-name',
      args.folderName,
      '--site-template',
      args.siteTemplate,
      '--skip-install',
    ], {
      cwd: path.resolve(args.projectDir),
      stdio: 'inherit',
    });
    child.on('error', reject);
    child.on('exit', (code, signal) => {
      resolve({ code: signal ? 1 : (code == null ? 1 : code) });
    });
  });
}

// Removes WIX_SCAFFOLD_STATUS entirely (not just blanking its value, which config-env.js's
// upsertEnvFile cannot do and which would itself read back as a present-but-unrecognized
// value) — used only when a spawn-launch failure proves nothing could have been created,
// so the next invocation sees a genuinely untouched config/wix.env, not a lingering marker.
async function clearWixScaffoldStatus(wixEnvPath) {
  let raw;
  try {
    raw = await fs.readFile(wixEnvPath, 'utf8');
  } catch (error) {
    if (error && error.code === 'ENOENT') {
      return;
    }
    throw error;
  }
  const hadTrailingNewline = /\r?\n$/.test(raw);
  const lines = raw.split(/\r?\n/);
  if (hadTrailingNewline && lines[lines.length - 1] === '') {
    lines.pop();
  }
  const kept = lines.filter((line) => {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) {
      return true;
    }
    const idx = line.indexOf('=');
    return idx === -1 || line.slice(0, idx).trim() !== 'WIX_SCAFFOLD_STATUS';
  });
  const out = kept.join('\n');
  await fs.writeFile(wixEnvPath, out === '' ? '' : `${out}\n`, 'utf8');
}

// Persists WIX_SITE_ID from a confirmed receipt, re-checking for a conflict immediately
// before the write (config/wix.env can change between the top-of-invocation read and now).
// Uses statEnvKeys' placeholder-aware classification for the conflict check — PR #184
// review correction: comparing the raw value directly treated a template placeholder
// (e.g. WIX_SITE_ID=REPLACE_WITH_REAL_VALUE) as a real, conflicting destination, which
// made this throw instead of persisting on the very first scaffold of a freshly
// templated project, silently discarding the receipt this function exists to confirm.
async function persistSiteId(wixEnvPath, siteId, scaffoldStatus) {
  const currentStatus = (await statEnvKeys(wixEnvPath, ['WIX_SITE_ID'])).keys.WIX_SITE_ID;
  if (currentStatus === 'present') {
    const current = await readWixEnvValues(wixEnvPath);
    if (current.WIX_SITE_ID !== siteId) {
      throw new Error(
        `config/wix.env's WIX_SITE_ID (${current.WIX_SITE_ID}) no longer matches the scaffold's own wix.config.json (${siteId}); refusing to overwrite a different destination.`,
      );
    }
  }
  await upsertEnvFile(wixEnvPath, { WIX_SITE_ID: siteId, WIX_SCAFFOLD_STATUS: scaffoldStatus });
}

// spec 0085: safe to call more than once against the same project directory, including
// after its own prior partial failure. Every branch below either confirms a destination
// receipt before returning success, or fails closed without touching config/wix.env.
async function ensureDestinationReceipt(args, { spawnScaffold = defaultSpawnScaffold } = {}) {
  const projectDir = path.resolve(args.projectDir);
  const frontendDir = path.join(projectDir, args.folderName);
  const wixEnvPath = path.join(projectDir, 'config', 'wix.env');

  const siteIdStatus = (await statEnvKeys(wixEnvPath, ['WIX_SITE_ID'])).keys.WIX_SITE_ID;
  const envValues = await readWixEnvValues(wixEnvPath);
  const wixConfig = await readWixConfig(frontendDir);

  if (siteIdStatus === 'present') {
    // Case 1: config/wix.env already names a destination — checked first, independent of
    // wix.config.json, so an env-only receipt (adopted/existing destination, or a lost
    // frontend folder) can never fall through to spawning a second site.
    if (wixConfig && wixConfig.siteId !== envValues.WIX_SITE_ID) {
      // 1b — conflicting.
      throw new Error(
        `config/wix.env already has WIX_SITE_ID=${envValues.WIX_SITE_ID}, but ${frontendDir}/wix.config.json names a different siteId=${wixConfig.siteId}. Refusing to create or adopt a second destination — resolve the conflict manually.`,
      );
    }
    // 1a — consistent (wix.config.json is absent, has no siteId, or matches).
    const status = envValues.WIX_SCAFFOLD_STATUS;
    if (status === undefined || status === 'complete') {
      return { siteId: envValues.WIX_SITE_ID };
    }
    if (status === 'incomplete') {
      throw new Error(
        `Destination ${envValues.WIX_SITE_ID} already exists, but a prior scaffold attempt did not complete (WIX_SCAFFOLD_STATUS=incomplete). Refusing to spawn again — that would risk a duplicate site. Resolve manually before retrying.`,
      );
    }
    throw new Error(
      `config/wix.env has an unrecognized WIX_SCAFFOLD_STATUS value (${JSON.stringify(status)}); expected "complete", "incomplete", or the key to be absent. Refusing to proceed.`,
    );
  }

  // Case 2: no confirmed real WIX_SITE_ID (missing, blank, or a placeholder — all treated
  // alike here, matching case 1's classification). PR #184 review correction: this branch
  // must also inspect WIX_SCAFFOLD_STATUS, not just wix.config.json's existence — a bare
  // "wix.config.json exists" check cannot tell a genuinely legacy/host-adopted receipt
  // apart from one left behind by a scaffold attempt this script itself started but never
  // finished recording (the wrapper crashed, or was killed, after the CLI created the site
  // but before persistSiteId ran). Silently adopting the latter as "complete" is the same
  // laundering bug as case 1 exists to prevent, just reached from the opposite direction.
  const status = envValues.WIX_SCAFFOLD_STATUS;
  if (status === 'in_progress') {
    if (wixConfig) {
      // A prior invocation marked in_progress before spawning (see 2c below) and never
      // got to record a final outcome. The CLI may well have finished — never infer
      // "complete" from an orphaned receipt like this. Persist it as incomplete (the same
      // durable, fail-closed record a known non-zero exit produces) so the *next*
      // invocation adopts and blocks via case 1's existing, tested handling instead of
      // this ambiguity recurring indefinitely.
      await persistSiteId(wixEnvPath, wixConfig.siteId, 'incomplete');
      throw new Error(
        `A prior scaffold attempt was interrupted before it could record its outcome (WIX_SCAFFOLD_STATUS=in_progress), but a destination was found (WIX_SITE_ID=${wixConfig.siteId}). Persisted as incomplete — resolve manually before retrying.`,
      );
    }
    // PR #184 review correction (round 6): no local receipt either does NOT mean nothing
    // was created remotely — a crash could have happened after a remote site was created
    // but before wix.config.json was written locally (or even before the frontend folder
    // existed at all), which isNonEmptyDir below cannot detect. Fail closed
    // unconditionally rather than falling through to 2b/2c; the one case that clears this
    // marker for a safe automatic retry is a genuine spawn-launch failure (see 2c) — that
    // is handled before this marker is ever left behind, not by re-reading it here.
    throw new Error(
      'A prior scaffold attempt was interrupted before it could record any outcome (WIX_SCAFFOLD_STATUS=in_progress) and no local destination receipt (wix.config.json) exists either. This cannot be safely distinguished from a remote site having been created before a local receipt was written. Refusing to retry automatically — confirm whether a destination already exists, then either record its WIX_SITE_ID manually or clear WIX_SCAFFOLD_STATUS from config/wix.env if nothing was actually created.',
    );
  }
  if (status !== undefined) {
    // WIX_SCAFFOLD_STATUS is set to something else (a known-ambiguous marker from this
    // script, or corrupted state) while no real WIX_SITE_ID exists. Fail closed rather
    // than silently proceeding as though nothing were recorded.
    throw new Error(
      `config/wix.env has WIX_SCAFFOLD_STATUS=${JSON.stringify(status)} but no valid WIX_SITE_ID; this cannot be automatically resolved. Refusing to proceed automatically — resolve manually.`,
    );
  }

  if (wixConfig) {
    // 2a — adopt a receipt with no status marker at all: a genuinely legacy/host-adopted
    // destination, or one scaffolded before this script wrote WIX_SCAFFOLD_STATUS.
    await upsertEnvFile(wixEnvPath, { WIX_SITE_ID: wixConfig.siteId, WIX_SCAFFOLD_STATUS: 'complete' });
    return { siteId: wixConfig.siteId };
  }

  if (await isNonEmptyDir(frontendDir)) {
    // 2b — genuinely ambiguous state this script cannot resolve on its own.
    throw new Error(
      `${frontendDir} already exists and is not empty, but no valid wix.config.json was found there and config/wix.env has no WIX_SITE_ID. Refusing to scaffold into this folder automatically — resolve manually before retrying.`,
    );
  }

  // 2c — nothing exists yet; mark in_progress before spawning so a crash between now and
  // persisting a final outcome always leaves a distinguishable trace instead of silently
  // looking like "nothing was ever attempted."
  await upsertEnvFile(wixEnvPath, { WIX_SCAFFOLD_STATUS: 'in_progress' });
  let code;
  try {
    ({ code } = await spawnScaffold(args));
  } catch (spawnError) {
    // A rejection alone isn't proof nothing was created — spawnScaffold could fail for
    // reasons other than a launch failure after the child already did real work. Check for
    // a receipt regardless of why this rejected: if one exists, leave the in_progress
    // marker in place so the next invocation's self-heal branch above handles it (never
    // clear a marker out from under a receipt that might exist). Only when there is
    // genuinely no receipt is it safe to clear — for the real spawnScaffold, which only
    // rejects via child_process's 'error' event (emitted specifically when the OS-level
    // process itself could never be launched, before any exit code exists), that absence
    // is deterministic: nothing could have been created remotely.
    const orphanedConfig = await readWixConfig(frontendDir);
    if (!orphanedConfig) {
      await clearWixScaffoldStatus(wixEnvPath);
    }
    throw spawnError;
  }
  const postConfig = await readWixConfig(frontendDir);
  if (postConfig) {
    // Persisted even on a non-zero exit: site creation and later template/release work are
    // separate phases of the CLI's run, so discarding the id here is exactly how a retry
    // would spawn a second site.
    await persistSiteId(wixEnvPath, postConfig.siteId, code === 0 ? 'complete' : 'incomplete');
    if (code === 0) {
      return { siteId: postConfig.siteId };
    }
    throw new Error(
      `Scaffold process exited with code ${code}, but a destination was created (WIX_SITE_ID=${postConfig.siteId}); persisted as incomplete. Do not retry automatically — resolve the underlying failure first.`,
    );
  }
  // The child process definitely ran to completion (it returned an exit code), but no
  // valid local receipt was found. This must NOT be left as a retryable in_progress
  // marker: a remote site could still have been created before a local write failed.
  // Convert it to a durable, always-blocked marker instead.
  await upsertEnvFile(wixEnvPath, { WIX_SCAFFOLD_STATUS: 'ambiguous' });
  if (code === 0) {
    throw new Error('Scaffold process exited 0, but no wix.config.json with a siteId was found afterward — cannot confirm whether a destination was created. Marked ambiguous; resolve manually before retrying.');
  }
  throw new Error(`Scaffold process exited with code ${code} and no destination receipt was found — cannot confirm whether a destination was created. Marked ambiguous; resolve manually before retrying.`);
}

async function main() {
  const args = parseArgs(process.argv.slice(2));
  if (args.help) {
    console.log(usage());
    return;
  }
  if (!args.businessName) {
    console.error(usage());
    process.exit(1);
    return;
  }
  const result = await ensureDestinationReceipt(args);
  console.log(JSON.stringify({ ok: true, siteId: result.siteId }));
}

if (require.main === module) {
  main().catch((error) => {
    console.error(error && error.message ? error.message : error);
    process.exit(1);
  });
}

module.exports = { ensureDestinationReceipt, parseArgs, usage };

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Node.js

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
Wix
Publisher
Wix (Official)
Source
wix/skills · wix-replatform · commit d168bc2
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Wix.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download wix-replatform.zip