Skip to content

Automated Issue Implementation preset

Editions: OSS, Cloud, Enterprise. Unless stated otherwise, everything on this page ships in OSS.

Turns a tracker issue into a working change. The agent reads the issue, implements it, adds tests, runs the project's checks, and commits to the checkout it was given. Preloop pushes the branch and opens the pull request after the run.

The preset ships as backend/presets/011-automated-issue-implementation.yaml (slug automated-issue-implementation).

What the agent does and what the flow does

Step Owner
Decide which issues qualify flow trigger (trigger_config)
Read the issue, plan, implement, test, lint agent
Commit to the local checkout agent
Write /workspace/result.json agent
Verify the final commit against the trusted test profile flow (runner-controlled verifier)
Push the branch and open the pull request flow (git_clone_config.create_pull_request)

The preset separates implementation from publication. Its MCP toolset is get_issue, get_pull_request, add_comment, update_comment, ask_user. Credential isolation additionally requires the opt-in isolated mode below. There is no approval tool: gating belongs to your deployment's policies, not to a preset prompt.

The verification gate

Asking the agent to test is a request; the gate makes it a contract. The preset ships with git_clone_config.verification.mode: "gate" and a trusted test profile: a versioned list of required checks that travels in the flow configuration, never inside the target repository, so the agent cannot narrow required checks or edit the profile inside its own PR. After the agent exits and commits, the flow re-runs the required checks itself and only pushes the branch and opens the pull request when they pass on the exact commit and tree being published.

The profile has three parts:

  • always: inexpensive hooks required on every change. The shipped profile uses two universal git checks (git diff --check over the published range, and a scan for committed conflict markers).
  • rules: changed-file patterns that pull in additional required checks (migration graph checks, frontend component tests, API contract checks, broader suites for shared interfaces). Each rule carries the reason it exists, and the reasons are recorded with the verification evidence.
  • unknown_default: checks required for every changed path without a matching rule. It is never an empty list. The shipped profile refuses publication with a message that says what to configure: a runnable repository profile is required before strict verification is enabled on a live flow.

Customize the profile per repository:

git_clone_config:
  verification:
    mode: gate
    gate_budget_seconds: 3600
    profile:
      version: v1
      profile_id: my-repo
      always:
        - id: git-diff-check
          command: 'git diff --check "$PRELOOP_VERIFY_BASE...$PRELOOP_VERIFY_HEAD"'
          reason: whitespace and conflict markers in the published range
          scope: shared
      rules:
        - id: backend
          description: Python changes run the focused backend suite
          path_globs: ["backend/**"]
          commands:
            - id: backend-tests
              command: pytest tests/backend -q
              reason: regression protection for changed code
              scope: backend
              timeout_seconds: 900
        - id: migration
          description: Database migrations must keep one head
          path_globs: ["**/alembic/versions/**"]
          commands:
            - id: alembic-heads
              command: alembic heads
              reason: a branching migration graph breaks upgrades
              scope: migration
      unknown_default:
        - id: fast-tests
          command: pytest -q -x
          reason: unknown impact uses the conservative default
          scope: unknown

Check commands run in the repository working tree with PRELOOP_DISABLE_TELEMETRY=true and a PRELOOP_VERIFY_BASE / PRELOOP_VERIFY_HEAD range contract, so a check can scope itself to the published diff. Legacy sandbox checks inherit the agent's setup from git_clone_config.setup_commands. Isolated checks start in fresh runtimes and inherit neither that setup nor its writable caches. Each trusted command must find its dependencies in the pinned image or perform bounded setup itself. A database needed by a check must be available inside that check runtime; external services are unreachable because verifier network access is denied. A command that cannot start (exit 126/127), runtime failure or timeout is verification_blocked. A check that runs and exits nonzero is verification_failed; an operator profile can use an explicit prerequisite check returning 127 to distinguish an unavailable database from test failure. Both outcomes prevent publication and retain the commit and diagnostics.

