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
308 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 branch 'worktree-agent-aa68cf6ecc03dffaf'1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { Claim, Decision, G1tEvent, WorkSession } from "@g1t/contracts";
5
6import {
7 checkHref,
8 evidenceOf,
9 expiresIn,
10 feedLine,
11 harnessName,
Merge branch 'worktree-agent-aef0bb4ceda89e542'12 intentTitle,
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'13 liveByIssue,
Merge branch 'worktree-agent-aef0bb4ceda89e542'14 sessionTitle,
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.15 duration,
16 mergeSessions,
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'17 numberedParts,
18 parseBlockedBy,
19 resolutionOf,
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.20 sessionTree,
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'21 span,
22 standingFailure,
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.23 touchedByKind,
24 treeSize,
25 viaLabel,
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'26} from "./coordination.ts";
27
28const ana = { id: "usr_ana", username: "ana" };
29const bo = { id: "usr_bo", username: "bo" };
30
31function claim(issue: number, over: Partial<Claim> = {}): Claim {
32 return {
33 id: `clm_${issue}_${over.actor?.username ?? "ana"}`,
34 repoId: "rep_1",
35 issue,
36 sessionId: null,
37 actor: ana,
38 harness: "claude_code",
39 note: null,
40 state: "active",
41 createdAt: "2026-10-12T10:00:00Z",
42 expiresAt: "2026-10-12T10:30:00Z",
43 endedAt: null,
44 endReason: null,
45 handoffTo: null,
46 ...over,
47 };
48}
49
50function session(id: string, over: Partial<WorkSession> = {}): WorkSession {
51 return {
52 id,
53 repoId: "rep_1",
54 issue: null,
55 pull: null,
56 branch: null,
57 actor: bo,
58 harness: "codex",
59 harnessSessionId: null,
60 title: null,
61 state: "active",
62 headCommit: null,
63 startedAt: "2026-10-12T10:00:00Z",
64 lastSeenAt: "2026-10-12T10:05:00Z",
65 endedAt: null,
66 endReason: null,
67 ...over,
68 };
69}
70
71function decision(kind: Decision["kind"], at: string, over: Partial<Decision> = {}): Decision {
72 return {
73 id: `dec_${kind}_${at}`,
74 issue: 2,
75 pull: 5,
76 sessionId: null,
77 actor: null,
78 kind,
79 confidence: "tested",
80 summary: kind,
81 evidence: {},
82 createdAt: at,
83 ...over,
84 };
85}
86
87const event = (type: string, data: unknown): G1tEvent =>
88 ({ id: `evt_${type}`, type, source: "work", time: "2026-10-12T10:00:00Z", repoId: "rep_1", actor: "usr_ana", data }) as G1tEvent;
89
90test("harnesses are named as people know them", () => {
91 assert.equal(harnessName("claude_code"), "Claude Code");
92 assert.equal(harnessName("codex"), "Codex");
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.93 assert.equal(harnessName("claude_managed_agents"), "Claude Managed Agents");
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'94 assert.equal(harnessName(null), null);
95});
96
97test("a claim says when it lapses; one that ended says nothing", () => {
98 const now = Date.parse("2026-10-12T10:07:00Z");
99 assert.equal(expiresIn(claim(1), now), "expires in 23m");
100 assert.equal(expiresIn(claim(1, { expiresAt: "2026-10-12T12:00:00Z" }), now), "expires in 1h 53m");
101 assert.equal(expiresIn(claim(1, { expiresAt: "2026-10-12T10:00:00Z" }), now), "expiring now");
102 assert.equal(expiresIn(claim(1, { state: "released" }), now), null);
103 assert.equal(span(30_000), "less than a minute");
104 assert.equal(span(2 * 3_600_000), "2h");
105});
106
107test("live work is grouped by issue, most recent first, with sessions on no issue apart", () => {
108 const { issues, loose } = liveByIssue(
109 [claim(1), claim(2, { createdAt: "2026-10-12T10:20:00Z" }), claim(2, { actor: bo })],
110 [session("ses_a", { issue: 1, lastSeenAt: "2026-10-12T10:30:00Z" }), session("ses_b")],
111 );
112 assert.deepEqual(
113 issues.map((group) => [group.issue, group.claims.length, group.sessions.length]),
114 [
115 [1, 1, 1],
116 [2, 2, 0],
117 ],
118 );
119 assert.deepEqual(loose.map((one) => one.id), ["ses_b"]);
120});
121
Merge branch 'worktree-agent-aef0bb4ceda89e542'122test("sessions on no issue are grouped by pull request, then by a branch of their own, then the rest together", () => {
123 const seen = (minute: number) => `2026-10-12T10:${String(minute).padStart(2, "0")}:00Z`;
124 const { issues, groups, loose } = liveByIssue(
125 [],
126 [
127 session("ses_main", { branch: "main", lastSeenAt: seen(50) }),
128 session("ses_fix1", { branch: "fix-previews", lastSeenAt: seen(10) }),
129 session("ses_pr", { pull: 12, branch: "tidy-readme", lastSeenAt: seen(20) }),
130 session("ses_fix2", { branch: "fix-previews", lastSeenAt: seen(40) }),
131 session("ses_none", { lastSeenAt: seen(30) }),
132 session("ses_issue", { issue: 3, branch: "3-x", lastSeenAt: seen(5) }),
133 ],
134 "main",
135 );
136 assert.deepEqual(issues.map((group) => group.issue), [3]);
137 assert.deepEqual(
138 groups.map((group) => [group.kind === "pull" ? `#${group.pull}` : group.kind === "branch" ? group.branch : "none", group.sessions.map((one) => one.id)]),
139 [
140 // The most recently heard from first; the rest, on no branch of their own (the default branch is none), last.
141 ["fix-previews", ["ses_fix2", "ses_fix1"]],
142 ["#12", ["ses_pr"]],
143 ["none", ["ses_main", "ses_none"]],
144 ],
145 );
146 assert.deepEqual(loose.map((one) => one.id), ["ses_fix2", "ses_fix1", "ses_pr", "ses_main", "ses_none"]);
147 // Without the default branch known, its sessions are a branch's.
148 assert.equal(liveByIssue([], [session("ses_main", { branch: "main" })]).groups[0].kind, "branch");
149});
150
151test("a session is never title-less: its title, its first prompt's intent, its branch, or untitled", () => {
152 assert.equal(sessionTitle({ title: "Rewrite the auth flow", branch: "auth", firstPrompt: "fix it" }), "Rewrite the auth flow");
153 assert.equal(sessionTitle({ title: null, branch: "auth", firstPrompt: "fix the login redirect. It loops." }), "Fix the login redirect");
154 assert.equal(sessionTitle({ title: " ", branch: "auth", firstPrompt: "/clear" }), "Session on auth");
155 assert.equal(sessionTitle({ title: null, branch: null }), "Untitled session");
156 assert.equal(sessionTitle({ title: null, branch: null }, "look at the CI"), "Look at the CI", "a first prompt given stands in");
157});
158
159test("a prompt's intent is its first line or sentence, plain, clipped on a word", () => {
160 assert.equal(intentTitle("Make preview builds faster. They time out on big repositories."), "Make preview builds faster");
161 assert.equal(intentTitle("Why does `src/app.ts` fail? It worked yesterday."), "Why does src/app.ts fail?");
162 assert.equal(intentTitle("```js\nconst a = 1;\n```\n## Clean **this** up\nmore"), "Clean this up");
163 assert.equal(intentTitle("\n\n- look at [the docs](https://docs.g1t.sh) for g1t.mjs"), "Look at the docs for g1t.mjs");
164 const long = intentTitle("Tidy up the README and then look at the CI pipeline, which keeps failing on the Windows runners every night")!;
165 assert.ok(long.length <= 80 && long.endsWith("…") && !long.endsWith(" …"), long);
166 for (const prompt of ["/clear", "/g1t:status 4", "<command-name>/clear</command-name>", "```\ncode only\n```", "?", "", null]) {
167 assert.equal(intentTitle(prompt), null, String(prompt));
168 }
169});
170
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'171test("evidence is read as far as it goes", () => {
172 const failed = decision("integration_failure", "2026-10-12T10:00:00Z", {
173 evidence: { commit: "abc1234", check: { name: "CI / merge_group", conclusion: "failure", url: "https://g1t.sh/acme/web/actions/runs/run_1" }, combination: [4, 5], suspects: [4], bisected: false },
174 });
175 assert.deepEqual(evidenceOf(failed), {
176 commit: "abc1234",
177 check: { name: "CI / merge_group", conclusion: "failure", url: "https://g1t.sh/acme/web/actions/runs/run_1" },
178 combination: [4, 5],
179 suspects: [4],
180 bisected: false,
181 });
182 assert.deepEqual(evidenceOf(decision("note", "2026-10-12T10:00:00Z", { evidence: { combination: "nope" } })).combination, []);
183 assert.equal(checkHref("https://g1t.sh/acme/web/actions/runs/run_1"), "/acme/web/actions/runs/run_1");
184 assert.equal(checkHref("https://ci.example.com/build/9"), "https://ci.example.com/build/9");
185 assert.equal(checkHref(null), null);
186});
187
188test("a failure stands until the pull request passes in the queue or merges, and a fix after it answers it", () => {
189 const failed = decision("integration_failure", "2026-10-12T10:00:00Z");
190 const fix = decision("fix", "2026-10-12T10:10:00Z", { confidence: "claimed" });
191 const passed = decision("integration_passed", "2026-10-12T10:20:00Z");
192 assert.equal(standingFailure([failed], 5), failed);
193 assert.equal(standingFailure([failed, fix], 5), failed);
194 assert.equal(standingFailure([passed, failed], 5), null);
195 assert.equal(standingFailure([failed], 6), null);
196 assert.deepEqual(resolutionOf([failed, fix, passed], failed), { fix, passed });
197 assert.deepEqual(resolutionOf([fix, failed], { ...failed, createdAt: "2026-10-12T10:15:00Z" }), { fix: null, passed: null });
198});
199
200test("coordination events read as lines of the feed", () => {
201 const claimed = feedLine(event("work.claimed", { repoId: "rep_1", number: 2, issue: 2, claim: claim(2, { actor: bo, harness: "codex" }), others: [claim(2)] }))!;
202 assert.equal(claimed.who, "bo");
203 assert.equal(claimed.harness, "codex");
204 assert.equal(claimed.text, "claimed #2 (ana is on it too)");
205 assert.equal(claimed.tone, "warn");
206
207 const failed = feedLine(
208 event("integration.failed", {
209 repoId: "rep_1", pullId: "pul_5", number: 5, pull: 5, issue: 2, combination: [4, 5],
210 check: { name: "CI / merge_group", conclusion: "failure", url: null }, bisected: false, suspects: [4], otherPulls: [4], commit: null,
211 }),
212 )!;
213 assert.equal(failed.who, null);
214 assert.equal(failed.text, "#5 failed in the merge queue combined as #4, #5: CI / merge_group; fails with #4");
215 assert.equal(failed.tone, "danger");
216
217 const unblocked = feedLine(
218 event("dependency.changed", { repoId: "rep_1", number: 2, issue: 2, blockedBy: [1], added: [], removed: [], cleared: [1], remaining: [], mergedPull: 4 }),
219 )!;
220 assert.equal(unblocked.text, "#2 #1 landed (#4 merged); unblocked");
221
222 const overlap = feedLine(event("overlap.detected", { repoId: "rep_1", number: 5, pull: 5, otherPull: 4, files: ["src/auth.rs"] }))!;
223 assert.equal(overlap.text, "#5 and #4 change the same file: src/auth.rs");
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.224 assert.equal(overlap.session, undefined);
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'225
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.226 const sessions = feedLine(
227 event("overlap.detected", { repoId: "rep_1", sessionId: "ses_a", otherSessionId: "ses_b", otherActor: "bo", files: ["a.rs", "b.rs", "c.rs", "d.rs"], issue: 2 }),
228 )!;
229 assert.equal(sessions.who, "bo");
230 assert.equal(sessions.text, "touched the same files in a session as another session: a.rs, b.rs, c.rs and 1 more");
231 assert.equal(sessions.session, "ses_a");
232 assert.equal(sessions.number, 2);
233 assert.equal(feedLine(event("session.progressed", { repoId: "rep_1", number: 2, sessionId: "ses_a" })), null);
234
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'235 const started = feedLine(event("session.started", { repoId: "rep_1", session: session("ses_a", { issue: 2 }) }))!;
236 assert.equal(started.text, "started a session on #2");
237 assert.equal(feedLine(event("session.appended", { repoId: "rep_1", number: 5, pullId: "p", count: 3 })), null);
238});
239
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.240test("sessions become trees by their parents; one whose parent is missing is a root", () => {
241 const roots = sessionTree([
242 session("ses_root"),
243 session("ses_a", { parentId: "ses_root" }),
244 session("ses_a1", { parentId: "ses_a" }),
245 session("ses_b", { parentId: "ses_root" }),
246 session("ses_orphan", { parentId: "ses_gone" }),
247 session("ses_other"),
248 ]);
249 const shape = (nodes: ReturnType<typeof sessionTree>): unknown[] => nodes.map((node) => [node.session.id, shape(node.children)]);
250 assert.deepEqual(shape(roots), [
251 ["ses_root", [["ses_a", [["ses_a1", []]]], ["ses_b", []]]],
252 ["ses_orphan", []],
253 ["ses_other", []],
254 ]);
255 assert.equal(treeSize(roots[0]!), 3);
256 // A child listed before its parent still lands under it.
257 assert.deepEqual(shape(sessionTree([session("ses_c", { parentId: "ses_p" }), session("ses_p")])), [["ses_p", [["ses_c", []]]]]);
258 // A cycle does not lose sessions.
259 const cycle = sessionTree([session("ses_x", { parentId: "ses_y" }), session("ses_y", { parentId: "ses_x" })]);
260 assert.equal(cycle.length + cycle.reduce((n, node) => n + treeSize(node), 0), 2);
261 assert.deepEqual(sessionTree([]), []);
262 assert.deepEqual(
263 mergeSessions([session("ses_a"), session("ses_b")], null, [session("ses_b", { title: "later" }), session("ses_c")]).map((one) => [one.id, one.title]),
264 [
265 ["ses_a", null],
266 ["ses_b", null],
267 ["ses_c", null],
268 ],
269 );
270});
271
272test("how a session was tied to its work, what it touched, and how long it ran", () => {
273 assert.equal(viaLabel("attached"), "attached");
274 assert.equal(viaLabel("claim"), "claimed");
275 assert.equal(viaLabel("branch"), "its branch");
276 assert.equal(viaLabel("commit"), "its commit");
277 assert.equal(viaLabel("trailer"), "commit trailer");
278 assert.equal(viaLabel("opened"), "opened it");
279 assert.equal(viaLabel("ref"), "named it");
280 assert.deepEqual(
281 touchedByKind([
282 { kind: "commit", value: "abc" },
283 { kind: "file", value: "b.rs" },
284 { kind: "file", value: "a.rs" },
285 { kind: "file", value: "b.rs" },
286 ]),
287 [
288 { kind: "file", values: ["b.rs", "a.rs"] },
289 { kind: "commit", values: ["abc"] },
290 ],
291 );
292 const now = Date.parse("2026-10-12T10:30:00Z");
293 assert.equal(duration(session("ses_a"), now), "30m");
294 assert.equal(duration(session("ses_a", { state: "ended", endedAt: "2026-10-12T10:00:42Z" }), now), "42s");
295 assert.equal(duration(session("ses_a", { state: "ended", endedAt: null }), now), "5m");
296});
297
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'298test("numbers in a sentence are found for linking", () => {
299 assert.deepEqual(numberedParts("#5 fails with #4."), [5, " fails with ", 4, "."]);
300 assert.deepEqual(numberedParts("no numbers"), ["no numbers"]);
301});
302
303test("blocked_by is typed as numbers", () => {
304 assert.deepEqual(parseBlockedBy("#12, 14 #12"), [12, 14]);
305 assert.deepEqual(parseBlockedBy(""), []);
306 assert.equal(parseBlockedBy("#12, soon"), null);
307 assert.equal(parseBlockedBy("0"), null);
308});

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