Commit

A dusk palette and isometric line art, with the landing page rewritten around agents as a team

Indigo night with a mint accent for what is live, passed or added, and lavender and peach for art and status. The landing page now leads with what only g1t does: outcomes instead of pull requests, agents that work as a team, and a main that only moves forward, with GitHub's basics as table stakes.

syntaqxcommitted Parentbd72e8dBrowse files
8 files+573−2170/8 viewed
+2−2
22 <rect width="32" height="32" rx="7" fill="#12110d"/>
33 <path d="M4 7h6c7 0 7 9 14 9" stroke="#8f8c82"/>
44 <path d="M4 25h6c7 0 7-9 14-9" stroke="#8f8c82"/>
5− <path d="M4 16h20" stroke="#b6f24a"/>
6− <circle cx="25" cy="16" r="3.5" fill="#b6f24a"/>
5+ <path d="M4 16h20" stroke="#86efc4"/>
6+ <circle cx="25" cy="16" r="3.5" fill="#86efc4"/>
77 </svg>
+33−0
1313 --color-line-strong: var(--g1t-line-strong);
1414
1515 --color-fg: var(--g1t-fg);
16+ --color-fg-soft: var(--g1t-fg-soft);
1617 --color-muted: var(--g1t-muted);
1718 --color-faint: var(--g1t-faint);
1819
173174 content: counter(line);
174175 @apply mr-5 inline-block w-10 text-right text-faint select-none;
175176 }
177+
178+/* Artwork: dashes that flow along a track. */
179+.art-flow {
180+ animation: dash 1.6s linear infinite;
181+}
182+@media (prefers-reduced-motion: reduce) {
183+ .art-flow {
184+ animation: none;
185+ }
186+}
187+
188+/*
189+ * The sky after dusk: deep indigo overhead, a lavender and peach glow at
190+ * the horizon, a few stars. Behind the landing page's opening.
191+ */
192+.dusk {
193+ background:
194+ radial-gradient(1px 1px at 12% 18%, rgb(255 255 255 / 0.5), transparent),
195+ radial-gradient(1px 1px at 27% 8%, rgb(255 255 255 / 0.35), transparent),
196+ radial-gradient(1px 1px at 44% 22%, rgb(255 255 255 / 0.3), transparent),
197+ radial-gradient(1px 1px at 63% 12%, rgb(255 255 255 / 0.45), transparent),
198+ radial-gradient(1px 1px at 81% 26%, rgb(255 255 255 / 0.3), transparent),
199+ radial-gradient(1.5px 1.5px at 90% 9%, rgb(255 255 255 / 0.5), transparent),
200+ radial-gradient(70% 45% at 50% 100%, rgb(255 189 140 / 0.22), transparent 70%),
201+ radial-gradient(90% 60% at 50% 95%, rgb(182 168 255 / 0.28), transparent 75%),
202+ linear-gradient(to bottom, #0b0c18 0%, #15163a 55%, #2a2556 100%);
203+}
204+/* A planet rising behind the horizon, its lit edge catching the glow. */
205+.dusk-planet {
206+ background: radial-gradient(circle at 70% 30%, rgb(182 168 255 / 0.35), rgb(255 189 140 / 0.12) 45%, transparent 70%);
207+ box-shadow: inset 18px -10px 60px rgb(255 214 186 / 0.18);
208+}
+335−0
1+/**
2+ * g1t's artwork: thin isometric line drawings of what it does, on a faint
3+ * grid, with small dots at the corners. Everything is drawn from one
4+ * projection so the pieces sit together.
5+ */
6+import type { ReactNode } from "react";
7+
8+/** Isometric projection: x runs down-right, y down-left, z up. */
9+const COS = Math.cos(Math.PI / 6);
10+const SIN = 0.5;
11+function iso(x: number, y: number, z = 0): [number, number] {
12+ return [(x - y) * COS, (x + y) * SIN - z];
13+}
14+function pts(points: [number, number][]): string {
15+ return points.map(([x, y]) => `${x.toFixed(1)},${y.toFixed(1)}`).join(" ");
16+}
17+
18+const LINE = "var(--color-fg)";
19+
20+/** A flat rectangle on the floor (or at height `z`). */
21+function Plate({
22+ x,
23+ y,
24+ w,
25+ d,
26+ z = 0,
27+ stroke = LINE,
28+ opacity = 0.45,
29+ fill = "none",
30+ dots = true,
31+ dash,
32+}: {
33+ x: number;
34+ y: number;
35+ w: number;
36+ d: number;
37+ z?: number;
38+ stroke?: string;
39+ opacity?: number;
40+ fill?: string;
41+ dots?: boolean;
42+ dash?: string;
43+}) {
44+ const corners = [iso(x, y, z), iso(x + w, y, z), iso(x + w, y + d, z), iso(x, y + d, z)];
45+ return (
46+ <g>
47+ <polygon
48+ points={pts(corners)}
49+ fill={fill}
50+ stroke={stroke}
51+ strokeOpacity={opacity}
52+ strokeWidth={1}
53+ strokeDasharray={dash}
54+ vectorEffect="non-scaling-stroke"
55+ />
56+ {dots &&
57+ corners.map(([cx, cy], index) => (
58+ <circle key={index} cx={cx} cy={cy} r={1.6} fill={stroke} fillOpacity={Math.min(1, opacity + 0.3)} />
59+ ))}
60+ </g>
61+ );
62+}
63+
64+/** A box: its visible edges, and a faint fill on the top face. */
65+function Box({
66+ x,
67+ y,
68+ z = 0,
69+ w,
70+ d,
71+ h,
72+ stroke = LINE,
73+ opacity = 0.6,
74+ top,
75+}: {
76+ x: number;
77+ y: number;
78+ z?: number;
79+ w: number;
80+ d: number;
81+ h: number;
82+ stroke?: string;
83+ opacity?: number;
84+ top?: string;
85+}) {
86+ const b = [iso(x, y, z), iso(x + w, y, z), iso(x + w, y + d, z), iso(x, y + d, z)];
87+ const t = [iso(x, y, z + h), iso(x + w, y, z + h), iso(x + w, y + d, z + h), iso(x, y + d, z + h)];
88+ const common = {
89+ stroke,
90+ strokeOpacity: opacity,
91+ strokeWidth: 1,
92+ vectorEffect: "non-scaling-stroke" as const,
93+ };
94+ return (
95+ <g>
96+ <polygon points={pts([b[1]!, b[2]!, t[2]!, t[1]!])} fill="var(--color-bg)" {...common} />
97+ <polygon points={pts([b[2]!, b[3]!, t[3]!, t[2]!])} fill="var(--color-bg)" {...common} />
98+ <polygon points={pts(t)} fill={top ?? "var(--color-surface)"} {...common} />
99+ {t.map(([cx, cy], index) => (
100+ <circle key={index} cx={cx} cy={cy} r={1.4} fill={stroke} fillOpacity={opacity} />
101+ ))}
102+ </g>
103+ );
104+}
105+
106+/** A path along the floor through `points`, given in floor coordinates. */
107+function Track({
108+ points,
109+ z = 0,
110+ stroke = LINE,
111+ opacity = 0.5,
112+ width = 1,
113+ dash,
114+ flow,
115+}: {
116+ points: [number, number][];
117+ z?: number;
118+ stroke?: string;
119+ opacity?: number;
120+ width?: number;
121+ dash?: string;
122+ /** Animate the dashes along the track. */
123+ flow?: boolean;
124+}) {
125+ return (
126+ <polyline
127+ points={pts(points.map(([x, y]) => iso(x, y, z)))}
128+ fill="none"
129+ stroke={stroke}
130+ strokeOpacity={opacity}
131+ strokeWidth={width}
132+ strokeDasharray={dash}
133+ strokeLinecap="round"
134+ strokeLinejoin="round"
135+ vectorEffect="non-scaling-stroke"
136+ className={flow ? "art-flow" : undefined}
137+ />
138+ );
139+}
140+
141+/** The faint floor grid every drawing stands on. */
142+function Grid({ size, step = 20, opacity = 0.08 }: { size: number; step?: number; opacity?: number }) {
143+ const lines: ReactNode[] = [];
144+ for (let i = 0; i <= size; i += step) {
145+ lines.push(<Track key={`a${i}`} points={[[i, 0], [i, size]]} opacity={opacity} />);
146+ lines.push(<Track key={`b${i}`} points={[[0, i], [size, i]]} opacity={opacity} />);
147+ }
148+ return <g>{lines}</g>;
149+}
150+
151+function Label({ x, y, z = 0, children, tone = "var(--color-muted)" }: { x: number; y: number; z?: number; children: string; tone?: string }) {
152+ const [px, py] = iso(x, y, z);
153+ return (
154+ <text x={px} y={py} fill={tone} fontSize={9} fontFamily="var(--font-mono)" letterSpacing="0.06em">
155+ {children}
156+ </text>
157+ );
158+}
159+
160+const MINT = "var(--color-accent)";
161+const LAVENDER = "var(--color-merged)";
162+const PEACH = "var(--color-warn)";
163+
164+/**
165+ * The hero: lanes of agents at work, each on its own track, converging
166+ * through the queue into one main line that only moves forward.
167+ */
168+export function ConvergeArt({ className }: { className?: string }) {
169+ const lanes = [20, 60, 100, 140, 180];
170+ return (
171+ <svg viewBox="-260 -70 560 300" className={className} role="img" aria-label="Agents on parallel lanes converging into main">
172+ <Grid size={300} />
173+ {/* The lanes, each with an agent at work. */}
174+ {lanes.map((y, index) => (
175+ <g key={y}>
176+ <Plate x={0} y={y - 8} w={150} d={16} opacity={0.22} dots={false} />
177+ <Track
178+ points={[[0, y], [150, y], [205, 100]]}
179+ stroke={index === 2 ? MINT : LAVENDER}
180+ opacity={0.65}
181+ dash="3 5"
182+ flow
183+ />
184+ <Box x={30 + ((index * 37) % 80)} y={y - 6} w={12} d={12} h={10} stroke={LAVENDER} opacity={0.8} />
185+ </g>
186+ ))}
187+ {/* The queue: combinations stacked and checked before they land. */}
188+ {[0, 1, 2].map((level) => (
189+ <Plate key={level} x={200} y={84} w={34} d={32} z={level * 9} stroke={PEACH} opacity={0.55 - level * 0.12} />
190+ ))}
191+ <Label x={196} y={124} tone="var(--color-faint)">QUEUE</Label>
192+ {/* Main: one line, only forward. */}
193+ <Track points={[[234, 100], [300, 100]]} stroke={MINT} opacity={0.95} width={2} />
194+ {[248, 266, 284].map((x) => {
195+ const [cx, cy] = iso(x, 100);
196+ return <circle key={x} cx={cx} cy={cy} r={3} fill={MINT} />;
197+ })}
198+ {(() => {
199+ const [cx, cy] = iso(300, 100);
200+ return (
201+ <g>
202+ <circle cx={cx} cy={cy} r={11} fill={MINT} fillOpacity={0.12} />
203+ <circle cx={cx} cy={cy} r={5} fill={MINT} />
204+ </g>
205+ );
206+ })()}
207+ <Label x={270} y={112} tone={MINT}>MAIN</Label>
208+ <Label x={-2} y={8} tone="var(--color-faint)">AGENTS</Label>
209+ </svg>
210+ );
211+}
212+
213+/** An outcome split into a plan: a brief, then issues with dependencies. */
214+export function PlanArt({ className }: { className?: string }) {
215+ const nodes: [number, number, number][] = [
216+ [40, 20, 0],
217+ [40, 70, 0],
218+ [40, 120, 0],
219+ [110, 45, 1],
220+ [110, 105, 1],
221+ [175, 75, 2],
222+ ];
223+ const edges: [number, number][] = [
224+ [0, 3],
225+ [1, 3],
226+ [1, 4],
227+ [2, 4],
228+ [3, 5],
229+ [4, 5],
230+ ];
231+ return (
232+ <svg viewBox="-170 -40 330 210" className={className} aria-hidden="true">
233+ <Grid size={200} opacity={0.06} />
234+ <Plate x={-30} y={50} w={40} d={50} z={0} stroke={PEACH} opacity={0.6} />
235+ <Label x={-30} y={110} tone="var(--color-faint)">BRIEF</Label>
236+ {[0, 1, 2].map((index) => (
237+ <Track key={index} points={[[10, 75], [40, nodes[index]![1]]]} stroke={PEACH} opacity={0.35} dash="2 4" />
238+ ))}
239+ {edges.map(([from, to]) => (
240+ <Track
241+ key={`${from}-${to}`}
242+ points={[
243+ [nodes[from]![0] + 10, nodes[from]![1] + 5],
244+ [nodes[to]![0], nodes[to]![1] + 5],
245+ ]}
246+ stroke={LAVENDER}
247+ opacity={0.55}
248+ />
249+ ))}
250+ {nodes.map(([x, y, level], index) => (
251+ <Box key={index} x={x} y={y} w={10} d={10} h={6 + level * 3} stroke={level === 2 ? MINT : LAVENDER} opacity={0.8} />
252+ ))}
253+ </svg>
254+ );
255+}
256+
257+/** Agents aware of each other: boxes linked, one opening an issue for another. */
258+export function TeamArt({ className }: { className?: string }) {
259+ const agents: [number, number][] = [
260+ [30, 30],
261+ [110, 20],
262+ [70, 100],
263+ [150, 90],
264+ ];
265+ return (
266+ <svg viewBox="-150 -40 300 200" className={className} aria-hidden="true">
267+ <Grid size={180} opacity={0.06} />
268+ {agents.map(([x, y], i) =>
269+ agents.slice(i + 1).map(([x2, y2], j) => (
270+ <Track key={`${i}-${j}`} points={[[x + 6, y + 6], [x2 + 6, y2 + 6]]} stroke={LAVENDER} opacity={0.3} dash="2 4" flow />
271+ )),
272+ )}
273+ {agents.map(([x, y], index) => (
274+ <Box key={index} x={x} y={y} w={14} d={14} h={14} stroke={LAVENDER} opacity={0.85} />
275+ ))}
276+ {/* A note passed between two of them. */}
277+ <Plate x={92} y={58} w={16} d={12} z={22} stroke={MINT} opacity={0.8} />
278+ <Track points={[[100, 64], [100, 64]]} />
279+ </svg>
280+ );
281+}
282+
283+/** The queue: combinations stacked and tested, one passing into main. */
284+export function QueueArt({ className }: { className?: string }) {
285+ return (
286+ <svg viewBox="-150 -60 300 200" className={className} aria-hidden="true">
287+ <Grid size={180} opacity={0.06} />
288+ <Track points={[[0, 90], [190, 90]]} stroke={MINT} opacity={0.9} width={2} />
289+ {[0, 1, 2, 3].map((level) => (
290+ <Plate
291+ key={level}
292+ x={50}
293+ y={50}
294+ w={60}
295+ d={60}
296+ z={10 + level * 14}
297+ stroke={level === 3 ? "var(--color-danger)" : level === 0 ? MINT : LAVENDER}
298+ opacity={0.75 - level * 0.08}
299+ />
300+ ))}
301+ <Label x={118} y={52} z={10} tone={MINT}>MAIN + #41</Label>
302+ <Label x={118} y={52} z={24} tone="var(--color-faint)">+ #44</Label>
303+ <Label x={118} y={52} z={38} tone="var(--color-faint)">+ #46</Label>
304+ <Label x={118} y={52} z={52} tone="var(--color-danger)">+ #48 ✕</Label>
305+ </svg>
306+ );
307+}
308+
309+/** Why-blame: a file in layers, one line lifted to show where it came from. */
310+export function WhyArt({ className }: { className?: string }) {
311+ return (
312+ <svg viewBox="-140 -50 280 190" className={className} aria-hidden="true">
313+ <Grid size={170} opacity={0.06} />
314+ <Plate x={30} y={30} w={90} d={110} stroke={LINE} opacity={0.4} />
315+ {[45, 58, 71, 97, 110, 123].map((y) => (
316+ <Track key={y} points={[[40, y], [100, y]]} opacity={0.3} />
317+ ))}
318+ <Track points={[[40, 84], [110, 84]]} stroke={MINT} opacity={0.9} width={2} />
319+ {/* Lifted: the commit, the pull request, the session. */}
320+ {[0, 1, 2].map((level) => (
321+ <Plate
322+ key={level}
323+ x={70}
324+ y={70 - level * 6}
325+ w={60}
326+ d={26}
327+ z={28 + level * 18}
328+ stroke={level === 2 ? LAVENDER : "var(--color-muted)"}
329+ opacity={0.6}
330+ />
331+ ))}
332+ <Track points={[[100, 84], [100, 84]]} />
333+ </svg>
334+ );
335+}
+180−193
44
55 import type { Repo } from "@g1t/contracts";
66
7−import {
8− AgentsIllustration,
9− HeroIllustration,
10− EventsIllustration,
11− ForkIllustration,
12− IssueIllustration,
13− SessionIllustration,
14− MergeIllustration,
15−} from "./illustrations";
7+import { ConvergeArt, PlanArt, QueueArt, TeamArt, WhyArt } from "./art";
168 import { RepoList } from "./repo-list";
179 import { ButtonLink, CopyLine } from "./ui";
1810
19−function FeatureCard({
11+/** A small label above a heading, in the mono face. */
12+function Eyebrow({ children }: { children: ReactNode }) {
13+ return <p className="font-mono text-xs tracking-[0.2em] text-merged uppercase">{children}</p>;
14+}
15+
16+function Tags({ items }: { items: string[] }) {
17+ return (
18+ <ul className="mt-5 flex flex-wrap gap-1.5">
19+ {items.map((item) => (
20+ <li
21+ key={item}
22+ className="rounded-full bg-bg/80 px-2.5 py-1 font-mono text-[0.6875rem] tracking-wide text-muted uppercase ring-1 ring-line"
23+ >
24+ {item}
25+ </li>
26+ ))}
27+ </ul>
28+ );
29+}
30+
31+/** A card with a line drawing above its words, on a faint grid. */
32+function Card({
2033 title,
21− illustration,
22− soon,
34+ art,
35+ tags,
2336 wide,
2437 children,
2538 }: {
2639 title: string;
27− illustration: ReactNode;
28− soon?: boolean;
40+ art: ReactNode;
41+ tags?: string[];
2942 wide?: boolean;
3043 children: ReactNode;
3144 }) {
3245 return (
3346 <article
34− className={`group overflow-hidden rounded-2xl border border-line bg-surface transition-colors hover:border-line-strong ${
35− wide ? "md:col-span-3" : "md:col-span-2"
47+ className={`group relative overflow-hidden rounded-3xl bg-surface p-7 ring-1 ring-line transition-colors hover:ring-line-strong ${
48+ wide ? "md:col-span-2" : ""
3649 }`}
3750 >
38− <div className="border-b border-line bg-bg/40 px-6 pt-6">
39− <div className="mx-auto max-w-sm">{illustration}</div>
51+ <h3 className="text-lg font-semibold tracking-tight">{title}</h3>
52+ <div className={`mx-auto mt-2 ${wide ? "max-w-md" : "max-w-xs"} opacity-90 transition-opacity group-hover:opacity-100`}>
53+ {art}
4054 </div>
41− <div className="p-6">
42− <h3 className="flex items-center gap-2 font-semibold tracking-tight">
43− {title}
44− {soon && (
45− <span className="rounded-full border border-line px-2 py-0.5 text-[0.6875rem] font-normal text-faint">
46− in progress
47− </span>
48− )}
49− </h3>
50− <p className="mt-2 text-sm leading-6 text-muted">{children}</p>
51− </div>
55+ <p className="mt-2 text-sm leading-6 text-muted">{children}</p>
56+ {tags && <Tags items={tags} />}
5257 </article>
5358 );
5459 }
5560
61+const FLOW: [string, string][] = [
62+ ["Brief", "Write the outcome you want, in plain words."],
63+ ["Plan", "A planner agent splits it into issues, each with checks that prove it done, and the order they depend on."],
64+ ["Agents", "Each issue gets an agent as it unblocks. They know what the others are doing, and tell each other."],
65+ ["Review", "Checks run in clean sandboxes; a second agent reviews; you ask for changes and the agent makes them."],
66+ ["Main", "The queue tests every change together with what lands before it, and main moves only to what passed."],
67+];
68+
69+const BASICS = [
70+ "Issues and labels",
71+ "Branches and forks",
72+ "Pull requests",
73+ "Line comments and reviews",
74+ "Protected branches",
75+ "Required approvals",
76+ "Workspaces and teams",
77+ "Access tokens",
78+ "Git over HTTPS",
79+ "REST API",
80+ "MCP server",
81+ "OAuth sign-in",
82+];
83+
5684 const COMPARISON: [string, string, string][] = [
57− [
58− "Unit of work",
59− "One issue, usually one pull request",
60− "One issue, as many pull requests as you have agents, and a record of which one was merged",
61− ],
62− [
63− "Where agents work",
64− "Branches and local worktrees",
65− "A server-side fork per pull request",
66− ],
67− [
68− "Why a change was made",
69− "A commit message, if you are lucky",
70− "The agent's full session, kept with the code",
71− ],
72− [
73− "Is it done?",
74− "Whatever the author says they ran",
75− "The issue's checks, run by the forge in a clean sandbox, before anything can merge",
76− ],
77− [
78− "Two changes to one file",
79− "A merge conflict at the end",
80− "Flagged on both pull requests while the work is still under way",
81− ],
82− [
83− "When main moves",
84− "Someone rebases by hand",
85− "An agent merges it in and resolves the conflict",
86− ],
87− [
88− "Review",
89− "A person reads every diff",
90− "Agents review first, on the lines that matter; people decide",
91− ],
92− [
93− "Connecting an agent",
94− "A vendor integration",
95− "Any MCP client, or plain HTTP",
96− ],
85+ ["What you hand over", "A pull request to review", "An outcome, which becomes a plan of issues and lands on main"],
86+ ["Many agents at once", "Separate pull requests to compare and untangle", "A team: told about each other's work, filing what they find, talking through the forge"],
87+ ["Is it done?", "Whatever the author says they ran", "The issue's checks, run by the forge in a clean sandbox"],
88+ ["When two changes collide", "A merge conflict, or a broken main", "Tested together in the queue first; the one that breaks goes back to its agent"],
89+ ["What main promises", "Whatever passed when each change merged", "Every check of every issue that ever landed, on every change since"],
90+ ["Why is this line here?", "A commit message, if you are lucky", "The commit, the pull request, the issue and the agent's own account"],
91+ ["You in the loop", "Reading every diff", "Asking for changes, approving, steering; the agents do the rest"],
9792 ];
9893
99−const PLATFORM = ["Workers", "Artifacts", "Containers", "D1", "Queues", "Rust"];
94+const PLATFORM = ["Workers", "Artifacts", "Containers", "D1", "Queues", "AI Gateway", "Rust"];
10095
10196 export function Landing({ repos }: { repos: Repo[] }) {
10297 return (
10398 <main>
104− {/* Hero */}
105− <section className="relative overflow-hidden border-b border-line">
99+ {/* The opening: the sky after dusk, agents converging on main. */}
100+ <section className="dusk relative overflow-hidden">
106101 <div
107102 aria-hidden="true"
108− className="pointer-events-none absolute inset-x-0 top-0 h-128 bg-[radial-gradient(60%_60%_at_50%_0%,color-mix(in_srgb,var(--color-accent)_9%,transparent),transparent)]"
103+ className="dusk-planet pointer-events-none absolute -top-[30rem] left-1/2 size-[60rem] -translate-x-[10%] rounded-full"
109104 />
110− <div className="relative mx-auto max-w-6xl px-4 pt-20 pb-10 text-center">
105+ <div className="relative mx-auto max-w-6xl px-4 pt-24 pb-6 text-center">
111106 <Link
112107 to="https://docs.g1t.sh/concepts/overview/"
113− className="inline-flex animate-fade-up items-center gap-2 rounded-full border border-line bg-surface px-3 py-1 text-xs text-muted transition-colors hover:border-line-strong hover:text-fg"
108+ className="inline-flex animate-fade-up items-center gap-2 rounded-full bg-bg/50 px-3 py-1 text-xs text-fg-soft ring-1 ring-white/10 backdrop-blur transition-colors hover:bg-bg/70"
114109 >
115110 <span className="size-1.5 rounded-full bg-accent" />
116− Built on Cloudflare Workers and Artifacts
111+ A git forge for teams of agents
117112 <ArrowRight size={12} />
118113 </Link>
119− <h1 className="mx-auto mt-6 max-w-3xl animate-fade-up text-5xl leading-[1.05] font-semibold tracking-[-0.035em] text-balance sm:text-7xl">
120− Git for
114+ <h1 className="mx-auto mt-7 max-w-4xl animate-fade-up text-5xl leading-[1.04] font-semibold tracking-[-0.035em] text-balance sm:text-7xl">
115+ Hand off the outcome.
121116 <br />
122− <span className="text-accent">AI scale.</span>
117+ <span className="bg-gradient-to-r from-[#d9d1ff] via-[#ffd4b8] to-accent bg-clip-text text-transparent">
118+ A team of agents ships it.
119+ </span>
123120 </h1>
124− <p className="mx-auto mt-6 max-w-xl animate-fade-up text-lg leading-7 text-muted text-balance">
125− Git was built for people taking turns. g1t is a forge for thousands
126− of agents working on the same code at once: every change isolated,
127− every decision recorded, every change landed in order.
121+ <p className="mx-auto mt-7 max-w-2xl animate-fade-up text-lg leading-8 text-fg-soft/80 text-balance">
122+ Everything you expect from GitHub: issues, branches, pull requests, review. On top of
123+ it, describe what you want and g1t plans it, puts agents on every part at once, keeps
124+ them working as a team, and lands it on main through checks that hold.
128125 </p>
129− <div className="mt-8 flex animate-fade-up flex-wrap items-center justify-center gap-3">
130− <ButtonLink to="/register" variant="accent" large>
126+ <div className="mt-9 flex animate-fade-up flex-wrap items-center justify-center gap-3">
127+ <ButtonLink to="/register" variant="primary" large>
131128 Get started
132129 <ArrowRight size={15} />
133130 </ButtonLink>
135132 Read the docs
136133 </ButtonLink>
137134 </div>
138− <div className="mx-auto mt-14 max-w-5xl">
139− <HeroIllustration />
140− </div>
141135 </div>
136+ <div className="relative mx-auto max-w-5xl px-4 pb-4">
137+ <ConvergeArt className="w-full" />
138+ </div>
139+ <div aria-hidden="true" className="h-24 bg-gradient-to-b from-transparent to-bg" />
142140 </section>
143141
144− {/* How it works */}
142+ {/* The three things only g1t does. */}
145143 <section className="mx-auto max-w-6xl px-4 py-24">
146− <p className="text-sm font-medium text-accent">How it works</p>
147− <h2 className="mt-2 max-w-2xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
148− Everything you know about git still works. It just stops assuming one
149− author at a time.
144+ <Eyebrow>Agents as a team</Eyebrow>
145+ <h2 className="mt-3 max-w-3xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
146+ Hosting git is the easy part. g1t is built for what comes after: many agents, one
147+ codebase, nobody refereeing.
150148 </h2>
151− <div className="mt-12 grid gap-4 md:grid-cols-6">
152− <FeatureCard
153− title="Start with an issue"
154− illustration={<IssueIllustration />}
155− >
156− A bug, a feature, a report from your error tracker. Label it, add
157− the checks that prove it is done, and put as many agents on it as
158− you like.
159− </FeatureCard>
160− <FeatureCard
161− title="A fork for every pull request"
162− illustration={<ForkIllustration />}
163− >
164− Each agent gets its own copy of the repository the moment it starts.
165− No branches to name, nothing to collide with.
166− </FeatureCard>
167− <FeatureCard
168− title="The session stays with the code"
169− illustration={<SessionIllustration />}
170− >
171− Prompts, reasoning and tool calls are recorded against the pull
172− request and the commit they produced, so you can see why, not only
173− what.
174− </FeatureCard>
175− <FeatureCard
176− title="Bring any agent"
177− illustration={<AgentsIllustration />}
178− wide
179− >
180− Claude Code and other MCP clients connect to mcp.g1t.sh with one
181− command. Everything is also a plain REST call at api.g1t.sh.
182− </FeatureCard>
183− <FeatureCard
184− title="Converge on main"
185− illustration={<MergeIllustration />}
186− wide
187− >
188− However many pull requests are in flight, changes reach main one
189− at a time and in order. Merge one and its issue closes, naming it;
190− the others for that issue close as superseded.
191− </FeatureCard>
149+ <div className="mt-12 grid gap-4 md:grid-cols-3">
150+ <Card title="Outcomes, not pull requests" art={<PlanArt className="w-full" />} tags={["Brief", "Plan", "Dependencies", "Checks"]}>
151+ Write what you want. A planner agent turns it into issues with acceptance checks and
152+ the order they depend on; agents start on each one as it unblocks.
153+ </Card>
154+ <Card title="Agents that work as a team" art={<TeamArt className="w-full" />} tags={["Overlap", "Handoffs", "Questions", "People first"]}>
155+ Every agent is told what the others are changing. They open issues for what they find
156+ instead of widening their change, comment on each other's work, and defer to people.
157+ </Card>
158+ <Card title="Main only moves forward" art={<QueueArt className="w-full" />} tags={["Merge queue", "Speculative", "Contract checks"]}>
159+ Changes are tested together with whatever lands before them, against every check that
160+ ever passed. One that breaks goes back to its agent; main never sees it.
161+ </Card>
162+ <Card title="Why is this line here?" art={<WhyArt className="w-full" />} tags={["Why-blame", "Sessions", "Provenance"]} wide>
163+ Pick any line. g1t shows the commit that last changed it, the pull request and issue
164+ it came from, and the agent's own account of why: the reasoning stays with the code.
165+ </Card>
166+ <article className="rounded-3xl bg-surface p-7 ring-1 ring-line">
167+ <h3 className="text-lg font-semibold tracking-tight">And everything you expect</h3>
168+ <p className="mt-2 text-sm leading-6 text-muted">
169+ Work by hand exactly as you would on GitHub. Agents are a teammate you can assign,
170+ not a different way of working.
171+ </p>
172+ <Tags items={BASICS} />
173+ </article>
174+ </div>
175+ </section>
176+
177+ {/* How it flows */}
178+ <section className="border-y border-line bg-surface/40">
179+ <div className="mx-auto max-w-6xl px-4 py-24">
180+ <Eyebrow>How it flows</Eyebrow>
181+ <h2 className="mt-3 text-3xl font-semibold tracking-tight">From a sentence to main</h2>
182+ <ol className="relative mt-12 grid gap-6 md:grid-cols-5">
183+ <span
184+ aria-hidden="true"
185+ className="absolute top-4 right-8 left-8 hidden h-px bg-gradient-to-r from-merged/50 via-warn/50 to-accent/70 md:block"
186+ />
187+ {FLOW.map(([step, about], index) => (
188+ <li key={step} className="relative">
189+ <span
190+ className={`relative flex size-8 items-center justify-center rounded-full font-mono text-xs ring-1 ${
191+ index === FLOW.length - 1
192+ ? "bg-accent text-bg ring-accent"
193+ : "bg-bg text-fg-soft ring-line-strong"
194+ }`}
195+ >
196+ {index + 1}
197+ </span>
198+ <h3 className="mt-4 font-semibold">{step}</h3>
199+ <p className="mt-1.5 text-sm leading-6 text-muted">{about}</p>
200+ </li>
201+ ))}
202+ </ol>
192203 </div>
193204 </section>
194205
195206 {/* Connect */}
196− <section className="border-y border-line bg-surface/50">
197− <div className="mx-auto grid max-w-6xl items-center gap-12 px-4 py-24 lg:grid-cols-2">
198− <div>
199− <p className="text-sm font-medium text-accent">For agents</p>
200− <h2 className="mt-2 text-3xl font-semibold tracking-tight text-balance">
201− One command to put your agent to work
202− </h2>
203− <p className="mt-4 max-w-md leading-7 text-muted">
204− Add g1t to Claude Code and it can read the open issues, open a
205− pull request with a fork to push to, and record its session as it
206− goes. No plugin, no
207− wrapper.
208− </p>
209− <div className="mt-6">
210− <ButtonLink to="https://docs.g1t.sh/guides/bring-your-own-agent/" variant="quiet">
211− Connect an agent
212− <ArrowRight size={14} />
213− </ButtonLink>
214− </div>
215− </div>
216− <div className="space-y-3">
217− <CopyLine
218− prompt
219− text="claude mcp add --transport http g1t https://mcp.g1t.sh"
220− />
221− <CopyLine prompt text="git clone https://g1t.sh/syntaqx/g1t.git" />
222− <CopyLine
223− prompt
224− text="curl https://api.g1t.sh/repos/syntaqx/g1t/issues"
225− />
226− <div className="pt-2">
227− <EventsIllustration />
228− </div>
207+ <section className="mx-auto grid max-w-6xl items-center gap-12 px-4 py-24 lg:grid-cols-2">
208+ <div>
209+ <Eyebrow>Bring your own agent</Eyebrow>
210+ <h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance">
211+ Any agent joins the team with one command
212+ </h2>
213+ <p className="mt-4 max-w-md leading-7 text-muted">
214+ Add g1t to Claude Code and it can read the plan, take an issue, open a pull request
215+ with a fork to push to, see what the others are doing and record its session. g1t's
216+ own agents use the same tools.
217+ </p>
218+ <div className="mt-6">
219+ <ButtonLink to="https://docs.g1t.sh/guides/bring-your-own-agent/" variant="quiet">
220+ Connect an agent
221+ <ArrowRight size={14} />
222+ </ButtonLink>
229223 </div>
230224 </div>
225+ <div className="space-y-3">
226+ <CopyLine prompt text="claude mcp add --transport http g1t https://mcp.g1t.sh" />
227+ <CopyLine prompt text="git clone https://g1t.sh/syntaqx/g1t.git" />
228+ <CopyLine prompt text="curl https://api.g1t.sh/repos/syntaqx/g1t/queue" />
229+ </div>
231230 </section>
232231
233232 {/* Comparison */}
234− <section className="mx-auto max-w-6xl px-4 py-24">
235− <p className="text-sm font-medium text-accent">What changes</p>
236− <h2 className="mt-2 text-3xl font-semibold tracking-tight">
237− The same git. Built for more hands.
238− </h2>
239− <div className="mt-10 overflow-hidden rounded-2xl border border-line">
240− <div className="grid grid-cols-[1fr_1.4fr_1.4fr] border-b border-line bg-surface text-sm font-medium">
233+ <section className="mx-auto max-w-6xl px-4 pb-24">
234+ <Eyebrow>What changes</Eyebrow>
235+ <h2 className="mt-3 text-3xl font-semibold tracking-tight">The same git. A different job.</h2>
236+ <div className="mt-10 overflow-hidden rounded-3xl ring-1 ring-line">
237+ <div className="grid grid-cols-[1fr_1.3fr_1.6fr] bg-surface text-sm font-medium">
241238 <div className="px-5 py-3" />
242239 <div className="px-5 py-3 text-muted">A forge built for people</div>
243240 <div className="px-5 py-3 text-accent">g1t</div>
244241 </div>
245242 {COMPARISON.map(([topic, before, after]) => (
246− <div
247− key={topic}
248− className="grid grid-cols-[1fr_1.4fr_1.4fr] border-b border-line text-sm last:border-b-0"
249− >
243+ <div key={topic} className="grid grid-cols-[1fr_1.3fr_1.6fr] border-t border-line text-sm">
250244 <div className="px-5 py-4 font-medium">{topic}</div>
251245 <div className="px-5 py-4 text-muted">{before}</div>
252246 <div className="px-5 py-4">{after}</div>
255249 </div>
256250 </section>
257251
258− {/* Platform and repos */}
252+ {/* Open source */}
259253 <section className="mx-auto max-w-6xl px-4 pb-8">
260− <div className="rounded-2xl border border-line bg-surface p-8 text-center">
261− <h2 className="text-2xl font-semibold tracking-tight">
262− Open source, and built on itself
263− </h2>
264− <p className="mx-auto mt-3 max-w-xl text-muted">
265− g1t's own source lives on g1t. It runs entirely on Cloudflare's
266− developer platform.
254+ <div className="dusk relative overflow-hidden rounded-3xl p-10 text-center ring-1 ring-line">
255+ <h2 className="text-2xl font-semibold tracking-tight">Open source, and built on itself</h2>
256+ <p className="mx-auto mt-3 max-w-xl text-fg-soft/80">
257+ g1t's own source lives on g1t, and its changes land through its own queue. It runs
258+ entirely on Cloudflare's developer platform.
267259 </p>
268260 <ul className="mt-6 flex flex-wrap justify-center gap-2">
269261 {PLATFORM.map((name) => (
270− <li
271− key={name}
272− className="rounded-full border border-line bg-bg px-3 py-1 font-mono text-xs text-muted"
273− >
262+ <li key={name} className="rounded-full bg-bg/60 px-3 py-1 font-mono text-xs text-fg-soft ring-1 ring-white/10">
274263 {name}
275264 </li>
276265 ))}
288277 {repos.length > 0 && (
289278 <div className="mt-20">
290279 <div className="flex items-baseline justify-between">
291− <h2 className="text-sm font-medium text-muted">
292− Public repositories
293− </h2>
280+ <h2 className="text-sm font-medium text-muted">Public repositories</h2>
294281 <Link to="/explore" className="text-sm text-muted hover:text-fg">
295282 Explore all
296283 </Link>
+1−1
105105
106106 const BUTTON_VARIANTS: Record<Variant, string> = {
107107 primary: "bg-fg text-bg hover:bg-white",
108− accent: "bg-accent text-bg hover:bg-[#c6ff5c]",
108+ accent: "bg-accent text-bg hover:bg-[#aaf5d6]",
109109 quiet:
110110 "border border-line text-fg/80 hover:border-line-strong hover:bg-surface hover:text-fg",
111111 };
+1−1
332332 <head>
333333 <meta charSet="utf-8" />
334334 <meta name="viewport" content="width=device-width, initial-scale=1" />
335− <meta name="theme-color" content="#0e0d0a" />
335+ <meta name="theme-color" content="#0b0c18" />
336336 <Meta />
337337 <Links />
338338 </head>
+2−2
22 <rect width="32" height="32" rx="7" fill="#12110d"/>
33 <path d="M4 7h6c7 0 7 9 14 9" stroke="#8f8c82"/>
44 <path d="M4 25h6c7 0 7-9 14-9" stroke="#8f8c82"/>
5− <path d="M4 16h20" stroke="#b6f24a"/>
6− <circle cx="25" cy="16" r="3.5" fill="#b6f24a"/>
5+ <path d="M4 16h20" stroke="#86efc4"/>
6+ <circle cx="25" cy="16" r="3.5" fill="#86efc4"/>
77 </svg>
+19−18
88 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
99 --g1t-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1010
11− /* Warm near-black, three elevations. */
12− --g1t-bg: #0e0d0a;
13− --g1t-surface: #16150f;
14− --g1t-raised: #1e1c15;
15− --g1t-line: #2a2820;
16− --g1t-line-strong: #3a372d;
11+ /* Indigo night, three elevations: the sky after dusk. */
12+ --g1t-bg: #0b0c18;
13+ --g1t-surface: #121327;
14+ --g1t-raised: #1a1b33;
15+ --g1t-line: #252743;
16+ --g1t-line-strong: #363960;
1717
18− --g1t-fg: #f0eee6;
19− --g1t-fg-soft: #e2dfd4;
20− --g1t-muted: #a09c8f;
21− --g1t-faint: #6e6a5e;
18+ --g1t-fg: #eeedf8;
19+ --g1t-fg-soft: #dddcf0;
20+ --g1t-muted: #a3a2c3;
21+ --g1t-faint: #6c6c90;
2222
23− --g1t-accent: #b6f24a;
24− --g1t-accent-dim: #7fae2c;
25− --g1t-accent-low: #26330f;
23+ /* Mint: what is live, what passed, what was added. */
24+ --g1t-accent: #86efc4;
25+ --g1t-accent-dim: #4fb38e;
26+ --g1t-accent-low: #10302a;
2627
27− /* Status colours, used sparingly. */
28− --g1t-info: #7cc4ff;
29− --g1t-merged: #b9a2ff;
30− --g1t-warn: #f2c14a;
31− --g1t-danger: #ff7a6b;
28+ /* The dusk: lavender and peach, for art and for status. */
29+ --g1t-info: #8ab4ff;
30+ --g1t-merged: #b6a8ff;
31+ --g1t-warn: #ffbd8c;
32+ --g1t-danger: #ff8394;
3233 }