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

Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread1import { FileText, LoaderCircle } from "lucide-react";
2import { useEffect, useState } from "react";
3
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.4import type { FoliosSidebar, Result } from "@g1t/contracts";
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread5
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.6import { Button } from "../ui/button";
7import { Card } from "../ui/card";
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread8import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog";
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.9import { Field, FieldError, FieldLabel } from "../ui/field";
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread10import { Input } from "../ui/input";
11import { SelectField } from "../ui/select";
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.12import { ORCHESTRATOR, type WritableSpace, type WriteUpAgent, type WriteUpWhere, defaultWhere, writableSpaces, writeUpMessage } from "../../lib/write-up";
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread13
The docs folder is gone, and what it held lives where people read it: how a self-hosted g1t runs and how to deploy g1t to Cloudflare are pages on docs.g1t.sh under Run g1t yourself, and speed, rate limits and operating g1t.sh are sections of CONTRIBUTING.md; code that cited a file in docs/ now points to the page or section that covers it, or says what it means itself, and applied migrations and the runner images are left as they were.14// "Write this up as an artifact" (docs.g1t.sh/guides/artifacts/, "Write a
15// thread up"):
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.16// where it goes, a title if you have one, and which agent writes it. The
17// kind is a doc for now. Sending posts the ask in the thread, as you,
18// where everyone sees it; the agent answers it as it answers any mention,
19// and links the artifact it made.
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread20
21type Spaces = { state: "loading" } | { state: "ready"; spaces: WritableSpace[] } | { state: "failed"; message: string };
22
23export function WriteUpDialog({
24 open,
25 onOpenChange,
26 slug,
27 agents,
28 link,
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.29 shared,
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread30 onSend,
31}: {
32 open: boolean;
33 onOpenChange: (open: boolean) => void;
34 slug: string;
35 /** Who can write it: @g1t, then the conversation's agents (lib/write-up.ts `writeUpAgents`). */
36 agents: WriteUpAgent[];
37 /** The thread's link, cited as the source. */
38 link: string;
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.39 /** A DM or a private channel: "Shared with this conversation" is offered, and chosen first. */
40 shared: boolean;
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread41 /** Posts the ask in the thread; answers with what went wrong, or null. */
42 onSend: (body: string) => Promise<string | null>;
43}) {
44 const [spaces, setSpaces] = useState<Spaces>({ state: "loading" });
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.45 const [where, setWhere] = useState<string>("private");
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread46 const [agent, setAgent] = useState(ORCHESTRATOR);
47 const [title, setTitle] = useState("");
48 const [busy, setBusy] = useState(false);
49 const [error, setError] = useState<string | null>(null);
50
51 // The spaces, read each time it opens: one may have been made meanwhile.
52 useEffect(() => {
53 if (!open) return;
54 let live = true;
55 setSpaces({ state: "loading" });
56 setError(null);
57 setTitle("");
58 setAgent(ORCHESTRATOR);
59 (async () => {
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.60 let list: WritableSpace[] = [];
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread61 try {
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.62 const response = await fetch(`/${slug}/-/artifacts/api`);
63 const result = (await response.json()) as Result<FoliosSidebar>;
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread64 if (!live) return;
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.65 if (!result.ok) setSpaces({ state: "failed", message: result.error.message });
66 else {
67 list = writableSpaces(result.value.spaces);
68 setSpaces({ state: "ready", spaces: list });
69 }
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread70 } catch {
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.71 if (live) setSpaces({ state: "failed", message: "Couldn't load your spaces. Private and this conversation still work." });
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread72 }
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.73 if (!live) return;
74 const first = defaultWhere(shared, list);
75 setWhere(first.kind === "space" ? first.id : first.kind);
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread76 })();
77 return () => {
78 live = false;
79 };
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.80 }, [open, slug, shared]);
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread81
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.82 const list = spaces.state === "ready" ? spaces.spaces : [];
83 const space = list.find((s) => s.id === where);
84 const chosen: WriteUpWhere | null = where === "private" ? { kind: "private" } : where === "conversation" ? { kind: "conversation" } : space ? { kind: "space", id: space.id, name: space.name } : null;
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread85 const writer = agents.find((a) => a.handle === agent) ?? agents[0] ?? { handle: ORCHESTRATOR, name: ORCHESTRATOR };
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.86 const body = chosen ? writeUpMessage({ agent: writer.handle, where: chosen, title, link }) : null;
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread87
88 const submit = async () => {
89 if (!body || busy) return;
90 setBusy(true);
91 setError(null);
92 const failed = await onSend(body);
93 setBusy(false);
94 if (failed) return setError(failed);
95 onOpenChange(false);
96 };
97
98 return (
99 <Dialog open={open} onOpenChange={onOpenChange}>
100 <DialogContent className="max-w-md">
101 <DialogHeader>
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.102 <DialogTitle>Write this up as an artifact</DialogTitle>
103 <DialogDescription>An agent turns this thread into a doc: what was decided, why, and what's next, with a link back here.</DialogDescription>
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread104 </DialogHeader>
105 <form
106 className="grid gap-4"
107 onSubmit={(event) => {
108 event.preventDefault();
109 void submit();
110 }}
111 >
112 <Field>
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.113 <FieldLabel htmlFor="write-up-where">Where</FieldLabel>
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread114 {spaces.state === "loading" ? (
115 <div className="flex h-9 items-center gap-2 rounded-md border border-line px-3 text-sm text-faint">
116 <LoaderCircle size={14} className="animate-spin" aria-hidden="true" />
117 Loading spaces…
118 </div>
119 ) : (
120 <SelectField
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.121 id="write-up-where"
122 value={where}
123 onValueChange={setWhere}
124 options={[
125 ...(shared ? [{ value: "conversation", label: "Shared with this conversation" }] : []),
126 { value: "private", label: "Private (just me)" },
127 ...list.map((s) => ({ value: s.id, label: s.name })),
128 ]}
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread129 />
130 )}
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.131 {spaces.state === "failed" && <FieldError>{spaces.message}</FieldError>}
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread132 </Field>
133 <Field>
134 <FieldLabel htmlFor="write-up-title">
135 Title <span className="font-normal text-faint">(optional)</span>
136 </FieldLabel>
Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash.137 <Input id="write-up-title" value={title} onChange={(event) => setTitle(event.target.value)} placeholder="Left to the agent" maxLength={120} autoComplete="off" />
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread138 </Field>
139 <Field>
140 <FieldLabel htmlFor="write-up-agent">Written by</FieldLabel>
141 <SelectField
142 id="write-up-agent"
143 value={writer.handle}
144 onValueChange={setAgent}
145 options={agents.map((a) => ({ value: a.handle, label: a.name === a.handle ? `@${a.handle}` : `${a.name} (@${a.handle})` }))}
146 />
147 </Field>
148 {body && (
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.149 <Card tone="plain" radius="lg" className="bg-bg/60 p-3">
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread150 <p className="mb-1 flex items-center gap-1.5 text-xs font-medium text-muted">
151 <FileText size={13} aria-hidden="true" />
152 Posts in this thread, as you
153 </p>
154 <p className="text-[0.8125rem] leading-snug break-words text-fg-soft">{body}</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.155 </Card>
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread156 )}
157 <FieldError>{error}</FieldError>
158 <DialogFooter>
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.159 <Button
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread160 type="button"
161 onClick={() => onOpenChange(false)}
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 variant="outline"
163 className="px-3 text-fg/90"
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread164 >
165 Cancel
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.166 </Button>
167 <Button
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread168 type="submit"
169 disabled={!body || busy}
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.170 variant="accent"
171 className="gap-1.5"
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread172 >
173 {busy && <LoaderCircle size={14} className="animate-spin" aria-hidden="true" />}
174 {busy ? "Asking…" : `Ask @${writer.handle}`}
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.175 </Button>
Write a thread up in Docs from chat; cards' buttons in notifications; a session's card stays at the top of its thread176 </DialogFooter>
177 </form>
178 </DialogContent>
179 </Dialog>
180 );
181}