Skills
Skill 30 of 48
Discovers and documents the source platform schema (entities, fields, relationships) for a migration project.
9 minutes · 1,991 words · 8 sections
Install
npx skills add wix/skills --skill rp-discoverynpx skills add wix/skills/plugin marketplace add wix/skillsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
Discover and document the source-platform schema for the active migration project.
Use this skill to inspect the source system, identify entities, relationships, fields, identifiers, media, rich content, and platform-specific constraints. Examples include Shopify, WordPress, WooCommerce, and custom CMS platforms.
This skill owns the platform-agnostic discovery process and its output contract
(source-profile.md + source-schema.json). Platform-specific details — how to capture a
given source, its auth model, REST quirks — live in a dedicated source adapter skill,
not here. For WordPress / WooCommerce, that adapter is rp-source-wordpress. To support a
new platform, add a sibling adapter (e.g. rp-source-shopify) and leave this skill
unchanged.
Expected inputs may include:
migrations/<project>/orchestration/run.jsonmigrations/<project>/orchestration/decisions.jsonmigrations/<project>/migrations/<project>/config/Before running source capture, verify the project-local config files created by
wix-replatform:
config/wix.env should always exist with WIX_SITE_STRATEGY, WIX_SITE_ID, and
WIX_AUTH_TOKEN keys, even though discovery itself may not use Wix credentials yet.config/source.<platform>.env should exist once the source platform is known. For
WordPress this is config/source.wordpress.env.If a required non-sensitive key is missing or blank, ask the user for that value and fill the config file before continuing. If a required sensitive key is missing or blank, use the secure Secrets Manager flow: check for an existing non-placeholder local env value, then an existing non-placeholder Wix secret under the resolved site, and ask the user to update the dashboard secret only for keys missing from both places. Never ask the user to paste sensitive values into chat. Never print secret values back to the user; report only present/missing.
Use skills/wix-replatform/scripts/source-secrets.js resolve for sensitive source keys.
Its output is limited to key names and statuses.
Treat migrations/<project>/config/*.env as secret-bearing once they may contain real
values. Do not inspect them with whole-file reads that echo contents into tool output.
Use secret-safe checks only: existence, required key names, and present / blank /
missing status.
If this skill encounters conflicting Wix guidance about how to create a new site +
headless destination, wix-replatform‘s migration contract wins.
resources/rp-destination/, which scaffolds
via npm create @wix/new@latest headless. This is the verified way to get a genuine
headless site; the account-level Projects API is deprecated for this workflow (it
produced non-headless sites).Confirm the active project under migrations/<project>/.
Start from the source URL when available and try to identify the source platform yourself before asking the user. Use lightweight signals such as a REST index, headers, HTML/application markers, or platform-specific route patterns. Only ask the user to name the platform if detection remains inconclusive.
Once the platform is inferred, resolve the acquisition mode before requesting source credentials when the platform has materially different read paths.
Admin API or only
publicly available storefront data.public content only or also include private/authenticated data.also include private/authenticated data branch
should trigger the secure Secrets Manager collection flow for sensitive credentials.
The public content only branch proceeds without credentials and should be described
as limited to public data. For WooCommerce,
this branch should still probe public Store API catalog routes such as
/wc/store/v1/products and /wc/store/v1/products/categories before declaring
commerce out of scope.
Treat file/export ingestion as a separate flow that starts from user-provided files
instead of a site URL probe; do not offer exports as a third option in the URL-based
acquisition-mode question.Then select the matching source adapter skill (e.g. rp-source-wordpress for
WordPress / WooCommerce, rp-source-csv when the run is file-based). If no adapter
exists for the platform, capture entities manually following the same output contract.
sourceMode=files_only, sourcePlatform=csv) use
rp-source-csv regardless of which system produced the files; that adapter identifies
the originating vendor from the header row. There is no acquisition-mode question and
no credentials request for this path.Run the adapter’s capture step to produce a raw, machine-captured dump under
<migrations-root>/<project>/data/<source>-discovery/. For WordPress, the capture
script lives in rp-source-wordpress/scripts/ — run it from that skill directory
(see rp-source-wordpress Capture section and CONVENTIONS.md). When using
project-local secret-bearing config, prefer the script’s deterministic --env-file
path over shell sourcing. The adapter owns the capture mechanics, auth model, and
platform quirks; this skill consumes its output.
For long runs, pass --progress-log <path> and poll it per
CONVENTIONS.md#progress-log-polling.
recordCount > 0). Entities advertised but empty should be flagged, not
mapped as if they hold data.data/wp-discovery/skipped-routes.json
when present. Treat it as the canonical route-scope audit trail: skipped routes are
evidence, not source entities, unless they were explicitly force-included by an
audited override.data/wp-discovery/plugin-coverage.json and data/wp-discovery/plugin-inventory.json.
These are the plugin-tier evidence: which plugins were detected, which are installed but
unrecognized, which entities were derived generically, and what each capability’s
coverage status is. Do not re-derive plugin knowledge by reasoning about route names.rp-source-csv/scripts/csv-discovery.js
and takes the whole file set in one run (--file is repeatable) so roles and split
files resolve together. Read data/csv-discovery/fileset.json — it is the canonical
machine capture, and source-schema.json is synthesized from it:
sourceFiles[] (with role, vendor, partOf), vendor, dialect, drift,
mappingHints, and csvInputRoot into sourceMeta, keeping file paths relative
to csvInputRoot so the project stays movable;origin (file-rows | row-group | column-values) with the
parameters that origin needs, and set hierarchical: true on nested derived entities
so the mapper’s faithfulness-ledger rule fires;drift.unmappedColumns as unknowns so the mapper handles them explicitly;halt: true. An ambiguous layout, an unknown file role, conflicting
split-file headers, or a near-miss vendor detection is a question for the user, not
something to resolve by picking the highest-scoring candidate. The warning text names
the decision to put to them.Capture field-level schema details, including type, cardinality, requiredness, and example values.
When bundled Wix domain knowledge recognizes a source route or source entity, annotate
the discovered entity with sourceMeta.candidateTargetRefs[] such as
["stores/product"]. Discovery must still record source facts only; these refs are
mapper hints, not target decisions.
Note operational constraints such as pagination, rate limits, auth model, and incremental sync options.
If the source base URL or discovered media/file URLs use localhost, 127.0.0.1, or
another private-only host, record a media reachability note in source-profile.md.
Localhost is fine for discovery and local source reads, but Wix Media import is
URL-based and Wix servers cannot fetch the user’s localhost. This is an optional
preparation step and, as far as we know today, only affects media import. State the two
acceptable choices:
Include concise ngrok setup instructions when relevant:
brew install ngrok
ngrok config add-authtoken "<YOUR_AUTHTOKEN>"
ngrok http 8090
export WP_BASE_URL=https://<id>.ngrok-free.appSynthesize the raw capture into the normalized artifacts below.
migrations/<project>/discovery/run.json
migrations/<project>/discovery/entities/
migrations/<project>/discovery/warnings.json
migrations/<project>/discovery/llm-handoff.json
migrations/<project>/discovery/plugin-coverage.json
migrations/<project>/discovery/review/plugin-coverage.md
migrations/<project>/orchestration/checkpoints.json
migrations/<project>/data/<source>-discovery/: raw machine-captured output from the source adapter. Treated as evidence, not a hand-off artifact — downstream skills reference it for traceability but do not read it wholesale.
migrations/<project>/source-profile.md: source platform, access method, limits, auth, and operational notes. Synthesized from the raw capture. Capture the operational facts the adapter documents (auth model, pagination, rate limits) so rp-import-codegen has them without re-deriving.
migrations/<project>/source-schema.json: machine-readable schema for entities and fields. Synthesized from the raw capture — this and source-profile.md are the canonical hand-off to rp-mapper. Include traceability pointers so the mapper can drill into a specific entity’s raw file when needed:
rawDiscovery: relative path to the raw capture dir, e.g. data/wp-discovery/.rawFile: file name within that dir, e.g. wp-v2--posts.md.recordCount and inUse so consumers can distinguish supported vs. actually-used entities.relations derived from the source-declared relationships in the raw capture, so relationships are evidence-backed rather than guessed. Each relation should carry an evidence pointer back to the source signal it came from.backend_data and
accepted backend_metadata route artifacts. Do not synthesize entities from routes
listed in skipped-routes.json unless the skipped-route record has
includedByOverride: true; in that case, include originalDiscoveryCategory,
includedByOverride: true, and overrideReason when present in the entity
sourceMeta.source-schema.example.json for the shape (e.g. rp-source-wordpress/source-schema.example.json). It is a template to follow, not a strict schema to validate against — keep the platform-agnostic core stable and push platform quirks into each entity’s open sourceMeta blob.Optional supporting notes under migrations/<project>/research/ if needed.
When the source adapter produces plugin evidence — WordPress / WooCommerce does — promote it into the canonical artifacts rather than leaving it in the raw capture:
migrations/<project>/discovery/plugin-coverage.json (one artifact: capability rows plus
the per-plugin projection), and render a short user-facing
discovery/review/plugin-coverage.md grouped by the four statuses — Migration planned ·
No need to migrate · Pending · Requires development. The statuses are already
customer-readable; phrase the rest in user terms (“your events will come across as a CMS
collection”), never internal jargon.source-schema.json like any other entity, with
sourceMeta.plugin, sourceMeta.capability, sourceMeta.channel,
sourceMeta.recognized (a profile matched) and sourceMeta.candidateTargetRefs[].sourceMeta.origin: "generic-post-type" | "generic-taxonomy"
and, when the source taxonomy is nested, "hierarchical": true so the mapper’s mandatory
hierarchy-lossiness rule fires.sourceMeta.origin: "embedded" plus the parent route, so codegen extracts them from the
parent fetch instead of issuing a second request.source-profile.md: whether the plugin list was available, how many plugins were
detected/unrecognized, and the counts by status. Downstream stages must not have to
parse the raw capture to learn whether plugin coverage was complete.Classifying an unrecognized plugin is a judgement, not a lookup.
For every installed plugin with no profile, you — not the [js] layer — answer the only
question that matters: is there anything here to migrate at all? The no-migration-needed
list (plugins/no-migration-needed.json) is an input to that answer: a slug hit is strong
evidence and not by itself the answer, because the list says nothing about what this
particular installation is holding. Add your own reading of the registered types, taxonomies
and data-shaped routes, and record the reasoning either way. Three exits, and only three:
basis: list (a list entry you confirmed)
or basis: proposed (your own reading) and the rationale filled in — a list hit with no
recorded confirmation is a failure.proposed, decided at the mapping review.reason: cannot-tell. An honest “cannot
tell” is the point of Pending — it is what stops this step from becoming a silent way to
drop data. Never resolve it yourself; the mapping review is the only exit.You may never conclude that Wix cannot do something — Requires development is reachable only from the human-signed register or from the human at the gate.
A recognized (profiled) plugin is not yours to re-decide: its rows come from the profile
and the registers. That includes a No need to migrate row with basis: decision — a
human-signed per-capability entry in no-migration-needed.json (capabilities[]), settled
and carrying its decidedBy / decidedOn. Report it; do not re-open it as Pending.
blocked[] entry across rows (a missing credential, a file only the user
has, a changed surface — Blocked — recoverable, never a status) and ask the user
once, as a single batched request with each item individually skippable. Record each
answer in orchestration/decisions.json under pluginBlocker:<capability>:<kind> with
value provided or declined — the discovery script reads these back so a declined ask
renders as declined, not as unanswered. Never block the run on a skipped capability.Discovers and documents the source platform schema (entities, fields, relationships) for a migration project. Use when capturing source structure before mapping to Wix.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 24 September 2026.SKILL.md, not by matching a directory convention. 8 distinct layouts observed: .claude/skills/*/SKILL.md, skills/*/SKILL.md, skills/wix-headless-fast/*/skill.md, skills/wix-headless/*/skill.md, skills/wix-replatform/resources/*/SKILL.md, wix-headless-replatform/resources/*/SKILL.md, */SKILL.md, wix-replatform/resources/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by Wix, declaring 1 plugin. It is read for editorial metadata only — never as the skill index, which is always the repository tree./wix/skills.md, and each skill at its own .md URL.