Skip to main content
Preloop gives coding agents a local CI loop without granting them GitHub push power. An agent can inspect a workflow’s job graph, run selected check jobs, stream NDJSON events, read logs, and repair a paused job. Publishing a branch or opening a pull request stays with the person who owns the change.

Prepare the engine yourself

Install the CLI and matching runner/runtime, then run preloop init yourself. The initialization flow stores the GitHub credential; do not ask an agent to handle that credential. See Control plane installation for host setup. The CLI uses PRELOOP_URL, defaulting to http://127.0.0.1:9090. For native API calls it checks PRELOOP_TOKEN, then PRELOOP_SYSTEM_TOKEN, then the managed engine credential.

Run checks before a push

1

Commit and inspect the graph

Commit the change before running checks when possible. preloop run snapshots the working tree, including uncommitted changes, but a commit makes the tree that the agent tests explicit.Inspect the expanded job graph without executing it:
Each job entry contains its ID, name, runner selection, needs, matrix data, and a step count. The plan does not include step commands, environment:, permissions:, or secret reads, so read the workflow before selecting jobs.
2

Select only check jobs

Choose tests, lint, builds, and a gate job that collects them. Skip jobs that deploy, publish, release, push, or read secrets other than GITHUB_TOKEN. Treat environment:, secrets., deploy, and pages as reasons to inspect a job carefully. Also skip jobs whose effective GITHUB_TOKEN permissions include write or write-all.--job includes that job’s needs: closure. Inspect every job in the closure before running it.
3

Run each selected job non-interactively

--base supplies the branch used for branches: filters and the base used to calculate paths: changes. A local pull_request run otherwise does not invent pull-request fields such as a number, labels, or review state. Pass --payload when a condition reads those fields; otherwise a skipped step can make an incomplete check look green. Use --event push for workflows that only trigger on pushes.
4

Inspect failures before pushing

Read a failed job’s output:
For a live debug session, submit with --debug. A non-terminal invocation does not wait for an interactive prompt; inspect the paused session and issue a verdict from another process:
For a completed failure that only needs a shell, use --preserve-on-failure and then preloop shell on the host that owns the VM. After a fix, commit it and submit a fresh run. preloop rerun RUN_ID --failed replays the originally captured tree, so it is useful for a flaky failure and does not include a later source fix.
The default checkout snapshot retention is 1,800 seconds. The in-place rerun window is 30 days when enabled by the control plane. A local check is a pre-push guard, not the record of the pull request’s CI run.

Consume NDJSON events

The native event feed requires a bearer token and returns application/x-ndjson:
The response starts with a snapshot of the run’s current statuses and persisted events, then stays open for live events until the run is terminal. A stalled connection closes after five minutes. Reconnect and de-duplicate lines because a new connection receives a fresh snapshot. Each line is a JSON object with a type field: Run and job statuses are queued, pending, in_progress, success, failure, skipped, or cancelled. For a point-in-time response, use GET /api/v1/runs/RUN_ID or preloop status RUN_ID --json.

Pre-push CI gate

An interactive preloop run offers to install the repository’s advisory pre-push hook. The hook holds a push of the checked-out branch’s current commit while it runs Preloop CI. Tags and deletions pass; a push of another branch passes with a warning because the hook can only validate the checked-out tree. The hook never performs the Git push itself. The hook also:
  • bypasses the gate when any pushed commit message contains [skip ci];
  • caches a verdict by remote, engine endpoint, and commit, then checks the recorded run’s live terminal status before reusing it;
  • fails open with a warning only when the Preloop engine is unreachable, identified by the CLI’s PRELOOP_UNREACHABLE marker;
  • preserves an existing hook as pre-push.preloop-prev, chains it first, and respects Git’s core.hooksPath.
This is a per-machine advisory gate. A push from another machine or the GitHub UI does not run it.

Push-back and auto-PR

Agents should not use --push or --create-pr. These are the human-controlled publish paths. For reference, push-back ends at:
The client first pushes the tested commit with local Git credentials. The server verifies the tested tree, reuses or creates the branch PR, and reports Check Runs. The endpoint is idempotent; a repeated preloop push RUN_ID is safe. A separate auto-PR path runs only for successful webhook-delivered push runs. Configure it under [github.pr] or with environment variables: The head commit message can override policy: [no-pr] always skips, [draft] requests a draft, and [pr] forces creation even with auto = never. Labels are read from the head commit only. Auto-PR needs pull_requests: write; a missing credential leaves the workflow result intact and skips PR creation.

Drive a debug session over HTTP

The native session API lets an agent control a paused job with its bearer token: Acquire a lease with a caller identity, then send an operation with a request ID and the version observed by the lease:
Use retry_from with a zero-based step_index, or use continue and abort. Repeating a request ID returns its original result; a stale expected_version is rejected.

DAP prompt for an agent

The built-in client is preloop dap RUN_ID. The prompt below matches the recorded omp demo and uses submit.sh plus the dapctl reference client.
For normal loops, keep the GitHub credential and publish decisions outside the agent’s control.