g1t/apps/web/app/components/landing.tsx
| 1 | import { ArrowRight, Check, KeyRound, PackageCheck, ScrollText, ShieldCheck } from "lucide-react"; |
| 2 | import type { CSSProperties, ReactNode } from "react"; |
| 3 | import { Link } from "react-router"; |
| 4 | |
| 5 | import { type Provider, PROVIDERS } from "@g1t/contracts"; |
| 6 | |
| 7 | import { AgentSetup } from "./agent-setup"; |
| 8 | import { DeployArt, HeroArt, Live, PlanArt, QueueArt, TeamArt, WhyArt } from "./art"; |
| 9 | import { ProviderMark } from "./model-providers"; |
| 10 | import { ButtonLink, CopyLine } from "./ui"; |
| 11 | import { HAVE_AN_INVITE } from "../lib/invites"; |
| 12 | import { useInviteOnly } from "../lib/registration"; |
| 13 | |
| 14 | const DOCS = "https://docs.g1t.sh"; |
| 15 | |
| 16 | /** A small label above a heading, in the mono face. */ |
| 17 | function Eyebrow({ children }: { children: ReactNode }) { |
| 18 | return <p className="font-mono text-xs tracking-[0.2em] text-merged uppercase">{children}</p>; |
| 19 | } |
| 20 | |
| 21 | function Tags({ items }: { items: string[] }) { |
| 22 | return ( |
| 23 | <ul className="mt-6 flex flex-wrap gap-1.5"> |
| 24 | {items.map((item) => ( |
| 25 | <li |
| 26 | key={item} |
| 27 | 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" |
| 28 | > |
| 29 | {item} |
| 30 | </li> |
| 31 | ))} |
| 32 | </ul> |
| 33 | ); |
| 34 | } |
| 35 | |
| 36 | /** A link in running copy that leads to the docs or another page. */ |
| 37 | function More({ to, children }: { to: string; children: ReactNode }) { |
| 38 | return ( |
| 39 | <Link to={to} className="group mt-7 inline-flex items-center gap-1.5 text-sm font-medium text-fg hover:text-merged"> |
| 40 | {children} |
| 41 | <ArrowRight size={14} className="transition-transform group-hover:translate-x-0.5" /> |
| 42 | </Link> |
| 43 | ); |
| 44 | } |
| 45 | |
| 46 | /** A drawing in its own card, on the page's dark gray. */ |
| 47 | function ArtFrame({ children }: { children: ReactNode }) { |
| 48 | return ( |
| 49 | <Live className="relative overflow-hidden rounded-3xl bg-surface/60 px-4 py-6 ring-1 ring-line sm:px-8"> |
| 50 | <div |
| 51 | aria-hidden="true" |
| 52 | className="pointer-events-none absolute inset-x-0 -bottom-24 h-48 bg-[radial-gradient(50%_60%_at_50%_100%,rgb(182_168_255/0.08),transparent)]" |
| 53 | /> |
| 54 | <div className="relative mx-auto max-w-lg">{children}</div> |
| 55 | </Live> |
| 56 | ); |
| 57 | } |
| 58 | |
| 59 | /** |
| 60 | * One of the product's pillars: what it does, the features that prove it, |
| 61 | * and a drawing of the idea, on alternating sides. |
| 62 | */ |
| 63 | function Pillar({ |
| 64 | eyebrow, |
| 65 | title, |
| 66 | art, |
| 67 | points, |
| 68 | more, |
| 69 | flip, |
| 70 | children, |
| 71 | }: { |
| 72 | eyebrow: string; |
| 73 | title: string; |
| 74 | art: ReactNode; |
| 75 | points: string[]; |
| 76 | more: [string, string]; |
| 77 | flip?: boolean; |
| 78 | children: ReactNode; |
| 79 | }) { |
| 80 | return ( |
| 81 | <article className="grid items-center gap-10 py-14 lg:grid-cols-2 lg:gap-16"> |
| 82 | <div className={flip ? "lg:order-2" : undefined}> |
| 83 | <Eyebrow>{eyebrow}</Eyebrow> |
| 84 | <h3 className="mt-3 text-2xl font-semibold tracking-tight text-balance sm:text-3xl">{title}</h3> |
| 85 | <p className="mt-4 max-w-xl leading-7 text-muted">{children}</p> |
| 86 | <ul className="mt-6 grid gap-2.5 text-sm sm:grid-cols-2"> |
| 87 | {points.map((point) => ( |
| 88 | <li key={point} className="flex gap-2.5 text-fg-soft"> |
| 89 | <Check size={15} className="mt-0.5 shrink-0 text-merged" /> |
| 90 | <span>{point}</span> |
| 91 | </li> |
| 92 | ))} |
| 93 | </ul> |
| 94 | <More to={more[1]}>{more[0]}</More> |
| 95 | </div> |
| 96 | <div className={flip ? "lg:order-1" : undefined}> |
| 97 | <ArtFrame>{art}</ArtFrame> |
| 98 | </div> |
| 99 | </article> |
| 100 | ); |
| 101 | } |
| 102 | |
| 103 | /** Facts under the opening, each one true today. */ |
| 104 | const FACTS: [string, string][] = [ |
| 105 | ["$0", "for the forge: repositories, issues, pull requests and review. No card."], |
| 106 | ["+20%", "on what compute costs g1t. That is the whole markup, and there is no seat price."], |
| 107 | ["MCP", "connects Claude Code, Codex, OpenCode or Cursor to your workspace: one command or one config file."], |
| 108 | ["MIT", "licensed. g1t's own source lives on g1t and lands through its own queue."], |
| 109 | ]; |
| 110 | |
| 111 | const FLOW: [string, string][] = [ |
| 112 | ["Brief", "Write the outcome you want, in plain words, or open an issue as you always would."], |
| 113 | ["Plan", "A planner agent splits it into issues, each saying what done looks like, and the order they depend on."], |
| 114 | ["Agents", "Each issue gets an agent as it unblocks. They know what the others are changing, and tell each other."], |
| 115 | ["Review", "Checks run in clean sandboxes; a second agent reviews; you ask for changes and the agent makes them."], |
| 116 | ["Main", "The queue tests every change with what lands before it. Main moves only to what passed, and production follows."], |
| 117 | ]; |
| 118 | |
| 119 | /** The forge itself, for the people on the team. */ |
| 120 | const FORGE = [ |
| 121 | "Git over HTTPS", |
| 122 | "Public and private repositories", |
| 123 | "Issues and labels", |
| 124 | "Pull requests and forks", |
| 125 | "Line comments and reviews", |
| 126 | "Protected branches", |
| 127 | "Required approvals", |
| 128 | "Workspaces and roles", |
| 129 | "Profiles", |
| 130 | "Search and Explore", |
| 131 | "Webhooks", |
| 132 | "Import from any git host", |
| 133 | "REST API and OpenAPI", |
| 134 | "MCP server", |
| 135 | "OAuth sign-in", |
| 136 | ]; |
| 137 | |
| 138 | const SECURE: { icon: ReactNode; title: string; about: string; to: string }[] = [ |
| 139 | { |
| 140 | icon: <ShieldCheck size={18} />, |
| 141 | title: "Push protection", |
| 142 | about: "A push that adds a key or a token is refused before it lands, and the history is scanned for ones already there.", |
| 143 | to: `${DOCS}/guides/security/`, |
| 144 | }, |
| 145 | { |
| 146 | icon: <PackageCheck size={18} />, |
| 147 | title: "Dependency upkeep", |
| 148 | about: "Each vulnerable dependency that has a fixed version becomes an upgrade issue, and an agent lands the upgrade through the same checks as any change.", |
| 149 | to: `${DOCS}/guides/security/#dependency-upkeep`, |
| 150 | }, |
| 151 | { |
| 152 | icon: <KeyRound size={18} />, |
| 153 | title: "Guardrails and credentials", |
| 154 | about: "What an agent may reach, run and spend is enforced outside its sandbox. Each run gets its own credential; your model keys never reach it.", |
| 155 | to: `${DOCS}/guides/guardrails/`, |
| 156 | }, |
| 157 | { |
| 158 | icon: <ScrollText size={18} />, |
| 159 | title: "Audit log on every workspace", |
| 160 | about: "Every action by people, tokens and agents, with whether it was allowed and the rule that decided. Kept 90 days on the plan and 7 free, with export.", |
| 161 | to: `${DOCS}/guides/audit-log/`, |
| 162 | }, |
| 163 | ]; |
| 164 | |
| 165 | /** The systems g1t connects to, shown on the landing page. */ |
| 166 | const STACK: Provider[] = [ |
| 167 | "anthropic", |
| 168 | "openai", |
| 169 | "gemini", |
| 170 | "xai", |
| 171 | "mistral", |
| 172 | "deepseek", |
| 173 | "azure_openai", |
| 174 | "openrouter", |
| 175 | "groq", |
| 176 | "sentry", |
| 177 | "jira", |
| 178 | "linear", |
| 179 | ]; |
| 180 | |
| 181 | /** What happens to a production error once Sentry is connected. */ |
| 182 | const LOOP = [ |
| 183 | "Sentry: TypeError in checkout", |
| 184 | "g1t opens an issue, with the stack trace", |
| 185 | "An agent fixes it; another reviews it", |
| 186 | "The merge queue lands it on main", |
| 187 | "Sentry marks the error resolved", |
| 188 | ]; |
| 189 | |
| 190 | const PRICES: { name: string; price: string; unit?: string; about: string }[] = [ |
| 191 | { |
| 192 | name: "The forge", |
| 193 | price: "$0", |
| 194 | about: "Public and private repositories, git, issues, pull requests, reviews, search and the audit log. No card.", |
| 195 | }, |
| 196 | { |
| 197 | name: "The g1t plan", |
| 198 | price: "$20", |
| 199 | unit: "a month per workspace", |
| 200 | about: "$10 of usage included. Unlimited members. Agents, checks, the merge queue and deployments.", |
| 201 | }, |
| 202 | { |
| 203 | name: "Usage", |
| 204 | price: "Cost + 20%", |
| 205 | about: "Past what is included, everything is priced at what it costs g1t plus 20%, under a spend limit you set.", |
| 206 | }, |
| 207 | ]; |
| 208 | |
| 209 | const PLATFORM = ["Workers", "Artifacts", "Containers", "D1", "Queues", "Durable Objects", "AI Gateway", "Rust"]; |
| 210 | |
| 211 | /** |
| 212 | * The signed-out home page: what g1t is, what it does, and how to start. |
| 213 | * It lists no one's repositories; those are a click away under Explore. |
| 214 | */ |
| 215 | export function Landing() { |
| 216 | const inviteOnly = useInviteOnly(); |
| 217 | return ( |
| 218 | <main className="overflow-x-clip"> |
| 219 | {/* The opening. */} |
| 220 | <section className="dusk relative"> |
| 221 | <div |
| 222 | aria-hidden="true" |
| 223 | className="dusk-planet pointer-events-none absolute -top-[30rem] left-1/2 size-[60rem] -translate-x-[10%] rounded-full" |
| 224 | /> |
| 225 | <div className="relative mx-auto max-w-6xl px-4 pt-20 text-center sm:pt-24"> |
| 226 | <Link |
| 227 | to={`${DOCS}/concepts/overview/`} |
| 228 | 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" |
| 229 | > |
| 230 | <span className="size-1.5 rounded-full bg-merged" /> |
| 231 | Open source · built on Cloudflare |
| 232 | <ArrowRight size={12} /> |
| 233 | </Link> |
| 234 | <h1 className="mx-auto mt-7 max-w-4xl animate-fade-up text-[2.75rem] leading-[1.04] font-semibold tracking-tight text-balance sm:text-7xl"> |
| 235 | Where people and agents{" "} |
| 236 | <span className="bg-gradient-to-r from-fg via-[#d9d1ff] to-merged bg-clip-text text-transparent"> |
| 237 | ship software together. |
| 238 | </span> |
| 239 | </h1> |
| 240 | <p className="mx-auto mt-7 max-w-2xl animate-fade-up text-lg leading-8 text-fg-soft/80 text-balance"> |
| 241 | g1t is the git platform for the whole job. Plan in issues, assign work to agents like |
| 242 | teammates, land it through checks that hold, and deploy every change to the edge. Open |
| 243 | source, and priced at what it costs. |
| 244 | </p> |
| 245 | <div className="mt-9 flex animate-fade-up flex-wrap items-center justify-center gap-3"> |
| 246 | <ButtonLink to="/register" variant="primary" large> |
| 247 | {inviteOnly ? "Request access" : "Start for free"} |
| 248 | <ArrowRight size={15} /> |
| 249 | </ButtonLink> |
| 250 | {inviteOnly ? ( |
| 251 | <ButtonLink to={HAVE_AN_INVITE} variant="quiet" large> |
| 252 | Have an invite? |
| 253 | </ButtonLink> |
| 254 | ) : ( |
| 255 | <ButtonLink to="#how" variant="quiet" large> |
| 256 | See how it works |
| 257 | </ButtonLink> |
| 258 | )} |
| 259 | </div> |
| 260 | <p className="mx-auto mt-5 max-w-xl animate-fade-up text-sm text-fg-soft/60 text-balance"> |
| 261 | {inviteOnly |
| 262 | ? "g1t is invite-only while we open it up. The forge is free, with no card; agents and checks start with a trial after a card check, and deployments come with the g1t plan." |
| 263 | : "The forge is free, with no card. Agents and checks start with a trial after a card check; deployments come with the g1t plan."} |
| 264 | </p> |
| 265 | </div> |
| 266 | <Live className="relative mx-auto max-w-6xl px-2 pt-6 pb-2 sm:px-4"> |
| 267 | <HeroArt className="w-full" /> |
| 268 | </Live> |
| 269 | <div aria-hidden="true" className="h-16 bg-gradient-to-b from-transparent to-bg" /> |
| 270 | </section> |
| 271 | |
| 272 | {/* Facts, each one true today. Above the hero's fade, with a border of |
| 273 | its own: a ring is a shadow, and the fade drew over its top edge. */} |
| 274 | <section className="relative z-10 mx-auto max-w-6xl px-4"> |
| 275 | <dl className="grid gap-px overflow-hidden rounded-2xl border border-line bg-line sm:grid-cols-2 lg:grid-cols-4"> |
| 276 | {FACTS.map(([figure, about]) => ( |
| 277 | <div key={figure} className="bg-bg px-6 py-6"> |
| 278 | <dt className="font-mono text-2xl font-medium tracking-tight text-fg">{figure}</dt> |
| 279 | <dd className="mt-2 text-sm leading-6 text-muted">{about}</dd> |
| 280 | </div> |
| 281 | ))} |
| 282 | </dl> |
| 283 | </section> |
| 284 | |
| 285 | {/* The pillars. */} |
| 286 | <section className="mx-auto max-w-6xl px-4 pt-24"> |
| 287 | <div className="max-w-3xl"> |
| 288 | <Eyebrow>One place, idea to production</Eyebrow> |
| 289 | <h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance sm:text-5xl"> |
| 290 | Everything between an idea and the people using it. |
| 291 | </h2> |
| 292 | <p className="mt-5 max-w-2xl text-lg leading-8 text-muted"> |
| 293 | Agents are members of the forge, not a tool beside it. They take issues, review, answer |
| 294 | each other and fix what fails, under the same rules, records and review as everyone |
| 295 | else. |
| 296 | </p> |
| 297 | </div> |
| 298 | |
| 299 | <div className="mt-6 divide-y divide-line"> |
| 300 | <Pillar |
| 301 | eyebrow="Agents as teammates" |
| 302 | title="Assign an agent like anyone on the team" |
| 303 | art={<TeamArt className="w-full" />} |
| 304 | points={[ |
| 305 | "Assign an issue, or @mention g1t anywhere", |
| 306 | "Told what the others are changing while they work", |
| 307 | "Agents ask each other, and ask you, through the forge", |
| 308 | "Steer a run while it works, or stop it", |
| 309 | "Memory per project and per workspace", |
| 310 | "Your own agent over MCP, its session on the pull request", |
| 311 | ]} |
| 312 | more={["How g1t works on issues", `${DOCS}/guides/working-with-g1t/`]} |
| 313 | > |
| 314 | Every agent works in its own sandbox and its own fork. It sees what is in flight, files |
| 315 | what it finds instead of widening its change, comments on the work of others, and |
| 316 | defers to people. |
| 317 | </Pillar> |
| 318 | |
| 319 | <Pillar |
| 320 | flip |
| 321 | eyebrow="Outcomes" |
| 322 | title="Hand off an outcome, not just a task" |
| 323 | art={<PlanArt className="w-full" />} |
| 324 | points={[ |
| 325 | "A brief planned into issues with dependencies", |
| 326 | "Your workflows' required checks on every change", |
| 327 | "Work starts as each dependency lands", |
| 328 | "The plan as a live graph, with its cost", |
| 329 | ]} |
| 330 | more={["Hand off an outcome", `${DOCS}/guides/outcomes/`]} |
| 331 | > |
| 332 | Write what should be true. A planner turns it into issues, each saying what done looks |
| 333 | like, and the order they depend on. Agents take each issue as it unblocks, and you |
| 334 | watch the whole outcome converge. |
| 335 | </Pillar> |
| 336 | |
| 337 | <Pillar |
| 338 | eyebrow="Ship safely" |
| 339 | title="Main only moves to what passed" |
| 340 | art={<QueueArt className="w-full" />} |
| 341 | points={[ |
| 342 | "Checks run by g1t in a clean sandbox", |
| 343 | "Workflows in GitHub Actions syntax", |
| 344 | "A merge queue that tests changes together", |
| 345 | "Conflicts found on every push, before a merge", |
| 346 | "Catch up with main in seconds", |
| 347 | "Reviews by people and by agents", |
| 348 | ]} |
| 349 | more={["The merge queue", `${DOCS}/guides/merge-queue/`]} |
| 350 | > |
| 351 | Checks are run by g1t, never by the agent being checked. The queue tests each change |
| 352 | together with what lands ahead of it; one that breaks goes back to its author with what |
| 353 | failed, and main never sees it. |
| 354 | </Pillar> |
| 355 | |
| 356 | <Pillar |
| 357 | flip |
| 358 | eyebrow="Context" |
| 359 | title="Every line knows why it is there" |
| 360 | art={<WhyArt className="w-full" />} |
| 361 | points={[ |
| 362 | "Sessions recorded onto pull requests", |
| 363 | "Why-blame on any line", |
| 364 | "A context hub agents search before they start", |
| 365 | "Search across code, issues and people", |
| 366 | ]} |
| 367 | more={["Sessions and why-blame", `${DOCS}/guides/why-blame/`]} |
| 368 | > |
| 369 | Pick any line. g1t shows the commit that changed it, the pull request and issue it came |
| 370 | from, and the agent's own session: what it read, ran and decided. The reasoning stays |
| 371 | with the code, for people and for the next agent. |
| 372 | </Pillar> |
| 373 | |
| 374 | <Pillar |
| 375 | eyebrow="Run it" |
| 376 | title="Every change, live on the edge" |
| 377 | art={<DeployArt className="w-full" />} |
| 378 | points={[ |
| 379 | "A live preview for every pull request", |
| 380 | "Production on every merge to main", |
| 381 | "Custom domains, with certificates", |
| 382 | "Projects that depend on each other", |
| 383 | ]} |
| 384 | more={["Deployments", `${DOCS}/guides/deployments/`]} |
| 385 | > |
| 386 | Turn on deployments and every pull request gets its own address on g1t.page; merging |
| 387 | ships production. Reviewers, and the agents reviewing for you, click through a change |
| 388 | instead of reading a diff. An app nobody visits runs nothing and costs nothing. |
| 389 | </Pillar> |
| 390 | </div> |
| 391 | </section> |
| 392 | |
| 393 | {/* How it flows */} |
| 394 | <section id="how" className="scroll-mt-20 border-y border-line bg-surface/40"> |
| 395 | <div className="mx-auto max-w-6xl px-4 py-24"> |
| 396 | <Eyebrow>How it flows</Eyebrow> |
| 397 | <h2 className="mt-3 text-3xl font-semibold tracking-tight">From a sentence to main</h2> |
| 398 | <Live> |
| 399 | <ol className="relative mt-12 grid gap-6 md:grid-cols-5"> |
| 400 | {/* From the first step's dot to the last one's, and no further: five |
| 401 | columns with 1.5rem gaps put the last dot 1rem into the last |
| 402 | column, so the line stops one column, less that, from the end. */} |
| 403 | <span |
| 404 | aria-hidden="true" |
| 405 | className="absolute top-4 right-[calc((100%-6rem)/5-1rem)] left-4 hidden h-px bg-gradient-to-r from-merged/50 via-warn/50 to-accent/70 md:block" |
| 406 | > |
| 407 | <span className="flow-runner absolute inset-0"> |
| 408 | <span className="absolute -top-[3px] -left-[3.5px] size-[7px] rounded-full bg-merged shadow-[0_0_12px_2px_rgb(182_168_255/0.6)]" /> |
| 409 | </span> |
| 410 | </span> |
| 411 | {FLOW.map(([step, about], index) => ( |
| 412 | <li key={step} className="relative"> |
| 413 | <span |
| 414 | className={`flow-step relative flex size-8 items-center justify-center rounded-full font-mono text-xs ring-1 ${ |
| 415 | index === FLOW.length - 1 ? "bg-accent text-bg ring-accent" : "bg-bg text-fg-soft ring-line-strong" |
| 416 | }`} |
| 417 | style={{ "--delay": `${index * 2}s` } as CSSProperties} |
| 418 | > |
| 419 | {index + 1} |
| 420 | </span> |
| 421 | <h3 className="mt-4 font-semibold">{step}</h3> |
| 422 | <p className="mt-1.5 text-sm leading-6 text-muted">{about}</p> |
| 423 | </li> |
| 424 | ))} |
| 425 | </ol> |
| 426 | </Live> |
| 427 | </div> |
| 428 | </section> |
| 429 | |
| 430 | {/* The forge, for people. */} |
| 431 | <section className="mx-auto max-w-6xl px-4 py-24"> |
| 432 | <div className="grid gap-10 lg:grid-cols-[1fr_1.2fr] lg:gap-16"> |
| 433 | <div> |
| 434 | <Eyebrow>Collaborate</Eyebrow> |
| 435 | <h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance"> |
| 436 | A complete forge for the people on your team |
| 437 | </h2> |
| 438 | <p className="mt-4 max-w-md leading-7 text-muted"> |
| 439 | Issues, branches, pull requests and reviews, the way your team already works, with |
| 440 | agents as members alongside you. Work by hand, hand work off, or both on the same |
| 441 | issue. |
| 442 | </p> |
| 443 | <More to={`${DOCS}/concepts/overview/`}>How g1t works</More> |
| 444 | </div> |
| 445 | <div className="rounded-3xl bg-surface p-7 ring-1 ring-line"> |
| 446 | <p className="text-sm font-medium">Included in every workspace</p> |
| 447 | <Tags items={FORGE} /> |
| 448 | </div> |
| 449 | </div> |
| 450 | </section> |
| 451 | |
| 452 | {/* Secure by default */} |
| 453 | <section className="mx-auto max-w-6xl px-4 pb-24"> |
| 454 | <Eyebrow>Secure by default</Eyebrow> |
| 455 | <h2 className="mt-3 max-w-2xl text-3xl font-semibold tracking-tight text-balance"> |
| 456 | Safe to hand the work to, and healthy without anyone watching |
| 457 | </h2> |
| 458 | <div className="mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-4"> |
| 459 | {SECURE.map((item) => ( |
| 460 | <Link |
| 461 | key={item.title} |
| 462 | to={item.to} |
| 463 | className="group rounded-2xl bg-surface p-6 ring-1 ring-line transition-colors hover:ring-line-strong" |
| 464 | > |
| 465 | <span className="flex size-9 items-center justify-center rounded-lg bg-bg text-merged ring-1 ring-line">{item.icon}</span> |
| 466 | <h3 className="mt-5 font-semibold">{item.title}</h3> |
| 467 | <p className="mt-2 text-sm leading-6 text-muted">{item.about}</p> |
| 468 | </Link> |
| 469 | ))} |
| 470 | </div> |
| 471 | </section> |
| 472 | |
| 473 | {/* Connect */} |
| 474 | <section className="border-y border-line bg-surface/40"> |
| 475 | <div className="mx-auto grid max-w-6xl items-center gap-12 px-4 py-24 lg:grid-cols-2"> |
| 476 | <div> |
| 477 | <Eyebrow>Bring your own agent</Eyebrow> |
| 478 | <h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance"> |
| 479 | Any agent that speaks MCP joins the team |
| 480 | </h2> |
| 481 | <p className="mt-4 max-w-md leading-7 text-muted"> |
| 482 | Add g1t to Claude Code, Codex, OpenCode or Cursor and it can read the plan, take an |
| 483 | issue, open a pull request with a fork to push to, and see what the others are doing. |
| 484 | Install the hook in Claude Code and its session is recorded onto the pull request as |
| 485 | it works. g1t's own agents use the same tools. |
| 486 | </p> |
| 487 | <p className="mt-4 max-w-md leading-7 text-muted"> |
| 488 | Every action is a REST route and an MCP tool, with an OpenAPI document and signed |
| 489 | webhooks for every event. |
| 490 | </p> |
| 491 | <div className="mt-6 flex flex-wrap gap-3"> |
| 492 | <ButtonLink to={`${DOCS}/guides/bring-your-own-agent/`} variant="quiet"> |
| 493 | Connect an agent |
| 494 | <ArrowRight size={14} /> |
| 495 | </ButtonLink> |
| 496 | <ButtonLink to={`${DOCS}/reference/api/`} variant="quiet"> |
| 497 | API reference |
| 498 | </ButtonLink> |
| 499 | </div> |
| 500 | </div> |
| 501 | <div className="space-y-3"> |
| 502 | <AgentSetup /> |
| 503 | <CopyLine prompt text="curl -fsSL https://g1t.sh/install/claude.sh | sh" /> |
| 504 | <CopyLine prompt text="git clone https://g1t.sh/flagon-io/g1t.git" /> |
| 505 | <CopyLine prompt text="curl https://api.g1t.sh/repos/flagon-io/g1t/queue" /> |
| 506 | </div> |
| 507 | </div> |
| 508 | </section> |
| 509 | |
| 510 | {/* Your stack */} |
| 511 | <section className="mx-auto grid max-w-6xl items-center gap-12 px-4 py-24 lg:grid-cols-2"> |
| 512 | <div className="lg:order-2"> |
| 513 | <Eyebrow>Your stack</Eyebrow> |
| 514 | <h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance"> |
| 515 | Your models. Your alerts. Your tickets. |
| 516 | </h2> |
| 517 | <p className="mt-4 max-w-md leading-7 text-muted"> |
| 518 | Run g1t's agents on g1t's models, or on your own accounts with any of the labs and |
| 519 | platforms, and choose which model does which work. Keys stay with g1t: an agent's |
| 520 | sandbox only ever holds a token for its own run. |
| 521 | </p> |
| 522 | <p className="mt-4 max-w-md leading-7 text-muted"> |
| 523 | Connect Sentry and a new error becomes an issue, an agent fixes it, and Sentry hears it |
| 524 | was resolved. Mention TECH-1234 and the agent reads the Jira ticket. |
| 525 | </p> |
| 526 | <More to={`${DOCS}/guides/integrations/`}>See the integrations</More> |
| 527 | </div> |
| 528 | <div className="space-y-6 lg:order-1"> |
| 529 | <div className="grid grid-cols-3 gap-2 sm:grid-cols-4"> |
| 530 | {STACK.map((provider) => ( |
| 531 | <div |
| 532 | key={provider} |
| 533 | className="flex flex-col items-center gap-2 rounded-xl bg-surface px-2 py-3 ring-1 ring-line" |
| 534 | title={PROVIDERS[provider].label} |
| 535 | > |
| 536 | <ProviderMark provider={provider} size={30} /> |
| 537 | <span className="w-full text-center text-xs leading-tight text-muted">{PROVIDERS[provider].label}</span> |
| 538 | </div> |
| 539 | ))} |
| 540 | </div> |
| 541 | <ol className="space-y-2 font-mono text-[0.8125rem]"> |
| 542 | {LOOP.map((step, index) => ( |
| 543 | <li key={step} className="flex items-center gap-3 text-fg-soft"> |
| 544 | <span className="flex size-6 shrink-0 items-center justify-center rounded-full bg-surface text-xs text-faint ring-1 ring-line"> |
| 545 | {index + 1} |
| 546 | </span> |
| 547 | {step} |
| 548 | </li> |
| 549 | ))} |
| 550 | </ol> |
| 551 | </div> |
| 552 | </section> |
| 553 | |
| 554 | {/* Pricing, in one band. */} |
| 555 | <section className="mx-auto max-w-6xl px-4 pb-24"> |
| 556 | <div className="flex flex-wrap items-end justify-between gap-6"> |
| 557 | <div> |
| 558 | <Eyebrow>Pricing</Eyebrow> |
| 559 | <h2 className="mt-3 max-w-2xl text-3xl font-semibold tracking-tight text-balance"> |
| 560 | What it costs to run, plus 20%. Never per seat. |
| 561 | </h2> |
| 562 | </div> |
| 563 | <More to="/pricing">See every price</More> |
| 564 | </div> |
| 565 | <div className="mt-10 grid gap-px overflow-hidden rounded-3xl bg-line ring-1 ring-line md:grid-cols-3"> |
| 566 | {PRICES.map((item) => ( |
| 567 | <div key={item.name} className="bg-surface p-7"> |
| 568 | <p className="text-sm text-muted">{item.name}</p> |
| 569 | <p className="mt-3 flex flex-wrap items-baseline gap-x-2"> |
| 570 | <span className="text-3xl font-semibold tracking-tight">{item.price}</span> |
| 571 | {item.unit && <span className="text-sm text-muted">{item.unit}</span>} |
| 572 | </p> |
| 573 | <p className="mt-3 text-sm leading-6 text-muted">{item.about}</p> |
| 574 | </div> |
| 575 | ))} |
| 576 | </div> |
| 577 | </section> |
| 578 | |
| 579 | {/* Open source */} |
| 580 | <section className="mx-auto max-w-6xl px-4 pb-24"> |
| 581 | <div className="grid gap-10 rounded-3xl bg-surface p-8 ring-1 ring-line sm:p-10 lg:grid-cols-[1.3fr_1fr]"> |
| 582 | <div> |
| 583 | <Eyebrow>Open source</Eyebrow> |
| 584 | <h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance">Open, and built on itself</h2> |
| 585 | <p className="mt-4 max-w-xl leading-7 text-muted"> |
| 586 | g1t is MIT licensed. Its own source lives on g1t, and its changes land through its own |
| 587 | merge queue. Your code is plain git: leaving is a <code className="font-mono text-fg-soft">git clone</code>. |
| 588 | </p> |
| 589 | <p className="mt-4 max-w-xl leading-7 text-muted"> |
| 590 | You can run the core forge yourself with Docker Compose today: accounts, repositories, |
| 591 | issues, pull requests and search. It is an early version, and agents, deployments and |
| 592 | context search still run only on g1t.sh. |
| 593 | </p> |
| 594 | <div className="mt-7 flex flex-wrap gap-3"> |
| 595 | <ButtonLink to="/flagon-io/g1t" variant="quiet"> |
| 596 | Browse the source |
| 597 | </ButtonLink> |
| 598 | <ButtonLink to={`${DOCS}/guides/self-hosting/`} variant="quiet"> |
| 599 | Run g1t yourself |
| 600 | </ButtonLink> |
| 601 | </div> |
| 602 | </div> |
| 603 | <div className="flex flex-col justify-between gap-6"> |
| 604 | <div> |
| 605 | <p className="text-sm font-medium">Built on Cloudflare</p> |
| 606 | <ul className="mt-4 flex flex-wrap gap-2"> |
| 607 | {PLATFORM.map((name) => ( |
| 608 | <li key={name} className="rounded-full bg-bg/60 px-3 py-1 font-mono text-xs text-fg-soft ring-1 ring-line"> |
| 609 | {name} |
| 610 | </li> |
| 611 | ))} |
| 612 | </ul> |
| 613 | </div> |
| 614 | <p className="text-sm leading-6 text-muted"> |
| 615 | g1t is made by Flagon, Inc., a small, independent software company. |
| 616 | </p> |
| 617 | </div> |
| 618 | </div> |
| 619 | </section> |
| 620 | |
| 621 | {/* The close. */} |
| 622 | <section className="mx-auto max-w-6xl px-4 pb-8"> |
| 623 | <div className="dusk relative overflow-hidden rounded-3xl px-6 py-16 text-center ring-1 ring-line"> |
| 624 | <h2 className="mx-auto max-w-2xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl"> |
| 625 | Bring your team. Bring your agents. |
| 626 | </h2> |
| 627 | <p className="mx-auto mt-4 max-w-xl text-fg-soft/80 text-balance"> |
| 628 | Create a workspace in a minute and push your first repository. The forge is free; start |
| 629 | the plan when you want agents and deployments. |
| 630 | </p> |
| 631 | <div className="mt-8 flex flex-wrap justify-center gap-3"> |
| 632 | <ButtonLink to="/register" variant="primary" large> |
| 633 | {inviteOnly ? "Request access" : "Create your workspace"} |
| 634 | <ArrowRight size={15} /> |
| 635 | </ButtonLink> |
| 636 | {inviteOnly && ( |
| 637 | <ButtonLink to={HAVE_AN_INVITE} variant="quiet" large> |
| 638 | Have an invite? |
| 639 | </ButtonLink> |
| 640 | )} |
| 641 | <ButtonLink to={`${DOCS}/quickstart/`} variant="quiet" large> |
| 642 | Read the quickstart |
| 643 | </ButtonLink> |
| 644 | </div> |
| 645 | </div> |
| 646 | </section> |
| 647 | </main> |
| 648 | ); |
| 649 | } |