Skip to content

g1t/packages/contracts/src/events.ts

341 lines15,032 bytesCodeBlame

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.

Initial g1t: services, event bus, intents and attempts1/**
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
Sidebar: the panels really slide4 * feeds timelines, webhooks and workflows.
Initial g1t: services, event bus, intents and attempts5 *
6 * The envelope follows CloudEvents: `type` says what happened, `subject`
7 * says to what, `data` is the type-specific payload.
8 */
Agents as a team: lifecycle, merge queue, billing and a new shell9
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look10import type { RepoRole } from "./access";
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step11import type { Confidence, Verdict } from "./work";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look12
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member13/** What every `package.*` event names. */
14export type PackageEventData = {
15 packageId: string;
16 workspace: string;
17 ecosystem: string;
18 name: string;
19 repoId: string | null;
20};
21
Events: review requests, assignments, stops and deployments are published22/** What `deployment.succeeded` and `deployment.failed` carry. */
23export type DeploymentEventData = {
24 deploymentId: string;
25 projectId: string;
26 repoId: string;
27 workspace: string;
28 project: string;
29 kind: "production" | "preview";
30 branch: string | null;
31 number: number | null;
32 commit: string;
33 path: string;
34 error: string | null;
35 recovered: boolean;
36 /** A username, or `g1t`. */
37 triggeredBy: string;
38};
39
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look40/** The payload of the `repo.collaborator_*` events. */
41export type RepoCollaboratorData = {
42 repoId: string;
43 namespace: string;
44 name: string;
45 username: string;
46 role: RepoRole | null;
47 previousRole: RepoRole | null;
48};
Initial g1t: services, event bus, intents and attempts49export type EventPayloads = {
50 "repo.created": { repoId: string; namespace: string; name: string; isPrivate: boolean };
Issues and pull requests replace intents and attempts51 "repo.forked": { repoId: string; sourceRepoId: string; pullId: string };
Events service in Rust, with RFC 3339 times and accurate push events52 /**
Search across all of g1t, Explore, and a command palette53 * A repository's description, topics or visibility changed.
54 * `visibilityChanged` says whether it went public or private, which
55 * `repo.visibility_changed` also announces on its own.
56 */
57 "repo.updated": { repoId: string; namespace: string; name: string; isPrivate: boolean; visibilityChanged: boolean };
58 "repo.visibility_changed": { repoId: string; isPrivate: boolean };
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look59 /**
60 * A repository's name changed within its workspace `namespace`, from
61 * `from` to `to`, keeping its id. A path change like `repo.transferred`:
62 * services move rows kept under its path to its *current* path (see
63 * `repoMove`, `currentMovedPath`).
64 */
65 "repo.renamed": { repoId: string; namespace: string; from: string; to: string };
66 /**
67 * A repository was deleted. It is hidden and git refuses it, but it can
68 * be restored until `purgeAfter`: services stop what runs for it and hide
69 * it, and keep their rows until `repo.purged`.
70 */
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member71 "repo.deleted": {
72 repoId: string;
73 namespace: string;
74 name: string;
75 isPrivate: boolean;
76 purgeAfter: string;
77 /** It went with its workspace (`workspace.deleting`); deployments leaves it to that. */
78 withWorkspace?: boolean;
79 };
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look80 /** 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 member81 "repo.restored": {
82 repoId: string;
83 namespace: string;
84 name: string;
85 isPrivate: boolean;
86 /** It came back with its workspace (`workspace.restored`). */
87 withWorkspace?: boolean;
88 };
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look89 /**
90 * A deleted repository is gone for good, its git data with it. Services
91 * drop every row they keep for it, except a workspace's history (ledgers,
92 * invoices, the audit log).
93 */
94 "repo.purged": { repoId: string; namespace: string; name: string };
95 /**
96 * A repository was archived (read-only: pushes, merges, agents and
97 * workflows refused; issues and pull requests locked; deployments keep
98 * serving), or unarchived.
99 */
100 "repo.archived": { repoId: string; namespace: string; name: string; archived: true };
101 "repo.unarchived": { repoId: string; namespace: string; name: string; archived: false };
102 /** The default branch is now `to`; `renamed` when `from` was renamed to it. */
103 "repo.default_branch_changed": { repoId: string; from: string; to: string; renamed: boolean };
104 /** A branch was renamed. Pull requests from it follow. */
105 "branch.renamed": { repoId: string; from: string; to: string; defaultBranch: boolean };
Search across all of g1t, Explore, and a command palette106 /** An account was made, or changed what its profile shows. Ask identity for the profile. */
107 "user.updated": { username: string };
108 /** A workspace was made, or its name, description or icon changed. */
109 "workspace.updated": { workspaceId: string; slug: string };
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look110 /** Someone, or g1t staff, made an invite. Never the code or the address. */
111 "invite.created": { inviteId: string; inviterId: string | null; workspaceId: string | null; bound: boolean };
112 /** An invite was used: by a new account, or by an account joining a workspace. */
113 "invite.redeemed": {
114 inviteId: string;
115 userId: string;
116 inviterId: string | null;
117 workspaceId: string | null;
118 createdAccount: boolean;
119 };
120 /** Someone asked for access while registration is invite-only. The address is not in the event. */
121 "waitlist.requested": { entryId: string };
Search across all of g1t, Explore, and a command palette122 /**
Events service in Rust, with RFC 3339 times and accurate push events123 * One branch moved by a push. `ref` is the full ref, `after` the commit it
124 * points to now, and `defaultBranch` whether it is the default branch.
125 */
Mission control counts people's direct pushes to the default branch126 /** `before` is where the ref pointed before; absent for a new branch or tag. */
127 "git.push": { repoId: string; ref: string; before?: string; after: string; defaultBranch: boolean };
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights128 /**
129 * `author` is who opened it: g1t, for one its agent filed while at work,
130 * with `requestedBy` the person it was working for. Every issue and pull
131 * request event carries both.
132 */
133 "issue.opened": {
134 issueId: string;
135 repoId: string;
136 number: number;
137 title: string;
138 author?: { id: string; username: string };
139 requestedBy?: { id: string; username: string };
140 };
Issues and pull requests replace intents and attempts141 "issue.updated": { issueId: string; repoId: string; number: number };
Events: review requests, assignments, stops and deployments are published142 /** The people an issue is assigned to changed; `assignees` is the new set, `added` those newly assigned. */
143 "issue.assigned": { issueId: string; repoId: string; number: number; assignees: string[]; added?: string[] };
Issues and pull requests replace intents and attempts144 /** `resolvedBy` is the number of the pull request whose merge closed it. */
145 "issue.closed": {
146 issueId: string;
147 repoId: string;
148 number: number;
149 reason: "completed" | "not_planned";
150 resolvedBy?: number;
151 };
152 "issue.reopened": { issueId: string; repoId: string; number: number };
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights153 /**
154 * `issue` is the number of the issue the pull request is for. `author` is
155 * who opened it: g1t, for a change g1t made, with `requestedBy` the person
156 * who asked for it.
157 */
158 "pull.opened": {
159 pullId: string;
160 repoId: string;
161 number: number;
162 issue?: number;
163 agent: string;
164 author?: { id: string; username: string };
165 requestedBy?: { id: string; username: string };
166 };
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step167 /** `confidence`, on a g1t agent's change once g1t has worked it out, is on every pull request event. */
168 "pull.ready": { pullId: string; repoId: string; number: number; issue?: number; confidence?: Confidence };
Acceptance checks in sandboxes, line comments and review verdicts169 /** A push moved the head of a pull request that is ready for review. */
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step170 "pull.updated": { pullId: string; repoId: string; number: number; issue?: number; commit: string; confidence?: Confidence };
Agents as a team: lifecycle, merge queue, billing and a new shell171 /** A merge was asked for while the pull request was behind; it has to catch up first. */
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step172 "pull.merge_requested": { pullId: string; repoId: string; number: number; issue?: number; confidence?: Confidence };
173 "pull.closed": { pullId: string; repoId: string; number: number; issue?: number; confidence?: Confidence };
Events: review requests, assignments, stops and deployments are published174 /** People were assigned to a pull request: `assignees` is the new set, `added` those newly assigned. */
175 "pull.assigned": { pullId: string; repoId: string; number: number; issue?: number; assignees: string[]; added: string[] };
176 /** Reviewers were asked for a pull request (`reviewers`), or no longer are. */
177 "pull.review_requested": { pullId: string; repoId: string; number: number; issue?: number; reviewers: string[] };
178 "pull.review_request_removed": { pullId: string; repoId: string; number: number; issue?: number; reviewers: string[] };
179 /** g1t stopped seeing a pull request through until a person steps in; `detail` says why. */
180 "pull.stalled": { pullId: string; repoId: string; number: number; issue?: number; detail: string };
181 /** A pull request g1t had stopped on is going again. */
182 "pull.resumed": { pullId: string; repoId: string; number: number; issue?: number };
Agents and memory, checks and conflicts, profiles, slug renames, custom domains183 /**
184 * The pull request's head or its target moved and the files both changed
185 * overlap: a sandbox should find out whether it still merges cleanly.
186 * `commit` is its head.
187 */
188 "pull.mergecheck": { pullId: string; repoId: string; number: number; issue?: number; commit: string };
189 /** Whether the pull request merges cleanly was settled. */
190 "pull.mergeability": { pullId: string; repoId: string; number: number; issue?: number };
Agents asked while not at work are woken to answer191 /** Another agent asked the agent on a pull request, which was not at work, a question or handed it work. */
192 "agent.asked": { pullId: string; repoId: string; number: number; issue?: number };
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step193 "pull.merged": { pullId: string; repoId: string; number: number; issue?: number; commit: string; confidence?: Confidence };
Acceptance checks in sandboxes, line comments and review verdicts194 /** A run of the acceptance checks finished. `commit` is what was checked. */
195 "checks.completed": {
196 pullId: string;
197 repoId: string;
198 number: number;
199 status: "passed" | "failed" | "errored";
200 commit: string;
201 };
Agents as a team: lifecycle, merge queue, billing and a new shell202 /** A g1t agent finished reviewing a pull request; no verdict if it could not. */
203 "review.completed": {
204 pullId: string;
205 repoId: string;
206 number: number;
207 verdict?: "approve" | "request_changes";
208 };
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look209 /** A person was given a role on one repository directly, had it changed, or lost it. `role` is null once removed. */
210 "repo.collaborator_added": RepoCollaboratorData;
211 "repo.collaborator_removed": RepoCollaboratorData;
212 "repo.collaborator_role_changed": RepoCollaboratorData;
Agents as a team: lifecycle, merge queue, billing and a new shell213 /** A repository's merge queue gained, lost or settled an entry. */
214 "queue.changed": { repoId: string };
What happened across an outcome, as a feed beside its graph215 /** `number` is the issue or pull request commented on. */
Agents as a team: lifecycle, merge queue, billing and a new shell216 "comment.created": {
217 commentId: string;
218 repoId: string;
219 number: number;
220 /** Set when the comment is on a pull request. */
221 pullId?: string;
222 /** Set when the comment is a review. */
223 verdict?: Verdict;
224 };
Issues and pull requests replace intents and attempts225 "session.appended": { pullId: string; repoId: string; number: number; count: number };
Agents and memory, checks and conflicts, profiles, slug renames, custom domains226 /**
Events: review requests, assignments, stops and deployments are published227 * A build of a project finished, for production or one pull request's
228 * preview (`number`). `path` is the deployment's page on the site;
229 * `recovered`, on a success, says the build before it failed.
230 */
231 "deployment.succeeded": DeploymentEventData;
232 "deployment.failed": DeploymentEventData;
233 /**
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member234 * A package version was published, such as an image pushed by
235 * `docker push`. `tags` are the tags that now point to it; `repoId` (and
236 * the event's) is the repository the package is linked to, if any.
237 */
238 "package.published": PackageEventData & { version: string; digest: string; size: number; tags: string[] };
239 /** One version of a package was deleted, with the tags that pointed to it. */
240 "package.version_deleted": PackageEventData & { version: string; digest: string };
241 /** A package was deleted with every version it had. */
242 "package.deleted": PackageEventData;
243 /** A package became public or private. */
244 "package.visibility_changed": PackageEventData & { visibility: "public" | "private" };
245 /**
Agents and memory, checks and conflicts, profiles, slug renames, custom domains246 * A workspace's slug changed from `from` to `to`. Services that store a
247 * slug move their rows to the workspace's *current* slug (see
248 * `currentWorkspaceSlug`), so a repeated or late delivery after a second
249 * rename still lands in the right place.
250 */
251 "workspace.renamed": { workspaceId: string; from: string; to: string };
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API252 /**
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look253 * A repository moved from workspace `from` to `to`, keeping its id and
254 * name. Services that store its path or its workspace's slug move those
255 * rows to its *current* path (ask repos `path_by_id`), so a repeated or
256 * late delivery after a second transfer still lands in the right place.
257 */
258 "repo.transferred": { repoId: string; name: string; from: string; to: string };
259 /**
260 * A workspace is gone. Services drop what they keep for it alone; ledgers,
261 * invoices and the audit log stay under its slug, which is never reused.
262 */
263 "workspace.deleted": { workspaceId: string; slug: string };
264 /**
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member265 * An owner deleted a workspace; staff can restore it until `purgeAfter`,
266 * and nobody can reach it meanwhile. Services hide what they keep for it
267 * and stop what runs for it, keeping their rows: repos deletes its
268 * repositories softly (`repo.deleted` with `withWorkspace`), deployments
269 * pauses its apps, search drops it. `workspace.restored` undoes exactly
270 * that; `workspace.deleted` follows once `purgeAfter` passes. `by` is the
271 * owner's username.
272 */
273 "workspace.deleting": { workspaceId: string; slug: string; by: string; purgeAfter: string };
274 /**
275 * Staff brought a deleted workspace back with its members and tokens.
276 * Services undo what they did on `workspace.deleting`, and only that.
277 */
278 "workspace.restored": { workspaceId: string; slug: string };
279 /**
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API280 * A memory was added, changed, reviewed or forgotten. No text: ask the
281 * work service for it by id. `repoId` is the project's, or null for the
282 * workspace's memory. `status` is `deleted` once forgotten.
283 */
284 "memory.changed": { memoryId: string; workspace: string; status: "candidate" | "kept" | "dismissed" | "deleted" };
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look285 /**
286 * A sandbox was stopped because it looked like it was mining: CPU pinned
287 * with little I/O and no progress, or a miner seen by name. For g1t's
288 * staff, in sudo; published with no `repoId` so it never reaches a
289 * repository's timeline or webhooks. `metrics` is what the sandbox
290 * measured (`Verdict` in crates/runner abuse.rs), or null if it could
291 * not say.
292 */
293 "abuse.flagged": {
294 workspace: string;
295 repo: string | null;
296 /** The agent run, when the sandbox had one. */
297 run: string | null;
298 /** What the sandbox was for: agent, checks, queue, actions, deploy... */
299 kind: string;
300 sandbox: string;
301 metrics: Record<string, unknown> | null;
302 };
Initial g1t: services, event bus, intents and attempts303};
304
305export type EventType = keyof EventPayloads;
306
307export type G1tEvent<T extends EventType = EventType> = {
308 [K in T]: {
309 id: string;
310 type: K;
311 /** The service that published it. */
312 source: string;
Events service in Rust, with RFC 3339 times and accurate push events313 /** RFC 3339. */
314 time: string;
Initial g1t: services, event bus, intents and attempts315 /** The repo the event concerns, used to scope timelines and deliveries. */
316 repoId: string | null;
317 /** The user or agent that caused it, if any. */
318 actor: string | null;
319 data: EventPayloads[K];
320 };
321}[T];
322
323/** What a publisher supplies; the bus fills in `id` and `time`. */
324export type NewEvent<T extends EventType = EventType> = {
325 [K in T]: Omit<G1tEvent<K>, "id" | "time">;
326}[T];
327
328export type EventQuery = {
329 repoId?: string;
330 types?: EventType[];
331 /** Return events older than this event id. */
332 before?: string;
333 limit?: number;
334};
335
336/** The event bus and its durable log. */
337export interface EventsApi {
338 publish(events: NewEvent[]): Promise<void>;
339 /** Newest first. */
340 list(query: EventQuery): Promise<G1tEvent[]>;
341}