Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
371 linesCodeBlameRaw
1import type { Provider } from "./integrations";
2
3/**
4 * The connector catalog: every tool g1t connects to, or will, in one list.
5 * The workspace's Integrations page and your own Integrations settings are
6 * both drawn from it, so a new connector is added here, once.
7 *
8 * A connector is `available` when g1t can set it up today (its `href` is
9 * where), and `soon` while it is planned. `scopes` says who connects it:
10 *
11 * - `workspace`: an owner connects it once, for everyone in the workspace.
12 * - `personal`: each person connects their own account, and it follows them
13 * into every workspace they belong to (a calendar, a personal sign-in).
14 *
15 * A connector with both scopes can say something different for each, in
16 * `personal`: its own description, status, capabilities or setup page.
17 * `connectorView` resolves that into what one context shows.
18 *
19 * Paths in `href` are g1t's own pages. `:workspace` stands for the
20 * workspace's slug.
21 */
22
23export type ConnectorScope = "workspace" | "personal";
24export type ConnectorStatus = "available" | "soon";
25
26export type ConnectorCategory =
27 | "code"
28 | "issues"
29 | "chat"
30 | "calendar"
31 | "docs"
32 | "monitoring"
33 | "cloud"
34 | "ai"
35 | "data"
36 | "crm"
37 | "design"
38 | "security"
39 | "files";
40
41/** What a connector lets g1t do, as the small tags on its card. */
42export type ConnectorCapability =
43 | "Agents can read"
44 | "Agents can act"
45 | "Opens issues"
46 | "Writes back"
47 | "Imports repositories"
48 | "Signs you in"
49 | "Sends events"
50 | "Alerts into chat"
51 | "Sets your status"
52 | "Deploys"
53 | "Syncs people";
54
55export type Connector = {
56 /** Stable and unique: used in links and requests. */
57 id: string;
58 name: string;
59 category: ConnectorCategory;
60 /** One plain line of what it does in g1t, for a workspace (or for you, when it is only personal). */
61 description: string;
62 scopes: ConnectorScope[];
63 status: ConnectorStatus;
64 /** Where an available connector is set up, for each scope it has. */
65 href?: Partial<Record<ConnectorScope, string>>;
66 capabilities?: ConnectorCapability[];
67 /** The integration provider behind it, whose connections show it as connected. */
68 provider?: Provider;
69 /** What differs when you connect it for yourself. */
70 personal?: { description?: string; status?: ConnectorStatus; capabilities?: ConnectorCapability[] };
71 /** More words search should find it by. */
72 keywords?: string[];
73};
74
75/** A connector as one context (a workspace, or you) shows it. */
76export type ConnectorView = {
77 id: string;
78 name: string;
79 category: ConnectorCategory;
80 description: string;
81 status: ConnectorStatus;
82 href: string | null;
83 capabilities: ConnectorCapability[];
84 provider: Provider | null;
85 keywords: string[];
86 /** The other scope it can also be connected in. */
87 alsoIn: ConnectorScope | null;
88};
89
90/** The categories, in the order the directory lists them. */
91export const CONNECTOR_CATEGORIES: { id: ConnectorCategory; title: string }[] = [
92 { id: "code", title: "Code & CI" },
93 { id: "issues", title: "Issues & projects" },
94 { id: "chat", title: "Chat & meetings" },
95 { id: "calendar", title: "Calendar & email" },
96 { id: "docs", title: "Docs & knowledge" },
97 { id: "monitoring", title: "Monitoring & incidents" },
98 { id: "cloud", title: "Cloud & deploy" },
99 { id: "ai", title: "AI & agents" },
100 { id: "data", title: "Data & analytics" },
101 { id: "crm", title: "CRM & support" },
102 { id: "design", title: "Design" },
103 { id: "security", title: "Security & identity" },
104 { id: "files", title: "Files & storage" },
105];
106
107const W: ConnectorScope[] = ["workspace"];
108const P: ConnectorScope[] = ["personal"];
109const BOTH: ConnectorScope[] = ["workspace", "personal"];
110
111/** A planned connector. */
112function soon(
113 id: string,
114 name: string,
115 category: ConnectorCategory,
116 scopes: ConnectorScope[],
117 description: string,
118 capabilities: ConnectorCapability[] = [],
119 personal?: Connector["personal"],
120): Connector {
121 return { id, name, category, description, scopes, status: "soon", capabilities, ...(personal ? { personal } : {}) };
122}
123
124export const CONNECTORS: Connector[] = [
125 // Code & CI -------------------------------------------------------------
126 {
127 id: "github",
128 name: "GitHub",
129 category: "code",
130 description: "Import repositories, with their branches, tags and issues, through g1t's GitHub App.",
131 scopes: BOTH,
132 status: "available",
133 href: { workspace: "/new/github?workspace=:workspace", personal: "/settings/github" },
134 capabilities: ["Imports repositories"],
135 personal: {
136 description: "Sign in with your GitHub account, and reach the repositories you can see there to import them.",
137 capabilities: ["Signs you in", "Imports repositories"],
138 },
139 keywords: ["git", "import", "sign in"],
140 },
141 {
142 id: "webhooks",
143 name: "Webhooks",
144 category: "code",
145 description: "Every repository's events, sent to your own addresses as they happen, signed.",
146 scopes: W,
147 status: "available",
148 href: { workspace: "/:workspace/-/webhooks" },
149 capabilities: ["Sends events"],
150 keywords: ["http", "events", "outgoing"],
151 },
152 soon("gitlab", "GitLab", "code", BOTH, "Import projects, with their branches, tags and issues.", ["Imports repositories"], {
153 description: "Sign in with GitLab, and reach your own projects to import them.",
154 capabilities: ["Signs you in", "Imports repositories"],
155 }),
156 soon("bitbucket", "Bitbucket", "code", BOTH, "Import repositories, with their branches and tags.", ["Imports repositories"], {
157 description: "Reach your own Bitbucket repositories to import them.",
158 capabilities: ["Imports repositories"],
159 }),
160 soon("circleci", "CircleCI", "code", W, "Pipeline results as checks on pull requests, which agents read when a build fails.", ["Agents can read"]),
161 soon("buildkite", "Buildkite", "code", W, "Build results as checks on pull requests, with the failing step for agents to fix.", ["Agents can read"]),
162 soon("docker-hub", "Docker Hub", "code", W, "Push images your workflows build, and pull private base images.", ["Deploys"]),
163
164 // Issues & projects -----------------------------------------------------
165 {
166 id: "linear",
167 name: "Linear",
168 category: "issues",
169 description: "Agents read ENG-42 when work mentions it; import issues, and they hear back when the work lands.",
170 scopes: BOTH,
171 status: "available",
172 href: { workspace: "/:workspace/-/integrations/trackers?add=linear#add" },
173 capabilities: ["Agents can read", "Writes back"],
174 provider: "linear",
175 personal: {
176 description: "Issues assigned to you in Linear, in your g1t inbox beside everything else.",
177 status: "soon",
178 capabilities: ["Agents can read"],
179 },
180 keywords: ["tracker", "tickets"],
181 },
182 {
183 id: "jira",
184 name: "Jira",
185 category: "issues",
186 description: "Agents read TECH-1234 when work mentions it; import tickets, and they hear back when the work lands.",
187 scopes: W,
188 status: "available",
189 href: { workspace: "/:workspace/-/integrations/trackers?add=jira#add" },
190 capabilities: ["Agents can read", "Writes back"],
191 provider: "jira",
192 keywords: ["atlassian", "tracker", "tickets"],
193 },
194 soon("shortcut", "Shortcut", "issues", W, "Stories agents read when work mentions them, updated when the work lands.", ["Agents can read", "Writes back"]),
195 soon("clickup", "ClickUp", "issues", W, "Tasks agents can read and import, kept in step with their pull requests.", ["Agents can read", "Writes back"]),
196 soon("trello", "Trello", "issues", W, "Cards become issues, and move along their board as the work does.", ["Opens issues", "Writes back"]),
197
198 // Chat & meetings -------------------------------------------------------
199 soon("slack", "Slack", "chat", BOTH, "Alerts and updates in the channels your team already reads.", ["Alerts into chat"], {
200 description: "Your status in g1t follows the one you set in Slack, and the other way round.",
201 capabilities: ["Sets your status"],
202 }),
203 soon("microsoft-teams", "Microsoft Teams", "chat", BOTH, "Alerts and updates posted to Teams channels.", ["Alerts into chat"], {
204 description: "Your status in g1t follows your Teams presence.",
205 capabilities: ["Sets your status"],
206 }),
207 soon("discord", "Discord", "chat", W, "Releases, alerts and updates posted to a Discord server.", ["Alerts into chat"]),
208 soon("zoom", "Zoom", "chat", BOTH, "Meeting notes and recordings agents can read when work refers to them.", ["Agents can read"], {
209 description: "Sets your status to On a call while you are in a Zoom meeting.",
210 capabilities: ["Sets your status"],
211 }),
212 soon("google-meet", "Google Meet", "chat", P, "Sets your status to On a call while you are in a meeting, and starts a call from any channel.", ["Sets your status"]),
213
214 // Calendar & email ------------------------------------------------------
215 soon("google-calendar", "Google Calendar", "calendar", P, "Sets your status to In a meeting while you are in one.", ["Sets your status"]),
216 soon("outlook-calendar", "Outlook Calendar", "calendar", P, "Sets your status to In a meeting while you are in one.", ["Sets your status"]),
217 soon("gmail", "Gmail", "calendar", P, "Turn an email into an issue, from your own inbox.", ["Opens issues"]),
218 soon("outlook-mail", "Outlook Mail", "calendar", P, "Turn an email into an issue, from your own inbox.", ["Opens issues"]),
219
220 // Docs & knowledge ------------------------------------------------------
221 soon("google-docs", "Google Docs", "docs", BOTH, "Agents read the specs and plans linked from issues and chat.", ["Agents can read"], {
222 description: "Docs you share in chat open for agents as well as people.",
223 capabilities: ["Agents can read"],
224 }),
225 soon("coda", "Coda", "docs", W, "Agents read the docs and tables linked from issues and chat.", ["Agents can read"]),
226
227 // Monitoring & incidents ------------------------------------------------
228 {
229 id: "sentry",
230 name: "Sentry",
231 category: "monitoring",
232 description: "New errors open issues with the stack trace, and resolve in Sentry when the fix merges.",
233 scopes: W,
234 status: "available",
235 href: { workspace: "/:workspace/-/integrations/alerts?add=sentry#add" },
236 capabilities: ["Opens issues", "Agents can read", "Writes back"],
237 provider: "sentry",
238 keywords: ["errors", "alerts", "exceptions"],
239 },
240 {
241 id: "datadog",
242 name: "Datadog",
243 category: "monitoring",
244 description: "Monitors that trigger open issues, and recoveries are noted on them.",
245 scopes: W,
246 status: "available",
247 href: { workspace: "/:workspace/-/integrations/alerts?add=datadog#add" },
248 capabilities: ["Opens issues"],
249 provider: "datadog",
250 keywords: ["monitors", "alerts", "apm"],
251 },
252 {
253 id: "alerts-webhook",
254 name: "Alerts webhook",
255 category: "monitoring",
256 description: "Anything that can send signed JSON opens issues: your own scripts, or any monitoring tool.",
257 scopes: W,
258 status: "available",
259 href: { workspace: "/:workspace/-/integrations/alerts?add=webhook#add" },
260 capabilities: ["Opens issues"],
261 provider: "webhook",
262 keywords: ["incoming", "http", "alerts", "pagerduty", "grafana"],
263 },
264 soon("pagerduty", "PagerDuty", "monitoring", BOTH, "Incidents open issues, and resolve when the fix lands.", ["Opens issues", "Writes back"], {
265 description: "Sets your status to On call while you are on call.",
266 capabilities: ["Sets your status"],
267 }),
268 soon("opsgenie", "Opsgenie", "monitoring", W, "Alerts open issues, and close when the fix lands.", ["Opens issues", "Writes back"]),
269 soon("incident-io", "incident.io", "monitoring", W, "Incidents get a channel in g1t, with what changed alongside.", ["Opens issues", "Alerts into chat"]),
270 soon("grafana", "Grafana", "monitoring", W, "Alert rules open issues, and agents read the dashboards they link to.", ["Opens issues", "Agents can read"]),
271 soon("new-relic", "New Relic", "monitoring", W, "Alerts open issues, with the traces agents need to find the cause.", ["Opens issues", "Agents can read"]),
272 soon("honeycomb", "Honeycomb", "monitoring", W, "Triggers open issues, and agents query traces while they work.", ["Opens issues", "Agents can read"]),
273 soon("better-stack", "Better Stack", "monitoring", W, "Uptime incidents and log alerts open issues.", ["Opens issues"]),
274
275 // Cloud & deploy --------------------------------------------------------
276 soon("aws", "Amazon Web Services", "cloud", W, "Workflows and deployments reach AWS with short-lived credentials, no stored keys.", ["Deploys"]),
277 soon("google-cloud", "Google Cloud", "cloud", W, "Workflows and deployments reach Google Cloud with short-lived credentials.", ["Deploys"]),
278 soon("azure", "Microsoft Azure", "cloud", W, "Workflows and deployments reach Azure with short-lived credentials.", ["Deploys"]),
279 soon("netlify", "Netlify", "cloud", W, "Deploy previews as checks on pull requests.", ["Deploys", "Agents can read"]),
280 soon("fly-io", "Fly.io", "cloud", W, "Deploy apps from workflows, and roll back from the deployment's page.", ["Deploys"]),
281 soon("kubernetes", "Kubernetes", "cloud", W, "Roll out to your own clusters from workflows, with each rollout's status on g1t.", ["Deploys"]),
282
283 // AI & agents. AI providers are not connectors: they are each workspace's
284 // own AI settings, at /:workspace/-/ai.
285 {
286 id: "mcp",
287 name: "MCP clients",
288 category: "ai",
289 description: "Your own agent, connected to g1t's MCP server, works in g1t as you.",
290 scopes: P,
291 status: "available",
292 href: { personal: "/settings/applications" },
293 capabilities: ["Agents can act"],
294 keywords: ["model context protocol", "agent", "applications", "oauth"],
295 },
296
297 // Data & analytics ------------------------------------------------------
298 soon("postgresql", "PostgreSQL", "data", W, "Agents read your schema, and run read-only queries while they investigate.", ["Agents can read"]),
299 soon("snowflake", "Snowflake", "data", W, "Agents answer questions from your warehouse with read-only queries.", ["Agents can read"]),
300 soon("bigquery", "BigQuery", "data", W, "Agents answer questions from your datasets with read-only queries.", ["Agents can read"]),
301 soon("amplitude", "Amplitude", "data", W, "Agents read the charts that work refers to.", ["Agents can read"]),
302 soon("segment", "Segment", "data", W, "Agents read your tracking plan, and check new events against it.", ["Agents can read"]),
303
304 // CRM & support ---------------------------------------------------------
305 soon("zendesk", "Zendesk", "crm", W, "Turn a ticket into an issue, and tell the customer when the fix ships.", ["Opens issues", "Writes back"]),
306 soon("salesforce", "Salesforce", "crm", W, "Agents read the account and case behind a request.", ["Agents can read"]),
307
308 // Design ----------------------------------------------------------------
309 soon("miro", "Miro", "design", W, "Agents read the boards linked from issues and chat.", ["Agents can read"]),
310 soon("storybook", "Storybook", "design", W, "Each pull request's stories as a check, with what changed.", ["Agents can read"]),
311
312 // Security & identity ---------------------------------------------------
313 soon("okta", "Okta", "security", W, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"]),
314 soon("entra-id", "Microsoft Entra ID", "security", W, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"]),
315 soon("google-workspace", "Google Workspace", "security", BOTH, "Single sign-on, and people added and removed with your directory.", ["Signs you in", "Syncs people"], {
316 description: "Sign in to g1t with your Google account.",
317 capabilities: ["Signs you in"],
318 }),
319 soon("1password", "1Password", "security", W, "Secrets from a vault, read by workflows and deployments when they run.", ["Deploys"]),
320 soon("snyk", "Snyk", "security", W, "Findings open issues, and an agent opens the fix.", ["Opens issues"]),
321
322 // Files & storage -------------------------------------------------------
323 soon("google-drive", "Google Drive", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
324 description: "Attach files from your Drive in chat, without downloading them first.",
325 capabilities: ["Agents can read"],
326 }),
327 soon("dropbox", "Dropbox", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
328 description: "Attach files from your Dropbox in chat.",
329 capabilities: ["Agents can read"],
330 }),
331 soon("onedrive", "OneDrive and SharePoint", "files", BOTH, "Agents read the files linked from issues and chat.", ["Agents can read"], {
332 description: "Attach files from your OneDrive in chat.",
333 capabilities: ["Agents can read"],
334 }),
335 soon("box", "Box", "files", W, "Agents read the files linked from issues and chat.", ["Agents can read"]),
336];
337
338/** The connector by its id. */
339export function connectorById(id: string): Connector | undefined {
340 return CONNECTORS.find((connector) => connector.id === id);
341}
342
343/** A connector as `scope` shows it, or null when it cannot be connected there. */
344export function connectorView(connector: Connector, scope: ConnectorScope): ConnectorView | null {
345 if (!connector.scopes.includes(scope)) return null;
346 const own = scope === "personal" ? connector.personal : undefined;
347 const status = own?.status ?? connector.status;
348 const other: ConnectorScope = scope === "workspace" ? "personal" : "workspace";
349 return {
350 id: connector.id,
351 name: connector.name,
352 category: connector.category,
353 description: own?.description ?? connector.description,
354 status,
355 href: status === "available" ? (connector.href?.[scope] ?? null) : null,
356 capabilities: own?.capabilities ?? connector.capabilities ?? [],
357 provider: connector.provider ?? null,
358 keywords: connector.keywords ?? [],
359 alsoIn: connector.scopes.includes(other) ? other : null,
360 };
361}
362
363/** Every connector `scope` can show, in catalog order. */
364export function connectorsFor(scope: ConnectorScope): ConnectorView[] {
365 return CONNECTORS.map((connector) => connectorView(connector, scope)).filter((view): view is ConnectorView => view != null);
366}
367
368/** A setup path with its `:workspace` filled in. */
369export function connectorPath(path: string, workspace: string): string {
370 return path.replace(/:workspace\b/g, encodeURIComponent(workspace));
371}