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

Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths1//! The webhooks service: events, delivered to the addresses a repository or
2//! a workspace registers.
3//!
4//! Every event g1t publishes can be delivered: an HTTPS `POST` of JSON,
5//! signed with the webhook's secret in `X-G1t-Signature-256`, and retried
6//! with growing waits when the receiver does not answer with a 2xx. Each
7//! delivery is kept, with what was sent and what came back, and can be sent
8//! again.
9//!
10//! Mirrors `packages/contracts/src/webhooks.ts`.
11
12use serde::{Deserialize, Serialize};
13
14use crate::repos::RepoPath;
15use crate::{User, Viewer};
16
17/// Every event a webhook can be sent, in the order people are shown them.
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.18pub const EVENT_TYPES: [&str; 109] = [
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths19 "git.push",
Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r920 "git.deleted",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths21 "branch.renamed",
22 "repo.created",
23 "repo.forked",
24 "repo.updated",
25 "repo.visibility_changed",
26 "repo.renamed",
27 "repo.transferred",
28 "repo.default_branch_changed",
29 "repo.archived",
30 "repo.unarchived",
31 "repo.deleted",
32 "repo.restored",
33 "repo.purged",
34 "repo.collaborator_added",
35 "repo.collaborator_removed",
36 "repo.collaborator_role_changed",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar37 "team.created",
38 "team.edited",
39 "team.deleted",
40 "team.member_added",
41 "team.member_role_changed",
42 "team.member_removed",
43 "team.repo_added",
44 "team.repo_role_changed",
45 "team.repo_removed",
@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.46 "workspace.member_joined",
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge47 "ruleset.created",
48 "ruleset.updated",
49 "ruleset.deleted",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths50 "issue.opened",
51 "issue.updated",
52 "issue.assigned",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar53 "issue.labeled",
54 "issue.unlabeled",
55 "issue.milestoned",
56 "issue.demilestoned",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths57 "issue.closed",
58 "issue.reopened",
59 "comment.created",
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts60 "comment.edited",
61 "comment.deleted",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths62 "pull.opened",
63 "pull.ready",
64 "pull.updated",
65 "pull.merge_requested",
66 "pull.merged",
67 "pull.closed",
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts68 "pull.reopened",
69 "pull.converted_to_draft",
Events: review requests, assignments, stops and deployments are published70 "pull.assigned",
71 "pull.review_requested",
72 "pull.review_request_removed",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar73 "pull.labeled",
74 "pull.unlabeled",
75 "pull.milestoned",
76 "pull.demilestoned",
77 "pull.base_changed",
Events: review requests, assignments, stops and deployments are published78 "pull.stalled",
79 "pull.resumed",
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts80 "release.created",
81 "release.published",
82 "release.released",
83 "release.prereleased",
84 "release.edited",
85 "release.unpublished",
86 "release.deleted",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths87 "agent.asked",
88 "checks.completed",
Merge checks: statuses and check runs on every commit89 "status.created",
90 "check_run.created",
91 "check_run.completed",
92 "check_run.rerequested",
93 "check_run.requested_action",
94 "check_suite.completed",
95 "check_suite.rerequested",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths96 "review.completed",
97 "workflow.completed",
Events: review requests, assignments, stops and deployments are published98 "deployment.succeeded",
99 "deployment.failed",
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97100 "deployment.created",
101 "deployment_status.created",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths102 "queue.changed",
103 "session.appended",
104 "package.published",
105 "package.version_deleted",
106 "package.deleted",
107 "package.visibility_changed",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar108 "secret_scanning_alert.created",
109 "secret_scanning_alert.fixed",
110 "secret_scanning_alert.dismissed",
111 "secret_scanning_alert.reopened",
112 "secret_scanning.bypass_requested",
113 "secret_scanning.bypass_reviewed",
114 "code_scanning_alert.created",
115 "code_scanning_alert.fixed",
116 "code_scanning_alert.dismissed",
117 "code_scanning_alert.reopened",
118 "vulnerability_alert.created",
119 "vulnerability_alert.fixed",
120 "vulnerability_alert.dismissed",
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9121 "secret_scanning_alert.summary",
122 "code_scanning_alert.summary",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar123 "vulnerability_alert.reopened",
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9124 "vulnerability_alert.summary",
125 "security_advisory.published",
126 "security_advisory.withdrawn",
127 "security_advisory.reported",
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths128];
129
130/// What a webhook belongs to.
131#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
132#[serde(rename_all = "snake_case")]
133pub enum HookScope {
134 /// One repository's events.
135 Repo,
136 /// The events of every repository in a workspace.
137 Workspace,
138}
139
140#[derive(Clone, Debug, Serialize, Deserialize)]
141#[serde(rename_all = "camelCase")]
142pub struct Hook {
143 pub id: String,
144 pub scope: HookScope,
145 pub workspace: String,
146 /// For a repository's webhook: `owner/name`.
147 pub repo: Option<String>,
148 pub url: String,
149 /// The event types it is sent, or `["*"]` for all.
150 pub events: Vec<String>,
151 pub active: bool,
152 /// The last four characters of its secret.
153 pub secret_hint: String,
154 pub created_by: String,
155 /// RFC 3339.
156 pub created_at: String,
157 /// How its latest delivery went: `delivered`, `pending` or `failed`.
158 pub last_status: Option<String>,
159 pub last_delivered_at: Option<String>,
160}
161
162/// One event sent, or being sent, to a webhook.
163#[derive(Clone, Debug, Serialize, Deserialize)]
164#[serde(rename_all = "camelCase")]
165pub struct HookDelivery {
166 pub id: String,
167 pub hook_id: String,
168 /// The event's id, or empty for a ping.
169 pub event_id: String,
170 pub event: String,
171 /// `pending` while it will be tried again, `delivered`, or `failed` once
172 /// it has been tried as often as it will be.
173 pub status: String,
174 pub attempts: u32,
175 /// The receiver's HTTP status, the last time it answered.
176 pub response_status: Option<u16>,
177 /// The start of what it answered.
178 pub response_body: Option<String>,
179 /// Why the last attempt failed, when the receiver could not be reached.
180 pub error: Option<String>,
181 pub duration_ms: Option<u32>,
182 /// The JSON that was sent.
183 pub payload: String,
184 /// RFC 3339.
185 pub created_at: String,
186 pub delivered_at: Option<String>,
187 pub next_attempt_at: Option<String>,
188}
189
190/// Which webhooks a call is about: a repository's, or with `repo` left out,
191/// the workspace's own.
192#[derive(Clone, Debug, Serialize, Deserialize)]
193pub struct HookOwner {
194 pub workspace: String,
195 #[serde(default)]
196 pub repo: Option<RepoPath>,
197}
198
199/// `list`. Returns `Outcome<Vec<Hook>>`. Members of the workspace only.
200#[derive(Debug, Serialize, Deserialize)]
201pub struct ListArgs {
202 pub viewer: Viewer,
203 #[serde(flatten)]
204 pub owner: HookOwner,
205}
206
207/// `create`. Returns `Outcome<CreatedHook>`. Members, for a repository's
208/// webhooks; owners, for the workspace's.
209#[derive(Debug, Serialize, Deserialize)]
210pub struct CreateArgs {
211 pub actor: User,
212 #[serde(flatten)]
213 pub owner: HookOwner,
214 pub url: String,
215 /// Event types, or `["*"]` for all. All when empty.
216 #[serde(default)]
217 pub events: Vec<String>,
218 /// Made by g1t when left out.
219 #[serde(default)]
220 pub secret: Option<String>,
221}
222
223#[derive(Clone, Debug, Serialize, Deserialize)]
224pub struct CreatedHook {
225 pub hook: Hook,
226 /// The secret, when g1t made it: shown this once.
227 pub secret: Option<String>,
228}
229
230/// `update`: only the fields given change. Returns `Outcome<Hook>`.
231#[derive(Debug, Serialize, Deserialize)]
232pub struct UpdateArgs {
233 pub actor: User,
234 #[serde(flatten)]
235 pub owner: HookOwner,
236 pub id: String,
237 #[serde(default)]
238 pub url: Option<String>,
239 #[serde(default)]
240 pub events: Option<Vec<String>>,
241 #[serde(default)]
242 pub active: Option<bool>,
243}
244
245/// `delete` (returns `Outcome<bool>`) and `ping` (sends a `ping` event and
246/// returns `Outcome<HookDelivery>`).
247#[derive(Debug, Serialize, Deserialize)]
248pub struct HookArgs {
249 pub actor: User,
250 #[serde(flatten)]
251 pub owner: HookOwner,
252 pub id: String,
253}
254
255/// `deliveries`: a webhook's latest deliveries, newest first. Returns
256/// `Outcome<Vec<HookDelivery>>`.
257#[derive(Debug, Serialize, Deserialize)]
258pub struct DeliveriesArgs {
259 pub viewer: Viewer,
260 #[serde(flatten)]
261 pub owner: HookOwner,
262 pub id: String,
263}
264
265/// `redeliver`: sends a delivery's payload again, as a new delivery.
266/// Returns `Outcome<HookDelivery>`.
267#[derive(Debug, Serialize, Deserialize)]
268#[serde(rename_all = "camelCase")]
269pub struct RedeliverArgs {
270 pub actor: User,
271 #[serde(flatten)]
272 pub owner: HookOwner,
273 pub delivery_id: String,
274}
275
276#[cfg(test)]
277mod tests {
278 use super::EVENT_TYPES;
279
280 /// The TypeScript mirror lists the same events, in the same order.
281 #[test]
282 fn the_typescript_mirror_lists_the_same_events() {
283 let ts = include_str!("../../../packages/contracts/src/webhooks.ts");
284 let list = ts
285 .split_once("export const EVENT_TYPES = [")
286 .and_then(|(_, rest)| rest.split_once("] as const"))
287 .map(|(list, _)| list)
288 .expect("EVENT_TYPES in webhooks.ts");
289 let mirrored: Vec<&str> = list
290 .split(',')
291 .map(|item| item.trim().trim_matches('"'))
292 .filter(|item| !item.is_empty())
293 .collect();
294 assert_eq!(mirrored, EVENT_TYPES);
295 }
296}

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