Skip to main content
This reference lists every plp command. Run plp <command> --help for the same text from the installed version. plp talks to the hosted Preloop platform at PRELOOP_URL, which defaults to https://app.preloop.dev, using the signed-in session. PRELOOP_TOKEN is an optional explicit bearer token for a script or a delegated child process; there is no administrator-token fallback. CI commands live under the plp ci group; plp --help lists the group, version and update stay top level.

Sign in and select an organization

Hosted Preloop uses an RFC 8628 device flow. login opens the Preloop login page with the device’s user code and prints that URL and code as a fallback for machines without a browser; sign in there, and the page approves the device and selects or creates your organization. The CLI polls until approval completes, then stores the session credential for the CLI. Access tokens are short-lived and refreshed by the platform; they are always scoped to the selected organization.
org use changes the organization on which subsequent commands operate and checks that the signed-in user belongs to it. An organization is the only tenant: a request for another organization is refused rather than treated as an administrator request. A user may delegate only within the current organization.

Manage coding agents

Agent administration is performed by a non-delegated user session. These actions are human-gated: an agent cannot create or delete another agent, register or revoke credentials, or approve a device flow.
agent list returns agents in the selected organization. agent credentials shows credential metadata and revocation state, never a private key or bearer value. Agent credentials are registered by the user, then the agent authenticates its own session with either a federated OIDC ID token or an RFC 7523 Ed25519 key assertion:
Assertions are single-use and replay is refused. The helper never prints a token or assertion. agent exec delegates a bounded session to an active agent:
The resulting delegated token is the intersection of the user’s grants, the agent’s ceiling, and the requested scopes. --ttl must be at most 15 minutes because delegated access tokens carry the revocation epoch directly; a longer request is refused. Cross-organization agents, inactive agents, an empty intersection, and requests outside the ceiling are refused. grant-job is a task grant: explicit actions scoped to run:RUN_ID/job:JOB, live only for that job and its grant lifetime; it is not a standing organization grant. The built-in ci-agent role is intentionally narrow: it can create/read runs, cancel its own runs, read and control its own debug sessions, and read artifacts and workflow/job/step data. It has no secrets:use, oidc:use, or runs:publish permission. Delegation never grants human-gated actions, including environment approval/override, fork approval, agent administration, policy changes, or secret administration.

Grant scopes

A grant is an action list attached to a scope; the scope is what makes a repository- or environment-scoped delegation possible. The canonical grammar is hierarchical — org contains every repository, a repository contains its environments and workflows, a workflow contains its jobs, a run contains its jobs:
The forge is github.com; the short github spelling early tokens minted is accepted and normalized, and any other spelling is refused, because a scope the platform can never build would leave the grant silently dead. Workflow paths are URL-escaped so they may embed / as %2F. A delegated token (--act agt_…) carries the intersection of the user’s grants, the agent’s ceiling and the request; the platform re-checks that intersection at every decision, so a scope in the token is an upper bound, not the decision itself.

Approve human-gated work

Approvals use the logged-in human session. There is no administrator override flag, and delegated agents are refused by the server:
The first command satisfies an environment approval gate; the second approves a run held by fork policy. Both actions are audited with the authenticated principal.

Run and inspect workflows

plp ci run

Submit a workflow to the platform, stream its events, and wait for the run to finish.
Working tree. A run snapshots your working tree, including uncommitted and untracked files that git does not ignore, and uploads it with the run. The run never depends on what you pushed. Interactive debugging. In a terminal, a non-detached run pauses a failed job in a debug session for plp ci debug. Pass --debug to opt in for detached or non-interactive runs. pull_request runs. Like GitHub, a pull_request run tests the merge of the base branch’s current tip into your head; the base is fetched from origin. A conflicted pull request fails the submission with the conflicted files listed, and an unfetchable base fails loudly. --no-merge tests the branch alone. push events are unaffected: they test the commit itself. Derived event data. The CLI fills in what git can answer: changed files (for paths: filters, from git diff against the base), the target branch for branches: filters, and the current branch or tag. It does not invent a pull request number, actor, or labels. Pass --payload when a workflow depends on those. Secret preflight. When the workflow reads a secrets.* name the platform has not stored, the submission reports the missing names so you can store them. --strict-secrets turns that warning into a failure. The check reads the platform’s store — global, repository, and each environment: tier the workflow declares — never GitHub’s, whose values are write-only. A job that passes secrets: inherit to a reusable workflow is called out, because its callee’s names cannot be listed statically. GITHUB_TOKEN and the ACTIONS_* runtime tokens are ignored: the platform mints those per job. --push. A dirty tree is committed as a snapshot of exactly the files that were tested, and that commit is pushed only after the run succeeds. Publishing needs a GitHub App with checks: write to report check runs.

plp ci plan

Show the expanded job graph, including matrix fan-out and needs:, without running anything.

plp ci status

Show active and recent runs, or print one run’s status word for scripts.

plp ci logs

Show run logs. Without flags, every job’s log is merged in dispatch order.
Steps that the runner adds itself, such as Set up job and Complete job, appear in the whole-job log but do not take a --step number.

