> For the index of every page in Orbital's docs, read https://docs.beta.runorbital.dev/llms.txt.

# Ticket to merge

> A complete workflow that takes a ticket to a merged pull request, like the shipped delivery sub workflows

In this example you run the complete delivery workflow. It implements a ticket, publishes a pull request, watches it, repairs what CI and reviewers find, and merges. It imports two sub workflows and ships twelve prompt files.

About ten minutes to set up, including reading the prompts. The run then works until the pull request merges or closes.

```dot title="ticket.dot"
digraph implement_ticket {
  graph [version="1", entry="create_worktree", inputs="work", description="Deliver one ticket through reviewed implementation and a merged PR"]

  create_worktree [shape="folder", action="create"]
  implementation [import="subgraphs/implementation.dot"]
  delivery [import="subgraphs/pr-delivery.dot"]
  complete_ticket [prompt_file="prompts/complete-ticket.md", outputs="completion_summary:text"]
  cleanup_merged [shape="folder", action="remove"]
  cleanup_closed [shape="folder", action="remove"]
  complete [shape="Msquare", outcome="success"]
  closed [shape="Msquare", outcome="failed", label="PR closed without merging"]
  worktree_retained [shape="Msquare", outcome="success", label="Delivered; worktree retained for the unpushed commits worktree.status names"]
  cleanup_pending [shape="Msquare", outcome="failed", label="Worktree retained to preserve local work"]

  create_worktree -> implementation
  implementation -> delivery [exit="approved"]
  delivery -> complete_ticket [exit="merged"]
  delivery -> cleanup_closed [exit="closed"]
  complete_ticket -> cleanup_merged
  cleanup_merged -> complete [condition="worktree.clean == true", weight="1"]
  cleanup_merged -> worktree_retained
  cleanup_closed -> closed [condition="worktree.clean == true", weight="1"]
  cleanup_closed -> cleanup_pending
}
```

![create_worktree → implementation → delivery → complete_ticket → cleanup. Delivery loops through PR observations and repairs until merged or closed. Cleanup retains unsafe worktrees.](/ticket.svg?v=1780408f93)

## Before you start

You need:

- a project whose primary folder is the Git repository the ticket changes, with a GitHub remote you can push to, because the run works in a worktree and opens a pull request. An empty practice repository is not enough for this workflow;
- a GitHub token and a signed-in harness. The agent needs access to the repository and the tracker, and permission to publish and repair the pull request;
- the workflow: [download the archive](/ticket.zip).

