---
name: multi-agent-sync
language: en
description: "One-shot sync of the entire multi-agent ecosystem: Claude Code, Copilot CLI, pipeline repo, website, and the multi-agent-toolkit MCP server. Use when work is finished and should be propagated across Claude Code, Copilot CLI, the repos, the website and the multi-agent-toolkit server."
user-invocable: true
argument-hint: 'release | multi-agent-toolkit | "change description"'
---

# Multi-Agent Sync

**Single command. Full ecosystem sync. No argument required.**

When invoked, it synchronizes all targets in order. It detects what changed, updates only the stale ones, and reports the result.

**Input**: $ARGUMENTS (optional  -  `release` or a change description to apply to all targets)

## Targets

| # | Target | Path | Direction |
|---|-------|-----|-----|
| 1 | Claude Code (source of truth) | `~/.claude/commands/multi-agent/` + `~/.claude/multi-agent-refs/` + `~/.claude/agents/` + `~/.claude/scripts/` + `~/.claude/lib/` | source |
| 2 | Copilot CLI | `~/.copilot/copilot-instructions.md` + `~/.copilot/skills/` | <- from Claude |
| 2b | Codex CLI | `~/.codex/AGENTS.md` + `~/.codex/skills/multi-agent/` + `~/.codex/multi-agent-refs/` + `~/.codex/agents/*.toml` | <- from Claude (path-rewritten) |
| 3 | multi-agent-pipeline repo | `~/multi-agent-pipeline/pipeline/` | <- from Claude (genericized) |
| 4 | Website | `{owner}/{website-host}` | <- version + features |
| 5 | multi-agent-toolkit MCP server | resolved from `prefs.global.devToolkit` or the `mcpServers` registration | own repo: gate, commit, publish |

## Default Behavior (no argument)

Run all steps automatically:

```
Step 1: DETECT      Compare timestamps, find stale targets
Step 2: COPILOT     Claude Code -> Copilot CLI (instructions + 53 sub-command skills)
Step 2b: CODEX      Claude Code -> Codex CLI (1 router skill + 51 specs as refs + 8 agent TOML)
Step 3: REPO        Claude Code -> pipeline repo (genericized, personal data scrub)
Step 3d: DEV-TOOLKIT Companion MCP server -> detect movement, ship gates, commit + publish
Step 4: WEBSITE     Version + phase/model counts -> {website-host} (i18n + projects.ts)
Step 5: Commit      Commit + push all changed repos
Step 6: Report      Summary: synced targets, changed files, deploy status, multi-agent-toolkit version
```

If nothing is stale -> report "All targets up to date" and stop.

## Special inputs

| Input | Behavior |
|-------|----------|
| (no argument) | Full ecosystem sync (default) |
| `release` | Full sync + version bump + tag + npm publish + website deploy |
| `multi-agent-toolkit` | Run Step 3d only: gate, commit and publish the companion MCP server |
| `"change description"` | Apply the description to ALL targets at once |


## Sync rules

1. **Read first**  -  Understand the current state of all targets before making changes
2. **Preserve file structure**  -  Each target has its own format:
   - `commands/multi-agent/` SKILL tree + `multi-agent-refs/phases/`: detailed pipeline spec (frontmatter, phases, routing)
   - `copilot-instructions.md`: general development instructions + pipeline summary section
   - `multi-agent-pipeline/pipeline/`: generic open-source version (NO personal data)
3. **Sync shared sections** (Claude <-> Copilot):
   - Pipeline entries table (base / :local / :autopilot / :local-autopilot) + the Full-or-Short depth question
   - Project detection (URL-based + cwd-based)
   - Figma pipeline flow
   - Git conventions (author, branch, commit format)
   - Short-run model info (Opus)
   - Keychain management (registry, naming convention, multi-agent pattern)
4. **Do not duplicate**  -  Summary in Copilot, full spec in Claude. Preserve this distinction.
5. **Report**  -  Show a short diff summary after the sync

## Pipeline Repo Sync Rules (CRITICAL)

