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

A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending1/**
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";
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending11import type { RepoRole } from "./access";
Merge checks: statuses and check runs on every commit12import type { CheckRunEventData, CheckSuiteEventData, StatusEventData } from "./checks";
Merge branch 'mirroring' into artifacts-mode13import type { RepoMirror } from "./mirrors";
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb9714import type { DeploymentStatus, RepoDeployment } from "./deployments";
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar15import type { TeamRole, TeamVisibility } from "./teams";
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar16import type { AgentRef, Confidence, Verdict } from "./work";
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending17
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member18/** What every `package.*` event names. */
19export type PackageEventData = {
20 packageId: string;
21 workspace: string;
22 ecosystem: string;
23 name: string;
24 repoId: string | null;
25};
26
Events: review requests, assignments, stops and deployments are published27/** What `deployment.succeeded` and `deployment.failed` carry. */
28export type DeploymentEventData = {
29 deploymentId: string;
30 projectId: string;
31 repoId: string;
32 workspace: string;
33 project: string;
34 kind: "production" | "preview";
35 branch: string | null;
36 number: number | null;
37 commit: string;
38 path: string;
39 error: string | null;
40 recovered: boolean;
41 /** A username, or `g1t`. */
42 triggeredBy: string;
43};
44
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts45/** What every `release.*` event carries. */
46export type ReleaseEventData = {
47 releaseId: string;
48 repoId: string;
49 tagName: string;
50 release: Release;
51 /** On `release.edited`: what the title and notes were before. */
52 changes?: { name?: { from: string | null }; body?: { from: string } };
53 /** Set when a workflow job's token made the change: the run's id. */
54 causedByJob?: string;
55};
56
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending57/** The payload of the `repo.collaborator_*` events. */
58export type RepoCollaboratorData = {
59 repoId: string;
60 namespace: string;
61 name: string;
62 username: string;
63 role: RepoRole | null;
64 previousRole: RepoRole | null;
65};
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar66/** A team asked to review a pull request. */
67export type TeamRequested = { team: string; notified: string[]; assigned: string[] };
68
69/** 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.70/** How someone came to be a member of a workspace (`workspace.member_joined`). */
71export type JoinedHow = "invitation" | "created" | "joined";
72
73/** The payload of `workspace.member_joined`. Mirrors `MemberJoined` in events.rs. */
74export type MemberJoinedData = {
75 workspaceId: string;
76 /** The workspace's slug. */
77 workspace: string;
78 userId: string;
79 username: string;
80 role: "owner" | "member";
81 how: JoinedHow;
82};
83
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar84export type TeamChangedData = {
85 workspace: string;
86 teamId: string;
87 team: string;
88 name: string;
89 visibility: TeamVisibility | null;
90 parent?: string;
91 changes?: string[];
92 username?: string;
93 role?: TeamRole;
94 previousRole?: TeamRole;
95 repoId?: string;
96 repo?: string;
97 repoRole?: RepoRole;
98 previousRepoRole?: RepoRole;
99};
100
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending101export type EventPayloads = {
102 "repo.created": { repoId: string; namespace: string; name: string; isPrivate: boolean };
103 "repo.forked": { repoId: string; sourceRepoId: string; pullId: string };
104 /**
105 * A repository's description, topics or visibility changed.
106 * `visibilityChanged` says whether it went public or private, which
107 * `repo.visibility_changed` also announces on its own.
108 */
109 "repo.updated": { repoId: string; namespace: string; name: string; isPrivate: boolean; visibilityChanged: boolean };
110 "repo.visibility_changed": { repoId: string; isPrivate: boolean };
111 /**
112 * A repository's name changed within its workspace `namespace`, from
113 * `from` to `to`, keeping its id. A path change like `repo.transferred`:
114 * services move rows kept under its path to its *current* path (see
115 * `repoMove`, `currentMovedPath`).
116 */
117 "repo.renamed": { repoId: string; namespace: string; from: string; to: string };
118 /**
119 * A repository was deleted. It is hidden and git refuses it, but it can
120 * be restored until `purgeAfter`: services stop what runs for it and hide
121 * it, and keep their rows until `repo.purged`.
122 */
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member123 "repo.deleted": {
124 repoId: string;
125 namespace: string;
126 name: string;
127 isPrivate: boolean;
128 purgeAfter: string;
129 /** It went with its workspace (`workspace.deleting`); deployments leaves it to that. */
130 withWorkspace?: boolean;
131 };
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending132 /** A deleted repository is back, as it was. Services start again what they stopped. */
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member133 "repo.restored": {
134 repoId: string;
135 namespace: string;
136 name: string;
137 isPrivate: boolean;
138 /** It came back with its workspace (`workspace.restored`). */
139 withWorkspace?: boolean;
140 };
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending141 /**
142 * A deleted repository is gone for good, its git data with it. Services
143 * drop every row they keep for it, except a workspace's history (ledgers,
144 * invoices, the audit log).
145 */
146 "repo.purged": { repoId: string; namespace: string; name: string };
147 /**
148 * A repository was archived (read-only: pushes, merges, agents and
149 * workflows refused; issues and pull requests locked; deployments keep
150 * serving), or unarchived.
151 */
152 "repo.archived": { repoId: string; namespace: string; name: string; archived: true };
153 "repo.unarchived": { repoId: string; namespace: string; name: string; archived: false };
154 /** The default branch is now `to`; `renamed` when `from` was renamed to it. */
155 "repo.default_branch_changed": { repoId: string; from: string; to: string; renamed: boolean };
156 /** A branch was renamed. Pull requests from it follow. */
157 "branch.renamed": { repoId: string; from: string; to: string; defaultBranch: boolean };
158 /** An account was made, or changed what its profile shows. Ask identity for the profile. */
159 "user.updated": { username: string };
Merge account deletion: soft delete for 30 days, staff restore and purge, ghost for what remains (identity 0037)160 /**
161 * An account was deleted, by the person or by g1t's staff; staff can
162 * restore it until `purgeAfter`. Its sessions, tokens and keys have ended
163 * and it has left every workspace. Services stop what they do for it and
164 * keep their rows; `user.restored` undoes that, and `user.deleted` follows
165 * once `purgeAfter` passes.
166 */
167 "user.deleting": { userId: string; username: string; byStaff: boolean; purgeAfter: string };
168 /** Staff brought a deleted account back. Services undo what they did on `user.deleting`. */
169 "user.restored": { userId: string; username: string };
170 /**
171 * An account is gone for good. Services drop what they keep for it alone
172 * and show what it wrote as `ghost` (`GHOST_USERNAME`, `GHOST_ID`).
173 * Ledgers, invoices and audit logs keep its username, which is never given
174 * to anyone again.
175 */
176 "user.deleted": { userId: string; username: string };
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending177 /** A workspace was made, or its name, description or icon changed. */
178 "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.179 /**
180 * A person became a member of a workspace. `how` says by which door;
181 * the workspace's creator is `created`, so a listener that greets new
182 * members leaves them out (the agents service's @g1t welcomes everyone
183 * else, once). Never for an agent or a token.
184 */
185 "workspace.member_joined": MemberJoinedData;
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending186 /** Someone, or g1t staff, made an invite. Never the code or the address. */
187 "invite.created": { inviteId: string; inviterId: string | null; workspaceId: string | null; bound: boolean };
188 /** An invite was used: by a new account, or by an account joining a workspace. */
189 "invite.redeemed": {
190 inviteId: string;
191 userId: string;
192 inviterId: string | null;
193 workspaceId: string | null;
194 createdAccount: boolean;
195 };
196 /** Someone asked for access while registration is invite-only. The address is not in the event. */
197 "waitlist.requested": { entryId: string };
198 /**
199 * One branch moved by a push. `ref` is the full ref, `after` the commit it
200 * points to now, and `defaultBranch` whether it is the default branch.
201 */
202 /**
Merge leftovers: plan activity filtered in the query, pushes counted by account, ghost during the deletion window, profile time zones (identity 0039)203 * `before` is where the ref pointed before; absent for a new branch or
204 * tag. `causedByJob` is set when a workflow job's token pushed: the run's id.
205 */
Merge branch 'mirroring' into artifacts-mode206 "git.push": {
207 repoId: string;
208 ref: string;
209 before?: string;
210 after: string;
211 defaultBranch: boolean;
212 causedByJob?: string;
213 /** Set when it was copied in from the remote a mirror follows, not made on g1t. */
214 mirrored?: boolean;
215 /** The repository's mirror state when it landed; absent for one that leads. */
216 mirror?: RepoMirror;
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.217 /**
218 * How many commits the push brought to the branch, along its
219 * first-parent line from `after` back to `before` (a merge commit is
220 * one), at most 50; one for a new branch. Absent when it was not
221 * counted: a tag, a branch deleted, a pull request landed, a push the
222 * store could not read back, or one from before this was recorded.
223 */
224 commits?: number;
Merge branch 'mirroring' into artifacts-mode225 };
Merge leftovers: plan activity filtered in the query, pushes counted by account, ghost during the deletion window, profile time zones (identity 0039)226 /**
Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9227 * A branch or tag was deleted by a push. `before` is the commit it pointed
228 * to. `causedByJob` is set when a workflow job's token deleted it: the run's id.
229 */
230 "git.deleted": { repoId: string; ref: string; before: string; causedByJob?: string };
231 /**
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending232 * `author` is who opened it: g1t, for one its agent filed while at work,
233 * with `requestedBy` the person it was working for. Every issue and pull
234 * request event carries both.
235 */
236 "issue.opened": {
237 issueId: string;
238 repoId: string;
239 number: number;
240 title: string;
241 author?: { id: string; username: string };
242 requestedBy?: { id: string; username: string };
243 };
244 "issue.updated": { issueId: string; repoId: string; number: number };
Events: review requests, assignments, stops and deployments are published245 /** The people an issue is assigned to changed; `assignees` is the new set, `added` those newly assigned. */
246 "issue.assigned": { issueId: string; repoId: string; number: number; assignees: string[]; added?: string[] };
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending247 /** `resolvedBy` is the number of the pull request whose merge closed it. */
248 "issue.closed": {
249 issueId: string;
250 repoId: string;
251 number: number;
252 reason: "completed" | "not_planned";
253 resolvedBy?: number;
254 };
255 "issue.reopened": { issueId: string; repoId: string; number: number };
256 /**
257 * `issue` is the number of the issue the pull request is for. `author` is
258 * who opened it: g1t, for a change g1t made, with `requestedBy` the person
259 * who asked for it.
260 */
261 "pull.opened": {
262 pullId: string;
263 repoId: string;
264 number: number;
265 issue?: number;
266 agent: string;
267 author?: { id: string; username: string };
268 requestedBy?: { id: string; username: string };
269 };
270 /** `confidence`, on a g1t agent's change once g1t has worked it out, is on every pull request event. */
271 "pull.ready": { pullId: string; repoId: string; number: number; issue?: number; confidence?: Confidence };
272 /** A push moved the head of a pull request that is ready for review. */
273 "pull.updated": { pullId: string; repoId: string; number: number; issue?: number; commit: string; confidence?: Confidence };
274 /** A merge was asked for while the pull request was behind; it has to catch up first. */
275 "pull.merge_requested": { pullId: string; repoId: string; number: number; issue?: number; confidence?: Confidence };
276 "pull.closed": { pullId: string; repoId: string; number: number; issue?: number; confidence?: Confidence };
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts277 /** A closed pull request was opened again. `commit` is its head. */
278 "pull.reopened": { pullId: string; repoId: string; number: number; issue?: number; commit?: string; confidence?: Confidence };
279 /** A pull request that was ready for review was turned back into a draft. */
280 "pull.converted_to_draft": { pullId: string; repoId: string; number: number; issue?: number; confidence?: Confidence };
Events: review requests, assignments, stops and deployments are published281 /** People were assigned to a pull request: `assignees` is the new set, `added` those newly assigned. */
282 "pull.assigned": { pullId: string; repoId: string; number: number; issue?: number; assignees: string[]; added: string[] };
283 /** 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 bar284 "pull.review_requested": {
285 pullId: string;
286 repoId: string;
287 number: number;
288 issue?: number;
289 reviewers?: string[];
290 /** Teams asked: `team` is `workspace/slug`, `notified` who is told, `assigned` who review assignment picked. */
291 teams?: TeamRequested[];
292 /** Asked because they own files it changes (its CODEOWNERS file). */
293 codeOwners?: boolean;
294 };
295 "pull.review_request_removed": {
296 pullId: string;
297 repoId: string;
298 number: number;
299 issue?: number;
300 reviewers?: string[];
301 teams?: TeamRequested[];
302 };
Events: review requests, assignments, stops and deployments are published303 /** g1t stopped seeing a pull request through until a person steps in; `detail` says why. */
304 "pull.stalled": { pullId: string; repoId: string; number: number; issue?: number; detail: string };
305 /** A pull request g1t had stopped on is going again. */
306 "pull.resumed": { pullId: string; repoId: string; number: number; issue?: number };
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending307 /**
308 * The pull request's head or its target moved and the files both changed
309 * overlap: a sandbox should find out whether it still merges cleanly.
310 * `commit` is its head.
311 */
312 "pull.mergecheck": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
313 /** Whether the pull request merges cleanly was settled. */
314 "pull.mergeability": { pullId: string; repoId: string; number: number; issue?: number };
315 /** Another agent asked the agent on a pull request, which was not at work, a question or handed it work. */
316 "agent.asked": { pullId: string; repoId: string; number: number; issue?: number };
317 "pull.merged": { pullId: string; repoId: string; number: number; issue?: number; commit: string; confidence?: Confidence };
318 /** A run of the acceptance checks finished. `commit` is what was checked. */
319 "checks.completed": {
320 pullId: string;
321 repoId: string;
322 number: number;
323 status: "passed" | "failed" | "errored";
324 commit: string;
325 };
Merge checks: statuses and check runs on every commit326 /** A status was set on a commit through the API. */
327 "status.created": StatusEventData;
328 /** A check run was reported on a commit through the API, completed, asked to run again, or had one of its buttons pressed (`requestedAction`). */
329 "check_run.created": CheckRunEventData;
330 "check_run.completed": CheckRunEventData;
331 "check_run.rerequested": CheckRunEventData;
332 "check_run.requested_action": CheckRunEventData;
333 /** A reporter's check runs on a commit all completed, or it was asked to run them again. */
334 "check_suite.completed": CheckSuiteEventData;
335 "check_suite.rerequested": CheckSuiteEventData;
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending336 /** A g1t agent finished reviewing a pull request; no verdict if it could not. */
337 "review.completed": {
338 pullId: string;
339 repoId: string;
340 number: number;
341 verdict?: "approve" | "request_changes";
342 };
343 /** A person was given a role on one repository directly, had it changed, or lost it. `role` is null once removed. */
344 "repo.collaborator_added": RepoCollaboratorData;
345 "repo.collaborator_removed": RepoCollaboratorData;
346 "repo.collaborator_role_changed": RepoCollaboratorData;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar347 /** A team of a workspace was created, changed (`changes` says what) or deleted. */
348 "team.created": TeamChangedData;
349 "team.edited": TeamChangedData;
350 "team.deleted": TeamChangedData;
351 /** Someone joined a team, had their role in it changed, or left it. */
352 "team.member_added": TeamChangedData;
353 "team.member_role_changed": TeamChangedData;
354 "team.member_removed": TeamChangedData;
355 /** A team was given a role on a repository, had it changed, or lost it. */
356 "team.repo_added": TeamChangedData;
357 "team.repo_role_changed": TeamChangedData;
358 "team.repo_removed": TeamChangedData;
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending359 /** A repository's merge queue gained, lost or settled an entry. */
360 "queue.changed": { repoId: string };
361 /** `number` is the issue or pull request commented on. */
362 "comment.created": {
363 commentId: string;
364 repoId: string;
365 number: number;
366 /** Set when the comment is on a pull request. */
367 pullId?: string;
368 /** Set when the comment is a review. */
369 verdict?: Verdict;
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar370 /**
371 * Set when one of the workspace's agents wrote it, as itself; the
372 * event's actor is then the person it acted for (`actingFor`).
373 */
374 agent?: AgentRef;
375 actingFor?: { id: string; username: string };
376 /** An agent's review: its verdict is advisory and counts toward nothing. */
377 advisory?: boolean;
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending378 };
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts379 /** A comment's text changed; `changes.body.from` is what it said before. */
380 "comment.edited": {
381 commentId: string;
382 repoId: string;
383 number: number;
384 /** Set when the comment is on a pull request. */
385 pullId?: string;
386 changes: { body: { from: string } };
387 };
388 /** A comment was deleted; `comment` is the comment as it was. */
389 "comment.deleted": {
390 commentId: string;
391 repoId: string;
392 number: number;
393 /** Set when the comment was on a pull request. */
394 pullId?: string;
395 comment: {
396 id: string;
397 body: string;
398 author: { id: string; username: string };
399 createdAt: string;
400 path: string | null;
401 line: number | null;
402 };
403 };
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending404 "session.appended": { pullId: string; repoId: string; number: number; count: number };
405 /**
Events: review requests, assignments, stops and deployments are published406 * A build of a project finished, for production or one pull request's
407 * preview (`number`). `path` is the deployment's page on the site;
408 * `recovered`, on a success, says the build before it failed.
409 */
410 "deployment.succeeded": DeploymentEventData;
411 "deployment.failed": DeploymentEventData;
412 /**
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97413 * A deployment was made, wherever it runs: reported through the API, by
414 * a g1t Actions job with an `environment:`, or a g1t.page build. Its
415 * `payload` is left out: read the deployment for it.
416 */
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts417 "deployment.created": { repoId: string; deployment: Omit<RepoDeployment, "payload">; causedByJob?: string };
418 /**
419 * A deployment has a new status; `deployment` is as it is now.
420 * `causedByJob` (as on every event a workflow job's token causes) is the
421 * run whose job made it, so no workflow starts for it.
422 */
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97423 "deployment_status.created": {
424 repoId: string;
425 deployment: Omit<RepoDeployment, "payload">;
426 deploymentStatus: DeploymentStatus;
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts427 causedByJob?: string;
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97428 };
429 /**
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts430 * A release changed, one event per GitHub release activity it amounts
431 * to: made (`created`; a published one is also `published`, and
432 * `released` or `prereleased`), a draft published, edited, made a draft
433 * again (`unpublished`) or deleted. `release` is as it is now (as it was,
434 * for `release.deleted`).
435 */
436 "release.created": ReleaseEventData;
437 "release.published": ReleaseEventData;
438 "release.released": ReleaseEventData;
439 "release.prereleased": ReleaseEventData;
440 "release.edited": ReleaseEventData;
441 "release.unpublished": ReleaseEventData;
442 "release.deleted": ReleaseEventData;
443 /**
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member444 * A package version was published, such as an image pushed by
445 * `docker push`. `tags` are the tags that now point to it; `repoId` (and
446 * the event's) is the repository the package is linked to, if any.
447 */
448 "package.published": PackageEventData & { version: string; digest: string; size: number; tags: string[] };
449 /** One version of a package was deleted, with the tags that pointed to it. */
450 "package.version_deleted": PackageEventData & { version: string; digest: string };
451 /** A package was deleted with every version it had. */
452 "package.deleted": PackageEventData;
453 /** A package became public or private. */
454 "package.visibility_changed": PackageEventData & { visibility: "public" | "private" };
455 /**
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending456 * A workspace's slug changed from `from` to `to`. Services that store a
457 * slug move their rows to the workspace's *current* slug (see
458 * `currentWorkspaceSlug`), so a repeated or late delivery after a second
459 * rename still lands in the right place.
460 */
461 "workspace.renamed": { workspaceId: string; from: string; to: string };
462 /**
463 * A repository moved from workspace `from` to `to`, keeping its id and
464 * name. Services that store its path or its workspace's slug move those
465 * rows to its *current* path (ask repos `path_by_id`), so a repeated or
466 * late delivery after a second transfer still lands in the right place.
467 */
468 "repo.transferred": { repoId: string; name: string; from: string; to: string };
469 /**
470 * A workspace is gone. Services drop what they keep for it alone; ledgers,
471 * invoices and the audit log stay under its slug, which is never reused.
472 */
473 "workspace.deleted": { workspaceId: string; slug: string };
474 /**
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member475 * An owner deleted a workspace; staff can restore it until `purgeAfter`,
476 * and nobody can reach it meanwhile. Services hide what they keep for it
477 * and stop what runs for it, keeping their rows: repos deletes its
478 * repositories softly (`repo.deleted` with `withWorkspace`), deployments
479 * pauses its apps, search drops it. `workspace.restored` undoes exactly
480 * that; `workspace.deleted` follows once `purgeAfter` passes. `by` is the
481 * owner's username.
482 */
483 "workspace.deleting": { workspaceId: string; slug: string; by: string; purgeAfter: string };
484 /**
485 * Staff brought a deleted workspace back with its members and tokens.
486 * Services undo what they did on `workspace.deleting`, and only that.
487 */
488 "workspace.restored": { workspaceId: string; slug: string };
489 /**
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending490 * A memory was added, changed, reviewed or forgotten. No text: ask the
491 * work service for it by id. `repoId` is the project's, or null for the
492 * workspace's memory. `status` is `deleted` once forgotten.
493 */
494 "memory.changed": { memoryId: string; workspace: string; status: "candidate" | "kept" | "dismissed" | "deleted" };
495 /**
496 * A sandbox was stopped because it looked like it was mining: CPU pinned
497 * with little I/O and no progress, or a miner seen by name. For g1t's
498 * staff, in sudo; published with no `repoId` so it never reaches a
499 * repository's timeline or webhooks. `metrics` is what the sandbox
500 * measured (`Verdict` in crates/runner abuse.rs), or null if it could
501 * not say.
502 */
503 "abuse.flagged": {
504 workspace: string;
505 repo: string | null;
506 /** The agent run, when the sandbox had one. */
507 run: string | null;
508 /** What the sandbox was for: agent, checks, queue, actions, deploy... */
509 kind: string;
510 sandbox: string;
511 metrics: Record<string, unknown> | null;
512 };
Docs know what code they describe; a project's docs folder in Docs; Docs events; files on any S3 store513 /**
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.514 * 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 store515 * a page (which may be in a private space) never reaches a repository's
516 * 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.517 * 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 store518 */
519 "doc.page.created": DocPageEventData;
520 /**
521 * A page's content changed: at most once per page every ten minutes of
522 * editing (when its history records a version), and for every agent
523 * edit, accepted suggestion and restore. `authors` are member keys
524 * (`user:<id>`, `agent:<id>`) of everyone whose changes are in it.
525 */
526 "doc.page.updated": DocPageEventData & { versionId: string; kind: "edit" | "agent" | "suggestion" | "restore"; authors: string[] };
527 /** A page went to the trash (with every page under it; one event for the page asked about). */
528 "doc.page.archived": DocPageEventData;
529 /**
530 * A page became possibly out of date: a merged pull request or a push to
531 * a repository's default branch changed code it cites. `repoId` is in
532 * `data`, not on the event, for the same reason as above. `owners` are
533 * member keys; an agent that owns the page can update it
534 * (`stalePagesForAgent` in docs.ts).
535 */
536 "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 yet537 /**
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.538 * 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 yet539 * 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.540 * 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 yet541 */
542 "folio.created": FolioEventData;
543 /** A folio's content changed: a version (`versionKind`) with everyone whose changes are in it. */
544 "folio.updated": FolioEventData & { versionId: string; versionKind: "edit" | "agent" | "suggestion" | "proposal" | "restore"; authors: string[] };
545 /** A folio went to the trash (with everything under it; one event for the folio asked about). */
546 "folio.trashed": FolioEventData;
547 "folio.restored": FolioEventData;
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9548 /**
549 * A folio was deleted for good from the trash (with everything under it;
550 * one event for each top that went): by someone with full access, by
551 * emptying the trash, or by the daily purge (`actor` null then).
552 */
553 "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 yet554 /** Someone was given access: who (member keys) and the role. Never content. */
555 "folio.shared": FolioEventData & { principals: string[]; role: "view" | "comment" | "edit" | "manage" };
556 /** Code a folio cites changed. The repository is in `data` as `owner/name` only. */
557 "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-7nm8r9558 /**
559 * A space was deleted (services/artifacts): everything in it went to the
560 * trash (`trashed` counts the artifacts; this one event stands for them
561 * all). Like `folio.*`, published with no `repoId` and never offered to
562 * webhooks; `name` is null for a members-only space.
563 */
564 "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 yet565};
566
567/**
568 * What every `folio.*` event carries. `title` is null unless every member
569 * of the workspace can read the folio, so a private folio's name never
570 * travels.
571 */
572export type FolioEventData = {
573 workspace: string;
574 workspaceId: string;
575 folioId: string;
576 kind: "doc" | "slides" | "design" | "dashboard";
577 spaceId: string | null;
578 title: string | null;
Docs know what code they describe; a project's docs folder in Docs; Docs events; files on any S3 store579};
580
581/** What every `doc.page.*` event carries. */
582export type DocPageEventData = {
583 workspace: string;
584 workspaceId: string;
585 pageId: string;
586 spaceId: string;
587 title: string;
588 /** The page's address on the site. */
589 path: string;
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending590};
591
592export type EventType = keyof EventPayloads;
593
594export type G1tEvent<T extends EventType = EventType> = {
595 [K in T]: {
596 id: string;
597 type: K;
598 /** The service that published it. */
599 source: string;
600 /** RFC 3339. */
601 time: string;
602 /** The repo the event concerns, used to scope timelines and deliveries. */
603 repoId: string | null;
604 /** The user or agent that caused it, if any. */
605 actor: string | null;
606 data: EventPayloads[K];
607 };
608}[T];
609
610/** What a publisher supplies; the bus fills in `id` and `time`. */
611export type NewEvent<T extends EventType = EventType> = {
612 [K in T]: Omit<G1tEvent<K>, "id" | "time">;
613}[T];
614
615export type EventQuery = {
616 repoId?: string;
617 types?: EventType[];
618 /** Return events older than this event id. */
619 before?: string;
Merge leftovers: plan activity filtered in the query, pushes counted by account, ghost during the deletion window, profile time zones (identity 0039)620 /** Only events by this account id. */
621 actor?: string;
622 /** Only events about these issues or pull requests (`number`, or the `issue` a comment or review is on). */
623 numbers?: number[];
624 /** Only events at or after this RFC 3339 time. */
625 since?: string;
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending626 limit?: number;
627};
628
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.629/**
630 * `activity_digest`: what happened in some repositories, and to a
631 * workspace's artifacts, over `[from, until)`, counted by who did it. Home
632 * reads it for what people and agents did since you were last there.
633 * snake_case, as the Rust service reads it
634 * (`g1t_contracts::events::ActivityDigestArgs`).
635 */
636export type ActivityDigestArgs = {
637 /** By id; the caller has checked the viewer may read each. At most `MAX_DIGEST_REPOS` are read. */
638 repo_ids: string[];
639 /** The workspace's slug, for its `folio.*` events (which carry no repository); null leaves artifacts out. */
640 workspace: string | null;
641 /** RFC 3339, inclusive. */
642 from: string;
643 /** RFC 3339, exclusive. */
644 until: string;
645};
646
647/** The most repositories one digest reads. */
648export const MAX_DIGEST_REPOS = 50;
649
650/**
651 * How many times one actor did something. The actor is a member key:
652 * `user:<id>` for a person (or g1t, `user:usr_g1t_agent`), `agent:<id>` for
653 * one of the workspace's agents acting as itself, or `""` when the event
654 * named nobody (a push copied in by a mirror).
655 */
656export type ActorCount = { actor: string; count: number };
657
658/** Pushes by one actor, with the commits they brought. */
659export type PushesBy = { actor: string; count: number; commits: number };
660
661/** Pushes to a repository's branches (tags are not pushes here). A push whose commits were not counted counts as one commit. */
662export type PushDigest = {
663 count: number;
664 commits: number;
665 /** The branches pushed to, by name, sorted. */
666 branches: string[];
667 /** Most pushes first. */
668 by: PushesBy[];
669 /** Of those, the pushes straight to the default branch: what landed without a pull request. */
670 default_branch: { count: number; commits: number; by: PushesBy[]; last_at: string | null };
671};
672
673export type RepoDigest = {
674 repo_id: string;
675 pushes: PushDigest;
676 /** Pull requests opened, merged and closed without merging, each by who did it. */
677 pulls: { opened: ActorCount[]; merged: ActorCount[]; closed: ActorCount[] };
678 issues: { opened: ActorCount[]; closed: ActorCount[] };
679 /** `review.completed` (g1t's), and a comment with a verdict (a person's). */
680 reviews: ActorCount[];
681 /** Comments without a verdict; one by an agent as itself is the agent's. */
682 comments: ActorCount[];
683 /** Builds that finished, by who set them off; `production` is how many successes were production. */
684 deployments: { succeeded: ActorCount[]; failed: ActorCount[]; production: number };
685 /** Releases published, newest first, at most 50. */
686 releases: { tag: string; name: string | null; actor: string; at: string }[];
687 /** Package versions published, newest first, at most 50. */
688 packages: { ecosystem: string; name: string; version: string; actor: string; at: string }[];
689};
690
691/** A workspace's artifacts over the span. Never a title. */
692export type FolioDigest = {
693 created: ActorCount[];
694 /** Each folio whose content changed, once, with everyone whose changes are in it (member keys); at most 50. */
695 edited: { folio_id: string; kind: "doc" | "slides" | "design" | "dashboard" | string; authors: string[] }[];
696 /** How many folios changed, counting those past the cap. */
697 edited_count: number;
698};
699
700export type ActivityDigest = {
701 from: string;
702 until: string;
703 /** One per repository that had any event counted; none for a quiet one. */
704 repos: RepoDigest[];
705 /** When a workspace was named. */
706 folios: FolioDigest | null;
707 /** False when more events fell in the span than were read, or more repositories were named than are read, so counts are low. */
708 complete: boolean;
709};
710
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending711/** The event bus and its durable log. */
712export interface EventsApi {
713 publish(events: NewEvent[]): Promise<void>;
714 /** Newest first. */
715 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.716 /** A span of some repositories' and a workspace's artifacts' events, counted by who did it. */
717 activityDigest(args: ActivityDigestArgs): Promise<ActivityDigest>;
A click away from a live page arrives: pages stop refreshing themselves while a navigation is pending718}

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