g1t/packages/contracts/src/events.ts
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 attempts | 1 | /** |
| 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 slide | 4 | * feeds timelines, webhooks and workflows. |
| Initial g1t: services, event bus, intents and attempts | 5 | * |
| 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 shell | 9 | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 10 | import type { RepoRole } from "./access"; |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 11 | import type { Verdict } from "./work"; |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 12 | |
| 13 | /** The payload of the `repo.collaborator_*` events. */ | |
| 14 | export type RepoCollaboratorData = { | |
| 15 | repoId: string; | |
| 16 | namespace: string; | |
| 17 | name: string; | |
| 18 | username: string; | |
| 19 | role: RepoRole | null; | |
| 20 | previousRole: RepoRole | null; | |
| 21 | }; | |
| Initial g1t: services, event bus, intents and attempts | 22 | export type EventPayloads = { |
| 23 | "repo.created": { repoId: string; namespace: string; name: string; isPrivate: boolean }; | |
| Issues and pull requests replace intents and attempts | 24 | "repo.forked": { repoId: string; sourceRepoId: string; pullId: string }; |
| Events service in Rust, with RFC 3339 times and accurate push events | 25 | /** |
| Search across all of g1t, Explore, and a command palette | 26 | * A repository's description, topics or visibility changed. |
| 27 | * `visibilityChanged` says whether it went public or private, which | |
| 28 | * `repo.visibility_changed` also announces on its own. | |
| 29 | */ | |
| 30 | "repo.updated": { repoId: string; namespace: string; name: string; isPrivate: boolean; visibilityChanged: boolean }; | |
| 31 | "repo.visibility_changed": { repoId: string; isPrivate: boolean }; | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 32 | /** |
| 33 | * A repository's name changed within its workspace `namespace`, from | |
| 34 | * `from` to `to`, keeping its id. A path change like `repo.transferred`: | |
| 35 | * services move rows kept under its path to its *current* path (see | |
| 36 | * `repoMove`, `currentMovedPath`). | |
| 37 | */ | |
| 38 | "repo.renamed": { repoId: string; namespace: string; from: string; to: string }; | |
| 39 | /** | |
| 40 | * A repository was deleted. It is hidden and git refuses it, but it can | |
| 41 | * be restored until `purgeAfter`: services stop what runs for it and hide | |
| 42 | * it, and keep their rows until `repo.purged`. | |
| 43 | */ | |
| 44 | "repo.deleted": { repoId: string; namespace: string; name: string; isPrivate: boolean; purgeAfter: string }; | |
| 45 | /** A deleted repository is back, as it was. Services start again what they stopped. */ | |
| 46 | "repo.restored": { repoId: string; namespace: string; name: string; isPrivate: boolean }; | |
| 47 | /** | |
| 48 | * A deleted repository is gone for good, its git data with it. Services | |
| 49 | * drop every row they keep for it, except a workspace's history (ledgers, | |
| 50 | * invoices, the audit log). | |
| 51 | */ | |
| 52 | "repo.purged": { repoId: string; namespace: string; name: string }; | |
| 53 | /** | |
| 54 | * A repository was archived (read-only: pushes, merges, agents and | |
| 55 | * workflows refused; issues and pull requests locked; deployments keep | |
| 56 | * serving), or unarchived. | |
| 57 | */ | |
| 58 | "repo.archived": { repoId: string; namespace: string; name: string; archived: true }; | |
| 59 | "repo.unarchived": { repoId: string; namespace: string; name: string; archived: false }; | |
| 60 | /** The default branch is now `to`; `renamed` when `from` was renamed to it. */ | |
| 61 | "repo.default_branch_changed": { repoId: string; from: string; to: string; renamed: boolean }; | |
| 62 | /** A branch was renamed. Pull requests from it follow. */ | |
| 63 | "branch.renamed": { repoId: string; from: string; to: string; defaultBranch: boolean }; | |
| Search across all of g1t, Explore, and a command palette | 64 | /** An account was made, or changed what its profile shows. Ask identity for the profile. */ |
| 65 | "user.updated": { username: string }; | |
| 66 | /** A workspace was made, or its name, description or icon changed. */ | |
| 67 | "workspace.updated": { workspaceId: string; slug: string }; | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 68 | /** Someone, or g1t staff, made an invite. Never the code or the address. */ |
| 69 | "invite.created": { inviteId: string; inviterId: string | null; workspaceId: string | null; bound: boolean }; | |
| 70 | /** An invite was used: by a new account, or by an account joining a workspace. */ | |
| 71 | "invite.redeemed": { | |
| 72 | inviteId: string; | |
| 73 | userId: string; | |
| 74 | inviterId: string | null; | |
| 75 | workspaceId: string | null; | |
| 76 | createdAccount: boolean; | |
| 77 | }; | |
| 78 | /** Someone asked for access while registration is invite-only. The address is not in the event. */ | |
| 79 | "waitlist.requested": { entryId: string }; | |
| Search across all of g1t, Explore, and a command palette | 80 | /** |
| Events service in Rust, with RFC 3339 times and accurate push events | 81 | * One branch moved by a push. `ref` is the full ref, `after` the commit it |
| 82 | * points to now, and `defaultBranch` whether it is the default branch. | |
| 83 | */ | |
| 84 | "git.push": { repoId: string; ref: string; after: string; defaultBranch: boolean }; | |
| Issues and pull requests replace intents and attempts | 85 | "issue.opened": { issueId: string; repoId: string; number: number; title: string }; |
| 86 | "issue.updated": { issueId: string; repoId: string; number: number }; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 87 | /** The people an issue is assigned to changed; `assignees` is the new set. */ |
| 88 | "issue.assigned": { issueId: string; repoId: string; number: number; assignees: string[] }; | |
| Issues and pull requests replace intents and attempts | 89 | /** `resolvedBy` is the number of the pull request whose merge closed it. */ |
| 90 | "issue.closed": { | |
| 91 | issueId: string; | |
| 92 | repoId: string; | |
| 93 | number: number; | |
| 94 | reason: "completed" | "not_planned"; | |
| 95 | resolvedBy?: number; | |
| 96 | }; | |
| 97 | "issue.reopened": { issueId: string; repoId: string; number: number }; | |
| 98 | /** `issue` is the number of the issue the pull request is for. */ | |
| 99 | "pull.opened": { pullId: string; repoId: string; number: number; issue?: number; agent: string }; | |
| 100 | "pull.ready": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Acceptance checks in sandboxes, line comments and review verdicts | 101 | /** A push moved the head of a pull request that is ready for review. */ |
| 102 | "pull.updated": { pullId: string; repoId: string; number: number; issue?: number; commit: string }; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 103 | /** A merge was asked for while the pull request was behind; it has to catch up first. */ |
| 104 | "pull.merge_requested": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Issues and pull requests replace intents and attempts | 105 | "pull.closed": { pullId: string; repoId: string; number: number; issue?: number }; |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 106 | /** |
| 107 | * The pull request's head or its target moved and the files both changed | |
| 108 | * overlap: a sandbox should find out whether it still merges cleanly. | |
| 109 | * `commit` is its head. | |
| 110 | */ | |
| 111 | "pull.mergecheck": { pullId: string; repoId: string; number: number; issue?: number; commit: string }; | |
| 112 | /** Whether the pull request merges cleanly was settled. */ | |
| 113 | "pull.mergeability": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Agents asked while not at work are woken to answer | 114 | /** Another agent asked the agent on a pull request, which was not at work, a question or handed it work. */ |
| 115 | "agent.asked": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Issues and pull requests replace intents and attempts | 116 | "pull.merged": { pullId: string; repoId: string; number: number; issue?: number; commit: string }; |
| Acceptance checks in sandboxes, line comments and review verdicts | 117 | /** A run of the acceptance checks finished. `commit` is what was checked. */ |
| 118 | "checks.completed": { | |
| 119 | pullId: string; | |
| 120 | repoId: string; | |
| 121 | number: number; | |
| 122 | status: "passed" | "failed" | "errored"; | |
| 123 | commit: string; | |
| 124 | }; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 125 | /** A g1t agent finished reviewing a pull request; no verdict if it could not. */ |
| 126 | "review.completed": { | |
| 127 | pullId: string; | |
| 128 | repoId: string; | |
| 129 | number: number; | |
| 130 | verdict?: "approve" | "request_changes"; | |
| 131 | }; | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 132 | /** A person was given a role on one repository directly, had it changed, or lost it. `role` is null once removed. */ |
| 133 | "repo.collaborator_added": RepoCollaboratorData; | |
| 134 | "repo.collaborator_removed": RepoCollaboratorData; | |
| 135 | "repo.collaborator_role_changed": RepoCollaboratorData; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 136 | /** A repository's merge queue gained, lost or settled an entry. */ |
| 137 | "queue.changed": { repoId: string }; | |
| What happened across an outcome, as a feed beside its graph | 138 | /** `number` is the issue or pull request commented on. */ |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 139 | "comment.created": { |
| 140 | commentId: string; | |
| 141 | repoId: string; | |
| 142 | number: number; | |
| 143 | /** Set when the comment is on a pull request. */ | |
| 144 | pullId?: string; | |
| 145 | /** Set when the comment is a review. */ | |
| 146 | verdict?: Verdict; | |
| 147 | }; | |
| Issues and pull requests replace intents and attempts | 148 | "session.appended": { pullId: string; repoId: string; number: number; count: number }; |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 149 | /** |
| 150 | * A workspace's slug changed from `from` to `to`. Services that store a | |
| 151 | * slug move their rows to the workspace's *current* slug (see | |
| 152 | * `currentWorkspaceSlug`), so a repeated or late delivery after a second | |
| 153 | * rename still lands in the right place. | |
| 154 | */ | |
| 155 | "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 API | 156 | /** |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 157 | * A repository moved from workspace `from` to `to`, keeping its id and |
| 158 | * name. Services that store its path or its workspace's slug move those | |
| 159 | * rows to its *current* path (ask repos `path_by_id`), so a repeated or | |
| 160 | * late delivery after a second transfer still lands in the right place. | |
| 161 | */ | |
| 162 | "repo.transferred": { repoId: string; name: string; from: string; to: string }; | |
| 163 | /** | |
| 164 | * A workspace is gone. Services drop what they keep for it alone; ledgers, | |
| 165 | * invoices and the audit log stay under its slug, which is never reused. | |
| 166 | */ | |
| 167 | "workspace.deleted": { workspaceId: string; slug: string }; | |
| 168 | /** | |
| Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API | 169 | * A memory was added, changed, reviewed or forgotten. No text: ask the |
| 170 | * work service for it by id. `repoId` is the project's, or null for the | |
| 171 | * workspace's memory. `status` is `deleted` once forgotten. | |
| 172 | */ | |
| 173 | "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 look | 174 | /** |
| 175 | * A sandbox was stopped because it looked like it was mining: CPU pinned | |
| 176 | * with little I/O and no progress, or a miner seen by name. For g1t's | |
| 177 | * staff, in sudo; published with no `repoId` so it never reaches a | |
| 178 | * repository's timeline or webhooks. `metrics` is what the sandbox | |
| 179 | * measured (`Verdict` in crates/runner abuse.rs), or null if it could | |
| 180 | * not say. | |
| 181 | */ | |
| 182 | "abuse.flagged": { | |
| 183 | workspace: string; | |
| 184 | repo: string | null; | |
| 185 | /** The agent run, when the sandbox had one. */ | |
| 186 | run: string | null; | |
| 187 | /** What the sandbox was for: agent, checks, queue, actions, deploy... */ | |
| 188 | kind: string; | |
| 189 | sandbox: string; | |
| 190 | metrics: Record<string, unknown> | null; | |
| 191 | }; | |
| Initial g1t: services, event bus, intents and attempts | 192 | }; |
| 193 | ||
| 194 | export type EventType = keyof EventPayloads; | |
| 195 | ||
| 196 | export type G1tEvent<T extends EventType = EventType> = { | |
| 197 | [K in T]: { | |
| 198 | id: string; | |
| 199 | type: K; | |
| 200 | /** The service that published it. */ | |
| 201 | source: string; | |
| Events service in Rust, with RFC 3339 times and accurate push events | 202 | /** RFC 3339. */ |
| 203 | time: string; | |
| Initial g1t: services, event bus, intents and attempts | 204 | /** The repo the event concerns, used to scope timelines and deliveries. */ |
| 205 | repoId: string | null; | |
| 206 | /** The user or agent that caused it, if any. */ | |
| 207 | actor: string | null; | |
| 208 | data: EventPayloads[K]; | |
| 209 | }; | |
| 210 | }[T]; | |
| 211 | ||
| 212 | /** What a publisher supplies; the bus fills in `id` and `time`. */ | |
| 213 | export type NewEvent<T extends EventType = EventType> = { | |
| 214 | [K in T]: Omit<G1tEvent<K>, "id" | "time">; | |
| 215 | }[T]; | |
| 216 | ||
| 217 | export type EventQuery = { | |
| 218 | repoId?: string; | |
| 219 | types?: EventType[]; | |
| 220 | /** Return events older than this event id. */ | |
| 221 | before?: string; | |
| 222 | limit?: number; | |
| 223 | }; | |
| 224 | ||
| 225 | /** The event bus and its durable log. */ | |
| 226 | export interface EventsApi { | |
| 227 | publish(events: NewEvent[]): Promise<void>; | |
| 228 | /** Newest first. */ | |
| 229 | list(query: EventQuery): Promise<G1tEvent[]>; | |
| 230 | } |