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
257 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,
12 liveByIssue,
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.13 duration,
14 mergeSessions,
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'15 numberedParts,
16 parseBlockedBy,
17 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.18 sessionTree,
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'19 span,
20 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.21 touchedByKind,
22 treeSize,
23 viaLabel,
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'24} from "./coordination.ts";
25
26const ana = { id: "usr_ana", username: "ana" };
27const bo = { id: "usr_bo", username: "bo" };
28
29function claim(issue: number, over: Partial<Claim> = {}): Claim {
30 return {
31 id: `clm_${issue}_${over.actor?.username ?? "ana"}`,
32 repoId: "rep_1",
33 issue,
34 sessionId: null,
35 actor: ana,
36 harness: "claude_code",
37 note: null,
38 state: "active",
39 createdAt: "2026-10-12T10:00:00Z",
40 expiresAt: "2026-10-12T10:30:00Z",
41 endedAt: null,
42 endReason: null,
43 handoffTo: null,
44 ...over,
45 };
46}
47
48function session(id: string, over: Partial<WorkSession> = {}): WorkSession {
49 return {
50 id,
51 repoId: "rep_1",
52 issue: null,
53 pull: null,
54 branch: null,
55 actor: bo,
56 harness: "codex",
57 harnessSessionId: null,
58 title: null,
59 state: "active",
60 headCommit: null,
61 startedAt: "2026-10-12T10:00:00Z",
62 lastSeenAt: "2026-10-12T10:05:00Z",
63 endedAt: null,
64 endReason: null,
65 ...over,
66 };
67}
68
69function decision(kind: Decision["kind"], at: string, over: Partial<Decision> = {}): Decision {
70 return {
71 id: `dec_${kind}_${at}`,
72 issue: 2,
73 pull: 5,
74 sessionId: null,
75 actor: null,
76 kind,
77 confidence: "tested",
78 summary: kind,
79 evidence: {},
80 createdAt: at,
81 ...over,
82 };
83}
84
85const event = (type: string, data: unknown): G1tEvent =>
86 ({ id: `evt_${type}`, type, source: "work", time: "2026-10-12T10:00:00Z", repoId: "rep_1", actor: "usr_ana", data }) as G1tEvent;
87
88test("harnesses are named as people know them", () => {
89 assert.equal(harnessName("claude_code"), "Claude Code");
90 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.91 assert.equal(harnessName("claude_managed_agents"), "Claude Managed Agents");
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'92 assert.equal(harnessName(null), null);
93});
94
95test("a claim says when it lapses; one that ended says nothing", () => {
96 const now = Date.parse("2026-10-12T10:07:00Z");
97 assert.equal(expiresIn(claim(1), now), "expires in 23m");
98 assert.equal(expiresIn(claim(1, { expiresAt: "2026-10-12T12:00:00Z" }), now), "expires in 1h 53m");
99 assert.equal(expiresIn(claim(1, { expiresAt: "2026-10-12T10:00:00Z" }), now), "expiring now");
100 assert.equal(expiresIn(claim(1, { state: "released" }), now), null);
101 assert.equal(span(30_000), "less than a minute");
102 assert.equal(span(2 * 3_600_000), "2h");
103});
104
105test("live work is grouped by issue, most recent first, with sessions on no issue apart", () => {
106 const { issues, loose } = liveByIssue(
107 [claim(1), claim(2, { createdAt: "2026-10-12T10:20:00Z" }), claim(2, { actor: bo })],
108 [session("ses_a", { issue: 1, lastSeenAt: "2026-10-12T10:30:00Z" }), session("ses_b")],
109 );
110 assert.deepEqual(
111 issues.map((group) => [group.issue, group.claims.length, group.sessions.length]),
112 [
113 [1, 1, 1],
114 [2, 2, 0],
115 ],
116 );
117 assert.deepEqual(loose.map((one) => one.id), ["ses_b"]);
118});
119
120test("evidence is read as far as it goes", () => {
121 const failed = decision("integration_failure", "2026-10-12T10:00:00Z", {
122 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 },
123 });
124 assert.deepEqual(evidenceOf(failed), {
125 commit: "abc1234",
126 check: { name: "CI / merge_group", conclusion: "failure", url: "https://g1t.sh/acme/web/actions/runs/run_1" },
127 combination: [4, 5],
128 suspects: [4],
129 bisected: false,
130 });
131 assert.deepEqual(evidenceOf(decision("note", "2026-10-12T10:00:00Z", { evidence: { combination: "nope" } })).combination, []);
132 assert.equal(checkHref("https://g1t.sh/acme/web/actions/runs/run_1"), "/acme/web/actions/runs/run_1");
133 assert.equal(checkHref("https://ci.example.com/build/9"), "https://ci.example.com/build/9");
134 assert.equal(checkHref(null), null);
135});
136
137test("a failure stands until the pull request passes in the queue or merges, and a fix after it answers it", () => {
138 const failed = decision("integration_failure", "2026-10-12T10:00:00Z");
139 const fix = decision("fix", "2026-10-12T10:10:00Z", { confidence: "claimed" });
140 const passed = decision("integration_passed", "2026-10-12T10:20:00Z");
141 assert.equal(standingFailure([failed], 5), failed);
142 assert.equal(standingFailure([failed, fix], 5), failed);
143 assert.equal(standingFailure([passed, failed], 5), null);
144 assert.equal(standingFailure([failed], 6), null);
145 assert.deepEqual(resolutionOf([failed, fix, passed], failed), { fix, passed });
146 assert.deepEqual(resolutionOf([fix, failed], { ...failed, createdAt: "2026-10-12T10:15:00Z" }), { fix: null, passed: null });
147});
148
149test("coordination events read as lines of the feed", () => {
150 const claimed = feedLine(event("work.claimed", { repoId: "rep_1", number: 2, issue: 2, claim: claim(2, { actor: bo, harness: "codex" }), others: [claim(2)] }))!;
151 assert.equal(claimed.who, "bo");
152 assert.equal(claimed.harness, "codex");
153 assert.equal(claimed.text, "claimed #2 (ana is on it too)");
154 assert.equal(claimed.tone, "warn");
155
156 const failed = feedLine(
157 event("integration.failed", {
158 repoId: "rep_1", pullId: "pul_5", number: 5, pull: 5, issue: 2, combination: [4, 5],
159 check: { name: "CI / merge_group", conclusion: "failure", url: null }, bisected: false, suspects: [4], otherPulls: [4], commit: null,
160 }),
161 )!;
162 assert.equal(failed.who, null);
163 assert.equal(failed.text, "#5 failed in the merge queue combined as #4, #5: CI / merge_group; fails with #4");
164 assert.equal(failed.tone, "danger");
165
166 const unblocked = feedLine(
167 event("dependency.changed", { repoId: "rep_1", number: 2, issue: 2, blockedBy: [1], added: [], removed: [], cleared: [1], remaining: [], mergedPull: 4 }),
168 )!;
169 assert.equal(unblocked.text, "#2 #1 landed (#4 merged); unblocked");
170
171 const overlap = feedLine(event("overlap.detected", { repoId: "rep_1", number: 5, pull: 5, otherPull: 4, files: ["src/auth.rs"] }))!;
172 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.173 assert.equal(overlap.session, undefined);
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'174
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.175 const sessions = feedLine(
176 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 }),
177 )!;
178 assert.equal(sessions.who, "bo");
179 assert.equal(sessions.text, "touched the same files in a session as another session: a.rs, b.rs, c.rs and 1 more");
180 assert.equal(sessions.session, "ses_a");
181 assert.equal(sessions.number, 2);
182 assert.equal(feedLine(event("session.progressed", { repoId: "rep_1", number: 2, sessionId: "ses_a" })), null);
183
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'184 const started = feedLine(event("session.started", { repoId: "rep_1", session: session("ses_a", { issue: 2 }) }))!;
185 assert.equal(started.text, "started a session on #2");
186 assert.equal(feedLine(event("session.appended", { repoId: "rep_1", number: 5, pullId: "p", count: 3 })), null);
187});
188
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.189test("sessions become trees by their parents; one whose parent is missing is a root", () => {
190 const roots = sessionTree([
191 session("ses_root"),
192 session("ses_a", { parentId: "ses_root" }),
193 session("ses_a1", { parentId: "ses_a" }),
194 session("ses_b", { parentId: "ses_root" }),
195 session("ses_orphan", { parentId: "ses_gone" }),
196 session("ses_other"),
197 ]);
198 const shape = (nodes: ReturnType<typeof sessionTree>): unknown[] => nodes.map((node) => [node.session.id, shape(node.children)]);
199 assert.deepEqual(shape(roots), [
200 ["ses_root", [["ses_a", [["ses_a1", []]]], ["ses_b", []]]],
201 ["ses_orphan", []],
202 ["ses_other", []],
203 ]);
204 assert.equal(treeSize(roots[0]!), 3);
205 // A child listed before its parent still lands under it.
206 assert.deepEqual(shape(sessionTree([session("ses_c", { parentId: "ses_p" }), session("ses_p")])), [["ses_p", [["ses_c", []]]]]);
207 // A cycle does not lose sessions.
208 const cycle = sessionTree([session("ses_x", { parentId: "ses_y" }), session("ses_y", { parentId: "ses_x" })]);
209 assert.equal(cycle.length + cycle.reduce((n, node) => n + treeSize(node), 0), 2);
210 assert.deepEqual(sessionTree([]), []);
211 assert.deepEqual(
212 mergeSessions([session("ses_a"), session("ses_b")], null, [session("ses_b", { title: "later" }), session("ses_c")]).map((one) => [one.id, one.title]),
213 [
214 ["ses_a", null],
215 ["ses_b", null],
216 ["ses_c", null],
217 ],
218 );
219});
220
221test("how a session was tied to its work, what it touched, and how long it ran", () => {
222 assert.equal(viaLabel("attached"), "attached");
223 assert.equal(viaLabel("claim"), "claimed");
224 assert.equal(viaLabel("branch"), "its branch");
225 assert.equal(viaLabel("commit"), "its commit");
226 assert.equal(viaLabel("trailer"), "commit trailer");
227 assert.equal(viaLabel("opened"), "opened it");
228 assert.equal(viaLabel("ref"), "named it");
229 assert.deepEqual(
230 touchedByKind([
231 { kind: "commit", value: "abc" },
232 { kind: "file", value: "b.rs" },
233 { kind: "file", value: "a.rs" },
234 { kind: "file", value: "b.rs" },
235 ]),
236 [
237 { kind: "file", values: ["b.rs", "a.rs"] },
238 { kind: "commit", values: ["abc"] },
239 ],
240 );
241 const now = Date.parse("2026-10-12T10:30:00Z");
242 assert.equal(duration(session("ses_a"), now), "30m");
243 assert.equal(duration(session("ses_a", { state: "ended", endedAt: "2026-10-12T10:00:42Z" }), now), "42s");
244 assert.equal(duration(session("ses_a", { state: "ended", endedAt: null }), now), "5m");
245});
246
Merge branch 'worktree-agent-aa68cf6ecc03dffaf'247test("numbers in a sentence are found for linking", () => {
248 assert.deepEqual(numberedParts("#5 fails with #4."), [5, " fails with ", 4, "."]);
249 assert.deepEqual(numberedParts("no numbers"), ["no numbers"]);
250});
251
252test("blocked_by is typed as numbers", () => {
253 assert.deepEqual(parseBlockedBy("#12, 14 #12"), [12, 14]);
254 assert.deepEqual(parseBlockedBy(""), []);
255 assert.equal(parseBlockedBy("#12, soon"), null);
256 assert.equal(parseBlockedBy("0"), null);
257});

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