/push
Push direction: ports local mechanism-script fixes back to the hub as a reviewed PR. Opposite of /update.
> /plugin marketplace add anshss/shiploop> /plugin install shiploop@shiploop
Command definition
push.mddescription: Push direction: ports local mechanism-script fixes back to the hub as a reviewed PR. Opposite of /update.
allowed-tools: Bash, Read
/shiploop:push
**The push direction of the harness-code update channel.** Reconciles the hub against improvements you've made locally to mechanism scripts inside THIS workspace. Think of it as `git push` for harness code: `sync-port.sh` is the machinery (already generalized in v1.2.0), this command wraps it into a one-command action for interactive use.
Companion to `/shiploop:update` (pull). The two commands close the loop on fleet drift.
What it does (procedure)
1. **Preconditions:** `GOVERN_UPSTREAM_HARNESS_REPO` set in `workspace.sh`; the workspace scaffolded from v1.2.0 or later (so `scripts/govern/sync-port.sh` is present); a local hub clone reachable. 2. **Drift detection** via `scripts/govern/sync-templates.sh --check` — mirrored files you've changed vs the last sync marker. 3. If drift → **invoke `scripts/govern/sync-port.sh`** (the existing porter). It:
- Cuts a branch off `origin/main` in the hub clone.
- Spawns a headless porter that genericizes your changes (strips your identity strings, adds
placeholders like `__META_NAME__`, `__GITHUB_ORG__`).
- Validates: `bash -n` on changed shell files + forbidden-identity-strings gate on ADDED lines +
scaffold-test-suite baseline diff.
- On any gate failure, files an escalation and exits non-zero. NEVER pushes an unvalidated port.
- On pass, opens a PR **against the canonical hub** for **HUMAN review** — routing by your access
posture (see below): a same-repo PR when you can push to the hub, otherwise a cross-repo PR from your fork (auto-created via `gh repo fork` when you don't already have one). 4. **Report** the PR URL (if any) and the marker state.
The three access postures (push v2 — the contribution funnel)
`sync-port.sh` derives where the branch lands and where the PR opens from **git + GitHub**, not from workspace config — it reads the templates clone's `origin`, finds the canonical hub as that repo's `parent` (falling back to `origin` itself when there is no parent), and checks your push permission. So the PR **always** targets the real canonical hub, never stranding inside your own fork:
| Posture | Your templates clone | What `/push` does | |---|---|---| | **direct-access** | you can push to `origin`, and `origin` **is** the hub (the maintainer) | push the branch to `origin`, open a **same-repo** PR (bare head). Historical behavior — unchanged. | | **fork** | `origin` is **your fork** of the hub (has a `parent`), you can push to it | push to `origin` (your fork), open a **cross-repo** PR against the hub (`<you>:<branch>`). | | **plain-clone** | a clone of the hub with **no push access** (the common adopter) | `gh repo fork --clone=false` creates your fork, the branch is pushed there, and a **cross-repo** PR opens against the hub. No manual fork step needed. |
If GitHub can't resolve the clone's repo (offline, a non-GitHub remote), sync-port **degrades safely** to the historical direct-to-origin push — it only takes the fork funnel on an *affirmative* no-push signal, never on an unknown one.
Why HUMAN review, never auto-merge
`sync-port.sh` in v1.2.0 gained a `--no-merge` mode for safe first rollouts. `/push` invokes it with `--no-merge` unconditionally — this is an INTERACTIVE command driven by an operator, and the whole point is a human reviews the genericized port before it lands on the global skill. Even if `--no-merge` weren't set, the hub's three-factor auto-merge guard (own-author + own-branch-pattern
- no-forks) would block the governor from merging it. Both belts, both suspenders.
Workspace-specific files (`scripts/lib/workspace.sh`, `package.json`, repo lists, `governor/` operator-data files) are intentionally NEVER pushed. `sync-templates.sh` filters them out at the git-pathspec level. This command's summary tells the operator so — no surprises.
Phase 0 — Preconditions
Must be in a meta-repo workspace
`scripts/lib/workspace.sh` exists AND `scripts/govern/sync-port.sh` + `scripts/govern/sync-templates.sh` exist. If either sync script is missing, the workspace was scaffolded before v1.2.0 — instruct the operator:
This workspace is missing scripts/govern/sync-{port,templates}.sh — scaffold predates v1.2.0.
Run /shiploop:update first to install the sync channel, then re-run /shiploop:push.`GOVERN_UPSTREAM_HARNESS_REPO` must be set
Source `scripts/lib/workspace.sh` (in a subshell) and check. If empty, STOP and print:
GOVERN_UPSTREAM_HARNESS_REPO not set in scripts/lib/workspace.sh — the sync channel is inert.
To enable /shiploop:push:
1. Get a local clone of the hub to port INTO. Either is fine (push v2 handles both):
• a PLAIN clone of https://github.com/anshss/shiploop — no fork needed; /push auto-forks
on your behalf if you lack push access, and
• a clone of YOUR fork of the hub — /push opens a cross-repo PR from it.
Call its path $HUB_DIR.
2. Edit scripts/lib/workspace.sh and set:
GOVERN_UPSTREAM_HARNESS_REPO="shiploop"
GOVERN_UPSTREAM_HARNESS_DIR="$HUB_DIR"
3. Re-run /shiploop:push.Local hub clone must be reachable
`sync-port.sh` reads `GOVERN_UPSTREAM_HARNESS_DIR` (or `wsp_repo_localdir` from workspace.sh) to locate the templates repo working dir. If the resolved directory isn't a git repo, `sync-port.sh` will itself escalate with a clear reason. That's fine — surface its output.
`gh` must be authenticated
`gh auth status` must succeed. `sync-port.sh` calls `gh pr create` and errors out clean if not.
Phase 1 — Dry-run first (recommended by default)
Unless the operator passed `--run` or `--yes` in `$ARGUMENTS`, run the dry-run first:
bash scripts/govern/sync-port.sh --dry-run
The dry-run prints the plan: drifted mirrored files, the branch it WOULD cut, the forbidden
Read more
description: Push direction: ports local mechanism-script fixes back to the hub as a reviewed PR. Opposite of /update. allowed-tools: Bash, Read
/shiploop:push
**The push direction of the harness-code update channel.** Reconciles the hub against improvements you've made locally to mechanism scripts inside THIS workspace. Think of it as `git push` for harness code: `sync-port.sh` is the machinery (already generalized in v1.2.0), this command wraps it into a one-command action for interactive use.
Companion to `/shiploop:update` (pull). The two commands close the loop on fleet drift.
What it does (procedure)
1. **Preconditions:** `GOVERN_UPSTREAM_HARNESS_REPO` set in `workspace.sh`; the workspace scaffolded from v1.2.0 or later (so `scripts/govern/sync-port.sh` is present); a local hub clone reachable. 2. **Drift detection** via `scripts/govern/sync-templates.sh --check` — mirrored files you've changed vs the last sync marker. 3. If drift → **invoke `scripts/govern/sync-port.sh`** (the existing porter). It:
- Cuts a branch off `origin/main` in the hub clone.
- Spawns a headless porter that genericizes your changes (strips your identity strings, adds
placeholders like `__META_NAME__`, `__GITHUB_ORG__`).
- Validates: `bash -n` on changed shell files + forbidden-identity-strings gate on ADDED lines +
scaffold-test-suite baseline diff.
- On any gate failure, files an escalation and exits non-zero. NEVER pushes an unvalidated port.
- On pass, opens a PR **against the canonical hub** for **HUMAN review** — routing by your access
posture (see below): a same-repo PR when you can push to the hub, otherwise a cross-repo PR from your fork (auto-created via `gh repo fork` when you don't already have one). 4. **Report** the PR URL (if any) and the marker state.
The three access postures (push v2 — the contribution funnel)
`sync-port.sh` derives where the branch lands and where the PR opens from **git + GitHub**, not from workspace config — it reads the templates clone's `origin`, finds the canonical hub as that repo's `parent` (falling back to `origin` itself when there is no parent), and checks your push permission. So the PR **always** targets the real canonical hub, never stranding inside your own fork:
| Posture | Your templates clone | What `/push` does | |---|---|---| | **direct-access** | you can push to `origin`, and `origin` **is** the hub (the maintainer) | push the branch to `origin`, open a **same-repo** PR (bare head). Historical behavior — unchanged. | | **fork** | `origin` is **your fork** of the hub (has a `parent`), you can push to it | push to `origin` (your fork), open a **cross-repo** PR against the hub (`<you>:<branch>`). | | **plain-clone** | a clone of the hub with **no push access** (the common adopter) | `gh repo fork --clone=false` creates your fork, the branch is pushed there, and a **cross-repo** PR opens against the hub. No manual fork step needed. |
If GitHub can't resolve the clone's repo (offline, a non-GitHub remote), sync-port **degrades safely** to the historical direct-to-origin push — it only takes the fork funnel on an *affirmative* no-push signal, never on an unknown one.
Why HUMAN review, never auto-merge
`sync-port.sh` in v1.2.0 gained a `--no-merge` mode for safe first rollouts. `/push` invokes it with `--no-merge` unconditionally — this is an INTERACTIVE command driven by an operator, and the whole point is a human reviews the genericized port before it lands on the global skill. Even if `--no-merge` weren't set, the hub's three-factor auto-merge guard (own-author + own-branch-pattern
- no-forks) would block the governor from merging it. Both belts, both suspenders.
Workspace-specific files (`scripts/lib/workspace.sh`, `package.json`, repo lists, `governor/` operator-data files) are intentionally NEVER pushed. `sync-templates.sh` filters them out at the git-pathspec level. This command's summary tells the operator so — no surprises.
Phase 0 — Preconditions
Must be in a meta-repo workspace
`scripts/lib/workspace.sh` exists AND `scripts/govern/sync-port.sh` + `scripts/govern/sync-templates.sh` exist. If either sync script is missing, the workspace was scaffolded before v1.2.0 — instruct the operator:
This workspace is missing scripts/govern/sync-{port,templates}.sh — scaffold predates v1.2.0.
Run /shiploop:update first to install the sync channel, then re-run /shiploop:push.`GOVERN_UPSTREAM_HARNESS_REPO` must be set
Source `scripts/lib/workspace.sh` (in a subshell) and check. If empty, STOP and print:
GOVERN_UPSTREAM_HARNESS_REPO not set in scripts/lib/workspace.sh — the sync channel is inert.
To enable /shiploop:push:
1. Get a local clone of the hub to port INTO. Either is fine (push v2 handles both):
• a PLAIN clone of https://github.com/anshss/shiploop — no fork needed; /push auto-forks
on your behalf if you lack push access, and
• a clone of YOUR fork of the hub — /push opens a cross-repo PR from it.
Call its path $HUB_DIR.
2. Edit scripts/lib/workspace.sh and set:
GOVERN_UPSTREAM_HARNESS_REPO="shiploop"
GOVERN_UPSTREAM_HARNESS_DIR="$HUB_DIR"
3. Re-run /shiploop:push.Local hub clone must be reachable
`sync-port.sh` reads `GOVERN_UPSTREAM_HARNESS_DIR` (or `wsp_repo_localdir` from workspace.sh) to locate the templates repo working dir. If the resolved directory isn't a git repo, `sync-port.sh` will itself escalate with a clear reason. That's fine — surface its output.
`gh` must be authenticated
`gh auth status` must succeed. `sync-port.sh` calls `gh pr create` and errors out clean if not.
Phase 1 — Dry-run first (recommended by default)
Unless the operator passed `--run` or `--yes` in `$ARGUMENTS`, run the dry-run first:
bash scripts/govern/sync-port.sh --dry-run
The dry-run prints the plan: drifted mirrored files, the branch it WOULD cut, the forbidden
Other commands on shiploop.
More commands from other plugins.
build
CommandImplement tasks incrementally — build, test, verify, commit. Add "auto" to run the whole plan in one approved pass.