1. **Source**: `~/.claude/commands/multi-agent/` + `~/.claude/multi-agent-refs/` + `~/.claude/agents/` + `~/.claude/lib/`
2. **Target**: `~/multi-agent-pipeline/pipeline/`
3. **Genericization** (must be applied BEFORE writing to the target):
   - Jira project key (`prefs.global.defaultJiraKey`) -> `{JIRA_KEY}`, `PROJ` in examples
   - Personal names/emails -> generic placeholder
   - Branch names -> `develop`
   - Project names -> `my-app`
   - `{JIRA_HOST}`, `{BITBUCKET_HOST}`, `{CONFLUENCE_HOST}`, `{CORP_DOMAIN}` stay as-is
   - **Verify**: scan for personal/corporate data inside pipeline/ with `grep` -> 0 results
4. **File mapping**:
   ```
   ~/.claude/commands/multi-agent/        -> pipeline/commands/multi-agent/
   ~/.claude/multi-agent-refs/            -> pipeline/multi-agent-refs/   (refs + pickers, non-command)
   ~/.claude/commands/sim-test.md         -> pipeline/commands/sim-test.md
   ~/.claude/agents/*.md                  -> pipeline/agents/
   ```
5. **Files NOT synced** (local-only, may contain personal data):
   - `~/.claude/multi-agent-preferences.json`
   - `~/.claude/CLAUDE.md`, `~/.claude/rules/`, `~/.claude/knowledge/`
   - `~/.claude/scripts/`  -  EXCEPT `pre-commit-check.sh` and `build-stack-plugins.mjs` (generic, synced)
   - Step 3c (PLUGINS): rebuild the `{owner}/multi-agent-plugins` marketplace from `shared/external` via `build-stack-plugins.mjs` (bumps changed plugins' patch version), then commit + push the plugins repo. On any change also verify help + README freshness: every plugin registers `./skills/tools/help` in plugin.json, `tools/bump.py --check` shows no DRIFT, `tools/validate.py` clean (CHANGELOG entry per bumped version), and pipeline help/READMEs reflect any command-surface change from Step 3
   - `~/.claude/settings.json`


## Codex Sync (Step 2b)

This step does **not** hand-copy files. The Codex tree is a *transform* of the Claude
tree, not a mirror: the 53 sub-command specs become reference files (Codex silently
truncates its skills block  -  see `cross-cli-contract.md` 2.6), every reference to a
CLI-owned tree is retargeted (`agents/<persona>.md` becomes `.toml`, the dispatcher
becomes the router skill), the 8 personas are regenerated as TOML with a model +
reasoning-effort map, and shared state (`logs/`, prefs, `knowledge/`) is deliberately
left under `~/.claude`.

That transform lives in `install/codex.mjs` and is gate-locked by
`smoke-codex-install.sh`. Describing it again in prose would give the pipeline two
definitions of the same thing, and the prose one would rot. So the step runs the
installer:

```bash
cd "$HOME/multi-agent-pipeline" && node install.js --codex
```

Verify:

```bash
ls -1 "$HOME/.codex/skills" | grep -c '^multi-agent$'                  # want 1
find "$HOME/.codex/multi-agent-refs/commands" -name SKILL.md | wc -l  # want the command count
grep -rhoE '(\$HOME|~)/\.claude/(agents|scripts|lib|schemas|commands|multi-agent-refs|rules)' \
  "$HOME/.codex/skills" "$HOME/.codex/multi-agent-refs" | sort -u     # want empty
```

MCP is registered by the installer via `codex mcp add multi-agent-toolkit` (idempotent,
skipped with a warning when `codex` is absent). Never hand-edit
`~/.codex/config.toml`  -  Codex owns it. Run this AFTER the REPO step, since the
installer reads the repo tree.

---

## Dev-Toolkit Sync (Step 3d)

The companion MCP server (`multi-agent-toolkit-mcp`) is its own repo with its own registry. Pipeline skills call its tools and several declare a minimum version, so when it moves it has to ship.

**Resolution**: identical to `multi-agent-refactor` Step 0c  -  `prefs.global.devToolkit` first, then the `mcpServers` registration, then skip.

**Detect movement**: dirty working tree, unpushed commits, or no `v<version>` tag for the version in `package.json`. Nothing moved -> report "up to date" and continue.

**Ship gates** (a failure aborts this step only, with file + line; the rest of the sync continues).
When the toolkit ships its own gate script (`npm run gates` / `scripts/gates.sh`), run that instead of the list below - the repo owns the definition, this skill owns the requirement. The list is the fallback, and the coverage the script must have:

1. `node --check index.js` plus every `tools/**/*.js`.
2. stdio handshake (`initialize` -> `notifications/initialized` -> `tools/list`) must answer with a non-zero tool count.
3. That count must match every advertised count (`package.json` description, README header and per-family rows). Fix the docs, never the gate.
4. `npm pack --dry-run` must list every `tools/*/` directory the server loads  -  a missing `files[]` entry publishes a broken package.
5. `grep -rn "console\.log(" index.js tools/` must be empty: stdout carries the JSON-RPC frames, diagnostics go to `console.error`.
6. Personal-data scan: no absolute `/Users/<name>` paths, no tokens, no corporate hostnames.
7. Version contract: every pipeline-side minimum version must be satisfied by what is about to ship; a new tool a pipeline skill now needs -> bump that minimum in the same sync.

**Version bump**: patch for fixes and docs, minor for a new tool, major for a removed or renamed tool.

**Ship**: commit with that repo's own convention, tag `v<version>`, push with `--tags`, then publish to the registry from `publishConfig` using a throwaway userconfig  -  never edit `~/.npmrc`, never a bare `npm publish`. The token depends on the registry AND on the package scope: the registry picks the credential type, the scope picks the account. `npm.pkg.github.com` needs a **Classic** GitHub PAT with `write:packages`; `registry.npmjs.org` needs the `npm` key. Resolving on host alone misroutes on any machine with a work and a personal GitHub identity  -  prefer a scope-specific mapping (`github_<scope>`) and fall back to the generic `github` key only when there is one identity.

```bash
NPMRC=$(mktemp); trap 'rm -f "$NPMRC"' EXIT
REG=$(node -p "require('./package.json').publishConfig?.registry || 'https://registry.npmjs.org'")
HOST=${REG#https://}; HOST=${HOST%/}
SCOPE=$(node -p "(require('./package.json').name.match(/^@([^/]+)/)||[])[1] || ''")
case "$HOST" in
  npm.pkg.github.com*) KEY=github; [ -n "$SCOPE" ] && KEY="github_$SCOPE" ;;
  *) KEY=npm ;;
esac
# Fall back to the generic key when no scope-specific mapping exists.
bash "$HOME/.copilot/lib/credential-store.sh" get "$KEY" >/dev/null 2>&1 || KEY=github
TOKEN=$(bash "$HOME/.claude/lib/credential-store.sh" get "$KEY")
[ -n "$TOKEN" ] || echo "ABORT: no '$KEY' token - onboard it via /multi-agent:setup before publishing"
printf '%s\n' "registry=$REG" "//$HOST/:_authToken=$TOKEN" > "$NPMRC"
npm publish --userconfig "$NPMRC"
```

**Approval**: outside autopilot and outside `release`, ask first: commit + push / commit + push + publish / skip. Never ship unapproved band-E work from `multi-agent-refactor` silently.


## Website Sync (Step 4)

Propagate version, phase and model counts and feature descriptions to the website.

```bash
gh auth switch --user {owner}
WEBSITE_DIR="$HOME/{website-host}"
[ ! -d "$WEBSITE_DIR" ] && gh repo clone {owner}/website "$WEBSITE_DIR"
cd "$WEBSITE_DIR" && git pull origin main
```

| File | To sync |
|-------|--------------|
| `src/lib/i18n.tsx` | Phase count, model count, feature descriptions (EN + TR) |
| `src/data/projects.ts` | Version number, tagline, description, feature list |

```bash
# A commit the platform does not recognise is pushed fine and never built, so the site
# keeps the old version. {identity} is the one routed to {owner}, not the run's own.
# Why, signature, recovery: `$HOME/.claude/multi-agent-refs/website-deploy.md`.
bash "$HOME/.claude/scripts/website-deploy-commit.sh" "{identity.name}" "{identity.email}" "{VERSION}" "$WEBSITE_DIR"
```


## Release Flow

When invoked with the `release` argument:

```
1. REPO          Claude Code -> pipeline repo (genericized)
2. VERIFY        Personal data scan -> 0 results
3. LINT + TEST   ESLint + smoke tests
4. VERSION       package.json version bump (patch/minor/major)
5. Commit + TAG  git commit + git tag v{VERSION}
6. PUSH          git push --tags -> release.yml auto-publish
7. DEV-TOOLKIT   Ship the companion MCP server if it moved (Step 3d gates, then publish)
8. WEBSITE       Version + features -> {website-host} (maintainer identity, build verified Ready)
9. COPILOT       Copilot CLI instructions + skills sync
9b. CODEX        Codex CLI router skill + refs + agent TOML (node install.js --codex)
10. Report       Summary: version, touched repos, deploy status
```


## Sub-Command Sync (Claude Code <-> Copilot CLI Skills)

> Codex takes the Step 2b path instead; see that section.

| Claude Code | Copilot CLI |
|-------------|-------------|
| `~/.claude/commands/multi-agent/{cmd}.md` | `~/.copilot/skills/multi-agent-{cmd}/SKILL.md` |

**53 commands are synced** (canonical inventory  -  must match `cross-cli-contract.md` section 1; drift = contract violation):

```
analysis, analysis-resolve, autopilot, build-optimize, channels,
complaint-analysis, create-jira, design-check, dev, dev-autopilot, dev-local,
dev-local-autopilot, diff-explain, feedback, forget, garbage-collect, help,
ios-coding-standard, issue, jira, kill, language, local, local-autopilot,
log, manual-test, prune-logs, prune-prompts, purge, refactor, resume,
resume-local, review, review-analysis, review-issue, review-jira, routines,
save, scan, search, setup, stack, status, store-ready, sync, test,
test-accessibility, test-dark-mode, test-dynamic-type, test-screenshots,
testflight-validation, uninstall, update
```

**NOT synced**: `refs/*`  -  Lazy-load references, Claude Code specific

**Claude -> Copilot**: Add SKILL.md frontmatter (`name`, `description`, `user-invocable: true`, `argument-hint`)
**Copilot -> Claude**: Simplify the frontmatter (`description` + `allowed-tools`), add `$ARGUMENTS`


## Keychain Token Access

| Operation | Token Source |
|-------|---------------|
| `gh` CLI (personal) | `{owner}` gh auth (Keychain) |
| `gh` CLI (work) | `${USER}_{work-gh-alias}` gh auth (Keychain) |
| npm publish | `NODE_AUTH_TOKEN`  -  `GITHUB_TOKEN` in CI, Keychain PAT locally |
| multi-agent-toolkit publish (Step 3d) | scope-resolved key (`github_<scope>`, else `github`, else `npm`) -> throwaway `--userconfig`, registry from that repo's `publishConfig` |

```bash
gh auth switch --user {owner}  # for personal repos
```


## Pre-flight the token scope

GitHub reports a token's scopes on any authenticated request, so check before
uploading instead of reading it out of a 403:

```bash
curl -sI -H "Authorization: token $TOKEN" https://api.github.com/user \
  | grep -i '^x-oauth-scopes:' | grep -q 'write:packages'
```

Candidate order for `npm.pkg.github.com`, because storage location and scope are
not correlated: `github_<scope>` from the mapping, then `gh auth token -u <scope>`
(gh's own OAuth token often carries `write:packages` when a hand-made PAT does
not), then the generic `github` key only on a single-identity machine. Take the
first candidate whose scopes include `write:packages` AND whose login matches the
package scope. If none qualifies, stop before publishing and report each candidate
with the login it resolved to and the scope it was missing  -  that is the
actionable output, not a 403 body.

## Publish 403s: two causes, two fixes

Neither message says "wrong token" plainly, and they need opposite responses:

- `Unauthorized: As an Enterprise Managed User, you cannot access this content`  -
  the resolved token belongs to a corporate EMU account, which cannot publish to a
  personal scope at all. No scope grant fixes this; map the personal account's PAT
  under `github_<scope>`.
- `The token provided does not match expected scopes`  -  right account, missing
  permission. Regenerate as a **Classic** PAT with `write:packages`
  (plus `repo` for a private package) and re-onboard through setup.

Always report which of the two occurred. "Permission denied" alone sends the user
to regenerate a token that was never the problem.
