Install
$ agentstack add skill-contentstack-contentstack-agent-skills-migration-companion Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ● Dynamic code execution Used
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
contentstack-migration-companion
Guide a user through migrating a project from Contentful to Contentstack — first the content (content types, entries, assets, locales) via the Contentstack CLI migrate plugin, then the website code that reads from the CMS.
This is a sequential workflow where each step produces output that the next step consumes (the create command produces a populated stack and a bundle with credentials, which feeds the code migration). Treat the artifact paths and counts that each command prints as state you must capture and carry forward.
Operating principles
Follow these throughout — they matter more than any single command:
- Work in a unique session workspace. At the very start of Step 1, create a
session-scoped directory by running: ``bash SESSION_ID=$(date +%Y%m%d-%H%M%S) && SESSION_DIR="/tmp/migrate-to-cs/$SESSION_ID" && mkdir -p "$SESSION_DIR" && echo "SESSION_DIR=$SESSION_DIR" ` Record the printed SESSION_DIR value (e.g. /tmp/migrate-to-cs/20260608-143022`) and carry it as a concrete literal through every shell command in this migration — do not regenerate it. This keeps each migration run isolated so concurrent sessions and re-runs never collide. If the user points you to a different workspace, use their path instead.
- Bundled scripts & references live next to this skill — resolve them via
{SKILL_DIR}.
This skill ships helper scripts (a scripts/ folder) and reference docs (a references/ folder) alongside this SKILL.md file. Wherever these instructions write {SKILL_DIR}, substitute the absolute path of the directory this SKILL.md was loaded from — i.e. the skill's own install directory. Do not assume a fixed path. The location differs by AI assistant, by OS, and by whether the skill was installed per-project or per-user — for example it may be /.claude/skills/contentstack-migration-companion, ~/.claude/skills/contentstack-migration-companion, or a Windows path like %USERPROFILE%\.claude\skills\contentstack-migration-companion. Determine the real path once (it is the folder you read this SKILL.md from; if unsure, search the workspace and home directory for */contentstack-migration-companion/SKILL.md), and for shell commands set it as a variable up front (SKILL_DIR="") so bundled scripts can be invoked as "$SKILL_DIR/scripts/". The bundled scripts self-locate their own siblings, so once you invoke them by absolute path they work regardless of your current directory.
- Pin the Node version for the whole session. A machine often has several Node versions
(system, Homebrew, multiple nvm installs) and a non-interactive shell may resolve an old one (e.g. /usr/local/bin/node v14) ahead of the user's nvm default. The Step 1 prereq checker finds the highest installed Node ≥ 20 and reports its directory as node.bin_dir in the JSON. Record that value as a concrete literal NODE_BIN_DIR and prefix every csdx, npm, and contentful command for the rest of the migration with it, e.g. PATH=":$PATH" csdx migrate:create …. This guarantees the CLI runs on the Node the prereq check validated, not whatever an unconfigured shell picks first. If node.bin_dir is absent (older check output), fall back to the plain command.
- One step at a time, and show the result. After each command, surface the meaningful
output to the user — the summary tables, the counts, the artifact path — not a wall of raw logs. The user is watching this like a progress bar; give them a clean status, then the path/handle the next step needs.
- Track migration progress with the checklist. At each
[PROGRESS]trigger below, output
a progress block in your response using these emoji: ✅ = completed, ⏳ = currently running, ⬜ = not yet started. Example for Step 3 in progress: ``` Migration progress
- ✅ Step 1 — Prerequisites & inputs
- ✅ Step 2 — Install migrate plugin
- ⏳ Step 3 — Content Migration
- ⬜ Step 4 — Code Migration
`` Output it at two moments: (1) at the start of each step, and (2) when each step's eval passes. Only one step is ⏳ at a time. Step 4 stays ⏳` through all sub-steps 4.1–4.6. Step 5 (Welcome) is not tracked — it triggers automatically once Step 4 is ✅.
- Gate the destructive or expensive steps. Confirm before logging in, before creating a
new stack, and before editing the user's code. These either touch live accounts or modify their repo, so a quick "ready to proceed?" prevents nasty surprises.
- Capture the outputs explicitly. When a command prints a bundle path, a log directory,
or a stack API key, record the exact path/value and reuse it verbatim. Do not guess paths — read them back from the command output.
- Browser-based login is normal here.
csdx auth:login --oauthopens the user's browser;
the terminal then blocks and auto-detects when they finish. Run it, tell the user to complete login in the browser, and simply wait for the command to return — do not try to script the browser or kill the command.
- Currently Contentful is the only supported source. Do not ask the user which legacy
platform they're on; assume Contentful. (The CLI flag is --source contentful.)
- If a step fails, stop and diagnose rather than barrelling ahead. Most failures here are
recoverable (expired token → re-login, missing content model → inform the user), and the relevant recovery is described in the step that can fail.
- Never display code in your text output. Do not show shell commands, code snippets,
scripts, or any fenced code blocks (``` blocks) in your chat messages at any point during the migration. Just run commands silently and report the result in plain prose. The user sees tool calls in the tool panel — repeating code in chat is noise.
The migration at a glance
| # | Step | Command (core) | Produces | |---|------|----------------|----------| | 1 | Prerequisites & inputs | prereq check script | verified env + gathered inputs | | 2 | Install migrate plugin | csdx plugins:link . (or plugins:add) | csdx migrate:* available | | 3 | Content Migration | csdx migrate:create | populated stack + bundle + credentials | | 4 | Code Migration | detect → plan → rewrite → eval (13 checks) | rewritten data layer | | 5 | Welcome to Contentstack 🎉 | — | celebration + next steps |
Work through them in order. The sections below give the exact commands, what to show the user, and what to carry forward.
> Self-contained skill. Everything Step 4 needs — the full code-migration procedure, the > Contentful → Contentstack SDK reference (references/), and the eval scripts (scripts/) — > ships inside this one skill. There is no separate code-migration skill to install; resolve the > bundled files via {SKILL_DIR} as described above.
Step 1 — Prerequisites & inputs
> [PROGRESS] Output the migration progress block: > Step 1 → "in_progress", Steps 2–4 → "pending".
1.0 — Create session workspace
Before doing anything else, create the unique session directory for this migration run:
SESSION_ID=$(date +%Y%m%d-%H%M%S) && SESSION_DIR="/tmp/migrate-to-cs/$SESSION_ID" && mkdir -p "$SESSION_DIR" && echo "SESSION_DIR=$SESSION_DIR"
Record the printed SESSION_DIR path exactly (e.g. /tmp/migrate-to-cs/20260608-143022). Substitute this concrete value wherever these instructions reference $SESSION_DIR. Do not regenerate it — every step in this migration must use the same directory so artifacts chain correctly.
Tell the user: "Session workspace created at ``."
1.1 — Detect the Python 3 command
Run this to find the correct Python 3 command for this environment:
if python3 --version 2>&1 | grep -q "Python 3"; then
PYTHON_CMD=python3
elif python --version 2>&1 | grep -q "Python 3"; then
PYTHON_CMD=python
else
PYTHON_CMD=""
fi
echo "PYTHON_CMD=$PYTHON_CMD"
Record PYTHON_CMD exactly as printed. Substitute $PYTHON_CMD wherever these instructions show a Python invocation — do not hardcode python3 or python.
If PYTHON_CMD is empty, stop immediately and tell the user:
> "Python 3 is required but not found. Install it from python.org or via your package manager > (e.g. brew install python3 on macOS, sudo apt install python3 on Ubuntu, > or download the installer from python.org on Windows), then try again."
Do not proceed past this point until Python 3 is detected.
1.2 — Run the prerequisite checker
Run this single script. It silently evaluates Node.js, installs any missing CLIs (csdx, contentful), checks the Contentstack region and login, and checks the Contentful login and spaces — all in one pass. It outputs a JSON summary:
$PYTHON_CMD "{SKILL_DIR}/scripts/check_prereqs.py"
Parse the JSON result and carry every field forward as session state.
Record the Node bin directory. Capture node.bin_dir from the JSON as the concrete literal NODE_BIN_DIR. Per the "Pin the Node version" principle in the overview, prefix every later csdx, npm, and contentful command with PATH=":$PATH" so the whole migration runs on the Node the checker validated — not whatever an unconfigured non-interactive shell would resolve first (the checker already picks the highest installed Node ≥ 20, scanning PATH and all nvm installs). If node.bin_dir is missing, fall back to the plain command.
Hard blocker: If the script exits with code 1, Node.js is missing or too old. The reported node.version/node.path reflect the best Node found anywhere on the machine, so the message is accurate even when a newer Node exists but isn't on the default PATH. Stop immediately and tell the user the exact problem:
node.error == "not_installed"→ "Node.js is not installed. Install it vianvm install 22
or from nodejs.org, then try again."
node.ok == false(e.g.node.version == "v18.x") → "The newest Node I can find is
`, but Node 20+ is required. Install a newer one with nvm install 22 && nvm use 22` (or upgrade your system Node), then try again."
Do not continue past this point until Node 20+ is confirmed.
1.3 — Handle missing Contentstack login (if needed)
Skip this sub-step if cs_login.ok is true in the JSON.
If cs_login.ok is false (needslogin) or cs_login.org_uid is null (needsoauth_reauth), trigger a fresh OAuth login:
csdx auth:login --oauth
Tell the user: "A browser window is opening — complete the Contentstack login there, then come back here." Wait for the command to return (it blocks until the browser flow finishes), then re-run the prereq checker (same command as 1.2) to capture the updated email and org UID.
If the org UID is still missing after the retry, tell the user:
> "OAuth login did not store an org UID. Please re-run csdx auth:login --oauth manually, then > let me know when done so I can retry."
1.4 — Handle missing Contentful login (if needed)
Skip this sub-step if contentful_login.ok is true in the JSON.
contentful login is interactive (it needs the user to press Y and paste a token) — you cannot run it as a Bash command. Instruct the user to run it themselves:
> "Please run this command in your terminal: > > `` > contentful login > `` > > It will ask 'Continue login on the browser? (Y/n)' — press Y. > A browser window will open — sign in there. > When the browser login completes, the terminal will show 'Paste your token here:' — > copy your Management Token from the browser page and paste it, then press Enter. > Come back here once the login confirms success."
Wait for the user to confirm they have completed the login, then re-run the prereq checker to pick up the new session.
> The Management Token is a secret: do not ask the user to share it with you, do not echo it > back in your summaries, and do not write it into any file in this workspace.
1.5 — Show the prerequisites summary and confirm
Once cs_login.ok and contentful_login.ok are both true, display a summary table from the JSON result. Use ✅ for items that look good and ⚠️ for anything that may need attention:
| Check | Status | Detail | | ----------------------- | ----------------------------------------------------- | ----------------------------- | | Python 3 | ✅ ` | | | Node.js | ✅ | | | Contentstack CLI (csdx) | ✅ | | | Contentstack region | ⚙️ | | | Contentstack login | ✅ | Org UID: | | Contentful CLI | ✅ | | | Contentful login | ✅ ` | |
Then ask this single question:
> "Everything looks good — ready to proceed? Or would you like to change anything before > we start? > > - proceed — start the migration > - region — switch the Contentstack region > - contentstack login — switch the Contentstack account > - contentful login — switch the Contentful account"
Wait for the user's answer before continuing.
| Answer | Action | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | | "proceed" / "yes" / any confirmation | Skip to 1.6 | | "region" | Present the region menu (see below), wait for selection, run csdx config:set:region , re-run the prereq checker, re-display the summary | | "contentstack login" | Run csdx auth:login --oauth, wait for browser login, re-run the prereq checker, re-display the summary | | "contentful login" | Instruct the user to run contentful login themselves (same as 1.4), wait for confirmation, re-run the prereq checker, re-display the summary |
Region picker — when the user asks to change the region, show this menu and wait for their choice before running the command:
> "Which region is your destination stack in? > > 1. AWS-NA — AWS North America > 2. AWS-EU — AWS Europe > 3. AWS-AU — AWS Australia > 4. AZURE-NA — Azure North America > 5. AZURE-EU — Azure Europe > 6. GCP-NA — Google Cloud North America > 7. GCP-EU — Google Cloud Europe"
Map the number to its region code and run:
csdx config:set:region # e.g. csdx config:set:region AWS-EU
Repeat the summary + question until the user confirms they are ready to proceed.
1.6 — Contentful Space ID (select from list)
The contentful_spaces array in the prereq JSON already holds all accessible spaces (populated from the contentful space list call run inside the checker).
If there is exactly one space in the list, select it automatically — do not ask the user. Announce the selection:
> "Found one Contentful space: My Marketing Site (abc123). Using it automatically."
Capture its ID as SPACE_ID and continue.
If there are two or more spaces, present them as a numbered menu — do not ask the user to type or paste a Space ID:
1. My Marketing Site (abc123)
2. Developer Sandbox (def456)
…
Ask:
> "Which space do you want to migrate? Enter the number."
Wait for the answer. Map the num
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: contentstack
- Source: contentstack/contentstack-agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.