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 | |
| 10 | import type { Verdict } from "./work"; | |
| Initial g1t: services, event bus, intents and attempts | 11 | export type EventPayloads = { |
| 12 | "repo.created": { repoId: string; namespace: string; name: string; isPrivate: boolean }; | |
| Issues and pull requests replace intents and attempts | 13 | "repo.forked": { repoId: string; sourceRepoId: string; pullId: string }; |
| Events service in Rust, with RFC 3339 times and accurate push events | 14 | /** |
| 15 | * One branch moved by a push. `ref` is the full ref, `after` the commit it | |
| 16 | * points to now, and `defaultBranch` whether it is the default branch. | |
| 17 | */ | |
| 18 | "git.push": { repoId: string; ref: string; after: string; defaultBranch: boolean }; | |
| Issues and pull requests replace intents and attempts | 19 | "issue.opened": { issueId: string; repoId: string; number: number; title: string }; |
| 20 | "issue.updated": { issueId: string; repoId: string; number: number }; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 21 | /** The people an issue is assigned to changed; `assignees` is the new set. */ |
| 22 | "issue.assigned": { issueId: string; repoId: string; number: number; assignees: string[] }; | |
| Issues and pull requests replace intents and attempts | 23 | /** `resolvedBy` is the number of the pull request whose merge closed it. */ |
| 24 | "issue.closed": { | |
| 25 | issueId: string; | |
| 26 | repoId: string; | |
| 27 | number: number; | |
| 28 | reason: "completed" | "not_planned"; | |
| 29 | resolvedBy?: number; | |
| 30 | }; | |
| 31 | "issue.reopened": { issueId: string; repoId: string; number: number }; | |
| 32 | /** `issue` is the number of the issue the pull request is for. */ | |
| 33 | "pull.opened": { pullId: string; repoId: string; number: number; issue?: number; agent: string }; | |
| 34 | "pull.ready": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Acceptance checks in sandboxes, line comments and review verdicts | 35 | /** A push moved the head of a pull request that is ready for review. */ |
| 36 | "pull.updated": { pullId: string; repoId: string; number: number; issue?: number; commit: string }; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 37 | /** A merge was asked for while the pull request was behind; it has to catch up first. */ |
| 38 | "pull.merge_requested": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Issues and pull requests replace intents and attempts | 39 | "pull.closed": { pullId: string; repoId: string; number: number; issue?: number }; |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 40 | /** |
| 41 | * The pull request's head or its target moved and the files both changed | |
| 42 | * overlap: a sandbox should find out whether it still merges cleanly. | |
| 43 | * `commit` is its head. | |
| 44 | */ | |
| 45 | "pull.mergecheck": { pullId: string; repoId: string; number: number; issue?: number; commit: string }; | |
| 46 | /** Whether the pull request merges cleanly was settled. */ | |
| 47 | "pull.mergeability": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Agents asked while not at work are woken to answer | 48 | /** Another agent asked the agent on a pull request, which was not at work, a question or handed it work. */ |
| 49 | "agent.asked": { pullId: string; repoId: string; number: number; issue?: number }; | |
| Issues and pull requests replace intents and attempts | 50 | "pull.merged": { pullId: string; repoId: string; number: number; issue?: number; commit: string }; |
| Acceptance checks in sandboxes, line comments and review verdicts | 51 | /** A run of the acceptance checks finished. `commit` is what was checked. */ |
| 52 | "checks.completed": { | |
| 53 | pullId: string; | |
| 54 | repoId: string; | |
| 55 | number: number; | |
| 56 | status: "passed" | "failed" | "errored"; | |
| 57 | commit: string; | |
| 58 | }; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 59 | /** A g1t agent finished reviewing a pull request; no verdict if it could not. */ |
| 60 | "review.completed": { | |
| 61 | pullId: string; | |
| 62 | repoId: string; | |
| 63 | number: number; | |
| 64 | verdict?: "approve" | "request_changes"; | |
| 65 | }; | |
| 66 | /** A repository's merge queue gained, lost or settled an entry. */ | |
| 67 | "queue.changed": { repoId: string }; | |
| What happened across an outcome, as a feed beside its graph | 68 | /** `number` is the issue or pull request commented on. */ |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 69 | "comment.created": { |
| 70 | commentId: string; | |
| 71 | repoId: string; | |
| 72 | number: number; | |
| 73 | /** Set when the comment is on a pull request. */ | |
| 74 | pullId?: string; | |
| 75 | /** Set when the comment is a review. */ | |
| 76 | verdict?: Verdict; | |
| 77 | }; | |
| Issues and pull requests replace intents and attempts | 78 | "session.appended": { pullId: string; repoId: string; number: number; count: number }; |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 79 | /** |
| 80 | * A workspace's slug changed from `from` to `to`. Services that store a | |
| 81 | * slug move their rows to the workspace's *current* slug (see | |
| 82 | * `currentWorkspaceSlug`), so a repeated or late delivery after a second | |
| 83 | * rename still lands in the right place. | |
| 84 | */ | |
| 85 | "workspace.renamed": { workspaceId: string; from: string; to: string }; | |
| Initial g1t: services, event bus, intents and attempts | 86 | }; |
| 87 | ||
| 88 | export type EventType = keyof EventPayloads; | |
| 89 | ||
| 90 | export type G1tEvent<T extends EventType = EventType> = { | |
| 91 | [K in T]: { | |
| 92 | id: string; | |
| 93 | type: K; | |
| 94 | /** The service that published it. */ | |
| 95 | source: string; | |
| Events service in Rust, with RFC 3339 times and accurate push events | 96 | /** RFC 3339. */ |
| 97 | time: string; | |
| Initial g1t: services, event bus, intents and attempts | 98 | /** The repo the event concerns, used to scope timelines and deliveries. */ |
| 99 | repoId: string | null; | |
| 100 | /** The user or agent that caused it, if any. */ | |
| 101 | actor: string | null; | |
| 102 | data: EventPayloads[K]; | |
| 103 | }; | |
| 104 | }[T]; | |
| 105 | ||
| 106 | /** What a publisher supplies; the bus fills in `id` and `time`. */ | |
| 107 | export type NewEvent<T extends EventType = EventType> = { | |
| 108 | [K in T]: Omit<G1tEvent<K>, "id" | "time">; | |
| 109 | }[T]; | |
| 110 | ||
| 111 | export type EventQuery = { | |
| 112 | repoId?: string; | |
| 113 | types?: EventType[]; | |
| 114 | /** Return events older than this event id. */ | |
| 115 | before?: string; | |
| 116 | limit?: number; | |
| 117 | }; | |
| 118 | ||
| 119 | /** The event bus and its durable log. */ | |
| 120 | export interface EventsApi { | |
| 121 | publish(events: NewEvent[]): Promise<void>; | |
| 122 | /** Newest first. */ | |
| 123 | list(query: EventQuery): Promise<G1tEvent[]>; | |
| 124 | } |