CI Publishing
Run pixi-sandbox init, review the generated .github/workflows/publish-sandbox.yml, and commit it
with pixi-sandbox.toml. The project-owned workflow installs pixi-sandbox from
https://prefix.dev/archont561/archont561, computes the native matrix with plan, then calls
pack, doctor --verify, and publish directly. No pixi-sandbox composite Action or reusable
workflow is involved.
Regenerate after changing the init contract and validate the workflow with actionlint. Existing projects migrating from v0.3.x should replace root/setup/publish Action calls and reusable-workflow calls with the newly generated file; immutable old refs remain available for historical jobs.
Carrying CI policy in pixi-sandbox.toml
Section titled “Carrying CI policy in pixi-sandbox.toml”Every real repository wants to change something about the generated workflow: a paths:
allowlist so an unrelated change does not repack and force-push the transport, tighter
permissions:, a concurrency: guard against two publishes racing, timeout-minutes: so a
hung pack does not hold a runner for six hours, or a pinned pixi-version:/disabled cache on
setup-pixi. Older guidance was to hand-edit the generated file for these and re-apply the same
five edits after every init --force — with nothing confirming the re-applied edit still
matched what the current generator would produce.
That ritual is retired. An optional [workflow] table in pixi-sandbox.toml carries this
policy instead, and init renders it straight into the workflow — no hand edits, ever:
[workflow]push_paths = ["pixi-sandbox.toml", "pixi.toml", "pixi.lock"]permissions = truepixi_version = "0.81.0"setup_pixi_cache = true
[workflow.concurrency]group = "publish-sandbox"cancel_in_progress = false
[workflow.timeouts]plan = 15publish = 60See the Configuration Reference
for every field and its default. No [workflow] table at all keeps rendering the historical,
unconditional template — nothing changes for an existing project until it opts in. Run
pixi-sandbox init again any time policy changes (or let the scheduled upgrade job below do
it): the output always matches exactly what the config describes, which is also what makes the
upgrade job’s own regenerated pull requests trustworthy — they come from the same renderer this
local init does, with no local edit left to disagree with it.
Where the published binary comes from
Section titled “Where the published binary comes from”The workflow’s “Download released pixi-sandbox” step always downloads the standalone
pixi-sandbox-<target> asset and its SHA256SUMS manifest from this project’s own
repository (github.com/Archont561/pixi-sandbox/releases/download/v<version>) — never from
the consumer repository the workflow runs in. The downloaded bytes are checksum-verified
against SHA256SUMS before chmod +x/execution in every leg; a mismatch fails the job.
Regenerate if you generated this workflow with v0.4.3, v0.4.4, or v0.5.0. Those versions built the download URL from
$GITHUB_REPOSITORY(the consumer’s own repository), which publishes no such release assets, so the step failed withcurl: (22)(a 404) before anything was packed (issue #80). Re-runpixi-sandbox init --forcewith a patched CLI to regenerate the workflow against the fixed template; no other part of the generated file changes.
Staying current: the upgrade job
Section titled “Staying current: the upgrade job”A new pixi-sandbox release leaves every consumer’s generated files silently stale until
someone notices and re-runs init by hand. The generated workflow also contains an upgrade
job that closes that gap without ever floating a production pin:
- Weekly, on its own (
schedule:), it bootstraps the standalone binary your workflow is currently pinned to (the same checksum-verified download thepublishjob uses), asks that exact binary toself-updateto the latest release, and runsinit --checkwith the updated binary against the exact paths, branch, and config this project was generated with. - On demand (
workflow_dispatch, leaving the newupgradeinput blank runs an ordinary publish exactly as before; naming an exact version there —1.2.3— makes the job self-update to that exact release instead of latest). This is also how you roll back: name an older released version to propose downgrading the generated files to it.
If init --check finds no drift, the job stops — nothing is written, nothing is proposed. If it
finds drift, the updated binary re-runs init for real and the job prepares a pull request
containing only the regenerated workflow, relock workflow, and launcher. It never pushes to
main and never touches pixi-sandbox.toml — config is reviewed data, and a config whose
schema the updated binary no longer understands is reported as a finding in that same
init --check output for a human to act on, never edited automatically.
Delivering workflow-file upgrades
Section titled “Delivering workflow-file upgrades”GitHub’s built-in GITHUB_TOKEN cannot create or update files under .github/workflows/, even
when the job grants contents: write and pull-requests: write. To let the generated job open
its PR automatically, add a consumer secret named PIXI_SANDBOX_UPGRADE_TOKEN containing a PAT
or GitHub App token with permission to write workflow files. The upgrade job uses that token for
checkout, the branch push, and gh pr create; it does not use it to push main.
The secret is optional. Without it, or when GitHub refuses the configured token, the scheduled
job stays green and writes an actionable error and step summary naming the missing Workflows: write permission. It uploads pixi-sandbox-upgrade-artifacts, including a git apply-able
patch for the exact regenerated files, so a maintainer can apply and review the upgrade manually.
This fallback preserves exact version pins and does not bypass the human review gate. There is
no separate upgrade workflow to configure: the generated publisher owns the versioned paths and
keeps the upgrade and publish lanes mutually exclusive.
Review the diff like any other dependency bump — it is, after all, exactly the file init --force would produce locally with the same binary — then merge it. Because a github.token
commit or merge starts no on: push workflow (the same trap the relock workflow documents),
merging this PR does not by itself trigger a new publish. Dispatch it explicitly:
gh workflow run .github/workflows/publish-sandbox.yml --ref mainAfter that run, the matrix’s bootstrap step downloads the exact new release named in the
merged PIXI_SANDBOX_VERSION, and pack/doctor --verify/publish/--self-bin all use that
one verified binary — the published transport’s manifest names that exact version. No
production step ever resolves latest; latest only ever decided what the proposed pull
request contained.
This repository’s own publisher is unaffected by any of this: it builds pixi-sandbox from source and never installs or self-updates a released CLI, so there is nothing here for it to depend on.
Pipeline diagnostics and transport preservation
Section titled “Pipeline diagnostics and transport preservation”Publish failures inside the generated workflow (install → pack → doctor → publish) do
not require access to the live Actions log CDN to diagnose:
- Durable diagnostics artifact: every publish leg records bounded execution logs into
$RUNNER_TEMP/pixi-sandbox-logs/(with--log-fileforpack,doctor, andpublish) and uploads them viaactions/upload-artifactaspublish-diagnostics-<platform>with 7-day retention. - Secondary GitHub failure surface: if any phase fails, the step formats an actionable failure
report directly into
$GITHUB_STEP_SUMMARYnaming the failed phase, target branch, the uploaded diagnostic artifact name, and a bounded 50-line excerpt without leaking tokens or secrets. - Transport preservation: failures during
install,pack, ordoctorhalt beforepublishis called. A rejected push or publish error never commits over or corrupts an existing healthy orphan transport snapshot on the remote branch, leaving the existing transport byte-identical and fetchable. - Separation of concerns: diagnostic logs remain in runner temporary storage and are uploaded as standard workflow artifacts; they are never committed into or published over the transport branch.