Skip to content

g1t/apps/api/src/openapi.rs

1,241 lines54,453 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.

API and MCP server in Rust; a public index at the API root1//! The OpenAPI document, generated from the same list the routes are.
Merge branch 'worktree-agent-ab2e39e11a6493412'2//!
3//! The docs site builds its API reference from a copy of this document,
4//! `apps/docs/src/data/openapi.json`. A test keeps the copy current: run
5//! `G1T_WRITE_OPENAPI=1 cargo test -p g1t-api openapi` to rewrite it.
API and MCP server in Rust; a public index at the API root6
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step7use g1t_contracts::scopes::scope_for;
API and MCP server in Rust; a public index at the API root8use serde_json::{Map, Value, json};
9
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb9710use crate::about::AboutOp;
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R211use crate::artifacts::ArtifactsOp;
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb9712use crate::deployments::DeploymentsOp;
Merge branch 'worktree-agent-a3abfcce648e87dca'13use crate::protection::ProtectionOp;
API and MCP server in Rust; a public index at the API root14use crate::operations::Op;
Merge checks: statuses and check runs on every commit15use crate::checks::ChecksOp;
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge16use crate::rules::RulesOp;
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar17use crate::security::SecurityOp;
API and MCP server in Rust; a public index at the API root18use crate::rest::{ROUTES, Route};
19
Merge branch 'worktree-agent-ab2e39e11a6493412'20/// The sections of the API reference: a name, what it covers, and its
21/// operations in the order a reader meets them.
22const SECTIONS: &[(&str, &str, &[Op])] = &[
23 (
24 "Accounts",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look25 "Signing in from a tool, who a token acts as, and your email addresses.",
26 &[Op::Whoami, Op::ListEmails, Op::AddEmail, Op::RemoveEmail, Op::UpdateEmailSettings],
Merge branch 'worktree-agent-ab2e39e11a6493412'27 ),
28 (
API: notifications over REST and MCP, with notifications scopes29 "Notifications",
30 "Your inbox: a thread for each thing you were told about (an issue, a pull request, a workflow on a branch, a deployment), why you were told, and what you subscribe to and watch. Your own: personal tokens and sessions only.",
31 &[
32 Op::ListNotifications,
33 Op::MarkNotificationsRead,
34 Op::GetNotificationThread,
35 Op::MarkThreadRead,
36 Op::MarkThreadDone,
37 Op::SaveThread,
38 Op::SnoozeThread,
39 Op::GetThreadSubscription,
40 Op::SetThreadSubscription,
41 Op::DeleteThreadSubscription,
42 Op::GetRepoSubscription,
43 Op::SetRepoSubscription,
44 Op::DeleteRepoSubscription,
45 Op::ListWatchedRepos,
46 ],
47 ),
48 (
API: pinned projects over REST and MCP49 "Pinned projects",
50 "The projects you keep at the top of a workspace's sidebar, in your order, up to eight a workspace. Your own: personal tokens and sessions only.",
51 &[Op::ListPinnedProjects, Op::PinProject, Op::UnpinProject, Op::ReorderPinnedProjects],
52 ),
53 (
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb9754 "Projects",
55 "A project is what a workspace builds and runs, from a repository or a root directory in one. Each says what it is, where it runs and where to find it: its homepage, docs and other links.",
56 &[Op::ListProjects, Op::GetProject, Op::UpdateProject],
57 ),
58 (
Merge branch 'worktree-agent-ab2e39e11a6493412'59 "Workspaces",
60 "A workspace owns repositories and is the first part of their address. People and agents work in workspaces.",
Merge branch 'worktree-agent-ad7c6d88d93adc817'61 &[Op::GetWorkspace, Op::CreateWorkspace, Op::UpdateWorkspace, Op::DeleteWorkspace],
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look62 ),
63 (
Merge membership: owners, org roles, GitHub's repo roles, privileges, 2FA64 "Members",
65 "A workspace's members and owners: who belongs to it, their roles (owner or member, with billing manager and security manager on top), handing it to another member, and leaving it.",
66 &[Op::ListMembers, Op::UpdateMember, Op::RemoveMember, Op::TransferOwnership, Op::LeaveWorkspace],
67 ),
68 (
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look69 "Invites",
70 "While g1t is invite-only, every new account needs an invite. Your invites, and inviting people into a workspace by email.",
71 &[
72 Op::ListInvites,
73 Op::CreateInvite,
74 Op::RevokeInvite,
75 Op::ListWorkspaceInvites,
76 Op::InviteMember,
77 Op::RevokeWorkspaceInvite,
78 ],
Merge branch 'worktree-agent-ab2e39e11a6493412'79 ),
80 (
Usage, Billing settings and prepaid AI credit; fixes from the UX audit81 "Billing",
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens82 "A workspace's usage, its budget, its AI credit, its invoices and its AI Gateway requests. Members read them; owners change the budget and buy credit, as people. g1t's agents never change billing.",
Usage, Billing settings and prepaid AI credit; fixes from the UX audit83 &[
84 Op::GetUsage,
85 Op::GetBudget,
86 Op::SetBudget,
87 Op::GetAiCredit,
88 Op::BuyAiCredit,
89 Op::ListInvoices,
90 Op::GetBillingDetails,
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens91 Op::ListGatewayRequests,
Usage, Billing settings and prepaid AI credit; fixes from the UX audit92 ],
93 ),
94 (
Merge branch 'worktree-agent-ab2e39e11a6493412'95 "Repositories",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look96 "A repository, how it handles pull requests, and its timeline: renaming, archiving, moving and deleting it.",
Merge branch 'worktree-agent-ab2e39e11a6493412'97 &[
98 Op::ListRepos,
99 Op::CreateRepo,
100 Op::GetRepo,
101 Op::UpdateRepo,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look102 Op::RenameRepo,
103 Op::RenameBranch,
104 Op::SetRepoVisibility,
105 Op::ArchiveRepo,
106 Op::UnarchiveRepo,
107 Op::TransferRepo,
108 Op::DeleteRepo,
109 Op::ListDeletedRepos,
110 Op::RestoreRepo,
111 Op::PurgeRepo,
Merge branch 'worktree-agent-ab2e39e11a6493412'112 Op::GetRepoSettings,
113 Op::UpdateRepoSettings,
Fast pages, required checks on the branch, self-hosted runners, honest incidents114 Op::ListCheckNames,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar115 Op::GetCodeownersErrors,
Merge branch 'worktree-agent-ab2e39e11a6493412'116 Op::ListEvents,
117 ],
118 ),
119 (
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97120 "Repository insights",
121 "What a repository's default branch says about it, read in the background and kept by commit: the languages it is written in, who made it, and its license.",
122 &[Op::About(AboutOp::GetLanguages), Op::About(AboutOp::ListContributors), Op::About(AboutOp::GetLicense)],
123 ),
124 (
125 "Stars",
126 "Starring a repository, to keep it and to say you like it: who starred one, and what you starred.",
127 &[
128 Op::About(AboutOp::ListStargazers),
129 Op::About(AboutOp::ListStarred),
130 Op::About(AboutOp::CheckStarred),
131 Op::About(AboutOp::Star),
132 Op::About(AboutOp::Unstar),
133 ],
134 ),
135 (
136 "Releases",
137 "A release is a tag published with a title and notes. The latest is the newest published one that is neither a draft nor a prerelease.",
138 &[
139 Op::About(AboutOp::ListReleases),
140 Op::About(AboutOp::CreateRelease),
141 Op::About(AboutOp::GetLatestRelease),
142 Op::About(AboutOp::GetReleaseByTag),
143 Op::About(AboutOp::GetRelease),
144 Op::About(AboutOp::UpdateRelease),
145 Op::About(AboutOp::DeleteRelease),
146 ],
147 ),
148 (
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look149 "Access",
150 "Who can do what in a repository: repository roles, people given a role on one repository (outside collaborators when they are not members), invitations, and a workspace's base permission.",
151 &[
152 Op::ListCollaborators,
153 Op::AddCollaborator,
154 Op::UpdateCollaborator,
155 Op::RemoveCollaborator,
156 Op::GetCollaboratorPermission,
157 Op::ListRepoInvitations,
158 Op::RevokeRepoInvitation,
159 Op::ListMyRepoInvitations,
160 Op::AcceptRepoInvitation,
161 Op::DeclineRepoInvitation,
162 Op::SetBasePermission,
163 Op::ListOutsideCollaborators,
164 ],
165 ),
166 (
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar167 "Teams",
168 "Groups of a workspace's members: given a role on repositories together, mentioned together as @workspace/team, and asked to review together. Any member may create a team; the workspace's owners and the team's maintainers manage it.",
169 &[
170 Op::ListTeams,
171 Op::CreateTeam,
172 Op::GetTeam,
173 Op::UpdateTeam,
174 Op::DeleteTeam,
175 Op::ListTeamMembers,
176 Op::SetTeamMember,
177 Op::RemoveTeamMember,
178 Op::ListChildTeams,
179 Op::ListTeamRepos,
180 Op::SetTeamRepo,
181 Op::RemoveTeamRepo,
182 Op::SetTeamReviewAssignment,
183 Op::ListUserTeams,
184 ],
185 ),
186 (
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily187 "Security",
188 "Secrets found in what is pushed and in a repository's history, and dependencies with known vulnerabilities: listing the alerts, and dismissing or reopening them.",
189 &[Op::ListSecurityAlerts, Op::DismissSecurityAlert, Op::ReopenSecurityAlert],
190 ),
191 (
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar192 "Secret scanning",
193 "Secrets found in pushes and history, where each one is, pushing past push protection with a reason (and asking for approval when the workspace delegates bypasses), checking with a secret's issuer whether it still works, and custom patterns.",
194 &[
195 Op::Security(SecurityOp::ListSecretAlerts),
196 Op::Security(SecurityOp::GetSecretAlert),
197 Op::Security(SecurityOp::UpdateSecretAlert),
198 Op::Security(SecurityOp::ListSecretLocations),
199 Op::Security(SecurityOp::BypassPushProtection),
200 Op::Security(SecurityOp::CheckSecretValidity),
201 Op::Security(SecurityOp::ListBypassRequests),
202 Op::Security(SecurityOp::ReviewBypassRequest),
203 Op::Security(SecurityOp::ListCustomPatterns),
204 Op::Security(SecurityOp::CreateCustomPattern),
205 Op::Security(SecurityOp::UpdateCustomPattern),
206 Op::Security(SecurityOp::DeleteCustomPattern),
207 Op::Security(SecurityOp::DryRunCustomPattern),
208 ],
209 ),
210 (
211 "Code scanning",
212 "Results of static analysis tools, uploaded as SARIF: alerts on the default branch, the analyses that made them, uploads, and putting g1t on an alert to fix it.",
213 &[
214 Op::Security(SecurityOp::ListCodeAlerts),
215 Op::Security(SecurityOp::GetCodeAlert),
216 Op::Security(SecurityOp::UpdateCodeAlert),
217 Op::Security(SecurityOp::ListAnalyses),
218 Op::Security(SecurityOp::UploadSarif),
219 Op::Security(SecurityOp::GetSarifUpload),
220 Op::Security(SecurityOp::FixAlert),
221 ],
222 ),
223 (
224 "Supply chain",
225 "What a repository depends on: vulnerability alerts, the dependency graph, an SPDX SBOM of it, and comparing two commits' dependencies as dependency review does.",
226 &[
227 Op::Security(SecurityOp::ListVulnerabilityAlerts),
228 Op::Security(SecurityOp::GetVulnerabilityAlert),
229 Op::Security(SecurityOp::UpdateVulnerabilityAlert),
230 Op::Security(SecurityOp::GetDependencyGraph),
231 Op::Security(SecurityOp::GetSbom),
232 Op::Security(SecurityOp::CompareDependencies),
233 ],
234 ),
235 (
236 "Security settings",
237 "When pull request checks fail, dependency review's policy, delegated bypass and validity checks, and a workspace's security overview.",
238 &[
239 Op::Security(SecurityOp::GetSettings),
240 Op::Security(SecurityOp::UpdateSettings),
241 Op::Security(SecurityOp::GetWorkspaceSettings),
242 Op::Security(SecurityOp::UpdateWorkspaceSettings),
243 Op::Security(SecurityOp::GetOverview),
244 ],
245 ),
246 (
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge247 "Rules",
248 "Rulesets: what may happen to a repository's branches and tags and what a pull request needs before it merges, for a repository or across a workspace; the rules that hold for one branch; and how they judged each push and merge, with insights.",
249 &[
250 Op::Rules(RulesOp::ListRepoRulesets),
251 Op::Rules(RulesOp::CreateRepoRuleset),
252 Op::Rules(RulesOp::GetRepoRuleset),
253 Op::Rules(RulesOp::UpdateRepoRuleset),
254 Op::Rules(RulesOp::DeleteRepoRuleset),
255 Op::Rules(RulesOp::GetBranchRules),
256 Op::Rules(RulesOp::ListRuleEvaluations),
257 Op::Rules(RulesOp::ListWorkspaceRulesets),
258 Op::Rules(RulesOp::CreateWorkspaceRuleset),
259 Op::Rules(RulesOp::GetWorkspaceRuleset),
260 Op::Rules(RulesOp::UpdateWorkspaceRuleset),
261 Op::Rules(RulesOp::DeleteWorkspaceRuleset),
262 Op::Rules(RulesOp::ListWorkspaceRuleEvaluations),
263 ],
264 ),
265 (
Merge checks: statuses and check runs on every commit266 "Checks",
267 "What CI, integrations and g1t Actions say about a commit, in the shapes CI tools already send: statuses (a state per context) and check runs (a lifecycle, a conclusion, a Markdown report, annotations on lines and buttons), grouped per reporter into check suites. g1t Actions jobs are check runs too. Required checks are met by either.",
268 &[
269 Op::Checks(ChecksOp::CreateCommitStatus),
270 Op::Checks(ChecksOp::ListCommitStatuses),
271 Op::Checks(ChecksOp::GetCombinedStatus),
272 Op::Checks(ChecksOp::CreateCheckRun),
273 Op::Checks(ChecksOp::UpdateCheckRun),
274 Op::Checks(ChecksOp::GetCheckRun),
275 Op::Checks(ChecksOp::ListCheckRunAnnotations),
276 Op::Checks(ChecksOp::RerequestCheckRun),
277 Op::Checks(ChecksOp::ListCheckRunsForRef),
278 Op::Checks(ChecksOp::ListCheckSuitesForRef),
279 Op::Checks(ChecksOp::GetCheckSuite),
280 Op::Checks(ChecksOp::RerequestCheckSuite),
281 ],
282 ),
283 (
Merge branch 'worktree-agent-ab2e39e11a6493412'284 "Issues",
285 "What should change in a repository, with labels and comments. Issues and pull requests share one sequence of numbers.",
286 &[
287 Op::ListIssues,
288 Op::CreateIssue,
289 Op::GetIssue,
290 Op::UpdateIssue,
291 Op::CloseIssue,
292 Op::ReopenIssue,
293 Op::AssignIssue,
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step294 Op::Delegate,
Merge branch 'worktree-agent-ab2e39e11a6493412'295 Op::AddComment,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar296 Op::ListIssueLabels,
297 Op::AddIssueLabels,
298 Op::SetIssueLabels,
299 Op::RemoveIssueLabels,
300 ],
301 ),
302 (
303 "Labels and milestones",
304 "A repository's labels, which issues and pull requests carry by name, and its milestones, which gather them under a goal and a due date.",
305 &[
Merge branch 'worktree-agent-ab2e39e11a6493412'306 Op::ListLabels,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar307 Op::CreateLabel,
308 Op::UpdateLabel,
309 Op::DeleteLabel,
310 Op::AddDefaultLabels,
311 Op::ListMilestones,
312 Op::CreateMilestone,
313 Op::GetMilestone,
314 Op::UpdateMilestone,
315 Op::DeleteMilestone,
Merge branch 'worktree-agent-ab2e39e11a6493412'316 ],
317 ),
318 (
319 "Plans",
320 "An outcome turned into the issues that would get there, with the order they must merge in.",
321 &[Op::PlanWork, Op::GetPlan, Op::ApplyPlan],
322 ),
323 (
324 "Pull requests",
325 "A proposed change in its own fork or on a branch. Several can be made for one issue; the one merged resolves it.",
326 &[
327 Op::ListPullRequests,
328 Op::CreatePullRequest,
329 Op::GetPullRequest,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar330 Op::UpdatePullRequest,
Merge branch 'worktree-agent-ab2e39e11a6493412'331 Op::GetPullRequestChanges,
332 Op::MarkPullRequestReady,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar333 Op::RequestReviewers,
334 Op::RemoveRequestedReviewers,
Merge branch 'worktree-agent-ab2e39e11a6493412'335 Op::ReviewPullRequest,
336 Op::MergePullRequest,
337 Op::ClosePullRequest,
338 Op::GetMergeQueue,
339 Op::MessageAgent,
340 Op::AnswerMessage,
341 Op::TakeMessages,
342 ],
343 ),
344 (
345 "Sessions",
346 "The record of how a pull request was made: prompts, reasoning and the tools that ran.",
347 &[Op::ReadSession, Op::RecordSession],
348 ),
349 (
Agents and memory, checks and conflicts, profiles, slug renames, custom domains350 "Memory",
351 "What agents and people learned that the next agent should know, for one project or across a workspace. Members and g1t's agents only; never a secret.",
352 &[Op::Remember, Op::Recall],
353 ),
354 (
Search across all of g1t, Explore, and a command palette355 "Search",
356 "One search across all of g1t: repositories, code, issues, pull requests, people and workspaces. Public content for everyone, and private content in workspaces you belong to.",
357 &[Op::Search],
358 ),
359 (
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API360 "Context",
361 "A workspace's context hub: a catalog of what it builds and runs, built from its repositories, deployments and integrations, and one search across the catalog, docs, issues, pull requests and memory.",
362 &[Op::SearchContext, Op::GetEntity],
363 ),
364 (
Merge branch 'worktree-agent-ab2e39e11a6493412'365 "Actions",
366 "GitHub Actions workflows in .g1t/workflows, their runs, and their jobs' logs.",
367 &[
368 Op::ListWorkflows,
369 Op::ListWorkflowRuns,
370 Op::GetWorkflowRun,
371 Op::GetJobLogs,
372 Op::DispatchWorkflow,
373 Op::CancelWorkflowRun,
374 Op::RerunWorkflowRun,
375 Op::UpdateWorkflow,
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2376 Op::Artifacts(ArtifactsOp::ListArtifacts),
377 Op::Artifacts(ArtifactsOp::ListRunArtifacts),
378 Op::Artifacts(ArtifactsOp::GetArtifact),
379 Op::Artifacts(ArtifactsOp::DownloadArtifact),
380 Op::Artifacts(ArtifactsOp::DeleteArtifact),
381 Op::Artifacts(ArtifactsOp::GetArtifactRetention),
382 Op::Artifacts(ArtifactsOp::SetArtifactRetention),
Merge branch 'worktree-agent-ab2e39e11a6493412'383 ],
384 ),
385 (
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97386 "Deployments",
387 "A repository's deployments wherever they run: reported from any CI with these routes, made by g1t Actions jobs with an `environment:`, or built on g1t.page. Each has statuses, shows on its commit as the check `deploy / <environment>`, and belongs to an environment.",
388 &[
389 Op::Deployments(DeploymentsOp::ListDeployments),
390 Op::Deployments(DeploymentsOp::CreateDeployment),
391 Op::Deployments(DeploymentsOp::GetDeployment),
392 Op::Deployments(DeploymentsOp::ListDeploymentStatuses),
393 Op::Deployments(DeploymentsOp::CreateDeploymentStatus),
394 Op::Deployments(DeploymentsOp::ListEnvironments),
395 Op::Deployments(DeploymentsOp::GetEnvironment),
396 ],
397 ),
398 (
Merge branch 'worktree-agent-a3abfcce648e87dca'399 "Run protection",
400 "What keeps workflow runs safe: environments' protection rules (required reviewers, a wait timer, which branches may deploy) and the reviews of the jobs they hold, approving a pull request's run from outside, what a job's token gets when its workflow writes no `permissions:`, and repository_dispatch, which a job's own token may send.",
401 &[
402 Op::Protection(ProtectionOp::UpdateEnvironment),
403 Op::Protection(ProtectionOp::DeleteEnvironment),
404 Op::Protection(ProtectionOp::GetPendingDeployments),
405 Op::Protection(ProtectionOp::ReviewPendingDeployments),
406 Op::Protection(ProtectionOp::ApproveWorkflowRun),
407 Op::Protection(ProtectionOp::GetWorkflowPermissions),
408 Op::Protection(ProtectionOp::SetWorkflowPermissions),
409 Op::Protection(ProtectionOp::GetForkPrApproval),
410 Op::Protection(ProtectionOp::SetForkPrApproval),
411 Op::Protection(ProtectionOp::CreateRepositoryDispatch),
412 Op::Protection(ProtectionOp::GetWorkspaceWorkflowPermissions),
413 Op::Protection(ProtectionOp::SetWorkspaceWorkflowPermissions),
414 ],
415 ),
416 (
Merge branch 'worktree-agent-ab2e39e11a6493412'417 "Secrets and variables",
418 "Values that workflows and deployments read, per repository or for a whole workspace, with a row per environment.",
419 &[
420 Op::ListActionsSecrets,
421 Op::SetActionsSecret,
422 Op::DeleteActionsSecret,
423 Op::ListActionsVariables,
424 Op::SetActionsVariable,
425 Op::DeleteActionsVariable,
426 ],
427 ),
428 (
Fast pages, required checks on the branch, self-hosted runners, honest incidents429 "Runners",
430 "Self-hosted runners: your own machines, which run your workflow jobs (and, if you choose, your agents' work) for $0 of g1t compute. They register with a short-lived token and only ever connect out.",
431 &[
432 Op::ListRunners,
433 Op::CreateRunnerRegistrationToken,
434 Op::RemoveRunner,
435 Op::ListRunnerGroups,
436 Op::CreateRunnerGroup,
437 Op::UpdateRunnerGroup,
438 Op::DeleteRunnerGroup,
439 Op::GetRunnerSettings,
440 Op::UpdateRunnerSettings,
441 ],
442 ),
443 (
Merge branch 'worktree-agent-ab2e39e11a6493412'444 "Webhooks",
445 "Signed HTTPS requests sent to your own address as things happen, for a repository or a whole workspace.",
446 &[
447 Op::ListWebhooks,
448 Op::CreateWebhook,
449 Op::UpdateWebhook,
450 Op::DeleteWebhook,
451 Op::PingWebhook,
452 Op::ListWebhookDeliveries,
453 Op::RedeliverWebhook,
454 ],
455 ),
456 (
457 "Integrations",
458 "A workspace's connections to outside systems: model providers, alert sources and issue trackers.",
459 &[
460 Op::ListIntegrations,
461 Op::ConnectIntegration,
AI Gateway: OpenAI's format, open models, and your own providers462 Op::UpdateIntegration,
Merge branch 'worktree-agent-ab2e39e11a6493412'463 Op::DisconnectIntegration,
464 Op::TestIntegration,
465 Op::GetModelRoutes,
466 Op::SetModelRoutes,
467 Op::GetContext,
468 Op::ImportIssue,
469 ],
470 ),
471];
472
API and MCP server in Rust; a public index at the API root473/// The section of the API reference an operation is listed under.
474fn tag(op: Op) -> &'static str {
Merge branch 'worktree-agent-ab2e39e11a6493412'475 SECTIONS
API and MCP server in Rust; a public index at the API root476 .iter()
Merge branch 'worktree-agent-ab2e39e11a6493412'477 .find(|(_, _, ops)| ops.contains(&op))
478 .map_or("Repositories", |(name, _, _)| name)
479}
480
481/// What an operation's page is called, as a short sentence.
482fn title(op: Op) -> &'static str {
483 match op {
484 Op::Whoami => "Get the current user",
Merge branch 'worktree-agent-ad7c6d88d93adc817'485 Op::GetWorkspace => "Get a workspace",
Merge branch 'worktree-agent-ab2e39e11a6493412'486 Op::CreateWorkspace => "Create a workspace",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look487 Op::DeleteWorkspace => "Delete a workspace",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily488 Op::UpdateWorkspace => "Update a workspace",
Merge membership: owners, org roles, GitHub's repo roles, privileges, 2FA489 Op::ListMembers => "List a workspace's members",
490 Op::UpdateMember => "Change a member's role",
491 Op::RemoveMember => "Remove a member",
492 Op::TransferOwnership => "Transfer a workspace's ownership",
493 Op::LeaveWorkspace => "Leave a workspace",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look494 Op::ListEmails => "List your email addresses",
495 Op::AddEmail => "Add an email address",
496 Op::RemoveEmail => "Remove an email address",
497 Op::UpdateEmailSettings => "Change your email settings",
498 Op::ListInvites => "List your invites",
499 Op::CreateInvite => "Create an invite",
500 Op::RevokeInvite => "Revoke an invite",
501 Op::ListWorkspaceInvites => "List a workspace's invites",
502 Op::InviteMember => "Invite someone to a workspace",
503 Op::RevokeWorkspaceInvite => "Revoke a workspace's invite",
504 Op::TransferRepo => "Transfer a repository",
505 Op::RenameRepo => "Rename a repository",
506 Op::RenameBranch => "Rename a branch",
507 Op::ArchiveRepo => "Archive a repository",
508 Op::UnarchiveRepo => "Unarchive a repository",
509 Op::SetRepoVisibility => "Change a repository's visibility",
510 Op::DeleteRepo => "Delete a repository",
511 Op::ListDeletedRepos => "List recently deleted repositories",
512 Op::RestoreRepo => "Restore a deleted repository",
513 Op::PurgeRepo => "Purge a deleted repository",
Merge branch 'worktree-agent-ab2e39e11a6493412'514 Op::ListRepos => "List repositories",
515 Op::GetRepo => "Get a repository",
516 Op::CreateRepo => "Create a repository",
517 Op::UpdateRepo => "Update a repository",
518 Op::GetRepoSettings => "Get repository settings",
519 Op::UpdateRepoSettings => "Update repository settings",
Fast pages, required checks on the branch, self-hosted runners, honest incidents520 Op::ListCheckNames => "List check names",
Merge branch 'worktree-agent-ab2e39e11a6493412'521 Op::GetMergeQueue => "Get the merge queue",
522 Op::MessageAgent => "Message an agent",
523 Op::AnswerMessage => "Answer a message",
524 Op::TakeMessages => "Take new messages",
Agents and memory, checks and conflicts, profiles, slug renames, custom domains525 Op::Remember => "Remember something",
526 Op::Recall => "Recall memory",
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API527 Op::SearchContext => "Search the context hub",
528 Op::GetEntity => "Get a catalog entry",
Search across all of g1t, Explore, and a command palette529 Op::Search => "Search g1t",
Merge branch 'worktree-agent-ab2e39e11a6493412'530 Op::ListIssues => "List issues",
531 Op::GetIssue => "Get an issue",
532 Op::CreateIssue => "Create an issue",
533 Op::UpdateIssue => "Update an issue",
534 Op::CloseIssue => "Close an issue",
535 Op::ReopenIssue => "Reopen an issue",
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent536 Op::AssignIssue => "Assign an issue to g1t",
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step537 Op::Delegate => "Put an agent on it",
Merge branch 'worktree-agent-ab2e39e11a6493412'538 Op::PlanWork => "Plan work",
539 Op::GetPlan => "Get a plan",
540 Op::ApplyPlan => "Apply a plan",
541 Op::ListLabels => "List labels",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar542 Op::CreateLabel => "Create a label",
543 Op::UpdateLabel => "Update a label",
544 Op::DeleteLabel => "Delete a label",
545 Op::AddDefaultLabels => "Add the default labels",
546 Op::ListIssueLabels => "List an issue's labels",
547 Op::AddIssueLabels => "Add labels to an issue",
548 Op::SetIssueLabels => "Set an issue's labels",
549 Op::RemoveIssueLabels => "Remove labels from an issue",
550 Op::ListMilestones => "List milestones",
551 Op::GetMilestone => "Get a milestone",
552 Op::CreateMilestone => "Create a milestone",
553 Op::UpdateMilestone => "Update a milestone",
554 Op::DeleteMilestone => "Delete a milestone",
555 Op::UpdatePullRequest => "Update a pull request",
Merge branch 'worktree-agent-ab2e39e11a6493412'556 Op::AddComment => "Add a comment",
557 Op::ReviewPullRequest => "Review a pull request",
558 Op::ListPullRequests => "List pull requests",
559 Op::GetPullRequest => "Get a pull request",
560 Op::CreatePullRequest => "Create a pull request",
561 Op::RecordSession => "Record session entries",
562 Op::ReadSession => "Read a session",
563 Op::MarkPullRequestReady => "Mark a pull request ready",
564 Op::ClosePullRequest => "Close a pull request",
565 Op::GetPullRequestChanges => "Get a pull request's changes",
566 Op::MergePullRequest => "Merge a pull request",
567 Op::ListEvents => "List repository events",
568 Op::ListIntegrations => "List integrations",
569 Op::ConnectIntegration => "Connect an integration",
AI Gateway: OpenAI's format, open models, and your own providers570 Op::UpdateIntegration => "Update an integration",
Merge branch 'worktree-agent-ab2e39e11a6493412'571 Op::DisconnectIntegration => "Disconnect an integration",
572 Op::TestIntegration => "Test an integration",
573 Op::GetContext => "Look up a ticket",
574 Op::ImportIssue => "Import an issue",
575 Op::GetModelRoutes => "Get model routes",
576 Op::SetModelRoutes => "Set model routes",
577 Op::ListWebhooks => "List webhooks",
578 Op::CreateWebhook => "Create a webhook",
579 Op::UpdateWebhook => "Update a webhook",
580 Op::DeleteWebhook => "Delete a webhook",
581 Op::PingWebhook => "Ping a webhook",
582 Op::ListWebhookDeliveries => "List webhook deliveries",
583 Op::RedeliverWebhook => "Redeliver a webhook delivery",
584 Op::ListWorkflows => "List workflows",
585 Op::ListWorkflowRuns => "List workflow runs",
586 Op::GetWorkflowRun => "Get a workflow run",
587 Op::GetJobLogs => "Get a job's log",
588 Op::DispatchWorkflow => "Run a workflow",
589 Op::CancelWorkflowRun => "Cancel a workflow run",
590 Op::RerunWorkflowRun => "Re-run a workflow run",
591 Op::UpdateWorkflow => "Turn a workflow on or off",
592 Op::ListActionsSecrets => "List secrets",
593 Op::SetActionsSecret => "Set a secret",
594 Op::DeleteActionsSecret => "Delete a secret",
595 Op::ListActionsVariables => "List variables",
596 Op::SetActionsVariable => "Set a variable",
597 Op::DeleteActionsVariable => "Delete a variable",
Fast pages, required checks on the branch, self-hosted runners, honest incidents598 Op::ListRunners => "List self-hosted runners",
599 Op::ListRunnerGroups => "List runner groups",
600 Op::GetRunnerSettings => "Get runner settings",
601 Op::CreateRunnerRegistrationToken => "Create a runner registration token",
602 Op::RemoveRunner => "Remove a self-hosted runner",
603 Op::CreateRunnerGroup => "Create a runner group",
604 Op::UpdateRunnerGroup => "Change a runner group",
605 Op::DeleteRunnerGroup => "Delete a runner group",
606 Op::UpdateRunnerSettings => "Change runner settings",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look607 Op::ListCollaborators => "List who has access",
608 Op::AddCollaborator => "Add a collaborator",
609 Op::UpdateCollaborator => "Change a collaborator's role",
610 Op::RemoveCollaborator => "Remove a collaborator",
611 Op::GetCollaboratorPermission => "Get someone's permission",
612 Op::ListRepoInvitations => "List a repository's invitations",
613 Op::RevokeRepoInvitation => "Revoke a repository invitation",
614 Op::ListMyRepoInvitations => "List your repository invitations",
615 Op::AcceptRepoInvitation => "Accept a repository invitation",
616 Op::DeclineRepoInvitation => "Decline a repository invitation",
617 Op::SetBasePermission => "Set the base permission",
618 Op::ListOutsideCollaborators => "List outside collaborators",
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily619 Op::ListSecurityAlerts => "List security alerts",
620 Op::DismissSecurityAlert => "Dismiss a security alert",
621 Op::ReopenSecurityAlert => "Reopen a security alert",
API: notifications over REST and MCP, with notifications scopes622 Op::ListNotifications => "List notifications",
623 Op::MarkNotificationsRead => "Mark notifications read",
624 Op::GetNotificationThread => "Get a thread",
625 Op::MarkThreadRead => "Mark a thread read",
626 Op::MarkThreadDone => "Mark a thread done",
627 Op::SaveThread => "Save a thread",
628 Op::SnoozeThread => "Snooze a thread",
629 Op::GetThreadSubscription => "Get a thread subscription",
630 Op::SetThreadSubscription => "Set a thread subscription",
631 Op::DeleteThreadSubscription => "Unsubscribe from a thread",
632 Op::GetRepoSubscription => "Get how you watch a repository",
633 Op::SetRepoSubscription => "Watch a repository",
634 Op::DeleteRepoSubscription => "Stop watching a repository",
635 Op::ListWatchedRepos => "List repositories you watch",
API: pinned projects over REST and MCP636 Op::ListPinnedProjects => "List your pinned projects",
Usage, Billing settings and prepaid AI credit; fixes from the UX audit637 Op::GetUsage => "Get a workspace's usage",
638 Op::GetBudget => "Get a workspace's budget",
639 Op::SetBudget => "Change a workspace's budget",
640 Op::GetAiCredit => "Get a workspace's AI credit",
641 Op::BuyAiCredit => "Buy AI credit",
642 Op::ListInvoices => "List a workspace's invoices",
643 Op::GetBillingDetails => "Get a workspace's billing details",
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens644 Op::ListGatewayRequests => "List a workspace's AI Gateway requests",
API: pinned projects over REST and MCP645 Op::PinProject => "Pin a project",
646 Op::UnpinProject => "Unpin a project",
647 Op::ReorderPinnedProjects => "Reorder your pinned projects",
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97648 Op::ListProjects => "List a workspace's projects",
649 Op::GetProject => "Get a project",
650 Op::UpdateProject => "Update a project",
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar651 Op::ListTeams => "List teams",
652 Op::GetTeam => "Get a team",
653 Op::CreateTeam => "Create a team",
654 Op::UpdateTeam => "Update a team",
655 Op::DeleteTeam => "Delete a team",
656 Op::ListTeamMembers => "List a team's members",
657 Op::SetTeamMember => "Add or change a team member",
658 Op::RemoveTeamMember => "Remove a team member",
659 Op::ListChildTeams => "List child teams",
660 Op::ListTeamRepos => "List a team's repositories",
661 Op::SetTeamRepo => "Give a team a role on a repository",
662 Op::RemoveTeamRepo => "Remove a team from a repository",
663 Op::SetTeamReviewAssignment => "Set a team's review assignment",
664 Op::ListUserTeams => "List someone's teams",
665 Op::RequestReviewers => "Request reviewers",
666 Op::RemoveRequestedReviewers => "Remove requested reviewers",
667 Op::GetCodeownersErrors => "List CODEOWNERS errors",
668 Op::Security(op) => op.title(),
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge669 Op::Rules(op) => op.title(),
Merge checks: statuses and check runs on every commit670 Op::Checks(op) => op.title(),
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97671 Op::About(op) => op.title(),
672 Op::Deployments(op) => op.title(),
Merge branch 'worktree-agent-a3abfcce648e87dca'673 Op::Protection(op) => op.title(),
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2674 Op::Artifacts(op) => op.title(),
API and MCP server in Rust; a public index at the API root675 }
676}
677
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look678/// Why an operation can be refused with `402 payment_required`, if it
679/// can: the ones that start an agent, when the workspace has no credit,
680/// and the ones that make a repository private in a workspace, when a free
681/// workspace's private storage has no room for it.
682fn may_need_payment(op: Op) -> Option<&'static str> {
683 match op {
684 Op::AssignIssue | Op::PlanWork | Op::ApplyPlan => Some("The workspace has no agent credit."),
685 Op::UpdateRepo | Op::SetRepoVisibility | Op::TransferRepo => Some(
686 "A free workspace's private storage has no room for this private repository.",
687 ),
688 _ => None,
689 }
Merge branch 'worktree-agent-ab2e39e11a6493412'690}
691
692/// What the reference says beyond each operation's own description, keyed
693/// by operation id, written by hand from what the services return: `notes`
694/// (Markdown, added to the description) and example `params` (path),
695/// `query`, `request` (body) and `response`.
696const REFERENCE: &str = include_str!("reference.json");
697
698fn examples() -> Map<String, Value> {
699 match serde_json::from_str(REFERENCE) {
700 Ok(Value::Object(examples)) => examples,
701 _ => Map::new(),
API and MCP server in Rust; a public index at the API root702 }
703}
704
Agents as a team: lifecycle, merge queue, billing and a new shell705/// `/repos/:owner/:name` as OpenAPI writes it: `/repos/{owner}/{name}`.
API and MCP server in Rust; a public index at the API root706fn openapi_path(route: &Route) -> String {
707 route
708 .path
709 .split('/')
710 .map(|segment| match segment.strip_prefix(':') {
711 Some(name) => format!("{{{name}}}"),
712 None => segment.to_owned(),
713 })
714 .collect::<Vec<_>>()
715 .join("/")
716}
717
718fn error_response(description: &str) -> Value {
719 json!({
720 "description": description,
721 "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } },
722 })
723}
724
Merge branch 'worktree-agent-ab2e39e11a6493412'725/// A parameter in the path or the query, described by the operation's
726/// input schema where it has the same name.
727fn parameter(name: &str, place: &str, required: bool, schema: Option<&Value>) -> Value {
728 let mut schema = schema.cloned().unwrap_or_else(|| json!({ "type": "string" }));
729 let description = match name {
730 "owner" => Some(Value::from("The workspace that owns the repository.")),
731 "name" => Some(Value::from("The repository's name.")),
732 _ => schema.as_object_mut().and_then(|schema| schema.remove("description")),
733 };
734 let mut parameter = json!({
735 "name": name,
736 "in": place,
737 "required": required,
738 "schema": schema,
739 });
740 if let Some(description) = description {
741 parameter["description"] = description;
742 }
743 parameter
744}
745
746/// The operation id of a route. An operation reached at a workspace's
747/// address as well as a repository's is documented once for each, with its
748/// own id; GitHub's alternative addresses for one operation keep GitHub's
749/// names.
750fn operation_id(route: &Route) -> String {
751 let op = route.op;
752 let base = match (route.method, route.path.rsplit('/').next().unwrap_or_default()) {
753 ("PUT", "enable") => "enable_workflow".to_owned(),
754 ("PUT", "disable") => "disable_workflow".to_owned(),
755 ("POST", "rerun-failed-jobs") => "rerun_failed_jobs".to_owned(),
756 ("PATCH", ":setting") => "update_actions_variable".to_owned(),
757 ("GET", "runs") if route.path.contains("/workflows/:workflow/") => "list_runs_of_workflow".to_owned(),
API: notifications over REST and MCP, with notifications scopes758 // One repository's notifications, and an issue's subscription by
759 // its number rather than a thread's id.
760 (_, "notifications") if route.path.starts_with("/repos/") => match op {
761 Op::ListNotifications => "list_repo_notifications".to_owned(),
762 _ => "mark_repo_notifications_read".to_owned(),
763 },
764 (method, "subscription") if route.path.contains("/issues/:number/") => match method {
765 "GET" => "get_issue_subscription".to_owned(),
766 "PUT" => "set_issue_subscription".to_owned(),
767 _ => "delete_issue_subscription".to_owned(),
768 },
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar769 // One label off an issue, by its name in the path.
770 ("DELETE", ":label") if route.path.contains("/issues/:number/") => "remove_issue_label".to_owned(),
API: notifications over REST and MCP, with notifications scopes771 ("DELETE", "saved") => "unsave_thread".to_owned(),
772 ("DELETE", "snooze") => "unsnooze_thread".to_owned(),
Merge branch 'worktree-agent-ab2e39e11a6493412'773 _ => op.name().to_owned(),
774 };
775 if route.path.starts_with("/workspaces/") && ROUTES.iter().any(|other| other.op == op && other.path.starts_with("/repos/")) {
776 format!("{base}_for_workspace")
777 } else {
778 base
779 }
780}
781
782/// The summary of a route: its operation's title, or for one of GitHub's
783/// alternative addresses, what that address does.
784fn summary(route: &Route, id: &str) -> String {
785 let base = match id.trim_end_matches("_for_workspace") {
786 "enable_workflow" => "Turn a workflow on",
787 "disable_workflow" => "Turn a workflow off",
788 "rerun_failed_jobs" => "Re-run failed jobs",
789 "update_actions_variable" => "Update a variable",
790 "list_runs_of_workflow" => "List a workflow's runs",
API: notifications over REST and MCP, with notifications scopes791 "list_repo_notifications" => "List a repository's notifications",
792 "mark_repo_notifications_read" => "Mark a repository's notifications read",
793 "get_issue_subscription" => "Get your subscription to an issue",
794 "set_issue_subscription" => "Subscribe to an issue",
795 "delete_issue_subscription" => "Unsubscribe from an issue",
796 "unsave_thread" => "Unsave a thread",
797 "unsnooze_thread" => "Bring a snoozed thread back",
Merge branch 'worktree-agent-ab2e39e11a6493412'798 _ => title(route.op),
799 };
800 if id.ends_with("_for_workspace") {
801 format!("{base} for a workspace")
802 } else {
803 base.to_owned()
804 }
805}
806
API and MCP server in Rust; a public index at the API root807fn operation(route: &Route) -> Value {
808 let op = route.op;
809 let path_params: Vec<&str> = route.params().collect();
Merge checks: statuses and check runs on every commit810 // `owner` and `name` in the path stand for the operation's `repo` input,
811 // so a `name` in the body, such as a check run's, is the body's own.
812 let stands_for_repo =
813 |name: &str| matches!(name, "owner" | "name") && path_params.contains(&"owner") && path_params.contains(&"name");
814 let covered = |name: &str| name == "repo" || (path_params.contains(&name) && !stands_for_repo(name));
Merge branch 'worktree-agent-ab2e39e11a6493412'815 let all_properties = op.properties();
816 let mut properties = all_properties.clone();
API and MCP server in Rust; a public index at the API root817 properties.retain(|name, _| !covered(name));
818 let required: Vec<String> = op
819 .required()
820 .into_iter()
821 .filter(|name| !covered(name))
822 .collect();
823
824 let mut parameters: Vec<Value> = path_params
825 .iter()
Merge checks: statuses and check runs on every commit826 .map(|name| parameter(name, "path", true, if stands_for_repo(name) { None } else { all_properties.get(*name) }))
API and MCP server in Rust; a public index at the API root827 .collect();
828 let mut body = Value::Null;
829 if route.method == "GET" {
830 for (name, key) in route.query {
Merge branch 'worktree-agent-ab2e39e11a6493412'831 parameters.push(parameter(
832 name,
833 "query",
834 required.iter().any(|required| required == key),
835 properties.get(*key),
836 ));
API and MCP server in Rust; a public index at the API root837 }
838 } else if !properties.is_empty() {
839 let mut schema = json!({ "type": "object", "properties": properties });
840 if !required.is_empty() {
841 schema["required"] = json!(required);
842 }
843 body = json!({
844 "required": !required.is_empty(),
845 "content": { "application/json": { "schema": schema } },
846 });
847 }
848
Merge branch 'worktree-agent-ab2e39e11a6493412'849 let id = operation_id(route);
850 let mut responses = Map::new();
851 responses.insert(
852 "200".into(),
853 json!({
854 "description": "Success.",
855 "content": { "application/json": { "schema": {} } },
856 }),
857 );
858 responses.insert(
859 "401".into(),
860 error_response("A token is required, or the one sent is not valid."),
861 );
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look862 if let Some(reason) = may_need_payment(op) {
863 responses.insert("402".into(), error_response(reason));
Merge branch 'worktree-agent-ab2e39e11a6493412'864 }
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step865 responses.insert(
866 "403".into(),
867 error_response("Signed in, but not allowed to do this: the role you have is not enough, or the token lacks the scope it needs, which `needed_scope` names."),
868 );
Search across all of g1t, Explore, and a command palette869 if !matches!(op, Op::Whoami | Op::ListRepos | Op::Search) {
Merge branch 'worktree-agent-ab2e39e11a6493412'870 responses.insert("404".into(), error_response("It does not exist, or you cannot see it."));
871 }
872 if route.method != "GET" {
873 responses.insert(
874 "409".into(),
875 error_response("The request conflicts with the current state."),
876 );
877 }
878 if op != Op::Whoami {
879 responses.insert("422".into(), error_response("The input is not valid."));
880 }
881 // Public data can be read without a token; everything else needs one.
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step882 let scope: Vec<&str> = scope_for(op.name()).map(|scope| scope.as_str()).into_iter().collect();
Merge branch 'worktree-agent-ab2e39e11a6493412'883 let security = if op.needs_user() {
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step884 json!([{ "token": scope }])
Webhooks: every event, to your own addresses, signed and retried885 } else {
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step886 json!([{ "token": scope }, {}])
Webhooks: every event, to your own addresses, signed and retried887 };
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step888 let (tool, action) = crate::tools::TOOLS
889 .iter()
890 .find_map(|tool| {
891 tool.actions
892 .iter()
893 .find(|action| action.op == op)
894 .map(|action| (tool.name, action.name))
895 })
896 .unwrap_or_default();
API and MCP server in Rust; a public index at the API root897 let mut described = json!({
Webhooks: every event, to your own addresses, signed and retried898 "operationId": id,
API and MCP server in Rust; a public index at the API root899 "tags": [tag(op)],
Merge branch 'worktree-agent-ab2e39e11a6493412'900 "summary": summary(route, &id),
API and MCP server in Rust; a public index at the API root901 "description": op.description(),
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step902 "x-operation": op.name(),
903 "x-mcp-tool": tool,
904 "x-mcp-action": action,
905 "x-scope": scope.first().copied(),
Merge branch 'worktree-agent-ab2e39e11a6493412'906 "security": security,
API and MCP server in Rust; a public index at the API root907 "parameters": parameters,
Merge branch 'worktree-agent-ab2e39e11a6493412'908 "responses": responses,
API and MCP server in Rust; a public index at the API root909 });
910 if !body.is_null() {
911 described["requestBody"] = body;
912 }
913 described
914}
915
916/// Entries for device sign-in, which is not an operation.
917fn onboarding() -> Map<String, Value> {
918 let paths = json!({
Agents as a team: lifecycle, merge queue, billing and a new shell919 "/device/code": {
API and MCP server in Rust; a public index at the API root920 "post": {
921 "operationId": "device_code",
922 "tags": ["Accounts"],
923 "summary": "Start signing in",
Agents as a team: lifecycle, merge queue, billing and a new shell924 "description": "Begins a device sign-in. Show the person `verification_uri_complete` and have them open it in a browser, where they sign in or register and approve the code. Then poll `/device/token`.",
API and MCP server in Rust; a public index at the API root925 "security": [],
926 "requestBody": {
927 "content": { "application/json": { "schema": {
928 "type": "object",
929 "properties": {
930 "client_name": {
931 "type": "string",
932 "description": "What is asking, shown to the person approving. For example, Claude Code.",
933 },
934 },
935 } } },
936 },
937 "responses": { "200": {
938 "description": "The codes for this sign-in.",
939 "content": { "application/json": { "schema": {
940 "type": "object",
941 "properties": {
Agents as a team: lifecycle, merge queue, billing and a new shell942 "device_code": { "type": "string", "description": "Secret. Send it to /device/token." },
API and MCP server in Rust; a public index at the API root943 "user_code": { "type": "string", "description": "Shown to the person, like WDJB-MJHT." },
944 "verification_uri": { "type": "string" },
945 "verification_uri_complete": {
946 "type": "string",
947 "description": "The link to give the person; it carries the code.",
948 },
949 "expires_in": { "type": "integer", "description": "Seconds until the codes expire." },
950 "interval": { "type": "integer", "description": "Seconds to wait between polls." },
951 },
952 } } },
953 } },
954 },
955 },
Agents as a team: lifecycle, merge queue, billing and a new shell956 "/device/token": {
API and MCP server in Rust; a public index at the API root957 "post": {
958 "operationId": "device_token",
959 "tags": ["Accounts"],
960 "summary": "Finish signing in",
961 "description": "Asks whether the person has approved. Poll no faster than the interval. The token is returned once.",
962 "security": [],
963 "requestBody": {
964 "required": true,
965 "content": { "application/json": { "schema": {
966 "type": "object",
967 "required": ["device_code"],
968 "properties": { "device_code": { "type": "string" } },
969 } } },
970 },
971 "responses": { "200": {
972 "description": "The state of the sign-in.",
973 "content": { "application/json": { "schema": {
974 "type": "object",
975 "required": ["status"],
976 "properties": {
977 "status": { "type": "string", "enum": ["pending", "approved", "denied", "expired"] },
978 "token": { "type": "string", "description": "Present when approved." },
979 "username": { "type": "string" },
980 "verified": {
981 "type": "boolean",
982 "description": "Whether the account's email is confirmed.",
983 },
984 },
985 } } },
986 } },
987 },
988 },
989 });
990 match paths {
991 Value::Object(paths) => paths,
992 _ => Map::new(),
993 }
994}
995
Merge branch 'worktree-agent-ab2e39e11a6493412'996
997/// Puts each operation's examples, where it has them, into its request
998/// and response. Path and query values go under `x-example-params` and
999/// `x-example-query`, which tools that build a request can use.
1000fn attach_examples(paths: &mut Map<String, Value>) {
1001 let examples = examples();
1002 for methods in paths.values_mut() {
1003 let Some(methods) = methods.as_object_mut() else { continue };
1004 for operation in methods.values_mut() {
1005 let id = operation["operationId"].as_str().unwrap_or_default().to_owned();
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step1006 let name = operation["x-operation"].as_str().unwrap_or_default().to_owned();
1007 let Some(example) = examples.get(&id).or_else(|| examples.get(&name)) else {
Merge branch 'worktree-agent-ab2e39e11a6493412'1008 continue;
1009 };
1010 if let Some(notes) = example.get("notes").and_then(Value::as_str) {
1011 let description = operation["description"].as_str().unwrap_or_default();
1012 operation["description"] = json!(format!("{description}\n\n{notes}"));
1013 }
1014 if let Some(response) = example.get("response") {
1015 let content = &mut operation["responses"]["200"]["content"]["application/json"];
1016 if content.is_object() {
1017 content["example"] = response.clone();
1018 }
1019 }
1020 if let Some(request) = example.get("request") {
1021 let content = &mut operation["requestBody"]["content"]["application/json"];
1022 if content.is_object() {
1023 content["example"] = request.clone();
1024 }
1025 }
1026 for (key, extension) in [("params", "x-example-params"), ("query", "x-example-query")] {
1027 if let Some(values) = example.get(key) {
1028 operation[extension] = values.clone();
1029 }
1030 }
1031 }
1032 }
1033}
1034
API and MCP server in Rust; a public index at the API root1035pub fn document() -> Value {
1036 let mut paths = onboarding();
1037 for route in ROUTES {
1038 let entry = paths
1039 .entry(openapi_path(route))
1040 .or_insert_with(|| json!({}));
1041 entry[route.method.to_lowercase()] = operation(route);
1042 }
Merge branch 'worktree-agent-ab2e39e11a6493412'1043 attach_examples(&mut paths);
1044 let tags: Vec<Value> = SECTIONS
1045 .iter()
1046 .map(|(name, description, ops)| {
1047 json!({
1048 "name": name,
1049 "description": description,
1050 // The section's operations in reading order, by MCP tool name.
1051 "x-tools": ops.iter().map(|op| op.name()).collect::<Vec<_>>(),
1052 })
1053 })
1054 .collect();
1055 let codes = ["unauthenticated", "payment_required", "forbidden", "not_found", "conflict", "invalid"];
API and MCP server in Rust; a public index at the API root1056 json!({
1057 "openapi": "3.1.0",
1058 "info": {
1059 "title": "g1t API",
1060 "version": "1",
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API1061 "description": "The REST API for g1t, a git forge built for agents. The same operations are available to agents as MCP tools at https://mcp.g1t.sh. Every name in a request or response body is `snake_case`; names you chose, such as a workflow's inputs or a secret's name, are returned as you wrote them.",
API and MCP server in Rust; a public index at the API root1062 "license": { "name": "MIT", "identifier": "MIT" },
1063 },
1064 "servers": [{ "url": "https://api.g1t.sh" }],
1065 "security": [{ "token": [] }, {}],
Merge branch 'worktree-agent-ab2e39e11a6493412'1066 "tags": tags,
API and MCP server in Rust; a public index at the API root1067 "paths": paths,
1068 "components": {
1069 "securitySchemes": {
1070 "token": {
1071 "type": "http",
1072 "scheme": "bearer",
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step1073 "description": "An access token, `g1t_…`. Public data needs none. Each operation names the scope a token needs for it; see https://docs.g1t.sh/guides/authentication/#scopes.",
API and MCP server in Rust; a public index at the API root1074 },
1075 },
1076 "schemas": {
1077 "Error": {
1078 "type": "object",
1079 "required": ["error"],
1080 "properties": {
1081 "error": {
1082 "type": "object",
1083 "required": ["code", "message"],
1084 "properties": {
Merge branch 'worktree-agent-ab2e39e11a6493412'1085 "code": { "type": "string", "enum": codes },
API and MCP server in Rust; a public index at the API root1086 "message": { "type": "string" },
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step1087 "needed_scope": {
1088 "type": "string",
1089 "description": "On a 403 for an access token without the scope the call needs: that scope, such as `issues:write`.",
1090 },
API and MCP server in Rust; a public index at the API root1091 },
1092 },
1093 },
1094 },
1095 },
1096 },
1097 })
1098}
1099
1100#[cfg(test)]
1101mod tests {
1102 use super::*;
1103
1104 #[test]
1105 fn every_route_is_documented_once() {
1106 let document = document();
1107 let mut ids = Vec::new();
1108 for (_, methods) in document["paths"].as_object().unwrap() {
1109 for (_, operation) in methods.as_object().unwrap() {
1110 ids.push(operation["operationId"].as_str().unwrap().to_owned());
1111 }
1112 }
1113 for op in Op::ALL {
1114 assert_eq!(
1115 ids.iter().filter(|id| *id == op.name()).count(),
1116 1,
1117 "{}",
1118 op.name()
1119 );
1120 }
Webhooks: every event, to your own addresses, signed and retried1121 let mut unique = ids.clone();
1122 unique.sort();
1123 unique.dedup();
1124 assert_eq!(unique.len(), ids.len(), "operation ids repeat");
API and MCP server in Rust; a public index at the API root1125 }
1126
1127 #[test]
1128 fn path_and_query_inputs_are_not_repeated_in_the_body() {
1129 let document = document();
Agents as a team: lifecycle, merge queue, billing and a new shell1130 let merge = &document["paths"]["/repos/{owner}/{name}/pulls/{number}/merge"]["post"];
API and MCP server in Rust; a public index at the API root1131 let body = &merge["requestBody"]["content"]["application/json"]["schema"]["properties"];
1132 assert!(body.get("keep_issue_open").is_some());
1133 assert!(body.get("repo").is_none() && body.get("number").is_none());
Agents as a team: lifecycle, merge queue, billing and a new shell1134 let list = &document["paths"]["/repos"]["get"];
API and MCP server in Rust; a public index at the API root1135 assert_eq!(list["parameters"][0]["name"], "q");
1136 assert!(list.get("requestBody").is_none());
1137 }
1138
1139 #[test]
Merge branch 'worktree-agent-ab2e39e11a6493412'1140 fn every_operation_is_in_one_section() {
1141 for op in Op::ALL {
1142 let sections = SECTIONS
1143 .iter()
1144 .filter(|(_, _, ops)| ops.contains(&op))
1145 .count();
1146 assert_eq!(sections, 1, "{}", op.name());
1147 }
1148 }
1149
1150 #[test]
API and MCP server in Rust; a public index at the API root1151 fn titles_read_as_sentences() {
Merge branch 'worktree-agent-ab2e39e11a6493412'1152 assert_eq!(title(Op::CreateIssue), "Create an issue");
API and MCP server in Rust; a public index at the API root1153 assert_eq!(title(Op::Whoami), "Get the current user");
1154 }
Merge branch 'worktree-agent-ab2e39e11a6493412'1155
1156 #[test]
1157 fn every_operation_has_an_example_response() {
1158 let examples = examples();
1159 assert!(!examples.is_empty(), "reference.json does not parse");
1160 let document = document();
1161 let mut known = Vec::new();
1162 for (path, methods) in document["paths"].as_object().unwrap() {
1163 for (method, operation) in methods.as_object().unwrap() {
1164 known.push(operation["operationId"].as_str().unwrap().to_owned());
1165 let example = &operation["responses"]["200"]["content"]["application/json"]["example"];
1166 assert!(!example.is_null(), "{method} {path} has no example response");
1167 }
1168 }
1169 for id in examples.keys() {
1170 assert!(known.contains(id), "reference.json names {id}, which is not an operation");
1171 }
1172 }
1173
1174 #[test]
1175 fn example_requests_send_only_what_the_body_takes() {
1176 let document = document();
1177 for (path, methods) in document["paths"].as_object().unwrap() {
1178 for (method, operation) in methods.as_object().unwrap() {
1179 let content = &operation["requestBody"]["content"]["application/json"];
1180 let Some(example) = content["example"].as_object() else { continue };
1181 let properties = &content["schema"]["properties"];
1182 for key in example.keys() {
1183 assert!(!properties[key].is_null(), "{method} {path}: {key} is not in the body");
1184 }
1185 }
1186 }
1187 }
1188
1189 /// The docs site's copy of the document. Run with `G1T_WRITE_OPENAPI=1`
1190 /// to rewrite it after changing an operation.
1191 #[test]
1192 fn the_docs_copy_is_current() {
1193 let path = concat!(env!("CARGO_MANIFEST_DIR"), "/../docs/src/data/openapi.json");
1194 let current = serde_json::to_string_pretty(&document()).unwrap() + "\n";
1195 if std::env::var_os("G1T_WRITE_OPENAPI").is_some() {
1196 std::fs::write(path, &current).unwrap();
1197 return;
1198 }
1199 let copy = std::fs::read_to_string(path).unwrap_or_default().replace("\r\n", "\n");
1200 assert!(
1201 copy == current,
1202 "apps/docs/src/data/openapi.json is out of date: run G1T_WRITE_OPENAPI=1 cargo test -p g1t-api openapi"
1203 );
1204 }
API reference: no example reads as a real secret1205
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API1206 /// The reference shows responses as they are sent: `snake_case`.
1207 #[test]
1208 fn example_responses_are_snake_case() {
1209 let document = document();
1210 for (path, methods) in document["paths"].as_object().unwrap() {
1211 for (method, operation) in methods.as_object().unwrap() {
1212 let example = &operation["responses"]["200"]["content"]["application/json"]["example"];
1213 let leaked = g1t_kit::wire::camel_case_keys(example);
1214 assert!(leaked.is_empty(), "{method} {path} shows {leaked:?}");
1215 }
1216 }
1217 }
1218
API reference: no example reads as a real secret1219 /// Examples never hold anything that reads as a real credential, which
1220 /// secret scanners rightly flag in a public repository: they end in `…`
1221 /// after the prefix, as `whsec_…` and `g1t_…` do.
1222 #[test]
1223 fn examples_hold_no_real_looking_secrets() {
Fast pages, required checks on the branch, self-hosted runners, honest incidents1224 let prefixes = ["whsec_", "g1t_", "g1tr_", "g1trt_", "sk_live_", "sk_test_", "ghp_", "github_pat_", "xoxb-", "AKIA"];
API reference: no example reads as a real secret1225 for (line, text) in REFERENCE.lines().enumerate() {
1226 for prefix in prefixes {
1227 let mut rest = text;
1228 while let Some(at) = rest.find(prefix) {
1229 let after = &rest[at + prefix.len()..];
1230 let run = after.chars().take_while(|c| c.is_ascii_alphanumeric()).count();
1231 assert!(
1232 run < 12,
1233 "reference.json line {}: `{prefix}` followed by {run} characters reads as a real secret; write `{prefix}…`",
1234 line + 1
1235 );
1236 rest = after;
1237 }
1238 }
1239 }
1240 }
API and MCP server in Rust; a public index at the API root1241}

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