Skip to content
1,007 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.

Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.01import type { ActionsApi } from "./actions";
2import type { BillingAdminApi, BillingApi } from "./billing";
3import type { DeploymentsApi } from "./deployments";
4import type { ProjectsApi } from "./projects";
5import type { EventsApi } from "./events";
6import type { IdentityAdminApi, IdentityApi } from "./identity";
7import type { IntegrationsApi } from "./integrations";
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member8import type { PackagesApi } from "./packages";
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.09import type { WebhooksApi } from "./webhooks";
10import type { ReposApi } from "./repos";
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar11import type { PullDetail, WorkApi } from "./work";
12import type { Result } from "./result";
Every agent can have its own computer. A session that needs one wakes it: a home of its own on g1t cloud, one per agent and never shared, where it runs commands, reads and writes files and keeps what it made, with each session working in its own folder under a shared home; after ten idle minutes it sleeps, its home kept as a snapshot and restored when it wakes, and Reset wipes the home while memory and artifacts stay. Its shell and files are abilities with the usual choices, Alone, Alone when asked, Ask first or Never, offered only inside sessions and never to a chat reply; every command shows on the session with its output, and the agent's new Computer tab shows the state, the disk used of the five gigabytes included, the recent commands, and Wake, Put to sleep and Reset. Machine time counts only while it is awake, on the sandbox lines of the ledger that name the agent and who asked, held to the same spend caps as the session; the disk itself costs nothing in this version. The runner gained a long-lived supervisor that answers the computer's requests inside the container, and the runner service a computer per agent that keeps its snapshot in the agent homes bucket when one is attached, and says so when none is. The REST API and the agent tool can read a computer, wake it, put it to sleep and reset it. The agents, abilities, sessions, runners, billing and deploy guides say how it works and what an operator sets up; pinning a computer to your own runner, its browser and take-over come next.13import type { RunnerComputerApi } from "./runner";
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.014import type { RunnersApi } from "./runners";
15
16/** A service binding, as far as these clients need it. */
17export type ServiceBinding = {
18 fetch(input: string, init?: RequestInit): Promise<Response>;
19};
20
21/**
22 * Calls a method on a service that speaks the JSON protocol used by the
23 * Rust services: `POST /rpc/<method>` with the arguments as the body.
24 */
25async function rpc<T>(
26 service: ServiceBinding,
27 method: string,
28 args: object,
29): Promise<T> {
30 // The hostname is ignored; a service binding always reaches its service.
31 const response = await service.fetch(`https://service/rpc/${method}`, {
32 method: "POST",
33 headers: { "content-type": "application/json" },
34 body: JSON.stringify(args),
35 });
36 if (!response.ok) {
37 throw new Error(`${method} failed with status ${response.status}`);
38 }
39 return (await response.json()) as T;
40}
41
42export function identityClient(service: ServiceBinding): IdentityApi {
43 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
44 return {
Merge invite emails that confirm the address: the emailed link carries a proof only that email has, so signing up from it needs no code; shared links and typed codes still confirm45 register: (username, email, password, inviteCode, client, emailProof) =>
46 call("register", {
47 username,
48 email,
49 password,
50 invite_code: inviteCode ?? null,
51 email_proof: emailProof ?? null,
52 client: client ?? null,
53 }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.054 signIn: (username, password, client) => call("sign_in", { username, password, client: client ?? null }),
Merge main (membership, two-factor, GitHub repo roles) into tokens55 twoFactorSignIn: (challenge, code, client) => call("two_factor_sign_in", { challenge, code, client: client ?? null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.056 signOut: (sessionToken) => call("sign_out", { sessionToken }),
57 resendVerification: (user) => call("resend_verification", { user }),
58 verifyEmail: (token) => call("verify_email", { token }),
59 requestPasswordReset: (email, client) => call("request_password_reset", { email, client: client ?? null }),
60 resetPassword: (token, password) =>
61 call("reset_password", { token, password }),
62 deviceStart: (clientName) => call("device_start", { clientName }),
63 deviceLookup: (userCode) => call("device_lookup", { userCode }),
64 deviceResolve: (userCode, user, approve) =>
65 call("device_resolve", { userCode, user, approve }),
66 deviceClaim: (deviceCode) => call("device_claim", { deviceCode }),
67 oauthAuthorize: (user, approval) => call("oauth_authorize", { user, ...approval }),
68 oauthExchange: (code, codeVerifier, clientId, redirectUri) =>
69 call("oauth_exchange", { code, codeVerifier, clientId, redirectUri }),
70 oauthRefresh: (refreshToken, clientId) =>
71 call("oauth_refresh", { refreshToken, clientId }),
72 listOAuthGrants: (user) => call("list_oauth_grants", { user }),
73 revokeOAuthGrant: (user, id) => call("revoke_oauth_grant", { user, id }),
74 updateOAuthGrant: (user, id, grant) =>
75 call("update_oauth_grant", { user, id, scopes: grant.scopes }),
76 createWorkspace: (user, slug, name) => call("create_workspace", { user, slug, name }),
77 getWorkspace: (slug) => call("get_workspace", { slug }),
Merge branch 'worktree-agent-a2013627e5ea4ab13'78 workspaceResidency: (slug) => call("workspace_residency", { slug }),
79 setWorkspaceResidency: (actor, slug, residency) => call("set_workspace_residency", { actor, slug, residency }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.080 listMembers: (slug, viewer) => call("list_members", { slug, viewer }),
81 addMember: (actor, slug, username) => call("add_member", { actor, slug, username }),
82 removeMember: (actor, slug, username) =>
Merge main (membership, two-factor, GitHub repo roles) into tokens83 call("remove_member", { actor, slug, username, surface: "web" }),
84 updateMember: (actor, slug, username, change) =>
85 call("update_member", { actor, slug, username, role: change.role ?? null, org_roles: change.org_roles ?? null, surface: "web" }),
86 transferOwnership: (actor, slug, username) => call("transfer_ownership", { actor, slug, username, surface: "web" }),
87 leaveWorkspace: (user, slug) => call("leave_workspace", { user, slug, surface: "web" }),
88 setMemberPrivileges: (actor, slug, change) => call("set_member_privileges", { actor, slug, privileges: change, surface: "web" }),
89 setTwoFactorRequirement: (actor, slug, required) =>
90 call("set_two_factor_requirement", { actor, slug, required, surface: "web" }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.091 updateWorkspace: (actor, slug, details) =>
92 call("update_workspace", { actor, slug, ...details }),
93 renameWorkspace: (actor, slug, newSlug) => call("rename_workspace", { actor, slug, newSlug }),
94 checkWorkspaceRename: (actor, slug, newSlug) =>
95 call("check_workspace_rename", { actor, slug, newSlug }),
96 resolveSlug: (slug) => call("resolve_slug", { slug }),
97 deleteWorkspace: (actor, slug, confirm) => call("delete_workspace", { actor, slug, confirm }),
98 checkWorkspaceDeletion: (actor, slug) => call("check_workspace_deletion", { actor, slug }),
99 setWorkspaceAvatar: (actor, slug, image) => call("set_workspace_avatar", { actor, slug, image }),
100 setUserAvatar: (user, image) => call("set_user_avatar", { user, image }),
101 listWorkspaceTokens: (slug, viewer) => call("list_workspace_tokens", { slug, viewer }),
102 removeWorkspaceToken: (actor, slug, id) =>
103 call("remove_workspace_token", { actor, slug, id }),
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers104 createToken: (actor, input) =>
105 call("create_token", {
106 actor,
107 owner: input.owner ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules108 name: input.name,
109 description: input.description ?? null,
110 ttl_seconds: input.ttlSeconds,
111 workspace: input.workspace,
112 repository_selection: input.repositorySelection,
113 repositories: input.repositories,
114 permissions: input.permissions,
Merge main into Artifacts Phase 2115 website: input.website ?? false,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules116 }),
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers117 updateToken: (actor, id, change, owner) =>
118 call("update_token", {
119 actor,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules120 id,
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers121 owner: owner ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules122 name: change.name ?? null,
123 description: change.description ?? null,
124 repository_selection: change.repositorySelection ?? null,
125 repositories: change.repositories ?? null,
126 permissions: change.permissions ?? null,
Merge main into Artifacts Phase 2127 website: change.website ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules128 }),
An access token can be regenerated: a new secret, its name, permissions, repositories and reach kept, and the old secret refused at once. Its page (yours under Settings, a workspace's under its settings for owners) has Regenerate with a new expiry, within the workspace's rules on lifetime, and shows the secret once; identity's regenerate_token logs it to the security log or the workspace's audit log, and refuses a revoked token. The token form's quick permissions have All, every resource at its highest level. A project's Observability settings no longer list the token g1t gives its apps on g1t.page: it is g1t's, and the page says apps there need none.129 regenerateToken: (actor, id, ttlSeconds, owner) =>
130 call("regenerate_token", { actor, id, owner: owner ?? null, ttl_seconds: ttlSeconds ?? null }),
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules131 getTokenPolicy: (slug, viewer) => call("get_token_policy", { slug, viewer }),
132 setTokenPolicy: (actor, slug, change) =>
133 call("set_token_policy", {
134 actor,
135 slug,
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers136 allow_tokens_for_all_workspaces: change.allowTokensForAllWorkspaces ?? null,
137 allow_tokens_for_this_workspace: change.allowTokensForThisWorkspace ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules138 require_approval: change.requireApproval ?? null,
139 max_lifetime_days: change.maxLifetimeDays ?? null,
140 forbid_no_expiry: change.forbidNoExpiry ?? null,
141 surface: "web",
142 }),
143 listMemberTokens: (actor, slug, filter = {}) =>
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers144 call("list_member_tokens", { actor, slug, status: filter.status ?? null }),
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules145 reviewTokenRequest: (actor, slug, id, approve, reason) =>
146 call("review_token_request", { actor, slug, id, approve, reason: reason ?? null, surface: "web" }),
147 revokeMemberToken: (actor, slug, id, reason) =>
148 call("revoke_member_token", { actor, slug, id, reason: reason ?? null, surface: "web" }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0149 userForSession: (sessionToken) => call("user_for_session", { sessionToken }),
150 registration: () => call("registration", {}),
151 listInvites: (user) => call("list_invites", { user }),
152 createInvite: (user, options = {}) =>
Merge two kinds of invite, kept apart: an invite to g1t (Settings, invite-only only, no workspace unless asked) and an invitation to a workspace (its People page)153 call("create_invite", { user, email: options.email ?? null, workspace: options.workspace ?? null, join: options.join ?? null, join_role: options.join ? (options.joinRole ?? null) : null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0154 revokeInvite: (user, id) => call("revoke_invite", { user, id }),
155 checkInvite: (code, client, options = {}) =>
156 call("check_invite", {
157 code,
158 client: client ?? null,
159 viewer: options.viewer ?? null,
160 any_status: options.anyStatus ?? false,
Merge invite emails that confirm the address: the emailed link carries a proof only that email has, so signing up from it needs no code; shared links and typed codes still confirm161 email_proof: options.emailProof ?? null,
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0162 }),
163 acceptInvite: (user, code) => call("accept_invite", { user, code }),
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)164 inviteMember: (actor, slug, who) =>
Workspace is the workspace's settings, in one place. Its sidebar is grouped, General, Access, Money, Compute, Code, Agents, Chat, Artifacts, Security and Integrations, every page one click away with no settings inside settings, the groups folding and the owner-only pages hidden from members; what is not here yet is marked Soon with a hint. Members is a list with search and filters for role, two-factor and team, and Invite opens a dialog: who, by username, name or email, their role and a note that goes into the invitation; nothing is filled in inline any more. Invitations is its own page with All, Pending, Accepted, Declined, Expired and Revoked filters that say how many, and each row's menu can copy the link, send it again or revoke it; identity learned to send an invitation again and to carry the note. Permissions gathers every rule about who may do what, by part: Code's base permission and member privileges, who creates teams, who creates channels, and, marked Soon with what applies today, forking private repositories, adding agents to conversations, messaging agents directly, creating spaces and default sharing, creating workspace agents and raising budgets, deploying to production and publishing packages. General lost what moved. The permissions guide is new, and the workspaces, people and teams, access, chat, teams, authentication and billing guides say where things are now.165 call("invite_member", { actor, slug, email: who.email ?? "", username: who.username ?? null, role: who.role ?? null, message: who.message ?? null }),
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)166 listInvitations: (user) => call("list_invitations", { user }),
167 acceptInvitation: (user, id) => call("accept_invitation", { user, id, surface: "web" }),
168 declineInvitation: (user, id) => call("decline_invitation", { user, id, surface: "web" }),
169 findPeople: (query, limit) => call("find_people", { query, limit: limit ?? null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0170 workspaceInvites: (slug, viewer) => call("workspace_invites", { slug, viewer }),
171 revokeWorkspaceInvite: (actor, slug, id) => call("revoke_workspace_invite", { actor, slug, id }),
Workspace is the workspace's settings, in one place. Its sidebar is grouped, General, Access, Money, Compute, Code, Agents, Chat, Artifacts, Security and Integrations, every page one click away with no settings inside settings, the groups folding and the owner-only pages hidden from members; what is not here yet is marked Soon with a hint. Members is a list with search and filters for role, two-factor and team, and Invite opens a dialog: who, by username, name or email, their role and a note that goes into the invitation; nothing is filled in inline any more. Invitations is its own page with All, Pending, Accepted, Declined, Expired and Revoked filters that say how many, and each row's menu can copy the link, send it again or revoke it; identity learned to send an invitation again and to carry the note. Permissions gathers every rule about who may do what, by part: Code's base permission and member privileges, who creates teams, who creates channels, and, marked Soon with what applies today, forking private repositories, adding agents to conversations, messaging agents directly, creating spaces and default sharing, creating workspace agents and raising budgets, deploying to production and publishing packages. General lost what moved. The permissions guide is new, and the workspaces, people and teams, access, chat, teams, authentication and billing guides say where things are now.172 resendWorkspaceInvite: (actor, slug, id) => call("resend_workspace_invite", { actor, slug, id }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0173 requestAccess: (email, about, client) => call("request_access", { email, about, client: client ?? null }),
174 userForGitCredentials: (username, secret) =>
175 call("user_for_git_credentials", { username, secret }),
176 userForAccessToken: (token) => call("user_for_access_token", { token }),
177 userForSshKey: (fingerprint) => call("user_for_ssh_key", { fingerprint }),
178 userByUsername: (username) => call("user_by_username", { username }),
179 usernames: (ids) => call("usernames", { ids }),
Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002)180 usersForAudience: (ids) => call("users_for_audience", { ids }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0181 profile: (username) => call("profile", { username }),
182 updateProfile: (actor, fields) => call("update_profile", { actor, ...fields }),
183 profileWorkspaces: (username, viewer, publicIn) =>
184 call("profile_workspaces", { username, viewer, public: publicIn }),
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.185 dockPins: (user, workspace) => call("dock_pins", { user, workspace }),
186 setDockPins: (user, workspace, apps) => call("set_dock_pins", { user, workspace, apps }),
Chat has sounds. A short warm cue plays for a message in a conversation you have open but aren't looking at, a direct message, a mention of you and an agent finishing something for you, with a soft tick for sending that is off until you turn it on; never for your own messages, a muted conversation, a conversation you are looking at in a window that has the front, or while you have paused notifications, and never twice for one message or more than once in a second and a half. The cues are made by the browser itself in two sets, Soft and Bright, so nothing is downloaded; the Sounds and notifications section of your notification settings turns them on and off, picks the set and the volume, plays each one, and offers desktop notifications for when the window is behind; Do not disturb is the one pause everyone sees, set from the chat sidebar's bell, the settings, or your avatar menu, now with a two-hour choice, and the top bar's bell shows a dot while it's on. Your choices are kept with your account. The sound layer sits behind one small interface so the desktop app can play them natively later. The chat and notifications guides say the rules.187 soundSettings: (user) => call("sound_settings", { user }),
188 setSoundSettings: (user, change) => call("set_sound_settings", { user, change }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0189 listSshKeys: (user) => call("list_ssh_keys", { user }),
190 addSshKey: (user, title, publicKey) =>
191 call("add_ssh_key", { user, title, publicKey }),
192 removeSshKey: (user, id) => call("remove_ssh_key", { user, id }),
193 listAccessTokens: (user) => call("list_access_tokens", { user }),
194 createAccessToken: (user, name, ttlSeconds, grant) =>
195 call("create_access_token", {
196 user,
197 name,
198 ttlSeconds,
199 scopes: grant?.scopes ?? null,
200 listed: grant?.listed ?? false,
201 }),
202 createAgentToken: (onBehalfOf, scope, ttlSeconds) =>
203 call("create_agent_token", { onBehalfOf, scope, ttlSeconds }),
204 removeAccessToken: (user, id) => call("remove_access_token", { user, id }),
205 createRunCredential: (input) => call("create_run_credential", input),
206 bindRunCredentials: (tokenHashes, runId) => call("bind_run_credentials", { tokenHashes, runId }),
207 revokeRunCredentials: (target) => call("revoke_run_credentials", target),
208 // Who has access to a repository; see access.ts.
209 repoAccess: (owner, name, viewer) => call("repo_access", { viewer, path: { namespace: owner, name } }),
210 addCollaborator: (actor, owner, name, invitee, role) =>
211 call("add_collaborator", { actor, path: { namespace: owner, name }, invitee, role }),
212 setCollaboratorRole: (actor, owner, name, username, role) =>
213 call("set_collaborator_role", { actor, path: { namespace: owner, name }, username, role }),
214 removeCollaborator: (actor, owner, name, username) =>
215 call("remove_collaborator", { actor, path: { namespace: owner, name }, username }),
216 collaboratorPermission: (viewer, owner, name, username) =>
217 call("collaborator_permission", { viewer, path: { namespace: owner, name }, username }),
218 myRepoInvitations: (user) => call("my_repo_invitations", { user }),
219 respondRepoInvitation: (user, id, accept) => call("respond_repo_invitation", { user, id, accept }),
220 revokeRepoInvitation: (actor, owner, name, id) =>
221 call("revoke_repo_invitation", { actor, path: { namespace: owner, name }, id }),
222 setBasePermission: (actor, slug, base) => call("set_base_permission", { actor, slug, base_permission: base }),
223 outsideCollaborators: (viewer, slug) => call("outside_collaborators", { viewer, slug }),
Merge branch 'worktree-agent-a5a5de74d8863d554' into worktree-agent-a16631325aecf58ca224 // A repository's deploy keys; see deploy-keys.ts.
225 listDeployKeys: (viewer, owner, name) => call("list_deploy_keys", { viewer, path: { namespace: owner, name } }),
226 addDeployKey: (actor, owner, name, key) =>
227 call("add_deploy_key", { actor, path: { namespace: owner, name }, title: key.title, key: key.key, read_only: key.readOnly }),
228 removeDeployKey: (actor, owner, name, id) => call("remove_deploy_key", { actor, path: { namespace: owner, name }, id }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar229 // Teams; see teams.ts.
230 listTeams: (viewer, workspace, query) => call("list_teams", { viewer, workspace, query: query ?? null }),
231 getTeam: (viewer, workspace, team) => call("get_team", { viewer, workspace, team }),
232 createTeam: (actor, workspace, team) => call("create_team", { actor, workspace, ...team }),
Merge branch 'worktree-agent-ad7c6d88d93adc817'233 setTeamCreation: (actor, slug, setting) => call("set_team_creation", { actor, slug, team_creation: setting }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar234 updateTeam: (actor, workspace, team, changes) => call("update_team", { actor, workspace, team, ...changes }),
235 deleteTeam: (actor, workspace, team) => call("delete_team", { actor, workspace, team }),
236 teamMembers: (viewer, workspace, team, includeChildTeams) =>
237 call("team_members", { viewer, workspace, team, include_child_teams: includeChildTeams ?? false }),
238 setTeamMember: (actor, workspace, team, username, role) =>
239 call("set_team_member", { actor, workspace, team, username, role }),
240 removeTeamMember: (actor, workspace, team, username) =>
241 call("remove_team_member", { actor, workspace, team, username }),
242 childTeams: (viewer, workspace, team) => call("child_teams", { viewer, workspace, team }),
243 teamRepos: (viewer, workspace, team) => call("team_repos", { viewer, workspace, team }),
244 setTeamRepo: (actor, workspace, team, owner, name, role) =>
245 call("set_team_repo", { actor, workspace, team, repo: { namespace: owner, name }, role }),
246 removeTeamRepo: (actor, workspace, team, owner, name) =>
247 call("remove_team_repo", { actor, workspace, team, repo: { namespace: owner, name } }),
248 userTeams: (viewer, workspace, username) => call("user_teams", { viewer, workspace, username }),
249 teamMemberships: (viewer, workspace) => call("team_memberships", { viewer, workspace }),
People and teams are front and centre: one directory of people and agents with presence, local time, titles, teams and what each owns; profiles with manager and reports and the agents they work with; an org chart with each team's agents beside the person who leads it; and teams of any mix, with a lead, a channel, a budget agents keep to and the agents on them. Every agent is told its teams each turn (who leads, who owns what, who's around and who to page), and the team page shows exactly what. Member management is Members and invites; the people and teams guide says how.250 teamAgents: (viewer, workspace, team) => call("team_agents", { viewer, workspace, team }),
251 setTeamAgent: (actor, workspace, team, agentId) => call("set_team_agent", { actor, workspace, team, agent_id: agentId }),
252 removeTeamAgent: (actor, workspace, team, agentId) => call("remove_team_agent", { actor, workspace, team, agent_id: agentId }),
An agent is on teams the way a person is: through team membership, with no team or department of its own. Add it to teams when you create it, from its profile or from the team's page; the Agents sidebar groups agents by the teams they're on, with those on none last; what an agent is told about its teammates, team budgets, skills reach, Spend's By team and the People pages all read memberships. Agents with an old team name matching a team are moved onto it once; the rest are left off a team. Templates name a role only. The agents, teams and people guides say how.253 agentTeams: (workspace, agentId) => call("agent_teams", { workspace, agent_id: agentId }),
254 teamAgentIndex: (workspace) => call("team_agent_index", { workspace }),
255 adoptAgentTeams: (workspaceId, agents) => call("adopt_agent_teams", { workspace_id: workspaceId, agents }),
People and teams are front and centre: one directory of people and agents with presence, local time, titles, teams and what each owns; profiles with manager and reports and the agents they work with; an org chart with each team's agents beside the person who leads it; and teams of any mix, with a lead, a channel, a budget agents keep to and the agents on them. Every agent is told its teams each turn (who leads, who owns what, who's around and who to page), and the team page shows exactly what. Member management is Members and invites; the people and teams guide says how.256 // People; see people.ts.
257 peopleDirectory: (viewer, workspace) => call("people_directory", { viewer, workspace }),
258 setMemberProfile: (actor, workspace, username, changes) => call("set_member_profile", { actor, workspace, username, ...changes }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0259 };
260}
261
262/**
263 * The slug a renamed workspace has now, for a `workspace.renamed` handler:
264 * asked of identity by the workspace's id, so that renames delivered twice
265 * or out of order converge. Falls back to the event's `to`.
266 */
267export async function currentWorkspaceSlug(
268 identity: ServiceBinding,
269 renamed: { workspaceId: string; to: string },
270): Promise<string> {
271 const names = await identityClient(identity).usernames([renamed.workspaceId]);
272 return names[renamed.workspaceId] ?? renamed.to;
273}
274
275/** The slugs whose rows move to `current`: the two a rename names, less `current`. */
276export function staleSlugs(renamed: { from: string; to: string }, current: string): string[] {
277 return [...new Set([renamed.from, renamed.to])].filter((slug) => slug !== current);
278}
279
280/**
281 * Where a transferred repository is now, as `namespace/name`, for a
282 * `repo.transferred` handler: asked of repos by id, so transfers delivered
283 * twice or out of order converge. Falls back to the event's destination.
284 */
285export async function currentRepoPath(
286 repos: ServiceBinding,
287 transferred: { repoId: string; name: string; to: string },
288): Promise<string> {
289 const path = await rpc<{ namespace: string; name: string } | null>(repos, "path_by_id", { id: transferred.repoId });
290 return path ? `${path.namespace}/${path.name}` : `${transferred.to}/${transferred.name}`;
291}
292
293/** The paths whose rows move to `current`: the two a transfer names, less `current`. */
294export function stalePaths(transferred: { name: string; from: string; to: string }, current: string): string[] {
295 return [...new Set([transferred.from, transferred.to].map((ns) => `${ns}/${transferred.name}`))].filter(
296 (path) => path !== current,
297 );
298}
299
300/**
301 * A repository's path change, from `repo.transferred` or `repo.renamed`,
302 * read the same way: the two paths (`namespace/name`) the event names, old
303 * then new. Null for any other event.
304 */
305export type RepoMove = { repoId: string; paths: [string, string] };
306
307export function repoMove(event: { type: string; data: unknown }): RepoMove | null {
308 const data = event.data as Record<string, string>;
309 if (event.type === "repo.transferred") {
310 return { repoId: data.repoId!, paths: [`${data.from}/${data.name}`, `${data.to}/${data.name}`] };
311 }
312 if (event.type === "repo.renamed") {
313 return { repoId: data.repoId!, paths: [`${data.namespace}/${data.from}`, `${data.namespace}/${data.to}`] };
314 }
315 return null;
316}
317
318/**
319 * Where a moved repository is now, as `namespace/name`: asked of repos by
320 * id, so moves delivered twice or out of order converge. Falls back to the
321 * event's new path.
322 */
323export async function currentMovedPath(repos: ServiceBinding, move: RepoMove): Promise<string> {
324 const path = await rpc<{ namespace: string; name: string } | null>(repos, "path_by_id", { id: move.repoId });
325 return path ? `${path.namespace}/${path.name}` : move.paths[1];
326}
327
328/** The paths whose rows move to `current`: the two a move names, less `current`. */
329export function staleMovedPaths(move: RepoMove, current: string): string[] {
330 return [...new Set(move.paths)].filter((path) => path !== current);
331}
332
333/** Staff-only identity. Only sudo binds to it; see `IdentityAdminApi`. */
334export function identityAdminClient(service: ServiceBinding): IdentityAdminApi {
335 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
336 return {
337 workspaces: (query) => call("admin_workspaces", { query: query ?? null }),
338 workspace: (slug) => call("admin_workspace", { slug }),
339 waitlist: (query, status) => call("admin_waitlist", { query: query ?? null, status: status ?? null }),
340 waitlistPending: () => call("admin_waitlist_pending", {}),
341 decideWaitlist: (id, approve, staff, note) => call("admin_decide_waitlist", { id, approve, staff, note: note ?? null }),
342 invites: (query) => call("admin_invites", { query: query ?? null }),
343 revokeInvite: (id, staff) => call("admin_revoke_invite", { id, staff }),
344 mintInvite: (email, staff) => call("admin_mint_invite", { email, staff }),
345 grantInvites: (target, name, amount, note, staff) =>
346 call("admin_grant_invites", { target, name, amount, note, staff }),
347 inviteTree: (username) => call("admin_invite_tree", { username }),
348 workspaceInvites: (slug) => call("admin_workspace_invites", { slug }),
Merge shared invite links: label, uses, expiry, domains; joined through recorded (identity 0038)349 sharedInvites: () => call("admin_shared_invites", {}),
350 createSharedInvite: (link, staff) =>
351 call("admin_create_shared_invite", {
352 label: link.label,
353 max_uses: link.maxUses,
354 expires_on: link.expiresOn,
355 domains: link.domains,
356 staff,
357 }),
358 revokeSharedInvite: (id, staff) => call("admin_revoke_shared_invite", { id, staff }),
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member359 deletedWorkspaces: () => call("admin_deleted_workspaces", {}),
360 restoreWorkspace: (workspaceId, staff) => call("admin_restore_workspace", { workspaceId, staff }),
361 purgeWorkspace: (workspaceId, staff, confirm) => call("admin_purge_workspace", { workspaceId, staff, confirm }),
Merge branch 'worktree-agent-a8385d293d42c913a'362 aliases: () => call("admin_aliases", {}),
363 setAlias: (alias, workspace, note, staff) => call("admin_set_alias", { alias, workspace, note, staff }),
364 removeAlias: (alias, reason, staff) => call("admin_remove_alias", { alias, reason, staff }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0365 };
366}
367
368export function reposClient(service: ServiceBinding): ReposApi {
369 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
370 return {
371 get: (path, viewer) => call("get", { path, viewer }),
372 getById: (id, viewer) => call("get_by_id", { id, viewer }),
373 readable: (ids, viewer) => call("readable", { ids, viewer }),
374 publicNamespaces: (ownerId) => call("public_namespaces", { ownerId }),
375 list: (viewer, options = {}) => call("list", { viewer, ...options }),
376 create: (owner, input) => call("create", { owner, ...input }),
377 update: (actor, path, changes) => call("update", { actor, path, ...changes }),
378 transfer: (actor, path, to) => call("transfer", { actor, path, to }),
379 delete: (actor, path, confirm) => call("delete", { actor, path, confirm }),
380 deleted: (viewer, namespace) => call("deleted", { viewer, namespace }),
381 restore: (actor, path) => call("restore", { actor, path }),
382 purge: (actor, path, confirm) => call("purge", { actor, path, confirm }),
383 rename: (actor, path, name) => call("rename", { actor, path, name }),
384 archive: (actor, path, archived) => call("archive", { actor, path, archived }),
385 setVisibility: (actor, path, isPrivate, confirm) => call("set_visibility", { actor, path, isPrivate, confirm }),
386 setDefaultBranch: (actor, path, branch) => call("set_default_branch", { actor, path, branch }),
387 renameBranch: (actor, path, from, to) => call("rename_branch", { actor, path, from, to }),
The Branches page does things to branches now. It has tabs (Overview, Yours, Active, Stale, All, kept in the address as ?tab=) and search; Overview shows the default branch, then the first five of your branches, the active ones and the stale ones, each linking to the rest. Each branch is a row with its name in a code chip with a copy button, who made its latest commit and when, that commit's checks, behind and ahead counts with bars drawn against the largest shown, and its pull request (the open one, else the newest merged or closed) with its state; on a phone the columns fold under the name. Yours is branches whose latest commit is the viewer's; stale is no commit in 90 days.388 createBranch: (actor, path, name, from = "") => call("create_branch", { actor, path, name, from }),
389 removeBranch: (actor, path, branch, head) => call("remove_branch", { actor, path, branch, head }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0390 resolveBranch: (repoId, branch) => call("resolve_branch", { repoId, branch }),
391 statusById: (id) => call("status_by_id", { id }),
Merge branch 'worktree-agent-a2013627e5ea4ab13'392 storageOptions: () => call("storage_options", {}),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0393 resolvePath: (path) => call("resolve_path", { path }),
394 tree: (path, viewer, ref, treePath) =>
395 call("tree", { path, viewer, ref, treePath }),
396 blob: (path, viewer, ref, filePath) =>
397 call("blob", { path, viewer, ref, filePath }),
398 log: (path, viewer, ref, limit) => call("log", { path, viewer, ref, limit }),
399 blame: (path, viewer, ref, filePath) => call("blame", { path, viewer, ref, filePath }),
400 forkForPull: (sourceId, pullId, actor) =>
401 call("fork_for_pull", { sourceId, pullId, actor }),
402 gitAccess: (path, viewer, service) =>
403 call("git_access", { path, viewer, service }),
404 branches: (path, viewer) => call("branches", { path, viewer }),
Branches and Tags pages, each file's last commit, and the branch menu on files405 lastCommits: (path, viewer, ref, treePath) => call("last_commits", { path, viewer, ref, treePath }),
Merge project overview: one branch_drift call, spliced histories, cached tags, 6 repos calls instead of 25406 branchDrift: (path, viewer, base, heads) => call("branch_drift", { path, viewer, base, heads }),
Branches and Tags pages, each file's last commit, and the branch menu on files407 tags: (path, viewer) => call("tags", { path, viewer }),
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97408 about: (path, viewer) => call("about", { path, viewer }),
409 languages: (path, viewer) => call("languages", { path, viewer }),
410 contributors: (path, viewer) => call("contributors", { path, viewer }),
411 license: (path, viewer) => call("license", { path, viewer }),
412 stars: (path, viewer) => call("stars", { path, viewer }),
413 star: (actor, path, starred) => call("star", { path, actor, starred }),
414 stargazers: (path, viewer, page) => call("stargazers", { path, viewer, page: page ?? null }),
415 starred: (username, viewer) => call("starred", { username, viewer }),
416 releases: (path, viewer) => call("releases", { path, viewer }),
417 release: (path, viewer, which) => call("release", { path, viewer, id: which.id ?? null, tag: which.tag ?? null, latest: which.latest ?? false }),
418 createRelease: (actor, path, release) => call("create_release", { path, actor, ...release }),
419 updateRelease: (actor, path, id, change) => call("update_release", { path, actor, id, ...change }),
420 deleteRelease: (actor, path, id) => call("delete_release", { path, actor, id }),
Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's.421 listFiles: (repoId, ref, limit, options) => call("list_files", { repoId, ref, skipDirs: [], limit, links: options?.links ?? false }),
422 openArchiveToken: (path, token) => call("open_archive_token", { path, token }),
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths423 rawBlobs: (repoId, hashes, maxBytes) => call("raw_blobs", { repoId, hashes, maxBytes }),
Merge g1tusercontent.com: registry answers run nothing in a browser, the site's pages run only their own scripts, repository files and avatars on their own origin, raw files rate limited per address424 rawFile: (repoId, ref, path, maxBytes) => call("raw_file", { repoId, ref, path, maxBytes }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0425 commitFile: (repo, actor, file) => call("commit_file", { repo, actor, ...file }),
426 land: (sourceId, actor, branch) => call("land", { sourceId, actor, branch }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar427 compare: (repoId, viewer, base, head, baseBranch) => call("compare", { repoId, viewer, base, head, baseBranch }),
Merge branch 'worktree-agent-ac5b181a013e54348'428 claimBackups: (limit, maxRunning) => call("claim_backups", { limit, maxRunning }),
429 // The sandbox's own calls are snake_case (they come through the API).
430 failBackup: (jobId, token, error) => call("backup_fail", { job_id: jobId, token, error }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0431 };
432}
433
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar434/**
435 * `PullDetail`'s own fields that the work service writes in snake_case:
436 * `g1t_contracts::work::PullDetail` has no camelCase renaming, though what
437 * it holds (`Pull`, `CheckRun` and the rest) does. Each with its name here.
438 */
439const PULL_DETAIL_FIELDS = [
440 ["review_pending", "reviewPending"],
441 ["earlier_checks", "earlierChecks"],
442 ["required_checks", "requiredChecks"],
443 ["code_owners", "codeOwners"],
444] as const;
445
446/**
447 * A pull request's detail as the work service sent it, with its own fields
448 * in the camelCase this package uses: read at the edge, by `workClient`'s
449 * `getPull`. Either spelling is taken, so a service that already sends
450 * camelCase reads the same.
451 */
452export function pullDetailFromWire(raw: Record<string, unknown>): PullDetail {
453 const detail: Record<string, unknown> = { ...raw };
454 for (const [snake, camel] of PULL_DETAIL_FIELDS) {
455 if (snake in detail) {
456 if (!(camel in detail)) detail[camel] = detail[snake];
457 delete detail[snake];
458 }
459 }
460 if (typeof detail.reviewPending !== "boolean") detail.reviewPending = false;
461 return detail as PullDetail;
462}
463
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0464export function workClient(service: ServiceBinding): WorkApi {
465 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
466 return {
467 openIssue: (actor, repo, input) => call("open_issue", { actor, repo, ...input }),
468 delegateIssue: (actor, repo, input) => call("delegate_issue", { actor, repo, ...input }),
469 listIssues: (repo, viewer, filter = {}) => call("list_issues", { repo, viewer, ...filter }),
470 getIssue: (repo, number, viewer) => call("get_issue", { repo, number, viewer }),
471 updateIssue: (actor, repo, number, input) =>
472 call("update_issue", { actor, repo, number, ...input }),
473 closeIssue: (actor, repo, number, reason) =>
474 call("close_issue", { actor, repo, number, reason }),
475 reopenIssue: (actor, repo, number) => call("reopen_issue", { actor, repo, number }),
476 listLabels: (repo, viewer) => call("list_labels", { repo, viewer }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar477 saveLabel: (actor, repo, label) => call("save_label", { actor, repo, ...label }),
478 deleteLabel: (actor, repo, name) => call("delete_label", { actor, repo, name }),
479 addDefaultLabels: (actor, repo) => call("add_default_labels", { actor, repo }),
480 setLabels: (actor, repo, number, labels, change = "set") =>
481 call("set_labels", { actor, repo, number, labels, change }),
482 listMilestones: (repo, viewer, state) => call("list_milestones", { repo, viewer, state }),
483 getMilestone: (repo, number, viewer) => call("get_milestone", { repo, number, viewer }),
484 saveMilestone: (actor, repo, milestone) => call("save_milestone", { actor, repo, ...milestone }),
485 deleteMilestone: (actor, repo, number) => call("delete_milestone", { actor, repo, number }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0486 counts: (repo, viewer) => call("counts", { repo, viewer }),
487 addComment: (actor, repo, number, comment) =>
488 call("add_comment", { actor, repo, number, ...comment }),
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts489 editComment: (actor, repo, commentId, body) => call("edit_comment", { actor, repo, commentId, body }),
490 deleteComment: (actor, repo, commentId) => call("delete_comment", { actor, repo, commentId }),
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar491 workspaceAgentComment: (repo, number, agent, actingFor, body) =>
492 call("workspace_agent_comment", { repo, number, agent, acting_for: actingFor, body }),
493 workspaceAgentReview: (repo, number, agent, actingFor, verdict, body) =>
494 call("workspace_agent_review", { repo, number, agent, acting_for: actingFor, verdict, body }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0495 startChecks: (pullId) => call("start_checks", { pullId }),
496 reportChecks: (runId, token, report) =>
497 call("report_checks", { runId, token, ...report }),
498 startReview: (pullId) => call("start_review", { pullId }),
499 failReview: (runId, token, error) => call("report_review", { runId, token, error }),
500 startMergecheck: (pullId) => call("start_mergecheck", { pullId }),
501 failMergecheck: (pullId, token, error) => call("report_mergecheck", { pullId, token, error }),
502 advance: (pullId) => call("advance", { pullId }),
503 stall: (pullId, reason) => call("stall", { pullId, reason }),
504 managedPulls: (repoId) => call("managed_pulls", { repoId }),
505 queue: (repo, viewer) => call("queue", { repo, viewer }),
506 queueBuild: (repoId) => call("queue_build", { repoId }),
507 failQueue: (entryId, token, error) => call("report_queue", { entryId, token, error }),
508 removeFromQueue: (actor, repo, number) => call("remove_from_queue", { actor, repo, number }),
509 messageAgent: (actor, repo, number, body) => call("message_agent", { actor, repo, number, body }),
510 catchUpJob: (pullId) => call("catch_up_job", { pullId }),
511 wakeForMessages: (pullId) => call("wake_for_messages", { pullId }),
512 getSettings: (repo, viewer) => call("get_settings", { repo, viewer }),
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge513 // Rulesets travel in snake_case (rules.ts).
514 listRulesets: (owner, viewer, includeParents = false) =>
515 call("list_rulesets", { viewer, ...owner, include_parents: includeParents }),
516 getRuleset: (owner, id, viewer) => call("get_ruleset", { viewer, ...owner, id }),
517 saveRuleset: (actor, owner, ruleset, id) => call("save_ruleset", { actor, ...owner, id: id ?? null, ruleset }),
518 deleteRuleset: (actor, owner, id) => call("delete_ruleset", { actor, ...owner, id }),
519 effectiveRules: (repo, name, viewer, target = "branch") => call("effective_rules", { viewer, repo, name, target }),
520 ruleEvaluations: (owner, viewer, filter = {}) => call("rule_evaluations", { viewer, ...owner, ...filter }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0521 seenChecks: (repo, viewer) => call("seen_checks", { repo, viewer }),
Merge checks: statuses and check runs on every commit522 commitChecks: (repo, viewer, shas) => call("commit_checks", { repo, viewer, shas }),
523 getCheckRun: (repo, id, viewer) => call("get_check_run", { repo, id, viewer }),
524 checkRunAnnotations: (repo, id, viewer) => call("check_run_annotations", { repo, id, viewer }),
525 requestCheckAction: (actor, repo, id, identifier) => call("request_check_action", { actor, repo, id, identifier }),
526 rerequestCheckRun: (actor, repo, id) => call("rerequest_check_run", { actor, repo, id }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar527 codeownersErrors: (repo, viewer, ref) => call("codeowners_errors", { repo, viewer, ref: ref ?? null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0528 updateSettings: (actor, repo, settings) =>
529 call("update_settings", { actor, repo, settings }),
530 openPull: (actor, repo, input) => call("open_pull", { actor, repo, ...input }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar531 listPulls: (repo, viewer, state, filter = {}) => call("list_pulls", { repo, viewer, state, ...filter }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0532 pullsForRepos: (repoIds, viewer, limit) => call("pulls_for_repos", { repoIds, viewer, limit }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar533 // Its own fields arrive in snake_case: read into camelCase here.
534 getPull: (repo, number, viewer) =>
535 call<Result<Record<string, unknown>>>("get_pull", { repo, number, viewer }).then(
536 (found): Result<PullDetail> => (found.ok ? { ok: true, value: pullDetailFromWire(found.value) } : found),
537 ),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0538 updatePull: (actor, repo, number, changes) =>
539 call("update_pull", { actor, repo, number, ...changes }),
540 catchUpPull: (actor, repo, number) => call("catch_up_pull", { actor, repo, number }),
541 readyPull: (actor, repo, number, summary) =>
542 call("ready_pull", { actor, repo, number, summary }),
543 closePull: (actor, repo, number) => call("close_pull", { actor, repo, number }),
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts544 reopenPull: (actor, repo, number) => call("reopen_pull", { actor, repo, number }),
545 convertPullToDraft: (actor, repo, number) => call("convert_pull_to_draft", { actor, repo, number }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0546 mergePull: (actor, repo, number, options = {}) =>
547 call("merge_pull", { actor, repo, number, ...options }),
548 listActivePulls: (viewer) => call("list_active_pulls", { viewer }),
549 byAuthor: (username, viewer, filter = {}) => call("by_author", { username, viewer, ...filter }),
Chat controls, public profiles, shadcn selects, and no Docs tab in a project550 contributions: (username, viewer) => call("contributions", { username, viewer }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0551 startPlan: (actor, repo, brief) => call("start_plan", { actor, repo, brief }),
552 failPlan: (planId, token, error) => call("report_plan", { planId, token, error }),
553 getPlan: (repo, viewer, id) => call("get_plan", { repo, viewer, id }),
554 listPlans: (repo, viewer) => call("list_plans", { repo, viewer }),
555 applyPlan: (actor, repo, id, options = {}) =>
556 call("apply_plan", { actor, repo, id, ...options }),
557 queueIssue: (actor, repo, number, queued) =>
558 call("queue_issue", { actor, repo, number, queued }),
559 readyIssues: (repoId) => call("ready_issues", { repoId }),
560 listAssignedIssues: (viewer) => call("list_assigned_issues", { viewer }),
561 appendSession: (actor, repo, number, entries) =>
562 call("append_session", { actor, repo, number, entries }),
563 readSession: (repo, number, viewer, afterSeq = 0) =>
564 call("read_session", { repo, number, viewer, afterSeq }),
565 };
566}
567
568export function billingClient(service: ServiceBinding): BillingApi {
569 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
570 return {
571 status: () => call("status", {}),
572 account: (workspace, viewer) => call("account", { workspace, viewer }),
573 ledger: (workspace, viewer) => call("ledger", { workspace, viewer }),
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging574 credits: (workspace, viewer) => call("credits", { workspace, viewer }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0575 statement: (workspace, viewer, month = null, group = "day") => call("statement", { workspace, viewer, month, group }),
576 statementEntries: (workspace, viewer, filter) =>
577 call("statement_entries", {
578 workspace,
579 viewer,
580 month: filter.month,
581 kind: filter.kind,
582 day: filter.day ?? null,
583 project: filter.project ?? null,
584 before: filter.before ?? null,
585 }),
586 usage: (workspace, viewer, since) => call("usage", { workspace, viewer, since }),
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix587 tokenUsage: (workspace, viewer, options = {}) =>
588 call("token_usage", { workspace, viewer, person: options.person ?? null, days: options.days ?? null }),
589 recordTokens: (usage) => call("record_tokens", usage),
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens590 gatewayModels: () => call("gateway_models", {}),
Merge branch 'main' into actions-toolkit-oidc-artifacts591 modelDefaults: () => call("model_defaults", {}),
592 recordDiscovery: (provider, models, by, error = null) => call("record_discovery", { provider, models, by, error }),
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens593 gatewayAdmit: (workspace) => call("gateway_admit", { workspace }),
594 recordGateway: (record) => call("record_gateway", record),
595 gatewayRequests: (workspace, viewer, options = {}) =>
596 call("gateway_requests", { workspace, viewer, limit: options.limit ?? null, before: options.before ?? null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0597 checkout: (actor, workspace, amountCents, returnUrl, method = "card") =>
598 call("checkout", { actor, workspace, amountCents, returnUrl, method }),
599 confirm: (workspace, viewer, session) => call("confirm", { workspace, viewer, session }),
600 canStart: (workspace) => call("can_start", { workspace }),
601 trial: (workspace, exempt) => call("trial", { workspace, exempt }),
602 startRun: (run) => call("start_run", run),
603 features: (workspace, viewer) => call("features", { workspace, viewer }),
604 subscribe: (actor, workspace, feature, returnUrl) =>
605 call("subscribe", { actor, workspace, feature, returnUrl }),
606 confirmSubscription: (workspace, viewer, session) =>
607 call("confirm_subscription", { workspace, viewer, session }),
608 cancelSubscription: (actor, workspace, feature, resume = false) =>
609 call("cancel_subscription", { actor, workspace, feature, resume }),
610 hasFeature: (workspace, feature) => call("has_feature", { workspace, feature }),
Merge Stripe Tax, the card fee on card payments, and one free workspace per person611 freeWorkspaces: (workspaces) => call("free_workspaces", { workspaces }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0612 chargeFeature: (charge) => call("charge_feature", charge),
613 billingPortal: (actor, workspace, returnUrl) => call("billing_portal", { actor, workspace, return_url: returnUrl }),
614 recordSandbox: (usage) => call("record_sandbox", usage),
615 limit: (workspace, viewer) => call("limit", { workspace, viewer }),
616 checkLimit: (workspace) => call("check_limit", { workspace }),
617 prices: () => call("prices", {}),
618 notePending: (workspace, source, costMicros, detail = null) => call("note_pending", { workspace, source, costMicros, detail }),
619 usageMeters: (workspace, viewer) => call("usage_meters", { workspace, viewer }),
620 setSpendLimit: (actor, workspace, spendLimitMicros, useFullLimit = false, raiseOnce = false) =>
621 call("set_spend_limit", { actor, workspace, spendLimitMicros, use_full_limit: useFullLimit, raise_once: raiseOnce }),
622 invoices: (workspace, viewer) => call("invoices", { workspace, viewer }),
623 entitlements: (workspace) => call("entitlements", { workspace }),
624 reserve: (reservation) => call("reserve", reservation),
625 settle: (reservationId, actualMicros) => call("settle", { reservationId, actualMicros }),
626 cardCheck: (actor, workspace, returnUrl) => call("card_check", { actor, workspace, returnUrl }),
627 confirmCardCheck: (workspace, viewer, session) => call("confirm_card_check", { workspace, viewer, session }),
628 requestLimit: (actor, workspace, request) => call("request_limit", { actor, workspace, ...request }),
629 limitRequests: (workspace, viewer) => call("limit_requests", { workspace, viewer }),
630 confirmSpike: (actor, workspace, keepGoing) => call("confirm_spike", { actor, workspace, keepGoing }),
631 setCaps: (actor, workspace, caps) => call("set_caps", { actor, workspace, ...caps }),
Usage, Billing settings and prepaid AI credit; fixes from the UX audit632 usageReport: (workspace, viewer, range) =>
633 call("usage_report", { workspace, viewer, from: range.from, until: range.until, products: range.products ?? [], projects: range.projects ?? [] }),
634 aiCredit: (workspace, viewer) => call("ai_credit", { workspace, viewer }),
635 buyAiCredit: (actor, workspace, amountCents, returnUrl) => call("buy_ai_credit", { actor, workspace, amountCents, returnUrl }),
636 confirmAiCredit: (workspace, viewer, session) => call("confirm_ai_credit", { workspace, viewer, session }),
637 setAiReload: (actor, workspace, reload) => call("set_ai_reload", { actor, workspace, ...reload }),
638 setBudget: (actor, workspace, budget) => call("set_budget", { actor, workspace, ...budget }),
639 billingDetails: (workspace, viewer) => call("billing_details", { workspace, viewer }),
640 setBillingDetails: (actor, workspace, details) => call("set_billing_details", { actor, workspace, ...details }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0641 };
642}
643
644export function billingAdminClient(service: ServiceBinding): BillingAdminApi {
645 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
646 return {
647 accounts: (query) => call("admin_accounts", { query: query ?? null }),
648 account: (id) => call("admin_account", { id }),
649 setTerms: (id, terms, by) => call("admin_set_terms", { id, terms, by }),
650 setAllowances: (id, allowances, note, by) => call("admin_set_allowances", { id, allowances, note, by }),
651 createEnterprise: (name, workspaces, by) => call("admin_create_enterprise", { name, workspaces, by }),
652 attach: (workspace, account, by) => call("admin_attach", { workspace, account, by }),
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging653 credit: (workspace, amountMicros, note, by, options = { kind: "goodwill" }) =>
654 call("admin_credit", {
655 workspace,
656 amount_micros: amountMicros,
657 note,
658 by,
659 kind: options.kind,
660 expires_at: options.expiresAt ?? null,
661 refund_for: options.refundFor ?? null,
662 refund_day: options.refundDay ?? null,
663 }),
664 credits: (filter = {}) =>
665 call("admin_credits", {
666 workspace: filter.workspace ?? null,
667 kind: filter.kind ?? null,
668 month: filter.month ?? null,
669 by: filter.by ?? null,
670 }),
671 revokeCredit: (id, note, by) => call("admin_revoke_credit", { id, note, by }),
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's672 resetBilling: (workspace, confirm, note, by) => call("admin_reset_billing", { workspace, confirm, note, by }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0673 billingLink: (workspace, by) => call("admin_billing_link", { workspace, by }),
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard674 stripe: (fix = false, by) => call("admin_stripe", { fix, by: by ?? null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0675 enterpriseBilling: (id, email, by) => call("admin_enterprise_billing", { id, email, by }),
Merge Stripe Tax, the card fee on card payments, and one free workspace per person676 enterpriseAddress: (id, address, taxIdType, taxId, by) => call("admin_enterprise_address", { id, address, taxIdType, taxId, by }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0677 invoiceEnterprise: (id, by) => call("admin_invoice_enterprise", { id, by }),
678 accountsFor: (workspaces) => call("admin_accounts", { query: null, workspaces }),
679 signals: () => call("admin_signals", {}),
680 overview: () => call("admin_overview", {}),
681 sales: (workspace) => call("admin_sales", { workspace }),
682 setSales: (workspace, record, by) =>
683 call("admin_set_sales", {
684 workspace,
685 stage: record.stage,
686 owner: record.owner ?? null,
687 next_step: record.nextStep ?? null,
688 next_at: record.nextAt ?? null,
689 by,
690 }),
691 addNote: (workspace, text, by) => call("admin_add_note", { workspace, text, by }),
692 workspaceInvoices: (workspace) => call("admin_workspace_invoices", { workspace }),
693 allInvoices: (filter = {}) => call("admin_invoices", { status: filter.status ?? null, month: filter.month ?? null }),
694 audit: (filter = {}) =>
695 call("admin_audit", { by: filter.by ?? null, action: filter.action ?? null, before: filter.before ?? null }),
696 limitRequests: (status = "open") => call("admin_limit_requests", { status }),
697 decideLimitRequest: (id, decision, amountMicros, note, by) =>
698 call("admin_decide_limit_request", { id, decision, amount_micros: amountMicros, note, by }),
699 overages: () => call("admin_overages", {}),
700 goodwill: (workspace, amountMicros, reason, by, day = null) =>
701 call("admin_goodwill", { workspace, amount_micros: amountMicros, reason, by, day }),
702 velocity: () => call("admin_velocity", {}),
703 recordPayment: (workspace, amountMicros, reference, note, by) =>
704 call("admin_record_payment", { workspace, amount_micros: amountMicros, reference, note, by }),
705 costs: (days) => call("admin_costs", { days: days ?? null }),
706 costAlerts: () => call("admin_cost_alerts", {}),
707 spendCaps: () => call("admin_spend_caps", {}),
708 liftBreaker: (note, by) => call("admin_lift_breaker", { note, by }),
Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006)709 platformGuard: () => call("admin_platform_guard", {}),
710 setPause: (level, paused, note, by) => call("admin_set_pause", { level, paused, note, by }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0711 decideProposal: (id, decision, note, by) => call("admin_decide_proposal", { id, decision, note, by }),
712 setCostSettings: (settings, by) => call("admin_set_cost_settings", { settings, by }),
713 setCostMapping: (mapping, by) =>
714 call("admin_set_cost_mapping", {
715 product: mapping.product,
716 meter: mapping.meter,
717 bucket: mapping.bucket ?? "",
718 price_meter: mapping.priceMeter ?? null,
719 own_meter: mapping.ownMeter ?? null,
720 scale_to_own: mapping.scaleToOwn ?? false,
721 drift_percent: mapping.driftPercent ?? null,
722 note: mapping.note ?? "",
723 remove: mapping.remove ?? false,
724 by,
725 }),
726 runCosts: (by) => call("admin_run_costs", { by }),
Merge branch 'main' into actions-toolkit-oidc-artifacts727 models: () => call("admin_models", {}),
728 decideModel: (model, decision, details, reason, by) =>
729 call("admin_decide_model", {
730 model,
731 decision,
732 name: details.name ?? null,
733 tier_hint: details.tierHint ?? null,
734 prices: details.prices
735 ? {
736 input_micros: details.prices.inputMicros,
737 output_micros: details.prices.outputMicros,
738 cache_read_micros: details.prices.cacheReadMicros,
739 cache_write_micros: details.prices.cacheWriteMicros,
740 cache_write_1h_micros: details.prices.cacheWrite1hMicros,
741 threshold: details.prices.threshold,
742 over_input_micros: details.prices.overInputMicros,
743 over_output_micros: details.prices.overOutputMicros,
744 over_cache_read_micros: details.prices.overCacheReadMicros,
745 over_cache_write_micros: details.prices.overCacheWriteMicros,
746 over_cache_write_1h_micros: details.prices.overCacheWrite1hMicros,
747 }
748 : null,
749 reason,
750 by,
751 }),
752 setModelDefault: (purpose, value, reason, by) =>
753 call("admin_set_model_default", {
754 purpose,
755 model: value.model ?? null,
756 tier: value.tier ?? null,
757 effort: value.effort ?? null,
758 reason,
759 by,
760 }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0761 };
762}
763
764export function eventsClient(service: ServiceBinding): EventsApi {
765 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
766 return {
767 publish: (events) => call("publish", { events }),
768 list: (query) => call("list", query),
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.769 activityDigest: (args) => call("activity_digest", args),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0770 };
771}
772
773export function integrationsClient(service: ServiceBinding): IntegrationsApi {
774 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
775 return {
776 list: (workspace, viewer) => call("list", { workspace, viewer }),
777 connect: (actor, workspace, input) => call("connect", { actor, workspace, ...input }),
778 update: (actor, workspace, id, input) => call("update", { actor, workspace, id, ...input }),
779 disconnect: (actor, workspace, id) => call("disconnect", { actor, workspace, id }),
780 test: (actor, workspace, id) => call("test", { actor, workspace, id }),
781 deliveries: (workspace, viewer, id) => call("deliveries", { workspace, viewer, id }),
782 resolve: (workspace, viewer, reference) => call("resolve", { workspace, viewer, reference }),
783 references: (workspace, text, limit) => call("references", { workspace, text, limit }),
784 import: (actor, repo, reference, assign) => call("import", { actor, repo, reference, assign }),
Each agent has an Abilities tab: g1t's built-ins, always on within the asker's access; its computer, coming; each connected integration's actions one row each, read, import, comment or resolve, with a level for each, alone, alone when the person asked for it, ask first or never, and whose connection it runs on; and MCP servers an owner adds. Reading is alone, writing inside g1t follows today's choices, anything that leaves g1t asks first, and production deploys can't go above ask. The agents service enforces every level: ask first posts a card to allow or deny and parks a session until it's answered, a refusal names its rule in the transcript and the audit log, and a missing ability posts a request to owners. The agent abilities guide says how.785 comment: (actor, workspace, reference, text, link) => call("comment", { actor, workspace, reference, text, link }),
786 close: (actor, workspace, reference, text, link) => call("close", { actor, workspace, reference, text, link }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0787 links: (repo, number) => call("links", { repo, number }),
788 modelProvider: (workspace) => call("model_provider", { workspace }),
789 openModelSession: (run) => call("open_model_session", run),
790 modelUpstream: (token) => call("model_upstream", { token }),
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens791 gatewayUpstream: (workspace) => call("gateway_upstream", { workspace }),
AI Gateway: OpenAI's format, open models, and your own providers792 gatewayProviders: (workspace) => call("gateway_providers", { workspace }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0793 closeModelSessions: (tokenHashes) => call("close_model_sessions", { token_hashes: tokenHashes }),
Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006)794 capModelSessions: (tokenHashes, capMicros) => call("cap_model_sessions", { token_hashes: tokenHashes, cap_micros: capMicros }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0795 routes: (workspace, viewer) => call("routes", { workspace, viewer }),
796 setRoutes: (actor, workspace, routes) => call("set_routes", { actor, workspace, routes }),
797 };
798}
799
800export function webhooksClient(service: ServiceBinding): WebhooksApi {
801 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
802 return {
803 list: (viewer, owner) => call("list", { viewer, ...owner }),
804 create: (actor, owner, input) => call("create", { actor, ...owner, ...input }),
805 update: (actor, owner, id, input) => call("update", { actor, ...owner, id, ...input }),
806 delete: (actor, owner, id) => call("delete", { actor, ...owner, id }),
807 ping: (actor, owner, id) => call("ping", { actor, ...owner, id }),
808 deliveries: (viewer, owner, id) => call("deliveries", { viewer, ...owner, id }),
809 redeliver: (actor, owner, deliveryId) => call("redeliver", { actor, ...owner, deliveryId }),
810 };
811}
812
813export function actionsClient(service: ServiceBinding): ActionsApi {
814 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
815 return {
816 workflows: (repo, viewer) => call("workflows", { repo, viewer }),
817 runs: (repo, viewer, filter = {}) => call("runs", { repo, viewer, ...filter }),
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)818 run: (repo, viewer, id, attempt) => call("run", { repo, viewer, id, attempt: attempt ?? null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0819 logs: (repo, viewer, job, after = 0) => call("logs", { repo, viewer, job, after }),
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)820 summaries: (repo, viewer, id, attempt) => call("summaries", { repo, viewer, id, attempt: attempt ?? null }),
821 jobLogText: (repo, viewer, job) => call("job_log_text", { repo, viewer, job }),
822 runLogs: (repo, viewer, id, attempt) => call("run_logs", { repo, viewer, id, attempt: attempt ?? null }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0823 dispatch: (actor, repo, workflow, ref, inputs) => call("dispatch", { actor, repo, workflow, ref, inputs }),
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)824 cancel: (actor, repo, id, force = false) => call("cancel", { actor, repo, id, force }),
825 rerun: (actor, repo, id, failedOnly = false, options = {}) =>
826 call("rerun", { actor, repo, id, failed_only: failedOnly, job: options.job ?? null, debug: options.debug ?? false }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0827 setWorkflowEnabled: (actor, repo, workflow, enabled) =>
828 call("set_workflow_enabled", { actor, repo, workflow, enabled }),
829 settings: (actor, owner, kind) => call("settings", { actor, ...owner, kind }),
830 setSetting: (actor, owner, kind, name, value, options = {}) =>
831 call("set_setting", { actor, ...owner, kind, name, value, ...options }),
832 deleteSetting: (actor, owner, kind, name, id) => call("delete_setting", { actor, ...owner, kind, name, id }),
Merge branch 'worktree-agent-a3abfcce648e87dca'833 approveRun: (actor, repo, id) => call("approve_run", { actor, repo, id }),
834 pendingDeployments: (repo, viewer, id) => call("pending_deployments", { repo, viewer, id }),
835 reviewDeployments: (actor, repo, id, state, environments = [], comment) =>
836 call("review_deployments", { actor, repo, id, state, environments, comment: comment ?? null }),
837 actionsSettings: (repo, viewer) => call("actions_settings", { repo, viewer }),
838 setActionsSettings: (actor, repo, change) => call("set_actions_settings", { actor, repo, ...change }),
839 workspaceActionsSettings: (workspace, viewer) => call("workspace_actions_settings", { workspace, viewer }),
840 setWorkspaceActionsSettings: (actor, workspace, change) =>
841 call("set_workspace_actions_settings", { actor, workspace, ...change }),
Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's.842 workspaceManagedWorkflows: (workspace, viewer) => call("workspace_managed_workflows", { workspace, viewer }),
843 setWorkspaceManagedWorkflow: (actor, workspace, name, change, create = false) =>
844 call("set_workspace_managed_workflow", { actor, workspace, name, create, ...change }),
845 removeWorkspaceManagedWorkflow: (actor, workspace, name) =>
846 call("remove_workspace_managed_workflow", { actor, workspace, name }),
Merge branch 'worktree-agent-a3abfcce648e87dca'847 environments: (repo, viewer) => call("environments", { repo, viewer }),
848 setEnvironment: (actor, repo, name, change) => call("set_environment", { actor, repo, name, ...change }),
849 deleteEnvironment: (actor, repo, name) => call("delete_environment", { actor, repo, name }),
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2850 artifacts: (repo, viewer, filter = {}) => call("artifacts", { repo, viewer, ...filter }),
851 artifactDownload: (repo, viewer, by) => call("artifact_download", { repo, viewer, ...by }),
852 deleteArtifact: (actor, repo, id) => call("delete_artifact", { actor, repo, id }),
853 artifactRetention: (repo, viewer, days) => call("artifact_retention", { repo, viewer, days }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0854 };
855}
856
857
858/** Self-hosted runners, kept by the actions service. */
859export function runnersClient(service: ServiceBinding): RunnersApi {
860 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
861 return {
862 stuck: (viewer) => call("stuck_jobs", { viewer }),
The Runners page shows the machines a workspace's agents and workflow jobs run on, in Workspace under Compute: g1t's cloud beside your own runners, what each is running now with a link to it, what's waiting, this month's machine time and its cost (your own runners' free), where agent work and workflow jobs run, adding a runner, and groups; runner_activity in Actions says what runs where, work handed to your runners keeps its agent run, and the self-hosted runners guide says how.863 activity: (actor, workspace) => call("runner_activity", { actor, workspace }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0864 list: (actor, owner) => call("runners", { actor, ...owner }),
865 createToken: (actor, owner, group) => call("create_registration_token", { actor, ...owner, group }),
866 remove: (actor, owner, id) => call("remove_runner", { actor, ...owner, id }),
867 groups: (actor, workspace) => call("runner_groups", { actor, workspace }),
868 setGroup: (actor, workspace, group) => call("set_runner_group", { actor, workspace, ...group }),
869 deleteGroup: (actor, workspace, id) => call("delete_runner_group", { actor, workspace, id }),
870 settings: (actor, owner) => call("runner_settings", { actor, ...owner }),
871 setSettings: (actor, owner, change) => call("set_runner_settings", { actor, ...owner, ...change }),
Merge the desktop app's runner: it starts with the app for the signed-in person, sandboxed by default and running nothing where no sandbox is available yet, registers through the site, keeps itself up to date, and says everywhere what it is doing, why it is not, and how to fix it.872 reportDesktop: (actor, report) => call("report_desktop", { actor, ...report }),
873 desktops: (actor, workspace) => call("desktop_runners", { actor, workspace }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0874 };
875}
876
877export function deploymentsClient(service: ServiceBinding): DeploymentsApi {
878 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
879 return {
880 settings: (project, viewer) => call("settings", { project, viewer }),
881 updateSettings: (actor, project, changes) => call("update_settings", { actor, project, changes }),
882 list: (project, viewer) => call("list", { project, viewer }),
883 get: (project, id, viewer) => call("get", { project, id, viewer }),
884 redeploy: (actor, project, branch) => call("redeploy", { actor, project, branch }),
885 takeDown: (actor, project, branch) => call("take_down", { actor, project, branch }),
886 overview: (workspace, viewer) => call("overview", { workspace, viewer }),
887 usage: (workspace, viewer) => call("usage", { workspace, viewer }),
888 domains: (project, viewer) => call("domains", { project, viewer }),
889 addDomain: (actor, project, hostname, options = {}) =>
890 call("add_domain", { actor, project, hostname, twin: !!options.twin }),
891 removeDomain: (actor, project, id) => call("remove_domain", { actor, project, id }),
892 refreshDomain: (actor, project, id) => call("refresh_domain", { actor, project, id }),
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97893 repoDeployments: (repo, viewer, filter = {}) => call("list_deployments", { repo, viewer, ...filter }),
894 repoDeployment: (repo, id, viewer) => call("get_deployment", { repo, id, viewer }),
895 environments: (repo, viewer) => call("list_environments", { repo, viewer }),
896 createDeployment: (actor, repo, input) => call("create_deployment", { repo, actor, ...input }),
897 createDeploymentStatus: (actor, repo, id, input) => call("create_deployment_status", { repo, actor, id, ...input }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0898 };
899}
900
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member901/** Packages: the registries beside the code (services/packages). */
902export function packagesClient(service: ServiceBinding): PackagesApi {
903 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
904 return {
905 list: (workspace, viewer, filter = {}) =>
906 call("list_packages", {
907 workspace,
908 viewer,
909 ecosystem: filter.ecosystem ?? null,
910 repo_id: filter.repoId ?? null,
911 query: filter.query ?? null,
912 }),
913 get: (workspace, ecosystem, name, viewer) => call("get_package", { workspace, ecosystem, name, viewer }),
914 deleteVersion: (actor, workspace, ecosystem, name, version, surface) =>
915 call("delete_version", { actor, workspace, ecosystem, name, version, surface: surface ?? null }),
916 deletePackage: (actor, workspace, ecosystem, name, surface) =>
917 call("delete_package", { actor, workspace, ecosystem, name, surface: surface ?? null }),
918 set: (actor, workspace, ecosystem, name, change, surface) =>
919 call("set_package", {
920 actor,
921 workspace,
922 ecosystem,
923 name,
924 visibility: change.visibility ?? null,
925 link: change.link ?? null,
926 unlink: change.unlink ?? false,
Merge packages: roles, Actions access, source label, soft delete, API927 inherit_access: change.inheritAccess ?? null,
928 surface: surface ?? null,
929 }),
930 settings: (workspace, ecosystem, name, viewer) => call("package_settings", { workspace, ecosystem, name, viewer }),
931 deleted: (workspace, viewer) => call("deleted_packages", { workspace, viewer }),
932 restorePackage: (actor, workspace, ecosystem, name, surface) =>
933 call("restore_package", { actor, workspace, ecosystem, name, surface: surface ?? null }),
934 restoreVersion: (actor, workspace, ecosystem, name, version, surface) =>
935 call("restore_version", { actor, workspace, ecosystem, name, version, surface: surface ?? null }),
936 setAccess: (actor, workspace, ecosystem, name, who, role, surface) =>
937 call("set_package_access", {
938 actor,
939 workspace,
940 ecosystem,
941 name,
942 user: "user" in who ? who.user : null,
943 team: "team" in who ? who.team : null,
944 role,
945 surface: surface ?? null,
946 }),
947 removeAccess: (actor, workspace, ecosystem, name, who, surface) =>
948 call("remove_package_access", {
949 actor,
950 workspace,
951 ecosystem,
952 name,
953 user: "user" in who ? who.user : null,
954 team: "team" in who ? who.team : null,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member955 surface: surface ?? null,
956 }),
Merge packages: roles, Actions access, source label, soft delete, API957 setActionsAccess: (actor, workspace, ecosystem, name, repo, role, surface) =>
958 call("set_actions_access", { actor, workspace, ecosystem, name, repo, role, surface: surface ?? null }),
959 removeActionsAccess: (actor, workspace, ecosystem, name, repo, surface) =>
960 call("remove_actions_access", { actor, workspace, ecosystem, name, repo, surface: surface ?? null }),
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member961 storage: (workspace) => call("storage", { workspace }),
962 storageAll: () => call("storage_all", {}),
Composer from the workspace's own repositories, and go get from g1t.sh963 syncComposer: (repoId) => call("sync_composer", { repo_id: repoId }),
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member964 };
965}
966
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0967export function projectsClient(service: ServiceBinding): ProjectsApi {
968 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
969 return {
970 list: (workspace, viewer) => call("list", { workspace, viewer }),
971 get: (workspace, slug, viewer) => call("get", { workspace, slug, viewer }),
972 byRepo: (repoId) => call("by_repo", { repoId }),
973 create: (actor, workspace, input) => call("create", { actor, workspace, input }),
974 update: (actor, workspace, slug, changes) => call("update", { actor, workspace, slug, changes }),
Merge branch 'worktree-agent-a5b0d9e2733e9e382'975 setProductionImage: (actor, workspace, slug, change) => call("set_production_image", { actor, workspace, slug, change }),
976 externalProductions: () => call("external_productions", {}),
A project is an app or a library: libraries show their package and how to ship a release, not production977 deploymentsChanged: (projectId, enabled) => call("deployments_changed", { projectId, enabled }),
Projects: pinned and recent projects, per person per workspace978 shortcuts: (workspace, viewer) => call("shortcuts", { workspace, viewer }),
979 pin: (actor, workspace, slug, position) => call("pin", { actor, workspace, slug, position: position ?? null }),
980 unpin: (actor, workspace, slug) => call("unpin", { actor, workspace, slug }),
981 reorderPins: (actor, workspace, slugs) => call("reorder_pins", { actor, workspace, slugs }),
982 visited: (actor, projectId) => call("visited", { actor, projectId }),
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97983 publicLinks: (repos) => call("public_links", { repos }),
Cleanup: clippy is quiet outside billing, the README says g1t, and http-cache-semantics is 4.3.0984 };
985}
Every agent can have its own computer. A session that needs one wakes it: a home of its own on g1t cloud, one per agent and never shared, where it runs commands, reads and writes files and keeps what it made, with each session working in its own folder under a shared home; after ten idle minutes it sleeps, its home kept as a snapshot and restored when it wakes, and Reset wipes the home while memory and artifacts stay. Its shell and files are abilities with the usual choices, Alone, Alone when asked, Ask first or Never, offered only inside sessions and never to a chat reply; every command shows on the session with its output, and the agent's new Computer tab shows the state, the disk used of the five gigabytes included, the recent commands, and Wake, Put to sleep and Reset. Machine time counts only while it is awake, on the sandbox lines of the ledger that name the agent and who asked, held to the same spend caps as the session; the disk itself costs nothing in this version. The runner gained a long-lived supervisor that answers the computer's requests inside the container, and the runner service a computer per agent that keeps its snapshot in the agent homes bucket when one is attached, and says so when none is. The REST API and the agent tool can read a computer, wake it, put it to sleep and reset it. The agents, abilities, sessions, runners, billing and deploy guides say how it works and what an operator sets up; pinning a computer to your own runner, its browser and take-over come next.986
987/**
988 * An agent's own computer, on the runner (services/runner `AgentComputer`):
989 * what the agents service calls for a session's `run_command` and file
990 * tools, and for the Computer tab. Arguments and answers are snake_case.
991 */
992export function runnerComputerClient(service: ServiceBinding): RunnerComputerApi {
993 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
994 return {
995 computerStatus: (agentId) => call("computer_status", { agent_id: agentId }),
996 computerWake: (args) => call("computer_wake", args),
997 computerExec: (args) => call("computer_exec", args),
998 computerReadFile: (args) => call("computer_read_file", args),
999 computerWriteFile: (args) => call("computer_write_file", args),
1000 computerSleep: (agentId) => call("computer_sleep", { agent_id: agentId }),
1001 computerReset: (agentId) => call("computer_reset", { agent_id: agentId }),
1002 computerForget: (agentId) => call("computer_forget", { agent_id: agentId }),
An archived agent can be found, brought back, or deleted for good. The Agents page ends with Archived, folded, where owners see every archived agent and members their own personal ones, each with when and by whom it was archived and what deleting it would take; Restore brings it back, under a new handle when a live agent has taken its old one, and Delete permanently asks for the handle to be typed and then removes its sessions, replies, memories, routines, versions, drafts, skills and its computer's home, leaving its messages in chat under its saved name, the workspace's spend totals and the audit log. In Chat an archived agent is deactivated the way people expect: never offered as someone to message or mention, never woken, a conversation with it kept in the list, dimmed and marked Archived, open to read with a note in place of the composer and a way to restore it for owners; after deletion the conversation still reads, its messages marked as a deleted agent's. The agents, chat and agent budgets guides say so.1003 computerKeep: (agentId) => call("computer_keep", { agent_id: agentId }),
1004 computerErase: (agentId) => call("computer_erase", { agent_id: agentId }),
Every agent can have its own computer. A session that needs one wakes it: a home of its own on g1t cloud, one per agent and never shared, where it runs commands, reads and writes files and keeps what it made, with each session working in its own folder under a shared home; after ten idle minutes it sleeps, its home kept as a snapshot and restored when it wakes, and Reset wipes the home while memory and artifacts stay. Its shell and files are abilities with the usual choices, Alone, Alone when asked, Ask first or Never, offered only inside sessions and never to a chat reply; every command shows on the session with its output, and the agent's new Computer tab shows the state, the disk used of the five gigabytes included, the recent commands, and Wake, Put to sleep and Reset. Machine time counts only while it is awake, on the sandbox lines of the ledger that name the agent and who asked, held to the same spend caps as the session; the disk itself costs nothing in this version. The runner gained a long-lived supervisor that answers the computer's requests inside the container, and the runner service a computer per agent that keeps its snapshot in the agent homes bucket when one is attached, and says so when none is. The REST API and the agent tool can read a computer, wake it, put it to sleep and reset it. The agents, abilities, sessions, runners, billing and deploy guides say how it works and what an operator sets up; pinning a computer to your own runner, its browser and take-over come next.1005 computerCommands: (agentId, sessionId) => call("computer_commands", { agent_id: agentId, session_id: sessionId ?? null }),
1006 };
1007}

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