| name | updating-xport |
| description | Act on `xport.json` lock-step drift: auto-bump `version-pin` rows; the other row kinds (file-fork, feature-parity, spec-conformance, lang-parity) are advisory only. |
| user-invocable | true |
| allowed-tools | Bash(pnpm:*), Bash(npm:*), Bash(git:*), Bash(node:*), Bash(rg:*), Bash(grep:*), Bash(find:*), Bash(ls:*), Bash(cat:*), Bash(head:*), Bash(tail:*), Bash(wc:*), Bash(diff:*), Read, Edit, Grep, Glob |
| metadata | {"internal":true} |
updating-xport
Act on drift findings in `xport.json`. Auto-apply mechanical version-pin bumps; surface everything else as advisory notes for human review. Commit each actioned row as its own atomic commit so the PR reviewer can accept/reject per-row.
**xport** is a cross-project lock-step manifest. Not every repo has one; this skill exits cleanly when `xport.json` is absent. See `xport.schema.json` (deployed via `socket-wheelhouse/sync-scaffolding.mjs`) for the five row kinds.
The harness at scripts/xport.mts emits JSON reports with severity ∈ {ok, drift, error} per row. This skill consumes that JSON.
Per-kind action policy:
| Kind | Drift signal | Action |
|---|
version-pin | Upstream commits on default ref since pinned SHA | Auto-bump per upgrade_policy: track-latest → advance to latest stable tag; major-gate → advance patch/minor only; locked → advisory only |
file-fork | Upstream file changed since forked_at_sha | Advisory - note in PR body; do NOT auto-merge (forks carry local deltas that need human review) |
feature-parity | Parity score below criticality/10 floor | Advisory - note in PR body; human decides implement vs downgrade criticality |
spec-conformance | Spec submodule moved | Advisory - note in PR body; human decides whether to bump spec_version |
lang-parity | Port divergence / rejected anti-pattern reintroduced | Advisory - note in PR body; humans fix the port or update the manifest |
The common rule: version-pin is mechanical (safe to auto-apply with track-latest/major-gate policies); everything else is advisory (upstream semantics and local deltas matter, humans decide).
**Requirements:**
- Start with clean working directory (check via `git status --porcelain`)
- Run from repo root
- Exit 0 cleanly if `xport.json` is absent - the repo doesn't use xport
- Conventional commit format: `chore(deps): bump to `
- Update `.gitmodules` version comments when submodule tags change (pattern: `# -` on the line above the submodule block)
- Target stable releases only (filter `-rc`, `-alpha`, `-beta`, `-dev`, `-snapshot`, `-nightly`, `-preview`)
Forbidden:
- Never auto-edit
file-fork, feature-parity, spec-conformance, or lang-parity rows' tracked state
- Never bump a
locked version-pin without human approval
- Never skip the tag-stability filter
- Never use
npx, pnpm dlx, yarn dlx - use pnpm exec or pnpm run
CI mode (CI=true or GITHUB_ACTIONS): skip per-row test validation (workflow validates at the end); emit advisory summary to $GITHUB_OUTPUT when present.
Interactive mode (default): validate each auto-bump with pnpm test before committing the next.
Phase 1 - Pre-flight
test -f xport.json || { echo "no xport.json; skill n/a"; exit 0; }
test -f xport.schema.json || { echo "xport.schema.json missing — malformed scaffolding"; exit 1; }
test -f scripts/xport.mts || { echo "scripts/xport.mts missing — malformed scaffolding"; exit 1; }
git status --porcelain | grep -v '^??' && { echo "dirty tree; aborting"; exit 1; } || true
[ "$CI" = "true" ] || [ -n "$GITHUB_ACTIONS" ] && CI_MODE=true || CI_MODE=false
Phase 2 - Collect drift
pnpm run lockstep --json > /tmp/xport-report.json
Parse reports[] from the JSON. Split into:
- auto - rows where
severity == "drift" AND kind == "version-pin" AND upgrade_policy ∈ { "track-latest", "major-gate" }
- advisory - everything else with
severity != "ok"
If both lists empty: exit 0 with "no xport drift".
Phase 3 - Auto-bump version-pin rows
For each row in auto list, in manifest declaration order:
Steps 3a-3e: resolve, find the tag, check out, update the pins, validate + commit
3a. Resolve the upstream submodule + fetch tags
SUBMODULE=$(jq -r --arg a "$UPSTREAM_ALIAS" '.upstreams[$a].submodule' xport.json)
cd "$SUBMODULE"
git fetch origin --tags --quiet
OLD_SHA=$(git rev-parse HEAD)
3b. Find the target tag
Examine existing pinned_tag to identify the tag scheme, then match:
v1.2.3 (v-prefixed semver)
1.2.3 (bare semver)
<prefix>-1.2.3 (project-prefixed)
<prefix>_1_2_3 (underscore style; curl, liburing)
For major-gate policy: parse major version from LATEST vs current pinned_tag. If majors differ, skip - add to advisory with note "major bump needs human review".
3c. Check out + capture new SHA
NEW_SHA_FOR_CHECK=$(git rev-parse "$LATEST")
[ "$OLD_SHA" = "$NEW_SHA_FOR_CHECK" ] && { cd -; continue; }
git checkout "$LATEST" --quiet
NEW_SHA=$(git rev-parse HEAD)
cd -
3d. Update xport.json + .gitmodules
Use jq for structured edit:
jq --arg id "$ROW_ID" --arg sha "$NEW_SHA" --arg tag "$LATEST" \
'(.rows[] | select(.id == $id) | .pinned_sha) = $sha
| (.rows[] | select(.id == $id) | .pinned_tag) = $tag' \
xport.json > xport.json.tmp && xport.json.tmp xport.json
Phase 4 - Compose advisory notes
For each row in advisory, accumulate a markdown line:
- **file-fork** `<id>`: `<local>` — <N> upstream commit(s) since <forked_at_sha[0:12]>. Review diff, cherry-pick if applicable, bump forked_at_sha.
- **feature-parity** `<id>`: parity score <score> below floor <floor>. Implement or downgrade criticality with reason.
- **spec-conformance** `<id>`: upstream spec repo moved. Review for breaking changes before bumping spec_version.
- **lang-parity** `<id>`: <details from messages[]>.
- **version-pin** `<id>`: major bump to <LATEST> — policy=major-gate requires human review.
- **version-pin** `<id>`: upgrade_policy=locked — skipped.
Phase 5 - Report + emit
Final human-readable report to stdout:
The report shape, the CI advisory output, and the HANDOFF block
## updating-xport report
**Auto-bumped:** <N> row(s)
<list>
**Advisory (human review):** <M> row(s)
<list>
In CI mode, emit the advisory block to $GITHUB_OUTPUT (base64-encoded) under key xport-advisory so the weekly-update workflow can include it in the PR body:
if [ -n "$GITHUB_OUTPUT" ]; then
echo "xport-advisory=$(printf '%s' "$ADVISORY" | base64 | tr -d '\n')" >> "$GITHUB_OUTPUT"
fi
Emit a HANDOFF block per _shared/report-format.md:
=== HANDOFF: updating-xport ===
Status: {pass|fail}
Findings: {auto_bumped: N, advisory: M}
Summary: {one-line description}
=== END HANDOFF ===
Success Criteria
- All actionable
version-pin rows bumped atomically (one commit per row)
- Advisory rows collected for PR body / workflow output
- No edits to non-version-pin row state
pnpm run lockstep exits 0 or 2 at end (never 1 - no schema errors introduced)
.gitmodules version comments synchronized with pinned_tag
Commands
pnpm run lockstep --json - drift report (consumed by this skill)
jq - parse + edit xport.json (structured JSON edits)
git submodule status - verify submodule state after bumps
When to use
- Invoked by the
updating umbrella skill (weekly-update workflow)
- Standalone:
/updating-xport when syncing just the xport manifest
- After manual submodule bumps, to refresh
xport.json metadata