Skip to content

Quickstart

This walkthrough takes you from zero to a signed release that a client successfully applies. It uses the local filesystem backend and a Python HTTP server in place of S3 + CloudFront, so you can run the whole thing on one machine.

Install

Terminal window
go install github.com/ethan-mdev/patchline/cmd/patchline@latest

Generate a signing keypair

Terminal window
patchline keygen \
--private-out ./patchline.key \
--public-out ./patchline.pub

The private key is written with mode 0600. Keep it out of your repo.

Publish a build

Assuming your build artifacts live in ./dist:

Terminal window
patchline publish \
--app-id com.example.game \
--version 1.0.0 \
--channel beta \
--output ./release-output \
--signing-key ./patchline.key \
./dist

This scans ./dist, hashes every file with SHA-256, writes the content-addressed objects to ./release-output/objects/sha256/..., signs the release manifest with your private key, and writes both releases/1.0.0/manifest.json and channels/beta/manifest.json.

Serve the release tree

Any static HTTP server works:

Terminal window
python -m http.server 8080 --directory ./release-output

Apply on a client

Terminal window
patchline apply \
--app-id com.example.game \
--channel beta \
--base-url http://localhost:8080 \
--public-key ./patchline.pub \
--install-dir ./install

The client fetches channels/beta/manifest.json, verifies the Ed25519 signature against the literal payload bytes, plans which local files differ from the manifest, downloads the missing/changed objects, and atomically swaps them in.

Promote to stable

Once you’re happy with beta:

Terminal window
patchline promote \
--version 1.0.0 \
--channel stable \
--signing-key ./patchline.key

This rewrites channels/stable/manifest.json to point at the existing v1.0.0 release. No file uploads, no rescanning — just a single pointer move.

Next steps

  • Concepts: Channels — how promote, rollback, and gc fit together.
  • CLI Reference — every command and every flag.
  • Use a patchline.yaml next to the CLI to avoid repeating common flags. The config supports ${VAR} interpolation so CI can inject secrets without committing them.