Shipyard Deploy

3 min read

Continuous delivery from agents to devices in seconds: per-branch channels, verified installs, build notes, FCM-nudged auto-upgrades. No Play, no CI queue, no USB cable.

Shipyard Deploy is continuous delivery for development builds: an agent (or a human) builds an Android APK anywhere, publishes it in one command, and it’s installable on an enrolled device in seconds. No Play track, no CI queue, no USB cable.

Device client home: all apps up to date, synced seconds ago Apps list with per-app build status App detail: installed build, channel, and history

Why it exists

The productivity story is the architecture story. My agents work remotely: a Shipyard runner on another machine builds a branch while I’m away from the desk. Before Deploy, “let me try that build” meant being at the machine, cabling a device, or waiting on a release pipeline. Now the loop is:

agent builds APK ──> publishes to its branch's channel ──> FCM nudge
me, wherever I am ──> phone shows the build ──> tap to install
(or it auto-upgrades)

Any build, any branch, any time, on whatever enrolled device I’m holding. The agent never touches the device; I never touch the build machine.

Highlights

  • Builds per branch. Every branch publishes to its own channel, so feature work, main, and experiments coexist on one device without clobbering each other. Milestone builds get durable channels of their own.
  • Configurable delivery. Per-app, per-channel policy decides whether a device auto-upgrades the moment a build lands or waits for a tap.
  • Build notes travel with the build. What changed and why, visible on the device before installing.
  • FCM integration. Publishing nudges enrolled devices instantly; polling covers the quiet path, so delivery works with or without push.
  • Trust is verified, not assumed. A Gradle plugin embeds a build identity into the APK at packaging time; the device client downloads, verifies the bytes match what the publisher sent, and never reinstalls a build it already has.

Architecture

Three small pieces around a Cloudflare control plane:

PieceRole
Gradle pluginStamps build identity into the APK at packaging time
Go CLI (shipyard-deploy)Publishes signed artifacts, resumable transfers, inspection
Cloudflare Worker + D1 + R2Control plane: channels, build metadata, presigned artifact transfers
Android clientPolls + FCM, downloads, verifies, installs; shows status and history

The whole system runs two ways: fully local (local Worker, emulator, no FCM) and against a deployed Cloudflare dev environment with real D1, R2, and FCM, both exercised end to end. There’s also a Claude Code skill so agents can onboard a repo, publish, and query deployed builds without human hands: the same integration this site’s tooling uses.

Status

MVP proven end to end on both topologies, in daily use for my own device fleet. The staged pilot toward multi-developer and physical-fleet use is scoped and honest about what isn’t there yet: the README’s “proven vs. not” section is the contract.