Read all prompts before running. They are listed under [complete source](#complete-source).

:::caution
Like the shipped workflows, the publish step sets `auto_merge="squash"`, so Orbital turns on auto-merge for the pull request. Where your branch rules require no review, the pull request merges as soon as its required checks pass. Delete that attribute from `subgraphs/pr-delivery.dot` to merge by hand. See [turn auto-merge off](/projects/worktrees-and-delivery/#turn-auto-merge-off).
:::

## 1. Add the workflow

1. Unpack the archive into your workflow library, `~/.orbital/workflows/`. Keep every relative path.

2. Check it:

   ```sh
   orbital validate ~/.orbital/workflows/ticket.dot
   ```

![The workflow editor showing a pull-request workflow whose conditioned edges loop back to earlier steps.](/screenshots/workflow-editor-loop.webp?v=4dacb0ba6a)

*Conditioned edges loop back until the pull request merges or closes.*

## 2. Start the run

Choose **New task**, pick the project and choose the `ticket` workflow. Set work to the ticket URL and write the delivery goal.

## What you get

Implementation plans, implements and reviews until approved. Delivery publishes the pull request, reads its state, handles CI, conflicts and reviews, and waits at a human gate while the pull request waits for review or merge. The waiting run shows a clock and "Waiting: The pull request is waiting for review or merge", takes no run slot, and carries on by itself when the pull request changes. An approved pull request that is not merged yet returns to the gate.

| The pull request | Result |
| --- | --- |
| Merges | The run completes the ticket, cleans up and ends Succeeded. |
| Merges, but the worktree still holds commits the remote never saw | The run ends Succeeded and keeps the worktree. `worktree.status` names those commits. |
| Closes without merging | The run cleans up and ends Failed, labelled "PR closed without merging". |
| Closes, and cleanup would lose work | The run ends Failed and keeps the worktree. |

## The review loop has no repair budget

`subgraphs/implementation.dot` loops `local_review → plan_review → implement_review → local_review` until the review passes. It has no `repair_budget`, because it mirrors the shipped `implementation` sub workflow, which has none. The workflow's `max_visits` bounds the loop instead. It defaults to 200 agent visits for the whole run, and when they are spent the run ends Failed.

For a tighter bound, put a `repair_budget` pair on the edges out of `local_review`:

1. Give the reject edge `repair_budget="review"` and `repair_round="retry"`.
2. Add an edge to a failed terminal with the same condition and budget, `repair_round="exhausted"` and a different weight.
3. Give the pass edge `repair_round="reset"` with the same budget.

After five rejected rounds the run then takes the exhausted edge. [Error handling](/reference/error-handling/#bounded-repair) describes the rules, and [outer loop over an epic](/examples/workflows/epic/) uses such a budget.

## Complete source

Every DOT file below is a complete workflow, and the archive holds the same files. The Markdown files are prompts the workflows name, not separate workflows. `ticket.dot` is at the top of this page. [Download ticket.dot](/examples/ticket/ticket.dot) on its own.

### subgraphs/implementation.dot

```dot title="subgraphs/implementation.dot"
digraph implementation {
  graph [version="1", entry="plan", inputs="work", description="Plan, implement and locally review one work scope"]

  plan [prompt_file="../prompts/implementation/plan.md", outputs="implementation_plan:text"]
  implement [prompt_file="../prompts/implementation/implement.md", outputs="implementation_summary:text"]
  local_review [prompt_file="../prompts/implementation/review.md", outputs="review_verdict:choice, review_findings:json"]
  plan_review [prompt_file="../prompts/implementation/plan-review.md", outputs="implementation_plan:text"]
  implement_review [prompt_file="../prompts/implementation/implement-review.md", outputs="implementation_summary:text"]
  approved [shape="Msquare", outcome="success"]

  plan -> implement
  implement -> local_review
  local_review -> plan_review [condition="review_verdict == 'reject'", weight="2"]
  local_review -> approved [condition="review_verdict == 'pass'", weight="1"]
  plan_review -> implement_review
  implement_review -> local_review
}
```

[Download implementation.dot](/examples/ticket/subgraphs/implementation.dot)

### subgraphs/pr-delivery.dot

```dot title="subgraphs/pr-delivery.dot"
digraph pr_delivery {
  graph [version="1", entry="publish", inputs="work", description="Publish a change, then wait on its review and publish each repair until the PR is merged or closed"]

  publish [prompt_file="../prompts/pr-delivery/publish.md", outputs="publication_summary:text", auto_merge="squash"]
  probe_pr [shape="parallelogram", repeat_safety="idempotent", probes="pr,threads"]
  address_reviews [prompt_file="../prompts/pr-delivery/address-reviews.md", outputs="repair_summary:text, repair_result:choice"]
  fix_ci [prompt_file="../prompts/pr-delivery/fix-ci.md", outputs="repair_summary:text, repair_result:choice"]
  resolve_conflicts [prompt_file="../prompts/pr-delivery/resolve-conflicts.md", outputs="repair_summary:text, repair_result:choice"]
  review_repairs [prompt_file="../prompts/pr-delivery/review-repairs.md", outputs="review_verdict:choice, review_findings:json"]
  revise_repairs [prompt_file="../prompts/pr-delivery/revise-repairs.md", outputs="repair_summary:text"]
  await_review [shape="hexagon", label="The pull request is waiting for review or merge"]
  merged [shape="Msquare", outcome="success"]
  closed [shape="Msquare", outcome="failed"]

  publish -> probe_pr
  probe_pr -> closed [condition="outcome == 'failed'", weight="7"]
  probe_pr -> merged [condition="pr.state == 'MERGED'", weight="6"]
  probe_pr -> closed [condition="pr.state == 'CLOSED'", weight="5"]
  probe_pr -> resolve_conflicts [condition="pr.state == 'CONFLICTS'", weight="4"]
  probe_pr -> fix_ci [condition="pr.state == 'CI_FAILED'", weight="3"]
  probe_pr -> address_reviews [condition="pr.state == 'CHANGES_REQUIRED'", weight="2"]
  probe_pr -> await_review
  await_review -> probe_pr
  address_reviews -> review_repairs [condition="repair_result == 'changed'", weight="2"]
  address_reviews -> publish [condition="repair_result == 'unchanged'", weight="1"]
  fix_ci -> review_repairs [condition="repair_result == 'changed'", weight="2"]
  fix_ci -> publish [condition="repair_result == 'unchanged'", weight="1"]
  resolve_conflicts -> review_repairs [condition="repair_result == 'changed'", weight="2"]
  resolve_conflicts -> publish [condition="repair_result == 'unchanged'", weight="1"]
  review_repairs -> revise_repairs [condition="review_verdict == 'reject'", weight="2"]
  review_repairs -> publish [condition="review_verdict == 'pass'", weight="1"]
  revise_repairs -> publish
}
```

[Download pr-delivery.dot](/examples/ticket/subgraphs/pr-delivery.dot)

### prompts/complete-ticket.md

```markdown title="prompts/complete-ticket.md"
Discover and use relevant installed skills for completing tickets and communicating delivery results.

Ticket:

{{ context.work }}

Publication summary:

{{ context.publication_summary }}

Confirm from the remote that the PR delivering this work has merged. Verify that the merged change satisfies the ticket and goal. Identify any ticket-related changes that remain unpublished before marking the work complete.

Mark the supplied ticket done using its tracker’s workflow.

If the ticket is already complete, verify the recorded delivery evidence and avoid duplicate updates. Leave parent, sibling and unrelated tickets unchanged.

This step may update the supplied ticket's completion record. Leave repository files, commits, branches and pull requests unchanged.

Return `completion_summary` with the ticket’s confirmed status, merged PR link and delivery evidence.

A follow-up step cleans up the worktree.
```

[Download complete-ticket.md](/examples/ticket/prompts/complete-ticket.md)

### prompts/implementation/implement-review.md

```markdown title="prompts/implementation/implement-review.md"
Discover and use relevant installed skills for implementation and verification.

Work scope:

{{ context.work }}

Revised implementation plan:

{{ context.implementation_plan }}

Previous implementation summary:

{{ context.implementation_summary }}

Review findings:

{{ context.review_findings | dump }}

Inspect the current changes and applicable repository instructions. Apply the revised plan and address every blocking finding. Preserve correct work and remove changes the plan identifies as outside scope.

Verify each correction and run the relevant checks for the complete change. Close all remaining defects, unmet requirements or verification gaps in the work scope and the plan. Address all required changes from the plan and review. Create or update local commits using the repository’s conventions.

This step may change repository files, run checks and create local commits. Later steps own local review and publication. The caller owns any tracker updates.

Return an updated `implementation_summary` that replaces the previous one. Describe the change as it stands now, then how this round corrected and verified each finding above, then anything still unresolved, stated once. Leave out earlier rounds, their findings and any dispute already settled: later steps read only this summary and the code, so history in it only makes every later prompt longer.
```

[Download implement-review.md](/examples/ticket/prompts/implementation/implement-review.md)

### prompts/implementation/implement.md

```markdown title="prompts/implementation/implement.md"
Discover and use relevant installed skills for implementation and verification.

Work scope:

{{ context.work }}

Implementation plan:

{{ context.implementation_plan }}

Implement the planned change in the prepared worktree. If the work scope names an open pull request, check out its branch first and build on it, so publication updates that pull request instead of opening another. Follow applicable repository instructions and preserve unrelated work.

Satisfy every requirement in the work scope and goal. If the code reveals an error in the plan, make the necessary adjustment within that scope and explain it.

Run the relevant checks. Record what each check establishes and any failures or verification gaps. Create or update local commits using the repository’s conventions.

This step may change repository files, run checks and create local commits. Later steps own publication. The caller owns any tracker updates.

Return `implementation_summary` with the changes, verification evidence, deviations from the plan and any unmet requirements.
```

[Download implement.md](/examples/ticket/prompts/implementation/implement.md)

### prompts/implementation/plan-review.md

```markdown title="prompts/implementation/plan-review.md"
Discover and use relevant installed skills for planning and communicating the plan.

Work scope:

{{ context.work }}

Previous implementation plan:

{{ context.implementation_plan }}

Implementation summary:

{{ context.implementation_summary }}

Review findings:

{{ context.review_findings | dump }}

Read the work scope, applicable repository instructions and current changes. Investigate each blocking finding against the code and available evidence.

Revise the implementation plan to address every blocking finding. Specify each correction and how it will be verified. Preserve work that already satisfies the requirements and identify any changes that must be removed or revised.

Keep the revised plan complete enough for implementation. Cover the work scope and goal without adding unrelated work. State assumptions and material risks.

Return the revised plan as `implementation_plan`. Leave repository files and tracker records unchanged.

Later steps will implement and publish the changes. The caller owns any tracker updates.
```

[Download plan-review.md](/examples/ticket/prompts/implementation/plan-review.md)

### prompts/implementation/plan.md

```markdown title="prompts/implementation/plan.md"
Discover and use relevant installed skills for planning and communicating the plan.

Work scope:

{{ context.work }}

Read the supplied work scope, relevant linked context and applicable repository instructions. Inspect the affected code and tests. For ticket-based work, read the identified ticket.

Plan the changes needed to satisfy the work scope. Use the goal to guide decisions without expanding that scope. Choose the smallest implementation that meets every requirement.

Explain the required behaviour, affected components, implementation order and how each acceptance criterion will be verified. Ground decisions in the inspected code.

Return the plan as `implementation_plan`. Leave repository files and tracker records unchanged.

Later steps will implement and publish the changes.
```

[Download plan.md](/examples/ticket/prompts/implementation/plan.md)

### prompts/implementation/review.md

```markdown title="prompts/implementation/review.md"
Discover and use relevant installed skills for code review and communicating findings.

Work scope:

{{ context.work }}

Implementation plan:

{{ context.implementation_plan }}

Implementation summary:

{{ context.implementation_summary }}

Review the current change against the work scope, goal, plan and applicable repository instructions. Inspect the complete branch diff against its target, including uncommitted changes, affected code and relevant tests.

Review only requirements and defects that can be verified through automated checks or code inspection. For each rejection, identify the requirement, concrete evidence, required correction and machine-checkable completion condition.

Use the work scope, plan and summary as context. Verify their claims against the code and available evidence.

Reject unmet requirements, correctness or security defects, violations of mandatory repository rules, missing verification of required behaviour and changes made which are outside the work scope. Treat preferences as non-blocking unless repository instructions require them.

Human reviews, manual acceptance, visual approval and user sign-off are non-blocking. Report them as outstanding without requiring their completion to pass.

Compare each finding with previous reviews and attempted corrections. If the same finding returns without new evidence or a materially different actionable correction, recognise that the review is looping. Do not reject again for that finding. Report the unresolved concern and explain why another repair pass would not advance it.

For each blocking finding, identify the requirement or defect, supporting evidence and the correction needed.

This step is read-only. Leave files, commits, branches, pull requests and tracker records unchanged.

Return `review_verdict` as `reject` only when actionable, machine-checkable blocking findings remain. Otherwise return `pass`. Keep outstanding human or manual checks and concerns excluded. Return `review_findings` as an array containing those findings, or an empty array when the review passes.
```

[Download review.md](/examples/ticket/prompts/implementation/review.md)

### prompts/pr-delivery/address-reviews.md

```markdown title="prompts/pr-delivery/address-reviews.md"
Discover and use relevant installed skills for addressing pull request feedback, verification and communicating with reviewers.

Work scope:

{{ context.work }}

Publication summary:

{{ context.publication_summary }}

The review threads still open, one repository at a time:

{% for name, folder in run.folders %}{% if context[name].threads.open %}### {{ name }}

{{ context[name].threads.open }}

{% endif %}{% endfor %}
Inspect the current PR, its published head, review decisions and unresolved threads. Read the affected code and applicable repository instructions.

Address feedback within the work scope and goal. Make the required local changes, verify them and create or update local commits using the repository’s conventions. Preserve unrelated work.

For feedback already satisfied by the published change, reply with supporting evidence and resolve the thread. For feedback requiring a new local change, keep the thread unresolved until that correction is published and verified. Check existing replies before posting to avoid duplicates.

Explain with evidence when a requested change is unnecessary or outside scope.

If the PR has merged or closed, report that state without modifying it.

This step may change repository files, run checks, create local commits, reply to reviews and resolve addressed threads. Later steps own local review and publication. The caller owns any tracker updates.

Return `repair_summary` with the feedback addressed, changes, verification evidence, published corrections confirmed, and threads awaiting publication or further resolution.

Return `repair_result` as `changed` when this step changed the local branch or its files, otherwise `unchanged`. A changed repair is reviewed against its reason before it is published. An unchanged one goes straight to publication.
```

[Download address-reviews.md](/examples/ticket/prompts/pr-delivery/address-reviews.md)

### prompts/pr-delivery/fix-ci.md

```markdown title="prompts/pr-delivery/fix-ci.md"
Discover and use relevant installed skills for diagnosing CI failures, implementing corrections and verification.

Work scope:

{{ context.work }}

Publication summary:

{{ context.publication_summary }}

Get the PR's required CI checks green. Inspect the current PR, published head and failing checks. Read their logs, affected code and applicable repository instructions. Confirm the failures belong to the current published change.

Identify the cause of each failure. Use focused local checks where possible and compare against the target branch when needed to distinguish defects in this change from existing failures or external problems.

Correct failures within the work scope and goal. Preserve unrelated work. Rerun a failed remote check when the evidence supports a transient failure; do not rerun checks repeatedly without investigating.

Verify the corrections and create or update local commits using the repository’s conventions.

If the PR has merged or closed, report that state without modifying it.

This step may change repository files, run checks, rerun remote CI and create local commits. Later steps own local review and publication. The caller owns any tracker updates.

Return `repair_summary` with the failed checks, diagnosis, corrections, verification results and anything still unresolved.

Return `repair_result` as `changed` when this step changed the local branch or its files, otherwise `unchanged`. A changed repair is reviewed against its reason before it is published. An unchanged one goes straight to publication.
```

[Download fix-ci.md](/examples/ticket/prompts/pr-delivery/fix-ci.md)

### prompts/pr-delivery/publish.md

```markdown title="prompts/pr-delivery/publish.md"
Discover and use relevant installed skills for publishing pull requests and communicating the change.

Work scope:

{{ context.work }}

Inspect the prepared worktree, current branch and any associated pull request.

Push the intended local commits. Update the existing open PR, or create one against the repository’s intended target branch. Describe the complete change, its relationship to the work scope and the verification performed. When the commit messages record review decisions, state each decision and its reason in the description. Keep an existing `Open items` section, and remove an item only when the published change resolves it.

Use ticket references only when the work scope identifies an existing ticket. When it does, write `Closes #N` in the description if the change completes that ticket, and `Part of #N` if it only advances it.

If the associated PR is already merged and the branch contains follow up changes, open a new PR.

Confirm the PR URL from the remote. If publication fails, inspect the current remote state before retrying. Preserve local work and avoid creating duplicate PRs.

This step owns publication. Leave implementation files and tracker records unchanged. Later steps handle PR feedback, CI and conflicts. The caller owns any tracker updates.

Return `publication_summary` with the PR URL, confirmed remote state and published commits.
```

[Download publish.md](/examples/ticket/prompts/pr-delivery/publish.md)

### prompts/pr-delivery/resolve-conflicts.md

```markdown title="prompts/pr-delivery/resolve-conflicts.md"
Discover and use relevant installed skills for resolving merge conflicts and verifying the resulting change.

Work scope:

{{ context.work }}

Publication summary:

{{ context.publication_summary }}

Make the PR mergeable by resolving its conflicts with the target branch. Inspect the current PR, its target branch, published head and prepared worktree. Read applicable repository instructions.

If the PR has merged or closed, report that state without modifying it.

Fetch the latest target branch and integrate it using the repository’s conventions. Prefer rebase. Resolve conflicts by understanding both changes. Preserve the required behaviour of the work scope, relevant target-branch changes and unrelated work.

Verify that the local branch integrates cleanly with the fetched target. Run the relevant checks and create or update local commits using the repository’s conventions.

If the conflict has already disappeared, report the evidence without introducing unnecessary changes.

This step may fetch remote changes, merge or rebase locally, resolve conflicts, run checks and create local commits. Later steps own local review and publication. The caller owns any tracker updates.

Return `repair_summary` with the target revision, conflicts resolved, resulting changes, verification evidence and anything still unresolved.

Return `repair_result` as `changed` when this step changed the local branch or its files, otherwise `unchanged`. A changed repair is reviewed against its reason before it is published. An unchanged one goes straight to publication.
```

[Download resolve-conflicts.md](/examples/ticket/prompts/pr-delivery/resolve-conflicts.md)

### prompts/pr-delivery/review-repairs.md

```markdown title="prompts/pr-delivery/review-repairs.md"
Discover and use relevant installed skills for code review and communicating findings.

Publication summary:

{{ context.publication_summary }}

Repair summary:

{{ context.repair_summary }}

The published head each repair started from, and the reason for the repair, one repository at a time:

{% for name, folder in run.folders %}### {{ name }}

Started from: {{ context[name].pr.head }}
Reason: {{ context[name].pr.state }}
{% if context[name].pr.state == "CHANGES_REQUIRED" %}
The review threads the repair answers:

{{ context[name].threads.open }}
{% endif %}
{% endfor %}
A `CI_FAILED` repair answers the failing checks on the pull request. A `CONFLICTS` repair answers the merge conflict with the target branch. A `CHANGES_REQUIRED` repair answers the review threads above. A repository whose reason is `WAITING` needed no repair.

Review only what the repair step changed. Inspect the diff from the head it started from to the current local head, including uncommitted changes. When the repair rebased onto the target branch, compare the change before and after the rebase, for example with `git range-diff`, and review only the resolution. Read the failing checks, the conflict or the review threads to judge the repair against its reason.

The complete change passed review before it was published. Do not review it again against the ticket, and do not search for defects the repair did not introduce.

Verify the corrections and verification claims in the repair summary against the code and available evidence.

Reject a repair only when it is wrong, incomplete for its reason, breaks a mandatory repository rule, or changes things outside its reason. Treat preferences as non-blocking unless repository instructions require them.

This step is read-only. Leave files, commits, branches, pull requests and tracker records unchanged.

Return `review_verdict` as `reject` when blocking findings remain, otherwise `pass`. Return `review_findings` as an array of blocking findings, each with `requirement`, `evidence` and `correction`. A pass returns an empty array.

A pass publishes the repair. A reject goes to one revision step, which fixes what it can, records the rest as open items in the pull request description and publishes without another review.
```

[Download review-repairs.md](/examples/ticket/prompts/pr-delivery/review-repairs.md)

### prompts/pr-delivery/revise-repairs.md

```markdown title="prompts/pr-delivery/revise-repairs.md"
Discover and use relevant installed skills for implementation and verification.

Work scope:

{{ context.work }}

Publication summary:

{{ context.publication_summary }}

Previous repair summary:

{{ context.repair_summary }}

Review findings:

{{ context.review_findings | dump }}

Inspect the current changes and applicable repository instructions. Address each blocking finding you can fix within this step's permissions. Preserve correct work and remove changes identified as outside the repair's reason.

Verify each correction and run the relevant checks for the complete change. Create or update local commits using the repository’s conventions.

Some findings cannot be fixed here: they need a tracker change, a decision from a person, or a change this step may not make. Record each one, and each finding you judged wrong, as an open item in the pull request description. Keep the rest of the description, add the items under an `Open items` heading, and state for each the finding and why it was not fixed here. Do not repeat an item already listed.

This step may change repository files, run checks, create local commits and edit the pull request description. Leave the PR's commits, reviews and tracker records otherwise unchanged.

Return an updated `repair_summary` that replaces the previous one. Describe the repair as it stands now, then how this step corrected and verified each finding above, then the open items it recorded, stated once. Leave out earlier rounds and any dispute already settled: later steps read only this summary and the code, so history in it only makes every later prompt longer.

The next step publishes these changes without another review and continues monitoring the PR.
```

[Download revise-repairs.md](/examples/ticket/prompts/pr-delivery/revise-repairs.md)

## Related

This is the workflow the shorter examples build up to.

- [One-shot implementation](/examples/workflows/one-shot-implementation/): compare it to see what waiting on a pull request adds
- [Outer loop over an epic](/examples/workflows/epic/): run this kind of delivery once per sub ticket
- [Add gates and waits](/workflows/gates-and-waits/): how the run waits on the pull request
- [Worktrees and delivery](/projects/worktrees-and-delivery/): how the pull request is published and merged
