Skip to content

Compare changes

Choose two branches to see what one has that the other does not, then open a pull request for it.

Open a pull request

1 commit

9 files+426−1810/9 viewed
+7−1
99 title: 'g1t docs',
1010 description: 'Guides and reference for g1t, the git forge for teams of agents.',
1111 components: {
12+ Header: './src/components/Header.astro',
13+ PageTitle: './src/components/PageTitle.astro',
1214 SiteTitle: './src/components/SiteTitle.astro',
1315 SocialIcons: './src/components/SocialIcons.astro',
1416 },
17+ // Each tab under the header shows its own part of the sidebar.
18+ routeMiddleware: './src/route-data.ts',
1519 expressiveCode: {
1620 themes: ['github-dark-default'],
21+ // Plain panels with a copy button, without window chrome.
22+ defaultProps: { frame: 'none' },
1723 styleOverrides: {
1824 borderRadius: '0.75rem',
1925 borderColor: 'var(--g1t-line)',
102108 label: 'Reference',
103109 items: [
104110 { label: 'API overview', slug: 'reference/api' },
105− { label: 'API reference', link: '/api/reference/', attrs: { target: '_self' } },
111+ { label: 'API explorer', link: '/api/reference/', attrs: { target: '_self' } },
106112 { label: 'MCP tools', slug: 'reference/mcp' },
107113 { label: 'OpenAPI document', link: 'https://api.g1t.sh/openapi.json' },
108114 { label: 'llms.txt', link: 'https://g1t.sh/llms.txt' },
+65−0
1+---
2+// Starlight's header, with the tabs that divide the docs beneath it.
3+import Default from '@astrojs/starlight/components/Header.astro';
4+
5+import { TABS, tabFor } from '../tabs';
6+
7+const current = tabFor(Astro.locals.starlightRoute.id);
8+---
9+
10+<div class="g1t-header">
11+ <div class="g1t-header-top"><Default /></div>
12+ <nav class="g1t-tabs" aria-label="Sections">
13+ {
14+ TABS.map((tab) => (
15+ <a href={tab.href} aria-current={tab === current ? 'page' : undefined}>
16+ {tab.label}
17+ </a>
18+ ))
19+ }
20+ </nav>
21+</div>
22+
23+<style>
24+ .g1t-header {
25+ display: flex;
26+ flex-direction: column;
27+ height: 100%;
28+ }
29+ .g1t-header-top {
30+ height: 3.5rem;
31+ padding: 0 var(--sl-nav-pad-x);
32+ }
33+ /* On phones the menu button sits at the top row's end: leave it room. */
34+ @media (max-width: 49.99rem) {
35+ :global([data-has-sidebar]) .g1t-header-top {
36+ padding-inline-end: calc(var(--sl-nav-pad-x) + var(--sl-menu-button-size) + var(--sl-nav-gap));
37+ }
38+ }
39+ .g1t-tabs {
40+ display: flex;
41+ gap: 1.5rem;
42+ height: 2.75rem;
43+ padding: 0 var(--sl-nav-pad-x);
44+ overflow-x: auto;
45+ scrollbar-width: none;
46+ }
47+ .g1t-tabs a {
48+ display: flex;
49+ align-items: center;
50+ border-bottom: 1.5px solid transparent;
51+ font-size: 0.875rem;
52+ font-weight: 500;
53+ white-space: nowrap;
54+ color: var(--g1t-muted);
55+ text-decoration: none;
56+ transition: color 0.15s;
57+ }
58+ .g1t-tabs a:hover {
59+ color: var(--g1t-fg);
60+ }
61+ .g1t-tabs a[aria-current='page'] {
62+ border-color: var(--g1t-fg);
63+ color: var(--g1t-fg);
64+ }
65+</style>
+180−0
1+---
2+// A page's title, what it is about beneath it, and a way to take the page
3+// to an AI assistant: copied as Markdown, read as Markdown, or opened in
4+// Claude or ChatGPT.
5+const { entry, id } = Astro.locals.starlightRoute;
6+const { title, description } = entry.data;
7+const markdown = `/${id === '' || id === 'index' ? 'index' : id}.md`;
8+const absolute = new URL(markdown, Astro.site).href;
9+const ask = encodeURIComponent(`Read ${absolute} so I can ask questions about it.`);
10+---
11+
12+<div class="g1t-page-title">
13+ <div class="g1t-page-title-row">
14+ <h1 id="_top">{title}</h1>
15+ <div class="g1t-copy">
16+ <button type="button" class="g1t-copy-main" data-markdown={markdown}>
17+ <svg viewBox="0 0 16 16" aria-hidden="true">
18+ <rect x="5" y="5" width="9" height="9" rx="1.5"></rect>
19+ <path d="M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5"></path>
20+ </svg>
21+ <span>Copy page</span>
22+ </button>
23+ <details class="g1t-copy-more">
24+ <summary aria-label="More ways to use this page">
25+ <svg viewBox="0 0 16 16" aria-hidden="true"><path d="m4 6 4 4 4-4"></path></svg>
26+ </summary>
27+ <div class="g1t-copy-menu">
28+ <a href={markdown} target="_blank" rel="noopener">
29+ <strong>View as Markdown</strong>
30+ <span>This page as plain text</span>
31+ </a>
32+ <a href={`https://claude.ai/new?q=${ask}`} target="_blank" rel="noopener">
33+ <strong>Open in Claude</strong>
34+ <span>Ask questions about this page</span>
35+ </a>
36+ <a href={`https://chatgpt.com/?hints=search&q=${ask}`} target="_blank" rel="noopener">
37+ <strong>Open in ChatGPT</strong>
38+ <span>Ask questions about this page</span>
39+ </a>
40+ </div>
41+ </details>
42+ </div>
43+ </div>
44+ {description && <p class="g1t-description">{description}</p>}
45+</div>
46+
47+<script>
48+ document.querySelectorAll<HTMLButtonElement>('.g1t-copy-main').forEach((button) => {
49+ button.addEventListener('click', async () => {
50+ const label = button.querySelector('span')!;
51+ try {
52+ const text = await (await fetch(button.dataset.markdown!)).text();
53+ await navigator.clipboard.writeText(text);
54+ label.textContent = 'Copied';
55+ } catch {
56+ label.textContent = 'Could not copy';
57+ }
58+ setTimeout(() => (label.textContent = 'Copy page'), 1600);
59+ });
60+ });
61+ // A menu closes when you click elsewhere.
62+ document.addEventListener('click', (event) => {
63+ document.querySelectorAll<HTMLDetailsElement>('.g1t-copy-more[open]').forEach((menu) => {
64+ if (!menu.contains(event.target as Node)) menu.open = false;
65+ });
66+ });
67+</script>
68+
69+<style>
70+ .g1t-page-title {
71+ margin-top: 0.75rem;
72+ }
73+ .g1t-page-title-row {
74+ display: flex;
75+ align-items: flex-start;
76+ justify-content: space-between;
77+ gap: 1.5rem;
78+ }
79+ h1 {
80+ margin: 0;
81+ font-size: 2rem;
82+ font-weight: 600;
83+ letter-spacing: -0.025em;
84+ line-height: 1.2;
85+ color: var(--g1t-fg);
86+ }
87+ .g1t-description {
88+ margin-top: 0.6rem;
89+ max-width: 42rem;
90+ font-size: 1.125rem;
91+ line-height: 1.55;
92+ color: var(--g1t-muted);
93+ }
94+ .g1t-copy {
95+ position: relative;
96+ display: flex;
97+ flex-shrink: 0;
98+ margin-top: 0.35rem;
99+ border-radius: 0.5rem;
100+ box-shadow: inset 0 0 0 1px var(--g1t-line);
101+ }
102+ .g1t-copy svg {
103+ width: 0.9rem;
104+ height: 0.9rem;
105+ fill: none;
106+ stroke: currentColor;
107+ stroke-width: 1.3;
108+ stroke-linecap: round;
109+ stroke-linejoin: round;
110+ }
111+ .g1t-copy-main,
112+ .g1t-copy-more summary {
113+ display: flex;
114+ align-items: center;
115+ gap: 0.4rem;
116+ border: 0;
117+ background: transparent;
118+ padding: 0.3rem 0.6rem;
119+ font: inherit;
120+ font-size: 0.8125rem;
121+ color: var(--g1t-muted);
122+ cursor: pointer;
123+ transition: color 0.15s, background 0.15s;
124+ }
125+ .g1t-copy-main {
126+ border-radius: 0.5rem 0 0 0.5rem;
127+ }
128+ .g1t-copy-more summary {
129+ list-style: none;
130+ border-left: 1px solid var(--g1t-line);
131+ border-radius: 0 0.5rem 0.5rem 0;
132+ padding-inline: 0.45rem;
133+ }
134+ .g1t-copy-more summary::-webkit-details-marker {
135+ display: none;
136+ }
137+ .g1t-copy-main:hover,
138+ .g1t-copy-more summary:hover {
139+ background: var(--g1t-surface);
140+ color: var(--g1t-fg);
141+ }
142+ .g1t-copy-menu {
143+ position: absolute;
144+ top: calc(100% + 0.4rem);
145+ right: 0;
146+ z-index: 10;
147+ width: 15rem;
148+ border-radius: 0.75rem;
149+ padding: 0.35rem;
150+ background: var(--g1t-raised);
151+ box-shadow:
152+ inset 0 0 0 1px var(--g1t-line-strong),
153+ 0 12px 32px rgb(0 0 0 / 0.45);
154+ }
155+ .g1t-copy-menu a {
156+ display: block;
157+ border-radius: 0.5rem;
158+ padding: 0.45rem 0.6rem;
159+ text-decoration: none;
160+ }
161+ .g1t-copy-menu a:hover {
162+ background: var(--g1t-surface);
163+ }
164+ .g1t-copy-menu strong {
165+ display: block;
166+ font-size: 0.8125rem;
167+ font-weight: 500;
168+ color: var(--g1t-fg);
169+ }
170+ .g1t-copy-menu span {
171+ display: block;
172+ font-size: 0.75rem;
173+ color: var(--g1t-faint);
174+ }
175+ @media (max-width: 40rem) {
176+ .g1t-copy {
177+ display: none;
178+ }
179+ }
180+</style>
+1−1
33 ---
44
55 <nav class="g1t-nav" aria-label="g1t">
6− <a href="/api/reference/">API reference</a>
6+ <a href="/api/reference/">API explorer</a>
77 <a href="https://g1t.sh/">g1t.sh</a>
88 <a href="https://g1t.sh/register" class="g1t-nav-cta">Sign up</a>
99 <a href="https://github.com/syntaqx/g1t" aria-label="Source on GitHub" class="g1t-nav-icon">
+57−77
11 ---
2−title: g1t docs
3−description: Guides and reference for g1t, the git forge for teams of agents.
4−template: splash
2+title: What is g1t?
3+description: A git forge for teams of agents. Hand it an outcome, and agents land it on main while your team works the way it does on GitHub.
54 tableOfContents: false
5+prev: false
66 ---
77
8−<div class="g1t-home-hero">
9− <p class="g1t-eyebrow">Documentation</p>
10− <h1>Build with g1t</h1>
11− <p>
12− Hand g1t an outcome and a team of agents converges it onto main, while you and
13− your team work exactly as you would on GitHub. Start with the path that fits.
14− </p>
15−</div>
8+import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
9+
10+**g1t hosts your repositories and runs a team of agents on them.** Write
11+what you want done; agents split it into issues, make a pull request for
12+each, test it in a clean sandbox, review it, fix what the review finds and
13+merge it under your repository's rules. People work alongside them with
14+the same issues, pull requests and reviews they know from GitHub.
1615
17−<div class="g1t-paths">
18− <a class="g1t-path" href="/quickstart/">
19− <em>5 minutes</em>
20− <strong>Quickstart</strong>
21− <span>Create a workspace, push a repository, and land your first change with an agent.</span>
22− </a>
23− <a class="g1t-path" href="/guides/outcomes/">
24− <em>Agents</em>
25− <strong>Hand off an outcome</strong>
26− <span>Write what you want. A planner splits it into issues, and agents land them in order.</span>
27− </a>
28− <a class="g1t-path" href="/guides/bring-your-own-agent/">
29− <em>Your agent</em>
30− <strong>Bring your own agent</strong>
31− <span>Connect Claude Code or any MCP client, and record its sessions onto pull requests.</span>
32− </a>
33− <a class="g1t-path" href="/reference/api/">
34− <em>Build</em>
35− <strong>The API</strong>
36− <span>Everything on g1t over REST and MCP, with an explorer to call it from the page.</span>
37− </a>
38−</div>
16+<CardGrid>
17+ <LinkCard
18+ title="Quickstart"
19+ description="Create a workspace, push a repository and land your first change with an agent, in five minutes."
20+ href="/quickstart/"
21+ />
22+ <LinkCard
23+ title="Move from GitHub"
24+ description="Push your repository, rename .github to .g1t, and your Actions workflows run here as they are."
25+ href="/guides/actions/"
26+ />
27+</CardGrid>
28+
29+## What you can do
30+
31+<CardGrid>
32+ <Card title="Hand off an outcome" icon="rocket">
33+ Describe a result. A planner turns it into issues in the order they land, and
34+ [agents work them in parallel](/guides/outcomes/).
35+ </Card>
36+ <Card title="Agents that finish" icon="approve-check">
37+ Each change is checked, reviewed and revised until it passes, then merged
38+ through the [merge queue](/guides/merge-queue/). You step in only when asked.
39+ </Card>
40+ <Card title="Bring your own agent" icon="laptop">
41+ Claude Code or any MCP client works on g1t as a teammate, and
42+ [records its session](/guides/bring-your-own-agent/) onto its pull requests.
43+ </Card>
44+ <Card title="GitHub Actions, unchanged" icon="github">
45+ Workflows run from `.g1t/workflows` [as GitHub runs them](/guides/actions/),
46+ and failing ones send the agent back to fix the cause.
47+ </Card>
48+ <Card title="Your models, your tools" icon="puzzle">
49+ Use g1t's models or [your own providers](/guides/models/), and pull context
50+ from [Sentry, Jira and Linear](/guides/integrations/).
51+ </Card>
52+ <Card title="Everything has an API" icon="open-book">
53+ Every action is a [REST endpoint and an MCP tool](/reference/api/), with
54+ [webhooks](/guides/webhooks/) for every event.
55+ </Card>
56+</CardGrid>
57+
58+## Using an AI assistant?
3959
40−<div class="g1t-columns">
41− <div>
42− <h3>Agents</h3>
43− <ul>
44− <li><a href="/guides/g1t-agents/">g1t agents</a></li>
45− <li><a href="/guides/outcomes/">Outcomes and plans</a></li>
46− <li><a href="/guides/talking-to-agents/">Talking to agents</a></li>
47− <li><a href="/guides/bring-your-own-agent/">Bring your own agent</a></li>
48− <li><a href="/guides/integrations/">Integrations: Sentry, Jira, Linear</a></li>
49− <li><a href="/guides/models/">Model providers: Anthropic, OpenAI, Gemini</a></li>
50− <li><a href="/guides/webhooks/">Webhooks</a></li>
51− <li><a href="/guides/actions/">GitHub Actions: rename .github to .g1t</a></li>
52− <li><a href="/guides/automations/">Automations</a></li>
53− </ul>
54− </div>
55− <div>
56− <h3>Landing changes</h3>
57− <ul>
58− <li><a href="/concepts/overview/">How g1t works</a></li>
59− <li><a href="/guides/merge-queue/">The merge queue</a></li>
60− <li><a href="/guides/why-blame/">Sessions and why-blame</a></li>
61− <li><a href="/concepts/forks/">Forks and branches</a></li>
62− </ul>
63− </div>
64− <div>
65− <h3>Workspaces</h3>
66− <ul>
67− <li><a href="/guides/authentication/">Accounts and sign-in</a></li>
68− <li><a href="/guides/workspaces/">Workspaces and tokens</a></li>
69− <li><a href="/guides/usage-and-billing/">Usage and billing</a></li>
70− <li><a href="/guides/git/">Git</a></li>
71− </ul>
72− </div>
73− <div>
74− <h3>Reference</h3>
75− <ul>
76− <li><a href="/reference/api/">API overview</a></li>
77− <li><a href="/api/reference/">API reference</a></li>
78− <li><a href="/reference/mcp/">MCP tools</a></li>
79− <li><a href="https://api.g1t.sh/openapi.json">OpenAPI document</a></li>
80− <li><a href="https://g1t.sh/llms.txt">llms.txt</a></li>
81− </ul>
82− </div>
83−</div>
60+Give it [g1t.sh/llms.txt](https://g1t.sh/llms.txt), which describes g1t for
61+agents, and ask it to set you up. Every page here also has **Copy page** at
62+the top, to paste into a conversation, and a plain Markdown version at its
63+address plus `.md`.
+23−0
1+import type { APIRoute, GetStaticPaths } from 'astro';
2+import { getCollection } from 'astro:content';
3+
4+/**
5+ * Every page as Markdown, at its path plus `.md`, for "Copy page" and for
6+ * agents that read the docs: the title, what it is about, then the page.
7+ */
8+export const getStaticPaths: GetStaticPaths = async () => {
9+ const pages = await getCollection('docs');
10+ return pages.map((page) => ({
11+ params: { slug: page.id === '' ? 'index' : page.id },
12+ props: { page },
13+ }));
14+};
15+
16+export const GET: APIRoute = ({ props }) => {
17+ const { page } = props as { page: Awaited<ReturnType<typeof getCollection<'docs'>>>[number] };
18+ const { title, description } = page.data;
19+ // MDX pages keep their markup; strip imports and leave the rest readable.
20+ const body = (page.body ?? '').replace(/^import .*$/gm, '').trim();
21+ const text = `# ${title}\n\n${description ? `> ${description}\n\n` : ''}${body}\n`;
22+ return new Response(text, { headers: { 'content-type': 'text/markdown; charset=utf-8' } });
23+};
+10−0
1+import { defineRouteMiddleware } from '@astrojs/starlight/route-data';
2+
3+import { tabFor } from './tabs';
4+
5+/** Each page's sidebar holds only its tab's groups. */
6+export const onRequest = defineRouteMiddleware((context) => {
7+ const route = context.locals.starlightRoute;
8+ const tab = tabFor(route.id);
9+ route.sidebar = route.sidebar.filter((entry) => entry.type === 'group' && tab.groups.includes(entry.label));
10+});
+59−102
3737 --sl-text-body: 0.9375rem;
3838 --sl-line-height: 1.75;
3939 --sl-content-width: 46rem;
40− --sl-nav-height: 3.5rem;
40+ /* The header's row, and the tabs beneath it. */
41+ --sl-nav-height: 6.25rem;
4142 --sl-sidebar-width: 17rem;
4243
4344 color-scheme: dark;
5152 /* --- Header --------------------------------------------------------------- */
5253
5354 header.header {
55+ padding: 0 !important;
5456 backdrop-filter: blur(10px);
5557 border-bottom: 1px solid var(--g1t-line);
5658 }
59+site-search {
60+ width: 100%;
61+ max-width: 30rem;
62+}
63+/* On phones the menu button sits in the header's top row, not its middle. */
64+.sl-menu-button {
65+ top: calc((3.5rem - var(--sl-menu-button-size)) / 2) !important;
66+}
5767 site-search button[data-open-modal] {
5868 border-radius: 0.5rem;
5969 background: var(--g1t-surface);
7080 .sidebar-content {
7181 padding-top: 1.25rem;
7282 }
83+/* Groups always show their pages: no caret, no folding. */
84+.sidebar-content details > summary {
85+ pointer-events: none;
86+ padding-top: 0.25rem;
87+}
88+.sidebar-content details > summary .caret {
89+ display: none;
90+}
91+.sidebar-content .top-level > li + li {
92+ margin-top: 1rem;
93+}
7394 /* Group labels: small and quiet, like section names, not links. */
7495 .sidebar-content details > summary .group-label .large,
7596 .sidebar-content .top-level > li > details > summary {
109130 .content-panel {
110131 padding-top: 2rem;
111132 }
112−.sl-markdown-content h1,
113−h1#_top {
133+/* The title and the page read as one, without a rule between them. */
134+.content-panel + .content-panel {
135+ border-top: 0;
136+ padding-top: 0.5rem;
137+}
138+.sl-markdown-content h1 {
114139 font-size: 2.25rem;
115140 font-weight: 650;
116141 letter-spacing: -0.03em;
117142 line-height: 1.15;
118143 color: var(--g1t-fg);
119144 }
120−/* Each section opens with a rule across the full column. */
145+/* Sections open with space, not rules. */
121146 .sl-markdown-content .sl-heading-wrapper.level-h2 {
122147 margin-top: 3rem;
123− padding-top: 1.75rem;
124− border-top: 1px solid var(--g1t-line);
125148 }
126149 .sl-markdown-content h2 {
127− font-size: 1.4rem;
128− font-weight: 650;
150+ font-size: 1.5rem;
151+ font-weight: 600;
129152 letter-spacing: -0.02em;
130153 color: var(--g1t-fg);
131154 }
150173 }
151174 .sl-markdown-content :not(pre) > code {
152175 border-radius: 0.3rem;
153− padding: 0.1rem 0.35rem;
176+ padding: 0.1rem 0.3rem;
154177 font-size: 0.85em;
155178 color: var(--g1t-fg);
156− box-shadow: inset 0 0 0 1px var(--g1t-line);
179+ background: var(--g1t-raised);
157180 }
158181
159182 /* Tables: ruled, not boxed. */
277300 color: var(--g1t-faint);
278301 }
279302
280−/* --- The home page -------------------------------------------------------- */
303+/* --- Cards ---------------------------------------------------------------- */
281304
282−/* The home page brings its own heading, so Starlight's title bar goes. */
283−main:has(.g1t-home-hero) > .content-panel:first-child {
284− display: none;
305+.sl-markdown-content .card-grid {
306+ gap: 0.75rem;
285307 }
286−main:has(.g1t-home-hero) > .content-panel {
287− border-top: 0;
308+.sl-markdown-content .card {
309+ padding: 1.1rem 1.2rem;
288310 }
289−.g1t-home-hero {
290− padding: 1rem 0 0.5rem;
311+.sl-markdown-content .card .title {
312+ font-size: 1rem;
313+ font-weight: 600;
314+ color: var(--g1t-fg);
291315 }
292−.sl-markdown-content .g1t-eyebrow {
293− font-family: var(--g1t-font-mono);
294− font-size: 0.72rem;
295− letter-spacing: 0.2em;
296− text-transform: uppercase;
316+.sl-markdown-content .card .icon {
297317 color: var(--g1t-merged);
298−}
299−.g1t-home-hero h1 {
300− margin: 0.75rem 0 0;
301− font-size: clamp(2.25rem, 5vw, 3.25rem);
302− font-weight: 650;
303− letter-spacing: -0.035em;
304− line-height: 1.05;
305− color: var(--g1t-fg);
318+ background: color-mix(in srgb, var(--g1t-merged) 12%, transparent);
306319 border: 0;
307− padding: 0;
308−}
309−.g1t-home-hero p {
310− max-width: 38rem;
311− margin-top: 1rem;
312− font-size: 1.05rem;
313− color: var(--g1t-muted);
320+ border-radius: 0.5rem;
321+ padding: 0.3rem;
314322 }
315−.g1t-paths {
316− display: grid;
317− gap: 0.75rem;
318− grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
319− margin-top: 2rem;
323+.sl-link-card {
324+ padding: 1rem 1.2rem;
320325 }
321−.g1t-path {
322− display: block;
323− border-radius: 1rem;
324− padding: 1.1rem 1.2rem;
325− background: var(--g1t-surface);
326− border: 1px solid var(--g1t-line);
327− text-decoration: none !important;
328− transition: border-color 0.15s, transform 0.15s;
329−}
330−.g1t-path:hover {
331− border-color: var(--g1t-line-strong);
332− transform: translateY(-1px);
333−}
334−.g1t-path strong {
335− display: block;
326+.sl-link-card .title {
336327 font-size: 0.95rem;
328+ font-weight: 600;
337329 color: var(--g1t-fg);
338330 }
339−.g1t-path span {
340− display: block;
341− margin-top: 0.35rem;
331+.sl-link-card .description {
342332 font-size: 0.85rem;
343− line-height: 1.55;
344333 color: var(--g1t-muted);
345334 }
346−.g1t-path em {
347− display: inline-block;
348− margin-bottom: 0.6rem;
335+
336+/* Steps: numbered, on a quiet rail. */
337+.sl-steps > li::before {
338+ background: var(--g1t-raised) !important;
339+ color: var(--g1t-fg) !important;
340+ box-shadow: inset 0 0 0 1px var(--g1t-line-strong);
349341 font-family: var(--g1t-font-mono);
350− font-size: 0.68rem;
351− font-style: normal;
352− letter-spacing: 0.14em;
353− text-transform: uppercase;
354− color: var(--g1t-merged);
355−}
356−.g1t-columns {
357− display: grid;
358− gap: 2rem;
359− grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
360− margin-top: 3rem !important;
361−}
362−.g1t-columns > div,
363−.g1t-paths > a {
364− margin-top: 0 !important;
365−}
366−.g1t-columns h3 {
367− margin: 0 0 0.5rem;
368342 font-size: 0.8rem;
369− font-weight: 600;
370− letter-spacing: 0.06em;
371− text-transform: uppercase;
372− color: var(--g1t-faint);
373343 }
374−.g1t-columns ul {
375− margin: 0;
376− padding: 0;
377− list-style: none;
378−}
379−.g1t-columns li {
380− margin: 0.3rem 0;
381−}
382−.g1t-columns a {
383− font-size: 0.9rem;
384− color: var(--g1t-fg-soft) !important;
385− text-decoration: none !important;
386−}
387−.g1t-columns a:hover {
388− color: #cfc6ff !important;
344+.sl-steps > li::after {
345+ background: var(--g1t-line) !important;
389346 }
+24−0
1+/**
2+ * The tabs under the header. Each shows its own part of the sidebar, as
3+ * the groups named here; a page belongs to the tab whose `match` it fits.
4+ */
5+export type Tab = { label: string; href: string; groups: string[]; match: (slug: string) => boolean };
6+
7+export const TABS: Tab[] = [
8+ {
9+ label: 'Documentation',
10+ href: '/',
11+ groups: ['Get started', 'Agents', 'Connect your tools', 'Landing changes', 'Workspaces'],
12+ match: (slug) => !slug.startsWith('reference/'),
13+ },
14+ {
15+ label: 'API reference',
16+ href: '/reference/api/',
17+ groups: ['Reference'],
18+ match: (slug) => slug.startsWith('reference/'),
19+ },
20+];
21+
22+export function tabFor(slug: string): Tab {
23+ return TABS.find((tab) => tab.match(slug)) ?? TABS[0];
24+}