plp ci cancel

Cancels the run. RUN_ID defaults to the most recent active run.

plp ci rerun

With no flag, every job runs again as a new attempt on the same run. github.run_attempt increments, and the previous attempt stays in history. A run that the archiver has already moved to history can only be re-run in full, as a new run.

plp ci push

Publishes a completed run’s result to GitHub: pushes the tested commit, creates or updates the pull request, and reports check runs. RUN_ID defaults to the most recent run. Re-running the command is safe.

plp ci manifest

Read a run’s signed manifest for each job, including the exact tested source tree, workflow-byte digest and binding state, environment, actions, result, and evidence gaps. Run-level output selects only each job’s newest attempt and one representation. The aggregate is capped at 31 MiB of body bytes (with framing headroom under the CLI’s 32 MiB response limit); use --job if the server returns 413.
--verify accepts a record whose signature is valid but whose evidence is incomplete; inspect collection.missing and spec.source before treating it as proof of a clean run.

Debug and inspect

plp ci debug

Attach to a job paused at a failed step, inspect it, and issue a verdict.

plp ci dap

Attach an interactive DAP client to a run that was started with debugging enabled.

Secrets

plp ci secrets

Manage the secrets jobs read: list, inspect, store, restrict, and delete them. Every subcommand is one call to the platform’s secrets API, so what the command line can do is what the API can do. Values are write-only: no subcommand prints one, and the API never returns one.
Names are UPPER_SNAKE: letters, digits, and underscores.

Import from GitHub Actions

plp ci migrate apply runs this import as its secrets phase after gate set_secret; the standalone command remains for migrating a repository later. It moves the GitHub Actions values into the platform without handling a plaintext value locally:
With no --secrets, names come from the same parser walk as plp ci run’s secret preflight. --scope repo (default) writes the repository tier; --scope env writes one environment tier per --environment (or per environment the workflows pin a job to) and generates one workflow job per environment, because GitHub only exposes an environment’s secrets to a job that declares it; --scope org writes the organization tier of the repository’s owner. The command creates a five-minute import intent, then commits a throwaway workflow to a local branch with git plumbing — the worktree and index are untouched. It prints, and with --push runs, the exact push:
Pushing a workflow file needs a git credential that may write workflows (a gh login carries the workflow scope; a classic PAT needs it too). The workflow runs on ubuntu-latest with id-token: write and contents: write, reads only the explicitly mapped secrets.NAME values, seals each value to the intent’s one-use RSA key (RSA-OAEP-SHA256 + AES-256-CBC + HMAC-SHA256), and posts the sealed bytes with a GitHub OIDC token for the preloop-secret-import audience. The platform accepts the post only when the token’s signature, issuer, audience, repository, ref (the throwaway branch), and — for --scope env — environment match the intent. Every entry is imported once; a replay or an expired intent is refused. The workflow deletes its branch in a final always() job. After a push, the command polls the intent and reports per-secret progress. A declined push leaves the local branch in place so it can be pushed manually. The intent’s private key never leaves the platform process and is dropped when the intent is consumed; no value is ever logged, committed, or returned by the API. Selectors. A secret lives in one tier. Give exactly one form; it is checked before any request is sent. --org never combines with --repo or --env, and --env needs --repo. list with no selector shows every tier. Setting a value. Give the value through exactly one source: With none of them, a terminal gets a hidden prompt; anything else is refused. Pass --stdin, --from-file or --from-env in scripts and agents.
For --org, --repos <OWNER/NAME,…> names the repositories that may read the secret; each one must belong to the organization. Omit it for every repository of the organization. Each set defines the list in full, so a set without --repos makes the secret visible to every repository again. Bindings. A binding restricts which jobs may read a secret. A secret with no bindings is available to every job its tier reaches. These flags build bindings for set and scope: One set of flags builds one binding, and every field in it must match (AND). Each --binding adds another, and a job gets the secret when any one binding matches (OR).
A set without scope flags keeps the secret’s existing bindings, so rotating a value never widens access. A set with scope flags replaces them. Invalid combinations are refused before the request, with the flag named: --job needs --workflow, --caller-job and --subtree need --caller, and a --caller plus --caller-job binding with no --workflow, --job or --subtree would only match the caller job, which runs no steps. The platform applies the same rules and is the authority. Output. list prints a table of name, scope, repositories (organization secrets), and bindings; get prints the tier and each binding; scopes prints what the platform supports. Add --json to list, get, or scopes for the platform’s response as-is.
Secret values remain write-only. A signed-in user with the required organization grant can manage a secret, but an agent cannot list or use secrets unless a user explicitly delegates those actions; the built-in ci-agent role cannot use secrets.

Migrate from GitHub Actions

plp ci migrate moves a repository’s workflows to Preloop in one end-to-end flow: workflows (copy into .preloop/workflows/ and open the pull request), secrets (the GitHub OIDC import after gate set_secret), and OIDC (each provider’s per-organization issuer and trust check, after gate configure_trust). Release, publish, deploy, and environment: workflows stay on GitHub.

Self-management

plp update

Check for a newer release, or install one. Installs are atomic.