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
702 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.

Cache hits are counted, not only their bytes1/**
2 * Every state change in g1t is published as an event. Services react to
3 * each other through events rather than direct calls, and the same stream
4 * feeds timelines, webhooks and workflows.
5 *
6 * The envelope follows CloudEvents: `type` says what happened, `subject`
7 * says to what, `data` is the type-specific payload.
8 */
9
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts10import type { Release } from "./about";
Cache hits are counted, not only their bytes11import type { RepoRole } from "./access";
Merge checks: statuses and check runs on every commit12import type { CheckRunEventData, CheckSuiteEventData, StatusEventData } from "./checks";
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb9713import type { DeploymentStatus, RepoDeployment } from "./deployments";
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar14import type { TeamRole, TeamVisibility } from "./teams";
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.15import type { AgentRef, Verdict } from "./work";
Cache hits are counted, not only their bytes16
17/** What every `package.*` event names. */
18export type PackageEventData = {
19 packageId: string;
20 workspace: string;
21 ecosystem: string;
22 name: string;
23 repoId: string | null;
24};
25
Events: review requests, assignments, stops and deployments are published26/** What `deployment.succeeded` and `deployment.failed` carry. */
27export type DeploymentEventData = {
28 deploymentId: string;
29 projectId: string;
30 repoId: string;
31 workspace: string;
32 project: string;
33 kind: "production" | "preview";
34 branch: string | null;
35 number: number | null;
36 commit: string;
37 path: string;
38 error: string | null;
39 recovered: boolean;
40 /** A username, or `g1t`. */
41 triggeredBy: string;
42};
43
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts44/** What every `release.*` event carries. */
45export type ReleaseEventData = {
46 releaseId: string;
47 repoId: string;
48 tagName: string;
49 release: Release;
50 /** On `release.edited`: what the title and notes were before. */
51 changes?: { name?: { from: string | null }; body?: { from: string } };
52 /** Set when a workflow job's token made the change: the run's id. */
53 causedByJob?: string;
54};
55
Cache hits are counted, not only their bytes56/** The payload of the `repo.collaborator_*` events. */
57export type RepoCollaboratorData = {
58 repoId: string;
59 namespace: string;
60 name: string;
61 username: string;
62 role: RepoRole | null;
63 previousRole: RepoRole | null;
64};
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar65/** A team asked to review a pull request. */
66export type TeamRequested = { team: string; notified: string[]; assigned: string[] };
67
68/** The payload of the `team.*` events; each sets the fields that apply. */
@g1t welcomes you when you join a workspace, and that is the one introduction any agent makes. Identity now says when a person becomes a member, workspace.member_joined, by invitation, by an invite code, or by creating the workspace, and webhooks can hear it; the agents service hears it too, and for anyone who joined, never the creator, the workspace's @g1t opens your direct message and says in its own voice who it is, what to ask it, how agents answer, and where things are, once per person per workspace and charged to @g1t like any reply, with a fixed welcome when no model can be used. The agents, workspaces, authentication and webhooks guides say so.69/** How someone came to be a member of a workspace (`workspace.member_joined`). */
70export type JoinedHow = "invitation" | "created" | "joined";
71
72/** The payload of `workspace.member_joined`. Mirrors `MemberJoined` in events.rs. */
73export type MemberJoinedData = {
74 workspaceId: string;
75 /** The workspace's slug. */
76 workspace: string;
77 userId: string;
78 username: string;
79 role: "owner" | "member";
80 how: JoinedHow;
81};
82
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar83export type TeamChangedData = {
84 workspace: string;
85 teamId: string;
86 team: string;
87 name: string;
88 visibility: TeamVisibility | null;
89 parent?: string;
90 changes?: string[];
91 username?: string;
92 role?: TeamRole;
93 previousRole?: TeamRole;
94 repoId?: string;
95 repo?: string;
96 repoRole?: RepoRole;
97 previousRepoRole?: RepoRole;
98};
99
Cache hits are counted, not only their bytes100export type EventPayloads = {
101 "repo.created": { repoId: string; namespace: string; name: string; isPrivate: boolean };
102 "repo.forked": { repoId: string; sourceRepoId: string; pullId: string };
103 /**
104 * A repository's description, topics or visibility changed.
105 * `visibilityChanged` says whether it went public or private, which
106 * `repo.visibility_changed` also announces on its own.
107 */
108 "repo.updated": { repoId: string; namespace: string; name: string; isPrivate: boolean; visibilityChanged: boolean };
109 "repo.visibility_changed": { repoId: string; isPrivate: boolean };
110 /**
111 * A repository's name changed within its workspace `namespace`, from
112 * `from` to `to`, keeping its id. A path change like `repo.transferred`:
113 * services move rows kept under its path to its *current* path (see
114 * `repoMove`, `currentMovedPath`).
115 */
116 "repo.renamed": { repoId: string; namespace: string; from: string; to: string };
117 /**
118 * A repository was deleted. It is hidden and git refuses it, but it can
119 * be restored until `purgeAfter`: services stop what runs for it and hide
120 * it, and keep their rows until `repo.purged`.
121 */
122 "repo.deleted": {
123 repoId: string;
124 namespace: string;
125 name: string;
126 isPrivate: boolean;
127 purgeAfter: string;
128 /** It went with its workspace (`workspace.deleting`); deployments leaves it to that. */
129 withWorkspace?: boolean;
130 };
131 /** A deleted repository is back, as it was. Services start again what they stopped. */
132 "repo.restored": {
133 repoId: string;
134 namespace: string;
135 name: string;
136 isPrivate: boolean;
137 /** It came back with its workspace (`workspace.restored`). */
138 withWorkspace?: boolean;
139 };
140 /**
141 * A deleted repository is gone for good, its git data with it. Services
142 * drop every row they keep for it, except a workspace's history (ledgers,
143 * invoices, the audit log).
144 */
145 "repo.purged": { repoId: string; namespace: string; name: string };
146 /**
147 * A repository was archived (read-only: pushes, merges, agents and
148 * workflows refused; issues and pull requests locked; deployments keep
149 * serving), or unarchived.
150 */
151 "repo.archived": { repoId: string; namespace: string; name: string; archived: true };
152 "repo.unarchived": { repoId: string; namespace: string; name: string; archived: false };
153 /** The default branch is now `to`; `renamed` when `from` was renamed to it. */
154 "repo.default_branch_changed": { repoId: string; from: string; to: string; renamed: boolean };
155 /** A branch was renamed. Pull requests from it follow. */
156 "branch.renamed": { repoId: string; from: string; to: string; defaultBranch: boolean };
157 /** An account was made, or changed what its profile shows. Ask identity for the profile. */
158 "user.updated": { username: string };
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)159 /**
160 * An account was deleted, by the person or by g1t's staff; staff can
161 * restore it until `purgeAfter`. Its sessions, tokens and keys have ended
162 * and it has left every workspace. Services stop what they do for it and
163 * keep their rows; `user.restored` undoes that, and `user.deleted` follows
164 * once `purgeAfter` passes.
165 */
166 "user.deleting": { userId: string; username: string; byStaff: boolean; purgeAfter: string };
167 /** Staff brought a deleted account back. Services undo what they did on `user.deleting`. */
168 "user.restored": { userId: string; username: string };
169 /**
170 * An account is gone for good. Services drop what they keep for it alone
171 * and show what it wrote as `ghost` (`GHOST_USERNAME`, `GHOST_ID`).
172 * Ledgers, invoices and audit logs keep its username, which is never given
173 * to anyone again.
174 */
175 "user.deleted": { userId: string; username: string };
Cache hits are counted, not only their bytes176 /** A workspace was made, or its name, description or icon changed. */
177 "workspace.updated": { workspaceId: string; slug: string };
@g1t welcomes you when you join a workspace, and that is the one introduction any agent makes. Identity now says when a person becomes a member, workspace.member_joined, by invitation, by an invite code, or by creating the workspace, and webhooks can hear it; the agents service hears it too, and for anyone who joined, never the creator, the workspace's @g1t opens your direct message and says in its own voice who it is, what to ask it, how agents answer, and where things are, once per person per workspace and charged to @g1t like any reply, with a fixed welcome when no model can be used. The agents, workspaces, authentication and webhooks guides say so.178 /**
179 * A person became a member of a workspace. `how` says by which door;
180 * the workspace's creator is `created`, so a listener that greets new
181 * members leaves them out (the agents service's @g1t welcomes everyone
182 * else, once). Never for an agent or a token.
183 */
184 "workspace.member_joined": MemberJoinedData;
Cache hits are counted, not only their bytes185 /** Someone, or g1t staff, made an invite. Never the code or the address. */
186 "invite.created": { inviteId: string; inviterId: string | null; workspaceId: string | null; bound: boolean };
187 /** An invite was used: by a new account, or by an account joining a workspace. */
188 "invite.redeemed": {
189 inviteId: string;
190 userId: string;
191 inviterId: string | null;
192 workspaceId: string | null;
193 createdAccount: boolean;
194 };
195 /**
196 * One branch moved by a push. `ref` is the full ref, `after` the commit it
197 * points to now, and `defaultBranch` whether it is the default branch.
198 */
199 /**
Merge leftovers: plan activity filtered in the query, pushes counted by account, ghost during the deletion window, profile time zones (identity 0039)200 * `before` is where the ref pointed before; absent for a new branch or
201 * tag. `causedByJob` is set when a workflow job's token pushed: the run's id.
202 */
Merge branch 'mirroring' into artifacts-mode203 "git.push": {
204 repoId: string;
205 ref: string;
206 before?: string;
207 after: string;
208 defaultBranch: boolean;
209 causedByJob?: string;
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.210 /**
211 * How many commits the push brought to the branch, along its
212 * first-parent line from `after` back to `before` (a merge commit is
213 * one), at most 50; one for a new branch. Absent when it was not
214 * counted: a tag, a branch deleted, a pull request landed, a push the
215 * store could not read back, or one from before this was recorded.
216 */
217 commits?: number;
Merge branch 'mirroring' into artifacts-mode218 };
Merge leftovers: plan activity filtered in the query, pushes counted by account, ghost during the deletion window, profile time zones (identity 0039)219 /**
Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9220 * A branch or tag was deleted by a push. `before` is the commit it pointed
221 * to. `causedByJob` is set when a workflow job's token deleted it: the run's id.
222 */
223 "git.deleted": { repoId: string; ref: string; before: string; causedByJob?: string };
224 /**
Cache hits are counted, not only their bytes225 * `author` is who opened it: g1t, for one its agent filed while at work,
226 * with `requestedBy` the person it was working for. Every issue and pull
227 * request event carries both.
228 */
229 "issue.opened": {
230 issueId: string;
231 repoId: string;
232 number: number;
233 title: string;
234 author?: { id: string; username: string };
235 requestedBy?: { id: string; username: string };
236 };
237 "issue.updated": { issueId: string; repoId: string; number: number };
Events: review requests, assignments, stops and deployments are published238 /** The people an issue is assigned to changed; `assignees` is the new set, `added` those newly assigned. */
239 "issue.assigned": { issueId: string; repoId: string; number: number; assignees: string[]; added?: string[] };
Cache hits are counted, not only their bytes240 /** `resolvedBy` is the number of the pull request whose merge closed it. */
241 "issue.closed": {
242 issueId: string;
243 repoId: string;
244 number: number;
245 reason: "completed" | "not_planned";
246 resolvedBy?: number;
247 };
248 "issue.reopened": { issueId: string; repoId: string; number: number };
249 /**
250 * `issue` is the number of the issue the pull request is for. `author` is
251 * who opened it: g1t, for a change g1t made, with `requestedBy` the person
252 * who asked for it.
253 */
254 "pull.opened": {
255 pullId: string;
256 repoId: string;
257 number: number;
258 issue?: number;
259 agent: string;
260 author?: { id: string; username: string };
261 requestedBy?: { id: string; username: string };
262 };
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.263 "pull.ready": { pullId: string; repoId: string; number: number; issue?: number };
Cache hits are counted, not only their bytes264 /** A push moved the head of a pull request that is ready for review. */
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.265 "pull.updated": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
Cache hits are counted, not only their bytes266 /** A merge was asked for while the pull request was behind; it has to catch up first. */
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.267 "pull.merge_requested": { pullId: string; repoId: string; number: number; issue?: number };
268 "pull.closed": { pullId: string; repoId: string; number: number; issue?: number };
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts269 /** A closed pull request was opened again. `commit` is its head. */
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.270 "pull.reopened": { pullId: string; repoId: string; number: number; issue?: number; commit?: string };
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts271 /** A pull request that was ready for review was turned back into a draft. */
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.272 "pull.converted_to_draft": { pullId: string; repoId: string; number: number; issue?: number };
Events: review requests, assignments, stops and deployments are published273 /** People were assigned to a pull request: `assignees` is the new set, `added` those newly assigned. */
274 "pull.assigned": { pullId: string; repoId: string; number: number; issue?: number; assignees: string[]; added: string[] };
275 /** Reviewers were asked for a pull request (`reviewers`), or no longer are. */
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar276 "pull.review_requested": {
277 pullId: string;
278 repoId: string;
279 number: number;
280 issue?: number;
281 reviewers?: string[];
282 /** Teams asked: `team` is `workspace/slug`, `notified` who is told, `assigned` who review assignment picked. */
283 teams?: TeamRequested[];
284 /** Asked because they own files it changes (its CODEOWNERS file). */
285 codeOwners?: boolean;
286 };
287 "pull.review_request_removed": {
288 pullId: string;
289 repoId: string;
290 number: number;
291 issue?: number;
292 reviewers?: string[];
293 teams?: TeamRequested[];
294 };
Events: review requests, assignments, stops and deployments are published295 /** g1t stopped seeing a pull request through until a person steps in; `detail` says why. */
296 "pull.stalled": { pullId: string; repoId: string; number: number; issue?: number; detail: string };
297 /** A pull request g1t had stopped on is going again. */
298 "pull.resumed": { pullId: string; repoId: string; number: number; issue?: number };
Cache hits are counted, not only their bytes299 /**
300 * The pull request's head or its target moved and the files both changed
301 * overlap: a sandbox should find out whether it still merges cleanly.
302 * `commit` is its head.
303 */
304 "pull.mergecheck": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
305 /** Whether the pull request merges cleanly was settled. */
306 "pull.mergeability": { pullId: string; repoId: string; number: number; issue?: number };
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.307 "pull.merged": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
Cache hits are counted, not only their bytes308 /** A run of the acceptance checks finished. `commit` is what was checked. */
309 "checks.completed": {
310 pullId: string;
311 repoId: string;
312 number: number;
313 status: "passed" | "failed" | "errored";
314 commit: string;
315 };
Merge checks: statuses and check runs on every commit316 /** A status was set on a commit through the API. */
317 "status.created": StatusEventData;
318 /** A check run was reported on a commit through the API, completed, asked to run again, or had one of its buttons pressed (`requestedAction`). */
319 "check_run.created": CheckRunEventData;
320 "check_run.completed": CheckRunEventData;
321 "check_run.rerequested": CheckRunEventData;
322 "check_run.requested_action": CheckRunEventData;
323 /** A reporter's check runs on a commit all completed, or it was asked to run them again. */
324 "check_suite.completed": CheckSuiteEventData;
325 "check_suite.rerequested": CheckSuiteEventData;
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.326 /** A g1t agent finished reviewing a pull request; no verdict if it could not. No longer published: on older events only. */
Cache hits are counted, not only their bytes327 "review.completed": {
328 pullId: string;
329 repoId: string;
330 number: number;
331 verdict?: "approve" | "request_changes";
332 };
333 /** A person was given a role on one repository directly, had it changed, or lost it. `role` is null once removed. */
334 "repo.collaborator_added": RepoCollaboratorData;
335 "repo.collaborator_removed": RepoCollaboratorData;
336 "repo.collaborator_role_changed": RepoCollaboratorData;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar337 /** A team of a workspace was created, changed (`changes` says what) or deleted. */
338 "team.created": TeamChangedData;
339 "team.edited": TeamChangedData;
340 "team.deleted": TeamChangedData;
341 /** Someone joined a team, had their role in it changed, or left it. */
342 "team.member_added": TeamChangedData;
343 "team.member_role_changed": TeamChangedData;
344 "team.member_removed": TeamChangedData;
345 /** A team was given a role on a repository, had it changed, or lost it. */
346 "team.repo_added": TeamChangedData;
347 "team.repo_role_changed": TeamChangedData;
348 "team.repo_removed": TeamChangedData;
Cache hits are counted, not only their bytes349 /** A repository's merge queue gained, lost or settled an entry. */
350 "queue.changed": { repoId: string };
351 /** `number` is the issue or pull request commented on. */
352 "comment.created": {
353 commentId: string;
354 repoId: string;
355 number: number;
356 /** Set when the comment is on a pull request. */
357 pullId?: string;
358 /** Set when the comment is a review. */
359 verdict?: Verdict;
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar360 /**
361 * Set when one of the workspace's agents wrote it, as itself; the
362 * event's actor is then the person it acted for (`actingFor`).
363 */
364 agent?: AgentRef;
365 actingFor?: { id: string; username: string };
366 /** An agent's review: its verdict is advisory and counts toward nothing. */
367 advisory?: boolean;
Cache hits are counted, not only their bytes368 };
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts369 /** A comment's text changed; `changes.body.from` is what it said before. */
370 "comment.edited": {
371 commentId: string;
372 repoId: string;
373 number: number;
374 /** Set when the comment is on a pull request. */
375 pullId?: string;
376 changes: { body: { from: string } };
377 };
378 /** A comment was deleted; `comment` is the comment as it was. */
379 "comment.deleted": {
380 commentId: string;
381 repoId: string;
382 number: number;
383 /** Set when the comment was on a pull request. */
384 pullId?: string;
385 comment: {
386 id: string;
387 body: string;
388 author: { id: string; username: string };
389 createdAt: string;
390 path: string | null;
391 line: number | null;
392 };
393 };
Cache hits are counted, not only their bytes394 "session.appended": { pullId: string; repoId: string; number: number; count: number };
395 /**
Events: review requests, assignments, stops and deployments are published396 * A build of a project finished, for production or one pull request's
397 * preview (`number`). `path` is the deployment's page on the site;
398 * `recovered`, on a success, says the build before it failed.
399 */
400 "deployment.succeeded": DeploymentEventData;
401 "deployment.failed": DeploymentEventData;
402 /**
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97403 * A deployment was made, wherever it runs: reported through the API, by
404 * a g1t Actions job with an `environment:`, or a g1t.page build. Its
405 * `payload` is left out: read the deployment for it.
406 */
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts407 "deployment.created": { repoId: string; deployment: Omit<RepoDeployment, "payload">; causedByJob?: string };
408 /**
409 * A deployment has a new status; `deployment` is as it is now.
410 * `causedByJob` (as on every event a workflow job's token causes) is the
411 * run whose job made it, so no workflow starts for it.
412 */
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97413 "deployment_status.created": {
414 repoId: string;
415 deployment: Omit<RepoDeployment, "payload">;
416 deploymentStatus: DeploymentStatus;
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts417 causedByJob?: string;
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97418 };
419 /**
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts420 * A release changed, one event per GitHub release activity it amounts
421 * to: made (`created`; a published one is also `published`, and
422 * `released` or `prereleased`), a draft published, edited, made a draft
423 * again (`unpublished`) or deleted. `release` is as it is now (as it was,
424 * for `release.deleted`).
425 */
426 "release.created": ReleaseEventData;
427 "release.published": ReleaseEventData;
428 "release.released": ReleaseEventData;
429 "release.prereleased": ReleaseEventData;
430 "release.edited": ReleaseEventData;
431 "release.unpublished": ReleaseEventData;
432 "release.deleted": ReleaseEventData;
433 /**
Cache hits are counted, not only their bytes434 * A package version was published, such as an image pushed by
435 * `docker push`. `tags` are the tags that now point to it; `repoId` (and
436 * the event's) is the repository the package is linked to, if any.
437 */
438 "package.published": PackageEventData & { version: string; digest: string; size: number; tags: string[] };
439 /** One version of a package was deleted, with the tags that pointed to it. */
440 "package.version_deleted": PackageEventData & { version: string; digest: string };
441 /** A package was deleted with every version it had. */
442 "package.deleted": PackageEventData;
443 /** A package became public or private. */
444 "package.visibility_changed": PackageEventData & { visibility: "public" | "private" };
445 /**
446 * A workspace's slug changed from `from` to `to`. Services that store a
447 * slug move their rows to the workspace's *current* slug (see
448 * `currentWorkspaceSlug`), so a repeated or late delivery after a second
449 * rename still lands in the right place.
450 */
451 "workspace.renamed": { workspaceId: string; from: string; to: string };
452 /**
453 * A repository moved from workspace `from` to `to`, keeping its id and
454 * name. Services that store its path or its workspace's slug move those
455 * rows to its *current* path (ask repos `path_by_id`), so a repeated or
456 * late delivery after a second transfer still lands in the right place.
457 */
458 "repo.transferred": { repoId: string; name: string; from: string; to: string };
459 /**
460 * A workspace is gone. Services drop what they keep for it alone; ledgers,
461 * invoices and the audit log stay under its slug, which is never reused.
462 */
463 "workspace.deleted": { workspaceId: string; slug: string };
464 /**
465 * An owner deleted a workspace; staff can restore it until `purgeAfter`,
466 * and nobody can reach it meanwhile. Services hide what they keep for it
467 * and stop what runs for it, keeping their rows: repos deletes its
468 * repositories softly (`repo.deleted` with `withWorkspace`), deployments
469 * pauses its apps, search drops it. `workspace.restored` undoes exactly
470 * that; `workspace.deleted` follows once `purgeAfter` passes. `by` is the
471 * owner's username.
472 */
473 "workspace.deleting": { workspaceId: string; slug: string; by: string; purgeAfter: string };
474 /**
475 * Staff brought a deleted workspace back with its members and tokens.
476 * Services undo what they did on `workspace.deleting`, and only that.
477 */
478 "workspace.restored": { workspaceId: string; slug: string };
479 /**
480 * A sandbox was stopped because it looked like it was mining: CPU pinned
481 * with little I/O and no progress, or a miner seen by name. For g1t's
482 * staff, in sudo; published with no `repoId` so it never reaches a
483 * repository's timeline or webhooks. `metrics` is what the sandbox
484 * measured (`Verdict` in crates/runner abuse.rs), or null if it could
485 * not say.
486 */
487 "abuse.flagged": {
488 workspace: string;
489 repo: string | null;
490 /** The agent run, when the sandbox had one. */
491 run: string | null;
492 /** What the sandbox was for: agent, checks, queue, actions, deploy... */
493 kind: string;
494 sandbox: string;
495 metrics: Record<string, unknown> | null;
496 };
Docs know what code they describe; a project's docs folder in Docs; Docs events; files on any S3 store497 /**
The artifacts service is services/artifacts, the Worker g1t-artifacts, bound as ARTIFACTS by the API, the site and the agents; its live rooms move to it with a Durable Object transfer from g1t-docs-service, and its database, bucket, indexes and queue keep their names. The git store's binding and settings are GITSTORE, its ops scripts gitstore-*, and workflow run artifacts keep their compatible API under run_artifacts modules. The deploy tool puts a Worker that has never deployed before the Workers in its stage that bind to it, and the deploy guide gives the cutover runbook.498 * Docs (services/artifacts): a page was made. Published with no `repoId`, so
Docs know what code they describe; a project's docs folder in Docs; Docs events; files on any S3 store499 * a page (which may be in a private space) never reaches a repository's
500 * timeline or webhooks; `actor` is the user's or agent's id. Readers
The artifacts service is services/artifacts, the Worker g1t-artifacts, bound as ARTIFACTS by the API, the site and the agents; its live rooms move to it with a Durable Object transfer from g1t-docs-service, and its database, bucket, indexes and queue keep their names. The git store's binding and settings are GITSTORE, its ops scripts gitstore-*, and workflow run artifacts keep their compatible API under run_artifacts modules. The deploy tool puts a Worker that has never deployed before the Workers in its stage that bind to it, and the deploy guide gives the cutover runbook.501 * check access with the artifacts service before showing anything of it.
Docs know what code they describe; a project's docs folder in Docs; Docs events; files on any S3 store502 */
503 "doc.page.created": DocPageEventData;
504 /**
505 * A page's content changed: at most once per page every ten minutes of
506 * editing (when its history records a version), and for every agent
507 * edit, accepted suggestion and restore. `authors` are member keys
508 * (`user:<id>`, `agent:<id>`) of everyone whose changes are in it.
509 */
510 "doc.page.updated": DocPageEventData & { versionId: string; kind: "edit" | "agent" | "suggestion" | "restore"; authors: string[] };
511 /** A page went to the trash (with every page under it; one event for the page asked about). */
512 "doc.page.archived": DocPageEventData;
513 /**
514 * A page became possibly out of date: a merged pull request or a push to
515 * a repository's default branch changed code it cites. `repoId` is in
516 * `data`, not on the event, for the same reason as above. `owners` are
517 * member keys; an agent that owns the page can update it
518 * (`stalePagesForAgent` in docs.ts).
519 */
520 "doc.page.stale": DocPageEventData & { repoId: string; repo: string; commit: string; pull: number | null; paths: string[]; owners: string[] };
Artifacts contracts: folios, their four kinds, dashboard datasets, folio events and the artifacts scopes are typed and validated the same in TypeScript and Rust, with nothing using them yet521 /**
The artifacts service is services/artifacts, the Worker g1t-artifacts, bound as ARTIFACTS by the API, the site and the agents; its live rooms move to it with a Durable Object transfer from g1t-docs-service, and its database, bucket, indexes and queue keep their names. The git store's binding and settings are GITSTORE, its ops scripts gitstore-*, and workflow run artifacts keep their compatible API under run_artifacts modules. The deploy tool puts a Worker that has never deployed before the Workers in its stage that bind to it, and the deploy guide gives the cutover runbook.522 * Artifacts (folios, services/artifacts): a folio was made. Like `doc.page.*`,
Artifacts contracts: folios, their four kinds, dashboard datasets, folio events and the artifacts scopes are typed and validated the same in TypeScript and Rust, with nothing using them yet523 * published with no `repoId`, never offered to webhooks, and readers check
The artifacts service is services/artifacts, the Worker g1t-artifacts, bound as ARTIFACTS by the API, the site and the agents; its live rooms move to it with a Durable Object transfer from g1t-docs-service, and its database, bucket, indexes and queue keep their names. The git store's binding and settings are GITSTORE, its ops scripts gitstore-*, and workflow run artifacts keep their compatible API under run_artifacts modules. The deploy tool puts a Worker that has never deployed before the Workers in its stage that bind to it, and the deploy guide gives the cutover runbook.524 * access with the artifacts service before showing anything of it.
Artifacts contracts: folios, their four kinds, dashboard datasets, folio events and the artifacts scopes are typed and validated the same in TypeScript and Rust, with nothing using them yet525 */
526 "folio.created": FolioEventData;
527 /** A folio's content changed: a version (`versionKind`) with everyone whose changes are in it. */
528 "folio.updated": FolioEventData & { versionId: string; versionKind: "edit" | "agent" | "suggestion" | "proposal" | "restore"; authors: string[] };
529 /** A folio went to the trash (with everything under it; one event for the folio asked about). */
530 "folio.trashed": FolioEventData;
531 "folio.restored": FolioEventData;
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9532 /**
533 * A folio was deleted for good from the trash (with everything under it;
534 * one event for each top that went): by someone with full access, by
535 * emptying the trash, or by the daily purge (`actor` null then).
536 */
537 "folio.deleted": FolioEventData;
Artifacts contracts: folios, their four kinds, dashboard datasets, folio events and the artifacts scopes are typed and validated the same in TypeScript and Rust, with nothing using them yet538 /** Someone was given access: who (member keys) and the role. Never content. */
539 "folio.shared": FolioEventData & { principals: string[]; role: "view" | "comment" | "edit" | "manage" };
540 /** Code a folio cites changed. The repository is in `data` as `owner/name` only. */
541 "folio.stale": FolioEventData & { repo: string; commit: string; pull: number | null; paths: string[]; owners: string[] };
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9542 /**
543 * A space was deleted (services/artifacts): everything in it went to the
544 * trash (`trashed` counts the artifacts; this one event stands for them
545 * all). Like `folio.*`, published with no `repoId` and never offered to
546 * webhooks; `name` is null for a members-only space.
547 */
548 "doc.space.deleted": { workspace: string; workspaceId: string; spaceId: string; name: string | null; kind: "workspace" | "team" | "private"; trashed: number };
Artifacts contracts: folios, their four kinds, dashboard datasets, folio events and the artifacts scopes are typed and validated the same in TypeScript and Rust, with nothing using them yet549};
550
551/**
552 * What every `folio.*` event carries. `title` is null unless every member
553 * of the workspace can read the folio, so a private folio's name never
554 * travels.
555 */
556export type FolioEventData = {
557 workspace: string;
558 workspaceId: string;
559 folioId: string;
560 kind: "doc" | "slides" | "design" | "dashboard";
561 spaceId: string | null;
562 title: string | null;
Docs know what code they describe; a project's docs folder in Docs; Docs events; files on any S3 store563};
564
565/** What every `doc.page.*` event carries. */
566export type DocPageEventData = {
567 workspace: string;
568 workspaceId: string;
569 pageId: string;
570 spaceId: string;
571 title: string;
572 /** The page's address on the site. */
573 path: string;
Cache hits are counted, not only their bytes574};
575
576export type EventType = keyof EventPayloads;
577
578export type G1tEvent<T extends EventType = EventType> = {
579 [K in T]: {
580 id: string;
581 type: K;
582 /** The service that published it. */
583 source: string;
584 /** RFC 3339. */
585 time: string;
586 /** The repo the event concerns, used to scope timelines and deliveries. */
587 repoId: string | null;
588 /** The user or agent that caused it, if any. */
589 actor: string | null;
590 data: EventPayloads[K];
591 };
592}[T];
593
594/** What a publisher supplies; the bus fills in `id` and `time`. */
595export type NewEvent<T extends EventType = EventType> = {
596 [K in T]: Omit<G1tEvent<K>, "id" | "time">;
597}[T];
598
599export type EventQuery = {
600 repoId?: string;
601 types?: EventType[];
602 /** Return events older than this event id. */
603 before?: string;
Merge leftovers: plan activity filtered in the query, pushes counted by account, ghost during the deletion window, profile time zones (identity 0039)604 /** Only events by this account id. */
605 actor?: string;
606 /** Only events about these issues or pull requests (`number`, or the `issue` a comment or review is on). */
607 numbers?: number[];
608 /** Only events at or after this RFC 3339 time. */
609 since?: string;
Cache hits are counted, not only their bytes610 limit?: number;
611};
612
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.613/**
614 * `activity_digest`: what happened in some repositories, and to a
615 * workspace's artifacts, over `[from, until)`, counted by who did it. Home
616 * reads it for what people and agents did since you were last there.
617 * snake_case, as the Rust service reads it
618 * (`g1t_contracts::events::ActivityDigestArgs`).
619 */
620export type ActivityDigestArgs = {
621 /** By id; the caller has checked the viewer may read each. At most `MAX_DIGEST_REPOS` are read. */
622 repo_ids: string[];
623 /** The workspace's slug, for its `folio.*` events (which carry no repository); null leaves artifacts out. */
624 workspace: string | null;
625 /** RFC 3339, inclusive. */
626 from: string;
627 /** RFC 3339, exclusive. */
628 until: string;
629};
630
631/** The most repositories one digest reads. */
632export const MAX_DIGEST_REPOS = 50;
633
634/**
635 * How many times one actor did something. The actor is a member key:
636 * `user:<id>` for a person (or g1t, `user:usr_g1t_agent`), `agent:<id>` for
637 * one of the workspace's agents acting as itself, or `""` when the event
Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them.638 * named nobody.
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.639 */
640export type ActorCount = { actor: string; count: number };
641
642/** Pushes by one actor, with the commits they brought. */
643export type PushesBy = { actor: string; count: number; commits: number };
644
645/** Pushes to a repository's branches (tags are not pushes here). A push whose commits were not counted counts as one commit. */
646export type PushDigest = {
647 count: number;
648 commits: number;
649 /** The branches pushed to, by name, sorted. */
650 branches: string[];
651 /** Most pushes first. */
652 by: PushesBy[];
653 /** Of those, the pushes straight to the default branch: what landed without a pull request. */
654 default_branch: { count: number; commits: number; by: PushesBy[]; last_at: string | null };
655};
656
657export type RepoDigest = {
658 repo_id: string;
659 pushes: PushDigest;
660 /** Pull requests opened, merged and closed without merging, each by who did it. */
661 pulls: { opened: ActorCount[]; merged: ActorCount[]; closed: ActorCount[] };
662 issues: { opened: ActorCount[]; closed: ActorCount[] };
663 /** `review.completed` (g1t's), and a comment with a verdict (a person's). */
664 reviews: ActorCount[];
665 /** Comments without a verdict; one by an agent as itself is the agent's. */
666 comments: ActorCount[];
667 /** Builds that finished, by who set them off; `production` is how many successes were production. */
668 deployments: { succeeded: ActorCount[]; failed: ActorCount[]; production: number };
669 /** Releases published, newest first, at most 50. */
670 releases: { tag: string; name: string | null; actor: string; at: string }[];
671 /** Package versions published, newest first, at most 50. */
672 packages: { ecosystem: string; name: string; version: string; actor: string; at: string }[];
673};
674
675/** A workspace's artifacts over the span. Never a title. */
676export type FolioDigest = {
677 created: ActorCount[];
678 /** Each folio whose content changed, once, with everyone whose changes are in it (member keys); at most 50. */
679 edited: { folio_id: string; kind: "doc" | "slides" | "design" | "dashboard" | string; authors: string[] }[];
680 /** How many folios changed, counting those past the cap. */
681 edited_count: number;
682};
683
684export type ActivityDigest = {
685 from: string;
686 until: string;
687 /** One per repository that had any event counted; none for a quiet one. */
688 repos: RepoDigest[];
689 /** When a workspace was named. */
690 folios: FolioDigest | null;
691 /** False when more events fell in the span than were read, or more repositories were named than are read, so counts are low. */
692 complete: boolean;
693};
694
Cache hits are counted, not only their bytes695/** The event bus and its durable log. */
696export interface EventsApi {
697 publish(events: NewEvent[]): Promise<void>;
698 /** Newest first. */
699 list(query: EventQuery): Promise<G1tEvent[]>;
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.700 /** A span of some repositories' and a workspace's artifacts' events, counted by who did it. */
701 activityDigest(args: ActivityDigestArgs): Promise<ActivityDigest>;
Cache hits are counted, not only their bytes702}

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