What the agent sees and what the runner sees are two different report fields. The agent's result.json status says what it implemented; the legacy wrapper records a separate verification status from its gate. Its execution result is labeled source: sandbox_log, authenticated: false: log markers and sandbox files are observable diagnostics, not proof of origin. Isolated publication requires independently authenticated controller or runner-host verification before it can use these semantics to authorize a push. Anything the agent writes under verification itself is kept as verification_reported: a claim, not evidence. The full evidence (commands, exit codes, per-check logs, environment digest, profile version, commit and tree) lands in /workspace/evidence/verification/ inside the evidence pack, and the compact verdict is stored on the execution result.

A failed implementation report does not discard useful commits. On the ordinary post-execution path, commits that pass the configured push gate receive their configured PR/MR with the failure reason and an execution link. Already-pushed branches, including resumed branches, receive the PR or an updated failure notice without another push. Existing PR prose is preserved; the wrapper updates only its own notice. Automatically added issue references use Refs for failed or incomplete reports. The execution remains failed. This path requires the agent CLI to reach its post-execution script; it does not change nonzero CLI crash recovery or isolated controller publication authorization.

A denied publication fails the execution with the commits and evidence kept recoverable (the workspace snapshot and the verification_failed / verification_blocked failure categories tell you which kind of gap it was). Rejected work goes back to the agent; missing dependencies are an environment problem, visible as verification_blocked, and a runnable setup (see setup_commands in the architecture docs) is how you repair it.

Choosing which issues qualify

The prompt does not check labels. trigger_config does:

trigger_event_types:
  - issue_labeled
  - comment_created
trigger_config:
  filter_conditions:
    labels: ["agent-ready"]

Every issue_labeled event whose labels intersect the list starts a run. Matching reads label names from the webhook enrichment (extract_filter_fields) and also unwraps GitHub issue.labels[].name and GitLab labels[].title, so the example works on raw tracker payloads. Without a filter, every labeling event qualifies, which is rarely what you want on a busy repository.

To split issues between flows (and models) by tag, add labels_all, for example labels_all: ["complexity:low"] on one flow and ["complexity:medium"] on another. See Route by tags.

Resume on pull request comments

comment_created is only a trigger when the comment lands on a pull request this flow opened. The trigger service correlates the comment to the earlier execution and starts a new run with {{execution.resume_from}} set and the checkout already on the pull request's branch. On that path the agent reads the pull request with get_pull_request, addresses the review comments, and commits again on the same branch. It never opens a second pull request.

Comments on unrelated issues or pull requests do not start a cold run.

Durable review and CI continuation

New preset copies enable a durable PR subscription. Feedback uses the recorded PR binding independently of intake labels; the scheduler coalesces review and CI feedback into a new execution on the same branch. Existing saved flows opt in explicitly. Native Codex/OpenCode continuation uses an authorized, isolated checkpoint and explicit session ID. Missing state has a visible cold-handoff reason; corrupt or mismatched state fails restore.

See durable implementation feedback for configuration, provider gates, retention, runner capabilities and local tests.

Unclear issues

The agent asks a human only when a critical decision is missing and guessing wrong would waste the run. It uses ask_user, which surfaces the question in the console and in notifications. For anything smaller it picks the most reasonable option and records the choice under decisions in /workspace/result.json (and in its optional closing comment on the issue), so the reviewer sees what was assumed rather than having to infer it.

Result contract

{
  "status": "success",
  "summary": "...",
  "changes": ["backend/preloop/foo.py: keeps the retry hint"],
  "tests": ["pytest tests/services: 212 passed"],
  "decisions": ["chose the additive migration, no data rewrite"],
  "skipped": ["full backend suite: needs Postgres, not available"],
  "proposed_checks": ["pytest tests/test_retry.py::test_wrapped_retry_after"],
  "commits": ["550ca71c preserve retry_after_seconds when re-wrapping"],
  "pr_title": "Preserve retry_after_seconds when re-wrapping",
  "pr_body": "Keeps the retry hint on the wrapped error.\n\nCloses #212"
}

