Operate CI through an API.
Submit a run, stream events, inspect each step, pause failures, retry from any step and publish a signed record. Programs use the same authenticated operations as the dashboard.
Submit a run, stream events, inspect each step, pause failures, retry from any step and publish a signed record. Programs use the same authenticated operations as the dashboard.
An agent signs in with federated OIDC or a signed single-use assertion (RFC 7523). The credential identifies the agent itself, with its own scopes and its own audit history.
An owner or admin delegates access under their organization. The agent's working token is the intersection of the grants behind it, its own ceiling and the scopes it requested. Environment approvals, agent administration, policy and secrets stay human-only.
Each call records the actor, who it acted for, the action, the resource, and allow or deny. Delegated access reads as delegation in the audit trail.
Every operation the dashboard performs is an API call, and an agent can make all of them. Each route documents the scope it requires, the request shape, and the response it returns — written to be consumed by the program calling it, not just read by a person.
A generated OpenAPI document describes the full surface, so an agent can enumerate routes, generate a client, or validate its calls before it makes them. The API is plain HTTP with JSON and NDJSON; no SDK or client library is required.
Calls that take time return before they finish, so an agent streams progress instead of holding a connection. Reads that return a decision also return its reason, so the caller can act on the result without parsing a log.
Teaches the agent the preloop security posture: scope secrets to branches, workflows and jobs, gate fork pull requests, pin actions in `actions.lock`, keep values out of logs, and verify the controls around each job.
Teaches the agent to read what CI actually did: test-selection decisions, step-reuse and cache lookups, and the cost of every step. It prunes work that cannot affect the change and measures the savings on the next run.
Skills install into your agent runtime and operate through the same API documented on this page.
A submit returns immediately with a run id and the plan, so the caller knows what will run before it runs. Rerun and cancel are separate calls.
Read NDJSON events for a run and server-sent logs for a job. No polling a status string or scraping a rendered page.
Read what each job and step concluded, which tests ran, why a test was selected, which steps were reused and what a cache lookup returned.
A failed job can pause with its machine alive. An agent takes the writer lease, reads the state and decides what happens next.
Issue a retry from any requested step, including the failed step. `retry`, `retry --from <step>`, `continue` and `abort` are recorded as one controller decision.
Submit a signed record for work that happened elsewhere, read records back and verify them against a pinned key set.
All paths are relative to https://app.preloop.dev. Every call uses a bearer credential.
| Operation | Method and path | Returns |
|---|---|---|
| Submit | POST /api/v1/runs | Accepted, with a run id and the resolved plan |
| List runs | GET /api/v1/runs?limit=&status= | Runs, newest first |
| Read a run | GET /api/v1/runs/{run_id} | Status, jobs, steps, conclusions |
| Events | GET /api/v1/runs/{run_id}/events.ndjson | NDJSON, one event per line |
| Logs | GET /api/v1/runs/{run_id}/logs?job= | The stored log for a job |
| Live logs | GET /api/v1/runs/{run_id}/logs/live?job= | Server-sent events |
| Cancel | POST /api/v1/runs/{run_id}/cancel | Cancellation result |
| Rerun | POST /api/v1/runs/{run_id}/rerun | Accepted |
| Approve | POST /api/v1/runs/{run_id}/jobs/{job_id}/approve | Environment gate result |
| Approve a fork | POST /api/v1/runs/{run_id}/approve-fork | Fork hold released |
| Debug sessions | GET /api/v1/debug/sessions | Paused and attached sessions |
| Session detail | GET /api/v1/debug/sessions/{session_id} | State, lease holder, history |
| Verdict | POST /api/v1/debug/sessions/{session_id}/verdict | Issues retry, continue or abort |
| Verdict poll | GET /api/v1/debug/sessions/{session_id}/verdict | Worker view; null on timeout, which is not an abort |
| Close | POST /api/v1/debug/sessions/{session_id}/close | Session closed |
| Session audit | GET /api/v1/debug/sessions/{session_id}/audit | Every mutating operation |
| Debugger | GET /api/v1/runs/{run_id}/debug | WebSocket upgrade for the debug adapter |
| Tests | GET /api/v1/tests, /impact, /flaky, /savings | Selection and outcome data |
| Test detail | GET /api/v1/tests/{key}/explain | The decision, with its evidence |
| Step reuse | GET /api/v1/runs/{run}/steps/{step}/reuse | Reuse decision for one step |
| Records | GET /api/v1/attestations | Receipts, newest first, keyset paging |
| Record detail | GET /api/v1/attestations/{id} | Record, envelope, keys, publication state |
| Publish | POST /api/v1/attestations | Submit a record from elsewhere |
Expensive operations return before they finish, so callers can stream progress instead of holding a connection open. Reads that return a decision also return its reason, so an agent can act on the result without parsing a log.
while :; do
status=$(gh api "repos/$REPO/actions/runs" \
--jq '.workflow_runs[0].status')
[ "$status" = "completed" ] && break
sleep 20
done
gh run view --log-failed | head -40
# parse the log to find which step failedPolling and log parsing.
# stream the job instead of asking about it
plp ci logs "$RUN" --job test -f
# machine-readable state, including every skip reason
plp ci status "$RUN" --json
# attach to the paused job and retry the failed step
plp ci debug "$RUN" --from 6Streaming, structured state and retry.
| Credential | Scope |
|---|---|
| Human login | Device code flow (RFC 8628). No password ever reaches the CLI. |
| Agent login | Federated OIDC, or a signed single-use assertion (RFC 7523) with a one-time jti. |
| Agent exec token | The intersection of the user's grants, the agent's ceiling and the scopes requested, never wider than any of the three. TTL at most 15 minutes. |
| Task grants | Bind one named action to one live run or job, issued for a single task rather than standing access. |
| ci-agent role | Runs and debugs its own jobs, and reads. No secrets, no OIDC token, no publishing and no approvals. |
| Human-only gates | Environment and fork approvals, agent administration, policy and secret administration stay with a person. |
An agent can inspect and repair a run, while scopes and human-only gates limit which changes it can make. The boundary is enforced by the token, not by convention.
An agent cannot trigger a run on the default branch.
Agent-authored pull requests open as drafts.
A fix needs a clean verification before merge.
Secret access during a debug session is disabled by default.
One writer per session. Other controllers read state and audit history; mutations are recorded.
Yes. The dashboard uses the same authenticated API. There are no operations that require the UI when the credential has the required scope.
A paused session appears in GET /api/v1/debug/sessions and in the run's event stream. An agent can subscribe to the event instead of polling a log.
One gets the writer lease. The other attaches read-only and can still read state and audit history. Concurrent mutations are refused rather than raced.
Not with the ci-agent role. Its token excludes secrets, OIDC tokens, publishing and approvals entirely. Reading a secret during a debug session needs a human-held credential.
The API is plain HTTP with JSON and NDJSON, and the CLI adds --json to every read command. Use the interface that fits your runtime; no specific client library is required.
plp ci is a thin client over the same hosted API. Set PRELOOP_TOKEN for unattended use, or log in with a device code.
Yes. A retry can start from any requested step, including the failed step. The selected start point and the session history remain visible to the caller.
Use the API to submit a run and stream its state. Add pause, retry and attestation when the workflow needs them.