agentsclimarketplace

Ship

Skill yves-s/just-ship/skills/ship

Alles abschliessen — commit, push, PR, merge, zurück auf main. Vollständig autonom, NULL Rückfragen. Unterstützt /ship T-{N} für direkten Branch-Zugriff.From its SKILL.md

Install
npx -y skills add yves-s/just-ship --skill ship

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 24 stars24 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

13.0 KB, as published. Nobody here has run it

/ship — ALLES abschliessen, ein Befehl

Vom uncommitted Code bis zum gemergten PR auf main. Ein Befehl, keine Unterbrechung.

WICHTIGSTE REGEL

DU DARFST NICHT STOPPEN ODER FRAGEN. Führe ALLE Schritte 1-8 hintereinander aus. Kein "Soll ich...?", kein "Möchtest du...?", kein "Ich habe committed, soll ich jetzt pushen?". EINFACH ALLES DURCHLAUFEN.

Falls du den Drang hast eine Frage zu stellen: UNTERDRÜCKE IHN und mach einfach den nächsten Schritt.

NICHT verwenden

  • NICHT den Skill finishing-a-development-branch aufrufen
  • NICHT den User nach Optionen fragen
  • NICHT nach Bestätigung fragen
  • NICHT zwischen Schritten stoppen

Konfiguration

Lies project.json. Bestimme den Pipeline-Modus:

  1. Board API (bevorzugt): Falls pipeline.workspace_id gesetzt → board-api.sh verwenden:
    bash .claude/scripts/board-api.sh patch "tickets/$TICKET_NUMBER" '{"status": "done"}'
    
    Credentials werden intern aufgelöst. pipeline.project_id aus project.json.
  2. Legacy Supabase MCP: Falls nur project_id gesetzt (ohne workspace_id), und project_id hat keine Bindestriche → execute_sql verwenden, Warnung ausgeben: "Kein Board API konfiguriert. Nutze Legacy Supabase MCP. Fuehre /setup-just-ship aus um zu upgraden."
  3. Standalone: Falls weder workspace_id noch project_id konfiguriert → Pipeline-Schritte überspringen

project_id Format-Check: Falls pipeline.project_id gesetzt ist und KEINE Bindestriche enthält (kurzer alphanumerischer String wie wsmnutkobalfrceavpxs), ist es eine alte Supabase-Projekt-ID. Warnung ausgeben: "pipeline.project_id sieht nach einer alten Supabase-ID aus. Fuehre /setup-just-ship aus um auf Board-UUID zu migrieren."

Trigger

  • /ship
  • "passt", "done", "sieht gut aus", "klappt", "fertig", "ship it", "mach zu"

Ablauf — ALLE Schritte ohne Pause durchführen

0. Branch auflösen und TICKET_NUMBER setzen

KRITISCH — dieser Schritt setzt die Variable die ALLE folgenden Board-API-Calls verwenden.

Falls /ship mit Argument aufgerufen wird (z.B. /ship T-385):

  1. Ticket-Nummer aus Argument extrahieren (Pattern: T-385 → 385, oder 385 direkt):
    TICKET_NUMBER=$(echo "$ARGUMENTS" | grep -oE '[0-9]+' | head -1)
    
  2. Zugehörigen Branch finden:
    git branch --list "*T-${TICKET_NUMBER}*" "*/${TICKET_NUMBER}-*" | head -1 | xargs
    
  3. Branch auschecken:
    git checkout {branch}
    
  4. Weiter mit Schritt 1

Falls /ship ohne Argument: aktuellen Branch verwenden. Fehler wenn auf main.

In JEDEM Fall — Ticket-Nummer aus Branch-Name extrahieren und als Shell-Variable setzen:

TICKET_NUMBER=$(git branch --show-current | grep -oE 'T-[0-9]+' | head -1 | sed 's/T-//')
if [ -z "$TICKET_NUMBER" ]; then
  echo "ERROR: Konnte keine Ticket-Nummer aus Branch-Name extrahieren. Branch: $(git branch --show-current)"
  exit 1
fi
echo "TICKET_NUMBER=$TICKET_NUMBER"

