Skip to content
818 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.

Agents → Skills is the workspace's skill library in the open SKILL.md format: write a skill in g1t, import a SKILL.md or zip, link a repository whose .g1t/skills folders publish on every push, or save a finished session as a skill once a person reviews it; attach a skill to an agent, a team or the whole workspace, each attachment pinned to a version. Agents see each skill's name and when to use it, and read the rest with use_skill when a request needs it; a skill never adds a permission, and scripts wait for an agent's own computer. The agent skills guide says how.1import { Activity, BookMarked, Brain, ChevronRight, Dices, LayoutTemplate, Network, Plus, Route as RouteIcon, Sparkles } from "lucide-react";
Chat and workspace agents: channels, DMs and named agents you talk to2import { type ReactNode, useState } from "react";
3import { Form, NavLink, useLocation, useNavigation, useRouteLoaderData } from "react-router";
4
Pricing says it plainly: models at the provider's price, the agent rate for what g1t runs around every model call (the gateway, secrets, routing, context and pass-through to your own provider, so your own keys too), everything else at cost plus 20%, your own runners free, no seats; Security and quality comes with the plan with no separate fee, and live activations end. Each agent has an effort setting, Auto to Max, with what a typical task has cost at each level, and Spend's Spend less, keep quality suggests a lower level only when the agent's own past work shows quality held, to apply or dismiss. The pricing, spend and agents guides say how.5import type { AgentEffortCosts, AgentTemplate, ModelTier, WorkspaceAgent } from "@g1t/contracts";
Chat and workspace agents: channels, DMs and named agents you talk to6
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)7import { type AgentLike, AgentAvatar, PixelCreature } from "./agent-avatar";
8import { StatusDot, statusLabel } from "./chat/marks";
9import { isOrchestrator } from "./orchestrator";
Chat and workspace agents: channels, DMs and named agents you talk to10import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
11import { Skeleton } from "./ui/skeleton";
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)12import { AUTONOMY, type AgentDraft, PRESETS, TIER_LABELS, cleanHandle, dollarsField } from "../lib/agent-form";
13import { Hint } from "./ui/hint";
Pricing says it plainly: models at the provider's price, the agent rate for what g1t runs around every model call (the gateway, secrets, routing, context and pass-through to your own provider, so your own keys too), everything else at cost plus 20%, your own runners free, no seats; Security and quality comes with the plan with no separate fee, and live activations end. Each agent has an effort setting, Auto to Max, with what a typical task has cost at each level, and Spend's Spend less, keep quality suggests a lower level only when the agent's own past work shows quality held, to apply or dismiss. The pricing, spend and agents guides say how.14import { EffortPicker } from "./effort";
15import { effortSetting } from "../lib/effort";
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)16import { DEPARTMENTS, RoleFields, SubagentsField } from "./agent-role";
Chat and workspace agents: channels, DMs and named agents you talk to17import type { AgentsLayoutData } from "../routes/workspace/agents/layout";
18
19/** The workspace's agents while an Agents page is open; undefined elsewhere. */
20export function useAgentsData(): AgentsLayoutData | undefined {
21 return useRouteLoaderData("routes/workspace/agents/layout") as AgentsLayoutData | undefined;
22}
23
24/** An agent's face: its picture, or the sparkle mark. */
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)25export function AgentFace({ agent, size = 20 }: { agent: AgentLike; size?: number }) {
26 return <AgentAvatar agent={agent} size={size} />;
Chat and workspace agents: channels, DMs and named agents you talk to27}
28
29function SideLink({ to, end, icon, children, trailing }: { to: string; end?: boolean; icon: ReactNode; children: ReactNode; trailing?: ReactNode }) {
30 return (
31 <NavLink
32 to={to}
33 end={end}
34 prefetch="intent"
35 className={({ isActive }) =>
36 `group flex h-9 items-center gap-2.5 rounded-md px-2 text-[0.8125rem] transition-colors ${
37 isActive ? "bg-raised font-medium text-fg" : "text-muted hover:bg-raised/60 hover:text-fg"
38 }`
39 }
40 >
41 <span className="flex w-5 shrink-0 justify-center">{icon}</span>
42 <span className="min-w-0 grow truncate">{children}</span>
43 {trailing}
44 </NavLink>
45 );
46}
47
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)48/** An agent as the sidebar lists it: from the Agents pages' own data, or the shell's on any other page. */
49type Listed = Pick<WorkspaceAgent, "id" | "handle" | "display_name" | "avatar" | "role" | "status" | "title" | "team" | "department"> & {
50 builtin?: boolean;
51 avatar_seed?: string | null;
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.52 scope?: WorkspaceAgent["scope"];
53 personal_owner_id?: string | null;
54 personal_owner?: string | null;
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)55};
56
57/** Where an agent sits in the org chart: its team, else its department. */
58export function placeOf(agent: Pick<WorkspaceAgent, "team" | "department">): string {
59 if (agent.team) return agent.team.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
60 return agent.department?.trim() || "Unplaced";
61}
62
63/** "Margo · QA Engineer": how an agent reads wherever it shows. */
64export function nameAndTitle(agent: Pick<WorkspaceAgent, "display_name" | "title">): string {
65 return agent.title ? `${agent.display_name} · ${agent.title}` : agent.display_name;
66}
67
Chat and workspace agents: channels, DMs and named agents you talk to68/**
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)69 * Agents mode's sidebar: the fleet's runs, context and memory; g1t, the
70 * orchestrator, pinned at the top; then the specialists, each with its
71 * role and status; and the way to make a new one.
Chat and workspace agents: channels, DMs and named agents you talk to72 */
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)73export function AgentsSidebar({
74 slug,
75 shellAgents,
76 code,
77 owner,
78 phone = false,
79}: {
80 slug: string;
81 /** A phone's Agents tab: the list as the page, with no heading of its own and no fleet row (the fleet is under it). */
82 phone?: boolean;
83 /** The shell's list, for pages outside `-/agents` (context, memory). */
84 shellAgents: Listed[] | null;
85 /** Context and memory are about the code: only with Code access. */
86 code: boolean;
87 owner: boolean;
88}) {
Chat and workspace agents: channels, DMs and named agents you talk to89 const data = useAgentsData();
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)90 const agents: Listed[] | null = data?.agents ?? shellAgents;
Agents mode: an overview of every agent's work and spend, and each agent's sessions, memory, routines, spend, activity and versions91 const live = data?.live ?? {};
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)92 const orchestrator = agents?.find((agent) => isOrchestrator(agent)) ?? null;
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.93 const specialists = (agents ?? []).filter((agent) => !isOrchestrator(agent) && agent.scope !== "personal");
94 // Personal agents: the viewer's own under Yours; members' (an owner sees them) apart.
95 // The shell's list holds only the viewer's own.
96 const personal = (agents ?? []).filter((agent) => agent.scope === "personal").sort((a, b) => a.display_name.localeCompare(b.display_name));
97 const yours = personal.filter((agent) => !data || agent.personal_owner_id === data.viewer_id);
98 const members = personal.filter((agent) => !yours.includes(agent));
99 // Owners always create agents; members personal ones, unless owners turned that off.
100 const canCreate = data?.may_create ?? owner;
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)101 const row = (agent: Listed) => (
Chat and workspace agents: channels, DMs and named agents you talk to102 <li key={agent.id}>
103 <NavLink
104 to={`/${slug}/-/agents/${agent.handle}`}
105 prefetch="intent"
106 className={({ isActive }) =>
107 `group flex h-11 items-center gap-2.5 rounded-md px-2 transition-colors ${isActive ? "bg-raised" : "hover:bg-raised/60"}`
108 }
109 >
110 <span className="relative shrink-0">
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)111 <AgentFace agent={{ ...agent, builtin: isOrchestrator(agent) }} size={26} />
112 {!isOrchestrator(agent) && (
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.113 <StatusDot status={agent.status} className="absolute -right-0.5 -bottom-0.5 ring-2 ring-shell" />
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)114 )}
Chat and workspace agents: channels, DMs and named agents you talk to115 </span>
116 <span className="min-w-0 grow leading-tight">
117 <span className="block truncate text-[0.8125rem] font-medium text-fg">{agent.display_name}</span>
118 <span className="block truncate text-[0.6875rem] text-faint">
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.119 {isOrchestrator(agent)
120 ? "Orchestrator"
121 : agent.scope === "personal" && agent.personal_owner && agent.personal_owner_id !== data?.viewer_id
122 ? `@${agent.personal_owner}'s · ${agent.title || agent.role}`
123 : agent.status === "idle"
124 ? agent.title || agent.role
125 : `${statusLabel(agent.status)} · ${agent.title || agent.role}`}
Chat and workspace agents: channels, DMs and named agents you talk to126 </span>
127 </span>
Agents mode: an overview of every agent's work and spend, and each agent's sessions, memory, routines, spend, activity and versions128 {(live[agent.id] ?? 0) > 0 && (
129 <Hint label={`${live[agent.id]} live ${live[agent.id] === 1 ? "session" : "sessions"}`}>
130 <span className="flex h-5 min-w-5 shrink-0 items-center justify-center gap-1 rounded-full bg-accent/15 px-1.5 text-[0.6875rem] font-medium text-accent tabular-nums">
131 <span className="size-1.5 animate-pulse rounded-full bg-accent motion-reduce:animate-none" aria-hidden="true" />
132 {live[agent.id]}
133 <span className="sr-only"> live sessions</span>
134 </span>
135 </Hint>
136 )}
Chat and workspace agents: channels, DMs and named agents you talk to137 </NavLink>
138 </li>
139 );
140 return (
141 <div className="flex h-full flex-col">
g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them.142 <div className={`flex h-9 shrink-0 items-center justify-between pr-1 pl-3 ${phone ? "hidden" : ""}`}>
143 <h2 className="text-xs font-medium text-faint">Agents</h2>
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.144 {canCreate && (
145 <NavLink
146 to={`/${slug}/-/agents/new`}
147 aria-label="New agent"
148 className="flex size-8 items-center justify-center rounded-md text-faint transition-colors hover:bg-raised hover:text-fg"
149 >
150 <Plus size={16} />
151 </NavLink>
152 )}
Chat and workspace agents: channels, DMs and named agents you talk to153 </div>
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)154 <nav aria-label="Agents" className={`min-h-0 grow overflow-y-auto px-2.5 pt-3 pb-4 [scrollbar-width:thin] ${phone ? "[&_a]:min-h-11" : ""}`}>
Chat and workspace agents: channels, DMs and named agents you talk to155 <div className="space-y-px">
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)156 {!phone && (
157 <SideLink to={`/${slug}/-/agents`} end icon={<Activity size={15} className="text-faint" />}>
Agents mode: an overview of every agent's work and spend, and each agent's sessions, memory, routines, spend, activity and versions158 Overview
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)159 </SideLink>
160 )}
The Marketplace adds what g1t doesn't do and connects what you already use: extensions (Mail, Support, CRM, Recruiting, On-call, and bridges to a helpdesk, CRM or ERP you run, all Soon), starter kits, and integrations connected by the workspace or by each person; agents aren't installed there. Agent templates live in Agents, as starting points you configure, at Agents → Templates, and the Marketplace's old agent addresses lead there. The marketplace and agents guides say how.161 <SideLink to={`/${slug}/-/agents/templates`} icon={<LayoutTemplate size={15} className="text-faint" />}>
162 Templates
163 </SideLink>
Agents → Skills is the workspace's skill library in the open SKILL.md format: write a skill in g1t, import a SKILL.md or zip, link a repository whose .g1t/skills folders publish on every push, or save a finished session as a skill once a person reviews it; attach a skill to an agent, a team or the whole workspace, each attachment pinned to a version. Agents see each skill's name and when to use it, and read the rest with use_skill when a request needs it; a skill never adds a permission, and scripts wait for an agent's own computer. The agent skills guide says how.164 <SideLink to={`/${slug}/-/agents/skills`} icon={<BookMarked size={15} className="text-faint" />}>
165 Skills
166 </SideLink>
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)167 {code && (
168 <>
169 <SideLink to={`/${slug}/-/context`} icon={<Network size={15} className="text-faint" />}>
170 Context
171 </SideLink>
172 <SideLink to={`/${slug}/-/memory`} icon={<Brain size={15} className="text-faint" />}>
173 Memory
174 </SideLink>
175 </>
176 )}
Chat and workspace agents: channels, DMs and named agents you talk to177 </div>
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)178 {agents == null ? (
179 data === undefined && shellAgents === null ? (
180 <p className="mt-4 px-2 text-xs leading-relaxed text-faint">The agents service didn&apos;t answer. Your agents will show here once it does.</p>
181 ) : (
182 <div className="mt-5 space-y-3 px-2" aria-busy="true">
183 {[0, 1, 2].map((i) => (
184 <div key={i} className="flex items-center gap-2.5">
185 <Skeleton className="size-6 rounded-md" />
186 <Skeleton className="h-3 w-28" />
187 </div>
188 ))}
189 </div>
190 )
Chat and workspace agents: channels, DMs and named agents you talk to191 ) : (
192 <>
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)193 {orchestrator && <Group title="Orchestrator">{row(orchestrator)}</Group>}
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.194 {yours.length > 0 && <Group title="Yours">{yours.map(row)}</Group>}
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)195 <p className="mt-4 px-2 text-[0.6875rem] leading-snug text-faint">Specialists are colleagues hired into a role. g1t hands them work.</p>
196 {[...orgChart(specialists)].map(([place, members]) => (
197 <Group key={place} title={`${place} · ${members.length}`} collapsible>
198 {members.map(row)}
Chat and workspace agents: channels, DMs and named agents you talk to199 </Group>
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)200 ))}
201 {specialists.length === 0 && <p className="px-2 py-1 text-xs text-faint">No specialists yet. Hire one into a role.</p>}
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.202 {members.length > 0 && (
203 <Group title={`Members' personal · ${members.length}`} collapsible initiallyOpen={false}>
204 {members.map(row)}
205 </Group>
206 )}
Chat and workspace agents: channels, DMs and named agents you talk to207 </>
208 )}
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.209 {canCreate && (
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)210 <NavLink
211 to={`/${slug}/-/agents/new`}
212 className={({ isActive }) =>
213 `mt-2 flex h-9 items-center gap-2.5 rounded-md border border-dashed px-2 text-[0.8125rem] transition-colors ${
214 isActive ? "border-accent/50 bg-accent/10 text-fg" : "border-line text-muted hover:border-line-strong hover:text-fg"
215 }`
216 }
217 >
218 <span className="flex w-5 justify-center">
219 <Plus size={15} />
220 </span>
221 New agent
222 </NavLink>
223 )}
Chat and workspace agents: channels, DMs and named agents you talk to224 </nav>
225 </div>
226 );
227}
228
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)229/** Specialists by team or department, each group by name, the groups in the gallery's order. */
230function orgChart(agents: Listed[]): Map<string, Listed[]> {
231 const groups = new Map<string, Listed[]>();
232 for (const agent of agents) groups.set(placeOf(agent), [...(groups.get(placeOf(agent)) ?? []), agent]);
233 const rank = (place: string) => {
234 const at = DEPARTMENTS.indexOf(place);
235 return at < 0 ? DEPARTMENTS.length : at;
236 };
237 return new Map(
238 [...groups]
239 .sort(([a], [b]) => rank(a) - rank(b) || a.localeCompare(b))
240 .map(([place, list]) => [place, list.sort((x, y) => x.display_name.localeCompare(y.display_name))]),
241 );
242}
243
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.244function Group({ title, children, collapsible, initiallyOpen = true }: { title: string; children: ReactNode; collapsible?: boolean; initiallyOpen?: boolean }) {
245 const [open, setOpen] = useState(initiallyOpen);
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)246 if (collapsible) {
247 return (
248 <section className="mt-3">
249 <button
250 type="button"
251 onClick={() => setOpen(!open)}
252 aria-expanded={open}
253 className="mb-1 flex w-full items-center gap-1 rounded px-1 text-xs font-medium text-faint transition-colors hover:text-muted"
254 >
255 <ChevronRight size={12} className={`transition-transform ${open ? "rotate-90" : ""}`} />
256 {title}
257 </button>
258 {open && <ul className="space-y-px border-l border-line pl-1.5 ml-2.5">{children}</ul>}
259 </section>
260 );
261 }
Chat and workspace agents: channels, DMs and named agents you talk to262 return (
263 <section className="mt-4">
264 <h3 className="mb-1 px-2 text-xs font-medium text-faint">{title}</h3>
265 <ul className="space-y-px">{children}</ul>
266 </section>
267 );
268}
269
270/** The templates g1t ships, and a blank one, to start a new agent from. */
271export function TemplateGallery({ templates, chosen, onChoose }: { templates: AgentTemplate[]; chosen: string | null; onChoose: (id: string | null) => void }) {
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)272 // By department, in the order the departments are listed; any other after them.
273 const order = (department: string) => {
274 const at = DEPARTMENTS.indexOf(department);
275 return at < 0 ? DEPARTMENTS.length : at;
276 };
277 const groups = new Map<string, AgentTemplate[]>();
278 for (const template of [...templates].sort((a, b) => order(a.department) - order(b.department))) {
279 const key = template.department || "Other";
280 groups.set(key, [...(groups.get(key) ?? []), template]);
281 }
Chat and workspace agents: channels, DMs and named agents you talk to282 return (
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)283 <div className="space-y-8">
284 {[...groups].map(([department, list]) => (
285 <section key={department}>
286 <h2 className="mb-3 text-xs font-semibold tracking-wide text-faint uppercase">{department}</h2>
287 <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
288 {list.map((template) => (
289 <TemplateCard
290 key={template.id}
291 selected={chosen === template.id}
292 onClick={() => onChoose(template.id)}
293 name={template.display_name}
294 title={template.title}
295 seed={template.handle}
296 duties={template.responsibilities.slice(0, 3)}
297 />
298 ))}
299 </div>
300 </section>
Chat and workspace agents: channels, DMs and named agents you talk to301 ))}
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)302 <section>
303 <h2 className="mb-3 text-xs font-semibold tracking-wide text-faint uppercase">Your own</h2>
304 <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
305 <TemplateCard
306 selected={chosen === "blank"}
307 onClick={() => onChoose("blank")}
308 name="A new role"
309 title="Start from nothing"
310 blank
311 duties={["Give it a name, a title and a team", "Say what it is responsible for"]}
312 />
313 </div>
314 </section>
Chat and workspace agents: channels, DMs and named agents you talk to315 </div>
316 );
317}
318
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)319/** A role to hire into: its face, a name it suggests, its title and what it does. */
Chat and workspace agents: channels, DMs and named agents you talk to320function TemplateCard({
321 selected,
322 onClick,
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)323 name,
Chat and workspace agents: channels, DMs and named agents you talk to324 title,
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)325 seed,
326 duties,
Chat and workspace agents: channels, DMs and named agents you talk to327 blank,
328}: {
329 selected: boolean;
330 onClick: () => void;
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)331 name: string;
Chat and workspace agents: channels, DMs and named agents you talk to332 title: string;
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)333 seed?: string;
334 duties: string[];
Chat and workspace agents: channels, DMs and named agents you talk to335 blank?: boolean;
336}) {
337 return (
338 <button
339 type="button"
340 onClick={onClick}
341 aria-pressed={selected}
342 className={`group flex flex-col items-start rounded-xl border p-4 text-left transition-all ${
343 selected
344 ? "border-accent/60 bg-accent/[0.07] ring-1 ring-accent/40"
345 : "border-line bg-surface hover:-translate-y-px hover:border-line-strong hover:bg-raised/40"
346 }`}
347 >
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)348 <span className="flex w-full items-center gap-3">
Chat and workspace agents: channels, DMs and named agents you talk to349 {blank ? (
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)350 <span className="flex size-10 items-center justify-center rounded-[11px] border border-dashed border-line-strong text-muted">
Chat and workspace agents: channels, DMs and named agents you talk to351 <Plus size={16} />
352 </span>
353 ) : (
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)354 <PixelCreature seed={seed ?? name} size={40} />
Chat and workspace agents: channels, DMs and named agents you talk to355 )}
356 <span className="min-w-0 grow">
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)357 <span className="block truncate text-sm font-semibold">{name}</span>
358 <span className="block truncate text-xs text-muted">{title}</span>
Chat and workspace agents: channels, DMs and named agents you talk to359 </span>
360 <ChevronRight size={15} className={`shrink-0 transition-colors ${selected ? "text-accent" : "text-faint group-hover:text-muted"}`} />
361 </span>
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)362 <ul className="mt-3 space-y-1">
363 {duties.map((duty) => (
364 <li key={duty} className="flex gap-2 text-[0.8125rem] leading-snug text-muted">
365 <span className="mt-[0.45rem] size-1 shrink-0 rounded-full bg-line-strong" aria-hidden="true" />
366 <span className="line-clamp-1">{duty}</span>
367 </li>
368 ))}
369 </ul>
Chat and workspace agents: channels, DMs and named agents you talk to370 </button>
371 );
372}
373
374const FIELD = "w-full rounded-md border border-line bg-bg px-3 py-2 text-sm outline-none transition-colors placeholder:text-faint hover:border-line-strong focus:border-accent-dim";
375
376function Label({ children, hint, error, htmlFor }: { children: ReactNode; hint?: ReactNode; error?: string; htmlFor?: string }) {
377 return (
378 <div className="mb-1.5 flex items-baseline justify-between gap-3">
379 <label htmlFor={htmlFor} className="text-sm font-medium text-fg-soft">
380 {children}
381 </label>
382 {error ? <span className="text-xs text-danger">{error}</span> : hint ? <span className="text-xs text-faint">{hint}</span> : null}
383 </div>
384 );
385}
386
387/** A section of the form: what it is on the left, its fields on the right, on a wide screen. */
388function FormSection({ title, about, children }: { title: string; about: ReactNode; children: ReactNode }) {
389 return (
390 <section className="grid gap-x-10 gap-y-4 border-t border-line py-8 first-of-type:border-t-0 first-of-type:pt-0 md:grid-cols-[13rem_1fr]">
391 <div>
392 <h2 className="text-sm font-semibold">{title}</h2>
393 <p className="mt-1 text-[0.8125rem] leading-relaxed text-muted">{about}</p>
394 </div>
395 <div className="min-w-0 space-y-5">{children}</div>
396 </section>
397 );
398}
399
400function TierSelect({ name, value, none }: { name: string; value: ModelTier | null; none: string }) {
401 return (
402 <Select name={name} defaultValue={value ?? "none"}>
403 <SelectTrigger id={name}>
404 <SelectValue />
405 </SelectTrigger>
406 <SelectContent>
407 <SelectItem value="none">{none}</SelectItem>
408 {(["small", "large", "frontier"] as const).map((tier) => (
409 <SelectItem key={tier} value={tier} description={TIER_LABELS[tier].split(": ")[1]}>
410 {TIER_LABELS[tier].split(":")[0]}
411 </SelectItem>
412 ))}
413 </SelectContent>
414 </Select>
415 );
416}
417
418function Money({ name, value, label, hint, error }: { name: string; value: number | null; label: string; hint: string; error?: string }) {
419 return (
420 <div>
421 <Label htmlFor={name} hint={hint} error={error}>
422 {label}
423 </Label>
424 <div className="flex items-center rounded-md border border-line bg-bg transition-colors focus-within:border-accent-dim hover:border-line-strong">
425 <span className="pl-3 text-sm text-faint">$</span>
426 <input
427 id={name}
428 name={name}
429 inputMode="decimal"
430 defaultValue={dollarsField(value)}
431 placeholder="No cap"
432 autoComplete="off"
433 data-1p-ignore
434 className="min-w-0 grow bg-transparent px-2 py-2 text-sm tabular-nums outline-none placeholder:text-faint"
435 />
436 </div>
437 </div>
438 );
439}
440
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)441/** Names to shuffle through when a template has none of its own. */
442const FALLBACK_NAMES = ["Margo", "Juniper", "Otto", "Wren", "Basil", "Nova", "Clementine", "Fig", "Rook", "Pip"];
443
Chat and workspace agents: channels, DMs and named agents you talk to444/**
445 * Everything that defines an agent, for making one and for its Profile:
446 * who it is, its job, its voice, the limits on routing, its budget, what it
447 * may do alone, and how much it takes on at once.
448 */
449export function AgentForm({
450 draft,
451 errors,
452 submit,
453 intent,
454 formKey,
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)455 nameIdeas = [],
456 locked = false,
457 seed,
458 teams = [],
Agents recall what Docs say before they answer or work, and each has required reading459 spaces = [],
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.460 hidden = {},
461 personal = false,
Pricing says it plainly: models at the provider's price, the agent rate for what g1t runs around every model call (the gateway, secrets, routing, context and pass-through to your own provider, so your own keys too), everything else at cost plus 20%, your own runners free, no seats; Security and quality comes with the plan with no separate fee, and live activations end. Each agent has an effort setting, Auto to Max, with what a typical task has cost at each level, and Spend's Spend less, keep quality suggests a lower level only when the agent's own past work shows quality held, to apply or dismiss. The pricing, spend and agents guides say how.462 effortCosts,
Chat and workspace agents: channels, DMs and named agents you talk to463}: {
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.464 /** A personal agent: on no team. */
465 personal?: boolean;
466 /** Fields the form carries without showing: a drafted agent's scope, skills and face. */
467 hidden?: Record<string, string>;
Pricing says it plainly: models at the provider's price, the agent rate for what g1t runs around every model call (the gateway, secrets, routing, context and pass-through to your own provider, so your own keys too), everything else at cost plus 20%, your own runners free, no seats; Security and quality comes with the plan with no separate fee, and live activations end. Each agent has an effort setting, Auto to Max, with what a typical task has cost at each level, and Spend's Spend less, keep quality suggests a lower level only when the agent's own past work shows quality held, to apply or dismiss. The pricing, spend and agents guides say how.468 /** What each effort level has cost this agent, when it has a history; a new agent has none. */
469 effortCosts?: AgentEffortCosts | null;
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)470 /** The workspace's teams, to put it on one. */
471 teams?: { slug: string; name: string }[];
Agents recall what Docs say before they answer or work, and each has required reading472 /** The Docs spaces the person editing can read, for its required reading. */
473 spaces?: { id: string; name: string; kind: string }[];
Chat and workspace agents: channels, DMs and named agents you talk to474 draft: AgentDraft;
475 errors?: Record<string, string>;
476 submit: string;
477 intent: string;
478 formKey?: string;
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)479 /** Names to shuffle through (a template's `name_ideas`); the dice offers them. */
480 nameIdeas?: string[];
481 /** g1t, the orchestrator: its identity and job are fixed; the rest is editable. */
482 locked?: boolean;
483 /** The agent's own `avatar_seed`, once it has one; a new agent's face follows its handle. */
484 seed?: string | null;
Chat and workspace agents: channels, DMs and named agents you talk to485}) {
486 const navigation = useNavigation();
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)487 // The handle follows the name until someone edits it.
488 const [name, setName] = useState(draft.display_name);
489 const [handle, setHandle] = useState(draft.handle);
490 const [handleEdited, setHandleEdited] = useState(Boolean(draft.handle) && cleanHandle(draft.display_name) !== draft.handle);
491 const ideas = nameIdeas.length > 0 ? nameIdeas : FALLBACK_NAMES;
492 const [idea, setIdea] = useState(() => Math.max(0, ideas.indexOf(draft.display_name)));
493 const rename = (next: string) => {
494 setName(next);
495 if (!handleEdited) setHandle(cleanHandle(next));
496 };
497 const shuffle = () => {
498 const at = (idea + 1) % ideas.length;
499 setIdea(at);
500 rename(ideas[at]!);
501 };
Chat and workspace agents: channels, DMs and named agents you talk to502 const { pathname } = useLocation();
503 const busy = navigation.state === "submitting" && navigation.formAction === pathname;
504 const [preset, setPreset] = useState(draft.personality_preset);
505 const [advanced, setAdvanced] = useState(Boolean(draft.routing.pinned));
506 const e = errors ?? {};
507 const presetAbout = PRESETS.find((p) => p.value === preset)?.about;
508 return (
509 <Form method="post" key={formKey} className="pb-24">
510 <input type="hidden" name="intent" value={intent} />
511 <input type="hidden" name="template" value={draft.template ?? ""} />
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.512 {Object.entries(hidden).map(([name, value]) => (
513 <input key={name} type="hidden" name={name} value={value} />
514 ))}
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)515 <FormSection
516 title="Identity"
517 about={
518 locked
519 ? "g1t is the workspace's orchestrator: its name, handle and role are the same everywhere, and it can't be archived."
520 : "How it shows in chat, mentions, assignees and the audit log. Give it a name people will enjoy saying."
521 }
522 >
523 <div className="flex items-center gap-3">
524 <AgentAvatar agent={{ handle: handle || "agent", avatar_seed: seed ?? handle, builtin: locked }} size={44} />
525 <div className="min-w-0 text-sm">
526 <p className="truncate font-semibold">{name || "Your new agent"}</p>
527 <p className="truncate text-xs text-muted">{handle ? `@${handle}` : "@handle"}</p>
528 </div>
529 </div>
Chat and workspace agents: channels, DMs and named agents you talk to530 <div className="grid gap-5 sm:grid-cols-2">
531 <div>
532 <Label htmlFor="display_name" error={e.display_name}>
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)533 Name
Chat and workspace agents: channels, DMs and named agents you talk to534 </Label>
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)535 <div className="flex gap-2">
536 <input
537 id="display_name"
538 name="display_name"
539 value={name}
540 onChange={(event) => rename(event.target.value)}
541 readOnly={locked}
542 placeholder="Margo"
543 className={`${FIELD} ${locked ? "cursor-not-allowed text-muted" : ""}`}
544 autoComplete="off"
545 data-1p-ignore
546 />
547 {!locked && (
548 <Hint label="Another name">
549 <button
550 type="button"
551 aria-label="Another name"
552 onClick={shuffle}
553 className="flex size-[38px] shrink-0 items-center justify-center rounded-md border border-line text-muted transition-colors hover:border-line-strong hover:bg-raised hover:text-fg active:rotate-12"
554 >
555 <Dices size={17} />
556 </button>
557 </Hint>
558 )}
559 </div>
Chat and workspace agents: channels, DMs and named agents you talk to560 </div>
561 <div>
562 <Label htmlFor="handle" error={e.handle} hint="Mentioned as @handle">
563 Handle
564 </Label>
565 <div className="flex items-center rounded-md border border-line bg-bg transition-colors focus-within:border-accent-dim hover:border-line-strong">
566 <span className="pl-3 font-mono text-sm text-faint">@</span>
567 <input
568 id="handle"
569 name="handle"
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)570 value={handle}
571 onChange={(event) => {
572 setHandle(event.target.value);
573 setHandleEdited(true);
574 }}
575 readOnly={locked}
576 placeholder="margo"
Chat and workspace agents: channels, DMs and named agents you talk to577 autoComplete="off"
578 data-1p-ignore
579 className="min-w-0 grow bg-transparent py-2 pr-3 pl-0.5 font-mono text-sm outline-none placeholder:text-faint"
580 />
581 </div>
582 </div>
583 </div>
584 </FormSection>
585
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)586 {!locked && (
587 <FormSection
588 title="Role"
589 about="Hired into a role, not a task: a title, a team, and what it is responsible for. Shown as its name and title everywhere."
590 >
591 <RoleFields
592 title={draft.title}
593 team={draft.team}
594 department={draft.department}
595 responsibilities={draft.responsibilities}
596 teams={teams}
597 errors={e}
598 locked={locked}
Anyone makes an agent by describing it: one box drafts the whole agent (name, job, responsibilities, voice, skills to keep, integrations it needs, model limits and budget) as a card to change and try in a chat beside it before creating it, and an agent changes later by saying what to change, shown as a diff before it's saved. Members can make personal agents, which only they talk to and which spend from their own budget, unless owners turn that off; owners promote one to a workspace agent. The agents guide says how.599 personal={personal}
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)600 />
601 </FormSection>
602 )}
603
604 <FormSection
605 title="Job"
606 about={
607 locked
608 ? "Its job is fixed: know the team, hand work to the right specialist, do it itself when nobody fits, and report. Add your own instructions on top."
609 : "What it is responsible for, how it works, and what good looks like. It reads this before every reply and task."
610 }
611 >
Chat and workspace agents: channels, DMs and named agents you talk to612 <div>
613 <Label htmlFor="instructions" error={e.instructions}>
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)614 {locked ? "Extra instructions" : "Instructions"}
Chat and workspace agents: channels, DMs and named agents you talk to615 </Label>
616 <textarea
617 id="instructions"
618 name="instructions"
619 defaultValue={draft.instructions}
620 rows={9}
621 placeholder={"Cut a release of g1t every Tuesday.\n- Read the merged pull requests since the last tag.\n- Write the release notes.\n- Ask in #releases before tagging."}
622 className={`${FIELD} resize-y font-mono text-[0.8125rem] leading-relaxed`}
623 />
624 </div>
625 </FormSection>
626
Agents recall what Docs say before they answer or work, and each has required reading627 <FormSection
628 title="Required reading"
629 about="Docs it checks first, every time it answers or works. It also recalls whatever else in Docs fits the question, but only from spaces everyone in the conversation can read."
630 >
631 {spaces.length ? (
632 <div className="grid gap-1.5 sm:grid-cols-2">
633 {spaces.map((space) => (
634 <label
635 key={space.id}
636 className="flex min-h-10 cursor-pointer items-center gap-2.5 rounded-lg border border-line bg-surface px-3 py-2 text-sm has-[:checked]:border-accent/50 has-[:checked]:bg-accent/5"
637 >
638 <input type="checkbox" name="reading" value={space.id} defaultChecked={(draft.reading ?? []).includes(space.id)} className="size-4 accent-[var(--color-accent)]" />
639 <span className="min-w-0 grow truncate">{space.name}</span>
640 <span className="shrink-0 text-xs text-faint capitalize">{space.kind}</span>
641 </label>
642 ))}
643 </div>
644 ) : (
645 <p className="text-sm text-muted">No Docs spaces yet. Once your workspace has some, choose what it should know by heart.</p>
646 )}
647 {(draft.reading ?? []).filter((id) => !spaces.some((space) => space.id === id)).map((id) => (
648 // Spaces it reads that you can't see stay as they are.
649 <input key={id} type="hidden" name="reading" value={id} />
650 ))}
651 </FormSection>
652
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)653 {!locked && (
654 <FormSection title="Subagents" about="Help it calls on for one kind of work inside its own tasks. Never members of the workspace, and never wider than the agent itself.">
655 <SubagentsField initial={draft.subagents} routing={draft.routing} />
656 {e.subagents && <p className="text-sm text-danger">{e.subagents}</p>}
657 </FormSection>
658 )}
659
Chat and workspace agents: channels, DMs and named agents you talk to660 <FormSection title="Personality" about="Its voice only: tone, length, how it asks. A personality never changes what it may do.">
661 <div>
662 <input type="hidden" name="personality_preset" value={preset} />
663 <div role="radiogroup" aria-label="Voice" className="grid grid-cols-2 gap-1 rounded-lg bg-surface p-1 ring-1 ring-line sm:grid-cols-4">
664 {PRESETS.map((option) => (
665 <button
666 key={option.value}
667 type="button"
668 role="radio"
669 aria-checked={preset === option.value}
670 onClick={() => setPreset(option.value)}
671 className={`h-8 rounded-md text-[0.8125rem] font-medium transition-colors ${
672 preset === option.value ? "bg-raised text-fg shadow-sm ring-1 ring-line-strong" : "text-muted hover:text-fg"
673 }`}
674 >
675 {option.label}
676 </button>
677 ))}
678 </div>
679 <p className="mt-2 text-xs text-muted">{presetAbout}</p>
680 </div>
681 <div>
682 <Label htmlFor="personality" hint="Optional">
683 In its own words
684 </Label>
685 <textarea
686 id="personality"
687 name="personality"
688 defaultValue={draft.personality}
689 rows={3}
690 placeholder="Dry humor is fine. No emoji. Asks one question at a time."
691 className={`${FIELD} resize-y`}
692 />
693 </div>
694 </FormSection>
695
696 <FormSection
697 title="Models"
698 about="Nobody picks a model to get work done. g1t routes each step to the tier it needs and records which ran. These only limit the routing."
699 >
700 <div className="flex items-start gap-3 rounded-xl border border-accent/25 bg-accent/[0.06] p-4">
701 <span className="mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-accent/15 text-accent">
702 <RouteIcon size={16} />
703 </span>
704 <div>
705 <p className="text-sm font-semibold">Auto: routed per step by need</p>
706 <p className="mt-0.5 text-[0.8125rem] leading-relaxed text-muted">
707 Replies and triage run on Fast; making changes on Standard; planning, hard reviews and retries after a failure on Most capable. It steps up after a failure and back down when the cheaper tier works.
708 </p>
709 </div>
710 </div>
Pricing says it plainly: models at the provider's price, the agent rate for what g1t runs around every model call (the gateway, secrets, routing, context and pass-through to your own provider, so your own keys too), everything else at cost plus 20%, your own runners free, no seats; Security and quality comes with the plan with no separate fee, and live activations end. Each agent has an effort setting, Auto to Max, with what a typical task has cost at each level, and Spend's Spend less, keep quality suggests a lower level only when the agent's own past work shows quality held, to apply or dismiss. The pricing, spend and agents guides say how.711 <div>
712 <Label hint="Tier, reasoning and steps together">Effort</Label>
713 <EffortPicker value={effortSetting(draft.routing)} costs={effortCosts} />
714 </div>
Chat and workspace agents: channels, DMs and named agents you talk to715 <div className="grid gap-5 sm:grid-cols-3">
716 <div>
717 <Label htmlFor="floor">Floor</Label>
718 <TierSelect name="floor" value={draft.routing.floor} none="No floor" />
719 </div>
720 <div>
721 <Label htmlFor="ceiling" error={e.ceiling}>
722 Ceiling
723 </Label>
724 <TierSelect name="ceiling" value={draft.routing.ceiling} none="No ceiling" />
725 </div>
726 <div>
727 <Label htmlFor="providers">Providers</Label>
728 <Select name="providers" defaultValue={draft.routing.providers[0] ?? "any"}>
729 <SelectTrigger id="providers">
730 <SelectValue />
731 </SelectTrigger>
732 <SelectContent>
733 <SelectItem value="any" description="g1t's hosted models and the workspace's own">
734 Any the workspace allows
735 </SelectItem>
736 <SelectItem value="g1t" description="Never the workspace's own keys">
737 g1t's hosted models
738 </SelectItem>
739 <SelectItem value="workspace" description="Set up under Integrations; billed by the provider">
740 The workspace's own providers
741 </SelectItem>
742 </SelectContent>
743 </Select>
744 </div>
745 </div>
746 <div className="rounded-lg border border-line">
747 <button
748 type="button"
749 onClick={() => setAdvanced(!advanced)}
750 aria-expanded={advanced}
751 className="flex w-full items-center gap-2 px-3.5 py-2.5 text-left text-[0.8125rem] font-medium text-muted hover:text-fg"
752 >
753 <ChevronRight size={14} className={`transition-transform ${advanced ? "rotate-90" : ""}`} />
754 Advanced
755 <span className="font-normal text-faint">Pin one model</span>
756 </button>
757 <div hidden={!advanced} className="border-t border-line px-3.5 py-3.5">
758 <Label htmlFor="pinned" error={e.pinned} hint="For your own endpoints. Turns routing off.">
759 Pinned model
760 </Label>
761 <input id="pinned" name="pinned" defaultValue={draft.routing.pinned ?? ""} placeholder="provider/model" className={`${FIELD} font-mono`} autoComplete="off" data-1p-ignore />
762 </div>
763 </div>
764 </FormSection>
765
766 <FormSection title="Budget" about="Checked before work starts and enforced while it runs. At 80% of the month it tells you; at 100% it takes no new tasks.">
767 <div className="grid gap-5 sm:grid-cols-3">
768 <Money name="monthly" label="Monthly" hint="Per calendar month" value={draft.budget.monthly_micros} error={e.monthly} />
769 <Money name="daily" label="Daily" hint="Optional" value={draft.budget.daily_micros} error={e.daily} />
Agents mode: an overview of every agent's work and spend, and each agent's sessions, memory, routines, spend, activity and versions770 <Money name="task" label="Per session" hint="Going over asks an owner" value={draft.budget.task_micros} error={e.task} />
Chat and workspace agents: channels, DMs and named agents you talk to771 </div>
772 </FormSection>
773
774 <FormSection title="Autonomy" about="What it may do alone and what needs a person. Rulesets and branch protection still apply on top.">
775 <div className="grid gap-5 sm:grid-cols-2">
776 {(Object.keys(AUTONOMY) as (keyof typeof AUTONOMY)[]).map((key) => (
777 <div key={key}>
778 <Label htmlFor={key}>{AUTONOMY[key].label}</Label>
779 <Select name={key} defaultValue={draft.autonomy[key]}>
780 <SelectTrigger id={key}>
781 <SelectValue />
782 </SelectTrigger>
783 <SelectContent>
784 {AUTONOMY[key].options.map(([value, label]) => (
785 <SelectItem key={value} value={value}>
786 {label}
787 </SelectItem>
788 ))}
789 </SelectContent>
790 </Select>
791 </div>
792 ))}
793 </div>
794 </FormSection>
795
Agents mode: an overview of every agent's work and spend, and each agent's sessions, memory, routines, spend, activity and versions796 <FormSection title="Capacity" about="How many sessions it works on at once. More wait in line, queued.">
Chat and workspace agents: channels, DMs and named agents you talk to797 <div className="max-w-40">
798 <Label htmlFor="capacity" error={e.capacity}>
Agents mode: an overview of every agent's work and spend, and each agent's sessions, memory, routines, spend, activity and versions799 Sessions at once
Chat and workspace agents: channels, DMs and named agents you talk to800 </Label>
801 <input id="capacity" name="capacity" type="number" min={1} max={20} defaultValue={draft.capacity} className={`${FIELD} tabular-nums`} />
802 </div>
803 </FormSection>
804
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 bar805 <div className="sticky bottom-(--tabbar-h) in-data-[keyboard=open]:bottom-0 z-10 -mx-4 flex items-center justify-end gap-3 border-t border-line bg-bg/90 px-4 py-3 backdrop-blur sm:-mx-8 sm:px-8">
Chat and workspace agents: channels, DMs and named agents you talk to806 {Object.keys(e).length > 0 && <p className="mr-auto text-sm text-danger">Check the fields marked above.</p>}
807 <button
808 type="submit"
809 disabled={busy}
810 className="inline-flex h-9 items-center gap-2 rounded-md bg-accent px-4 text-sm font-medium text-bg transition-colors hover:bg-accent-hover disabled:opacity-60"
811 >
812 <Sparkles size={15} />
813 {busy ? "Saving…" : submit}
814 </button>
815 </div>
816 </Form>
817 );
818}

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