Skip to content
1,333 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge checks: statuses and check runs on every commit1import type { ChecksApi } from "./checks";
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar2import type { CodeownersReport, PullCodeOwners } from "./codeowners";
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'3import type { G1tEvent } from "./events";
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet4import type { User, Viewer } from "./identity";
5import type { PullBranchUpdate, RepoPath } from "./repos";
6import type { Result } from "./result";
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge7import type { MergeRules, RulesApi } from "./rules";
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet8
9/**
10 * The filter on lists of issues and pull requests. An open pull request is
11 * a draft or one ready for review; a closed one was merged or closed
12 * without merging.
13 */
14export type State = "open" | "closed";
15
16/** Why an issue was closed. */
17export type IssueReason = "completed" | "not_planned";
18
19/**
20 * Something that should change in a repository: a bug, a feature, a
21 * question. Opened by a person, an agent or an integration. Pull requests
22 * are made against it; the one that is merged resolves it.
23 *
24 * Issues and pull requests share one sequence of numbers per repository.
25 */
26export type Issue = {
27 id: string;
28 repoId: string;
29 /** Shown as `#12`. */
30 number: number;
31 title: string;
32 /** Markdown. Also what an agent is given to work from. */
33 body: string;
34 labels: string[];
35 state: State;
36 /** Set when closed. */
37 reason: IssueReason | null;
38 /** The number of the pull request whose merge closed this issue. */
39 resolvedBy: number | null;
40 /** Who opened it: a person, an integration, or g1t (`kind` `agent`) for one its agent filed while at work. */
41 author: User;
42 /**
43 * For an issue g1t's agent filed: the person it was working for. They may
44 * manage it as its author could. See `workOwner`.
45 */
46 requestedBy: User | null;
47 /** RFC 3339. */
48 createdAt: string;
49 /** RFC 3339. */
50 updatedAt: string;
51 /** RFC 3339. */
52 closedAt: string | null;
53 /** Pull requests made against this issue, in any state. */
54 pullCount: number;
55 commentCount: number;
56 /** Usernames of the people it is assigned to. */
57 assignees: string[];
58 /** The numbers of the issues that have to be merged before this one is worked on. */
59 blockedBy: number[];
60 /**
61 * Whether a g1t agent takes it as soon as it can: at once, or when what it
62 * is blocked by has merged.
63 */
64 queued: boolean;
65 /**
66 * The agent working on it now: the one behind its newest pull request
67 * that is still in progress in a fork, such as `g1t`.
68 */
69 agent: string | null;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar70 /** The milestone it is in, if any. */
71 milestone?: MilestoneRef | null;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet72};
73
74/**
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar75 * A label of a repository: a name, a color and what it means. Issues and
76 * pull requests carry labels by name; names are lowercase.
77 */
78export type Label = {
79 name: string;
80 /** Six hex digits, without `#`. */
81 color: string;
82 description: string;
83 /** How many issues carry it, open or closed. */
84 issues: number;
85 /** How many pull requests carry it, in any state. */
86 pulls: number;
87};
88
89/** A milestone, as an issue or pull request names it. */
90export type MilestoneRef = { number: number; title: string };
91
92/**
93 * A goal, with an optional due date, that issues and pull requests are
94 * gathered under. Its progress is how many of them are closed.
95 */
96export type Milestone = {
97 /** Numbered from 1 in each repository, apart from issues. */
98 number: number;
99 title: string;
100 /** Markdown. */
101 description: string;
102 /** `YYYY-MM-DD`. */
103 dueOn: string | null;
104 state: State;
105 /** Open issues and pull requests in it. */
106 openItems: number;
107 /** Closed issues, and merged or closed pull requests, in it. */
108 closedItems: number;
109 createdAt: string;
110 updatedAt: string;
111 closedAt: string | null;
112};
113
114/** One milestone and what is in it, newest first. */
115export type MilestoneDetail = { milestone: Milestone; issues: Issue[]; pulls: Pull[] };
116
117/** How `setLabels` changes an item's labels. */
118export type LabelChange = "set" | "add" | "remove";
119
120/**
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet121 * Whose an issue or a pull request is to answer for: whoever asked g1t for
122 * it, or its author. They may change, close and steer it, are never asked to
123 * review it and cannot approve it, and see it as theirs. Mirrors
124 * `Pull::owner` in the Rust contracts.
125 */
126export function workOwner(item: Pick<Pull, "author" | "requestedBy">): User {
127 return item.requestedBy ?? item.author;
128}
129
130/** `draft` is still being worked on; `open` is ready for review. */
131export type PullStatus = "draft" | "open" | "merged" | "closed";
132
133/** Where the agent runs: on g1t's sandboxes, or in someone's own session. */
134export type Runtime = "hosted" | "external";
135
136/**
137 * A proposed change. It is made either in a fork created for it, which is
138 * how agents work, or on a branch pushed to the repository itself.
139 */
140export type Pull = {
141 id: string;
142 repoId: string;
143 /** Shown as `#12`. */
144 number: number;
145 /** The number of the issue this is for, if any. */
146 issue: number | null;
147 title: string;
148 /** Markdown: what changed and why. Set when marked ready. */
149 body: string | null;
150 /** A label for the agent doing the work, e.g. `claude-code`. */
151 agent: string;
152 runtime: Runtime;
153 status: PullStatus;
154 /** The fork holding the change, unless it is on a branch. */
155 fork: RepoPath | null;
156 /** The fork's repository id. */
157 forkRepoId: string | null;
158 /** The branch of the repository holding the change, unless it is in a fork. */
159 branch: string | null;
160 headCommit: string | null;
161 /**
162 * For a merged pull request, what the branch pointed to before the merge.
163 * Comparing against it shows what the pull request changed.
164 */
165 mergeBase: string | null;
166 /** Username of whoever merged it. */
167 mergedBy: string | null;
168 /** RFC 3339. */
169 mergedAt: string | null;
170 /**
171 * Set on a pull request closed because another one for the same issue was
172 * merged: that one's number.
173 */
174 supersededBy: number | null;
175 /**
176 * Where the latest run of the issue's acceptance checks stands, if there
177 * has been one against the current head.
178 */
179 checkStatus: CheckStatus | null;
180 /** The files it changes, as of its latest push. */
181 files: ChangedFile[];
182 /** Usernames of the people it is assigned to. */
183 assignees: string[];
184 /**
185 * Those whose review was asked for: usernames, and `g1t` when a g1t
186 * agent was asked.
187 */
188 reviewers: string[];
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar189 /**
190 * Teams whose review was asked for, as `workspace/slug`. A team stays here
191 * after review assignment picks people from it, who are in `reviewers`.
192 */
193 teamReviewers?: string[];
194 /** The labels it carries, by name. */
195 labels?: string[];
196 /** The milestone it is in, if any. */
197 milestone?: MilestoneRef | null;
198 /**
199 * The branch it merges into. Lists and `getPull` name it; null only in
200 * what services pass between themselves, for the default branch.
201 */
202 base?: string | null;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet203 /** Who opened it: a person, or g1t (`kind` `agent`, username `g1t`) for a change g1t made. */
204 author: User;
205 /**
206 * For a change g1t made: the person who asked for it, by assigning an issue
207 * or handing g1t the work. They answer for it as its author would. See
208 * `workOwner`.
209 */
210 requestedBy: User | null;
211 /** RFC 3339. */
212 createdAt: string;
213 /** RFC 3339. */
214 updatedAt: string;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge215 /** Who last moved its head (a user id), and when; absent until a push after rulesets arrived. */
216 headPushedBy?: string;
217 headPushedAt?: string;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet218};
219
220/** One file a pull request changes, and by how much. */
221export type ChangedFile = { path: string; additions: number; deletions: number };
222
223/**
224 * Another pull request in progress that changes some of the same files. Two
225 * for the same issue are alternatives; two for different issues are heading
226 * for a conflict.
227 */
228export type Overlap = {
229 number: number;
230 title: string;
231 /** The number of the issue the other pull request is for. */
232 issue: number | null;
233 /** The files both change. */
234 paths: string[];
235};
236
237/**
238 * On a pull request, `failed` means the merge queue took it out, until its
239 * head moves. The other states are from runs of commands written on issues,
240 * which g1t no longer runs.
241 */
242export type CheckStatus = "queued" | "running" | "passed" | "failed" | "errored";
243
244/** How one command went, in a run recorded before checks were workflows. */
245export type CheckResult = {
246 command: string;
247 passed: boolean;
248 /** Null when the command was stopped for taking too long. */
249 exitCode: number | null;
250 /** What the command printed; the end of it, when there was a lot. */
251 output: string;
252 durationMs: number;
253};
254
255/**
256 * A record against a pull request's head: the merge queue taking it out,
257 * with why, or an earlier run of commands written on its issue.
258 */
259export type CheckRun = {
260 id: string;
261 /** The commit that was checked. */
262 headCommit: string;
263 status: CheckStatus;
264 results: CheckResult[];
265 /** Why the checks could not be run, when `status` is `errored`. */
266 error: string | null;
267 /** RFC 3339. */
268 createdAt: string;
269 /** RFC 3339. */
270 finishedAt: string | null;
271};
272
273/** A reviewer's decision on a pull request. */
274export type Verdict = "approve" | "request_changes";
275
276/**
277 * A comment on an issue or a pull request. On a pull request it can sit on
278 * one line of the change, and it can carry a reviewer's verdict.
279 */
280export type Comment = {
281 id: string;
282 /**
283 * Something a person or an agent wrote, or something that happened: an
284 * assignment, a review asked for, a close.
285 */
286 kind: "comment" | "event";
287 author: User;
288 /**
289 * Markdown. For an event, what its author did, as the rest of a sentence
290 * that starts with their name: "assigned ana".
291 */
292 body: string;
293 /** The file commented on, for a comment on a line. */
294 path: string | null;
295 /** The line of that file, as numbered after the change. */
296 line: number | null;
297 verdict: Verdict | null;
298 /** RFC 3339. */
299 createdAt: string;
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts300 /** When its text was last edited, RFC 3339; absent if it never was. */
301 editedAt?: string;
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar302 /**
303 * Set when one of the workspace's agents wrote it, as itself. `author`
304 * is then the agent (its id, its handle as `username`, kind `agent`):
305 * show it by `agent.displayName` with an Agent badge, never as a person.
306 */
307 agent?: AgentRef;
308 /** Who the agent acted for, whose access capped it. Set with `agent`. */
309 actingFor?: User;
310 /**
311 * An agent's review. Its `verdict` (none for a review that only
312 * comments) is shown but advisory: it never counts toward required
313 * approvals or code owners, and never blocks a merge.
314 */
315 advisory?: boolean;
316};
317
318/**
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.319 * One of a workspace's own agents, as a comment or review it wrote before
320 * g1t's agents were removed shows it: Margo (@margo), with the face drawn
321 * from `avatarSeed`. Kept so those comments still render.
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar322 */
323export type AgentRef = {
324 id: string;
325 handle: string;
326 displayName: string;
327 avatarSeed: string;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet328};
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar329
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet330export type NewComment = {
331 /** May be empty when approving. */
332 body: string;
333 path?: string;
334 line?: number;
335 verdict?: Verdict;
336};
337
338/** What a sandbox needs to carry out a check run. */
339export type CheckJob = {
340 runId: string;
341 /** Lets the sandbox, and nothing else, report this run's results. */
342 token: string;
343 commands: string[];
344 /** The repository holding the commit: the fork, or the repository itself. */
345 source: RepoPath;
346 commit: string;
347 /** Who the pull request is for (`workOwner`: whoever asked g1t for it, or its author), and so can read its source. */
348 author: User;
349 /** Username of whoever wrote the checks: the issue's author. */
350 requestedBy: string;
351 repo: RepoPath;
352 number: number;
353};
354
355export type CheckReport = { results?: CheckResult[]; error?: string; skip?: boolean };
356
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.357export type SessionEntryKind = "prompt" | "message" | "tool_call" | "tool_result" | "note" | "skill";
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet358
359/** One step of an agent's session: the "why" behind a pull request's commits. */
360export type SessionEntry = {
361 seq: number;
362 kind: SessionEntryKind;
363 text: string;
364 /** For tool calls and results. */
365 tool: string | null;
366 /** The fork's head commit when this entry was recorded, if known. */
367 commit: string | null;
368 /** RFC 3339. */
369 at: string;
370};
371
372export type NewSessionEntry = Pick<SessionEntry, "kind" | "text"> &
373 Partial<Pick<SessionEntry, "tool" | "commit">>;
374
375export type IssueDetail = {
376 issue: Issue;
377 /** Every pull request made against it, oldest first. */
378 pulls: Pull[];
379 comments: Comment[];
380};
381
382export type PullDetail = {
383 pull: Pull;
384 /** The issue it is for, if any. */
385 issue: Issue | null;
386 comments: Comment[];
387 /** The latest record against its head: the merge queue taking it out. */
388 checks: CheckRun | null;
389 /** Other pull requests in progress that change the same files. */
390 overlaps: Overlap[];
391 /**
392 * Whether the branch it would merge into has moved on without it, so that
393 * it has to catch up before it can merge.
394 */
395 behind: boolean;
396 /**
397 * Where it stands on its way to being merged, for a pull request g1t is
398 * seeing through. Null on anyone else's.
399 */
400 lifecycle: Lifecycle | null;
401 /**
402 * A merge was asked for while it was behind: g1t is bringing it up to
403 * date and will then land it.
404 */
405 landing: boolean;
406 /** Why g1t stopped working on it, if it did. */
407 stalled: string | null;
408 /** What workflow runs said about its head commit, one per workflow. */
409 statuses?: CommitStatus[];
410 /**
411 * Whether it merges cleanly into the branch it targets, worked out ahead
412 * of time whenever either side moves.
413 */
414 mergeable?: Mergeable;
415 /** When `mergeable` is `conflicting`: the files that conflict. */
416 conflicts?: string[];
417 /** Earlier records like `checks`, newest first, without their output. */
418 earlierChecks?: CheckRun[];
419 /**
420 * The checks the default branch's protection requires, each as it stands
421 * on the head commit. Empty when none are required.
422 */
423 requiredChecks?: RequiredCheck[];
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar424 /**
425 * Who owns the files it changes (the CODEOWNERS file of the branch it
426 * merges into) and whose approval is still needed. Absent without one.
427 */
428 codeOwners?: PullCodeOwners | null;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge429 /**
430 * The rules of the branch it merges into it does not meet yet, for whoever
431 * is looking: what refuses the merge, what they may bypass, and what rulesets
432 * in evaluate would refuse. Absent once it is closed or merged.
433 */
434 rules?: MergeRules | null;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet435};
436
437/** Where a required check stands on a commit; `expected` when nothing has reported it yet. */
438export type RequiredState = "success" | "failure" | "pending" | "expected";
439
440/** One check a branch's protection requires, as it stands on a commit. */
441export type RequiredCheck = {
442 /** A workflow's name, such as `CI`, or another status's context. */
443 name: string;
444 state: RequiredState;
445 description: string | null;
446 /** Where to see more: the workflow run, for one a workflow reported. */
447 targetUrl: string | null;
448};
449
450/** A check name reported on a repository's commits lately, for choosing required checks. */
451export type SeenCheck = {
452 name: string;
453 /** The events it was reported for, such as `pull_request`; empty for a status that names none. */
454 events: string[];
455 /** RFC 3339. */
456 lastSeen: string;
457};
458
459/**
460 * A status context's check name: `CI / pull_request` is the `CI` check,
461 * reported for a `pull_request` event. A context that does not end in an
462 * event, such as `g1t / deploy`, is its own name. As the work service reads it.
463 */
464export function checkName(context: string): string {
465 const at = context.lastIndexOf(" / ");
466 if (at <= 0) return context;
467 return STATUS_EVENTS.has(context.slice(at + 3)) ? context.slice(0, at) : context;
468}
469
470const STATUS_EVENTS = new Set([
471 "push",
472 "pull_request",
473 "pull_request_target",
474 "pull_request_review",
475 "merge_group",
476 "workflow_dispatch",
477 "workflow_run",
478 "workflow_call",
479 "schedule",
480 "release",
481 "issues",
482 "issue_comment",
483 "repository_dispatch",
484]);
485
486/**
487 * Whether a pull request merges cleanly into the branch it targets:
488 * `unknown` when it was never worked out or could not be, `checking` while
489 * a probe merges the two.
490 */
491export type Mergeable = "clean" | "conflicting" | "unknown" | "checking";
492
493/** What a sandbox needs to find out whether a pull request merges cleanly. */
494export type MergecheckJob = {
495 pullId: string;
496 /** Lets the sandbox, and nothing else, report this probe. */
497 token: string;
498 repo: RepoPath;
499 number: number;
500 defaultBranch: string;
501 /** The default branch's commit to merge into. */
502 base: string;
503 /** The repository holding the change: its fork, or the repository. */
504 source: RepoPath;
505 /** The branch of `source` holding it. */
506 branch: string;
507 /** The change's commit. */
508 head: string;
509 /** Who the pull request is for (`workOwner`: whoever asked g1t for it, or its author), and so can read its source. */
510 author: User;
511};
512
513/** What a workflow run (or another tool) says about a commit. */
514export type CommitStatus = {
515 /** What reported it, such as `CI / push`. */
516 context: string;
517 state: "pending" | "success" | "failure" | "error";
518 description: string | null;
519 targetUrl: string | null;
520 updatedAt: string;
Merge checks: statuses and check runs on every commit521 /** The integration that reported it: `actions`, `deployments`, `security`, `g1t` or `api`. */
522 source?: string;
523 /** Set on the status a check run stands as: the check run's id. */
524 checkRunId?: string;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet525};
526
527/**
528 * A step on the way from an assigned issue to a pull request that is ready
529 * to merge. g1t takes each one without being asked: `working` (the agent is
530 * making the change), `checking`, `reviewing`, `revising` (the agent is
531 * addressing failed checks or a review), `catching_up` (merging in the
532 * branch it would land on), `answering` (woken to answer another agent),
533 * then `ready` for a person to merge. `needs_you`
534 * means g1t has stopped and a person decides what happens next.
535 */
536export type Stage =
537 | "working"
538 | "checking"
539 | "reviewing"
540 | "revising"
541 | "catching_up"
542 | "answering"
543 | "queued"
544 | "ready"
545 | "needs_you";
546
547export type Lifecycle = {
548 stage: Stage;
549 /** One sentence saying what is happening, or why it stopped. */
550 detail: string;
551 /** How many times the agent has been sent back to revise it. */
552 revisions: number;
553};
554
555/**
556 * How a repository wants its pull requests handled. A repository that has
557 * changed nothing has the defaults.
558 */
559export type RepoSettings = {
560 /**
561 * Land a g1t agent's pull request without a person once it is ready:
562 * checks passed and approved as the settings below require.
563 */
564 autoMerge: boolean;
565 /**
566 * The checks that must pass on a pull request's head before it may merge
567 * into the default branch, by name: a workflow's name (`CI`) or another
568 * status's context (`g1t / deploy`). The same for people and agents, and
569 * for the merge queue.
570 */
571 requiredChecks: string[];
572 /**
573 * Refuse to merge a pull request that does not contain the default
574 * branch's latest commits, so that what merges is what was checked. When
575 * off, merging one that is behind brings it up to date first.
576 */
577 requireUpToDate: boolean;
578 /**
579 * How many approving reviews a pull request needs before it may merge. A
580 * reviewer who has since asked for changes blocks it.
581 */
582 requiredApprovals: number;
583 /** Whether a g1t agent's approval counts towards `requiredApprovals`. */
584 countAgentApprovals: boolean;
585 /** Whether someone who may merge can bypass required checks that have not passed. */
586 allowIgnoringChecks: boolean;
587 /**
588 * Merge through a queue: pull requests are tested together with those
589 * ahead of them, and only a combination that passed reaches the default
590 * branch.
591 */
592 mergeQueue: boolean;
593 /**
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar594 * Refuse to merge until the code owners of every file it changes have
595 * approved, as many as each section asks. People only; `g1t` only where
596 * the file names `@g1t`.
597 */
598 requireCodeOwnerReview?: boolean;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet599 /** Username of the member who last changed the settings, if anyone has. */
600 updatedBy: string | null;
601 /** RFC 3339. */
602 updatedAt: string | null;
603};
604
605/** The settings a member can change. */
606export type RepoSettingsInput = Omit<RepoSettings, "updatedBy" | "updatedAt">;
607
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.608/**
609 * What the runner is to do next for a pull request: always nothing now,
610 * since no step of a pull request is carried out in a sandbox any more.
611 */
612export type Advance = { action: "none" };
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet613
614export type OpenIssueInput = {
615 title: string;
616 body: string;
617 labels?: string[];
618 /** Deprecated: commands, added to the body under "Definition of done". */
619 checks?: string[];
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar620 /** The number of the milestone to put it in. Needs the Triage role. */
621 milestone?: number;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet622};
623
624export type UpdateIssueInput = {
625 title?: string;
626 body?: string;
627 labels?: string[];
628 /** Usernames of the people it is assigned to; replaces the whole set. */
629 assignees?: string[];
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar630 /** The number of the milestone to put it in; 0 takes it out. */
631 milestone?: number;
Merge branch 'worktree-agent-a6ec0a89d7fe7a9ae'632 /** The issues of the same repository that have to land first; replaces the whole set. */
633 blocked_by?: number[];
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet634};
635
636export type OpenPullInput = {
637 /** The number of the issue this is for. */
638 issue?: number;
639 /** Defaults to the issue's title; required without an issue. */
640 title?: string;
641 /** What changed and why. Usually set later, when a draft is marked ready. */
642 body?: string;
643 /**
644 * A branch of the repository that already holds the change. The pull
645 * request is then ready for review at once and has no fork.
646 */
647 branch?: string;
648 agent: string;
649 runtime: Runtime;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar650 /** The branch to merge into: the default branch when left out. */
651 base?: string;
Open a pull request as a draft: it can't merge, and agents' review routines wait, until it is marked ready652 /**
653 * Opened from a branch as a draft, still being worked on: it can't merge,
654 * and agents' review routines wait, until it is marked ready.
655 */
656 draft?: boolean;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet657};
658
659/** One repository's pull requests from `pullsForRepos`, newest first. */
660export type RepoPulls = {
661 repoId: string;
662 /** Draft and open. */
663 open: Pull[];
664 /** Merged and closed. */
665 closed: Pull[];
666};
667
668/** Issues, pull requests, comments and sessions. */
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'669export interface WorkApi extends RulesApi, ChecksApi, CoordinationApi {
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet670 openIssue(actor: User, repo: RepoPath, input: OpenIssueInput): Promise<Result<Issue>>;
671 /** Newest first. */
672 listIssues(
673 repo: RepoPath,
674 viewer: Viewer,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar675 filter?: { state?: State; label?: string; milestone?: number },
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet676 ): Promise<Result<Issue[]>>;
677 getIssue(repo: RepoPath, number: number, viewer: Viewer): Promise<Result<IssueDetail>>;
678 /** The author or a member of the workspace may. */
679 updateIssue(actor: User, repo: RepoPath, number: number, input: UpdateIssueInput): Promise<Result<Issue>>;
680 closeIssue(actor: User, repo: RepoPath, number: number, reason?: IssueReason): Promise<Result<Issue>>;
681 reopenIssue(actor: User, repo: RepoPath, number: number): Promise<Result<Issue>>;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar682 /** A repository's labels, by name, each with how many issues and pull requests carry it. */
683 listLabels(repo: RepoPath, viewer: Viewer): Promise<Result<Label[]>>;
684 /**
685 * Creates a label, or with `name` changes one; renaming it renames it on
686 * everything that carries it. Needs the Triage role.
687 */
688 saveLabel(
689 actor: User,
690 repo: RepoPath,
691 label: { name?: string; newName?: string; color?: string; description?: string },
692 ): Promise<Result<Label>>;
693 /** Removes a label from the repository and everything carrying it. */
694 deleteLabel(actor: User, repo: RepoPath, name: string): Promise<Result<boolean>>;
695 /** Adds the default labels the repository does not have yet; returns them all. */
696 addDefaultLabels(actor: User, repo: RepoPath): Promise<Result<Label[]>>;
697 /**
698 * The labels of an issue or a pull request, replaced, added to or taken
699 * from. Labels the repository lacks are created for someone with the
700 * Triage role. Returns its labels now.
701 */
702 setLabels(
703 actor: User,
704 repo: RepoPath,
705 number: number,
706 labels: string[],
707 change?: LabelChange,
708 ): Promise<Result<string[]>>;
709 /** Open ones by due date, then closed ones; both unless `state` says. */
710 listMilestones(repo: RepoPath, viewer: Viewer, state?: State): Promise<Result<Milestone[]>>;
711 getMilestone(repo: RepoPath, number: number, viewer: Viewer): Promise<Result<MilestoneDetail>>;
712 /** Creates a milestone, or with `number` changes the fields given. Needs the Triage role. */
713 saveMilestone(
714 actor: User,
715 repo: RepoPath,
716 milestone: { number?: number; title?: string; description?: string; dueOn?: string; state?: State },
717 ): Promise<Result<Milestone>>;
718 deleteMilestone(actor: User, repo: RepoPath, number: number): Promise<Result<boolean>>;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet719 /** How many issues and pull requests are open. */
720 counts(repo: RepoPath, viewer: Viewer): Promise<Result<{ issues: number; pulls: number }>>;
721
722 /**
723 * On an issue or a pull request. On a pull request it may name a line of
724 * the change and carry a verdict; nobody can give a verdict on their own.
725 */
726 addComment(actor: User, repo: RepoPath, number: number, comment: NewComment): Promise<Result<Comment>>;
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts727 /**
728 * Changes a comment's text. Its author may, and so may anyone with the
729 * Maintain role or higher; notes of what happened cannot be changed.
730 */
731 editComment(actor: User, repo: RepoPath, commentId: string, body: string): Promise<Result<Comment>>;
732 /**
733 * Deletes a comment: its author, or anyone with the Maintain role or
734 * higher. A review that gave a verdict cannot be deleted, only edited.
735 */
736 deleteComment(actor: User, repo: RepoPath, commentId: string): Promise<Result<boolean>>;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet737
738 /**
739 * Always refused now: a pull request's checks are the workflows run on
740 * it. Kept for a runner from before.
741 */
742 startChecks(pullId: string): Promise<Result<CheckJob>>;
743 /**
744 * What a sandbox says about a run from before checks were workflows: so
745 * one still finishing is recorded.
746 */
747 reportChecks(runId: string, token: string, report: CheckReport): Promise<Result<CheckRun>>;
748 /**
749 * Claims the probe of whether a pull request merges cleanly that a
750 * `pull.mergecheck` event asked for. Refused when it is no longer wanted
751 * or the repository has as many running as it may. For the runner service.
752 */
753 startMergecheck(pullId: string): Promise<Result<MergecheckJob>>;
754 /** Records that a probe could not be carried out. For the runner service. */
755 failMergecheck(pullId: string, token: string, error: string): Promise<Result<Mergeable>>;
756
757 /**
758 * Works out the next step for a pull request g1t is seeing through and,
759 * if there is one to take now, claims it, so that it is taken once
760 * however often this is called. For the runner service.
761 */
762 advance(pullId: string): Promise<Advance>;
763 /** Records that a step could not be carried out, so a person is asked. */
764 stall(pullId: string, reason: string): Promise<boolean>;
765 /** Ids of the open pull requests g1t is seeing through. */
766 managedPulls(repoId?: string): Promise<string[]>;
767
768 /** A repository's merge queue: what is in it, in order, and what recently left. */
769 queue(repo: RepoPath, viewer: Viewer): Promise<Result<QueueView>>;
770 /**
771 * The next batch of combined states to test for a repository, one per
772 * entry; empty while a batch is being tested or nothing waits.
773 */
774 queueBuild(repoId: string): Promise<QueueJob[]>;
775 /** Reports that a combined state could not be built or checked. */
776 failQueue(entryId: string, token: string, error: string): Promise<Result<QueueState>>;
777 /** Takes a pull request out of the merge queue. Members only. */
778 removeFromQueue(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
779
780 getSettings(repo: RepoPath, viewer: Viewer): Promise<Result<RepoSettings>>;
781 /** The check names reported on the repository's commits in the last 30 days, most recent first. */
782 seenChecks(repo: RepoPath, viewer: Viewer): Promise<Result<SeenCheck[]>>;
783 /** Members of the repository's workspace only. */
784 updateSettings(actor: User, repo: RepoPath, settings: RepoSettingsInput): Promise<Result<RepoSettings>>;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar785 /** The CODEOWNERS file at a branch (the default when left out), checked. Needs Read. */
786 codeownersErrors(repo: RepoPath, viewer: Viewer, ref?: string | null): Promise<Result<CodeownersReport>>;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet787
788 /**
789 * Opens a pull request: a draft with a fork to push to, or, given a
790 * branch, one ready for review.
791 */
792 openPull(actor: User, repo: RepoPath, input: OpenPullInput): Promise<Result<Pull>>;
793 /** Newest first. */
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar794 listPulls(
795 repo: RepoPath,
796 viewer: Viewer,
797 state?: State,
798 filter?: { label?: string; milestone?: number; base?: string },
799 ): Promise<Result<Pull[]>>;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet800 /**
801 * The newest `limit` open and closed pull requests of each repository,
802 * in one call. Repositories the viewer cannot read, and forks, are left
803 * out: ask those with `listPulls`.
804 */
805 pullsForRepos(repoIds: string[], viewer: Viewer, limit: number): Promise<RepoPulls[]>;
806 getPull(repo: RepoPath, number: number, viewer: Viewer): Promise<Result<PullDetail>>;
807 /**
808 * Changes who a pull request is assigned to and whose review is asked
809 * for; each list given replaces the whole set. Asking for `g1t`'s
810 * review does not by itself start one: the runner's `review` does.
811 */
812 updatePull(
813 actor: User,
814 repo: RepoPath,
815 number: number,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar816 changes: {
817 assignees?: string[];
818 reviewers?: string[];
819 labels?: string[];
820 /** 0 takes it out of its milestone. */
821 milestone?: number;
822 /** The branch it merges into. Needs the Write role. */
823 base?: string;
824 },
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet825 ): Promise<Result<Pull>>;
826 /**
827 * Brings a pull request up to date with the default branch in seconds,
828 * without a sandbox, when the two changed different files: the merge
829 * commit is pushed to its branch as `actor`, who must be whoever opened
830 * it (for a fork) or a member (for a branch). Otherwise `needs_agent`, and
831 * nothing is pushed: the runner's `update` is the way on.
832 */
833 catchUpPull(actor: User, repo: RepoPath, number: number): Promise<Result<PullBranchUpdate>>;
834 /** Marks a draft ready for review and sets its description. */
835 readyPull(actor: User, repo: RepoPath, number: number, summary: string): Promise<Result<Pull>>;
836 closePull(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts837 /** Opens a closed pull request again, as the draft it was if it was closed as one. Never a merged one. */
838 reopenPull(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
839 /** Turns an open pull request back into a draft; it leaves the merge queue. */
840 convertPullToDraft(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet841 /**
842 * Lands the pull request on the repository's default branch. Unless
843 * `keepIssueOpen`, that resolves the issue it was for: the issue closes
844 * naming this pull request, and the others still in progress for it close
845 * as superseded. Only members of the repository's workspace may merge.
846 *
847 * If the default branch has moved, the pull request is brought up to date
848 * first and lands when that is done; it comes back still open, and
849 * `PullDetail.landing` is true meanwhile. A repository that requires pull
850 * requests to be up to date refuses instead.
851 */
852 mergePull(
853 actor: User,
854 repo: RepoPath,
855 number: number,
856 options?: {
857 keepIssueOpen?: boolean;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge858 /** Merge although required checks have not passed, where the rule requiring them allows it. */
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet859 ignoreChecks?: boolean;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge860 /** Merge past rules a ruleset lets the actor bypass. Recorded as a bypass. */
861 bypassRules?: boolean;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet862 },
863 ): Promise<Result<Pull>>;
864 /**
865 * Drafts and open pull requests the viewer started, most recently active
866 * first, each with where it stands if g1t is seeing it through.
867 */
868 listActivePulls(
869 viewer: Viewer,
870 ): Promise<{ pull: Pull; issue: Issue | null; lifecycle: Lifecycle | null }[]>;
871 /**
872 * The issues and pull requests a person opened, a page at a time, only
873 * on repositories the viewer may read. Not found for no such account.
874 */
875 byAuthor(username: string, viewer: Viewer, filter?: AuthoredFilter): Promise<Result<Authored>>;
Chat controls, public profiles, shadcn selects, and no Docs tab in a project876 /**
877 * What a person did each day of the last year (issues and pull requests
878 * opened, reviews given), only on repositories the viewer may read: the
879 * calendar on their profile. Not found for no such account.
880 */
881 contributions(username: string, viewer: Viewer): Promise<Result<Contributions>>;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet882
883
884 /** Open issues assigned to the viewer, most recently changed first. */
885 listAssignedIssues(viewer: Viewer): Promise<Issue[]>;
886
887 appendSession(actor: User, repo: RepoPath, number: number, entries: NewSessionEntry[]): Promise<Result<{ count: number }>>;
888 readSession(repo: RepoPath, number: number, viewer: Viewer, afterSeq?: number): Promise<Result<SessionEntry[]>>;
889}
890
891/**
892 * What to pass `ReposApi.compare` to see what a pull request changes.
893 *
894 * A fork is compared as a whole. A branch is compared by name while the
895 * pull request is open, and by the commit it was merged or closed at
896 * afterwards, so later pushes to the branch do not change the record.
897 */
898export function pullComparison(pull: Pull): {
899 repoId: string;
900 base: string | null;
901 head: string | null;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar902 /** The branch it merges into, which it is compared from. */
903 baseBranch: string | null;
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet904} {
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar905 const baseBranch = pull.base ?? null;
906 if (pull.forkRepoId) return { repoId: pull.forkRepoId, base: pull.mergeBase, head: null, baseBranch };
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet907 const settled = pull.status === "merged" || pull.status === "closed";
908 return {
909 repoId: pull.repoId,
910 base: pull.mergeBase,
911 head: (settled && pull.headCommit) || pull.branch,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar912 baseBranch,
Code button: the SSH tab shows the address it will have, disabled, with why it is not on yet913 };
914}
915
916
917export type QueueState = "waiting" | "testing" | "passed" | "failed" | "landed" | "removed";
918
919/** One pull request's place in a merge queue. */
920export type QueueEntry = {
921 id: string;
922 number: number;
923 title: string;
924 agent: string;
925 state: QueueState;
926 /** The pull requests merged ahead of it in the state being tested, in order. */
927 ahead: number[];
928 baseCommit: string | null;
929 combinedCommit: string | null;
930 error: string | null;
931 results: CheckResult[];
932 /** Username of whoever merged it into the queue: a person, or `g1t`. */
933 enqueuedBy: string;
934 /** RFC 3339. */
935 createdAt: string;
936 /** RFC 3339. */
937 finishedAt: string | null;
938};
939
940/** A repository's merge queue: what is in it, in order, and what recently left. */
941export type QueueView = {
942 enabled: boolean;
943 active: QueueEntry[];
944 /** Newest first. */
945 recent: QueueEntry[];
946};
947
948export type QueueStackItem = {
949 number: number;
950 title: string;
951 /** The repository holding the change, and its branch. */
952 source: RepoPath;
953 branch: string;
954 commit: string;
955};
956
957/** What a sandbox needs to build and check one combined state. */
958export type QueueJob = {
959 entryId: string;
960 token: string;
961 repo: RepoPath;
962 defaultBranch: string;
963 baseCommit: string;
964 branch: string;
965 stack: QueueStackItem[];
966 /** Always empty: the state is checked by the merge_group workflows run on it. */
967 checks: string[];
968 /** Always empty, as `checks`. */
969 contractChecks: string[];
970 actor: User;
971};
972
973// --- A person's work ---------------------------------------------------------
974// Mirrors the `Authored*` types in `crates/contracts/src/work.rs`.
975
976export type AuthoredKind = "issue" | "pull";
977/** `closed` takes in merged pull requests too; `merged` is only those. */
978export type AuthoredState = "open" | "closed" | "merged";
979/** `created` is newest first, `updated` most recently changed, `oldest` oldest first. */
980export type AuthoredSort = "created" | "updated" | "oldest";
981
982/** The most items one `byAuthor` page holds. */
983export const AUTHORED_PAGE = 25;
984
985export type AuthoredFilter = {
986 kind?: AuthoredKind;
987 state?: AuthoredState;
988 /** `namespace/name`. */
989 repo?: string;
990 sort?: AuthoredSort;
991 /** The `next` of the page before. */
992 before?: string;
993 limit?: number;
994};
995
996export type AuthoredItem = {
997 kind: AuthoredKind;
998 repo: RepoPath;
999 number: number;
1000 title: string;
1001 /** A merged pull request is closed. */
1002 state: State;
1003 /** A pull request's own status; null on an issue. */
1004 status: PullStatus | null;
1005 /** Why an issue was closed. */
1006 reason: IssueReason | null;
1007 draft: boolean;
1008 merged: boolean;
1009 /** RFC 3339. */
1010 createdAt: string;
1011 /** RFC 3339. */
1012 updatedAt: string;
1013 /** RFC 3339. */
1014 mergedAt: string | null;
1015};
1016
1017/** Over every repository the viewer may read, whatever the filters. */
1018export type AuthoredCounts = {
1019 pullsMerged: number;
1020 pullsOpen: number;
1021 pulls: number;
1022 issues: number;
1023 issuesOpen: number;
1024};
1025
1026export type Authored = {
1027 items: AuthoredItem[];
1028 /** Pass as `before` for the next page; null on the last. */
1029 next: string | null;
1030 counts: AuthoredCounts;
1031 /** The repositories they worked in that the viewer may read, most work first. */
1032 repos: { repo: RepoPath; count: number }[];
1033};
Chat controls, public profiles, shadcn selects, and no Docs tab in a project1034
1035// Mirrors `Contributions` in `crates/contracts/src/work.rs`.
1036
1037/** How many days `contributions` covers: today and the 364 before it. */
1038export const CONTRIBUTION_DAYS = 365;
1039
1040/** One day with something on it; days with nothing are left out. */
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar1041export type ContributionDay = {
1042 /** `YYYY-MM-DD`, UTC. */
1043 date: string;
1044 /** Everything that day, commits included. */
1045 count: number;
1046 /** How many of `count` are commits they pushed to a default branch. */
1047 commits?: number;
1048};
Chat controls, public profiles, shadcn selects, and no Docs tab in a project1049
1050/** A person's year, as far as the viewer may see. */
1051export type Contributions = {
1052 /** Oldest first. */
1053 days: ContributionDay[];
1054 total: number;
1055 /** The first day counted, `YYYY-MM-DD`; the last is today (UTC). */
1056 from: string;
1057};
Merge branch 'worktree-agent-a6ec0a89d7fe7a9ae'1058
1059// --- Coordinating work: sessions, claims and dependencies -----------------
1060// Mirrors `crates/contracts/src/work/coordination.rs`.
1061
1062/** The harness a session runs in. */
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1063export type Harness = "claude_code" | "claude_managed_agents" | "codex" | "cursor" | "copilot" | "other";
Merge branch 'worktree-agent-a6ec0a89d7fe7a9ae'1064
1065/** Active: heard from in 15 minutes; idle: not since; ended: ended, or quiet for 2 hours. */
1066export type SessionState = "active" | "idle" | "ended";
1067
1068/** One run of someone's own harness on a repository. */
1069export type WorkSession = {
1070 /** `ses_…`. */
1071 id: string;
1072 repoId: string;
1073 issue: number | null;
1074 pull: number | null;
1075 branch: string | null;
1076 actor: { id: string; username: string };
1077 harness: Harness;
1078 harnessSessionId: string | null;
1079 title: string | null;
1080 state: SessionState;
1081 headCommit: string | null;
1082 startedAt: string;
1083 lastSeenAt: string;
1084 endedAt: string | null;
1085 /** What the harness said, or `timed_out`. */
1086 endReason: string | null;
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1087 /** For a subagent: the session that started it. */
1088 parentId?: string | null;
1089 /** For a subagent: its kind (Explore, security-reviewer). */
1090 agentType?: string | null;
1091 /** For a subagent: the task it was given, in a few words. */
1092 task?: string | null;
1093 /** For a subagent: the prompt its parent gave it. */
1094 prompt?: string | null;
1095 /** What it reported when it finished: a subagent's final message. */
1096 result?: string | null;
1097 model?: string | null;
1098 /** How many subagents it started. */
1099 subagents?: number;
Merge branch 'worktree-agent-aef0bb4ceda89e542'1100 /** In a list, for one with no title: the start of the first prompt it recorded. */
1101 firstPrompt?: string | null;
Merge branch 'worktree-agent-a6ec0a89d7fe7a9ae'1102};
1103
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1104/** What kind of thing a session touched. */
1105export type TouchKind = "file" | "commit" | "branch" | "pull" | "issue";
1106
1107/** Something a session touched, kept once per session. */
1108export type SessionTouch = { sessionId: string; kind: TouchKind; value: string; at: string };
1109
1110/** How a session was tied to an issue or pull request. */
1111export type LinkVia = "attached" | "claim" | "branch" | "commit" | "trailer" | "opened" | "ref";
1112
1113/** An issue or pull request a session, or one of its subagents, worked on. */
1114export type SessionLink = {
1115 kind: "issue" | "pull";
1116 number: number;
1117 title: string;
1118 /** The issue's state or the pull request's status. */
1119 state: string;
1120 via: LinkVia[];
1121 sessionIds: string[];
1122};
1123
1124/** A skill a session used, by name. */
1125export type SessionSkill = { sessionId: string; name: string; uses: number };
1126
Merge branch 'worktree-agent-a6ec0a89d7fe7a9ae'1127export type ClaimState = "active" | "released" | "expired" | "handed_off";
1128
1129/** An advisory, expiring "I'm working on #N". Never a lock. */
1130export type Claim = {
1131 /** `clm_…`. */
1132 id: string;
1133 repoId: string;
1134 issue: number;
1135 sessionId: string | null;
1136 actor: { id: string; username: string };
1137 harness: Harness | null;
1138 note: string | null;
1139 state: ClaimState;
1140 createdAt: string;
1141 expiresAt: string;
1142 endedAt: string | null;
1143 endReason: string | null;
1144 /** For a hand-off: who it was handed to; null for anyone. */
1145 handoffTo: string | null;
1146};
1147
1148/** `session.started` and `session.ended`. */
1149export type SessionEventData = { repoId: string; number?: number; issue?: number; session: WorkSession };
1150
1151/** `work.claimed`, `work.released`, `work.claim_expired` and `work.handoff_requested`. */
1152export type ClaimEventData = {
1153 repoId: string;
1154 number: number;
1155 issue: number;
1156 claim: Claim;
1157 others?: Claim[];
1158 tookOver?: string;
1159 reason?: string;
1160 from?: string;
1161 to?: string;
1162 note?: string;
1163};
1164
1165/** `dependency.changed`. */
1166export type DependencyChangedData = {
1167 repoId: string;
1168 number: number;
1169 issue: number;
1170 blockedBy: number[];
1171 added: number[];
1172 removed: number[];
1173 cleared: number[];
1174 remaining: number[];
1175 mergedPull?: number;
1176};
1177
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1178/** `overlap.detected` between two pull requests, sent once for each side of a new overlap. */
1179export type PullOverlapData = {
Merge branch 'worktree-agent-a6ec0a89d7fe7a9ae'1180 repoId: string;
1181 number: number;
1182 pull: number;
1183 otherPull: number;
1184 files: string[];
1185 issue?: number;
1186 otherIssue?: number;
1187};
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'1188
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1189/** `overlap.detected` between two sessions that touched the same files (siblings included), once for each side. */
1190export type SessionOverlapData = {
1191 repoId: string;
1192 number?: number;
1193 sessionId: string;
1194 otherSessionId: string;
1195 otherActor: string;
1196 files: string[];
1197 issue?: number;
1198 otherIssue?: number;
1199};
1200
1201/** `overlap.detected`: between pull requests, or between sessions (with `sessionId`). */
1202export type OverlapDetectedData = PullOverlapData | SessionOverlapData;
1203
1204/** `session.progressed`: a session recorded more (at most every few seconds). */
1205export type SessionProgressedData = { repoId: string; number?: number; sessionId: string; rootId?: string };
1206
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'1207/** An issue in brief. */
1208export type IssueBrief = { number: number; title: string; state: State };
1209
1210/** A pull request in brief. */
1211export type PullBrief = { number: number; title: string; status: PullStatus };
1212
1213/** An issue another is blocked by, and where it stands. */
1214export type Blocker = {
1215 number: number;
1216 title: string;
1217 state: State;
1218 /** Active claims on it. */
1219 claims: Claim[];
1220 pulls: PullBrief[];
1221};
1222
1223/** A pull request's place in the merge queue; `position` 1 is the front. */
1224export type QueuePlace = { state: QueueState; position: number };
1225
1226/** One of an issue's pull requests, with where it stands. */
1227export type WorkPull = {
1228 number: number;
1229 title: string;
1230 status: PullStatus;
1231 branch: string | null;
1232 headCommit: string | null;
1233 author: { id: string; username: string };
1234 /** `failed` when the merge queue took it out, until its head moves. */
1235 checkStatus: CheckStatus | null;
1236 requiredChecks: RequiredCheck[];
1237 mergeable: Mergeable;
1238 /** Other pull requests in progress changing the same files. */
1239 overlaps: Overlap[];
1240 /** Its place in the merge queue, while it is in it. */
1241 queue: QueuePlace | null;
1242};
1243
1244// --- Decision records (crates/contracts/src/decisions.rs) ------------------
1245
1246export type DecisionKind =
1247 | "proposal"
1248 | "claim"
1249 | "integration_failure"
1250 | "integration_passed"
1251 | "fix"
1252 | "approval"
1253 | "merge"
1254 | "note";
1255
1256/** Claimed: someone said so. Tested: a check or the merge queue proved it. Approved: a person approved it. */
1257export type DecisionConfidence = "claimed" | "tested" | "approved";
1258
1259/** A structured reason kept on an issue or pull request, with how sure it is. */
1260export type Decision = {
1261 /** `dec_…`. */
1262 id: string;
1263 issue: number | null;
1264 pull: number | null;
1265 sessionId: string | null;
1266 /** Username of who recorded it; null when g1t did. */
1267 actor: string | null;
1268 kind: DecisionKind;
1269 confidence: DecisionConfidence;
1270 summary: string;
1271 /**
1272 * What it rests on, kept as recorded, in snake_case: `commit`, `check`
1273 * (`name`, `conclusion`, `url`), `combination`, `other_pulls`,
1274 * `suspects`, `bisected`, `merge_queue`.
1275 */
1276 evidence: Record<string, unknown>;
1277 /** RFC 3339. */
1278 createdAt: string;
1279};
1280
1281/** Everything about an issue an agent needs to pick it up: `get_work`. */
1282export type WorkContext = {
1283 issue: Issue;
1284 /** The items under its "Definition of done" heading. */
1285 definitionOfDone: string[];
1286 /** The checks every pull request into the default branch must pass. */
1287 requiredChecks: string[];
1288 /** Active claims on it. */
1289 claims: Claim[];
1290 /** Sessions on it or its pull requests, most recently heard from first. */
1291 sessions: WorkSession[];
1292 pulls: WorkPull[];
1293 blockedBy: Blocker[];
1294 /** The issues it blocks. */
1295 blocks: IssueBrief[];
1296 /** On it and its pull requests, newest first. */
1297 decisions: Decision[];
1298 /** The latest `integration_failure` decision among them. */
1299 lastIntegrationFailure: Decision | null;
1300 /** Its latest coordination events, newest first. */
1301 recent: G1tEvent[];
1302};
1303
1304/** A harness session and what it recorded. */
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1305export type WorkSessionDetail = {
1306 session: WorkSession;
1307 entries: SessionEntry[];
1308 /** Its subagents and theirs, in the order they started. */
1309 children?: WorkSession[];
1310 /** What it and its subagents touched. */
1311 touched?: SessionTouch[];
1312 /** The issues and pull requests it and its subagents worked on. */
1313 links?: SessionLink[];
1314 skills?: SessionSkill[];
1315 /** For a subagent: the session at the top of its tree. */
1316 root?: WorkSession | null;
1317};
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'1318
1319/** Reading coordination: work service methods (services/work/src/coordination, decisions.rs). */
1320export interface CoordinationApi {
1321 getWork(repo: RepoPath, number: number, viewer: Viewer): Promise<Result<WorkContext>>;
1322 /** Newest first; active ones unless `state` says otherwise. */
1323 listClaims(repo: RepoPath, viewer: Viewer, filter?: { state?: ClaimState; issue?: number }): Promise<Result<Claim[]>>;
1324 /** Most recently heard from first. */
1325 listWorkSessions(
1326 repo: RepoPath,
1327 viewer: Viewer,
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1328 filter?: { state?: SessionState; issue?: number; pull?: number; path?: string; subagents?: boolean },
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'1329 ): Promise<Result<WorkSession[]>>;
1330 getWorkSession(repo: RepoPath, id: string, viewer: Viewer, afterSeq?: number): Promise<Result<WorkSessionDetail>>;
1331 /** An issue's (with its pull requests') or a pull request's, oldest first. */
1332 listDecisions(repo: RepoPath, number: number, viewer: Viewer): Promise<Result<Decision[]>>;
1333}

This file's history is long; its oldest lines are credited to the oldest commit read.