ALLE folgenden Bash-Blöcke MÜSSEN $TICKET_NUMBER verwenden. Niemals {N} als Platzhalter in board-api.sh Calls — das wird nicht aufgelöst und erzeugt einen 404.

SOFORT WEITER ZU SCHRITT 1.

1. Commit (falls nötig)

git status

Falls uncommitted changes:

git add <betroffene-dateien>
git commit -m "feat(T-{ticket}): {englische Beschreibung}

Co-Authored-By: Claude Opus 4.6 <[email protected]>"

SOFORT WEITER ZU SCHRITT 2.

2. Push

git push -u origin $(git branch --show-current)

SOFORT WEITER ZU SCHRITT 3.

3. PR erstellen (falls keiner existiert)

gh pr view 2>/dev/null || gh pr create --title "feat(T-{ticket}): {Beschreibung}" --body "$(cat <<'EOF'
## Summary
- {Bullet Points}

## Test plan
- {Was wurde getestet}

🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"

SOFORT WEITER ZU SCHRITT 3a.

3a. Review-URL ins Ticket schreiben (nur wenn Pipeline konfiguriert)

PR-URL extrahieren und ins Ticket patchen:

REVIEW_URL=$(gh pr view --json url -q .url 2>/dev/null || echo "")

Board API (bevorzugt):

if [ -n "$REVIEW_URL" ]; then
  if bash .claude/scripts/board-api.sh patch "tickets/$TICKET_NUMBER" '{"review_url": "'"$REVIEW_URL"'"}'; then
    echo "✓ review_url auf T-$TICKET_NUMBER gesetzt"
  else
    echo "⚠ review_url Patch fehlgeschlagen für T-$TICKET_NUMBER — weiter ohne Blockade"
  fi
fi

Legacy Supabase MCP (Fallback):

if [ -n "$REVIEW_URL" ]; then
  mcp__claude_ai_Supabase__execute_sql "UPDATE public.tickets SET review_url = '$REVIEW_URL' WHERE number = $TICKET_NUMBER AND workspace_id = '{pipeline.workspace_id}' RETURNING number, review_url;"
fi

SOFORT WEITER ZU SCHRITT 3b.

3b. Preview URL (Vercel, Shopify oder Coolify)

Nur ausführen wenn hosting.provider gesetzt ist. Die Scripts prüfen selbst ob ein Hosting-Provider konfiguriert ist und exiten graceful wenn nicht. Bei nicht gesetztem hosting-Feld wird dieser gesamte Schritt übersprungen — kein API-Call, kein Warten.

