Skip to main content
Submit-driven CI is useful when a GitHub webhook cannot reach the control plane, when a branch needs a check before its first push, or when you want to test a working-tree snapshot before opening a pull request. The run starts from the CLI; GitHub access is still needed for operations such as loading actions, checking out private repositories, publishing checks, and creating a pull request.

Before you start

Use a feature branch with a GitHub origin. Push-back uses your local Git credentials; the control plane never receives permission to push. The branch must be a real refs/heads/... branch, and push-back refuses the repository’s default branch. For reliable Check Run reporting, configure a GitHub App with checks: write. Creating a pull request also needs pull_requests: write. Configure PRELOOP_PUBLIC_URL with an address that GitHub viewers can reach if Check Runs should link back to the run page. A local-only URL leaves the check summary without a public details link.

Choose a command

--create-pr implies --push. A plain preloop run does not request push-back, although workflow loading and job actions can still use GitHub or other network services.

Submit and publish

1

Submit from the feature branch

Run the workflow from the checkout that owns the branch:
The CLI prints a run ID. A clean checkout records the current commit. A dirty checkout is snapshotted at submission, so CI tests the uncommitted tree as well. The dirty-tree snapshot does not change your index or working tree.
2

Let the run reach a terminal result

The run executes without a webhook trigger. Follow it with preloop status RUN_ID or inspect output with preloop logs RUN_ID --job JOB_ID.For a non-interactive submit, use --detach and save the printed run ID:
Detached submission returns after acceptance. It does not perform the local Git push after the run finishes; publish later from the submitting checkout with preloop push RUN_ID.
3

Publish the tested tree

When the run is terminal, the CLI pushes the exact tested commit to origin and calls the control plane’s publish endpoint:
The local Git operation is a branch creation, an already-equal update, or a fast-forward. A diverged remote branch is refused rather than force-pushed. The server then verifies the pushed commit’s tree, reuses the branch’s pull request, creates one when requested, and reports any missing Check Runs.

Dirty working trees

For a dirty --push run, a successful result lets the CLI materialize a commit whose tree exactly matches the snapshot tested by CI. The commit is parented on the submitted base commit and uses your local Git identity. If the working tree changed after submission, materialization stops and the CLI asks for a new submission. A failed dirty-tree run is not materialized or pushed. On a terminal, a dirty push without --create-pr can ask whether to open a PR. The explicit --create-pr flag takes precedence. Otherwise the head commit’s message labels are honored: [no-pr] suppresses creation, while [pr] or [draft] requests creation; a non-interactive explicit --push pushes without opening a new PR unless a label requests one. Clean-tree push-back can publish red Check Runs after a failed run. This records the tested result without pretending that the run passed. Dirty-tree push-back only materializes after success.

Run IDs and retries

The submit output, preloop status, and error messages expose the run ID. Use the explicit ID when replaying a publish:
The CLI retries transient publish failures after 1 minute, 5 minutes, and 15 minutes. Pressing Ctrl-C stops the wait; running preloop push RUN_ID later resumes the same idempotent operation. The server does not retry its own GitHub reads: a transport or 5xx failure is returned as a gateway error and the push-back is recorded as blocked with the upstream message, while other failures are returned as client errors.

Checks on the pull request

Check Runs move through queued, in_progress, and completed with the job conclusion. Push-back creates missing checks against the effective published commit, including the materialized commit for a dirty-tree run. The push webhook echo for that same published commit is recognized, so the workflow is not run a second time merely because push-back published it. The control plane verifies the tested tree before publishing checks. If the GitHub branch points at a different tree, the publish is blocked. The server also refuses the default branch as a push-back target; keep the default branch on the normal webhook flow.

Troubleshooting

Verify the branch and PR after a successful publish:
See GitHub App setup, GitHub tokens, and the CLI reference for credential and command details.