PatchHub
Also available as Markdown for agents

patchhub.json: downloads

patchhub.json at the root of a project tells PatchHub what people can download.

Nothing is stored ahead of time. When someone downloads, PatchHub applies the patches they picked to the version they picked, then builds it in a sandbox.

No patchhub.json yet? PatchHub's AI suggests one as a patch when a project first gets code. The maintainer can also ask for one in the project's Settings tab.

Example

{
  "version": 1,
  "setup": "ph-install go",
  "artifacts": [
    {
      "id": "app",
      "name": "Tasks",
      "kind": "download",
      "targets": [
        {"id": "macos-arm64", "name": "macOS (Apple Silicon)", "build": "GOOS=darwin GOARCH=arm64 go build -o dist/tasks .", "output": "dist/tasks"},
        {"id": "windows-x64", "name": "Windows (64-bit)", "build": "GOOS=windows GOARCH=amd64 go build -o dist/tasks.exe .", "output": "dist/tasks.exe"},
        {"id": "linux-x64", "name": "Linux (x64)", "build": "GOOS=linux GOARCH=amd64 go build -o dist/tasks .", "output": "dist/tasks"}
      ]
    },
    {"id": "manual", "name": "Manual", "kind": "download", "output": "MANUAL.pdf"}
  ]
}

Fields

FieldWhereMeaning
versiontop levelRequired. The file format version: 1.
imagetop level, artifact or targetOptional Docker image to build in, e.g. golang:1.27 or node:22-slim.
setuptop level, artifact or targetShell command run before the build. All levels run, in that order.
artifactstop levelWhat the project offers.
idartifact, targetLowercase letters, digits, dots and dashes.
nameartifact, targetShown to people.
kindartifactdownload (the default, and the only kind for now).
targetsdownload artifactOne entry per system or format. Leave it out for a single file.
buildartifact or targetShell command, run at the project root. Optional for files that are already in the code.
outputartifact or targetThe file to download. A folder ending in / is zipped.

Download ids are artifact/target (e.g. app/macos-arm64). A project with a single artifact uses the bare target id (e.g. macos-arm64). source (the code as a .zip) always exists.

The build sandbox

  • Linux x86-64, with Node, Bun, Python, git, curl and jq. There is no C compiler.
  • No internet, except package registries: proxy.golang.org, sum.golang.org, go.dev, dl.google.com, registry.npmjs.org, registry.yarnpkg.com, pypi.org, files.pythonhosted.org, index.crates.io, static.crates.io, static.rust-lang.org.
  • ph-install go (or ph-install go@1.27) installs Go from go.dev and verifies the official checksum. It's a convenience, not a requirement: setup can be any shell command.
  • Each step can take up to about 5 minutes. Downloads can be up to 500 MB.
  • Build commands come from the chosen version's patchhub.json, never from a patch, so a patch can't change how things are built.

Custom images

Set image to build inside a Docker container instead of the default sandbox:

{"version": 1, "image": "golang:1.27-alpine", "artifacts": [
  {"id": "app", "name": "Tasks", "targets": [
    {"id": "linux-x64", "name": "Linux", "build": "GOOS=linux CGO_ENABLED=0 go build -o dist/tasks .", "output": "dist/tasks"}]}]}
  • The project is mounted at /work (the working directory). setup and build run there with sh -c.
  • Images come from Docker Hub or GitHub's registry (ghcr.io/...). Pin a tag or digest so builds are repeatable.
  • Without image, builds run directly in the sandbox, and ph-install is available.

Problems

The project's Settings tab lists problems with its patchhub.json, e.g. a missing version or an output outside the project. Entries with problems are skipped; the rest still work.