g1t/apps/web/app/routes/home.tsx

160 lines6,004 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, Plus } from "lucide-react";
Workspaces own repositories2import { Link, redirect } from "react-router";
Initial g1t: services, event bus, intents and attempts3
4import type { Route } from "./+types/home";
API and MCP server, Rust identity service, registration, site redesign5import { Landing } from "../components/landing";
6import { RepoList } from "../components/repo-list";
7import {
8 Avatar,
9 ButtonLink,
10 CopyLine,
11 EmptyState,
12 Status,
13 TimeAgo,
14} from "../components/ui";
Work service in Rust, with RFC 3339 timestamps15import { repos as reposApi, work } from "../lib/services.server";
Initial g1t: services, event bus, intents and attempts16import { getViewer } from "../lib/session.server";
17
18export function meta({}: Route.MetaArgs) {
19 return [
Email verification, password reset, and Git for AI scale positioning20 { title: "g1t — Git for AI scale" },
Initial g1t: services, event bus, intents and attempts21 {
22 name: "description",
23 content:
Email verification, password reset, and Git for AI scale positioning24 "A git forge for thousands of agents working on the same code at once: every attempt isolated, every decision recorded, every change landed in order. Open source, built on Cloudflare.",
Initial g1t: services, event bus, intents and attempts25 },
26 ];
27}
28
29export async function loader({ context }: Route.LoaderArgs) {
30 const viewer = getViewer(context);
Workspaces own repositories31 // Nothing can be created outside a workspace, so a new account starts there.
32 if (viewer?.verified && (viewer.workspaces ?? []).length === 0) {
33 throw redirect("/workspaces/new");
34 }
Initial g1t: services, event bus, intents and attempts35 const [repos, attempts] = await Promise.all([
Workspaces own repositories36 reposApi.list(viewer, { memberOnly: Boolean(viewer) }),
Work service in Rust, with RFC 3339 timestamps37 work.listActiveAttempts(viewer),
Initial g1t: services, event bus, intents and attempts38 ]);
39 // Mission control links to each attempt under its repo.
40 const attemptRepos = await Promise.all(
Rust repos service with shipping; pull requests kept in the model41 attempts.map(({ attempt }) => reposApi.getById(attempt.repoId, viewer)),
Initial g1t: services, event bus, intents and attempts42 );
43 return {
44 viewer,
45 repos,
46 active: attempts.flatMap((item, i) => {
47 const repo = attemptRepos[i];
48 return repo.ok ? [{ ...item, repo: repo.value }] : [];
49 }),
50 };
51}
52
53export default function Home({ loaderData }: Route.ComponentProps) {
54 const { viewer, repos, active } = loaderData;
API and MCP server, Rust identity service, registration, site redesign55 if (!viewer) return <Landing repos={repos} />;
Initial g1t: services, event bus, intents and attempts56
API and MCP server, Rust identity service, registration, site redesign57 const working = active.filter(({ attempt }) => attempt.status === "working");
58 return (
59 <main className="mx-auto grid max-w-6xl gap-10 px-4 py-10 lg:grid-cols-[1fr_20rem]">
60 <div className="min-w-0 space-y-10">
Initial g1t: services, event bus, intents and attempts61 <section>
API and MCP server, Rust identity service, registration, site redesign62 <div className="flex items-center gap-3">
63 <Avatar name={viewer.username} size={36} />
64 <div>
65 <h1 className="text-xl font-semibold tracking-tight">
66 Mission control
67 </h1>
68 <p className="text-sm text-muted">
69 {working.length === 0
70 ? "Nothing is running right now."
71 : `${working.length} ${working.length === 1 ? "attempt is" : "attempts are"} running.`}
72 </p>
73 </div>
74 </div>
75 </section>
76
77 <section>
78 <h2 className="text-sm font-medium text-muted">In progress</h2>
79 <div className="mt-3">
80 {active.length === 0 ? (
81 <EmptyState title="No attempts in progress">
82 Open an intent on a repository and start an attempt, or point
83 your agent at one.
84 </EmptyState>
85 ) : (
86 <ul className="divide-y divide-line overflow-hidden rounded-xl border border-line bg-surface">
87 {active.map(({ attempt, intent, repo }) => (
88 <li key={attempt.id}>
89 <Link
90 to={`/${repo.namespace}/${repo.name}/attempts/${attempt.id}`}
91 className="flex items-center gap-4 px-4 py-3 transition-colors hover:bg-raised"
92 >
93 <span className="min-w-0 grow">
94 <span className="block truncate font-medium">
95 {intent.title}
96 </span>
97 <span className="font-mono text-xs text-muted">
98 {repo.namespace}/{repo.name} #{intent.number} · attempt{" "}
99 {attempt.number} · {attempt.agent}
100 </span>
101 </span>
102 <span className="shrink-0 text-xs text-faint">
103 <TimeAgo at={attempt.updatedAt} />
Initial g1t: services, event bus, intents and attempts104 </span>
API and MCP server, Rust identity service, registration, site redesign105 <Status value={attempt.status} />
106 </Link>
107 </li>
108 ))}
109 </ul>
110 )}
111 </div>
Initial g1t: services, event bus, intents and attempts112 </section>
API and MCP server, Rust identity service, registration, site redesign113
Initial g1t: services, event bus, intents and attempts114 <section>
API and MCP server, Rust identity service, registration, site redesign115 <div className="flex items-center justify-between">
116 <h2 className="text-sm font-medium text-muted">Your repositories</h2>
117 <ButtonLink to="/new" variant="quiet">
118 <Plus size={14} />
119 New
120 </ButtonLink>
121 </div>
Initial g1t: services, event bus, intents and attempts122 <RepoList repos={repos} />
123 </section>
API and MCP server, Rust identity service, registration, site redesign124 </div>
Initial g1t: services, event bus, intents and attempts125
API and MCP server, Rust identity service, registration, site redesign126 <aside className="space-y-4">
127 <div className="rounded-xl border border-line bg-surface p-5">
128 <h2 className="font-medium">Connect an agent</h2>
129 <p className="mt-1.5 text-sm text-muted">
130 Create an access token in settings, then add g1t to Claude Code.
131 </p>
132 <div className="mt-4 space-y-2">
133 <CopyLine
134 prompt
135 text='claude mcp add --transport http g1t https://mcp.g1t.sh --header "Authorization: Bearer $G1T_TOKEN"'
136 />
137 </div>
138 <Link
Docs as their own app; shared theme package139 to="https://docs.g1t.sh/guides/bring-your-own-agent/"
API and MCP server, Rust identity service, registration, site redesign140 className="mt-4 inline-flex items-center gap-1 text-sm text-accent hover:underline"
141 >
142 How it works <ArrowRight size={13} />
143 </Link>
144 </div>
145 <div className="rounded-xl border border-line bg-surface p-5">
146 <h2 className="font-medium">Explore</h2>
147 <p className="mt-1.5 text-sm text-muted">
148 Browse public repositories and the intents open on them.
149 </p>
150 <Link
151 to="/explore"
152 className="mt-3 inline-flex items-center gap-1 text-sm text-accent hover:underline"
153 >
154 Public repositories <ArrowRight size={13} />
155 </Link>
156 </div>
157 </aside>
Initial g1t: services, event bus, intents and attempts158 </main>
159 );
160}