Actions run the pinned commit
actions.lock is now the check, not a hint. A run must carry .github/workflows/actions.lock, and every action it names must resolve to the commit in the lock. A missing or unreadable lockfile, a workflow the lock does not list, or an action with no pin fails the run before preloop looks up a ref. A tag that has moved fails the job instead of running the moved commit. Refs the format does not pin — local paths, docker:// images, reusable workflows and expression refs — are left alone.
Rust, Go, Turbo, Nx and Docker caches
Swatinem/rust-cache and actions/setup-go now use preloop's cache, including Cargo's registry and target directories and Go's module and build caches. Rust jobs without a cache step still get the registry, and Go's build cache is wired when Go 1.24 or newer is present. Turborepo and Nx remote caches are served from the same cache, and Docker pulls go through a pull-through registry cache. Fork pull requests read but cannot write.
Job- and workflow-scoped secrets
A secret can name the branches, workflows, jobs and calling workflows allowed to read it. A job that matches none of the bindings sees the name as unset, and a more specific tier that misses does not fall back to a broader value. Environment protection rules are re-checked when the job starts, not only when it was admitted, so a rule added while a job sat queued still applies. A matrix value containing / cannot be mistaken for a caller in the chain.
Organization secrets
A secret can belong to an organization rather than a repository. Visibility is per secret: leave the repository list empty and every repository in the organization can read it, or name a list and only those repositories can. Resolution goes run, environment, repository, organization, then global. plp ci secrets set NPM_TOKEN --org acme --repos acme/api,acme/lib writes one, and the CLI never prints the value back.
Test selection
Only the tests a change can reach are run. preloop records what each test reads and imports, then on a later commit skips a test only when its dependency map is complete and unchanged, it hit no barrier, and it last passed. New, failed, flaky and uncertain tests always run, and lockfiles, package manifests, test configuration and .env files select the whole suite. The step still says pytest, go test, jest, vitest or playwright, and every run or skip carries a reason.
Migrate from GitHub Actions
plp ci migrate reads a repository and sorts every workflow into one it can move, one that should stay on GitHub, and one preloop cannot run. A release, a tag push, an environment or an OIDC deploy keeps a workflow on GitHub; macOS, Windows and GPU runners are unsupported. For the workflows it can move, apply rewrites the runs-on line and opens a pull request with your own git and GitHub CLI credentials. status reports which moved workflows are still enabled on GitHub. The same scan and plan are available as JSON for an agent, and as API endpoints.
Ruby, Java and Bun caches
ruby/setup-ruby, actions/setup-java and oven-sh/setup-bun now use the same cache. Ruby's Bundler bundle and toolcache are restored natively; Java provisions Temurin and Corretto JDKs through the shared cache and caches Maven, Gradle and sbt dependencies; Bun verifies its release against SHASUMS256.txt, caches installs, and skips bun install --frozen-lockfile on an exact hit. Each action falls back to its stock behavior for inputs the native path does not support.
Node and Python caches
actions/setup-node and actions/setup-python now restore their dependency caches from preloop instead of the legacy cache service. Node's npm, Yarn and pnpm stores and Python's pip, pipenv and poetry stores are keyed the way the actions key them, and a hit prints the same cache-hit output and log lines. Toolchain downloads use the shared cache, so a version is downloaded once and served from local storage.
Code-scanning uploads
github/codeql-action/upload-sarif now works unchanged. preloop accepts SARIF 2.1.0 at the endpoints the action uses, stores the document, and returns normalized findings with tool, rule, level, path, line and fingerprint. Re-uploading the same analysis deduplicates instead of creating a second copy. The same documents can be posted to the run API directly.
Rerun a workflow in place
Rerun a workflow from the GitHub API or gh run rerun, and preloop reruns it in the same run instead of creating a new one. A failed-jobs rerun, a single-job rerun, a cancel, and a check-suite rerequest all keep the run's history and check-run mapping. A rerun can turn the debugger on for the new attempt. Archived runs still accept a full rerun, which resubmits the recorded workflow.
One checkout per run
Every job in a run checks out the same immutable commit, so preloop can fetch it once and serve each job's checkout from that copy. Each job still gets its own writable workspace; only the Git objects are shared, read-only. The cache is scoped to the repository and the credential that fetched it, and large files are fetched on demand and kept for the run. A cache problem falls back to a direct checkout.
Green runs open the pull request
A push-triggered run that ends green can open the pull request itself. The repository chooses whether that happens always, never, or only when asked; [pr], [draft] and [no-pr] in the commit message override the policy, and an existing open pull request is reused instead of duplicated. The same flow works from an uncommitted tree: preloop runs the workflow on the snapshot, and a green result can become a real commit and pull request.