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.

g1t.sh
437 linesCodeBlameRaw
1---
2title: Sessions, claims and dependencies
3description: How agents and people on one repository see who is working on what, with sessions of their own harnesses, advisory claims on issues, what an issue is blocked by, and the one call that loads an issue's whole context.
4---
5
6When several agents and people work on one repository at once, each needs
7to know what the others are doing. g1t keeps that around the issue, which
8is the unit of work: its description says what is wanted and what done
9means, its pull requests are the proposals, and around it g1t records:
10
11- **Sessions**: one run of your own harness (a Claude Code session, a
12 Codex run) on the repository, attached to the issue and pull request it
13 works on.
14- **Claims**: an advisory, expiring "I'm working on #12". Never a lock.
15- **Dependencies**: the issues that have to land before this one.
16
17Until there is an issue, the session is the unit: work that starts from a
18question or a quick request is recorded as a session titled with what it
19is for, and shows to the team on its branch or pull request. It opens or
20claims an issue only when it becomes a change others should know about;
21see [Work with no issue yet](#work-with-no-issue-yet).
22
23Nothing here waits on a harness. A harness that crashes, loses its
24network or sends the same thing twice does no harm: sessions and claims
25that go quiet are read as idle, ended or expired the next time anyone
26looks, and starting a session or recording an entry again is a no-op.
27What git and g1t record (commits, pull requests, checks, merges) is the
28truth; sessions are the account of how it got there.
29
30## On the site
31
32Everything here shows on g1t.sh as it happens, without reloading.
33
34- **The Work page**, `g1t.sh/<workspace>/<repo>/work`, a tab beside
35 **Pull requests**, **Merge queue** and **Sessions**:
36 - **Live now**: the active claims and the active and idle sessions,
37 grouped by the issue they are on, the most recently active first. An
38 issue with more than one claim is marked. Sessions on no issue yet
39 follow, grouped by their pull request, else by their branch (when it
40 is not the default branch), the most recently heard from first; those
41 on neither are last, under **No branch yet**. Each session shows its
42 title, who it acts for, its harness, its state, when it was last heard
43 from and its branch. A session with no title is named by what its
44 first prompt was for, else **Session on** its branch, else **Untitled
45 session**.
46 - **Merge queue**: what is waiting to land and what is being tested,
47 as on the [Merge queue](/guides/merge-queue/#the-merge-queue-page) page.
48 - **What happened**: the latest 30 coordination events, from claims to
49 what the merge queue found when it combined changes.
50 - **Just landed**: the latest merges, each with a link to the session
51 behind it.
52
53 With nothing going on, it says how to start: install the
54 [Claude Code plugin](/guides/claude-code-plugin/), or run
55 `g1t work claim <number>` from any harness.
56- **An issue's Work panel**, at the top of its sidebar: its claims (who,
57 from which harness, since when and when each lapses; ones released,
58 expired or handed off lately are shown dimmed), the sessions on it with
59 their state and when each was last heard from, what it is blocked by
60 and where each of those stands, and the issues it blocks. Its author
61 and anyone with the Triage role change what it is blocked by with
62 **Edit**. Under its pull requests, the issue shows the latest
63 combination that failed in the merge queue, and its
64 [decision records](/guides/why-blame/#decision-records), each marked
65 **Claimed**, **Tested** or **Approved**.
66- **A session's page**, `g1t.sh/<workspace>/<repo>/work/sessions/<id>`,
67 opened from any of these: who ran it, in which harness and on which
68 model, how long it has run, the issues and pull requests it and its
69 subagents worked on (each says how it was tied), its subagents as a tree
70 you open one at a time (each with its kind, the task it was given, what
71 it touched and what it reported), the skills used, what was touched
72 (files, commits, branches, pull requests), and everything it recorded,
73 as it records it. A subagent's own page links back to the session that
74 started it.
75- **An issue's and a pull request's sessions**: every session tied to it
76 in any way, with its subagents under it.
77- **Start a session** on an issue, for members of a workspace with an
78 Anthropic connection: see
79 [Start a session on your Anthropic account](#start-a-session-on-your-anthropic-account).
80
81## Picking up an issue
82
83Before working on an issue, load its whole context in one call: `issue`
84with `"action": "work"` over MCP, or
85[`GET /repos/{owner}/{name}/issues/{number}/work`](/reference/api/claims-and-work/get-work/):
86
87```sh
88curl https://api.g1t.sh/repos/acme/web/issues/12/work \
89 -H "Authorization: Bearer $G1T_TOKEN"
90```
91
92| Field | What it holds |
93| --- | --- |
94| `issue` | The issue, with its body. |
95| `definition_of_done` | The items under its **Definition of done** heading. |
96| `required_checks` | The checks every pull request into the default branch must pass. |
97| `claims` | Who says they are working on it now. |
98| `sessions` | Sessions on it or its pull requests, or tied to it any other way, subagents included, active ones first. Each says how many `subagents` it started. |
99| `pulls` | Its pull requests. Those still open or draft carry their `required_checks` as they stand on the head, `mergeable`, the other pull requests they `overlap`, and their place in the merge `queue`. |
100| `blocked_by` | Each issue it waits on, with that issue's claims and pull requests. |
101| `blocks` | The issues waiting on it. |
102| `decisions` | [Decision records](/guides/why-blame/#decision-records) on it and its pull requests, newest first. |
103| `last_integration_failure` | The latest `integration_failure` decision among them, if any: the combination that failed in the merge queue, the check, the `suspects` and, when it failed on `main` alone, the pull requests that `landed` on `main` since it branched. |
104| `recent` | Its latest 20 coordination events, newest first. |
105
106Then claim it, and start (or attach) your session.
107
108## Sessions
109
110A session is one run of your harness on a repository. Start one when the
111harness starts, keep it alive while it works, and end it when it stops.
112
1131. **Start** it with `session` `start`, or
114 [`POST /repos/{owner}/{name}/sessions`](/reference/api/sessions/start-session/),
115 naming the `harness` (`claude_code`, `claude_managed_agents`, `codex`,
116 `cursor`, `copilot` or `other`) and the harness's own id for the session as
117 `harness_session_id`. Starting again with the same id returns the
118 session already started, so a hook can call it every time without
119 checking first. Give `issue`, `pull` and `branch` when you know them,
120 and a `title`: what the session is for, in a few words (up to 200
121 characters).
1222. **Heartbeat** with `session` `update`, or
123 [`PATCH /repos/{owner}/{name}/sessions/{id}`](/reference/api/sessions/update-session/)
124 with an empty body. The same call attaches the session to an issue or
125 pull request, records the `head_commit` it pushed, or changes its
126 `title`.
1273. **Record** what happens with `session` `record`, or
128 [`POST /repos/{owner}/{name}/sessions/{id}/entries`](/reference/api/sessions/record-session-entries/):
129 prompts, reasoning, tool calls, notes and the skills it used (`skill`,
130 the skill's name only), up to 200 a request, and in `touched` what it
131 touched (see [What a session worked on](#what-a-session-worked-on)).
132 Give each entry a `key`, and recording it again does nothing.
1334. **End** it with `session` `end`, or
134 [`POST /repos/{owner}/{name}/sessions/{id}/end`](/reference/api/sessions/end-session/),
135 with its `result` when it has one: what it reported when it finished.
136
137```sh
138curl -X POST https://api.g1t.sh/repos/acme/web/sessions \
139 -H "Authorization: Bearer $G1T_TOKEN" \
140 -H "Content-Type: application/json" \
141 -d '{"harness": "claude_code", "harness_session_id": "5b0c1f9e-3d2a-4e8b-9f61-0c7d2a9e4b13", "issue": 12}'
142```
143
144A session's `state` is worked out from when it was last heard from. Every
145update and every batch of entries counts as a heartbeat:
146
147| State | Means |
148| --- | --- |
149| `active` | Heard from in the last 15 minutes. |
150| `idle` | Not heard from for 15 minutes. It may still come back. |
151| `ended` | Ended with `end_session`, or not heard from for 2 hours (`end_reason` `timed_out`). A heartbeat brings a timed-out session back; an ended one stays ended. |
152
153Entries of a session attached to a pull request show in that pull
154request's [session](/guides/why-blame/#sessions), beside what was recorded
155on it with `record_session`, so reviewers and why-blame see them. Entries
156recorded before the session named its pull request move onto it when it
157does. A session never records tool output unless you send it as a
158`tool_result` entry; a session is as visible as the repository, so keep
159secrets out of it.
160
161List a repository's sessions with `session` `list`, or
162[`GET /repos/{owner}/{name}/sessions`](/reference/api/sessions/list-sessions/)
163by `state`, `issue` or `pull` (any session tied to it), or `path` (those
164that touched a file, or any under a folder ending in `/`); subagents are
165listed too with `subagents=true`. A session in the list with no `title`
166carries `first_prompt`: the first 300 characters of the first prompt it
167recorded. Read one with its entries, subagents, links, skills and what it
168touched with `session` `get`.
169
170## Work with no issue yet
171
172Not every session starts from an issue, and most should not end with one:
173a question, a look around or a quick fix needs no issue. The session is
174the record of that work, and the team sees it in **Live now** while it
175goes:
176
1771. **It says what it is for.** Give it a `title` when you start it, or
178 later with `session` `update`. The
179 [Claude Code plugin](/guides/claude-code-plugin/#work-with-no-issue-yet)
180 titles each session from its first prompt that is not a slash command,
181 and never replaces a title the session already has.
1822. **It shows where it works.** Attach its `branch` and, once there is
183 one, its `pull`: **Live now** groups sessions on no issue by pull
184 request, then by branch.
1853. **It opens or claims an issue when it becomes a change** others should
186 know about: a branch to push, a pull request. Look for one first
187 (`issue` `list`, `issue` `list_claims`); if one covers the work,
188 claim it. Otherwise open one and claim it in one step with `issue`
189 `claim` and a `title` instead of a `number` (see [Claims](#claims)),
190 which attaches the session to it.
191
192## Subagents
193
194A harness that hands part of its work to a subagent (Claude Code's
195subagents, a Managed Agents session's threads) records each as a session
196of its own under the one that started it:
197
198- Start it with `parent_id` (the session that started it), `agent_type`
199 (its kind, such as `Explore`), the `task` it was given in a few words and
200 the `prompt` (kept up to 4,000 characters). As its `harness_session_id`,
201 give the parent's, `/agent/` and the subagent's id: starting it again
202 returns it, in whatever order the harness's hooks arrive.
203- It starts on its parent's issue, pull request and branch unless it says
204 otherwise, so it is listed on them, and its heartbeats keep its parent
205 active.
206- End it with its `result`: its final message, kept up to 8,000
207 characters. That is its parent's evidence; what its tools returned is
208 never recorded. Once ended it stays ended, even when a late hook starts
209 it again: that only fills in what it says.
210- Ending a session ends the subagents it left going (`end_reason`
211 `parent ended`).
212
213Subagents see each other. Sibling subagents on one issue are listed in
214`get_work` and `session` `list` beside the session that started them,
215each holds a claim of its own (claims are told apart by session, so a
216sibling's claim is listed in `others`), and when two of them touch the
217same file, each is told with `overlap.detected`. The
218[Claude Code plugin](/guides/claude-code-plugin/#subagents) does all of
219this for Claude Code's subagents.
220
221## What a session worked on
222
223A session says what it touched in `touched`, each kept once:
224
225| `kind` | `value` |
226| --- | --- |
227| `file` | A file it wrote, from the repository's root. |
228| `commit` | A commit it made. |
229| `branch` | A branch it made or pushed. |
230| `pull` | A pull request it opened, by number. |
231| `issue` | An issue it named or claimed, by number. |
232
233From these and the rest of what it records, g1t ties the session to the
234issues and pull requests it worked on, each in as many ways as it was
235(`via` in the session's `links`):
236
237| `via` | When |
238| --- | --- |
239| `attached` | It said it is on it, starting or updating. |
240| `claim` | It claimed the issue. |
241| `opened` | It opened the pull request. |
242| `branch` | It pushed the pull request's branch, also when the pull request is opened later. |
243| `commit` | It made the pull request's head commit. |
244| `trailer` | A commit pushed to the pull request's branch names it in a `G1t-Session: ses_…` trailer. |
245| `ref` | Its prompt, its task, its result or a subagent's names it as `#12`. |
246
247A session's links cover its subagents too, and the issue and pull request
248pages list every session tied to them with its subagents. Put the trailer
249on the commits a session makes (`git commit --trailer "G1t-Session:
250$G1T_SESSION"`) and they lead back to it.
251
252When a file a session touched was touched by another active session as
253well (outside its own parents and subagents), g1t sends `overlap.detected`
254to both, naming each other and the files: once per pair.
255
256## Start a session on your Anthropic account
257
258g1t runs no model. Work on an issue happens in your own harness, with your
259own Claude, its skills and settings; g1t ties it back to the issue. To
260hand an issue to a session from g1t itself (the issue page's **Start a
261session**, `g1t work dispatch`, the `session` tool's `dispatch`, or
262[`POST /repos/{owner}/{name}/agent-sessions`](/reference/api/sessions/start-agent-session/)):
263
264```sh
265curl -X POST https://api.g1t.sh/repos/acme/web/agent-sessions \
266 -H "Authorization: Bearer $G1T_TOKEN" \
267 -H "Content-Type: application/json" \
268 -d '{"issue": 12, "mode": "implement", "instruction": "Keep the old greeting behind a flag."}'
269```
270
271Give `issue`, or `title` and `body` to open a new issue first, a `mode`
272(`plan`, `implement` or `review`) and an optional `instruction`.
273
274- **With an Anthropic connection** in the workspace (an owner adds one
275 under **Integrations**, **Your AI providers**), g1t starts a
276 [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview)
277 session on that account, with its key, on the model Ask is set to use
278 (or `claude-opus-5-5`). It runs in a sandbox on Anthropic's side and
279 reaches g1t through g1t's MCP server and git, with a token made for you
280 and that repository only, which lasts the session and is revoked when it
281 ends. The token is kept in a vault on the Anthropic account: the MCP
282 server's credential, and `G1T_TOKEN`, which the sandbox holds only as a
283 placeholder that is swapped for the token on its way to g1t. It is never
284 in the prompt, and the model never sees it. The session has g1t's skills
285 (work-on-issue, coordinate and fix-integration, uploaded to the account
286 the first time) next to the account's own custom skills, up to 20 in
287 all. It may hand parts of the work to copies of itself; each is recorded
288 as a subagent.
289- **Without one**, or with `handoff: true`, nothing starts: you get
290 `command`, a Claude Code command line to run in your working copy with
291 the [plugin](/guides/claude-code-plugin/), and `prompt`, what to paste.
292 The session that starts attaches to the issue.
293
294The answer has the `session` on g1t, its `session_url`, and
295`provider_session_url`, where the Anthropic Console shows it (its
296`default` workspace; another workspace's sessions are under its own id).
297The session is recorded as harness `claude_managed_agents`: its messages,
298the tools it called and with what (never what they returned), the skills
299it read, what it touched, and each thread as a subagent with its task and
300report. g1t follows it every minute, and at once while its page is open. A
301call that waits for someone's approval is declined, since nobody is
302watching. When it finishes, its session ends with its last message as its
303result. Whoever started it can stop it from its page. It runs on your
304workspace's key and Anthropic bills the account for it; g1t bills nothing.
305
306## Claims
307
308A claim says you are working on an issue. It is advisory: anyone may claim
309an issue someone else has, and is told about them, so two agents can
310decide between themselves rather than collide. Nothing is refused because
311of a claim.
312
313- **Claim** an open issue with `issue` `claim` (with `session_id`, so
314 that two of your sessions, such as sibling subagents, hold claims of
315 their own and each is told of the other's), or
316 [`POST /repos/{owner}/{name}/issues/{number}/claim`](/reference/api/claims-and-work/claim-issue/).
317 The answer has your `claim`, the `others` already on the issue, and
318 `blocked_by`: each issue this one waits on, with its claims and pull
319 requests.
320- **Open an issue and claim it** in one step, for work that has no issue
321 yet: `issue` `claim` with `title` (and `body`) and no `number`, or
322 [`POST /repos/{owner}/{name}/claims`](/reference/api/claims-and-work/claim-new-issue/).
323 The issue is opened (an `issue.opened` event), then claimed, and the
324 session named by `session_id` is attached to it. The answer also has
325 `issue`, the issue opened. The session is checked first: a claim that
326 would be refused for it opens nothing.
327- **Renew** it by claiming again, or give the `session_id` of your session
328 when you claim, and that session's heartbeats renew it.
329- **Release** it with `issue` `release`, or
330 [`POST /repos/{owner}/{name}/issues/{number}/release`](/reference/api/claims-and-work/release-claim/),
331 with an optional `reason`.
332- **Hand it off** with `issue` `handoff`, or
333 [`POST /repos/{owner}/{name}/issues/{number}/handoff`](/reference/api/claims-and-work/hand-off-issue/),
334 with a `note` on where the work stands, for `to` (a username) or anyone.
335 When whoever it was for claims the issue, their `work.claimed` event
336 names the hand-off in `took_over`.
337
338```sh
339curl -X POST https://api.g1t.sh/repos/acme/web/issues/12/claim \
340 -H "Authorization: Bearer $G1T_TOKEN" \
341 -H "Content-Type: application/json" \
342 -d '{"session_id": "ses_01m4b2c3d4e5f6g7h8j9k0m1n2", "note": "Taking the argument parsing first."}'
343
344curl -X POST https://api.g1t.sh/repos/acme/web/claims \
345 -H "Authorization: Bearer $G1T_TOKEN" \
346 -H "Content-Type: application/json" \
347 -d '{"session_id": "ses_01m4b2c3d4e5f6g7h8j9k0m1n2", "title": "Preview builds time out on large repositories"}'
348```
349
350| | |
351| --- | --- |
352| How long a claim lasts | `ttl_minutes`: 30 unless you say, at most 240. |
353| Opening its issue | `title` (and `body`) instead of `number`. Giving both is refused with `422`. |
354| When it ends | Released, handed off, its issue closed, or not renewed in time (`expired`). |
355| States | `active`, `released`, `expired`, `handed_off`. |
356
357See who is on what with `issue` `list_claims`, or
358[`GET /repos/{owner}/{name}/claims`](/reference/api/claims-and-work/list-claims/):
359active claims unless `state` says otherwise, and `issue` for one issue's.
360
361## Dependencies
362
363An issue's `blocked_by` lists the issues of the same repository that have
364to land before it. Set it with `issue` `update`, or
365[`PATCH /repos/{owner}/{name}/issues/{number}`](/reference/api/issues/update-issue/),
366which replaces the whole list:
367
368```sh
369curl -X PATCH https://api.g1t.sh/repos/acme/web/issues/12 \
370 -H "Authorization: Bearer $G1T_TOKEN" \
371 -H "Content-Type: application/json" \
372 -d '{"blocked_by": [9, 10]}'
373```
374
375A list is refused with `422` when a number is not an issue of the
376repository, names the issue itself, or would make a cycle (the answer
377shows the cycle, such as `#12 → #9 → #12`). Up to 50 issues. Changing it
378notes the change in the issue's conversation and needs what editing the
379issue does: being its author, or the Triage role.
380
381g1t says when a dependency moves, as a `dependency.changed` event on the
382blocked issue: when its list changes, and when one of its blockers closes
383or has a pull request merged into the default branch. `remaining` lists
384the blockers still open; when it is empty, the issue is unblocked.
385
386## Overlaps
387
388Opening a pull request, and each push to it, works out which files it
389changes. When it starts changing files another open or draft pull request
390changes, g1t sends `overlap.detected` once for each of the two, naming the
391other and the files. A pair is announced once, and again only after it stopped
392overlapping. `get_work` and `pull_request` `get` show current overlaps
393whenever you look.
394
395Sessions overlap too, before there is a pull request: when a session says
396it touched a file that another active session touched (see
397[What a session worked on](#what-a-session-worked-on)), each gets
398`overlap.detected` with `session_id`, `other_session_id`, `other_actor`
399and `files`, once per pair.
400
401## Events
402
403Coordination is published as events, which [webhooks](/guides/webhooks/)
404deliver and the repository's timeline lists. Each carries `number` (the
405issue or pull request it is about) and `issue` where there is one.
406
407| Event | When |
408| --- | --- |
409| `session.started` | A session (or a subagent) starts, or one that ended starts again. Not on a repeated start. |
410| `session.ended` | A session ends, or times out after 2 hours without a heartbeat. |
411| `session.progressed` | A session recorded more: at most every 5 seconds for each, with `session_id` (and `root_id` for a subagent), never what it recorded. Pages showing the session follow it with this. |
412| `work.claimed` | Someone claims an issue. `others` lists the claims already on it; `took_over` names a hand-off it takes. |
413| `work.released` | A claim is released, or its issue closed (`reason` `issue_closed`). |
414| `work.claim_expired` | A claim was not renewed in time. |
415| `work.handoff_requested` | Someone hands an issue off: `from`, `to` (absent for anyone) and `note`. |
416| `dependency.changed` | An issue's `blocked_by` changed (`added`, `removed`), or a blocker closed or had its pull request merged (`cleared`). `remaining` lists the blockers still open. |
417| `overlap.detected` | A pull request started changing files another open one changes: `pull`, `other_pull`, `files`, `issue` and `other_issue`. Or a session touched files another active session touched: `session_id`, `other_session_id`, `other_actor`, `files`. |
418
419A session or claim that went quiet is announced as ended or expired when
420the repository's sessions or claims are next read or changed, not at the
421minute it lapsed.
422
423## Who may do what
424
425| To | You need |
426| --- | --- |
427| Read sessions, claims and an issue's context | To be able to read the repository. Public repositories need no token. |
428| Start a session, claim an issue, open one by claiming it | A confirmed email address and a role that may open issues; the repository must not be archived. |
429| Update, record in or end a session | To be the person whose token started it. |
430| Release a claim or hand it off | To be the person who made it. |
431| Set `blocked_by` | To be the issue's author, or the Triage role. |
432| Start a session on the workspace's Anthropic account | To be a member of the workspace and able to open issues in the repository. The hand-off needs only to read the issue. |
433
434With an access token, sessions (and `start_agent_session`) need
435`pull_requests:read` or `pull_requests:write`, and claims and `get_work`
436need `issues:read` or `issues:write`, as
437[scopes](/guides/authentication/#scopes) say.