# Contentstack Migration Companion

> Migration companion for moving to Contentstack from another CMS. Guides content and application migration through a structured, step-by-step workflow. Currently supports migrations from Contentful, with additional source platforms planned. Use when users want to migrate, move, switch, port, or re-platform to Contentstack, including content models, content, assets, locales, application integration…

- **Type:** Skill
- **Install:** `agentstack add skill-contentstack-contentstack-agent-skills-migration-companion`
- **Verified:** Pending review
- **Seller:** [contentstack](https://agentstack.voostack.com/s/contentstack)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [contentstack](https://github.com/contentstack)
- **Source:** https://github.com/contentstack/contentstack-agent-skills/tree/main/skills/migration-companion

## Install

```sh
agentstack add skill-contentstack-contentstack-agent-skills-migration-companion
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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 --oauth` opens 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:

```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` 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:

```bash
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:

```bash
$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 via `nvm 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 (needs_login) or `cs_login.org_uid` is null (needs_oauth_reauth),
trigger a fresh OAuth login:

```bash
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:

```bash
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](https://github.com/contentstack)
- **Source:** [contentstack/contentstack-agent-skills](https://github.com/contentstack/contentstack-agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** yes
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** yes

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-contentstack-contentstack-agent-skills-migration-companion
- Seller: https://agentstack.voostack.com/s/contentstack
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
