Shipyard
Atomic-release deploy CLI. Zero-downtime SSH/rsync deploys with health-gated promotion and automatic rollback. One static Go binary, one YAML config, no agent on the server.

Overview
The first DevOps tool in the portfolio. Every prior piece (webhook-relay, docgen, pennant, inkwell, codex) is a content / data API selling to product or API teams. Shipyard sells to the person who got woken up at 3am because a Composer install on the production box ate all the RAM mid-deploy.
The wrong shape:
Most "deploy scripts" you'll inherit look like ssh prod 'cd app && git pull && pm2 restart app'. That serves half-old, half-new files for 30–90 seconds while git pull trickles in. Composer autoload sees a class the new code doesn't yet have. The restart returns the moment the process is alive — not when it's actually serving 200s. There's no rollback.
The right shape:
Immutable timestamped release directories. Atomic symlink flip via ln -s … current.new && mv -Tf current.new current (a bare ln -sfn is not atomic; the mv is the trick). Health probe with retries against your healthz endpoint. Auto-rollback on failure. Auto-prune of old releases. A remote lockfile so two deploys can't race. Same primitive Capistrano built in 2010 — modernized for a polyglot world.
13-step lifecycle:
- Parse YAML config (strict mode rejects unknown fields — catches
health-checkvs.health_checktypos at load time). - Run
pre_uploadhooks locally (build, package). - SSH connect with known_hosts verification.
- Acquire remote SFTP lockfile with TTL stale-steal.
- SFTP upload artifact into
_incoming/<timestamp>.<ext>. - Extract into
releases/<timestamp>/. - Symlink
shared.filesandshared.dirsinto the release dir. - Run
post_extracthooks remotely in the new release dir. - Atomic symlink flip.
- Run
post_fliphooks remotely (Apache reload, PM2 reload, supervisorctl restart). - Health check. Failure flips the symlink back and runs
on_rollbackhooks. - Auto-prune old releases per
releases.keep. - Release lockfile.
Eat-your-own-cooking:
The docs site at shipyard.philiprehberger.com is itself deployed by Shipyard. The shipyard.yaml that does it lives in the repo root. Every push to main reaches readers the same way every other shipyard-deployed app would.
CLI surface:
shipyard deploy / rollback / status / releases / prune / doctor / version. Exit codes 0/1/2/3/4/5 each mean a specific thing in the lifecycle — CI scripts can branch deterministically without parsing stderr. --dry-run, --skip-health, --release-id, --force for the override paths.
Stack:
- Go 1.23+ with the standard
log/slogfor structured logging golang.org/x/crypto/ssh+pkg/sftpfor native Go transport (no shell-out tossh/scp— that matters for Windows builds)- Cobra for the command tree
gopkg.in/yaml.v3with strict-mode unknown-field rejection- GoReleaser cross-builds for linux/darwin (amd64+arm64) and windows (amd64); GitHub Actions runs goreleaser on every
v*tag push - Next.js 15.5 + React 19 + Tailwind 4 for the docs site (static SSG)
- Apache reverse proxy + PM2 + Let's Encrypt for hosting
What it proves:
Same person designed the deploy lifecycle, hand-authored the Go binary, integration-tested it against a real EC2 host, wrote the GoReleaser config + GitHub Actions release workflow, built the Next.js docs site, provisioned the production vhost + cert + PM2 entry, migrated the docs site itself onto Shipyard-managed deploys, and verified rollback round-trips against the live PM2-fronted Next.js app. The case for hiring me when "we need someone who has actually built infrastructure they ship to other people, not just consumed it."
Results
13-step atomic-release lifecycle with health-gated promotion and automatic rollback
5 platform binaries per release (linux/darwin amd64+arm64 plus windows amd64) via GoReleaser
Exit codes 0..5 stable and documented for CI branching
YAML strict-mode rejects unknown fields at load time (catches health-check vs. health_check typos before the deploy starts)
Native Go SSH+SFTP (no shell-out to ssh/scp; Windows-friendly)
Eats own cooking — docs site at shipyard.philiprehberger.com is itself shipyard-deployed
26 unit tests across config / release / healthcheck / ssh / version packages, plus an integration test verified against real EC2
Gallery