WICHTIG: Die Preview-URL MUSS eine Deployment-URL sein (z.B. https://<project>-<hash>.vercel.app, https://<store>.myshopify.com/?preview_theme_id=... oder https://<app>.coolify-domain.tld). NIEMALS einen GitHub-Link, PR-URL oder Repository-URL als preview_url setzen. Das preview_url-Feld ist ausschließlich für die live deployete Vorschau.

# Read hosting provider from project.json (supports object and legacy string format)
HOSTING_PROVIDER=$(node -e "
  const c = require('./project.json');
  const h = c.hosting;
  if (typeof h === 'object' && h !== null) {
    process.stdout.write(h.provider || '');
  } else if (typeof h === 'string') {
    process.stdout.write(h);
  }
")

if [ "$HOSTING_PROVIDER" = "shopify" ]; then
  PREVIEW_URL=$(bash .claude/scripts/shopify-dev.sh start "T-${TICKET_NUMBER}" "${TITLE}")
elif [ "$HOSTING_PROVIDER" = "vercel" ]; then
  PREVIEW_URL=$(bash .claude/scripts/get-preview-url.sh 30)
elif [ "$HOSTING_PROVIDER" = "coolify" ]; then
  PREVIEW_URL=$(bash .claude/scripts/get-preview-url.sh 60)
else
  # No hosting provider configured — skip preview URL entirely
  PREVIEW_URL=""
fi

Falls eine URL gefunden wurde ($PREVIEW_URL nicht leer):

Board API:

if [ -n "$PREVIEW_URL" ]; then
  if bash .claude/scripts/board-api.sh patch "tickets/$TICKET_NUMBER" '{"preview_url": "'"$PREVIEW_URL"'"}'; then
    echo "✓ preview_url auf T-$TICKET_NUMBER gesetzt"
  else
    echo "⚠ preview_url Patch fehlgeschlagen für T-$TICKET_NUMBER — weiter ohne Blockade"
  fi
fi

Legacy Supabase MCP (Fallback):

if [ -n "$PREVIEW_URL" ]; then
  mcp__claude_ai_Supabase__execute_sql "UPDATE public.tickets SET preview_url = '$PREVIEW_URL' WHERE number = $TICKET_NUMBER AND workspace_id = '{pipeline.workspace_id}' RETURNING number, preview_url;"
fi

Falls keine URL gefunden: still überspringen, kein Fehler. Das Script exits immer mit Code 0.

SOFORT WEITER ZU SCHRITT 3c.

3c. Dev-Server stoppen (falls laufend)

PID-Tracking: /just-ship-review speichert die Dev-Server-PID in .claude/.dev-server-pid.

if [ -f ".claude/.dev-server-pid" ]; then
  PID=$(cat .claude/.dev-server-pid)
  kill $PID 2>/dev/null || true
  rm -f .claude/.dev-server-pid
fi

Falls PID-Datei nicht existiert aber build.dev_port in project.json konfiguriert:

DEV_PORT=$(node -e "process.stdout.write(String(require('./project.json').build?.dev_port || ''))")
if [ -n "$DEV_PORT" ]; then
  lsof -ti :$DEV_PORT | xargs kill 2>/dev/null || true
fi

SOFORT WEITER ZU SCHRITT 4.

4. Merge

gh pr merge --squash --delete-branch

SOFORT WEITER ZU SCHRITT 5.

5. Zurück auf main

git checkout main && git pull origin main
# Lokalen Branch aufräumen (Remote wird von --delete-branch gelöscht)
git branch -d {branch} 2>/dev/null || true

SOFORT WEITER ZU SCHRITT 5a.

5a. Shopify Post-Merge (falls Shopify-Projekt)

Bestimme Shopify-Variant und führe den passenden Post-Merge-Step aus:

PLATFORM=$(node -e "process.stdout.write(require('./project.json').stack?.platform || '')" 2>/dev/null || echo "")
VARIANT=$(node -e "process.stdout.write(require('./project.json').stack?.variant || '')" 2>/dev/null || echo "")

App-Variant (variant: "remix"): Extensions und App-Config deployen:

if [ "$PLATFORM" = "shopify" ] && [ "$VARIANT" = "remix" ]; then
  bash .claude/scripts/shopify-app-deploy.sh
fi

Das Script:

  • Führt shopify app deploy --force aus
  • Retry 1x bei Exit-Code 1 (transient), sofort abbrechen bei Exit-Code >1 (auth/validation)
  • Gibt Warnung aus bei Fehler — blockiert NICHT den Merge
  • Auth via SHOPIFY_CLI_PARTNERS_TOKEN (VPS) oder CLI-Session (lokal)

Ausgabe:

  • ✓ shopify — Extensions und App-Config deployed (bei Erfolg)
  • ⚠ shopify — App Deploy fehlgeschlagen, manuell deployen (bei Fehler)

Theme-Variant (default): Unpublished Preview-Theme löschen:

if [ "$PLATFORM" = "shopify" ] && [ "$VARIANT" != "remix" ]; then
  THEME_ID_FILE=".worktrees/T-${TICKET_NUMBER}/.claude/.shopify-theme-id"
  [ ! -f "$THEME_ID_FILE" ] && THEME_ID_FILE=".claude/.shopify-theme-id"
  SHOPIFY_THEME_ID_FILE="$THEME_ID_FILE" bash .claude/scripts/shopify-preview.sh cleanup
fi

Ausgabe:

  • ✓ shopify — Theme gelöscht (falls Theme-ID vorhanden)
  • Still überspringen falls kein Shopify-Projekt

SOFORT WEITER ZU SCHRITT 5b.

5b. Worktree Cleanup (falls Worktree existiert)

Prüfe ob ein Worktree für dieses Ticket existiert:

if [ -d ".worktrees/T-$TICKET_NUMBER" ]; then
  git worktree remove ".worktrees/T-$TICKET_NUMBER" --force 2>/dev/null || true
fi

Ausgabe: ✓ worktree — .worktrees/T-$TICKET_NUMBER aufgeräumt (falls vorhanden)

Falls kein Worktree existiert: still überspringen.

SOFORT WEITER ZU SCHRITT 5c.

Hinweis: Schritt 3b (Vercel Preview URL) bleibt unverändert. Für Shopify-Projekte returned das Vercel-Script leer, und die Preview-URL wurde bereits während /develop Schritt 9f ins Ticket geschrieben.

5c. Token-Tracking (nur wenn Pipeline konfiguriert)

Token-Delta-Berechnung und Board-Update läuft deterministisch über ein Script:

bash .claude/scripts/ship-token-tracking.sh $TICKET_NUMBER

Das Script berechnet das Delta zwischen dem Start-Snapshot (geschrieben bei /develop Step 3e) und dem aktuellen Session-Stand, patcht das Board mit den granularen Token-Feldern und räumt den Snapshot auf.

SOFORT WEITER ZU SCHRITT 6.

6. Pipeline-Status auf "done" (nur wenn konfiguriert)

Board API (bevorzugt): Via Bash curl mit Retry bei Fehler:

SHIP_STATUS_OK=false
for ATTEMPT in 1 2 3; do
  if bash .claude/scripts/board-api.sh patch "tickets/$TICKET_NUMBER" '{"status": "done", "summary": "{pr_summary}"}'; then
    SHIP_STATUS_OK=true
    break
  fi
  echo "Board-Status-Update fehlgeschlagen (Versuch $ATTEMPT/3), retry in ${ATTEMPT}s..."
  sleep $ATTEMPT
done
if [ "$SHIP_STATUS_OK" != "true" ]; then
  echo "⚠ Board-Status-Update auf 'done' fehlgeschlagen nach 3 Versuchen. Manuell prüfen: T-$TICKET_NUMBER"
fi

Hinweis: summary wird mitgesendet damit das Board eine Zusammenfassung des abgeschlossenen Tickets anzeigt.

Legacy Supabase MCP (Fallback): Via mcp__claude_ai_Supabase__execute_sql:

UPDATE public.tickets SET status = 'done', summary = '{summary}' WHERE number = $TICKET_NUMBER AND workspace_id = '{pipeline.workspace_id}' RETURNING number, title, status;

SOFORT WEITER ZU SCHRITT 7.

7. Bestätigung (EINZIGE Ausgabe an den User)

✓ Shipped: feat(T-{ticket}): {Beschreibung}
  PR: {url}
  Branch: {branch} → deleted
  Worktree: .worktrees/T-$TICKET_NUMBER → aufgeräumt (falls vorhanden)
  Board: done (falls konfiguriert)

Prüfe ob andere Branches aufgeräumt werden sollten:

git fetch --prune
STALE=$(git branch -v | grep '\[gone\]' | awk '{print $1}')
BEHIND=$(git for-each-ref --format='%(refname:short) %(upstream:track)' refs/heads | grep -v 'main' | while read branch track; do
  COUNT=$(git rev-list --count "$branch..main" 2>/dev/null || echo 0)
  if [ "$COUNT" -gt 50 ]; then
    echo "$branch — $COUNT Commits hinter main"
  fi
done)

Falls stale oder weit hinter main (>50 Commits):

Hinweis: Folgende Branches könnten aufgeräumt werden:
  {branch-name} — Remote gelöscht
  {branch-name} — 73 Commits hinter main

Nur als Hinweis — nicht automatisch löschen.

Fehlerbehandlung

  • Pre-Commit Hook Failure: Fixen, NEUEN Commit, weiter
  • Push rejected: git pull --rebase origin {branch}, dann nochmal pushen
  • Merge-Konflikte: NUR DANN dem User zeigen — das ist der EINZIGE Grund zum Stoppen
  • PR existiert bereits: Überspringen, direkt mergen
  • Alles schon auf main: Sagen "Bereits auf main, nichts zu tun"

Verboten

  • git add -A oder git add .
  • --force push
  • --amend bei Hook-Failure
  • Fragen stellen
  • Zwischen Schritten stoppen
  • Den Skill finishing-a-development-branch aufrufen

Keep looking

Skills are one crate of 626,474. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.