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.
| New workspaces are told to connect a model, before anything fails | 1 | import { env } from "cloudflare:workers"; |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 2 | import { data, redirect } from "react-router"; |
| Initial g1t: services, event bus, intents and attempts | 3 | |
| 4 | import type { Route } from "./+types/home"; | |
| Social cards for every page: og.g1t.sh | 5 | import { page } from "../lib/meta"; |
| Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put | 6 | import { WORKSPACE_COOKIE, chosenWorkspace } from "../lib/workspace-choice"; |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 7 | import { readCookie } from "../lib/mission"; |
| Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step | 8 | import { type NotStarted, chosenRepo, delegateForm, issuePath, notStarted } from "../lib/delegate"; |
| API and MCP server, Rust identity service, registration, site redesign | 9 | import { Landing } from "../components/landing"; |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 10 | import { repos as reposApi } from "../lib/services.server"; |
| 11 | import { assertSameOrigin, getViewer, requireUser } from "../lib/session.server"; | |
| 12 | import { homePath } from "../lib/workspace-nav"; | |
| A free allowance on g1t's models, so anyone can try its agents | 13 | |
| Social cards for every page: og.g1t.sh | 14 | export function meta(args: Route.MetaArgs) { |
| 15 | return page(args, { | |
| Chat and workspace agents: channels, DMs and named agents you talk to | 16 | title: "g1t · Your team and its agents, working in one place", |
| Social cards for every page: og.g1t.sh | 17 | description: |
| Chat and workspace agents: channels, DMs and named agents you talk to | 18 | "Chat with your team and your agents in channels and DMs. Agents are teammates with a role, a personality and a budget, and their code lands through pull requests, checks and a merge queue. Chat is free on every plan, never per seat.", |
| Social cards for every page: og.g1t.sh | 19 | }); |
| Initial g1t: services, event bus, intents and attempts | 20 | } |
| 21 | ||
| Mission control shows where you are needed and what agents landed without you; git answers in about 200ms | 22 | /** |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 23 | * g1t.sh: the landing page for a visitor. Someone signed in has a Home in |
| 24 | * their workspace (routes/workspace/home.tsx); Mission control's code | |
| 25 | * panels are Code's Overview. `/?agent=new` and the rest of the query go | |
| 26 | * with them. | |
| Mission control shows where you are needed and what agents landed without you; git answers in about 200ms | 27 | */ |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 28 | export async function loader({ context, request }: Route.LoaderArgs) { |
| 29 | const viewer = getViewer(context); | |
| 30 | if (!viewer) return data({ signedIn: false as const }); | |
| 31 | const url = new URL(request.url); | |
| 32 | const slug = chosenWorkspace(viewer.workspaces ?? [], readCookie(request.headers.get("cookie"), WORKSPACE_COOKIE))?.slug ?? null; | |
| 33 | // A workspace-less account is sent to make one by the session (lib/session.server.ts). | |
| 34 | if (!slug) throw redirect("/workspaces/new"); | |
| 35 | throw redirect(homePath(slug, url.search)); | |
| Mission control shows where you are needed and what agents landed without you; git answers in about 200ms | 36 | } |
| Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API | 37 | |
| Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step | 38 | /** What the composer said back, when the issue opened but the agent did not start, or nothing opened. */ |
| 39 | export type DelegateResult = { error: string; notStarted: null } | { error: null; notStarted: NotStarted }; | |
| Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API | 40 | |
| Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step | 41 | /** |
| 42 | * "Put an agent on it": opens an issue in one of the viewer's projects and | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 43 | * puts g1t on it, then lands on the issue. When the agent could not |
| Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step | 44 | * start, the issue is still open, and the composer says why and where to |
| 45 | * fix it. | |
| 46 | */ | |
| 47 | export async function action({ request, context }: Route.ActionArgs) { | |
| 48 | assertSameOrigin(request); | |
| 49 | const user = requireUser(context, request); | |
| 50 | const form = await request.formData(); | |
| 51 | if (form.get("intent") !== "delegate") return data<DelegateResult>({ error: "Nothing to do.", notStarted: null }, { status: 400 }); | |
| 52 | const projects = await reposApi.list(user, { memberOnly: true }).catch(() => []); | |
| 53 | const repo = chosenRepo(form.get("repo"), projects.map((repo) => ({ namespace: repo.namespace, name: repo.name }))); | |
| 54 | if (!repo) return data<DelegateResult>({ error: "Choose one of your projects.", notStarted: null }, { status: 400 }); | |
| 55 | const result = await env.RUNNER.delegate(user, repo, delegateForm(form)); | |
| 56 | if (!result.ok) return data<DelegateResult>({ error: result.error.message, notStarted: null }, { status: 400 }); | |
| 57 | const { issue, agent } = result.value; | |
| 58 | const refused = notStarted(agent, repo, issue.number); | |
| 59 | if (!refused) throw redirect(issuePath(repo, issue.number)); | |
| 60 | return data<DelegateResult>({ error: null, notStarted: refused }); | |
| 61 | } | |
| 62 | ||
| Mission control counts people's direct pushes to the default branch | 63 | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 64 | export default function Home() { |
| 65 | return <Landing />; | |
| Initial g1t: services, event bus, intents and attempts | 66 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.