g1t/apps/web/app/components/landing.tsx

246 lines10,029 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

API and MCP server, Rust identity service, registration, site redesign1import { ArrowRight } from "lucide-react";
2import type { ReactNode } from "react";
3import { Link } from "react-router";
4
5import type { Repo } from "@g1t/contracts";
6
7import {
8 AgentsIllustration,
9 ArenaIllustration,
10 EventsIllustration,
11 ForkIllustration,
12 IntentIllustration,
13 SessionIllustration,
14 ShipIllustration,
15} from "./illustrations";
16import { RepoList } from "./repo-list";
17import { ButtonLink, CopyLine } from "./ui";
18
19function FeatureCard({
20 title,
21 illustration,
22 soon,
23 wide,
24 children,
25}: {
26 title: string;
27 illustration: ReactNode;
28 soon?: boolean;
29 wide?: boolean;
30 children: ReactNode;
31}) {
32 return (
33 <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"
36 }`}
37 >
38 <div className="border-b border-line bg-bg/40 px-6 pt-6">
39 <div className="mx-auto max-w-sm">{illustration}</div>
40 </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>
52 </article>
53 );
54}
55
56const COMPARISON: [string, string, string][] = [
57 ["Unit of work", "A pull request: one author, one change", "An intent: one goal, any number of attempts"],
58 ["Where agents work", "Branches and local worktrees", "A server-side fork per attempt"],
59 ["Why a change was made", "A commit message, if you are lucky", "The agent's full session, kept with the code"],
60 ["Connecting an agent", "A vendor integration", "Any MCP client, or plain HTTP"],
61];
62
63const PLATFORM = ["Workers", "Artifacts", "D1", "Queues", "Rust"];
64
65export function Landing({ repos }: { repos: Repo[] }) {
66 return (
67 <main>
68 {/* Hero */}
69 <section className="relative overflow-hidden border-b border-line">
70 <div
71 aria-hidden="true"
72 className="pointer-events-none absolute inset-x-0 top-0 h-[32rem] bg-[radial-gradient(60%_60%_at_50%_0%,color-mix(in_srgb,var(--color-accent)_9%,transparent),transparent)]"
73 />
74 <div className="relative mx-auto max-w-6xl px-4 pt-20 pb-10 text-center">
75 <Link
76 to="/docs/concepts"
77 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"
78 >
79 <span className="size-1.5 rounded-full bg-accent" />
80 Built on Cloudflare Workers and Artifacts
81 <ArrowRight size={12} />
82 </Link>
83 <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">
84 Many attempts.
85 <br />
86 <span className="text-accent">One ships.</span>
87 </h1>
88 <p className="mx-auto mt-6 max-w-xl animate-fade-up text-lg leading-7 text-muted text-balance">
89 g1t is a git forge built for agents. State a goal, let any number
90 of agents attempt it in parallel, each in its own fork, and land
91 the one that works.
92 </p>
93 <div className="mt-8 flex animate-fade-up flex-wrap items-center justify-center gap-3">
94 <ButtonLink to="/register" variant="accent" large>
95 Get started
96 <ArrowRight size={15} />
97 </ButtonLink>
98 <ButtonLink to="/docs" variant="quiet" large>
99 Read the docs
100 </ButtonLink>
101 </div>
102 <div className="mx-auto mt-14 max-w-5xl">
103 <ArenaIllustration />
104 </div>
105 </div>
106 </section>
107
108 {/* How it works */}
109 <section className="mx-auto max-w-6xl px-4 py-24">
110 <p className="text-sm font-medium text-accent">How it works</p>
111 <h2 className="mt-2 max-w-2xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
112 Pull requests assume one author. Agents arrive by the hundred.
113 </h2>
114 <div className="mt-12 grid gap-4 md:grid-cols-6">
115 <FeatureCard title="Start with an intent" illustration={<IntentIllustration />}>
116 Write the goal and the checks that prove it is done. An intent
117 replaces both the issue and the pull request.
118 </FeatureCard>
119 <FeatureCard title="A fork for every attempt" illustration={<ForkIllustration />}>
120 Each agent gets its own copy of the repository the moment it
121 starts. No branches to name, nothing to collide with.
122 </FeatureCard>
123 <FeatureCard title="The session stays with the code" illustration={<SessionIllustration />}>
124 Prompts, reasoning and tool calls are recorded against the attempt
125 and the commit they produced, so you can see why, not only what.
126 </FeatureCard>
127 <FeatureCard title="Bring any agent" illustration={<AgentsIllustration />} wide>
128 Claude Code and other MCP clients connect to mcp.g1t.sh with one
129 command. Everything is also a plain REST call at api.g1t.sh.
130 </FeatureCard>
131 <FeatureCard title="Ship through a queue" illustration={<ShipIllustration />} soon wide>
132 Pick the attempt that passes. A landing queue merges it into main
133 and brings the others up to date.
134 </FeatureCard>
135 </div>
136 </section>
137
138 {/* Connect */}
139 <section className="border-y border-line bg-surface/50">
140 <div className="mx-auto grid max-w-6xl items-center gap-12 px-4 py-24 lg:grid-cols-2">
141 <div>
142 <p className="text-sm font-medium text-accent">For agents</p>
143 <h2 className="mt-2 text-3xl font-semibold tracking-tight text-balance">
144 One command to put your agent to work
145 </h2>
146 <p className="mt-4 max-w-md leading-7 text-muted">
147 Add g1t to Claude Code and it can list intents, claim one, get a
148 fork to push to, and record its session as it goes. No plugin, no
149 wrapper.
150 </p>
151 <div className="mt-6">
152 <ButtonLink to="/docs/agents" variant="quiet">
153 Connect an agent
154 <ArrowRight size={14} />
155 </ButtonLink>
156 </div>
157 </div>
158 <div className="space-y-3">
159 <CopyLine
160 prompt
161 text='claude mcp add --transport http g1t https://mcp.g1t.sh --header "Authorization: Bearer $G1T_TOKEN"'
162 />
163 <CopyLine prompt text="git clone https://g1t.sh/syntaqx/g1t.git" />
164 <CopyLine
165 prompt
166 text="curl https://api.g1t.sh/v1/repos/syntaqx/g1t/intents"
167 />
168 <div className="pt-2">
169 <EventsIllustration />
170 </div>
171 </div>
172 </div>
173 </section>
174
175 {/* Comparison */}
176 <section className="mx-auto max-w-6xl px-4 py-24">
177 <p className="text-sm font-medium text-accent">What changes</p>
178 <h2 className="mt-2 text-3xl font-semibold tracking-tight">
179 The same git. Different primitives.
180 </h2>
181 <div className="mt-10 overflow-hidden rounded-2xl border border-line">
182 <div className="grid grid-cols-[1fr_1.4fr_1.4fr] border-b border-line bg-surface text-sm font-medium">
183 <div className="px-5 py-3" />
184 <div className="px-5 py-3 text-muted">A forge built for people</div>
185 <div className="px-5 py-3 text-accent">g1t</div>
186 </div>
187 {COMPARISON.map(([topic, before, after]) => (
188 <div
189 key={topic}
190 className="grid grid-cols-[1fr_1.4fr_1.4fr] border-b border-line text-sm last:border-b-0"
191 >
192 <div className="px-5 py-4 font-medium">{topic}</div>
193 <div className="px-5 py-4 text-muted">{before}</div>
194 <div className="px-5 py-4">{after}</div>
195 </div>
196 ))}
197 </div>
198 </section>
199
200 {/* Platform and repos */}
201 <section className="mx-auto max-w-6xl px-4 pb-8">
202 <div className="rounded-2xl border border-line bg-surface p-8 text-center">
203 <h2 className="text-2xl font-semibold tracking-tight">
204 Open source, and built on itself
205 </h2>
206 <p className="mx-auto mt-3 max-w-xl text-muted">
207 g1t's own source lives on g1t. It runs entirely on Cloudflare's
208 developer platform.
209 </p>
210 <ul className="mt-6 flex flex-wrap justify-center gap-2">
211 {PLATFORM.map((name) => (
212 <li
213 key={name}
214 className="rounded-full border border-line bg-bg px-3 py-1 font-mono text-xs text-muted"
215 >
216 {name}
217 </li>
218 ))}
219 </ul>
220 <div className="mt-8 flex flex-wrap justify-center gap-3">
221 <ButtonLink to="/syntaqx/g1t" variant="primary" large>
222 Browse the source
223 </ButtonLink>
224 <ButtonLink to="/register" variant="quiet" large>
225 Create an account
226 </ButtonLink>
227 </div>
228 </div>
229
230 {repos.length > 0 && (
231 <div className="mt-20">
232 <div className="flex items-baseline justify-between">
233 <h2 className="text-sm font-medium text-muted">
234 Public repositories
235 </h2>
236 <Link to="/explore" className="text-sm text-muted hover:text-fg">
237 Explore all
238 </Link>
239 </div>
240 <RepoList repos={repos.slice(0, 6)} />
241 </div>
242 )}
243 </section>
244 </main>
245 );
246}