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
276 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.

The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.1/**
2 * Home's reads: each section's data from its own service, every call on
3 * its own so one that fails leaves only its section saying so. The shaping
4 * is in ./home.ts.
5 */
6import { env } from "cloudflare:workers";
7
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.8import {
9 type ActivityDigest,
10 type ChatActivity,
11 type Deployment,
12 MAX_DIGEST_REPOS,
13 type Memory,
14 type ProjectDeploys,
15 type Repo,
16 type RepoPath,
17 type User,
18 type WorkflowRun,
19 notifyClient,
20} from "@g1t/contracts";
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.21
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.22import { type CodePull, type CodeWork, G1T_ACTOR, type RepoRef, type Span, type Spend, deployActorKey, spanMonths, spendIn } from "./home";
23import { monthSpan } from "./usage";
24import { actions, agents, billing, chat, deployments, events, identity, repos, work } from "./services.server";
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.25
26/** Pull requests read per project and list: `LIST_PAGE` in services/work. */
27const PULL_PAGE = 100;
28/** The most projects whose pull requests are read. */
29const MAX_PROJECTS = 50;
30/** The most projects whose builds are read for the span. */
31const MAX_DEPLOY_PROJECTS = 20;
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.32/** The most projects whose workflow runs are read for Running now: those pushed to most in the span. */
33const MAX_WORKFLOW_PROJECTS = 10;
34/** Runs read per project: enough to find the ones not finished. */
35const WORKFLOW_RUNS = 20;
36/** The most member keys named in one lookup. */
37const MAX_NAMES = 200;
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.38const DAY = 24 * 60 * 60 * 1000;
39
40const warn = (what: string) => (error: unknown) => {
41 console.warn(`home: ${what} failed`, error);
42 return null;
43};
44
45/**
46 * When the viewer was last on this workspace's Home, from notify, where it
47 * is kept with them (the same on every device). Null when there is no
48 * visit on record; undefined when notify did not answer.
49 */
50export async function loadLastVisit(viewer: User, slug: string): Promise<number | null | undefined> {
51 if (!env.NOTIFY) return undefined;
52 const visit = await notifyClient(env.NOTIFY).lastVisit(viewer, slug).catch(warn("last visit"));
53 if (!visit) return undefined;
54 return visit.seen_at ? Date.parse(visit.seen_at) : null;
55}
56
57/** Marks the viewer's visit at `at`, the time the page they looked at loaded. */
58export async function markVisit(viewer: User, slug: string, at: number): Promise<boolean> {
59 if (!env.NOTIFY) return false;
60 const marked = await notifyClient(env.NOTIFY).markVisit(viewer, slug, new Date(at).toISOString()).catch(warn("mark visit"));
61 return marked != null;
62}
63
64/**
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.65 * The workspace's own repositories the viewer may read (no pull request
66 * working copies), as every Code section reads them. Null when repos did
67 * not answer.
68 */
69export async function loadRepos(viewer: User, slug: string): Promise<Repo[] | null> {
70 const list = await repos.list(viewer, { namespace: slug }).catch(warn("repos"));
71 return list ? list.filter((repo) => !repo.forkOf && repo.namespace.toLowerCase() === slug) : null;
72}
73
74/** The repositories by id, as the digest's lines and links need them. */
75export function repoRefs(list: Repo[] | null): Record<string, RepoRef> {
76 const refs: Record<string, RepoRef> = {};
77 for (const repo of list ?? []) refs[repo.id] = { namespace: repo.namespace, name: repo.name, defaultBranch: repo.defaultBranch };
78 return refs;
79}
80
81/**
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.82 * The workspace's projects' pull requests, open and recently merged or
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.83 * closed, any author's. `complete` when every list reaches back to
84 * `reach`. Null when Code did not answer.
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.85 */
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.86export async function loadCodeWork(viewer: User, slug: string, reach: number, owned: Repo[] | null): Promise<CodeWork | null> {
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.87 if (!owned) return null;
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.88 const chosen = owned.slice(0, MAX_PROJECTS);
89 const byId = new Map<string, Repo>(chosen.map((repo) => [repo.id, repo]));
90 const batch = chosen.length > 0 ? await work.pullsForRepos([...byId.keys()], viewer, PULL_PAGE).catch(warn("pull requests")) : [];
91 if (!batch) return null;
92 const pulls: CodePull[] = [];
93 let complete = owned.length <= MAX_PROJECTS;
94 for (const entry of batch) {
95 const repo = byId.get(entry.repoId);
96 if (!repo) continue;
97 const path = { namespace: repo.namespace, name: repo.name };
98 for (const pull of [...entry.open, ...entry.closed]) {
99 pulls.push({
100 repo: path,
101 number: pull.number,
102 title: pull.title,
103 status: pull.status,
104 mergedAt: pull.mergedAt,
105 mergedBy: pull.mergedBy,
106 createdAt: pull.createdAt,
107 updatedAt: pull.updatedAt,
108 author: { username: pull.author.username, kind: pull.author.kind },
109 });
110 }
111 // A full page that does not reach back far enough may leave some out.
112 for (const list of [entry.open, entry.closed]) {
113 if (list.length >= PULL_PAGE) {
114 const oldest = Math.min(...list.map((pull) => Date.parse(pull.mergedAt ?? pull.updatedAt)));
115 if (oldest > reach) complete = false;
116 }
117 }
118 }
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.119 return { pulls, complete };
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.120}
121
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.122/**
123 * What happened in the span, counted by who did it: the events service's
124 * digest of the workspace's repositories (the first MAX_DIGEST_REPOS of
125 * them; none without Code access) and of its artifacts. Null when events
126 * did not answer.
127 */
128export async function loadActivity(slug: string, span: Pick<Span, "from" | "now">, owned: Repo[] | null): Promise<ActivityDigest | null> {
129 const digest = await events
130 .activityDigest({
131 repo_ids: (owned ?? []).slice(0, MAX_DIGEST_REPOS).map((repo) => repo.id),
132 workspace: slug,
133 from: new Date(span.from).toISOString(),
134 until: new Date(span.now + 1).toISOString(),
135 })
136 .catch(warn("activity digest"));
137 if (!digest) return null;
138 // More repositories than the digest reads: it says so.
139 return owned && owned.length > MAX_DIGEST_REPOS ? { ...digest, complete: false } : digest;
140}
141
142/** What was said in the span where the viewer can read, counted. Null when chat did not answer. */
143export async function loadChatActivity(viewer: User, slug: string, span: Pick<Span, "from" | "now">): Promise<ChatActivity | null> {
144 const activity = await chat
145 .activity(slug, viewer, { from: new Date(span.from).toISOString(), until: new Date(span.now + 1).toISOString() })
146 .catch(warn("chat activity"));
147 return activity?.ok ? activity.value : null;
148}
149
150/** Every member key the digest and chat name. */
Notifications is the bell in the top bar alone: the rail no longer carries it, and the notifications guide points at the bell; a phone keeps it in the bottom bar, which has no bell. Home names who made a deployment, by username or by an agent's handle, instead of showing the account's id, and says someone when identity doesn't know the id. The Apps launcher's skeleton tiles are drawn in the line colour so they show on its raised surface.151export function actorKeys(activity: ActivityDigest | null, chatActivity: ChatActivity | null, deploys?: { projects: { deployments: { createdBy: string }[] }[] } | null): string[] {
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.152 const keys = new Set<string>();
Notifications is the bell in the top bar alone: the rail no longer carries it, and the notifications guide points at the bell; a phone keeps it in the bottom bar, which has no bell. Home names who made a deployment, by username or by an agent's handle, instead of showing the account's id, and says someone when identity doesn't know the id. The Apps launcher's skeleton tiles are drawn in the line colour so they show on its raised surface.153 for (const project of deploys?.projects ?? []) for (const deploy of project.deployments) keys.add(deployActorKey(deploy.createdBy) ?? "");
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.154 for (const repo of activity?.repos ?? []) {
155 for (const by of [...repo.pushes.by, ...repo.pushes.default_branch.by]) keys.add(by.actor);
156 for (const list of [repo.pulls.opened, repo.pulls.merged, repo.pulls.closed, repo.issues.opened, repo.issues.closed, repo.reviews, repo.comments, repo.deployments.succeeded, repo.deployments.failed]) {
157 for (const entry of list) keys.add(entry.actor);
158 }
159 for (const release of repo.releases) keys.add(release.actor);
160 for (const pkg of repo.packages) keys.add(pkg.actor);
161 }
162 for (const entry of activity?.folios?.created ?? []) keys.add(entry.actor);
163 for (const folio of activity?.folios?.edited ?? []) for (const author of folio.authors) keys.add(author);
164 for (const author of chatActivity?.authors ?? []) keys.add(author.key);
165 keys.delete("");
166 return [...keys];
167}
168
169/**
170 * The names behind member keys: people's usernames from identity (one
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.171 * lookup for them all), g1t as itself. A key identity does not know, and
172 * an agent of older rows, is left out, and shows as "someone".
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.173 */
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.174export async function loadNames(keys: string[]): Promise<Record<string, string>> {
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.175 const names: Record<string, string> = {};
176 const userIds: string[] = [];
177 for (const key of keys.slice(0, MAX_NAMES)) {
Four small things seen today. An agent can attach a file it made to any doc the person who asked can edit, whatever the space's agent mode: attaching changes nothing in the doc, so the suggest mode that stopped every PDF and spreadsheet no longer does; the ability is its own, attach, beside read, suggest and edit. Home no longer counts robots among the people: events that name an agent by its own id, or g1t's upkeep as the workspace or as g1t, read as the agent and as g1t, in the digest and on the page, so the faces say who instead of someone. Tooltips are the inverted bubble, the page's foreground behind the page's background, with no border. The Spend page's slice tabs keep their ring inside the row instead of losing its top to the scroll edge, and the Apps launcher keeps its search box and footer in place while it reads which apps there are, with skeleton tiles between.178 if (key === G1T_ACTOR || key === "user:g1t" || key.startsWith("user:wsp_")) names[key] = "g1t";
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.179 else if (key.startsWith("agent:") || key.startsWith("user:agt_")) continue;
180 else if (key.startsWith("user:")) userIds.push(key.slice("user:".length));
Home says what people did as well as what agents did. Since you were last here now has a People column and an Agents column: who pushed how many commits to which projects, pull requests opened, merged and reviewed, issues opened and closed, docs edited, messages sent and deploys that went out, each line a link to where those are listed, with the agents' acceptance (first time, after review, didn't finish) kept as a row of their column; the sentence under the heading sums it up honestly, and says when a part of g1t could not be read, or that the span was quiet. Landed counts merged pull requests, commits pushed straight to a default branch, production deploys that went live, releases and packages, newest first; Running now adds workflow runs. Behind it, the events service answers an activity digest over a span in one round trip from its existing indexes, every push now records how many commits it carried, and chat counts the messages sent in the conversations you can read. The Home guide defines every line, and says how this scales.181 }
182 if (userIds.length > 0) {
183 const found = await identity.usernames(userIds).catch(warn("usernames"));
184 for (const [id, username] of Object.entries(found ?? {})) names[`user:${id}`] = username;
185 }
186 return names;
187}
188
189/**
190 * The newest workflow runs of the projects pushed to most in the span (at
191 * most MAX_WORKFLOW_PROJECTS), for the ones still going. A project whose
192 * runs could not be read is left out; `complete` says whether every one was.
193 */
194export async function loadWorkflowRuns(
195 viewer: User,
196 activity: ActivityDigest | null,
197 owned: Repo[] | null,
198): Promise<{ projects: { repo: RepoPath; runs: WorkflowRun[] }[]; complete: boolean }> {
199 const byId = new Map((owned ?? []).map((repo) => [repo.id, repo]));
200 const active = [...(activity?.repos ?? [])]
201 .filter((repo) => repo.pushes.count > 0 && byId.has(repo.repo_id))
202 .sort((a, b) => b.pushes.count - a.pushes.count || a.repo_id.localeCompare(b.repo_id))
203 .slice(0, MAX_WORKFLOW_PROJECTS);
204 const lists = await Promise.all(
205 active.map((digest) => {
206 const repo = byId.get(digest.repo_id)!;
207 const path = { namespace: repo.namespace, name: repo.name };
208 return actions
209 .runs(path, viewer, { limit: WORKFLOW_RUNS })
210 .then((result) => (result.ok ? { repo: path, runs: result.value } : null))
211 .catch(warn(`workflow runs of ${repo.name}`));
212 }),
213 );
214 const projects = lists.filter((entry) => entry != null);
215 return { projects, complete: projects.length === active.length };
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.216}
217
218/** The workspace's memory, for the decisions recorded in it. */
219export async function loadMemories(viewer: User, slug: string): Promise<Memory[] | null> {
220 const memories = await agents.listMemories(viewer, slug, null).catch(warn("memories"));
221 return memories?.ok ? memories.value.workspace : null;
222}
223
224/**
225 * Every project's builds at a glance, and the builds of the projects that
226 * deploy, for the span: the projects whose newest build is older than the
227 * span are not read again.
228 */
229export async function loadDeploys(
230 viewer: User,
231 slug: string,
232 from: number,
233): Promise<{ overview: ProjectDeploys[]; projects: { slug: string; deployments: Deployment[] }[]; complete: boolean } | null> {
234 const overview = await deployments.overview(slug, viewer).catch(warn("deploys overview"));
235 if (!overview?.ok) return null;
236 const recent = overview.value.filter((project) => project.latest && Date.parse(project.latest.finishedAt ?? project.latest.createdAt) >= from);
237 const read = recent.slice(0, MAX_DEPLOY_PROJECTS);
238 const lists = await Promise.all(
239 read.map((project) =>
240 deployments
241 .list({ workspace: slug, slug: project.slug }, viewer)
242 .then((result) => (result.ok ? { slug: project.slug, deployments: result.value.deployments } : null))
243 .catch(warn(`deploys of ${project.slug}`)),
244 ),
245 );
246 const projects = lists.filter((entry) => entry != null);
247 return { overview: overview.value, projects, complete: projects.length === recent.length };
248}
249
Money is written one way. A single formatter turns millionths of a dollar into dollars, rounding half up on whole micros rather than on a float, so the same sum reads the same on every page: under a cent reads <$0.01 on a total and exactly nothing is $0.00, while the statement's lines, a session's receipt, the price book and an agent's effort costs carry up to four places where the fraction of a cent is the point; the six formatters that each rounded their own way are gone. This month is the calendar month in UTC from its first day to today everywhere, and billing counts the month's not-yet-closed usage in any range that reaches into the current month, so the top bar's pill, Spend, Home and Usage ask for the same days and get the same figure; Home now reads the usage report the others read instead of adding up statements. Usage's pending sentence says what of that usage the close will charge after the discount and included usage, which the billing API returns as pending_charged_micros. A reconciliation test holds the pill, Spend, Home and Usage to one number for one month. The usage and billing guide says how amounts are written and what this month means.250/**
251 * The span's spend from the statements of the months it touches, and the
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.252 * month so far from the usage report Usage reads (`usage.ts` `monthSpan`,
253 * at price), so Home's figure is Usage's. Null
Money is written one way. A single formatter turns millionths of a dollar into dollars, rounding half up on whole micros rather than on a float, so the same sum reads the same on every page: under a cent reads <$0.01 on a total and exactly nothing is $0.00, while the statement's lines, a session's receipt, the price book and an agent's effort costs carry up to four places where the fraction of a cent is the point; the six formatters that each rounded their own way are gone. This month is the calendar month in UTC from its first day to today everywhere, and billing counts the month's not-yet-closed usage in any range that reaches into the current month, so the top bar's pill, Spend, Home and Usage ask for the same days and get the same figure; Home now reads the usage report the others read instead of adding up statements. Usage's pending sentence says what of that usage the close will charge after the discount and included usage, which the billing API returns as pending_charged_micros. A reconciliation test holds the pill, Spend, Home and Usage to one number for one month. The usage and billing guide says how amounts are written and what this month means.254 * when billing did not answer; the month alone null when only it did not.
255 */
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.256export async function loadSpend(viewer: User, slug: string, span: Pick<Span, "from" | "now">): Promise<Spend | null> {
257 const months = spanMonths(span);
Money is written one way. A single formatter turns millionths of a dollar into dollars, rounding half up on whole micros rather than on a float, so the same sum reads the same on every page: under a cent reads <$0.01 on a total and exactly nothing is $0.00, while the statement's lines, a session's receipt, the price book and an agent's effort costs carry up to four places where the fraction of a cent is the point; the six formatters that each rounded their own way are gone. This month is the calendar month in UTC from its first day to today everywhere, and billing counts the month's not-yet-closed usage in any range that reaches into the current month, so the top bar's pill, Spend, Home and Usage ask for the same days and get the same figure; Home now reads the usage report the others read instead of adding up statements. Usage's pending sentence says what of that usage the close will charge after the discount and included usage, which the billing API returns as pending_charged_micros. A reconciliation test holds the pill, Spend, Home and Usage to one number for one month. The usage and billing guide says how amounts are written and what this month means.258 const [statements, month] = await Promise.all([
259 Promise.all(months.map((month) => billing.statement(slug, viewer, month, "day").catch(warn(`statement ${month}`)))),
260 billing
261 .usageReport(slug, viewer, monthSpan(new Date(span.now)))
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.262 .then((result) => (result.ok ? result.value.totals.priceMicros : null))
Money is written one way. A single formatter turns millionths of a dollar into dollars, rounding half up on whole micros rather than on a float, so the same sum reads the same on every page: under a cent reads <$0.01 on a total and exactly nothing is $0.00, while the statement's lines, a session's receipt, the price book and an agent's effort costs carry up to four places where the fraction of a cent is the point; the six formatters that each rounded their own way are gone. This month is the calendar month in UTC from its first day to today everywhere, and billing counts the month's not-yet-closed usage in any range that reaches into the current month, so the top bar's pill, Spend, Home and Usage ask for the same days and get the same figure; Home now reads the usage report the others read instead of adding up statements. Usage's pending sentence says what of that usage the close will charge after the discount and included usage, which the billing API returns as pending_charged_micros. A reconciliation test holds the pill, Spend, Home and Usage to one number for one month. The usage and billing guide says how amounts are written and what this month means.263 .catch(warn("month usage")),
264 ]);
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.265 if (statements.some((statement) => !statement?.ok)) return null;
266 return spendIn(
267 statements.map((statement) => (statement as Extract<typeof statement, { ok: true }>).value),
268 span,
Money is written one way. A single formatter turns millionths of a dollar into dollars, rounding half up on whole micros rather than on a float, so the same sum reads the same on every page: under a cent reads <$0.01 on a total and exactly nothing is $0.00, while the statement's lines, a session's receipt, the price book and an agent's effort costs carry up to four places where the fraction of a cent is the point; the six formatters that each rounded their own way are gone. This month is the calendar month in UTC from its first day to today everywhere, and billing counts the month's not-yet-closed usage in any range that reaches into the current month, so the top bar's pill, Spend, Home and Usage ask for the same days and get the same figure; Home now reads the usage report the others read instead of adding up statements. Usage's pending sentence says what of that usage the close will charge after the discount and included usage, which the billing API returns as pending_charged_micros. A reconciliation test holds the pill, Spend, Home and Usage to one number for one month. The usage and billing guide says how amounts are written and what this month means.269 month,
The front page is Home: where you're needed comes first, however long ago it started, with what's at stake and how long it has waited; then what happened since you were last here, in words, with the agent work that settled, what landed, what deployed, what was decided and what was spent, switchable to the last 24 hours or 7 days; then what's running now. Your last visit is kept with your account, so it's the same on every device; Today's old address leads here. The home guide says how.270 );
271}
272
273/** How far back Code is read: 7 days before the span, for the comparison. */
274export function reachFor(span: Pick<Span, "from">): number {
275 return span.from - 7 * DAY;
276}