Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

180 linesCodeBlameRaw
1---
2title: Work and the merge queue
3description: How the work service keeps issues, pull requests, checks and rulesets, coordinates sessions and claims, decides and lands a merge, and tests many changes at once in the merge queue.
4---
5
6import Aside from '../../../components/Aside.astro';
7import Diagram from '../../../components/Diagram.astro';
8
9`work` (`services/work`, Rust) keeps everything about a change that is not
10the code itself: issues, pull requests, comments, reviews, labels,
11milestones, rulesets, checks and commit statuses, CODEOWNERS, and the
12merge queue. Its database is `g1t-work`. The code lives in `repos`, and
13`work` asks `repos` whenever it needs it.
14
15## Issues and pull requests
16
17Issues and pull requests share one sequence of numbers per repository
18(the `counters` table), so `#12` names exactly one of them. A pull request
19records where its head is: a fork of its own, `pulls--<id>` in the git
20store, or a branch in the repository ([Git](/architecture/git/#pull-request-forks)).
21
22`work` reads every push from its event queue. A push to a pull request's
23head updates it: the new head, the files it changes, whether it is behind
24the base, and which other open pull requests change the same files, the
25overlap shown on each.
26
27When a pull request merges, its issue closes and records which pull
28request resolved it, and the issue's other open pull requests close as
29superseded ([How g1t works](/concepts/overview/#several-pull-requests-for-one-issue)).
30
31## Coordination
32
33Many agents and people can work on one repository at once. `work` keeps
34what lets them see each other, around the issue, which is the unit of
35work (`services/work/src/coordination/`):
36
37| Table | Holds | Module |
38| --- | --- | --- |
39| `sessions` | One run of someone's own harness (`claude_code`, `codex`, `cursor`, `copilot` or `other`), attached to an issue, a pull request and a branch | `sessions.rs` |
40| `session_entries` | What a session recorded: prompts, reasoning, tool calls, notes, each with an idempotency `key` | `sessions.rs` |
41| `claims` | An advisory, expiring "I'm working on #12" | `claims.rs` |
42| Issues' `blocked_by` | The issues that have to land first, refused if it would make a cycle | `dependencies.rs` |
43| `overlap_pairs` | Pairs of open pull requests changing the same files, announced once per pair | `overlaps.rs` |
44
45<Diagram name="coordination" />
46
47Three choices shape it:
48
49- **Nothing is a lock.** A claim is advice: anyone may claim an issue
50 someone else holds, is told about them, and decides. Nothing is ever
51 refused because of a claim (step 9 in the diagram).
52- **Nothing waits on a harness.** No cron sweeps for quiet sessions or
53 stale claims. The next read or change of a repository's coordination
54 finds them (`sweep`) and announces them then: a session quiet for 15
55 minutes is idle, one quiet for 2 hours has ended, and a claim not renewed
56 within its time (30 minutes unless asked, at most 240) has expired.
57- **Everything can be sent twice.** Starting a session is idempotent on the
58 harness's own session id, and each entry on its `key`, so a hook can call
59 every time without checking first, and a retry after a lost answer does
60 no harm.
61
62`get_work` gathers an issue's whole context in one call (`context.rs`): the
63issue, its definition of done, the required checks, claims, sessions,
64pull requests with their checks, overlaps and place in the queue, what it
65is blocked by and blocks, its decision records, and its latest
66coordination events. A session's entries on a pull request are what
67**Blame** reads to show the agent's account of a line ([Sessions and
68why-blame](/guides/why-blame/)). [Sessions, claims and
69dependencies](/guides/sessions/) has the calls.
70
71## Checks and statuses
72
73Anything can report on a commit: a workflow, an integration, g1t itself.
74Each report is a status with a `context` (its name) and a state, kept per
75commit in `commit_statuses`; richer reports are check runs and suites.
76
77Actions reports one status per run, named `<workflow> / <event>`, such as
78`CI / pull_request` (`services/actions/src/plan.rs`). A required check
79named `CI` is met by a status of that name for any event:
80`check_name` in `crates/contracts/src/work.rs` reads the name before the
81last ` / `. One that failed fails the check, even if another passed.
82
83## Deciding a merge
84
85Rulesets are stored in `work`, and judged by `crates/rules`, which does no
86I/O and so can be tested in full. The same rules run in two places:
87
88| When | Who asks | What is judged |
89| --- | --- | --- |
90| A push | `repos`, before anything is stored | Which refs may move, and how: deletion, force-push, signed commits, file paths |
91| A merge | `work` | Required reviews, required checks, CODEOWNERS, up to date, the merge queue |
92
93`requirements` gathers every rule that applies to the target branch, and
94`judge` returns, for each, whether it passes, fails or is still waiting,
95and whether the person asking may bypass it. A merge happens only when
96none fails or waits, for people and coding agents alike.
97
98When everything passes, `work` asks `repos` to land the pull request on
99the base by the merge method asked for: a merge commit, squash, rebase or
100fast-forward (`services/repos/src/merge_methods.rs`). Then it publishes
101`pull.merged`.
102
103## The merge queue
104
105Two changes can merge without a conflict and still break each other. A
106repository whose rules require the merge queue tests each pull request
107together with the ones ahead of it, and moves `main` only to a state whose
108required checks passed (`services/work/src/queue.rs`).
109
110<Diagram name="merge-queue" />
111
1121. **Build.** Up to `max_entries_to_build` entries (4 by default) are
113 tested at once. Each entry is landed by its own merge method on the
114 state of the entry ahead of it (the default branch, for the first), and
115 the result is pushed to `g1t-queue/<entry>` in the repository.
1162. **Test.** Workflows that run on `merge_group` run on each of those
117 commits, and the required checks have to pass there.
1183. **Land.** Entries land in order. Once everything ahead of it has landed,
119 an entry moves the default branch to the very commit that was tested.
1204. **Eject.** An entry whose checks fail leaves the queue with a failed
121 check run on its pull request, and the entries behind it are tested
122 again without it.
123
124| State | Means |
125| --- | --- |
126| `waiting` | In the queue, not yet being built |
127| `testing` | Built, its checks running |
128| `passed` | Its checks passed; it lands when those ahead have |
129| `failed` | Its checks failed; it leaves the queue |
130| `landed` | On the default branch |
131| `removed` | Taken out by hand |
132
133### Who answers for a failure
134
135A combined state can fail because of the entry itself, or because of an
136entry ahead of it. `integration.rs` works out which:
137
138- **Held, not blamed.** A state that fails while an entry ahead is still
139 being tested is held. If that entry fails too, the held one is tested
140 again without it and is not blamed. Only once everything ahead has
141 passed does the held entry answer for the failure, so a broken change is
142 blamed on itself, never on what was queued behind it.
143- **Narrowed down.** An entry whose own checks pass but whose combination
144 fails breaks *with* some of the entries ahead. `work` builds the default
145 branch with half of them and the entry, and halves again, within three
146 extra builds (`PROBE_BUDGET`), recorded in `queue_probes`. The builds run
147 on `merge_group` like any queued state and never land. What is left is
148 reported as the `suspects`.
149- **Told everywhere.** The answer goes on the pull request's and the
150 issue's timelines, into the pull request's session, as a decision record
151 (`integration_failure`, confidence `tested`, in `decisions`), and as the
152 `integration.failed` event. A passing combination is recorded as
153 `integration.passed`.
154- **Rejoining.** A pull request the queue took out keeps its merge
155 request. Once a new commit's checks pass, it is merged again, into the
156 queue, as whoever queued it, by the rules as they are then.
157
158[The merge queue](/guides/merge-queue/#who-answers-for-it) has the table of
159outcomes from a person's side.
160
161<Aside title="How states are built">
162 `work` builds each candidate in the repository itself, through repos'
163 `build_queue_step`: the entry landed by its own merge method on the
164 state ahead of it, with the commits `land` would make there, pushed to
165 the attempt's `g1t-queue/` branch. Landing is then a fast-forward to
166 exactly that commit, and no sandbox is involved.
167 [The merge queue](/guides/merge-queue/) has the settings.
168</Aside>
169
170## Events it publishes and reads
171
172`work` publishes what happens to issues, pull requests, comments, checks
173and the queue (`issue.*`, `pull.*`, `comment.*`, `status.created`,
174`queue.changed` and the like), and the coordination events:
175`session.started`, `session.ended`, `work.claimed`, `work.released`,
176`work.claim_expired`, `work.handoff_requested`, `dependency.changed`,
177`overlap.detected`, `integration.failed`, `integration.passed` and
178`decision.recorded`. It reads
179`git.push` and a few repository events from `g1t-events-work`
180([Events](/architecture/events/#subscriber-queues)).