Skip to content
1,204 linesCodeBlameRaw

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.

Mission control: a place to ask g1t, shown and not on yet, with the actions under it1import { ArrowDownWideNarrow, ArrowRight, ArrowUpRight, Check, ChevronDown, ChevronRight, ListTree, Plus, Sparkles } from "lucide-react";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look2import { type ReactNode, useEffect, useState } from "react";
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms3import { Link, useFetcher, useRouteLoaderData, useSearchParams } from "react-router";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look4
5import { trialClosed } from "../lib/trial";
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms6import { type ActivityGroup, type Verb, greetingFor, isAgent } from "../lib/mission";
7import {
8 BLOCKING,
9 type Fact,
10 type LandedRow,
11 type NeedRow,
12 type QuickAction,
13 REASON_LABEL,
14 type Reason,
15 type Sort,
16 type Tab,
17 type WaitingRow,
18 type Week,
19 type Who,
20 change,
21 dateLine,
22 parseSort,
23 parseTab,
24 signedPercent,
25 sortRows,
26 usd,
27 whyFor,
28} from "../lib/mission-control";
29import { cn } from "../lib/cn";
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step30import { AgentComposer, type ComposerResult } from "./agent-composer";
Mission control: a place to ask g1t, shown and not on yet, with the actions under it31import { AskComposer } from "./ask-composer";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look32import { AgentSetup } from "./agent-setup";
Inbox: a bell in the top bar opens it beside the page, and /inbox holds it all33import { InboxNeedsCard } from "./inbox";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look34import type { ShellData } from "./shell";
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms35import { useLiveRefresh } from "./agents";
36import { Unavailable } from "./mission";
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix37import { TokenUsagePanel } from "./token-usage";
Merge branch 'worktree-agent-a985c01f43538af01'38import { Avatar, SubmitButton, TimeAgo } from "./ui";
Merge branch 'worktree-agent-ae1299e92e4462012'39import { Hint } from "./ui/hint";
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms40import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger } from "./ui/dropdown-menu";
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look41import type { Loaded } from "../routes/home";
42
43/*
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms44 * Mission control: the home page of someone signed in. It answers where
45 * the viewer is needed, what agents are doing, and what landed without
46 * them. It is a chunk of its own, loaded only for them, so the signed-out
47 * home page does not carry it. routes/home.tsx loads its data;
48 * lib/mission-control.ts shapes it.
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look49 */
50
51/** The viewer's time zone, set by the page itself, so the greeting fits their day. */
52const TZ_COOKIE = "g1t_tz";
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms53/** Rows a tab shows before "See all". */
54const ROWS = 6;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look55
56const dollars = (micros: number) => `$${(Math.max(0, micros) / 1_000_000).toFixed(2)}`;
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms57const plural = (n: number, one: string, many = `${one}s`) => `${n.toLocaleString("en-US")} ${n === 1 ? one : many}`;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look58
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms59// --- Small pieces -----------------------------------------------------------------
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look60
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms61const CHIP_TONE: Record<Reason, string> = {
62 blocking: "border-danger/35 bg-danger/10 text-danger",
63 checks_failing: "border-danger/35 bg-danger/10 text-danger",
64 outside_guardrails: "border-warn/35 bg-warn/10 text-warn",
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step65 low_confidence: "border-warn/35 bg-warn/10 text-warn",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms66 stalled: "border-warn/35 bg-warn/10 text-warn",
Merge branch 'worktree-agent-ad7c6d88d93adc817'67 asked_for_you: "border-accent/35 bg-accent/10 text-accent",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms68 needs_review: "border-info/35 bg-info/10 text-info",
Merge branch 'worktree-agent-ad7c6d88d93adc817'69 ready_to_merge: "border-success/35 bg-success/10 text-success",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms70};
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look71
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms72function Chip({ children, tone }: { children: ReactNode; tone: string }) {
73 return (
74 <span
75 className={cn(
76 "inline-flex shrink-0 items-center rounded border px-1.5 py-px font-mono text-[0.625rem] font-medium tracking-wider whitespace-nowrap uppercase",
77 tone,
78 )}
79 >
80 {children}
81 </span>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look82 );
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms83}
84
85/** A person or an agent, by name, wearing the mark that tells them apart. */
86function Person({ who, size = 16, className }: { who: Who; size?: number; className?: string }) {
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look87 return (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms88 <span className={cn("inline-flex min-w-0 items-center gap-1.5", className)}>
89 <Avatar name={who.name} size={size} />
90 <span className="truncate">{who.name}</span>
91 </span>
92 );
93}
94
95function Eyebrow({ children }: { children: ReactNode }) {
96 return <p className="font-mono text-[0.625rem] font-medium tracking-[0.12em] text-faint uppercase">{children}</p>;
97}
98
Merge branch 'worktree-agent-ad7c6d88d93adc817'99const FACT_TONE = { good: "text-success", warn: "text-warn", bad: "text-danger" } as const;
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms100
101function Facts({ facts }: { facts: Fact[] }) {
102 if (facts.length === 0) return <p className="text-sm text-muted">Nothing more is known about it yet.</p>;
103 return (
104 <dl className="grid grid-cols-2 gap-x-4 gap-y-2.5">
105 {facts.map((fact) => (
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step106 <div key={fact.label} className={cn("min-w-0", fact.wide && "col-span-2")}>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms107 <dt className="text-xs text-faint">{fact.label}</dt>
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step108 <dd
109 className={cn(
110 "mt-0.5 text-sm font-medium tabular-nums",
111 fact.wide ? "leading-5" : "truncate",
112 fact.tone ? FACT_TONE[fact.tone] : "text-fg-soft",
113 )}
114 >
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms115 {fact.value}
116 </dd>
117 </div>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look118 ))}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms119 </dl>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look120 );
121}
122
Merge branch 'worktree-agent-a985c01f43538af01'123/**
124 * A form that acts on a pull request from here: working until the action
125 * has answered and the page has reloaded what it changed, then done, or
126 * the error beside it.
127 */
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms128function QuickForm({ quick, variant = "quiet" }: { quick: QuickAction; variant?: "quiet" | "accent" }) {
129 const fetcher = useFetcher<{ error?: string } | null>();
130 const [sent, setSent] = useState(false);
Merge branch 'worktree-agent-a985c01f43538af01'131 const done = sent && fetcher.state === "idle" && !fetcher.data?.error;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look132 return (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms133 <fetcher.Form method="post" action={quick.to} onSubmit={() => setSent(true)} className="contents">
134 {Object.entries(quick.fields).map(([name, value]) => (
135 <input key={name} type="hidden" name={name} value={value} />
136 ))}
Merge branch 'worktree-agent-a985c01f43538af01'137 <SubmitButton
138 fetcher={fetcher}
139 disabled={done}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms140 className={cn(
141 "inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors disabled:cursor-default",
142 variant === "accent"
Merge branch 'worktree-agent-ad7c6d88d93adc817'143 ? "bg-accent text-bg hover:bg-accent-hover"
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms144 : "border border-line-strong text-fg/90 hover:bg-raised hover:text-fg",
Merge branch 'worktree-agent-ad7c6d88d93adc817'145 done && "border-success/40 text-success",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms146 )}
147 >
Fast pages, required checks on the branch, self-hosted runners, honest incidents148 {done ? <Check size={14} /> : null}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms149 {done ? quick.done : quick.label}
Merge branch 'worktree-agent-a985c01f43538af01'150 </SubmitButton>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms151 {fetcher.data?.error && <span className="basis-full text-xs text-danger">{fetcher.data.error}</span>}
152 </fetcher.Form>
153 );
154}
155
156function ProjectMark({ repo }: { repo: { namespace: string; name: string } | null }) {
157 return <Avatar name={repo ? repo.name : "g1t"} size={32} square />;
158}
159
160/** A row that opens to what is known about it; the first one starts open. */
161function Row({
162 open,
163 repo,
164 by,
165 title,
166 sub,
167 chip,
168 at,
169 children,
170}: {
171 open: boolean;
172 repo: { namespace: string; name: string } | null;
173 by: Who | null;
174 title: ReactNode;
175 sub: ReactNode;
176 chip: ReactNode;
177 at: number;
178 children: ReactNode;
179}) {
180 return (
181 <li>
182 <details open={open} className="group">
183 <summary className="flex cursor-pointer list-none items-center gap-3 px-4 py-3 transition-colors select-none hover:bg-raised/60 sm:px-5 [&::-webkit-details-marker]:hidden">
184 <ProjectMark repo={repo} />
185 <span className="min-w-0 grow">
186 <span className="block truncate text-sm">{title}</span>
187 <span className="mt-0.5 flex min-w-0 items-center gap-1.5 text-xs text-muted">
188 <span className="shrink-0 font-medium text-fg-soft">{repo ? repo.name : "Workspace"}</span>
189 {by && (
190 <>
191 <span className="text-faint">·</span>
Merge branch 'worktree-agent-ad7c6d88d93adc817'192 <Person who={by} size={14} className={cn("shrink-0", by.agent ? "text-accent" : "")} />
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms193 </>
194 )}
195 {sub && (
196 <>
197 <span className="text-faint">—</span>
198 <span className="truncate">{sub}</span>
199 </>
200 )}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look201 </span>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms202 </span>
203 <span className="hidden sm:inline-flex">{chip}</span>
204 <span className="hidden w-16 shrink-0 text-right text-xs text-faint sm:block">
205 <TimeAgo at={at} />
206 </span>
207 <ChevronDown size={16} className="shrink-0 text-faint transition-transform group-open:rotate-180" />
208 </summary>
209 <div className="px-4 pb-4 sm:px-5 sm:pb-5">
210 <div className="mb-3 flex items-center gap-2 sm:hidden">
211 {chip}
212 <span className="text-xs text-faint">
213 <TimeAgo at={at} />
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look214 </span>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms215 </div>
216 {children}
217 </div>
218 </details>
219 </li>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look220 );
221}
222
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms223function NeedCard({ row, first }: { row: NeedRow; first: boolean }) {
224 const isPull = row.to.includes("/pull/");
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look225 return (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms226 <Row
227 open={first}
228 repo={row.repo}
229 by={row.by}
230 title={
231 <>
232 <span className="font-medium">{row.title}</span>
233 {row.ref && <span className="ml-1 font-mono text-xs text-faint">{row.ref}</span>}
234 </>
235 }
236 sub={row.ask}
237 chip={<Chip tone={CHIP_TONE[row.reason]}>{REASON_LABEL[row.reason]}</Chip>}
238 at={row.at}
239 >
240 <div className="grid gap-4 rounded-xl border border-line bg-bg/50 p-4 md:grid-cols-2 md:gap-x-6 2xl:grid-cols-[minmax(0,1.1fr)_minmax(0,1fr)_minmax(0,0.95fr)]">
241 <div className="min-w-0">
242 <Eyebrow>The ask</Eyebrow>
243 <p className="mt-2 text-sm leading-6 text-fg-soft">{row.ask}</p>
244 <p className="mt-2 text-xs leading-5 text-muted">
245 <Link to={row.to} className="font-medium text-fg hover:underline">
246 {row.repo ? `${row.repo.name}${row.ref ?? ""}` : row.title}
247 </Link>
248 {row.for && (
249 <>
250 {" "}
251 · started for <span className="text-fg-soft">{row.for}</span>
252 </>
253 )}
254 </p>
255 </div>
256 <div className="min-w-0">
Usage, Billing settings and prepaid AI credit; fixes from the UX audit257 <Eyebrow>{row.by?.agent ? "What the agent already knows" : "What is known"}</Eyebrow>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms258 <div className="mt-2">
259 <Facts facts={row.facts} />
260 </div>
261 </div>
262 <div className="rounded-lg border border-warn/20 bg-warn/[0.06] p-3.5 md:col-span-2 2xl:col-span-1">
263 <p className="text-xs font-semibold text-warn">Why this needs you</p>
264 <p className="mt-1.5 text-sm leading-6 text-fg-soft">{row.why}</p>
265 <p className="mt-2 text-xs text-faint">
Usage, Billing settings and prepaid AI credit; fixes from the UX audit266 Started waiting <TimeAgo at={row.at} />
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms267 </p>
268 </div>
269 </div>
270 <div className="mt-3 flex flex-wrap items-center gap-2">
271 <Link
272 to={row.to}
273 prefetch="intent"
274 className="inline-flex items-center gap-1.5 rounded-md bg-fg px-3 py-1.5 text-sm font-medium text-bg transition-colors hover:bg-white"
275 >
276 Review and respond <ArrowUpRight size={14} />
277 </Link>
278 {row.quick && <QuickForm quick={row.quick} />}
279 {row.link && (
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look280 <Link
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms281 to={row.link.to}
282 className="inline-flex items-center rounded-md border border-line-strong px-3 py-1.5 text-sm font-medium text-fg/90 hover:bg-raised hover:text-fg"
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look283 >
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms284 {row.link.label}
285 </Link>
286 )}
287 {row.open !== row.to && (
288 <Link to={row.open} prefetch="intent" className="px-2 py-1.5 text-sm text-muted hover:text-fg">
289 {row.open.includes("/issues/") ? "Open issue" : isPull ? "See the changes" : "Open pull request"}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look290 </Link>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms291 )}
292 </div>
293 </Row>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look294 );
295}
296
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms297function WaitingCard({ row, first }: { row: WaitingRow; first: boolean }) {
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look298 return (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms299 <Row
300 open={first}
301 repo={row.repo}
302 by={row.by}
303 title={
304 <>
305 <span className="font-medium">{row.title}</span>
306 {row.ref && <span className="ml-1 font-mono text-xs text-faint">{row.ref}</span>}
307 </>
308 }
309 sub={row.detail}
310 chip={
311 <Chip tone="border-line-strong bg-raised text-muted">
Merge branch 'worktree-agent-ad7c6d88d93adc817'312 {row.live && <span className="mr-1.5 size-1.5 animate-pulse rounded-full bg-success" />}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms313 {row.chip}
314 </Chip>
315 }
316 at={row.at}
317 >
318 <div className="grid gap-4 rounded-xl border border-line bg-bg/50 p-4 md:grid-cols-2 md:gap-6">
319 <div className="min-w-0">
320 <Eyebrow>{row.live ? "Doing now" : "Where it stands"}</Eyebrow>
321 <p className="mt-2 text-sm leading-6 text-fg-soft">{row.detail}</p>
322 </div>
323 <div className="min-w-0">
324 <Eyebrow>What is known</Eyebrow>
325 <div className="mt-2">
326 <Facts facts={row.facts} />
327 </div>
328 </div>
329 </div>
330 <div className="mt-3 flex flex-wrap gap-2">
331 <Link
332 to={row.to}
333 prefetch="intent"
334 className="inline-flex items-center gap-1.5 rounded-md border border-line-strong px-3 py-1.5 text-sm font-medium text-fg/90 hover:bg-raised hover:text-fg"
335 >
336 {row.to.includes("/runs/") ? "Watch the run" : "Open pull request"} <ArrowUpRight size={14} />
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look337 </Link>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms338 {row.run && row.run !== row.to && (
339 <Link to={row.run} prefetch="intent" className="px-2 py-1.5 text-sm text-muted hover:text-fg">
340 Watch the run
341 </Link>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look342 )}
343 </div>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms344 </Row>
345 );
346}
347
348function LandedCard({ row, first }: { row: LandedRow; first: boolean }) {
349 return (
350 <Row
351 open={first}
352 repo={row.repo}
353 by={row.byAgents ? { name: row.agent, agent: isAgent(row.agent) } : row.by}
354 title={
355 <>
356 <span className="font-medium">{row.title}</span>
357 <span className="ml-1 font-mono text-xs text-faint">{row.ref}</span>
358 </>
359 }
360 sub={row.byAgents ? "landed without a person" : `merged by ${row.by?.name ?? "a person"}`}
361 chip={
362 row.byAgents ? (
Merge branch 'worktree-agent-ad7c6d88d93adc817'363 <Chip tone="border-accent/35 bg-accent/10 text-accent">By agents</Chip>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look364 ) : (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms365 <Chip tone="border-warn/35 bg-warn/10 text-warn">Needed a person</Chip>
366 )
367 }
368 at={row.at}
369 >
370 <div className="grid gap-4 rounded-xl border border-line bg-bg/50 p-4 md:grid-cols-2 md:gap-6">
371 <div className="min-w-0">
372 <Eyebrow>How it landed</Eyebrow>
373 <p className="mt-2 text-sm leading-6 text-fg-soft">
374 {row.byAgents
375 ? `g1t merged it once everything the repository asks for was met, with no one pressing merge.`
376 : `${row.by?.name ?? "A person"} merged it.`}
377 {row.agent && isAgent(row.agent) && ` ${row.agent} made the change.`}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look378 </p>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms379 </div>
380 <div className="min-w-0">
381 <Eyebrow>What changed</Eyebrow>
382 <div className="mt-2">
383 <Facts facts={row.facts} />
384 </div>
385 </div>
386 </div>
387 <div className="mt-3">
388 <Link
389 to={row.to}
390 prefetch="intent"
391 className="inline-flex items-center gap-1.5 rounded-md border border-line-strong px-3 py-1.5 text-sm font-medium text-fg/90 hover:bg-raised hover:text-fg"
392 >
393 Open pull request <ArrowUpRight size={14} />
394 </Link>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look395 </div>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms396 </Row>
397 );
398}
399
400function List({ children }: { children: ReactNode }) {
401 return <ul className="divide-y divide-line">{children}</ul>;
402}
403
404function Empty({ children, action }: { children: ReactNode; action?: ReactNode }) {
405 return (
406 <div className="px-5 py-10 text-center">
407 <div className="mx-auto max-w-md text-sm leading-6 text-muted">{children}</div>
408 {action && <div className="mt-4 flex flex-wrap justify-center gap-2">{action}</div>}
409 </div>
410 );
411}
412
413// --- The stat strip -----------------------------------------------------------------
414
415function Stat({ label, value, hint, dot, title }: { label: string; value: string; hint: ReactNode; dot?: string; title?: string }) {
416 return (
Merge branch 'worktree-agent-ae1299e92e4462012'417 <Hint label={title}>
418 <div className="min-w-0 bg-surface px-4 py-3.5 sm:px-5 sm:py-4">
419 <p className="flex items-center gap-1.5 truncate text-xs text-muted">
420 {dot && <span className={cn("size-1.5 shrink-0 rounded-full", dot)} />}
421 {label}
422 </p>
423 <p className="mt-1 font-display text-2xl font-semibold tracking-tight tabular-nums sm:text-[1.75rem]">{value}</p>
424 <p className="mt-0.5 truncate text-xs text-faint">{hint}</p>
425 </div>
426 </Hint>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms427 );
428}
429
430// --- This week ----------------------------------------------------------------------
431
432/** Seven days of landed changes, each split into what agents landed alone and what a person merged. */
433function WeekChart({ week }: { week: Week }) {
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar434 const max = Math.max(1, ...week.days.map((d) => d.agents + d.assisted + d.people));
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms435 const height = 112;
436 const delta = change(week.total, week.previous);
437 return (
438 <div>
439 <div className="flex items-end justify-between gap-3">
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look440 <div>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms441 <p className="font-display text-3xl font-semibold tracking-tight tabular-nums">{week.total.toLocaleString("en-US")}</p>
442 <p className="text-xs text-muted">changes landed in 7 days</p>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look443 </div>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms444 {delta != null ? (
445 <span
446 className={cn(
447 "rounded-full px-2 py-0.5 text-xs font-medium tabular-nums ring-1",
Merge branch 'worktree-agent-ad7c6d88d93adc817'448 delta >= 0 ? "text-success ring-success/30" : "text-warn ring-warn/30",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms449 )}
450 >
451 {signedPercent(delta)} vs last week
452 </span>
453 ) : week.previous === 0 && week.total > 0 ? (
454 <span className="text-xs text-faint">none the week before</span>
455 ) : null}
456 </div>
457 {week.total === 0 ? (
458 <p className="mt-4 rounded-lg border border-dashed border-line px-4 py-6 text-center text-sm leading-6 text-muted">
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar459 Nothing landed in the last 7 days. Each change that does shows here, by day: agents' changes that landed on their own, agents' that a person merged, and people's own.
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms460 </p>
461 ) : (
462 <div className="relative mt-5" style={{ height: height + 20 }}>
463 <div className="absolute inset-x-0 border-t border-line" style={{ top: height }} />
464 <div className="absolute inset-x-0 top-0 flex items-end justify-between gap-1" style={{ height }}>
465 {week.days.map((day, index) => {
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar466 const total = day.agents + day.assisted + day.people;
467 const bar = (n: number) => Math.max(3, Math.round((n / max) * (height - 4)));
468 // Top to bottom: agents alone, agents with a person, people.
469 const segments = [
Merge branch 'worktree-agent-ad7c6d88d93adc817'470 { n: day.agents, tone: "bg-accent" },
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar471 { n: day.assisted, tone: "bg-warn" },
472 { n: day.people, tone: "bg-info" },
473 ].filter((segment) => segment.n > 0);
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms474 const today = index === week.days.length - 1;
475 return (
476 <div key={day.key} className="group relative flex h-full flex-1 flex-col items-center justify-end">
477 {total > 0 && (
478 <span
479 className={cn(
480 "mb-1 text-[0.625rem] tabular-nums",
481 today ? "text-fg-soft" : "text-faint opacity-0 group-hover:opacity-100",
482 )}
483 >
484 {total}
485 </span>
486 )}
487 <div className="flex w-full max-w-6 flex-col items-stretch gap-[2px]">
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar488 {segments.map((segment, at) => (
489 <span key={segment.tone} className={cn("block", segment.tone, at === 0 && "rounded-t")} style={{ height: bar(segment.n) }} />
490 ))}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms491 {total === 0 && <span className="block h-[2px] rounded-full bg-line-strong" />}
492 </div>
493 <div className="pointer-events-none absolute bottom-full left-1/2 z-10 mb-1 hidden -translate-x-1/2 rounded-md border border-line-strong bg-raised px-2.5 py-1.5 text-xs whitespace-nowrap shadow-lg shadow-black/40 group-hover:block">
494 <p className="font-medium text-fg">{day.label}</p>
495 <p className="mt-0.5 flex items-center gap-1.5 text-muted">
Merge branch 'worktree-agent-ad7c6d88d93adc817'496 <span className="size-1.5 rounded-full bg-accent" /> {day.agents} by agents on their own
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar497 </p>
498 <p className="flex items-center gap-1.5 text-muted">
499 <span className="size-1.5 rounded-full bg-warn" /> {day.assisted} by agents, merged by a person
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms500 </p>
501 <p className="flex items-center gap-1.5 text-muted">
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar502 <span className="size-1.5 rounded-full bg-info" /> {day.people} by people
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms503 </p>
504 </div>
505 </div>
506 );
507 })}
508 </div>
509 <div className="absolute inset-x-0 bottom-0 flex justify-between gap-1">
510 {week.days.map((day, index) => (
511 <span
512 key={day.key}
513 className={cn(
514 "flex-1 text-center text-[0.6875rem]",
515 index === week.days.length - 1 ? "font-medium text-fg-soft" : "text-faint",
516 )}
517 >
518 {day.label}
519 </span>
520 ))}
521 </div>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look522 </div>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms523 )}
524 <div className={cn("mt-3 flex-wrap gap-x-4 gap-y-1 text-xs text-muted", week.total === 0 ? "hidden" : "flex")}>
525 <span className="inline-flex items-center gap-1.5">
Merge branch 'worktree-agent-ad7c6d88d93adc817'526 <span className="size-2 rounded-sm bg-accent" /> Agents, on their own
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar527 </span>
528 <span className="inline-flex items-center gap-1.5">
529 <span className="size-2 rounded-sm bg-warn" /> Agents, merged by a person
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms530 </span>
531 <span className="inline-flex items-center gap-1.5">
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar532 <span className="size-2 rounded-sm bg-info" /> People
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms533 </span>
534 </div>
Fixes from the page sweep535 {/* A table does not shrink to sr-only's 1px; its wrapper does. */}
536 <div className="sr-only">
537 <table>
538 <caption>Changes landed each day</caption>
539 <thead>
540 <tr>
541 <th>Day</th>
542 <th>Agents, on their own</th>
543 <th>Agents, merged by a person</th>
544 <th>People</th>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms545 </tr>
Fixes from the page sweep546 </thead>
547 <tbody>
548 {week.days.map((day) => (
549 <tr key={day.key}>
550 <td>{day.key}</td>
551 <td>{day.agents}</td>
552 <td>{day.assisted}</td>
553 <td>{day.people}</td>
554 </tr>
555 ))}
556 </tbody>
557 </table>
558 </div>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms559 </div>
560 );
561}
562
563// --- Activity -----------------------------------------------------------------------
564
565const VERB: Record<Verb, string> = {
566 landed: "landed",
567 opened_issue: "opened",
568 closed_issue: "closed",
569 started: "started on",
570 ready: "marked ready",
571 checks_passed: "checks passed on",
572 checks_failed: "checks failed on",
573 approved: "approved",
574 changes_requested: "asked for changes on",
575 commented: "commented on",
576 asked: "was asked about",
577 deployed: "deployed production",
578 deploy_failed: "production build failed",
Merge demo dry run fixes: settled checks, other attempts, queue links, clone box, activity feed, DEMO.md579 pushed: "pushed to the default branch",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms580 learned: "learned",
581};
582
583/** One line of the feed: who, what, and the one thing it was about, by name. */
584function FeedLine({ group, titles }: { group: ActivityGroup; titles: Record<string, string> }) {
585 const part = group.parts[0];
586 const base = `/${group.repo.namespace}/${group.repo.name}`;
587 const actor = group.actor ?? "g1t";
588 const agent = group.actor == null || isAgent(group.actor);
589 const number = part.numbers[0];
590 const title = number != null ? titles[`${group.repo.namespace}/${group.repo.name}#${number}`.toLowerCase()] : undefined;
591 const more = group.parts.length - 1 + Math.max(0, part.numbers.length - 1);
592 return (
593 <li className="flex gap-2.5 py-2">
594 <span className="mt-px">
595 <Avatar name={actor} size={22} />
596 </span>
597 <span className="min-w-0 grow text-[0.8125rem] leading-5 text-muted">
Merge branch 'worktree-agent-ad7c6d88d93adc817'598 <span className={cn("font-medium", agent ? "text-accent" : "text-fg")}>{actor}</span> {VERB[part.verb]}{" "}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms599 {part.verb === "learned" ? (
600 <Link to={part.to ?? `${base}/memory`} className="text-fg-soft hover:text-fg">
601 “{part.texts[0]}”
602 </Link>
603 ) : number != null ? (
604 <Link to={`${base}/issues/${number}`} prefetch="intent" className="text-fg-soft hover:text-fg">
605 <span className="font-mono text-xs">#{number}</span>
606 {title && <> {title}</>}
607 </Link>
608 ) : part.to ? (
609 <Link to={part.to} className="text-fg-soft hover:text-fg">
610 {group.repo.name}
611 </Link>
612 ) : null}
613 {more > 0 && <span className="text-faint"> and {more} more</span>}
614 <span className="block text-xs text-faint">
615 <span className="font-mono">{group.repo.name}</span> · <TimeAgo at={group.at} />
616 </span>
617 </span>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look618 </li>
619 );
620}
621
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms622// --- Get started --------------------------------------------------------------------
623
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look624type Step = { done: boolean; title: string; about: string; to: string | null; action: string };
625
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms626/** The first things to do, ticked off as they are done, until work has been handed to agents. */
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look627function GetStarted({ steps }: { steps: Step[] }) {
628 const left = steps.filter((step) => !step.done).length;
629 return (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms630 <section className="rounded-xl border border-line bg-surface p-5">
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look631 <div className="flex items-baseline justify-between gap-3">
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms632 <h2 className="text-base font-semibold tracking-tight">Get started</h2>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look633 <span className="text-xs text-muted">
634 {steps.length - left} of {steps.length} done
635 </span>
636 </div>
637 <ol className="mt-4 space-y-2">
638 {steps.map((step, index) => (
639 <li
640 key={step.title}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms641 className={cn("flex items-start gap-3 rounded-lg px-3 py-2.5", step.done ? "" : "bg-bg/50 ring-1 ring-line")}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look642 >
643 <span
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms644 className={cn(
645 "mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full text-[0.6875rem] font-medium",
Merge branch 'worktree-agent-ad7c6d88d93adc817'646 step.done ? "bg-success text-bg" : "text-muted ring-1 ring-line-strong",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms647 )}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look648 >
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms649 {step.done ? <Check size={12} /> : index + 1}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look650 </span>
651 <span className="min-w-0 grow">
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms652 <span className={cn("block text-sm font-medium", step.done && "text-muted line-through decoration-faint")}>{step.title}</span>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look653 {!step.done && <span className="mt-0.5 block text-xs leading-5 text-muted">{step.about}</span>}
654 </span>
655 {!step.done && step.to && (
656 <Link
657 to={step.to}
658 className="shrink-0 rounded-md bg-fg px-2.5 py-1 text-xs font-medium text-bg transition-colors hover:bg-white"
659 >
660 {step.action}
661 </Link>
662 )}
663 </li>
664 ))}
665 </ol>
666 </section>
667 );
668}
669
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms670// --- The page -----------------------------------------------------------------------
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look671
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms672const TAB_LABEL: Record<Tab, string> = { needs: "Needs you", waiting: "Waiting on agents", landed: "Landed today" };
673const TAB_SHORT: Record<Tab, string> = { needs: "Needs you", waiting: "Waiting", landed: "Today" };
674const SORT_LABEL: Record<Sort, string> = { impact: "By impact", newest: "Newest" };
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look675
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step676export default function MissionControl({ loaderData, delegated = null }: { loaderData: Loaded; delegated?: ComposerResult }) {
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look677 const shell = useRouteLoaderData("root")?.shell as ShellData | null | undefined;
678 const loaded: Loaded = loaderData;
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms679 const [params] = useSearchParams();
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look680 // Agents are at work, so the page changes without anyone touching it.
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms681 useLiveRefresh(loaded.changing);
682 const [greeting, setGreeting] = useState(loaded.greeting);
683 const [date, setDate] = useState(loaded.date);
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look684 useEffect(() => {
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms685 // The greeting and date follow the viewer's own clock, and the server
686 // learns their zone for next time.
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look687 setGreeting(greetingFor(new Date().getHours()));
688 try {
689 const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms690 setDate(dateLine(Date.now(), zone ?? null));
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look691 if (zone) document.cookie = `${TZ_COOKIE}=${encodeURIComponent(zone)}; Path=/; Max-Age=31536000; SameSite=Lax`;
692 } catch {
693 // Nothing to remember.
694 }
695 }, []);
696
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms697 const { viewer, repos, waiting, landed, liveTotal, week, groups, titles, stats, canRunAgents, trial } = loaded;
698 const workspace = shell?.workspace?.slug ?? loaded.workspace ?? viewer.workspaces?.[0]?.slug ?? null;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look699
700 // The usage limit, as the sidebar knows it, heads the list when it bites.
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms701 const limit = shell?.limit && !shell.limit.comped && shell.limit.state !== "ok" && workspace ? shell.limit : null;
702 const limitRow: NeedRow[] = limit
703 ? [
704 (() => {
705 const detail =
706 limit.state === "stopped"
707 ? "No new agent starts until the limit is raised or a card is added."
708 : `${dollars(limit.exposureMicros)} of ${dollars(limit.ceilingMicros ?? 0)} used. Add a card so work keeps going.`;
709 return {
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look710 key: "limit",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms711 reason: "blocking" as const,
712 repo: null,
713 ref: null,
714 title: limit.state === "stopped" ? "Agents are stopped: the usage limit was reached" : "Usage is nearing its limit",
715 ask: detail,
716 by: null,
717 for: null,
718 at: Date.now(),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look719 to: `/${workspace}/-/billing`,
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms720 open: `/${workspace}/-/billing`,
721 facts: [
722 { label: "Used", value: `${dollars(limit.exposureMicros)} of ${dollars(limit.ceilingMicros ?? 0)}`, tone: "warn" as const },
723 ],
724 why: whyFor("blocking", { kind: "limit", detail }),
725 quick: null,
726 link: null,
727 };
728 })(),
729 ]
730 : [];
731 const needs = [...limitRow, ...loaded.needs];
732 const blocking = needs.filter((row) => BLOCKING.has(row.reason)).length;
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look733
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms734 const counts: Record<Tab, number> = { needs: needs.length, waiting: waiting.length, landed: landed.length };
735 const tab = parseTab(params.get("tab")) ?? "needs";
736 const sort = parseSort(params.get("sort"));
737 const all = params.get("all") === "1";
738 const everyActivity = params.get("activity") === "all";
739 const link = (changes: Record<string, string | null>) => {
740 const next = new URLSearchParams(params);
741 for (const [key, value] of Object.entries(changes)) {
742 if (value == null) next.delete(key);
743 else next.set(key, value);
744 }
745 const text = next.toString();
746 return text ? `?${text}` : "/";
747 };
748
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look749 const steps: Step[] = [
750 {
751 done: Boolean(workspace),
752 title: "Create a workspace",
753 about: "Projects, people and agent credit live in one.",
754 to: "/workspaces/new",
755 action: "Create",
756 },
757 {
758 done: repos.length > 0,
759 title: "Add a project",
760 about: "Create a repository, or import one by its address. Push to it with git as usual.",
761 to: workspace ? `/new?workspace=${workspace}` : "/new",
762 action: "Add",
763 },
764 trial?.open
765 ? {
766 done: true,
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent767 title: "Try g1t free",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look768 about: trial.granted
769 ? `This workspace has ${dollars(trial.limitMicros - trial.usedMicros)} of its ${dollars(trial.limitMicros)} trial credit left, for g1t's models and sandboxes.`
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent770 : `This workspace gets ${dollars(trial.limitMicros)} of trial credit, for g1t's models and sandboxes, the first time g1t works here.`,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look771 to: workspace ? `/${workspace}/-/integrations` : null,
772 action: "Connect",
773 }
774 : canRunAgents
775 ? {
776 done: Boolean(shell?.free) || shell?.limit == null || shell.limit.comped || shell.limit.state === "ok",
777 title: "Keep work running",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms778 about:
779 "Usage is charged after it runs. Add a card under Billing, so g1t charges it as you near your limit instead of stopping work.",
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look780 to: workspace ? `/${workspace}/-/billing` : null,
781 action: "Billing",
782 }
783 : {
784 done: false,
785 title: "Connect a model",
786 about: `${
787 trialClosed(trial, workspace ?? "This workspace") ? `${trialClosed(trial, workspace ?? "This workspace")} ` : ""
788 }Agents need a model to think with. Connect your Anthropic or OpenAI key, or any compatible endpoint.`,
789 to: workspace ? `/${workspace}/-/integrations` : null,
790 action: "Connect",
791 },
792 {
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms793 done: loaded.handedOff,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look794 title: "Hand off an outcome",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms795 about:
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent796 "Open an issue and assign it to g1t, or write an outcome on a project's Plans page and let a planner split it into issues.",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms797 to: repos[0] ? `/${repos[0].namespace}/${repos[0].name}/plans` : null,
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look798 action: "Write one",
799 },
800 ];
801 const starting = steps.some((step) => !step.done);
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms802 const noProjects = repos.length === 0;
803
804 const rows = tab === "needs" ? sortRows(needs, sort) : tab === "waiting" ? sortRows(waiting, sort) : sortRows(landed, sort);
805 const shown = all ? rows : rows.slice(0, ROWS);
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar806 // Of the agents' own changes only: people's work is not theirs to land.
807 const share = week.agentChanges > 0 ? week.byAgents / week.agentChanges : null;
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms808 const delta = change(week.total, week.previous);
809 const feed = everyActivity ? groups : groups.slice(0, 8);
810
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step811 // "Put an agent on it" first, with "New issue" beside it as before: one
812 // split control, the agent the main way in.
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms813 const newIssue =
814 repos.length > 0 ? (
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step815 <div className="flex items-stretch">
816 <AgentComposer
817 repos={repos}
818 open={params.get("agent") === "new" || delegated != null}
819 result={delegated}
820 note={
821 canRunAgents ? null : (
822 <>
823 Agents need a model first.{" "}
824 {workspace && (
825 <Link to={`/${workspace}/-/integrations`} className="font-medium text-fg hover:underline">
826 Connect one
827 </Link>
828 )}
829 . The issue still opens.
830 </>
831 )
832 }
833 >
834 <span className="inline-flex cursor-pointer items-center gap-1.5 rounded-l-md border border-line-strong bg-raised px-3 py-2 text-sm font-medium text-fg transition-colors hover:bg-line/60 group-open/composer:bg-line/60">
Merge branch 'worktree-agent-ad7c6d88d93adc817'835 <Sparkles size={14} className="text-accent" /> Put an agent on it
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step836 </span>
837 </AgentComposer>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms838 <DropdownMenu>
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step839 <DropdownMenuTrigger className="-ml-px inline-flex items-center gap-1.5 rounded-r-md border border-line-strong px-3 py-2 text-sm font-medium text-fg/90 transition-colors hover:bg-raised hover:text-fg">
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms840 <Plus size={14} /> New issue
841 </DropdownMenuTrigger>
842 <DropdownMenuContent align="end" className="max-h-80 overflow-y-auto">
843 <DropdownMenuLabel>In which project?</DropdownMenuLabel>
844 {repos.map((repo) => (
845 <DropdownMenuItem key={repo.name} asChild>
846 <Link to={`/${repo.namespace}/${repo.name}/issues/new`}>
847 <Avatar name={repo.name} size={18} square />
848 {repo.name}
849 </Link>
850 </DropdownMenuItem>
851 ))}
852 </DropdownMenuContent>
853 </DropdownMenu>
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step854 </div>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms855 ) : (
856 <Link
857 to={workspace ? `/new?workspace=${workspace}` : "/new"}
858 className="inline-flex items-center gap-1.5 rounded-md border border-line-strong px-3 py-2 text-sm font-medium text-fg/90 hover:bg-raised hover:text-fg"
859 >
860 <Plus size={14} /> New project
861 </Link>
862 );
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look863
864 return (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms865 <main className="mx-auto max-w-7xl space-y-6 px-4 py-8 sm:px-6 sm:py-10">
866 <header className="flex flex-wrap items-end justify-between gap-x-6 gap-y-4">
867 <div className="min-w-0">
868 <h1 className="text-[1.75rem] leading-tight font-semibold tracking-tight sm:text-[2rem]" suppressHydrationWarning>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look869 {greeting}, {loaded.name}
870 </h1>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms871 <p className="mt-1.5 text-sm text-muted" suppressHydrationWarning>
872 <span className="text-fg-soft">{date}</span> · {loaded.summary}
873 </p>
874 </div>
875 </header>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look876
Previews build from any branch; Agent in place of Ask AI; pin from the sidebar877 {/* The agent is not on yet; the actions under it do the work today. */}
Mission control: a place to ask g1t, shown and not on yet, with the actions under it878 <AskComposer>
879 {newIssue}
880 {repos.length > 0 && (
881 <DropdownMenu>
882 <DropdownMenuTrigger className="inline-flex items-center gap-1.5 rounded-md border border-line-strong px-3 py-2 text-sm font-medium text-fg/90 transition-colors hover:bg-raised hover:text-fg">
883 <ListTree size={14} /> Plan work
884 </DropdownMenuTrigger>
885 <DropdownMenuContent align="start" className="max-h-80 overflow-y-auto">
886 <DropdownMenuLabel>Plan in which project?</DropdownMenuLabel>
887 {repos.map((repo) => (
888 <DropdownMenuItem key={repo.name} asChild>
889 <Link to={`/${repo.namespace}/${repo.name}/plans`}>
890 <Avatar name={repo.name} size={18} square />
891 {repo.name}
892 </Link>
893 </DropdownMenuItem>
894 ))}
895 </DropdownMenuContent>
896 </DropdownMenu>
897 )}
898 {needs.length > 0 && (
899 <Link
900 to={`${link({ tab: "needs", all: null })}#work`}
901 preventScrollReset
Merge branch 'worktree-agent-ad7c6d88d93adc817'902 className="inline-flex items-center gap-1.5 rounded-md bg-accent px-3.5 py-2 text-sm font-semibold text-bg transition-colors hover:bg-accent-hover"
Mission control: a place to ask g1t, shown and not on yet, with the actions under it903 >
904 Review {needs.length} that need{needs.length === 1 ? "s" : ""} you <ArrowRight size={14} />
905 </Link>
906 )}
907 </AskComposer>
908
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms909 {starting && <GetStarted steps={steps} />}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look910
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms911 <section
912 aria-label="At a glance"
913 className="grid grid-cols-2 gap-px overflow-hidden rounded-xl border border-line bg-line lg:grid-cols-5"
914 >
915 <Stat
916 label="Projects"
917 value={stats.projects == null ? "—" : String(stats.projects)}
918 hint={
919 stats.projectsThisMonth == null
920 ? "in this workspace"
921 : stats.projectsThisMonth > 0
922 ? `+${stats.projectsThisMonth} this month`
923 : "none new this month"
924 }
925 />
926 <Stat
927 label="Agents"
928 value={loaded.runsLoaded || !workspace ? String(liveTotal) : "—"}
Merge branch 'worktree-agent-ad7c6d88d93adc817'929 dot={liveTotal > 0 ? "bg-success animate-pulse" : undefined}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms930 hint={
931 liveTotal > 0
932 ? `live now · ${stats.agentHours < 10 ? stats.agentHours.toFixed(1) : Math.round(stats.agentHours)}h this week`
933 : stats.agentHours > 0
934 ? `none live · ${stats.agentHours < 10 ? stats.agentHours.toFixed(1) : Math.round(stats.agentHours)}h this week`
935 : "none live now"
936 }
937 />
938 <Stat
939 label="Changes this week"
940 value={loaded.perRepoLoaded ? String(week.total) : "—"}
941 hint={
942 delta != null ? `${signedPercent(delta)} vs last week` : week.previous === 0 ? "none the week before" : "merged pull requests"
943 }
944 />
945 <Stat
946 label="Landed without you"
Merge branch 'worktree-agent-ad7c6d88d93adc817'947 dot="bg-accent"
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms948 value={share == null ? "—" : `${Math.round(share * 100)}%`}
Mission control counts people's own changes as theirs; a shorter sidebar with setup under Settings, and a 56px top bar949 hint={share == null ? "no agent changes yet" : `${week.byAgents} of ${week.agentChanges} agent changes`}
950 title="Of the changes agents wrote, those g1t merged by auto-merge or the merge queue, with no person pressing merge. People's own changes are not counted."
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms951 />
952 <div className="col-span-2 lg:col-span-1">
953 <Stat
Usage, Billing settings and prepaid AI credit; fixes from the UX audit954 label="Needs you"
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms955 dot="bg-warn"
956 value={String(needs.length)}
957 hint={blocking > 0 ? `${blocking} blocking` : needs.length > 0 ? "nothing blocking" : "all clear"}
958 />
959 </div>
960 </section>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look961
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms962 <div className="grid gap-6 lg:grid-cols-[minmax(0,1fr)_21rem] xl:grid-cols-[minmax(0,1fr)_23rem]">
963 <section id="work" className="min-w-0 scroll-mt-20 self-start overflow-hidden rounded-xl border border-line bg-surface">
964 <div className="flex items-center gap-2 border-b border-line px-2 sm:px-3">
965 <nav className="-mb-px flex min-w-0 grow gap-1 overflow-x-auto [scrollbar-width:none]" aria-label="Mission control">
966 {(["needs", "waiting", "landed"] as const).map((value) => (
967 <Link
968 key={value}
969 to={link({ tab: value, all: null })}
970 preventScrollReset
971 aria-current={tab === value ? "page" : undefined}
972 className={cn(
973 "flex shrink-0 items-center gap-1.5 border-b-2 px-2 py-3 text-sm whitespace-nowrap transition-colors sm:px-2.5",
Merge branch 'worktree-agent-ad7c6d88d93adc817'974 tab === value ? "border-accent font-medium text-fg" : "border-transparent text-muted hover:text-fg",
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms975 )}
976 >
977 <span className="sm:hidden">{TAB_SHORT[value]}</span>
978 <span className="hidden sm:inline">{TAB_LABEL[value]}</span>
979 <span
980 className={cn(
981 "rounded-full px-1.5 text-[0.6875rem] tabular-nums",
982 tab === value && value === "needs" && counts.needs > 0 ? "bg-warn/15 text-warn" : "bg-line text-muted",
983 )}
984 >
985 {counts[value]}
986 </span>
987 </Link>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look988 ))}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms989 </nav>
990 <DropdownMenu>
991 <DropdownMenuTrigger
992 className="inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-xs text-muted hover:bg-raised hover:text-fg"
993 aria-label="Sort"
994 >
995 <ArrowDownWideNarrow size={14} />
996 <span className="hidden sm:inline">{SORT_LABEL[sort]}</span>
997 </DropdownMenuTrigger>
998 <DropdownMenuContent align="end">
999 {(["impact", "newest"] as const).map((value) => (
1000 <DropdownMenuItem key={value} asChild>
1001 <Link to={link({ sort: value === "impact" ? null : value })} preventScrollReset>
1002 {sort === value ? <Check /> : <span className="size-4" />}
1003 {SORT_LABEL[value]}
1004 </Link>
1005 </DropdownMenuItem>
1006 ))}
1007 </DropdownMenuContent>
1008 </DropdownMenu>
1009 </div>
1010
1011 {!loaded.perRepoLoaded && tab !== "waiting" ? (
1012 <div className="p-4">
1013 <Unavailable what={tab === "needs" ? "Some of what needs you" : "What landed"} />
1014 </div>
1015 ) : null}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1016
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1017 {tab === "needs" &&
1018 (needs.length === 0 ? (
1019 noProjects ? (
1020 <Empty
1021 action={
1022 <Link
1023 to={workspace ? `/new?workspace=${workspace}` : "/new"}
1024 className="rounded-md bg-fg px-3 py-1.5 text-sm font-medium text-bg hover:bg-white"
1025 >
1026 Create or import a project
1027 </Link>
1028 }
1029 >
1030 <p className="font-medium text-fg">No projects yet</p>
1031 <p className="mt-1">
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent1032 Create a repository or import one. Assign its issues to g1t, and what needs you shows up here.
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1033 </p>
1034 </Empty>
1035 ) : (
1036 <>
1037 <Empty>
1038 <p className="font-medium text-fg">Nothing needs you</p>
1039 <p className="mt-1">
1040 Agents are handling everything.{" "}
1041 {landed.length > 0
1042 ? "Here's what they landed today."
1043 : "Reviews, stopped work and failed deploys show up here first."}
1044 </p>
1045 </Empty>
1046 {landed.length > 0 && (
1047 <div className="border-t border-line">
1048 <List>
1049 {landed.slice(0, ROWS).map((row) => (
1050 <LandedCard key={row.key} row={row} first={false} />
1051 ))}
1052 </List>
1053 </div>
1054 )}
1055 </>
1056 )
1057 ) : (
1058 <List>
1059 {(shown as NeedRow[]).map((row, index) => (
1060 <NeedCard key={row.key} row={row} first={index === 0} />
1061 ))}
1062 </List>
1063 ))}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1064
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1065 {tab === "waiting" &&
1066 (!loaded.runsLoaded && workspace ? (
1067 <div className="p-4">
1068 <Unavailable what="Agent runs" />
1069 </div>
1070 ) : waiting.length === 0 ? (
1071 <Empty>
1072 <p className="font-medium text-fg">No agent is at work right now</p>
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent1073 <p className="mt-1">Assign an issue to g1t and one starts on it in seconds. Its run shows here while it works.</p>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1074 </Empty>
1075 ) : (
1076 <List>
1077 {(shown as WaitingRow[]).map((row, index) => (
1078 <WaitingCard key={row.key} row={row} first={index === 0} />
1079 ))}
1080 </List>
1081 ))}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1082
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1083 {tab === "landed" &&
1084 loaded.perRepoLoaded &&
1085 (landed.length === 0 ? (
1086 <Empty>
1087 <p className="font-medium text-fg">Nothing has landed today yet</p>
1088 <p className="mt-1">
1089 {week.total > 0
1090 ? `${plural(week.total, "change")} landed in the last 7 days.`
1091 : "Merged pull requests show up here the moment they land."}
1092 </p>
1093 </Empty>
1094 ) : (
1095 <List>
1096 {(shown as LandedRow[]).map((row, index) => (
1097 <LandedCard key={row.key} row={row} first={index === 0} />
1098 ))}
1099 </List>
1100 ))}
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1101
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1102 {rows.length > ROWS && (
1103 <div className="flex items-center justify-between border-t border-line px-4 py-2.5 text-xs text-muted sm:px-5">
1104 <span>
1105 Showing {shown.length} of {rows.length}
1106 </span>
1107 <Link
1108 to={link({ all: all ? null : "1" })}
1109 preventScrollReset
1110 className="inline-flex items-center gap-1 font-medium text-fg-soft hover:text-fg"
1111 >
1112 {all ? "Show fewer" : "See all"} <ChevronRight size={12} />
1113 </Link>
1114 </div>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1115 )}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1116 </section>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1117
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1118 <aside className="min-w-0 space-y-6">
Inbox: a bell in the top bar opens it beside the page, and /inbox holds it all1119 <InboxNeedsCard items={loaderData.inboxNeeds.items} total={loaderData.inboxNeeds.total} />
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1120 <section className="rounded-xl border border-line bg-surface p-5">
1121 <div className="flex items-center justify-between">
1122 <h2 className="text-base font-semibold tracking-tight">This week</h2>
1123 {workspace && (
1124 <Link to={`/${workspace}/-/agents`} className="text-xs text-muted hover:text-fg">
1125 Fleet
1126 </Link>
1127 )}
1128 </div>
1129 <div className="mt-4">{loaded.perRepoLoaded ? <WeekChart week={week} /> : <Unavailable what="The week" />}</div>
1130 {workspace && stats.weekCost > 0 && (
1131 <Link
1132 to={`/${workspace}/-/usage`}
1133 className="mt-4 flex items-center justify-between border-t border-line pt-3 text-xs text-muted hover:text-fg"
1134 >
Usage, Billing settings and prepaid AI credit; fixes from the UX audit1135 <span>Usage at price this week: {usd(stats.weekCost)}</span>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1136 <ChevronRight size={12} />
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1137 </Link>
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1138 )}
1139 </section>
1140
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix1141 {workspace && (
1142 <TokenUsagePanel
1143 workspace={loaderData.tokens.workspace}
1144 mine={loaderData.tokens.mine}
1145 usageHref={`/${workspace}/-/usage`}
1146 />
1147 )}
1148
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1149 <section id="activity" className="scroll-mt-20 rounded-xl border border-line bg-surface p-5">
1150 <div className="flex items-center justify-between">
1151 <h2 className="text-base font-semibold tracking-tight">Activity</h2>
1152 {groups.length > 8 && (
1153 <Link
1154 to={`${link({ activity: everyActivity ? null : "all" })}#activity`}
1155 preventScrollReset
1156 className="inline-flex items-center gap-0.5 text-xs text-muted hover:text-fg"
1157 >
1158 {everyActivity ? "Less" : "All activity"} <ChevronRight size={12} />
1159 </Link>
1160 )}
1161 </div>
1162 <p className="mt-1 flex items-center gap-3 text-[0.6875rem] text-faint">
1163 <span className="inline-flex items-center gap-1.5">
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent1164 <Avatar name="g1t" size={12} /> agents
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1165 </span>
1166 <span className="inline-flex items-center gap-1.5">
1167 <Avatar name={viewer.username} size={12} /> people
1168 </span>
1169 </p>
1170 {!loaded.perRepoLoaded ? (
1171 <div className="mt-3">
1172 <Unavailable what="Activity" />
1173 </div>
1174 ) : feed.length === 0 ? (
1175 <p className="mt-3 text-sm leading-6 text-muted">
1176 Nothing has moved yet. Merges, deploys, checks, reviews and what agents learn show up here.
1177 </p>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1178 ) : (
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1179 <ol className="mt-2 divide-y divide-line/70">
1180 {feed.map((group) => (
1181 <FeedLine key={group.id} group={group} titles={titles} />
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1182 ))}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1183 </ol>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1184 )}
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1185 </section>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1186
Mission control shows where you are needed and what agents landed without you; git answers in about 200ms1187 <section className="rounded-xl border border-line bg-surface p-5">
1188 <h2 className="text-sm font-semibold">Connect your own agent</h2>
1189 <p className="mt-1.5 text-xs leading-5 text-muted">
1190 Add g1t to your coding agent. It signs in through your browser; there is no token to copy.
1191 </p>
1192 <AgentSetup className="mt-3" />
1193 <Link
1194 to="https://docs.g1t.sh/guides/bring-your-own-agent/"
1195 className="mt-3 inline-flex items-center gap-1 text-xs text-muted hover:text-fg"
1196 >
1197 How it works <ArrowRight size={12} />
1198 </Link>
1199 </section>
1200 </aside>
1201 </div>
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look1202 </main>
1203 );
1204}

This file's history is long; its oldest lines are credited to the oldest commit read.