status is success when a change was committed, even if some checks could not run (those belong under skipped), and failure with a reason when the issue could not be implemented. Checks that cannot run are reported, never faked. proposed_checks is advisory: the agent can suggest checks the profile should require, but only the profile (owned by the flow, not the repository) decides what is required, and the gate re-runs those itself against the final commit before anything is published.

The flow opens the pull request after the agent exits. When pr_title and pr_body are present it uses those; otherwise it uses interpolated git_clone_config.pull_request_title / pull_request_description, then a flow-attribution fallback (execution link, and a **Commits:** list when more than one commit landed). New branches are named preloop/issue-{number}-{execution[:8]} when the trigger carries an issue number.

Timeout

The preset sets timeout_seconds: 5400. Reading an unfamiliar repository, writing tests, and running a suite regularly outlives the 3600s default, and a run killed at the finish line loses the commit.

Inspect a saved publication policy

The flow detail page shows the API's read-only effective_publication_policy. Existing customized flows remain unchanged: an absent or disabled verification policy is explicitly No verification gate. A legacy gate is Checks in agent sandbox, whose log evidence is not a trusted publication attestation. An isolated policy with a valid profile and pinned image is Isolated verification configured. Missing configuration is shown as blocked with specific blocker codes.

This is a description of saved configuration, not a pass receipt or deployment readiness check. Repository selection can still come from the trigger. Tracker permissions, the supported publication provider, isolation capabilities and checks on the final commit are validated by each execution. The console never labels a flow trusted merely because its saved policy requests isolation.

Isolated publication rollout and repair

Set git_clone_config.publication_mode: isolated explicitly and configure verification.image with an immutable image@sha256:<64 hexadecimal digits> toolchain reference. Bind a supported GitHub App installation tracker and repository-specific trusted checks. The generic preset intentionally refuses unknown non-documentation changes. Existing saved customized flows are not silently migrated. Review the effective-policy panel, then enable isolation for that saved flow after its profile and runtime prerequisites are ready. GitLab, PAT trackers and unsupported runtime capabilities must not be described as trusted isolated publication paths.

The controller freezes the Git bundle, confirms agent teardown, selects checks from its saved profile and executes each check in a fresh credential-free checkout. Both adapters supply the exact controller-pinned base/head range. The audit manifest records the base/head/tree and bundle digest, profile ID, version and content digest, pinned image and runtime. Check records include selection reasons, commands, exit codes, bounded diagnostic tails and duration. A scoped write credential is acquired only after successful verification.

The controller can reuse successful evidence within the same executor and execution when the exact bundle, base, profile content, pinned image and runtime adapter are unchanged. Reuse is marked on each check. This bounded in-memory cache contains only checks whose runtime teardown was confirmed; failures are never cached. Agent-written JSON and writable dependency caches cannot supply evidence. Changing any bound input runs fresh checks. Pinned images provide reusable dependency layers without sharing agent-writable state.

An unpublished feedback repair keeps its own workspace and native conversation as the next repair's source. For a currently reserved durable thread, the controller may recover the last publication binding from a bounded same-flow, same-thread execution ancestry. That receipt identifies the existing PR branch; it does not attest the failed repair or authorize its next commit. Each new execution must pass its current saved verification policy before publication. Legacy resumes without a durable binding still require explicit migration.

Local acceptance exercises real Git bundles and Docker runtimes with fake provider writes in backend/tests/services/test_publication_worker.py. Set PRELOOP_DISABLE_TELEMETRY=true and PRELOOP_PUBLICATION_DOCKER_IMAGE to a local toolchain image containing Python 3 and Git, then run that file with pytest. The fixtures cover failing checks, repair, exact-artifact rejection, narrow selection, missing database setup, credential exclusion, teardown and successful initial/resumed publication. Adapter tests cover Kubernetes API contracts; these tests do not establish a live deployment's network isolation or operator profile readiness.