Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
256 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.

Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them1/**
2 * Guardrails: the form a workspace sets its defaults with and a project its
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.3 * overrides: the network a sandbox may reach, and how long its runs may take.
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them4 */
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.5import { type ReactNode, useState } from "react";
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them6import { Form } from "react-router";
7
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.8import { type GuardrailSettings, type Guardrails, type GuardrailsView, RUN_KIND_LABEL } from "@g1t/contracts";
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them9
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.10import { SANDBOX_RUN_KINDS, tri, workflowDomainLine } from "../lib/guardrails";
Merge branch 'worktree-agent-a985c01f43538af01'11import { ErrorText, Input, SubmitButton, TimeAgo } from "./ui";
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.12import { Card } from "./ui/card";
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them13import { CheckboxOption } from "./ui/checkbox";
14import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
15import { Textarea } from "./ui/textarea";
16
17function Section({ title, about, children }: { title: string; about: ReactNode; children: ReactNode }) {
18 return (
19 <section className="grid gap-x-10 gap-y-4 border-t border-line pt-8 first:border-t-0 first:pt-0 lg:grid-cols-[16rem_1fr]">
20 <div>
21 <h2 className="font-medium">{title}</h2>
22 <div className="mt-1 text-sm text-muted">{about}</div>
23 </div>
24 <div className="min-w-0 space-y-3">{children}</div>
25 </section>
26 );
27}
28
29/** A choice of inheriting, or on or off, for one setting. */
30function TriSelect({
31 name,
32 value,
33 inherited,
34 parent,
35 labels,
36 title,
37 children,
38}: {
39 name: string;
40 value: boolean | null | undefined;
41 inherited: boolean;
42 parent: string;
43 labels: [on: string, off: string];
44 title: string;
45 children: ReactNode;
46}) {
47 return (
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.48 <Card className="flex flex-col gap-3 p-4 sm:flex-row sm:items-start">
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them49 <div className="min-w-0 grow">
50 <p className="text-sm font-medium">{title}</p>
51 <p className="mt-1 text-sm text-muted">{children}</p>
52 </div>
53 <Select name={name} defaultValue={tri(value)}>
54 <SelectTrigger size="sm" aria-label={title} className="w-full shrink-0 sm:w-auto sm:min-w-44">
55 <SelectValue />
56 </SelectTrigger>
57 <SelectContent align="end">
58 <SelectItem value="inherit">
59 As {parent} ({(inherited ? labels[0] : labels[1]).toLowerCase()})
60 </SelectItem>
61 <SelectItem value="on">{labels[0]}</SelectItem>
62 <SelectItem value="off">{labels[1]}</SelectItem>
63 </SelectContent>
64 </Select>
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.65 </Card>
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them66 );
67}
68
69/** Hosts in a compact list. */
70function Hosts({ hosts }: { hosts: string[] }) {
71 return (
72 <span className="font-mono text-xs break-words text-faint">{hosts.length ? hosts.join(", ") : "none"}</span>
73 );
74}
75
76/**
77 * One level's guardrails. `level` says which: the workspace's defaults,
78 * over g1t's, or a project's overrides, over its workspace's.
79 */
80export function GuardrailsForm({
81 view,
82 level,
83 editable,
84 saving,
85 saved,
86 error,
87}: {
88 view: GuardrailsView;
89 level: "workspace" | "project";
90 editable: boolean;
Merge branch 'worktree-agent-a985c01f43538af01'91 /** Working for a reason the Save button cannot see; it follows its own submission by itself. */
92 saving?: boolean;
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them93 saved: boolean;
94 error: string | null | undefined;
95}) {
96 const own: GuardrailSettings = (level === "project" ? view.project : view.workspace) ?? {};
97 // What this level inherits, and what it is called.
98 const base: Guardrails = level === "project" ? view.inherited : view.defaults;
99 const parent = level === "project" ? "the workspace" : "g1t's default";
100 const [registryMode, setRegistryMode] = useState(own.registries ? "custom" : "inherit");
101 const shownRegistries = own.registries ?? base.registries;
102 const inheritedDomains = level === "project" ? view.inherited.domains : [];
103 const inheritedWorkflowDomains = level === "project" ? (view.inherited.workflowDomains ?? []) : [];
104 return (
Merge branch 'worktree-agent-a985c01f43538af01'105 // Keyed to the last change, so after a save the fields show what was kept, as it was tidied.
106 <Form key={own.updatedAt ?? "unset"} method="post" className="max-w-4xl space-y-8">
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them107 <fieldset disabled={!editable} className="min-w-0 space-y-8">
108 <Section
109 title="Network"
110 about={
111 <>
112 Which hosts a sandbox may reach. Requests anywhere else are refused at the sandbox's edge, and
113 each refused host shows on the run as a step.
114 </>
115 }
116 >
117 <TriSelect
118 name="restrictNetwork"
119 value={own.restrictNetwork}
120 inherited={base.restrictNetwork}
121 parent={parent}
122 labels={["Restricted", "Open"]}
123 title="Only allowed hosts"
124 >
125 Restricted, a sandbox reaches g1t, the registries below and the domains you list, over HTTP and
126 HTTPS only. Open, it reaches the whole internet.
127 </TriSelect>
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.128 <Card className="p-4">
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them129 <p className="text-sm font-medium">Always allowed</p>
130 <p className="mt-1 text-sm text-muted">
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.131 g1t's own hosts, for cloning, pushing and reporting: <Hosts hosts={view.g1tHosts} />
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them132 </p>
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.133 </Card>
134 <Card className="p-4">
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them135 <div className="flex flex-col gap-3 sm:flex-row sm:items-start">
136 <div className="min-w-0 grow">
137 <p className="text-sm font-medium">Package registries</p>
138 <p className="mt-1 text-sm text-muted">Where installs fetch dependencies from.</p>
139 </div>
140 <Select name="registries" value={registryMode} onValueChange={setRegistryMode}>
141 <SelectTrigger size="sm" aria-label="Package registries" className="w-full shrink-0 sm:w-auto sm:min-w-44">
142 <SelectValue />
143 </SelectTrigger>
144 <SelectContent align="end">
145 <SelectItem value="inherit">As {parent}</SelectItem>
146 <SelectItem value="custom">Choose</SelectItem>
147 </SelectContent>
148 </Select>
149 </div>
150 <div className="mt-4 grid gap-3 sm:grid-cols-2">
151 {view.registries.map((registry) => (
152 <CheckboxOption
153 key={`${registry.id}-${registryMode}`}
154 name={`registry:${registry.id}`}
155 disabled={registryMode !== "custom"}
156 defaultChecked={(registryMode === "custom" ? shownRegistries : base.registries).includes(registry.id)}
157 label={registry.name}
158 description={registry.hosts.join(", ")}
159 />
160 ))}
161 </div>
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.162 </Card>
163 <Card className="p-4">
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them164 <label htmlFor="guardrail-domains" className="text-sm font-medium">
165 Allowed domains
166 </label>
167 <p className="mt-1 text-sm text-muted">
168 One per line: <span className="font-mono text-xs">api.stripe.com</span>, or{" "}
169 <span className="font-mono text-xs">*.example.com</span> for its subdomains.
170 {level === "project" && " These add to the workspace's."}
171 </p>
172 <Textarea
173 id="guardrail-domains"
174 name="domains"
175 className="mt-3 font-mono text-xs"
176 rows={4}
177 defaultValue={(own.domains ?? []).join("\n")}
178 placeholder="api.stripe.com"
179 />
180 {inheritedDomains.length > 0 && (
181 <p className="mt-2 text-xs text-faint">
182 From the workspace: <Hosts hosts={inheritedDomains} />
183 </p>
184 )}
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.185 </Card>
186 <Card className="p-4">
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them187 <label htmlFor="guardrail-workflow-domains" className="text-sm font-medium">
188 Workflow-only domains
189 </label>
190 <p className="mt-1 text-sm text-muted">
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.191 Hosts that only workflow jobs may reach, such as the API a deploy uploads to. One
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them192 per line: the domain, then the workflows and the environments it is for, each comma-separated;
193 leave either out for any. Only jobs of runs that are not pull requests from forks get them.
194 {level === "project" && " These add to the workspace's."}
195 </p>
196 <Textarea
197 id="guardrail-workflow-domains"
198 name="workflowDomains"
199 className="mt-3 font-mono text-xs"
200 rows={3}
201 defaultValue={(own.workflowDomains ?? []).map(workflowDomainLine).join("\n")}
202 placeholder="api.cloudflare.com | deploy.yml | production"
203 />
204 {inheritedWorkflowDomains.length > 0 && (
205 <p className="mt-2 text-xs text-faint">
206 From the workspace:{" "}
207 <span className="font-mono break-words">{inheritedWorkflowDomains.map(workflowDomainLine).join("; ")}</span>
208 </p>
209 )}
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.210 </Card>
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them211 </Section>
212
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.213 <Section title="Time limits" about="How long one run may take. A run that reaches it is stopped.">
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.214 <Card className="p-4">
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them215 <p className="text-sm font-medium">Time per run, in minutes</p>
216 <p className="mt-1 text-sm text-muted">Empty: as {parent}, shown faded.</p>
217 <div className="mt-4 grid grid-cols-2 gap-3 sm:grid-cols-3">
The site no longer has g1t's own agents. g1t is where the coding agents you already use do their work, so the Agents mode is gone from the rail, with every page under /<workspace>/-/agents: personas, faces, skills, abilities, routines, computers, sessions and agent spend. Customize (skills, connectors, plugins, marketplaces), the context hub, model providers, the AI Gateway page, the Spend page and pill, Ask g1t, and the repository's Agents, Plans and agent settings pages go too, and their addresses now answer 404.218 {SANDBOX_RUN_KINDS.map((kind) => (
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them219 <label key={kind} className="flex flex-col gap-1 text-xs text-muted">
220 {RUN_KIND_LABEL[kind]}
221 <Input
222 name={`minutes:${kind}`}
223 inputMode="numeric"
224 defaultValue={own.minutes?.[kind] == null ? "" : String(own.minutes[kind])}
225 placeholder={String(base.minutes[kind] ?? "")}
226 />
227 </label>
228 ))}
229 </div>
The site is built from its shared components: one Button with its variants and sizes, one Badge, Card for every panel, Alert for notices, Kbd for keys, Table for the security tables, and Avatar, Command, Progress, ScrollArea, ToggleGroup, Collapsible and Accordion in the kit; raw buttons, hand-drawn cards and pills and per-file button class lists are gone, outline buttons stand the same height as filled ones, and the phone's Ask g1t loses its tile. Every page was compared pixel by pixel before and after.230 </Card>
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them231 </Section>
232 </fieldset>
233
234 {editable ? (
Phones reach every page: each mode's menu from the top bar or by tapping the tab you're on, Docs first in the avatar sheet, a project's pages as a swipeable strip; dialogs as bottom sheets above the keyboard, safe areas, menus kept on screen, 40px targets, touch-visible controls, save bars above the tab bar235 <div className="sticky bottom-(--tabbar-h) in-data-[keyboard=open]:bottom-0 -mx-4 flex flex-wrap items-center gap-4 border-t border-line bg-bg/90 px-4 py-4 backdrop-blur">
Merge branch 'worktree-agent-a985c01f43538af01'236 <SubmitButton pending="Saving…" busy={saving}>
237 Save guardrails
238 </SubmitButton>
Last commits read trees two dozen commits at a time, and the file list waits at most 3 s for them239 {saved && <span className="text-sm text-muted">Saved. Runs that start from now on get these.</span>}
240 <ErrorText>{error}</ErrorText>
241 {own.updatedBy && own.updatedAt && !saved && !error && (
242 <span className="text-xs text-faint">
243 Last changed by <span className="font-mono">{own.updatedBy}</span> <TimeAgo at={own.updatedAt} />
244 </span>
245 )}
246 </div>
247 ) : (
248 <p className="text-sm text-muted">
249 {level === "workspace"
250 ? "Only the workspace's owners can change its defaults."
251 : "Only members of the workspace can change a project's guardrails."}
252 </p>
253 )}
254 </Form>
255 );
256}

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