# Pack And Copy

> Pack and Copy

- Skill: `nrwl/pack-and-copy` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nrwl/pack-and-copy`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nrwl/pack-and-copy/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: nrwl (https://skillmd.com/u/nrwl)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nrwl/pack-and-copy

---


# Pack and Copy

Validate a publisher package change against its consumer repos **before** the publisher's version bump is merged and published. The flow is:

1. Build the publisher package(s) — repo-specific, not automatable.
2. Run `polygraph _pack-and-copy` (or the `pack_and_copy` MCP tool) to pack them and install the tarballs into each consumer, rewriting `package.json` to a `file:` dependency.
3. Commit the consumer changes, including `.polygraph-packages/*.tgz`, to a branch, open a PR, and let consumer CI validate the change.

This skill covers **steps 1 and 2**. PR creation / CI monitoring is left to the `polygraph` and `await-polygraph-ci` skills.

## Available Tools

Pack-and-copy functionality is available via both an MCP tool and a CLI command. Use whichever is available in your current environment.

| MCP Tool | CLI Equivalent | Description |
| --- | --- | --- |
| `pack_and_copy` | `polygraph _pack-and-copy` | Pack publisher packages and install tarballs into consumer repos for pre-release validation. |

Session discovery / inspection tools (`show_session`, `list_repos`, etc.) come from the `polygraph` skill — see that skill's tool table for the full mapping.

## Prerequisites

- An active Polygraph session that includes the publisher repo and one or more consumer repos. If you don't have a session yet, run the `polygraph` skill first to create one.
- The publisher repo's built artifacts are **packable** — i.e. running `npm pack` in the package directory produces a tarball that, when installed, Just Works. If the publisher needs to be built first, you'll need to do that explicitly.

## Phase 1: Identify Publishers and Consumers

Determine which packages are being changed in the publisher, and which consumer repos need to validate the change.

**If the user specified them**, skip to Phase 2.

**Otherwise**, inspect the session and the publisher's change:

1. Call `show_session(sessionId)` to enumerate the repos in the session and their local paths.
2. The **publisher** is usually the current repo (where the change is being made). Look at its `package.json` files to find the packages being shipped — the one being changed, or all packages in a monorepo package tree.
3. The **consumers** are the other repos in the session. Only repos that actually depend on one of the publisher's packages are relevant — the command will auto-skip the rest, but listing them up front keeps the user informed.

Before proceeding, print a short table:

| Publisher package | Publisher path          | Consumer repo | Consumer path     |
| ----------------- | ----------------------- | ------------- | ----------------- |
| @org/tokens       | /path/to/ds/packages/tokens | web-app       | /path/to/web-app |
| @org/button       | /path/to/ds/packages/button | web-app       | /path/to/web-app |

and confirm with the user using `AskUserQuestion` if anything is ambiguous.

## Phase 2: Build the Publisher Packages

**This step is not automatable.** Build commands vary per repo and per package. Ask the user how to build, or inspect the repo for conventions.

Common hints to surface to the user:

- A root-level `package.json` with a `build` script that builds all packages (e.g. `npm run build`, `nx run-many -t build`, `pnpm -r build`).
- Per-package `build` scripts (check each publisher's `package.json`).
- A `prepack` script — if one exists, `npm pack` will run it automatically and you don't need a separate build step.

Run the build. Verify the `dist/` or equivalent output exists in each publisher package directory before proceeding.

**If the build fails**, surface the error to the user and stop. Do not attempt to pack a broken package.

## Phase 3: Pack and Copy

Run `polygraph _pack-and-copy` (or the `pack_and_copy` MCP tool), passing a `--pair` for every (publisher, consumer) combination the user wants to test. The command is deterministic: it computes a unique pre-release version, runs `npm pack` in each publisher, copies the tarballs into each consumer's `.polygraph-packages/` directory, rewrites the consumer's `package.json` deps to point at the tarballs via `file:`, and POSTs a summary of published and consumed packages to the Polygraph session so the UI reflects what was packed where.

CLI form:

```bash
polygraph _pack-and-copy \
  --session <session-id> \
  --pair <publisher-path>=<consumer-path> \
  [--pair <publisher-path>=<consumer-path> ...] \
  --json
```

MCP tool form — call `pack_and_copy` with:

- `sessionId` (string, required): the Polygraph session ID
- `pairs` (array, required): one `{ publisherPath, consumerPath }` object per (publisher, consumer) combination
- `runScripts` (boolean, optional): enable npm lifecycle scripts during `npm pack` (off by default)

**Notes:**

- `<publisher-path>` / `publisherPath` is the directory containing the publisher package's `package.json` (not necessarily the repo root — for monorepos, this is `packages/<name>/`).
- `<consumer-path>` / `consumerPath` is the consumer repo's root (where its `package.json` lives).
- If a consumer doesn't declare a dependency on a publisher's package, that pair is silently skipped for that consumer — the tarball is still produced but not installed there.
- The command creates a new unique version on each run, but package managers can still keep stale `file:` dependency contents in `node_modules`. Use a forced install on reruns if the consumer still sees old package contents.
- Consumers' `.polygraph-packages/*.tgz` files **must be tracked and committed** with the consumer branch. Fresh CI clones need those tarballs to install the `file:` dependencies.

Parse the JSON output to get the `published` and `consumed` summaries. Print them back to the user:

```
Packed:
- @org/tokens  1.4.2 -> 1.4.3-pg.<session>.<timestamp>
- @org/button  2.1.0 -> 2.1.1-pg.<session>.<timestamp>

Installed into:
- web-app: @org/tokens, @org/button
- docs:    @org/tokens
```

## Phase 4: Install in Consumers and Commit

For each consumer that received a tarball:

1. Run the consumer's package manager install command, e.g. `npm install`, `pnpm install`, or `yarn install`, so the lockfile and `node_modules/` reflect the new `file:` dep. On reruns in the same worktree, use `npm install --force`, `pnpm install --force`, or `yarn install --force` if the consumer still sees old package contents.
2. Commit the `package.json`, lockfile, and `.polygraph-packages/*.tgz` changes on a dedicated branch.
{% if platform == "claude" %}
3. Push the branch and open a draft PR using the `polygraph` skill's `push_branch` + `create_pr` flow — **not** directly. The PR description should explain that this is validating an unmerged publisher change.
{% else %}
3. Push the branch and open a draft PR with a description that explains this is validating an unmerged publisher change.
{% endif %}
4. Once CI results come in (see the `await-polygraph-ci` skill), report back. Do **not** merge any consumer PR opened via this flow — these PRs are for validation only and should be closed once the publisher's real version lands.

## Common Pitfalls

- **Forgetting to build**: `npm pack` packs whatever the package's `files` field points at. If `dist/` is stale or missing, the tarball will be broken. Always rebuild before packing unless a `prepack` script does it.
- **Stale `file:` installs**: package managers may keep old extracted contents for local tarball dependencies after reruns. Use `install --force` if a consumer still sees old package contents.
- **Peer dependency mismatches**: if the publisher bumps a peer dep, consumers that don't satisfy it may fail to install. Surface this to the user.
- **Lockfile churn**: installing after a `file:` swap will change the lockfile. That's expected and should be committed alongside the `package.json` and tarball changes.
- **Multiple publishers in one repo**: pass one `--pair` per publisher package, using the same consumer path. They'll all be bundled into the same `.polygraph-packages/` dir.

## Related Skills

- `polygraph` — session setup, branch push, PR creation.
- `await-polygraph-ci` — monitor consumer CI after the PRs are opened.

