docs

Registries & publishing

ply has no registry protocol. A source is a URL template; fetching is construct URL → HTTPS GET → verify sha256 → store. That means any dumb file host is a first-class registry, and there is no rate-limited API in your deploy path.

#Source kinds

[sources]
default = "https://registry.plybox.sh/ply/{package}"   # the official registry
mine    = "github:iluxav/my-packages"                  # GitHub Releases
corp    = "https://artifacts.corp.net/ply"             # any https host
local   = "file:///srv/ply-packages"                   # a directory
Spec Resolves to
github:org/repo https://github.com/org/repo/releases/download/v{version}/{filename}
gitlab:group/proj https://gitlab.com/group/proj/-/releases/v{version}/downloads/{filename}
https://host/path https://host/path/{filename}{package} in the URL expands to the package name
file:///path local directory

Plain http:// is allowed for localhost and RFC-1918 hosts (handy for a LAN registry); public hosts require --insecure-source — the hash catches tampering either way, this is hygiene.

Dependencies pick a source by alias:

[dependencies]
node    = "22"                                    # uses `default`
mytools = { source = "mine", version = "0.1" }    # uses the alias

#The official registry

registry.plybox.sh serves mainstream Alpine packages converted to ply images — prebuilt, content-addressed, append-only (a published version never changes or disappears, so lockfiles never rot). It's a read-only CDN: no accounts, no uploads, no API. Browse it at registry.plybox.sh.

#Publishing your own packages

Because a registry is just files, publishing is copying:

GitHub Releases (the common case) — name the release tag v<version> and upload the image as an asset. ply build already names artifacts canonically, so a CI job is two lines:

- run: ply build .
- run: gh release upload v1.2.0 myapp-1.2.0-linux-x64.img

Any web host / bucket — upload the image under your chosen prefix.

A directory (great for testing and airgapped deploys):

mkdir -p /srv/ply-packages
cp myapp-1.2.0-linux-x64.img /srv/ply-packages/
# … and on the consuming side:
# [sources] default = "file:///srv/ply-packages"

#Version listing (index.json)

Fetching a pinned version needs nothing but the filename. Resolving a range (node = "22") needs to know which versions exist. On plain http(s) hosts, publish an index.json next to the images — a JSON array of filenames:

["node-22.5.0-linux-x64.img", "node-22.6.0-linux-x64.img"]

Directory sources list files directly, no index needed. Forge sources (GitHub/GitLab) can't list versions yet — pin exact versions for them.

#Private packages

For a private artifact host, anything your network can GET works (VPN, signed URLs, LAN). The hash check makes the transport untrusted by design. Token-authenticated GitHub sources are on the roadmap.

#The testing gift

python3 -m http.server 8000 --directory /srv/ply-packages

…is a complete, working registry. ply's own integration tests spin one up in a tempdir and run the full resolve→fetch→verify path offline in milliseconds. Airgapped deploys are the same trick: rsync the directory, use a file:// source.