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.
| Initial g1t: services, event bus, intents and attempts | 1 | # g1t plan |
| 2 | ||
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 3 | g1t is where people and agents ship software together: a git platform built on Cloudflare Workers and Artifacts for |
| Initial g1t: services, event bus, intents and attempts | 4 | the "Build the Next-Gen Git Platform on Cloudflare" competition. |
| 5 | ||
| 6 | - Submission closes **October 14, 2026, 11:59 PM PDT**: a 5–10 minute demo | |
| 7 | video, this repository (MIT) and run instructions. | |
| 8 | - Judging: 50% originality and quality of the prototype for agent-oriented | |
| 9 | collaboration; 25% multi-agent concurrency, coordination, context | |
| 10 | preservation, review and conflict handling; 25% ease of use. | |
| 11 | ||
| Agents as a team: lifecycle, merge queue, billing and a new shell | 12 | ## The point |
| 13 | ||
| The plan says what g1t is for without measuring it against other products | 14 | **g1t is where a team of agents ships code, with the people they work for.** |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 15 | |
| The plan says what g1t is for without measuring it against other products | 16 | Hosting git is table stakes, and g1t does it the familiar way: issues, |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 17 | branches, pull requests, review, protected branches, people working by hand. |
| 18 | None of that is the selling point. The selling point is the layer above it, | |
| 19 | which no forge has: **you hand g1t an outcome, and a fleet of agents converges | |
| 20 | it onto `main`, coordinating with each other and with you, with every decision | |
| 21 | on the record.** | |
| 22 | ||
| 23 | Three things only g1t does, and every feature should serve one of them: | |
| 24 | ||
| 25 | 1. **Outcomes, not pull requests.** The unit people work in is "make onboarding | |
| 26 | work offline", not branch #4012. A brief becomes a plan of issues with | |
| 27 | dependencies; agents take them as they unblock; people steer the outcome | |
| The plan says what g1t is for without measuring it against other products | 28 | and see it converge, rather than stopping at the pull request. |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 29 | 2. **Agents that work as a team.** Agents know what the others are doing, file |
| 30 | what they find instead of widening their change, ask and answer each other | |
| 31 | through the forge, and defer to people. Many agents on one codebase without | |
| 32 | a human refereeing collisions. | |
| 33 | 3. **`main` that only ever moves forward.** Every change lands through checks | |
| 34 | in the combination it will live in (the merge queue), failures go back to the | |
| 35 | agent that wrote them, and any line can answer "why is this here?" | |
| 36 | ||
| Initial g1t: services, event bus, intents and attempts | 37 | ## Product model |
| 38 | ||
| Issues and pull requests replace intents and attempts | 39 | g1t keeps the two things every engineer already knows, issues and pull |
| 40 | requests, and changes the assumption underneath them. A forge built for | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 41 | people expects a few changes in flight, each watched by its author. g1t |
| 42 | expects dozens of agents working at once across a project, each on its own | |
| 43 | issue, all of which have to land on `main`. A person assigns an issue to | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 44 | g1t and chooses nothing else: not how many agents, and not which |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 45 | model. An issue can still collect more than one pull request (a second |
| 46 | attempt, or someone's own agent alongside g1t's), and when it does the | |
| 47 | issue records which one was taken. | |
| Initial g1t: services, event bus, intents and attempts | 48 | |
| 49 | | Concept | What it is | | |
| 50 | | --- | --- | | |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 51 | | **Issue** | What should change in a repo: a bug, a feature, a question. Opened by a person, an agent or an integration such as an error tracker. Carries labels, a description that may say what done means (a Definition of done: context, never a gate), comments, and every pull request made for it. What a merge needs is the default branch's required checks: workflow statuses, the same for people and agents. | |
| Issues and pull requests replace intents and attempts | 52 | | **Pull request** | A proposed change in its own Artifacts fork, made by an agent or a person, usually for an issue. Any number can be open for one issue. Starts as a draft; marked ready; merged or closed. | |
| 53 | | **Session** | The agent's full context for a pull request: prompt, messages, tool calls, cost. Stored with the pull request and linked from every commit it produced. | | |
| 54 | | **Compare view** | Every pull request for an issue side by side with diff, check results, conflicts against main and against each other, and a reviewer agent's summary. | | |
| 55 | | **Merge** | A person or a policy picks a pull request. A per-repo merge queue lands it. The issue closes, recording which pull request resolved it; the others for that issue close as superseded, or are rebased by their agents when the issue is kept open. | | |
| 56 | ||
| 57 | Issues and pull requests share one sequence of numbers per repository, so | |
| 58 | `#12` names exactly one of them. | |
| Initial g1t: services, event bus, intents and attempts | 59 | |
| 60 | Features that fall out of the model: | |
| 61 | ||
| 62 | - **Why-blame.** Click a line and see the prompt and reasoning that produced | |
| 63 | it, not only the commit. | |
| Issues and pull requests replace intents and attempts | 64 | - **Overlap radar.** Pull requests that touch the same files are flagged |
| 65 | while the agents are still working, and the agents are told. | |
| 66 | - **Live lanes.** Watch every pull request progress in real time. | |
| 67 | ||
| 68 | ## Why issues and pull requests, not something new | |
| 69 | ||
| 70 | An earlier version of this plan merged the two into one new object, an | |
| 71 | "issue" holding "pull requests". That was wrong, for three reasons. | |
| Initial g1t: services, event bus, intents and attempts | 72 | |
| Issues and pull requests replace intents and attempts | 73 | - **Issues come from everywhere.** People file them, agents file them, and |
| 74 | Sentry files them. Most are never worked on by whoever opened them. They | |
| 75 | need their own life: labels, triage, discussion, closing as not planned. | |
| 76 | - **"Which change did we take?" needs two objects.** When five agents each | |
| 77 | propose a change, the answer has to be recorded somewhere other than the | |
| 78 | five proposals. On g1t it is on the issue: `resolved by #14`. | |
| 79 | - **Nobody should have to learn a word to use the product.** An engineer who | |
| 80 | has used any forge can use g1t on the first day, and finds the agent | |
| 81 | features where they would look for them. | |
| Rust repos service with shipping; pull requests kept in the model | 82 | |
| Issues and pull requests replace intents and attempts | 83 | What g1t adds to the familiar pair: |
| Rust repos service with shipping; pull requests kept in the model | 84 | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 85 | - **Several pull requests per issue is supported**, not an accident. It |
| 86 | is the exception, for a second attempt or a competing one, but when it | |
| 87 | happens the issue's page lists them with their state, and merging one | |
| 88 | closes the issue with that pull request recorded and the others marked | |
| 89 | superseded. | |
| Issues and pull requests replace intents and attempts | 90 | - **A pull request can be part of the work.** Merging with "keep the issue |
| 91 | open" leaves the issue and its other pull requests alone. | |
| 92 | - **Every pull request has a fork and a session.** See | |
| 93 | [forks and branches](https://docs.g1t.sh/concepts/forks/). | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 94 | - **Labels need no setup.** A repository starts with the default labels |
| 95 | (`bug`, `documentation`, `enhancement`, `question`, `dependencies`, | |
| 96 | `security` and the rest), each with a color and a description, on issues | |
| 97 | and pull requests alike; someone with Triage makes a new one as they use | |
| 98 | it. **Milestones** gather issues and pull requests under a goal and a | |
| 99 | due date. Pull requests can merge into any branch; the default branch's | |
| 100 | protection holds only for those into it. | |
| Pull requests from branches | 101 | - **The developer path is unchanged.** Push a branch, open a pull request |
| 102 | from it, get review, merge. Agents get a fork per pull request instead. | |
| Rust repos service with shipping; pull requests kept in the model | 103 | - **Both paths meet at `main`.** The same landing rules apply to a person's |
| Issues and pull requests replace intents and attempts | 104 | pull request and an agent's. |
| Rust repos service with shipping; pull requests kept in the model | 105 | |
| Initial g1t: services, event bus, intents and attempts | 106 | ## Converging on main |
| 107 | ||
| Issues and pull requests replace intents and attempts | 108 | Twelve issues started together will finish at different times and touch |
| Initial g1t: services, event bus, intents and attempts | 109 | overlapping code. Getting them all into `main` without a person refereeing |
| 110 | is the hard part, and it is handled in four places. | |
| 111 | ||
| 112 | 1. **Before work starts: plan the overlap away.** A project is a graph of | |
| Issues and pull requests replace intents and attempts | 113 | issues. A planner agent can split a large goal into issues, predict |
| Initial g1t: services, event bus, intents and attempts | 114 | which files each will touch, and add a dependency where two would collide, |
| 115 | so one starts from the other's result instead of from `main`. | |
| Issues and pull requests replace intents and attempts | 116 | 2. **While agents work: overlap radar.** Each pull request's changed files and |
| 117 | symbols are tracked as it pushes. When two pull requests from different issues | |
| Initial g1t: services, event bus, intents and attempts | 118 | enter the same area, both agents are told what the other is doing there. |
| Issues and pull requests replace intents and attempts | 119 | 3. **When `main` moves: the author resolves.** Every open pull request is |
| 120 | trial-merged against the new `main`. A clean merge updates the pull request | |
| 121 | silently. A conflict resumes that pull request's agent with its original | |
| Initial g1t: services, event bus, intents and attempts | 122 | session and the incoming change, so the conflict is resolved by the agent |
| 123 | that wrote the code and still knows why. | |
| Issues and pull requests replace intents and attempts | 124 | 4. **At landing: a speculative queue.** Approved pull requests enter the |
| 125 | repo's queue. g1t builds the combined states (`main`+A, `main`+A+B, …) and runs | |
| 126 | their checks in parallel. Pull requests land in order as their combined state | |
| Initial g1t: services, event bus, intents and attempts | 127 | passes; one that fails is ejected back to its agent and the states behind |
| 128 | it are rebuilt. `main` only ever receives a state that passed. | |
| 129 | ||
| 130 | Landing can be fully automatic: a repo policy such as "checks pass and the | |
| Issues and pull requests replace intents and attempts | 131 | reviewer agent approves" merges without a person. |
| Initial g1t: services, event bus, intents and attempts | 132 | |
| 133 | ## Agents aware of each other | |
| 134 | ||
| Issues and pull requests replace intents and attempts | 135 | Each repo keeps a live **work registry**: for every running pull request, its |
| 136 | issue, a running summary of what it has done, and the files and symbols it | |
| Initial g1t: services, event bus, intents and attempts | 137 | has touched or plans to touch. Agents use it through MCP tools; g1t also |
| 138 | acts on it without being asked. | |
| 139 | ||
| Issues and pull requests replace intents and attempts | 140 | - **Before starting.** When an issue is opened, or an agent is about to |
| 141 | begin a task, g1t searches open issues and running pull requests for the same | |
| Initial g1t: services, event bus, intents and attempts | 142 | goal (by meaning, not wording) and for the same area of code. If a match |
| 143 | exists the agent is told who is on it and how far along, and chooses: join | |
| 144 | as a deliberate racer, wait for the result, or drop the task. Duplicate | |
| Issues and pull requests replace intents and attempts | 145 | issues are offered for merging. |
| Initial g1t: services, event bus, intents and attempts | 146 | - **Finding out-of-scope work.** An agent that discovers something outside |
| Issues and pull requests replace intents and attempts | 147 | its issue asks the registry who works there. If another pull request owns that |
| Initial g1t: services, event bus, intents and attempts | 148 | area, it **hands off**: a note, the relevant excerpt of its session, and |
| 149 | optionally commits the receiver can take. If nobody does, it opens a child | |
| Issues and pull requests replace intents and attempts | 150 | issue instead of widening its own change. |
| 151 | - **Asking.** An agent can put a question or a request to another pull request. | |
| Initial g1t: services, event bus, intents and attempts | 152 | The receiver gets it at its next turn. |
| Issues and pull requests replace intents and attempts | 153 | - **Waiting.** An agent that needs another pull request's result parks itself. |
| Initial g1t: services, event bus, intents and attempts | 154 | Its sandbox sleeps, spend stops, and it resumes from the new state when |
| Issues and pull requests replace intents and attempts | 155 | that pull request merges. |
| Initial g1t: services, event bus, intents and attempts | 156 | - **Agents that do not cooperate.** For pushes from tools that never call |
| Issues and pull requests replace intents and attempts | 157 | these tools, g1t compares the pushed change against running pull requests and |
| Initial g1t: services, event bus, intents and attempts | 158 | flags near-duplicates itself. |
| 159 | ||
| 160 | Every handoff, question and wait has a state (offered, accepted, declined, | |
| 161 | done), appears in the timeline, and is visible to people. A handoff declined | |
| 162 | twice, or two agents passing work back and forth, goes to the "needs you" | |
| 163 | inbox. | |
| 164 | ||
| 165 | ## Review at scale | |
| 166 | ||
| 167 | Cloudflare's brief asks "how do you review everything they produce?". With | |
| 168 | hundreds of agents, a person cannot read every diff, so review is by | |
| 169 | exception. | |
| 170 | ||
| Issues and pull requests replace intents and attempts | 171 | - **Evidence, not diffs.** Every pull request carries a proof bundle: checks run |
| Initial g1t: services, event bus, intents and attempts | 172 | and their output, a preview URL, a plain-language summary, and the |
| 173 | behaviour that changed. | |
| Issues and pull requests replace intents and attempts | 174 | - **Two agent reviewers.** One reviews the change against the issue. A |
| Initial g1t: services, event bus, intents and attempts | 175 | second is adversarial: it tries to break the change and reports what it |
| 176 | found. | |
| 177 | - **Risk tiers.** Each change is scored from what it touches, how large it | |
| Issues and pull requests replace intents and attempts | 178 | is, and how the reviewers ruled. Low risk merges on policy; high risk goes |
| Initial g1t: services, event bus, intents and attempts | 179 | to a person with the evidence already assembled. |
| Issues and pull requests replace intents and attempts | 180 | - **Trust is earned.** An agent's record on a path (merged, reverted, caught |
| Initial g1t: services, event bus, intents and attempts | 181 | by review) raises or lowers the tier its changes land in. |
| Issues and pull requests replace intents and attempts | 182 | - **Sampling.** A share of auto-merged changes is sent to a person anyway, |
| Initial g1t: services, event bus, intents and attempts | 183 | to keep the policy honest. |
| 184 | ||
| 185 | ## Rethinking the git primitives | |
| 186 | ||
| Issues and pull requests replace intents and attempts | 187 | - **No branches for agents.** A pull request is a fork; `main` is the only |
| Initial g1t: services, event bus, intents and attempts | 188 | long-lived line. There is nothing to name, clean up or go stale. |
| Issues and pull requests replace intents and attempts | 189 | - **Projected main.** New pull requests start from `main` plus everything already |
| Initial g1t: services, event bus, intents and attempts | 190 | in the landing queue, so they are built on the state they will land on. |
| 191 | - **Structural merge.** The merge engine merges by syntax tree, not by line, | |
| 192 | for supported languages. Two agents adding different functions to the same | |
| 193 | file do not conflict. | |
| 194 | - **Forkable sessions.** A session can be forked at any turn: the code as it | |
| 195 | was at that moment plus the conversation up to it, continued with a | |
| 196 | different instruction. Branching applies to the reasoning as well as the | |
| 197 | code. | |
| Issues and pull requests replace intents and attempts | 198 | - **Provenance in history.** Every commit records its issue, session, |
| 199 | agent, model and cost, and is signed with a key issued to that pull request. The | |
| Initial g1t: services, event bus, intents and attempts | 200 | history can be audited by machine. |
| 201 | ||
| 202 | ## People in the loop | |
| 203 | ||
| 204 | ### Code that arrives from outside | |
| 205 | ||
| 206 | People will keep pushing with plain git, their editor, or another tool. Every | |
| 207 | push goes through g1t's git front end, so none of it bypasses the model. | |
| 208 | ||
| Issues and pull requests replace intents and attempts | 209 | - **A push to a branch becomes a pull request.** g1t adopts it with the pusher as |
| 210 | author. A reviewer agent writes the issue it appears to serve and offers | |
| 211 | to attach it to an open issue it matches. From there it gets the same | |
| 212 | checks, compare view and queue as agent work. | |
| Initial g1t: services, event bus, intents and attempts | 213 | - **A push to `main` follows repo policy.** Protected: refused with a message |
| 214 | saying which ref to push to instead, so it enters the queue. Open: accepted | |
| 215 | and treated as "`main` moved", which re-verifies the queue and triggers | |
| Issues and pull requests replace intents and attempts | 216 | resolve-on-move for every open pull request. |
| Initial g1t: services, event bus, intents and attempts | 217 | - **Context is an open format.** A commit trailer names the session that |
| 218 | produced it, so any tool can attach its transcript. Commits without one are | |
| 219 | shown in why-blame as "pushed by a person, no session". | |
| Issues and pull requests replace intents and attempts | 220 | - **Approval rules.** Per repo and per path: merge automatically, require a |
| Initial g1t: services, event bus, intents and attempts | 221 | named person, or require a person when the change is large or the reviewer |
| 222 | agent is unsure. | |
| 223 | ||
| 224 | ### Joining work that is already running | |
| 225 | ||
| 226 | - **Every session has a live page** that works on a phone: the transcript as | |
| 227 | it streams, the current diff, check results. | |
| 228 | - **Steer.** Send a message, pause, or redirect. Hosted agents receive it | |
| 229 | immediately; a person's own Claude Code receives it at its next turn | |
| 230 | through the CLI hooks. | |
| 231 | - **Answer.** When an agent is blocked on a question, it appears in a "needs | |
| 232 | you" inbox and as a notification. The answer resumes the agent. | |
| Issues and pull requests replace intents and attempts | 233 | - **Take over and hand back.** Check out the pull request's fork, commit by hand, |
| Initial g1t: services, event bus, intents and attempts | 234 | push, and let the agent continue from there. |
| 235 | ||
| 236 | ### Planning by writing | |
| 237 | ||
| 238 | - **Brief.** Write the outcome in prose on the site, or commit it as a | |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 239 | markdown file. A planner agent turns it into a project: issues, each with |
| 240 | what done means, and dependencies. The person edits the graph before anything starts. | |
| Initial g1t: services, event bus, intents and attempts | 241 | - **Plan from their own agent.** The same operations are MCP tools, so a |
| 242 | person can plan in their own Claude Code session and create the project | |
| 243 | from there. | |
| 244 | - **The brief stays the source of truth.** Editing it later re-plans: new | |
| Issues and pull requests replace intents and attempts | 245 | issues are added, obsolete ones are closed. |
| Initial g1t: services, event bus, intents and attempts | 246 | |
| 247 | ### Seeing what moved | |
| 248 | ||
| Issues and pull requests replace intents and attempts | 249 | - **Project page.** The outcome, the issue graph coloured by state, and how |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 250 | many of its issues have landed with their required checks passing, |
| 251 | compared with when the project started. | |
| Initial g1t: services, event bus, intents and attempts | 252 | - **Digest.** An agent-written summary per project and per person: what |
| Issues and pull requests replace intents and attempts | 253 | merged, what is blocked on whom, which conflicts were resolved, what it |
| Initial g1t: services, event bus, intents and attempts | 254 | cost. |
| Issues and pull requests replace intents and attempts | 255 | - **Timeline.** Every event (push, steer, check, conflict, merge) in order, |
| Initial g1t: services, event bus, intents and attempts | 256 | each linked to the session and the person or agent behind it. |
| 257 | ||
| 258 | ## One session, any surface | |
| 259 | ||
| 260 | A session belongs to g1t, not to the device it started on. The browser, a | |
| 261 | phone and Claude Code are views of the same session. | |
| 262 | ||
| 263 | - **Browser and phone.** The site is a responsive, installable web app with | |
| 264 | push notifications. Everything a person does (brief, steer, answer, | |
| Issues and pull requests replace intents and attempts | 265 | approve, merge) works there. |
| Initial g1t: services, event bus, intents and attempts | 266 | - **Claude Code.** Through `mcp.g1t.sh` and the CLI hooks, a local session is |
| 267 | a g1t session: its transcript syncs as it runs and it appears in mission | |
| 268 | control like any other. | |
| 269 | - **Moving a session.** A local session can be sent to the cloud: a hosted | |
| 270 | agent takes over the fork and the transcript and continues, so the laptop | |
| 271 | can close. A hosted session can be pulled down: the CLI checks out the fork | |
| 272 | and resumes it in local Claude Code with its history. | |
| 273 | - **Limit.** A session running only on a laptop stops when the laptop does. | |
| 274 | It can be steered between turns but not continued until it is moved or the | |
| 275 | laptop is back. | |
| 276 | ||
| 277 | ## For people who do not write code | |
| 278 | ||
| 279 | - **Documents are first-class.** Specs, guides, policies and decisions live | |
| 280 | in repos as markdown, shown in a Docs view: rendered pages, edited in the | |
| 281 | browser like a document, with inline comments. "Suggest a change" is an | |
| Issues and pull requests replace intents and attempts | 282 | pull request and "publish" is merge, without git vocabulary. |
| 283 | - **Document issues.** "Write the onboarding guide for the billing API" is | |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 284 | an issue. Its Definition of done is a checklist judged by a reviewer agent |
| 285 | instead of a workflow. Agents draft and revise; people comment and approve. | |
| Initial g1t: services, event bus, intents and attempts | 286 | - **Templates.** Product brief, RFC, decision record. A filled-in template is |
| 287 | a brief the planner can turn into a project. | |
| 288 | - **Explain.** Ask about any repo, project or change in plain language and | |
| 289 | get an answer with links to the code and sessions behind it. | |
| 290 | - **Living documentation.** g1t generates "how this works" pages from the | |
| Issues and pull requests replace intents and attempts | 291 | code and keeps them current. When a merged change contradicts a document, |
| 292 | an issue opens to update it. | |
| 293 | - **See it, don't read it.** Every pull request on a deployable repo gets a | |
| 294 | preview URL (Workers Builds from the pull request's fork), so an approver clicks | |
| Initial g1t: services, event bus, intents and attempts | 295 | through the result instead of reading a diff. Changes are also summarised |
| 296 | in plain language. | |
| Merge main (membership, two-factor, GitHub repo roles) into tokens | 297 | - **Roles.** A person can plan and approve work without ever cloning a |
| 298 | repo. The roles that were sketched here map onto the five repository | |
| 299 | roles that are built (see "Access" under what is built): a viewer is | |
| 300 | Read, a commenter is Read (anyone with Read opens issues and comments), | |
| 301 | a planner is Triage (labels, milestones, assigning, closing) or Write | |
| 302 | where planning spends compute, and an approver is Write (reviews count | |
| 303 | and merges). Workspace-wide, a member may also be a billing manager or a | |
| 304 | security manager. | |
| Initial g1t: services, event bus, intents and attempts | 305 | |
| 306 | ## The macro view | |
| 307 | ||
| 308 | The hierarchy above a single repo: | |
| 309 | ||
| 310 | | Level | What it is | | |
| 311 | | --- | --- | | |
| 312 | | **Workspace** | A company or team: its people, repos, agents, budget and policies. | | |
| 313 | | **Initiative** | A business outcome with an owner and measurable results, e.g. "move billing to usage-based pricing". Spans any number of repos. | | |
| Plan: Projects, the home of everything about running software | 314 | | **Outcome** | One deliverable inside an initiative: a brief and its graph of issues (shown as **Plan**). Called "project" before 2026-10-04; that name now means what [Projects](#projects) describes. | |
| Issues and pull requests replace intents and attempts | 315 | | **Issue / Pull request** | As above. An issue may touch several repos; a pull request for it then holds one fork per repo and they land together. | |
| Initial g1t: services, event bus, intents and attempts | 316 | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 317 | How it feeds up, and what is built: |
| 318 | ||
| 319 | - **A workspace is the unit everything belongs to.** Repositories, people, | |
| 320 | access tokens, and later projects, budgets and policies are the | |
| 321 | workspace's, never a person's. An account owns nothing; its first step | |
| 322 | after confirming its email is creating a workspace, and the site sends it | |
| 323 | there from wherever it was going. | |
| 324 | - **One namespace.** Usernames and workspaces share one set of names, as on | |
| 325 | Docker Hub and npm. A username is reserved for its owner's workspace, so | |
| 326 | `g1t.sh/<name>` never means two things. | |
| 327 | - **The workspace page is the roll-up.** `g1t.sh/<workspace>` shows its | |
| 328 | repositories with their open issues and pull requests, and the pull | |
| 329 | requests in progress across all of them. Projects and initiatives will | |
| 330 | roll up to the same page. Its own pages live under `/<workspace>/-/` | |
| 331 | (people, access tokens, settings), which no repository can be named. | |
| 332 | - **Workspace access tokens instead of service accounts.** A workspace has | |
| 333 | tokens of its own, in the same table and code path as personal ones. One | |
| Docs and plan: fine-grained tokens, workspace token rules, workflow files, workspace token Write | 334 | acts as the workspace, with a member's rights in that workspace only (the |
| 335 | Write role on its repositories; Admin only when an owner ticks it at | |
| 336 | creation, `access_tokens.admin`, identity/0034), records who made it and | |
| 337 | when it was last used, and keeps working when that person leaves. CI, | |
| 338 | integrations and automations use these. Until 2026-10-08 the code gave | |
| 339 | them Admin on every repository, which the security audit found let any | |
| 340 | workspace token manage webhooks; code, this plan and the docs now agree. | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 341 | |
| Initial g1t: services, event bus, intents and attempts | 342 | ### Portfolio |
| 343 | ||
| 344 | One page answers "where is the business" across every initiative: | |
| 345 | ||
| 346 | - **Health** per initiative: on track, at risk, or blocked, derived from | |
| Issues and pull requests replace intents and attempts | 347 | facts (checks passing, issues stalled, questions waiting on a person), |
| Initial g1t: services, event bus, intents and attempts | 348 | not self-reported. |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 349 | - **Progress** as measurable results: required checks passing, issues |
| Issues and pull requests replace intents and attempts | 350 | merged out of planned, and the trend since the start. |
| Initial g1t: services, event bus, intents and attempts | 351 | - **Forecast** from actual throughput: at the current rate, when the |
| Issues and pull requests replace intents and attempts | 352 | remaining issues land. |
| Initial g1t: services, event bus, intents and attempts | 353 | - **Spend** in tokens and dollars against a budget, per initiative. |
| 354 | - **Waiting on people**: every decision or approval a person owes, by name. | |
| 355 | - **Roadmap**: initiatives laid out as now, next, later, with optional | |
| 356 | time-boxed cycles for teams that work in sprints. | |
| 357 | ||
| 358 | ### Status without asking | |
| 359 | ||
| 360 | - **Standup.** An agent writes a daily report per initiative and one for the | |
| Issues and pull requests replace intents and attempts | 361 | whole workspace: what merged, what changed direction, what is at risk and |
| Initial g1t: services, event bus, intents and attempts | 362 | why, what needs a person. Delivered by email or webhook. |
| 363 | - **Ask.** A question box over the full event log and all sessions: "what | |
| 364 | happened on the billing migration since Monday?" answers with links to the | |
| 365 | sessions and commits behind each claim. | |
| 366 | ||
| 367 | ### Long-running agents | |
| 368 | ||
| 369 | Work that runs for days needs supervision that does not depend on someone | |
| 370 | watching. | |
| 371 | ||
| Issues and pull requests replace intents and attempts | 372 | - **Checkpoints.** A long pull request reports milestones against its issue, so |
| 373 | progress is visible before anything merges. | |
| 374 | - **Stall and drift detection.** A pull request with no meaningful progress, or | |
| 375 | whose changes have wandered away from its issue, is flagged and can be | |
| Initial g1t: services, event bus, intents and attempts | 376 | stopped or re-briefed automatically. |
| Issues and pull requests replace intents and attempts | 377 | - **Budgets.** Hard limits on spend and time per pull request, project and |
| Initial g1t: services, event bus, intents and attempts | 378 | initiative. |
| 379 | ||
| 380 | ### Context hub | |
| 381 | ||
| 382 | Agents working across repos and days need context that outlives any one | |
| 383 | session and reaches beyond the code. The context hub is one place an agent | |
| 384 | asks, whatever the source. | |
| 385 | ||
| 386 | | Source | What it holds | How it gets there | | |
| 387 | | --- | --- | --- | | |
| 388 | | **Memory** | Decisions, conventions, gotchas, facts about systems | Written by agents and people in g1t | | |
| 389 | | **Code and sessions** | The repos, and the reasoning behind every change | Already in g1t | | |
| 390 | | **Connected sources** | Jira and Linear tickets, Notion and Confluence pages, Google Drive documents, Slack threads, Sentry issues | Connectors, authorised per workspace | | |
| 391 | ||
| 392 | How it behaves: | |
| 393 | ||
| 394 | - **One search.** An agent asks a question and gets ranked results across | |
| 395 | all sources, each labelled with where it came from, who wrote it, and how | |
| 396 | fresh it is. | |
| 397 | - **Connected sources stay where they are.** g1t indexes them for search and | |
| 398 | fetches the current version when an agent opens one. The external system | |
| Issues and pull requests replace intents and attempts | 399 | remains the source of truth, and a link placed on an issue ("see |
| Initial g1t: services, event bus, intents and attempts | 400 | JIRA-482", a Notion URL) is pulled into the agent's starting context. |
| 401 | - **Permissions carry over.** A connector only exposes what the connecting | |
| 402 | account can see, and a workspace admin chooses which spaces, projects or | |
| 403 | channels are included. | |
| 404 | - **External content is untrusted.** A ticket or page can contain text meant | |
| 405 | to manipulate an agent. It is marked as reference material, never treated | |
| 406 | as instructions. | |
| 407 | - **Documentation is separate.** Context is what agents know; documentation | |
| 408 | is what people read, and it is generated from context and code. | |
| 409 | ||
| 410 | Memory is the part of the hub that g1t owns and agents write to: | |
| 411 | ||
| 412 | - **Memory is written freely.** Any agent or person adds an entry with one | |
| 413 | call: a decision, a convention, a gotcha, a fact about a system. No review | |
| 414 | gate. Each entry records who wrote it, from which session, and when. | |
| 415 | - **It is still a repository.** Each workspace has a memory repo in | |
| 416 | Artifacts, so every write is a commit: versioned, attributable, and | |
| 417 | revertible. | |
| 418 | - **It is kept healthy by an agent.** A consolidation agent merges | |
| 419 | duplicates, retires entries that newer ones contradict, and flags | |
| 420 | conflicts it cannot settle. People can pin an entry (agents may not change | |
| 421 | it), correct it, or retract it. | |
| 422 | - **Agents read it.** Every session starts with the context relevant to its | |
| Issues and pull requests replace intents and attempts | 423 | issue, found by search, and can query more through MCP. |
| Initial g1t: services, event bus, intents and attempts | 424 | - **Updates are events.** A memory write or a change in a connected source |
| 425 | is an event, so "when context changes, update the affected docs" is an | |
| 426 | automation, on by default. | |
| 427 | - **It is scoped inside the workspace.** Some context applies to the whole | |
| 428 | workspace, some to one initiative, project or repo, so an agent gets what | |
| 429 | applies to its work. | |
| 430 | - **It never crosses workspaces.** A workspace is the isolation boundary: its | |
| 431 | context, sessions and private repos are invisible to every other | |
| 432 | workspace, and an agent's token is bound to one workspace. | |
| 433 | ||
| 434 | ## Working in g1t | |
| 435 | ||
| 436 | - **Mission control.** The signed-in home page: every running session, every | |
| Issues and pull requests replace intents and attempts | 437 | issue waiting on a decision, and what merged, across all repos. |
| Plan: Projects, the home of everything about running software | 438 | - **Outcomes.** Group issues across repos toward one result and track how |
| 439 | many are open, racing, or merged. (What [Projects](#projects) means is | |
| 440 | below.) | |
| Issues and pull requests replace intents and attempts | 441 | - **Steering.** Send a message to a running pull request, or to all pull requests on an |
| 442 | issue at once, without stopping them. | |
| Initial g1t: services, event bus, intents and attempts | 443 | - **Automations.** Rules that start work without a person (next section). |
| 444 | ||
| 445 | ## Automations and integrations | |
| 446 | ||
| Sidebar: the panels really slide | 447 | > **2026-10-03:** g1t's own `.g1t/automations` format was built and then set |
| 448 | > aside at the user's request ("let's just copy GitHub Actions on that for the | |
| 449 | > time being"). Automation on g1t is GitHub Actions workflows in | |
| 450 | > `.g1t/workflows/`; the format below is kept for later. | |
| 451 | ||
| Initial g1t: services, event bus, intents and attempts | 452 | An automation is **when** an event happens, **if** conditions hold, **do** |
| 453 | something. They are defined as files in the repo (`.g1t/automations/`), the | |
| 454 | way GitHub Actions workflows are, and can also be built in the UI. | |
| 455 | ||
| 456 | ### Events that can trigger one | |
| 457 | ||
| 458 | | Source | Examples | | |
| 459 | | --- | --- | | |
| Issues and pull requests replace intents and attempts | 460 | | Git | push, merge, check failed, `main` moved | |
| 461 | | g1t | issue opened, pull request stalled, context updated, handoff declined, budget reached | | |
| Initial g1t: services, event bus, intents and attempts | 462 | | Time | cron schedule | |
| 463 | | Integrations | Sentry issue, PagerDuty incident, Linear or Jira ticket, Slack message or mention, GitHub issue, Stripe event | | |
| 464 | | Anything else | a signed generic webhook, or an email to a per-repo address | | |
| 465 | ||
| Issues and pull requests replace intents and attempts | 466 | **Actions**: open an issue (optionally assigning N agents to it), message |
| 467 | a running pull request, update documentation, notify, call a | |
| Initial g1t: services, event bus, intents and attempts | 468 | webhook, write back to the source system. |
| 469 | ||
| 470 | **Example: Sentry.** A new production error arrives. The automation opens an | |
| Issues and pull requests replace intents and attempts | 471 | issue labelled `bug`, with the stack trace, release and frequency in its |
| 472 | description. Why-blame | |
| Initial g1t: services, event bus, intents and attempts | 473 | finds the session that wrote the failing line, so the fixing agent starts |
| Issues and pull requests replace intents and attempts | 474 | with the original reasoning. When the fix merges, g1t comments on the Sentry |
| Initial g1t: services, event bus, intents and attempts | 475 | issue and resolves it. |
| 476 | ||
| 477 | ### Rules every automation obeys | |
| 478 | ||
| 479 | - **Deduplication.** The same Sentry issue firing 500 times maps to one | |
| Issues and pull requests replace intents and attempts | 480 | issue. |
| Initial g1t: services, event bus, intents and attempts | 481 | - **Limits.** Concurrency and budget caps per automation. |
| 482 | - **Loop protection.** Work started by an automation cannot retrigger the | |
| 483 | same automation without a person in between. | |
| 484 | - **External input is untrusted.** A webhook payload can contain text written | |
| 485 | by an attacker. Agents started by external events run with reduced | |
| Issues and pull requests replace intents and attempts | 486 | permissions and cannot merge without the repo's approval rule passing. |
| Initial g1t: services, event bus, intents and attempts | 487 | |
| 488 | **Checks** are the other half of what GitHub Actions does: build and test | |
| Issues and pull requests replace intents and attempts | 489 | commands declared in `.g1t/checks.yaml`, run in sandboxes on every pull request |
| Initial g1t: services, event bus, intents and attempts | 490 | and on every combined state in the landing queue. |
| 491 | ||
| Docs and plan: fine-grained tokens, workspace token rules, workflow files, workspace token Write | 492 | ### Tokens, scopes and packages the GitHub way (built 2026-10-08) |
| 493 | ||
| 494 | > **2026-10-08 (owner):** "emulate all of what GitHub does for scope | |
| 495 | > mapping and packages." GitHub's current behaviour is the spec. | |
| 496 | ||
| 497 | This **reverses identity/0023**, which retired a token's reach to some | |
| 498 | workspaces or repositories and left classic tokens only. The reason it is | |
| 499 | reversed: the owner chose GitHub parity, and GitHub has fine-grained tokens | |
| 500 | beside classic ones, with workspaces (organizations) governing both. | |
| 501 | ||
| 502 | - **Fine-grained personal access tokens** (identity/0034, | |
| 503 | `services/identity/src/token_reach.rs`, `g1t_contracts::fine_grained`): | |
| 504 | one resource owner (a workspace the person belongs to, or their own | |
| 505 | account), all, selected (up to 50, by repository id) or only public | |
| 506 | repositories, and a level per permission under GitHub's names (contents, | |
| 507 | metadata, issues, pull_requests, actions, workflows, checks, statuses, | |
| 508 | deployments, pages, environments, secrets, variables, webhooks, | |
| 509 | administration, packages, security_events; members, | |
| 510 | workspace_administration, self_hosted_runners, workspace_secrets, | |
| 511 | workspace_webhooks, workspace_billing, models; email_addresses, starring, | |
| 512 | notifications; g1t's agents and memory). Each level maps onto g1t's | |
| 513 | scopes, which the token stores, so every check that reads scopes | |
| 514 | (`scopes::decide` for the API and MCP, `decide_git`, `decide_packages`) | |
| 515 | reads them unchanged. They must expire, within 366 days. On each use, | |
| 516 | identity cuts the resolved person down to the token's reach | |
| 517 | (`apply_reach`); `access::granted` gives no role outside it, so a public | |
| 518 | repository elsewhere still reads and nothing more. | |
| 519 | - **Governance** (`token_policies`, `token_workspace_revocations`): per | |
| 520 | workspace, allow classic, allow fine-grained, require approval (on by | |
| 521 | default, as GitHub's; owners' own tokens never wait), the longest | |
| 522 | lifetime, and forbidding tokens that never expire. Owners see every | |
| 523 | member's token that can reach the workspace, approve or deny pending | |
| 524 | fine-grained ones (inbox: `token.approval_requested` and | |
| 525 | `token.approval_reviewed`, the inbox's first notices about no | |
| 526 | repository), and revoke one there. REST and MCP for owners; audited as | |
| 527 | `token.*`. | |
| 528 | - **Workflow files** need `workflow_files:write` (GitHub's `workflow` | |
| 529 | scope; the `workflows` permission) from any token, checked commit by | |
| 530 | commit on push (`services/repos/src/workflow_gate.rs`) and on files g1t | |
| 531 | writes for a token. A job's token never has it. g1t's agents push with | |
| 532 | run credentials, not tokens, and are not gated by it; their work arrives | |
| 533 | as pull requests people review. | |
| 534 | - **Workspace tokens** have Write unless an owner gives Admin at creation. | |
| 535 | - **Deploy keys** (identity/0035): per repository, read-only unless write | |
| 536 | is ticked; resolved to a principal bound to the one repository. | |
| 537 | Serving git over SSH is still to come, so nothing uses them yet. | |
| Merge packages: roles, Actions access, source label, soft delete, API | 538 | - **Packages** (packages/0006, `services/packages/src/access.rs` and |
| 539 | `settings.rs`): per-package roles (read, write, admin) for people and | |
| 540 | teams, with "inherit access from the linked repository" (on by default); | |
| 541 | "Manage Actions access", which a job's token is held to (its own linked | |
| 542 | repository writes; any other repository needs an entry, added | |
| 543 | automatically for the repository whose job first publishes an unlinked | |
| 544 | package); linking by `org.opencontainers.image.source` (manifest | |
| 545 | annotation or image label, same workspace, pusher may push there); 30-day | |
| 546 | soft delete of packages and versions, registry deletes included (the name | |
| 547 | and version stay reserved), restore, and a purge in the hourly cron; a | |
| 548 | settings tab and a "Deleted packages" view; 17 REST operations and one | |
| 549 | `package` MCP tool (reads `packages:read`; settings and access | |
| 550 | `packages:write` with the package's Admin role; delete and restore | |
| 551 | `packages:delete`); and download counts per version in every registry. | |
| 552 | Existing unlinked packages have no Actions access entries, so workflows | |
| 553 | that used them through `G1T_TOKEN` need one added. | |
| Docs and plan: fine-grained tokens, workspace token rules, workflow files, workspace token Write | 554 | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 555 | ### Keeping workflow runs safe (built 2026-10-08) |
| 556 | ||
| 557 | An audit of g1t Actions found a job's token was a full-access workspace | |
| 558 | token, environments had no protection, outside pull requests ran at once, | |
| 559 | the cache could be poisoned across branches, a job's token could set off | |
| 560 | more runs, and masking missed multi-line and encoded secrets. Now: | |
| 561 | ||
| 562 | - **The job's token** (`G1T_TOKEN`, `GITHUB_TOKEN`) is minted per job by | |
| 563 | identity (`create_job_token`, migration identity/0030): it reaches its | |
| 564 | repository only (`TokenAccess.repo`, enforced by the API, git and the | |
| 565 | registries), carries the scopes its `permissions:` map to | |
| 566 | (`g1t_actions::permissions`), is revoked when the job ends, and its | |
| 567 | writes are audited with the run as `run_kind: workflow_job`. Without | |
| 568 | `permissions:` it gets the repository's default, the GitHub way: | |
| 569 | repositories that existed when actions/0007 ran keep read and write, | |
| 570 | newer ones take their workspace's default (read-only unless an owner | |
| 571 | says), and a workspace can cap every repository at read-only. An outside | |
| 572 | pull request's is read-only. "Allow g1t Actions to create and approve | |
| 573 | pull requests" (repository and workspace, off by default) decides whether | |
| 574 | the token may open or approve pull requests. OIDC (`id-token: write`) | |
| 575 | reads the same permissions model. | |
| 576 | - **No loops.** Work and repos mark the events a job's token causes | |
| 577 | (`causedByJob`), carried on to a pull request it moves; the actions | |
| 578 | service starts nothing for them. `workflow_dispatch` and | |
| 579 | `repository_dispatch` (now sent by `POST {repo}/dispatches`) still start | |
| 580 | runs. | |
| 581 | - **Environments' protection rules** (actions/0007): required reviewers | |
| 582 | (people or teams, up to six, optionally not whoever started the run), a | |
| 583 | wait timer, which branches and tags may deploy, and admin bypass. A job | |
| 584 | naming one is `pending` once its needs are done, its environment read | |
| 585 | then (an expression included); reviewers hear in the inbox | |
| 586 | (`deployment.review_requested`) and approve on the run's page or through | |
| 587 | `pending_deployments`; secrets are read only when the job starts. | |
| 588 | - **Approval for outside pull requests**, by a repository policy | |
| 589 | (first-time contributors, outside contributors (the default), or every | |
| 590 | external contributor): such runs are `action_required` until someone with | |
| 591 | Write approves them. | |
| 592 | - **The cache is scoped by ref** (own, then the pull request's base, then | |
| 593 | the default branch; outside pull requests save where nothing else reads) | |
| 594 | and versioned by its paths and compression (0006's toolkit `version`, | |
| 595 | which g1t's runner now sends too); g1t's `actions/cache` and the | |
| 596 | toolkit's protocols share one scope rule. Entries from before were | |
| 597 | expired. | |
| 598 | - **Masking** covers each line of a multi-line secret, base64 at every | |
| 599 | offset and JSON-escaped forms; outputs holding a secret are withheld and | |
| 600 | annotations masked. | |
| 601 | - A job's own `concurrency:` is honoured, `create` runs on new branches and | |
| 602 | tags, and `on: delete` says plainly that it never runs yet. | |
| PLAN.md: blank line before Docker in workflow jobs | 603 | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 604 | ### Docker in workflow jobs (built 2026-10-08) |
| 605 | ||
| 606 | > **2026-10-08:** "Why didn't we give CI docker then? We need GitHub | |
| 607 | > Actions functionality maxxed baby but with all the good good security | |
| 608 | > etc." The trigger: `deploy.yml`'s runner-image job needs `docker build` | |
| 609 | > and `docker push`, and failed on hosted runners. | |
| 610 | ||
| 611 | **What Cloudflare Containers allow** (their FAQ, updated 2026-10-05, and | |
| 612 | the Docker-in-Docker guide and example it links): | |
| 613 | ||
| 614 | - Docker runs inside a container: `docker:dind`, with `dockerd` as | |
| 615 | **root**. A rootless Engine does not start there. | |
| 616 | - **No iptables**: `--iptables=false --ip6tables=false`, or the Engine | |
| 617 | fails setting up its rules. Containers with the `durable_object` | |
| 618 | scheduling policy (ours: each sandbox is a Durable Object's) cannot turn | |
| 619 | IP forwarding on either: `--ip-forward=false`, or the Engine exits. | |
| 620 | - So **a bridge network has no way out**: the guide's answer is | |
| 621 | `--network=host` for `docker run` and `docker build`, which gives | |
| 622 | containers the outer container's network. | |
| 623 | - Built images and containers are lost when the sandbox stops. | |
| 624 | ||
| 625 | **What was found by trying** (Docker Engine 29.8.2 in a privileged | |
| 626 | container standing in for a sandbox, with the same flags): | |
| 627 | ||
| 628 | - `--bridge=none` makes BuildKit's `RUN` steps fail outright ("network | |
| 629 | bridge not found"); with the default bridge they run with no route out. | |
| 630 | Containers default to the bridge too. The default bridge is created | |
| 631 | fine without iptables, as the FAQ's own example relies on. | |
| 632 | - The overlay snapshotter does not work on an overlay root filesystem, and | |
| 633 | the containerd image store does not fall back by itself: the Engine | |
| 634 | starts, then every container fails to mount. Whether a sandbox's disk | |
| 635 | takes overlays is not documented, so the runner tries a mount first and | |
| 636 | uses `native` (plain copies) when it fails. `vfs` is not a name the | |
| 637 | containerd store accepts. | |
| 638 | - `--cpus` and `--memory` need cgroup v2 controllers handed down from a | |
| 639 | cgroup with no processes, which `docker:dind`'s entrypoint does and a | |
| 640 | plain `dockerd` does not. | |
| 641 | - A `runc` earlier on the Engine's `PATH` is used both for containers (via | |
| 642 | containerd's shim) and by BuildKit's executor, with the bundle's | |
| 643 | `config.json` written before it runs. BuildKit's bridged steps carry | |
| 644 | libnetwork's `libnetwork-setkey` prestart hook; `RUN --network=none` | |
| 645 | does not. | |
| 646 | - Buildx skips `type=gha` caches when the job has no GitHub cache service, | |
| 647 | and the build succeeds without one. | |
| 648 | - Registries' layer hosts: Docker Hub sends layers from | |
| 649 | `production.cloudfront.docker.com` (and `production.cloudflare.docker.com`), | |
| 650 | Quay from `cdn0N.quay.io`, Microsoft's from regional | |
| 651 | `*.data.mcr.microsoft.com`, public ECR from a CloudFront host; | |
| 652 | `mirror.gcr.io` serves its own. | |
| 653 | ||
| 654 | **What was built** (`crates/runner/src/docker`, `actions/containers.rs`): | |
| 655 | ||
| 656 | - **One Engine per job, started lazily.** The runner listens on | |
| 657 | `/var/run/docker.sock` itself and starts `dockerd` (root, the flags | |
| 658 | above, containerd image store, `mirror.gcr.io` first for Docker Hub) on | |
| 659 | the first connection, or when the job has `services:` or `container:`. | |
| 660 | A log line says it started and how long it took. | |
| 661 | - **Containers on the job's network.** The socket is an API proxy: a | |
| 662 | container that asks for a bridge or user network gets `host`; its names | |
| 663 | (container name, aliases, Compose service, links) resolve to 127.0.0.1 | |
| 664 | in later containers (`ExtraHosts`) and in the job's steps | |
| 665 | (`/etc/hosts`); `-p 8080:80` is forwarded; `docker inspect` reports the | |
| 666 | ports as published; `network connect` adds aliases. Sharing the job's | |
| 667 | network is also what keeps the guardrails on every container: the | |
| 668 | egress Worker sees their traffic as the job's. | |
| 669 | - **A `runc` shim.** The runner binary, as `runc`: BuildKit steps bound for | |
| 670 | a bridge lose the network namespace and the libnetwork hook (so they use | |
| 671 | the job's network); in a guarded job every container (run, exec, build | |
| 672 | step) gets the egress certificate at `/dev/g1t-egress` and the | |
| 673 | variables that point tools at it. `/dev` is the container's own tmpfs, | |
| 674 | so none of it lands in a layer; checked by saving a built image. | |
| 675 | - **Job features:** `services:` (pull, credentials, health waits, logs at | |
| 676 | the end, `job.services.*`), `container:` (steps and JavaScript actions | |
| 677 | through `docker exec`, Node mounted from the runner, Alpine falls back to | |
| 678 | running actions beside it), `docker://` steps and Dockerfile actions in | |
| 679 | GitHub's `/github/*` layout, `docker/setup-buildx-action` answered | |
| 680 | natively (the job's Engine is the builder), sign-in to g1t's registry | |
| 681 | with the run's token. | |
| 682 | - **Kill switch:** the runner Worker's `DOCKER` var (`off`). | |
| 683 | ||
| 684 | **Rejected:** rootless Docker or BuildKit (does not start in Containers); | |
| 685 | Podman or buildah with `vfs` (no better networking, less compatible, slow); | |
| 686 | a standalone `buildkitd --oci-worker-net=host` as the default builder | |
| 687 | (images not in the Engine's store, so `FROM` a just-built image and | |
| 688 | `docker run` of a build fail without `--load` round trips); a `docker` CLI | |
| 689 | wrapper adding `--network=host` (misses Compose, SDKs and testcontainers, | |
| 690 | which speak the API). | |
| 691 | ||
| 692 | **Not yet:** | |
| 693 | ||
| 694 | - Seen on Cloudflare itself: whether a sandbox's disk takes overlays, | |
| 695 | `--privileged`, and the first deploy's pull of the base from | |
| 696 | `registry.cloudflare.com` (its layer host may need a workflow-only line). | |
| 697 | - `type=gha` build caches backed by g1t's Actions cache. | |
| 698 | - Multi-platform builds (QEMU's `binfmt_misc` in a sandbox). | |
| 699 | - Docker for agents and checks, not just workflow jobs. | |
| 700 | - `runner-base.yml` on g1t's machines: the base's apt step needs | |
| 701 | `Acquire::https::CAInfo` pointed at the egress certificate first. | |
| 702 | - A deploy that appends the runner binary as a layer through the registry | |
| 703 | API, with no Docker and no 3 GB pull. | |
| 704 | ||
| Initial g1t: services, event bus, intents and attempts | 705 | Agents can also reach integrations directly: an agent definition lists MCP |
| 706 | servers (Sentry, Linear and so on) it may use while working. | |
| 707 | ||
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 708 | ### Workflows: the toolkit, OIDC and artifacts |
| 709 | ||
| 710 | > **2026-10-08:** built so that workflows that deploy, cache and pass files | |
| 711 | > run unmodified. | |
| 712 | ||
| 713 | - **The toolkit's services.** Every job gets `ACTIONS_RUNTIME_TOKEN` (a | |
| 714 | JWT whose `scp` names its run and job, signed with a key derived from | |
| 715 | the job's own token, so nothing new is kept), `ACTIONS_RESULTS_URL`, | |
| 716 | `ACTIONS_CACHE_URL` and `ACTIONS_CACHE_SERVICE_V2`. The API answers the | |
| 717 | cache's Twirp service (v2) and its older REST protocol, the artifact | |
| 718 | Twirp service, and the signed blob links they hand out (a subset of | |
| 719 | Azure Blob's protocol mapped onto R2 multipart uploads), from the same | |
| 720 | cache and artifact rows g1t's own runner uses. As the clients' source | |
| 721 | reads, `@actions/cache` and `@actions/artifact` treat any server | |
| 722 | but github.com as GitHub Enterprise Server, so the cache client speaks | |
| 723 | the older protocol and the artifact client refuses to run. g1t's runner | |
| 724 | therefore keeps handling `actions/upload-artifact`, `download-artifact` | |
| 725 | and `upload-artifact/merge` itself; the Twirp artifact service is there | |
| 726 | for clients that do not check. | |
| 727 | - **OIDC.** The issuer is `{API}/actions/oidc`, the API's own host, with | |
| 728 | discovery, JWKS (RFC 7638 `kid`s, a previous key published while | |
| 729 | rotating) and a token endpoint for `core.getIDToken`. Claims follow | |
| 730 | GitHub's. A job gets one only when its permissions (or its workflow's) | |
| 731 | give `id-token: write`, and never for an untrusted run. The permission | |
| 732 | check reads only `id-token` (`services/actions/src/runtime.rs`, | |
| 733 | `id_token_permitted`), the seam for the full `permissions:` model. | |
| 734 | - **Artifacts** moved from KV to R2 (`a/` in the cache bucket), with rows | |
| 735 | in the actions service: numeric ids, 5 GiB each and 10 GiB a run, | |
| 736 | zipped by the runner, `retention-days` up to the repository's setting | |
| 737 | (1 to 90, 14 by default), `overwrite`, `compression-level`, patterns, | |
| 738 | merging and other runs of the same repository. The REST artifacts API and | |
| 739 | the `workflow` tool's artifact actions follow GitHub's shapes; the run's | |
| 740 | page lists them with size and expiry, with download and delete. Their | |
| 741 | storage is charged with the cache's. | |
| 742 | - **Later:** the toolkit's older artifact protocol (`upload-artifact@v3` | |
| 743 | inside other actions), downloads from other repositories, and npm | |
| 744 | trusted publishing, which depends on npm accepting g1t's issuer. | |
| 745 | ||
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 746 | ### Actions parity: other repositories, triggers, step timeouts (built 2026-10-08) |
| 747 | ||
| 748 | - **Other repositories' actions and reusable workflows** | |
| 749 | (`services/actions/src/reach.rs`, actions/0008): `uses: owner/repo@ref`, | |
| 750 | `owner/repo/path@ref` and `jobs.<id>.uses: owner/repo/.g1t|.github/workflows/x.yml@ref` | |
| 751 | are looked for on g1t first, as the calling workspace sees them. Same | |
| 752 | repository or public: used. Private: only from a private repository of | |
| 753 | the same workspace, when its **Settings → Actions → Access** (`access_level`, | |
| 754 | `GET`/`PUT …/actions/permissions/access`, MCP `get_access`/`set_access`) | |
| 755 | says `organization`; a job fetches such an action with a read-only token | |
| 756 | for that repository, revoked with the job (`job_action`, the runner's | |
| 757 | `POST /actions/jobs/{job}/action`). Not on g1t: actions from GitHub as | |
| 758 | before, reusable workflows from a public GitHub repository. A `./` call | |
| 759 | inside a called workflow reads from that workflow's own repository. | |
| 760 | - **Secrets for called workflows** follow GitHub: none but the job token | |
| 761 | unless the caller passes `secrets:` by name or `secrets: inherit`; | |
| 762 | required secrets are checked before the call; a called job's | |
| 763 | `environment:` reads that environment's secrets over what was passed. The | |
| 764 | mapping is kept with the called jobs and read when each starts, so no | |
| 765 | secret is stored. (Before, same-repository called workflows read every | |
| 766 | repository secret.) | |
| 767 | - **Triggers:** `release` (created, published, released, prereleased, | |
| 768 | edited, unpublished, deleted; repos now publishes `release.*`), | |
| 769 | `deployment` and `deployment_status` (from the deployments service's | |
| 770 | events; ones an Actions job or a job token made are marked | |
| 771 | `causedByJob` and start nothing), `pull_request` `reopened` and | |
| 772 | `converted_to_draft`, `issue_comment` `edited` and `deleted` (work | |
| 773 | publishes `pull.reopened`, `pull.converted_to_draft`, `comment.edited` | |
| 774 | and `comment.deleted`). | |
| 775 | - **`timeout-minutes` on every step**, `uses:` included: the runner keeps a | |
| 776 | step deadline every process it starts stops by, nested composite steps | |
| 777 | taking the nearer one. | |
| 778 | - **Not yet:** a deployment's `ref` that is neither a branch nor a commit | |
| 779 | is read as a tag; `on: delete`. | |
| 780 | ||
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 781 | ### Runs: summaries, attempts, cancelling, logs and badges (built 2026-10-08) |
| 782 | ||
| 783 | GitHub Actions parity on the run itself: | |
| 784 | ||
| 785 | - [x] **Job summaries.** The runner sends each step's | |
| 786 | `$GITHUB_STEP_SUMMARY`, masked, as a `summary` report (1 MiB a step, | |
| 787 | 20 steps a job, kept in `job_summaries`, actions/0009); the run's page | |
| 788 | renders them as sanitised Markdown, a card per job. | |
| 789 | - [x] **Attempts and re-runs.** A re-run is a new attempt that keeps the | |
| 790 | one before (`run_attempts`, `job_attempts`; a re-run job's logs and | |
| 791 | summary move to `{job}.{attempt}`, which is its id when that attempt is | |
| 792 | viewed). Re-run all, failed, or one job (`POST …/jobs/{job}/rerun`) with | |
| 793 | the jobs that need it; a matrix or a called workflow runs again whole. | |
| 794 | Debug re-runs set `RUNNER_DEBUG=1`, `ACTIONS_STEP_DEBUG`, | |
| 795 | `ACTIONS_RUNNER_DEBUG` and `runner.debug`; the runner then shows | |
| 796 | `::debug::` lines and how each step's `if:` read. An attempt picker on | |
| 797 | the run's page, `attempt` on `get_workflow_run` and | |
| 798 | `…/runs/{id}/attempts/{n}`. | |
| 799 | - [x] **Graceful cancel.** A running job gets `cancel_requested_at`, | |
| 800 | told in the answer to its next report (a quiet step pings every 10 s): | |
| 801 | the step's process group gets SIGINT, SIGTERM at 7.5 s, SIGKILL at 10 s; | |
| 802 | then only `always()`/`cancelled()` steps and post steps run, and the job | |
| 803 | ends `cancelled`. Hard-stopped after 5 minutes; cancelling again or | |
| 804 | `…/force-cancel` stops at once. | |
| 805 | - [x] **Logs.** Search on the run's page (matching lines, groups opened); | |
| 806 | one job's log as text (`…/jobs/{job}/log.txt`, API | |
| 807 | `…/jobs/{job}/logs?format=text`) and an attempt's as a zip laid out as | |
| 808 | GitHub's (`…/runs/{id}/logs.zip`, API `…/runs/{id}/logs`), up to 24 MiB. | |
| 809 | - [x] **Status badges** at `/{ws}/{repo}/actions/workflows/{file}/badge.svg` | |
| 810 | with `branch` and `event`; public repositories' for anyone (cached a | |
| 811 | minute), private ones' only for viewers who can see them. "Create status | |
| 812 | badge" on the workflow's page gives the Markdown. | |
| 813 | - Not yet: re-running one combination of a matrix alone; signals into a | |
| 814 | job container's processes on cancel (they reach `docker exec` only). | |
| 815 | ||
| Merge runner image: Java 21, .NET 8, Ruby 3.3 | 816 | ### Runner image: Java, .NET and Ruby (built 2026-10-08) |
| 817 | ||
| 818 | The base (`services/runner/base/Dockerfile`) adds Temurin 21, the .NET 8 | |
| 819 | SDK and Ruby 3.3, placed where the setup actions look so common workflows | |
| 820 | run unmodified and download nothing: | |
| 821 | ||
| 822 | - **Java** in `RUNNER_TOOL_CACHE/Java_Temurin-Hotspot_jdk/<semver, + as | |
| 823 | ->/x64` with `x64.complete`; `JAVA_HOME`, `JAVA_HOME_21_X64` and `PATH` | |
| 824 | set. `actions/setup-java` (`temurin`, `21`) resolves it from the cache. | |
| 825 | - **.NET** in `/usr/share/dotnet` (setup-dotnet's Linux install dir), | |
| 826 | owned by `node`; `DOTNET_ROOT` set, telemetry off. `setup-dotnet` with | |
| 827 | `8.0.x` keeps it while it is the newest 8.0 SDK, else installs beside it. | |
| 828 | - **Ruby** built from source into `RUNNER_TOOL_CACHE/Ruby/<v>/x64` with | |
| 829 | `x64.complete`, on `PATH`. On Debian, `ruby/setup-ruby` counts as | |
| 830 | self-hosted and uses only the tool cache, so any version but 3.3 fails | |
| 831 | (documented in limitations). | |
| 832 | ||
| 833 | **`gh`: not installed.** With `GH_HOST=g1t.sh`, `gh` treats g1t as | |
| 834 | GitHub Enterprise Server: REST under `https://g1t.sh/api/v3` and GraphQL at | |
| 835 | `https://g1t.sh/api/graphql`. Both are 404 today (the API is REST at | |
| 836 | `api.g1t.sh`, and `GITHUB_GRAPHQL_URL` is empty), and `pr`, `issue`, `repo` | |
| 837 | and `run` are GraphQL-first, so even `gh api` alone would need the | |
| 838 | `/api/v3` prefix. Jobs call the API with `curl` and `$GITHUB_API_URL` | |
| 839 | (documented in the Actions guide). | |
| 840 | ||
| 841 | **Later:** to make `gh` useful, `g1t.sh/api/v3/*` proxying to the REST API | |
| 842 | (enough for `gh api` and `gh auth status`), then a GraphQL subset for the | |
| 843 | `pr`/`issue` read paths. Ship `gh` in the base only once those exist. | |
| 844 | More preinstalled Rubies (3.2, 3.4) if workflows ask, at roughly 75 MB | |
| 845 | each. `setup-dotnet@v5` first installs the current LTS .NET runtime (10, | |
| 846 | a 36 MB download) every run before finding SDK 8 already there; | |
| 847 | preinstalling that runtime would skip it. | |
| 848 | ||
| 849 | **Size:** the base went from 3.18 GB to 4.52 GB as `docker image inspect` | |
| 850 | reports it (813 MB to about 1.2 GB compressed): Temurin 308 MB (without | |
| 851 | `src.zip`), .NET 512 MB (without the SDK's translations), Ruby 74 MB, | |
| 852 | headers and ICU 44 MB. | |
| 853 | ||
| Plan: a repository that maintains itself, and deployments on g1t.page | 854 | ## A repository that maintains itself |
| 855 | ||
| 856 | > **2026-10-04:** the user asked for Dependabot, GitHub Advanced Security and | |
| 857 | > Vercel-style deployments, "so you're not having to maintain shit and you're | |
| 858 | > just pushing up agents that are delivering work consistently". | |
| 859 | ||
| 860 | GitHub reports problems and leaves the fix to you. In g1t, an agent opens an | |
| 861 | issue for each problem, writes the fix, runs its checks, links a preview and | |
| 862 | lands it through the queue. People only decide. | |
| 863 | ||
| 864 | ### Upkeep agents | |
| 865 | ||
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 866 | - **Dependency updates.** The file is `dependabot.yml` version 2, read from |
| 867 | the default branch at `.g1t/dependabot.yml` (or `.yaml`), then | |
| 868 | `.github/dependabot.yml` (or `.yaml`); `.g1t/` wins when both exist, and | |
| 869 | an imported repository's file works unchanged. Every option is read and | |
| 870 | checked, each problem reported with its line and key on the Security page | |
| 871 | and as the `g1t / dependabot.yml` status on pull requests that change the | |
| 872 | file; a file with problems is not acted on. | |
| 873 | - **Built (2026-10-07):** version updates for npm, cargo, gomod and pip: | |
| 874 | schedules (all intervals, cron and natural phrases, time zones, a | |
| 875 | picked time per repository), allow, ignore, cooldown (3 days by | |
| 876 | default), groups (including across directories and `group-by`), | |
| 877 | versioning strategies, open-pull-requests-limit, commit-message, | |
| 878 | branch names, rebase-strategy, assignees, reviewers, private | |
| 879 | registries filled from workflow secrets (npm, cargo, Go proxy, Python | |
| 880 | index), and the `@g1t` comment commands. Pull requests come from g1t | |
| 881 | with an `updated-dependencies` commit record and land through the | |
| 882 | required checks; one that fails them is closed and becomes a | |
| 883 | "needs code changes" issue assigned to g1t. | |
| 884 | - **Security updates follow the same file:** ignore (and comment | |
| 885 | ignores), allow names, `applies-to: security-updates` groups, | |
| 886 | commit-message, assignees, reviewers, labels and milestone. Cooldown | |
| 887 | and the open pull request limit do not apply. The Security updates | |
| 888 | switch still turns them on and off. | |
| 889 | - **Labels, milestone and target-branch** are applied to version | |
| 890 | updates: `dependencies` and the ecosystem's label by default, missing | |
| 891 | labels created; `target-branch` updates are made from that branch and | |
| 892 | merge into it. | |
| 893 | - **Not done yet:** one pull request for a multi-ecosystem group | |
| 894 | (it opens one per ecosystem); registries that sign in with OIDC; | |
| 895 | updating vendored copies; and version updates for the other | |
| 896 | ecosystems (bundler, composer, docker, github-actions, gradle, maven, | |
| 897 | nuget, terraform, uv and the rest are read and checked only). | |
| Plan: a repository that maintains itself, and deployments on g1t.page | 898 | - **Secret scanning.** Pushes are scanned for known token formats. A push |
| 899 | that adds a secret is refused with the file and line; one already in | |
| 900 | history opens an issue to rotate it and remove it. | |
| 901 | - **Vulnerability alerts.** Dependencies are matched against the OSV | |
| 902 | database. Every alert links to the issue and pull request fixing it. | |
| 903 | - **Code scanning.** A reviewer agent reads each pull request's diff for | |
| 904 | security problems and leaves findings as review comments with a | |
| 905 | suggested fix. Findings on `main` open issues. | |
| 906 | - **A security page per repository** lists alerts, secrets and findings, | |
| 907 | with the agent work on each, like GitHub's Security tab. | |
| 908 | ||
| 909 | All of these are event sources for the existing issue → agent → checks → | |
| 910 | queue pipeline; they need no new kind of work. | |
| 911 | ||
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 912 | ### The security suite (built 2026-10-07) |
| 913 | ||
| 914 | GitHub Advanced Security's depth, in g1t's shape (services/security, | |
| 915 | `g1t_contracts::security_suite`, docs `guides/security/*`): | |
| 916 | ||
| 917 | - **Secret protection.** Custom patterns (repository and workspace; Rust | |
| 918 | `regex`, linear time, size-limited; test strings; dry run over the | |
| 919 | default branch) used by push protection, `commit_file` and history | |
| 920 | scans. Bypass with a reason (false positive, used in tests, will fix | |
| 921 | later), recorded on the alert and in the audit log; delegated bypass | |
| 922 | (requests reviewed by owners and repository admins, through the inbox). | |
| 923 | Validity checks for GitHub, GitLab, Stripe, Slack, npm, OpenAI, | |
| 924 | Anthropic and SendGrid tokens, made by the repos service, which reads the | |
| 925 | landed secret again: the value never leaves it except to the issuer. AWS | |
| 926 | keys (need their secret key to sign) and webhook addresses (would post) | |
| 927 | are the extension points left (`g1t_scan::validity::check_for`). | |
| 928 | - **Code scanning.** SARIF 2.1.0 uploads → alerts with fingerprints (tool | |
| 929 | partial fingerprints first), fixed when no longer reported; pull request | |
| 930 | uploads → line comments and the `Code scanning` commit status, gated by a | |
| 931 | per-repository threshold and required like any check. Starter workflow: | |
| 932 | a scanner per language present, each uploading its own category: Bandit | |
| 933 | (Python), gosec (Go), ESLint + eslint-plugin-security with the SARIF | |
| 934 | formatter (JS/TS), Clippy + clippy-sarif (Rust); all install from the | |
| 935 | registries the runner's egress already allows. Semgrep's registry rules | |
| 936 | and the Opengrep rules fork are not usable in a paid feature, so neither | |
| 937 | is used. "Fix with g1t" opens an issue and runs the agent. | |
| 938 | - **Supply chain.** Dependency graph (direct/transitive where the lockfile | |
| 939 | says, npm licenses), SPDX 2.3 SBOM, `Dependency review` status on every | |
| 940 | pull request (OSV severity threshold, license deny list, summary comment). | |
| 941 | - **Overview.** Workspace totals, opened/closed, a daily snapshot trend, | |
| 942 | coverage, repositories most in need first. | |
| 943 | - **Paid.** The Security and quality activation on private repositories; | |
| 944 | free on public ones; the free core (secret scanning, push protection, | |
| 945 | vulnerability alerts, security updates, dependency graph) free everywhere. | |
| 946 | ||
| 947 | Not built yet: | |
| 948 | ||
| 949 | - **The reviewer agent as an analysis source.** g1t's reviewer reads each | |
| 950 | pull request's diff (`agent_review`), but its findings are review | |
| 951 | comments, not SARIF. Next: have it emit SARIF for the security issues it | |
| 952 | finds and upload them as the tool `g1t review`, so they become alerts and | |
| 953 | count toward the Code scanning check. | |
| 954 | - **Repository security advisories.** Private advisories, draft → | |
| 955 | published, with affected versions (ranges per ecosystem), severity and a | |
| 956 | CVSS vector, credits, and a private fork (a `g1t/advisory/GHSA-…` working | |
| 957 | copy only the advisory's collaborators can see) for the fix, merged into | |
| 958 | the default branch when the advisory publishes. Published advisories | |
| 959 | should feed the OSV-shaped data other g1t repositories' vulnerability | |
| 960 | alerts read. CVE requests are out of scope. Needs: an `advisories` table | |
| 961 | per repository, a collaborator list per advisory, the private-fork | |
| 962 | visibility rule in repos, and an Advisories page on the Security tab. | |
| 963 | - **SARIF upload as a background job.** Uploads are read in the request | |
| 964 | (10 MB encoded, 40 MB unzipped, 5,000 results); larger ones need a queue. | |
| 965 | ||
| Plan: a repository that maintains itself, and deployments on g1t.page | 966 | ### Deployments |
| 967 | ||
| 968 | - **A preview for every pull request**, at | |
| 969 | `<pr>--<repo>--<owner>.g1t.page`, linked on the pull request and updated | |
| 970 | on each push. `main` deploys to `<repo>--<owner>.g1t.page`, and a | |
| 971 | repository can add its own domain. | |
| 972 | - **On g1t.page, not g1t.sh,** so customer code never shares cookies or an | |
| 973 | origin with the site people sign in to. | |
| 974 | - **Built on Workers for Platforms.** Each deployment is a user Worker in a | |
| 975 | dispatch namespace; one dispatch Worker on `*.g1t.page` routes to it. The | |
| 976 | build runs in the same runners as Actions. Static sites and Workers apps | |
| 977 | first; container apps and databases later. | |
| 978 | - **Agents use the preview.** The reviewer agent opens the preview in a | |
| 979 | browser, takes screenshots of what changed and attaches them to its | |
| 980 | review, so an approver sees the result without reading the diff. | |
| 981 | - **Environments.** Preview, production and their secrets; deploy history | |
| 982 | and one-click rollback. | |
| 983 | - **Scale to zero.** An idle branch costs neither g1t nor the customer | |
| 984 | anything: a Worker runs, and is billed, only while it answers a request. | |
| 985 | A preview is deleted when its pull request closes or merges, and after | |
| 986 | a set number of idle days. Container apps, later, sleep when idle. | |
| Plan: deployments are billed to the customer, never free | 987 | - **Billed to the customer, never free.** The user (2026-10-04): "we |
| 988 | should not be giving any of this available for free". Every deployment | |
| 989 | is metered per workspace (requests, CPU time, deployed apps, stored | |
| 990 | data), priced at Cloudflare's cost + 20% like agent usage, and drawn | |
| 991 | from prepaid credit. `FREE_WHILE_BUILDING` and the free model allowance | |
| 992 | do not cover deployments: a workspace without credit cannot deploy, and | |
| 993 | turning deployments on says so first. | |
| Plan: turning deployments on is a paid monthly plan | 994 | - **Turning them on is a paid plan, the way Cloudflare's is.** "Including |
| 995 | things like them even enabling the feature should have that pay like | |
| 996 | Cloudflare does." Enabling deployments for a workspace starts a monthly | |
| 997 | fee that includes an allowance of requests, CPU time and deployed apps; | |
| 998 | usage past it is billed per unit, as Workers for Platforms bills g1t. | |
| 999 | The fee and allowance are the user's to set. | |
| 1000 | - **Recommended, off in one click.** Because enabling costs money, it is | |
| 1001 | never switched on without the workspace agreeing: new repositories | |
| 1002 | recommend it prominently. A repository can turn it off, keep only production, or | |
| Plan: a repository that maintains itself, and deployments on g1t.page | 1003 | deploy somewhere else from its own workflows. Apps built for Cloudflare |
| 1004 | (Workers, static assets, D1, KV, R2) deploy without configuration. | |
| 1005 | ||
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1006 | Later, toward GitLab's DevOps breadth: package and container registries, |
| 1007 | releases, container hosting. (Environments' protection rules for g1t | |
| 1008 | Actions were built on 2026-10-08; see above.) | |
| Plan: a repository that maintains itself, and deployments on g1t.page | 1009 | |
| Plan: Projects, the home of everything about running software | 1010 | ## Projects |
| 1011 | ||
| 1012 | > **2026-10-04:** the user: "an extra dimension of Projects so it's not | |
| 1013 | > just repositories … where a lot of things can live", "very Vercel | |
| 1014 | > like", with dependencies across projects "the Platform Engineering / | |
| 1015 | > Port route", and "the repository is *part* of a project: you could be | |
| 1016 | > mirroring it from GitHub/GitLab/Bitbucket, or you could let us host it | |
| 1017 | > for you", with room for Mercurial or anything else later. | |
| 1018 | ||
| 1019 | **A project is the thing you are building and running; a repository is | |
| 1020 | where some of its code lives.** Everything that is about running software | |
| 1021 | (deployments, environments, domains, secrets, dependencies, owners, | |
| 1022 | health, upkeep) belongs to the project. What is about the code itself | |
| 1023 | (branches, pull requests, review, merge rules) stays with the repository. | |
| 1024 | That split is what lets the code live anywhere. | |
| 1025 | ||
| 1026 | ### The model | |
| 1027 | ||
| 1028 | | | What it is | Like | | |
| 1029 | | --- | --- | --- | | |
| 1030 | | **Workspace** | The company or team. Members, billing, plans, shared secrets. | Vercel team, GitLab group, GitHub org | | |
| 1031 | | **Group** | An optional named set of projects, one level: "Payments", "Mobile". For browsing, ownership and shared settings. | GitLab subgroup, Backstage system, Port domain | | |
| 1032 | | **Project** | One deployable thing: a site, an API, a worker, a library. Has exactly one **source**. | Vercel project, Port service, Backstage component | | |
| 1033 | | **Source** | Where its code is: a repository and a **root directory** in it. | Vercel's connected repo + root directory | | |
| 1034 | | **Dependency** | Project A uses project B: calls its API, consumes its package, reads its queue. | Port relations, Backstage `dependsOn` | | |
| 1035 | ||
| 1036 | - **One project, one source; one repository, any number of projects.** A | |
| 1037 | project builds from exactly one place, which keeps it as simple as | |
| 1038 | Vercel's. A monorepo is several projects on one repository, each with | |
| 1039 | its own root directory (`apps/web`, `services/api`), and a push builds | |
| 1040 | only the projects whose root it touched. The common case stays 1:1, and | |
| 1041 | every existing repository gets a project of its own name when this | |
| 1042 | ships, so nobody has to set anything up. | |
| 1043 | - **Groups are for people; dependencies are for software.** Groups decide | |
| 1044 | where a project shows up and who owns it. Dependencies decide what | |
| 1045 | happens when one changes. Neither replaces the other, and a dependency | |
| 1046 | can cross groups. | |
| 1047 | ||
| 1048 | ### Sources: where the code lives | |
| 1049 | ||
| 1050 | A source is an adapter behind one interface (`SourcePort`: clone URL, | |
| 1051 | branches, commits, pushes as events, pull requests if it has them): | |
| 1052 | ||
| 1053 | | Source | Code lives | g1t gets pushes by | Pull requests | | |
| 1054 | | --- | --- | --- | --- | | |
| 1055 | | **Hosted on g1t** (today) | Artifacts | its own events | g1t's, with agents, the queue, review | | |
| 1056 | | **Mirrored** from GitHub, GitLab or Bitbucket | Both; g1t keeps a copy | the provider's webhook, then fetch | The provider's, read into g1t; agents open theirs there | | |
| 1057 | | **Connected, not copied** | The provider only | webhook | The provider's | | |
| 1058 | | **Later:** Mercurial, Perforce, a tarball upload | Behind the same port | per adapter | per adapter | | |
| 1059 | ||
| 1060 | A mirrored or connected project still gets everything that is the | |
| 1061 | project's: previews on its pull requests (a status and a comment on | |
| 1062 | GitHub's), production on its default branch, secrets, dependencies, | |
| 1063 | upkeep agents. That is the on-ramp: a team keeps GitHub and gets g1t's | |
| 1064 | deployments and agents first, and moves the code later or never. | |
| 1065 | Bring-your-own-git is also why the project, not the repository, holds the | |
| 1066 | URL `g1t.sh/<workspace>/<project>`. | |
| 1067 | ||
| 1068 | ### What lives on a project | |
| 1069 | ||
| 1070 | | | Today it is on | Moves to the project | | |
| 1071 | | --- | --- | --- | | |
| 1072 | | Deployments: production, previews, build settings, root directory, framework | The repository | Yes | | |
| 1073 | | Environments: production, preview, and custom ones (`staging`) with protection rules (required approvers, branch limits) | Nowhere yet | New, on the project | | |
| 1074 | | Domains: `<project>--<workspace>.g1t.page`, and custom domains | The repository's name | Yes | | |
| 1075 | | Secrets and variables | The repository | Yes. Workspace rows link to projects instead of repositories. A repository's workflows read the rows of its project (with several projects on one repository, the one marked as the repository's default). | | |
| 1076 | | Dependencies | Nowhere | New | | |
| 1077 | | Owners, on-call, links (docs, dashboards, runbooks) | Nowhere | New: the catalog's metadata | | |
| 1078 | | Health: scorecards (has an owner, CI passes, dependencies current, no open security alerts, deploys within N days) | Nowhere | New | | |
| 1079 | | Upkeep agents: dependency updates, security alerts | The plan | Scoped per project | | |
| 1080 | | Logs and analytics of the running app | Nowhere | New: requests, errors and CPU per environment, from Workers analytics | | |
| 1081 | | Branches, pull requests, review, merge rules, the queue, webhooks | The repository | Stay | | |
| 1082 | ||
| 1083 | ### Dependencies: why this gets powerful | |
| 1084 | ||
| 1085 | Declared in the UI, or in the source as `.g1t/project.yml` (which wins | |
| 1086 | when present, as `catalog-info.yaml` does in Backstage): | |
| 1087 | ||
| 1088 | ```yaml | |
| 1089 | name: web | |
| 1090 | root: apps/web | |
| 1091 | dependsOn: | |
| 1092 | - project: api # calls its HTTP API | |
| 1093 | as: API_URL # its URL, per environment, as a variable | |
| 1094 | - project: ui-kit # consumes its package | |
| 1095 | ``` | |
| 1096 | ||
| 1097 | What g1t does with them: | |
| 1098 | ||
| 1099 | 1. **Reference variables.** `API_URL` above resolves to `api`'s production | |
| 1100 | URL in production and to the matching preview in a preview, the way | |
| 1101 | Railway's `${{ api.URL }}` references work. No hard-coded URLs. | |
| 1102 | 2. **Preview stacks.** A pull request on `api` gets its own preview, and | |
| 1103 | **Preview with dependents** builds `web`'s preview pointed at it, so a | |
| 1104 | reviewer clicks through the whole change across projects. A change that | |
| 1105 | spans repositories (one issue, one fork per repository) gets one stack. | |
| 1106 | 3. **Release order.** Production deploys go out in dependency order; a | |
| 1107 | change set across projects lands through the queue together or not at | |
| 1108 | all. | |
| 1109 | 4. **Impact on every pull request.** "Changes `api`; `web` and `mobile` | |
| 1110 | depend on it." Agents get the graph in their context: an agent | |
| 1111 | changing an API opens follow-up issues on the projects that call it, | |
| 1112 | and reviewers see what else could break. | |
| 1113 | 5. **Upkeep across the graph.** A vulnerable package in `ui-kit` opens | |
| 1114 | issues, assigned to agents, on every project that consumes it. | |
| 1115 | 6. **Scorecards turn into work.** A project failing a scorecard check | |
| 1116 | ("no owner", "dependencies 90 days old") gets an issue an agent can fix. | |
| 1117 | That is the Port idea with the work done for you. | |
| 1118 | 7. **The map.** A workspace's projects as a graph, coloured by health and | |
| 1119 | by what is deploying now. | |
| 1120 | ||
| 1121 | ### Pages | |
| 1122 | ||
| 1123 | - `g1t.sh/<workspace>`: projects first (grouped, with health and | |
| 1124 | production status), then repositories. | |
| 1125 | - `g1t.sh/<workspace>/<project>`: overview (production, latest previews, | |
| 1126 | health, owners, dependencies both ways), **Deployments**, | |
| 1127 | **Environments**, **Secrets and variables**, **Logs**, **Settings** | |
| 1128 | (source, root directory, build, domains, groups, owners). | |
| 1129 | - A hosted repository keeps its code pages; from a project they are its | |
| 1130 | **Code** tab. A repository page lists the projects built from it. | |
| 1131 | ||
| 1132 | ### Services | |
| 1133 | ||
| 1134 | - `services/projects` (new): projects, groups, sources, dependencies, | |
| 1135 | owners, scorecards. Events `project.created`, `project.updated`, | |
| 1136 | `dependency.changed`. | |
| 1137 | - `services/deployments`: keyed by project instead of repository. | |
| 1138 | - Secrets and variables: the scope becomes workspace → project. | |
| 1139 | - Sources: the hosted adapter wraps `services/repos`; a mirror adapter | |
| 1140 | per provider in `services/integrations`, which already holds those | |
| 1141 | connections. | |
| 1142 | ||
| 1143 | ### Build order | |
| 1144 | ||
| 1145 | 1. **Projects as the home of deployments and secrets**, 1:1 with every | |
| 1146 | existing repository: the service, the pages, deployments and secrets | |
| 1147 | moved to the project, `<project>--<workspace>.g1t.page`. | |
| 1148 | 2. **Dependencies:** declared in the UI and `.g1t/project.yml`, reference | |
| 1149 | variables, impact on pull requests and in agents' context, the map. | |
| 1150 | 3. **Preview stacks** and cross-project change sets. | |
| 1151 | 4. **Monorepos:** several projects on one repository, each with a root | |
| 1152 | directory, building only what a push touched. | |
| 1153 | 5. **Mirrored sources:** GitHub first, then GitLab and Bitbucket. | |
| 1154 | 6. **Groups, owners, scorecards** feeding the upkeep agents. | |
| 1155 | 7. **Environments** with protection rules; custom domains; logs. | |
| 1156 | ||
| Projects: what a workspace builds and runs, first on every page | 1157 | **Step 1 shipped 2026-10-04:** `services/projects`; every repository a |
| 1158 | project of its own name; the site projects-first (workspace page of | |
| 1159 | project cards, the project overview at `g1t.sh/<workspace>/<project>`, code | |
| 1160 | under `/code`, the sidebar and the New project flow); deployments keyed by | |
| 1161 | project and branch at `<project>-<workspace>.g1t.page` and | |
| 1162 | `<project>-git-<branch>-<workspace>.g1t.page`; secrets and variables owned | |
| 1163 | by the project. | |
| 1164 | ||
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 1165 | **Step 5, GitHub, built 2026-10-05:** one GitHub App (`g1t-sh`) for both |
| 1166 | sign-in and repository access. Sign-in is its user authorization with PKCE | |
| 1167 | (identity, `src/github.rs`): accounts known by GitHub's numeric id, a | |
| 1168 | matching verified email never linked without signing in to the account, | |
| 1169 | new accounts behind the invite check. Repositories come through its | |
| 1170 | installations (integrations, `src/github.rs`), copied with every branch and | |
| 1171 | tag by the repos service (`src/mirror.rs`) as **import**, **mirror** (g1t | |
| 1172 | follows GitHub on its push webhook) or **move to g1t** (GitHub follows g1t | |
| 1173 | on `git.push`). A mirror is a hosted repository that keeps a full copy, so | |
| 1174 | its project stays `hosted` and deploys like any other; the tie lives in | |
| 1175 | integrations' `github_repos`. Not yet: previews and statuses on GitHub's own | |
| 1176 | pull requests, comments and pull requests copied, GitLab and Bitbucket. | |
| 1177 | ||
| Projects: what a workspace builds and runs, first on every page | 1178 | ### People and search |
| 1179 | ||
| 1180 | > **2026-10-04:** "pull up user profiles, using a /u/username prefix kinda | |
| 1181 | > like DockerHub … search for users if you search that explicitly, how | |
| 1182 | > GitHub has the aside for searching against filters … a significantly | |
| 1183 | > stronger implementation." | |
| 1184 | ||
| 1185 | - **Profiles at `g1t.sh/u/<username>`**, apart from workspaces at | |
| 1186 | `g1t.sh/<workspace>`: who they are, their workspaces, recent work, | |
| 1187 | agents' sessions they steered. | |
| 1188 | - **Search with a filter sidebar:** Projects, Code, Issues, Pull requests, | |
| 1189 | Users, Workspaces, each with its count; filters by workspace, language, | |
| 1190 | state, author, agent, label, date; qualifiers in the query | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 1191 | (`user:`, `is:open`, `agent:g1t`) as on GitHub. Typing `u/name` |
| Projects: what a workspace builds and runs, first on every page | 1192 | searches people directly, as Docker Hub does. |
| 1193 | ||
| Plan: Projects, the home of everything about running software | 1194 | 1 and 2 serve the competition directly (multi-agent coordination across |
| 1195 | projects is 25% of the score); 3 is the demo's best moment if time allows. | |
| 1196 | ||
| Plan: the billing model | 1197 | ## Billing model |
| 1198 | ||
| 1199 | > **2026-10-04:** "Some things just require you to have a card on file … | |
| 1200 | > some things will be something you give us an initial amount of money | |
| 1201 | > per month just to activate, tons of things additionally will be usage | |
| 1202 | > based, some things will just be usage based only … at minimum a | |
| 1203 | > breakeven with Cloudflare costs, or in some cases a value add." Stripe | |
| 1204 | > moves to Flagon, Inc. (g1t.sh is its product). Proposed below; the | |
| 1205 | > prices are the user's to confirm. | |
| 1206 | ||
| 1207 | ### Four kinds of charge | |
| 1208 | ||
| 1209 | Every feature is exactly one of these, and the Billing page says which: | |
| 1210 | ||
| 1211 | | Kind | What the workspace does | Example | | |
| 1212 | | --- | --- | --- | | |
| 1213 | | **Free** | Nothing | Hosting code, issues, pull requests, review, the merge queue, bringing your own agent over MCP | | |
| Prices are what g1t pays plus 20%, from the first second | 1214 | | **Card on file** | Adds a card; pays only for what it uses | Previews, g1t's agents, workflow minutes | |
| Plan: the billing model | 1215 | | **Activation** | Turns a feature on for a monthly fee that includes an allowance; usage past it is metered | Production deployments, Security and quality | |
| 1216 | | **Usage only** | Nothing up front; every unit is metered | Model tokens, build minutes, storage past the free amount | | |
| 1217 | ||
| 1218 | A card is needed before anything that can cost money starts. Nothing is | |
| 1219 | ever switched on without the workspace choosing it. | |
| 1220 | ||
| 1221 | ### Postpaid, with spend limits | |
| 1222 | ||
| 1223 | - **One Stripe customer and one subscription per workspace**, on Flagon, | |
| 1224 | Inc.'s account. Activations are licensed line items; every usage | |
| 1225 | dimension is a metered price backed by a Stripe Meter. Stripe invoices | |
| 1226 | monthly in arrears and charges the card on file; failed payments go | |
| 1227 | through Stripe's retries and emails, and g1t hears of them by webhook. | |
| 1228 | - **Spend limits instead of prepaid credit.** A workspace sets a monthly | |
| 1229 | limit overall and per feature (Vercel's spend management). g1t counts | |
| 1230 | usage as it happens and stops starting new paid work at the limit, | |
| 1231 | with a warning at 50%, 80% and 100%. Prepaid top-ups go away; promotions | |
| 1232 | (the free model allowance) become Stripe credit on the customer. | |
| 1233 | - **Usage reaches Stripe from billing alone.** Every service reports | |
| 1234 | usage to the billing service as it happens (it already records agent | |
| 1235 | runs and builds); billing batches them into Stripe meter events every | |
| 1236 | few minutes, idempotently by g1t's own ids, and keeps the ledger g1t's | |
| 1237 | pages show. Nothing else talks to Stripe. | |
| 1238 | ||
| 1239 | ### Scope: workspace, then projects | |
| 1240 | ||
| 1241 | - A feature is turned on for the **workspace** (by an owner, with the | |
| 1242 | activation if it has one), then allowed for **all projects** or | |
| 1243 | **selected projects**. | |
| 1244 | - Every **project** can opt out on its own page. A project with nothing | |
| 1245 | to deploy (no Workers config, no build script, no `index.html`) is | |
| 1246 | detected, says so on its Deployments page, and never builds or costs | |
| 1247 | anything. | |
| 1248 | - Agents and workflows are allowed per project the same way, so a | |
| 1249 | workspace can keep spend to the projects that matter. | |
| 1250 | ||
| Plan: prices pass every Cloudflare cost through | 1251 | ### Prices: what it costs us, passed through |
| 1252 | ||
| 1253 | > **2026-10-04, decided:** postpaid with spend limits, as Vercel and | |
| 1254 | > Cloudflare do; no per-seat price, ever ("fuck per-seat pricing"). | |
| 1255 | > "If they're barely using them great, but if they're using the shit out | |
| 1256 | > of them that will cost me a ton, so that cost needs to move onto them." | |
| 1257 | ||
| 1258 | **Every Cloudflare cost a workspace causes is metered to it.** Light use | |
| 1259 | fits in a small free allowance; past it, each unit is charged at | |
| 1260 | Cloudflare's price times a margin of at least 1.5, which pays for Stripe | |
| 1261 | (about 3%), shared overhead (the site, the API, D1) and g1t itself. | |
| Plan: the billing model | 1262 | |
| Plan: prices pass every Cloudflare cost through | 1263 | Cloudflare's prices (October 2026), and the cost per unit g1t meters: |
| Plan: the billing model | 1264 | |
| Plan: prices pass every Cloudflare cost through | 1265 | | What g1t meters | Cloudflare's price | Cost to g1t per unit | |
| 1266 | | --- | --- | --- | | |
| 1267 | | **Sandbox minute** (agents, checks, merge queue, workflow jobs, deploy builds), standard-1: ½ vCPU, 4 GiB, 8 GB | CPU $0.00002 / vCPU-s while busy; memory $0.0000025 / GiB-s and disk $0.00000007 / GB-s while running | ≤ $0.0012 / minute (CPU counted as busy throughout, since g1t cannot see it per sandbox) | | |
| 1268 | | **App request** (deployments) | Workers for Platforms: $0.30 / million past 20M | $0.30 / million | | |
| 1269 | | **App CPU** | $0.02 / million CPU-ms past 60M | $0.02 / million ms | | |
| 1270 | | **App** (a deployed script) | $0.02 / script-month past 1,000 | $0.02 / app-month | | |
| 1271 | | **Storage** (repositories, artifacts, caches) | Artifacts $0.50 / GB-month (billing starts 2026-10-14); KV $0.50 / GB-month | $0.50 / GB-month | | |
| 1272 | | **Git operation** (clone, fetch, push) | Artifacts $0.15 / 1,000 past 10,000 | $0.15 / 1,000 | | |
| 1273 | | **Model tokens** | The provider's price | As charged | | |
| 1274 | | Container egress, emails, the site's own requests | Small and shared | In the margin | | |
| 1275 | ||
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 1276 | > **2026-10-06, decided:** no per-feature quotas on the plan. "A paying |
| 1277 | > user should be able to push past the Git operations number, they're | |
| 1278 | > just paying usage on it." One plan, $20 a month per workspace with $10 | |
| 1279 | > of usage included; every meter is charged from the first unit at cost + | |
| 1280 | > 20% (builds, app requests and CPU, custom domains), drawn from the $10 | |
| 1281 | > first, then up to the spend limit, which is the only thing that stops a | |
| 1282 | > paying workspace (with abuse protection). Projects, previews and apps | |
| 1283 | > are not metered (Workers for Platforms' script pool makes them ~free). | |
| 1284 | > The forge's free amounts are the same for everyone: 1 GB private storage | |
| 1285 | > and 50,000 git operations a month; past them the plan pays and a free | |
| 1286 | > workspace is held (pushes stop, git slowed). The table below is the | |
| 1287 | > earlier proposal; billing's price book and g1t.sh/pricing are current. | |
| 1288 | ||
| Plan: prices pass every Cloudflare cost through | 1289 | What a workspace pays: |
| 1290 | ||
| 1291 | | Meter | Free each month | Then | Margin | For comparison | | |
| 1292 | | --- | --- | --- | --- | --- | | |
| Prices are what g1t pays plus 20%, from the first second | 1293 | | Sandbox minutes | None (2026-10-05: charged from the first second) | Cost + 20%, by the second | 1.2× | GitHub Actions $0.008 / minute (Linux 2-core); Vercel builds $0.0035 / CPU-minute | |
| Plan: prices pass every Cloudflare cost through | 1294 | | App requests | 1 million with Deployments | $0.50 / million | 1.7× | Vercel $0.60 / million invocations | |
| 1295 | | App CPU | 3 million ms with Deployments | $0.04 / million ms | 2× | Vercel active CPU about $0.036 / million ms | | |
| 1296 | | Apps | 10 with Deployments | $0.05 / app-month | 2.5× | | | |
| 1297 | | Storage | 1 GB | $1.00 / GB-month | 2× | GitHub LFS $0.07 / GB, but repositories are free there | | |
| 1298 | | Git operations | 10,000 | $0.30 / 1,000 | 2× | | | |
| 1299 | | g1t's models | | Cost + 20% | 1.2× | The provider's own price | | |
| Prices are what g1t pays plus 20%, from the first second | 1300 | | Your own model provider | | Only its sandbox minutes (the $0.10 run fee was dropped 2026-10-05) | | | |
| Plan: prices pass every Cloudflare cost through | 1301 | | **Deployments** activation | | $5 / month, with the allowances above | covers Workers for Platforms' $25 / month across workspaces | Vercel Pro $20 per seat | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 1302 | | **Security and quality** activation (built 2026-10-07: price book meter `security_activation`) | | $10 / month; fixes as agent usage | | GitHub Advanced Security $49 per committer | |
| Plan: the billing model | 1303 | |
| Plan: prices pass every Cloudflare cost through | 1304 | A workspace that uses g1t lightly (a few agent runs, a small site) |
| 1305 | pays nothing or its activation; a workspace running agents all day pays | |
| 1306 | for the sandboxes and models those agents use, with g1t's margin on | |
| 1307 | each. Nothing in a workspace's bill is subsidised by another's. | |
| Plan: the billing model | 1308 | |
| 1309 | ### Build order | |
| 1310 | ||
| 1311 | 1. Stripe customer per workspace and card on file (Checkout in setup | |
| 1312 | mode), webhooks (invoice paid and failed, subscription changes, | |
| 1313 | payment method changes), the Billing page rebuilt around the four | |
| 1314 | kinds. | |
| 1315 | 2. One subscription per workspace with activations as items; Deployments | |
| 1316 | moves onto it. | |
| Plan: prices pass every Cloudflare cost through | 1317 | 3. Meters for each usage dimension above, fed from billing's ledger: |
| 1318 | every sandbox reports how long it ran when it stops (agents, checks, | |
| 1319 | the queue, workflow jobs and deploy builds alike); deployments report | |
| 1320 | requests, CPU and apps; repos report storage and git operations. Spend | |
| Plan: the billing model | 1321 | limits and their warnings; prepaid credit retired. |
| 1322 | 4. Per-workspace allow-lists of projects for each feature, and per-project | |
| 1323 | opt-out; "nothing to deploy" detection. | |
| Billing accounts, terms and enterprises; g1t is no longer free | 1324 | 5. Turn off FREE_WHILE_BUILDING when the user says so. **Done 2026-10-05.** |
| 1325 | ||
| 1326 | Shipped by 2026-10-05: sandbox seconds for every sandbox; the price book | |
| 1327 | and its keeper (runs settled to AI Gateway's price every 15 minutes; | |
| 1328 | Container and Workers costs checked against Cloudflare's billable usage | |
| 1329 | and container analytics daily, with a public change log on | |
| 1330 | g1t.sh/pricing); usage limits by trust with automatic payment near the | |
| 1331 | limit; app traffic counted toward limits as it happens; billing accounts, | |
| 1332 | terms and enterprises; free mode off, syntaqx comped. | |
| 1333 | ||
| 1334 | Still to build, in order: Stripe card-on-file without a payment (setup | |
| 1335 | mode) and webhooks; month-end invoices for postpaid usage (and one | |
| 1336 | invoice per enterprise); the subscription with activations as items; | |
| 1337 | storage and git-operation meters; limit warnings by email at 50/80/100%; | |
| 1338 | self-serve enterprise management for enterprise owners. | |
| 1339 | ||
| 1340 | ### Accounts, terms and enterprises | |
| 1341 | ||
| 1342 | Every workspace is paid for by a billing account: its own (`ws_<slug>`) | |
| 1343 | or an enterprise's (`ent_…`), which pays for several workspaces with one | |
| 1344 | limit, one set of terms and, once invoices exist, one bill, as GitHub | |
| 1345 | Enterprise does. Terms are standard, comped (nothing charged, usage still | |
| 1346 | recorded at cost, paid features on) or custom (a discount, its own | |
| 1347 | ceiling, an end date). g1t staff manage them in **sudo.g1t.sh**, a | |
| 1348 | separate Worker behind Cloudflare Access that also verifies the Access | |
| 1349 | token itself and allows only listed staff emails; every change is kept | |
| 1350 | with who made it and why. | |
| 1351 | ||
| 1352 | ### Limits: stop non-payers, never payers | |
| 1353 | ||
| 1354 | The limit is on usage not yet paid for, counted at cost to g1t or charge, | |
| 1355 | whichever is more: $3 before any live payment, then twice what has been | |
| 1356 | paid ($25 to $1,000), or what staff set. A workspace with a card on file | |
| 1357 | is charged automatically near its limit, which both pays what it owes and | |
| 1358 | raises the limit, so paying users are never stopped. A declined card | |
| 1359 | stops work until paid. The owner's own spend limit always means stop. | |
| 1360 | Test-mode payments never lower exposure or raise trust. | |
| Plan: the billing model | 1361 | |
| Merge Stripe Tax, the card fee on card payments, and one free workspace per person | 1362 | ### Tax, card fees and free workspaces (built 2026-10-08) |
| 1363 | ||
| 1364 | > **2026-10-08, decided:** Stripe Tax everywhere ("so I don't fuck up on | |
| 1365 | > taxes"); Stripe's card fee passed to the customer with the 20% markup | |
| 1366 | > kept; one free workspace per person; no invites on free workspaces. | |
| 1367 | ||
| 1368 | - **Stripe Tax on every payment.** `automatic_tax` on every Checkout page | |
| 1369 | (plan, Security and quality, prepaying, AI credit), every subscription | |
| 1370 | and every invoice g1t makes (month close, threshold, enterprise), and a | |
| 1371 | tax calculation and transaction for auto-reload's off-session charge. | |
| 1372 | Tax code `txcd_10103001` (SaaS, business use), every price | |
| 1373 | `tax_behavior=exclusive`. Checkout always collects the billing address | |
| 1374 | and tax ID and saves them on the customer. Prices on g1t are shown | |
| 1375 | excluding tax. Tax is never revenue: balances and plan payments are | |
| 1376 | credited without it, it is kept in `tax_and_fees`, shown as its own | |
| 1377 | statement line, and as **Tax collected** on sudo's Costs. Without an | |
| 1378 | address g1t does not charge: the owners are asked for one. | |
| 1379 | - **The card fee** (2.9% + $0.30, grossed up) is its own line on every | |
| 1380 | card payment, the plan's and Security's as a monthly item; never on a | |
| 1381 | bank transfer or an enterprise's invoice. On by default | |
| 1382 | (`cost_settings.card_fee`). Not revenue either. Meters stay at cost + | |
| 1383 | 20%; models at the provider's price plus the agent rate. | |
| 1384 | - **One free workspace per person.** Identity asks billing | |
| 1385 | (`free_workspaces`) before creating one; a second is refused with the | |
| 1386 | way forward. Those who own several from before keep them. | |
| 1387 | - **A free workspace adds no one**: no members, invites or outside | |
| 1388 | collaborators until it starts the plan; its members stay; @g1t never | |
| 1389 | counts. Enforced in identity for every path (site, API, MCP). | |
| 1390 | - Details: docs/BILLING_OPERATIONS.md, *Tax and the card fee*. | |
| 1391 | ||
| Billing: credits with a kind and expiry, discounts instead of comped, and safer charging | 1392 | ### Promo codes (planned) |
| 1393 | ||
| 1394 | Staff credits (promotional, goodwill, refund; `services/billing/src/grants.rs`, | |
| 1395 | docs/BILLING_OPERATIONS.md) are given one workspace at a time. Promo codes | |
| 1396 | give promotional credit in bulk, on redemption, through the same grants: | |
| 1397 | ||
| 1398 | - **Codes.** sudo → Credits & refunds → **New code**: the code (or one | |
| 1399 | made up), the credit ($ amount), max redemptions, when the code stops | |
| 1400 | working, how long each redeemed credit lasts (an expiry, as any grant), | |
| 1401 | and a note. Table `promo_codes` (code, amount, max, redeemed, ends_at, | |
| 1402 | credit_days, note, created_by, disabled_at) and `promo_redemptions` | |
| 1403 | (code, workspace, grant id, by, at), unique on (code, workspace). | |
| 1404 | - **Redeeming.** An owner types it on the workspace's Billing page | |
| 1405 | (`redeem_code`, owners only). One D1 batch checks the code is open, under | |
| 1406 | its max and not redeemed by the workspace, counts the redemption and | |
| 1407 | makes the grant (`grant_credit`, kind promotional, the code as its note), | |
| 1408 | so two redemptions at once never pass the max. Wrong or used-up codes say | |
| 1409 | so without telling which codes exist; redemptions are rate-limited per | |
| 1410 | owner. | |
| 1411 | - **Seeing them.** Each code's redemptions, credit given and spent come | |
| 1412 | from the grants it made, so margin needs nothing new: spent promo credit | |
| 1413 | is already given away, by kind. | |
| 1414 | - **Not yet built** because it adds an owner-facing form, abuse limits and | |
| 1415 | a second sudo form; giving credit by workspace covers launch. | |
| 1416 | ||
| Initial g1t: services, event bus, intents and attempts | 1417 | ## Agents and models |
| 1418 | ||
| 1419 | ### Defining an agent | |
| 1420 | ||
| 1421 | An agent is a file (`.g1t/agents/<name>.md`, or in the workspace library): | |
| 1422 | instructions, the harness and model to run, the tools and MCP servers it may | |
| 1423 | use, its sandbox image, permissions and budget. Agents take roles: planner, | |
| 1424 | implementer, reviewer, conflict resolver, documenter, memory consolidator. | |
| 1425 | Each role has a default that a repo can replace. | |
| 1426 | ||
| 1427 | ### Where it runs, and on whose model | |
| 1428 | ||
| 1429 | | Option | How it works | Fits | | |
| 1430 | | --- | --- | --- | | |
| 1431 | | Hosted, g1t's model | g1t runs the sandbox and bills usage | Getting started; no keys to manage | | |
| 1432 | | Hosted, your API key | Same sandbox, your Anthropic, OpenAI or Google key | Teams with existing contracts | | |
| 1433 | | Hosted, your endpoint | Any OpenAI-compatible URL: Bedrock, Vertex, Azure, a self-hosted model | Private or fine-tuned models | | |
| Issues and pull requests replace intents and attempts | 1434 | | Your runner | A g1t runner daemon on your own machines picks up pull requests | Code or models that may not leave your network | |
| Initial g1t: services, event bus, intents and attempts | 1435 | | Your own session | Local Claude Code, Cursor or any MCP client joins through `mcp.g1t.sh` | Individuals; subscription plans | |
| 1436 | ||
| 1437 | Decisions behind this: | |
| 1438 | ||
| 1439 | - **g1t does not build its own agent loop.** It runs existing harnesses | |
| 1440 | (Claude Code first, through its headless mode) behind a small runner | |
| 1441 | contract: a container image, an entry command, and session events reported | |
| 1442 | through the CLI. Other harnesses plug in by meeting the contract. | |
| 1443 | - **All hosted model traffic goes through Cloudflare AI Gateway.** That gives | |
| 1444 | one place for spend tracking, budgets, rate limits, fallback and logs, | |
| 1445 | whichever provider or endpoint is behind it. | |
| Merge branch 'model-routing' | 1446 | - **Nobody has to pick a model.** A person assigns work to `g1t`, as |
| 1447 | they would assign an issue to a colleague, and **Auto** routes each job | |
| 1448 | to the cheapest model that can do it (see | |
| 1449 | [Routing for cost](#routing-for-cost) below). A workspace can pin a tier | |
| 1450 | per kind of work instead. Each request is tagged at the gateway with the | |
| 1451 | kind of work, the tier, the repository and the pull request, and each | |
| 1452 | run says which model ran and why. The gateway's own dynamic routes | |
| 1453 | cannot make the choice yet: they work only on its OpenAI-compatible | |
| 1454 | endpoint, and the harness speaks Anthropic's. | |
| Initial g1t: services, event bus, intents and attempts | 1455 | - **Subscriptions stay local.** A Claude subscription cannot be used by a |
| 1456 | hosted sandbox; it needs an API key. People on subscriptions use their own | |
| 1457 | Claude Code session, which is a full participant. | |
| Merge branch 'model-routing' | 1458 | - **The workspace pays.** A workspace buys AI credit by card and each |
| 1459 | agent run deducts the model at the provider's price plus the agent rate | |
| 1460 | per million (weighted) tokens; on its own model key, only the agent rate, | |
| 1461 | counted from the model proxy and the sandbox's own report. The billing service asks | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1462 | nothing of the others: the runner asks it before starting a sandbox and |
| 1463 | is refused when there is no credit, and the sandbox reports what its run | |
| 1464 | cost with a token only it holds. Where no card processor is configured | |
| 1465 | nothing is charged and agents stay limited to listed accounts. | |
| Initial g1t: services, event bus, intents and attempts | 1466 | - **Keys are secrets.** Stored in Cloudflare Secrets Store, injected into the |
| Issues and pull requests replace intents and attempts | 1467 | sandbox for one pull request, never shown again. |
| Initial g1t: services, event bus, intents and attempts | 1468 | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1469 | ### Seeing a pull request through |
| 1470 | ||
| 1471 | Assigning an issue is the only thing a person does until there is something | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 1472 | to merge. A pull request made by g1t goes through checks, a review |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1473 | by another agent, revision when either finds something, and catching up |
| 1474 | when `main` moves, without anyone pressing a button. It ends as ready to | |
| 1475 | merge, or as "needs you" with the reason: the checks still fail after two | |
| 1476 | revisions, a review could not be written, or a conflict could not be | |
| 1477 | resolved. | |
| 1478 | ||
| 1479 | The work service decides the next step from the pull request's state and | |
| 1480 | claims it in one statement, so a step is taken once. The runner asks on | |
| 1481 | every event that could change the answer (ready, pushed, checks finished, | |
| 1482 | review finished, `main` moved), and on a five-minute sweep for anything | |
| 1483 | missed, and carries the step out in a sandbox. | |
| 1484 | ||
| 1485 | A pull request does not have to be up to date with `main` to merge, | |
| 1486 | unless the repository's settings require it, as on GitHub. Merging one that | |
| 1487 | is behind brings it up to date first (a clean merge needs no model; an | |
| 1488 | agent resolves a conflict) and lands it when that push arrives. With the | |
| 1489 | requirement on, catching up is a step of its own and the checks run again | |
| 1490 | on the result. | |
| 1491 | ||
| 1492 | Each repository sets its own rules, on one settings page: whether its | |
| 1493 | default branch takes pushes at all, how many approvals a merge needs and | |
| 1494 | whether an agent's counts, whether failed checks can be overridden, whether | |
| 1495 | a second agent reviews, and how often an agent is sent back before a person | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 1496 | is asked. A pull request g1t opens follows the same rules as anyone's. |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1497 | Pushes to a protected branch are refused in the git front end, with the |
| 1498 | reason shown by git beside the branch. | |
| 1499 | ||
| 1500 | Merging is a person's decision unless the repository says otherwise. With | |
| 1501 | "merge automatically when ready" turned on in its settings, a ready pull | |
| 1502 | request lands by itself, attributed to `g1t`. That is the whole path from | |
| 1503 | an assigned issue to a commit on `main` with nobody in between. Required | |
| 1504 | human approval per path, and risk tiers, are still to come. | |
| 1505 | ||
| Merge branch 'model-routing' | 1506 | ### Routing for cost |
| 1507 | ||
| 1508 | *Built (runner `route` in `services/runner/src/model-env.ts`).* The goal | |
| 1509 | is cost per merged change, not cost per request: a cheap attempt that | |
| 1510 | fails and is retried on the same model costs more than one that finishes. | |
| 1511 | ||
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 1512 | - **Tiers and catalogue.** `small` (Claude Haiku 5.5 since 2026-10-08, |
| 1513 | $0.10/$0.50 per million input/output up to 100k-token prompts, five | |
| 1514 | times that above; it was Haiku 4.5 at $1/$5), `large` (Claude Sonnet 5.5, $2/$10) and `frontier` | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 1515 | (Claude Opus 5.5, $4/$20). Models, names and list prices are data, |
| 1516 | never code: since 2026-10-08 billing's model catalogue | |
| 1517 | (`gateway_models`, one row per model g1t can use) and staff's defaults | |
| 1518 | in sudo, **Agents & models** (`model_defaults`: each tier's model, the | |
| 1519 | harness's background model, the AI Gateway's first Claude, each job's | |
| 1520 | starting tier and effort), read by the runner once a minute over | |
| 1521 | `AGENT_ROUTING`, which is only the fallback when billing cannot be read. | |
| 1522 | Catalogue prices are for estimates only; runs are charged what AI | |
| 1523 | Gateway priced them at. | |
| 1524 | - **Keeping up with new models (built 2026-10-08).** The models service | |
| 1525 | lists Anthropic's models (through the AI Gateway) and Workers AI's daily | |
| 1526 | and on demand; a new id lands in the catalogue as `new`, priced from a | |
| 1527 | maintained table of Anthropic's list prices or Workers AI's listing, or | |
| 1528 | unpriced, and staff are emailed. Nothing routes to it, offers it or | |
| 1529 | charges for it until staff approve it with its prices. A model a provider | |
| 1530 | stops listing is `deprecated`; routing never sends work to a deprecated | |
| 1531 | or retired model, falling back to the next model of the tier and saying | |
| 1532 | so on the run. Customers keep Auto: the catalogue is staff's. See | |
| 1533 | [BILLING_OPERATIONS.md](BILLING_OPERATIONS.md#the-model-catalogue). | |
| Merge branch 'model-routing' | 1534 | - **Starting tier by job.** Catch-up, answering a question, and reviews of |
| 1535 | at most 10 files and 200 lines touching no sensitive path: small. | |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 1536 | Plans: small at high effort (Haiku 5.5 takes an effort level). |
| 1537 | Changes, revisions and other reviews: large. Reviews over 60 files | |
| Merge branch 'model-routing' | 1538 | or 3,000 lines: frontier. Labels: `architecture` frontier, `security` off |
| 1539 | small, `docs`/`documentation`/`typo` let changes and answers start small. | |
| 1540 | - **Escalation.** A failed (or guardrail-stopped) attempt at the same work | |
| 1541 | goes one tier up; two in a row, frontier; a revision counts its rounds; | |
| 1542 | a change left at low confidence sends the next attempt up. | |
| 1543 | - **Learning, per repository.** From the last 20 runs of the same kind: | |
| 1544 | one tier down when the cheaper tier finished at least 90% of at least 5 | |
| 1545 | (never for sensitive or labelled work, never on a retry); one tier up | |
| 1546 | when this tier failed at least half of at least 5. No new tables: it | |
| 1547 | reads work's `agent_runs` (model, status, confidence). | |
| 1548 | - **Explained.** Every run's first step and session note is one line: | |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 1549 | *Used a fast model (Claude Haiku 5.5): small change, 3 files and 80 |
| 1550 | lines.* Effort per kind of job (`effort` in `AGENT_ROUTING`: plan high, | |
| 1551 | answer medium, update low) is sent as `CLAUDE_CODE_EFFORT_LEVEL` on | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 1552 | g1t's tiers (never on a model the catalogue says takes none) and named |
| 1553 | in that line, with the catalogue's name for the model. | |
| Merge branch 'model-routing' | 1554 | - **Chosen instead.** `model_routes` rows to g1t's models name `small`, |
| 1555 | `large` or `frontier`, or nothing for Auto (Integrations → Models). | |
| 1556 | A workspace's own Anthropic key with no model named is routed by Auto | |
| 1557 | too. | |
| 1558 | - **Measured.** `scripts/ops/routing-savings.mjs` replays tasks through | |
| 1559 | the router offline, priced from the catalogue, against routing before | |
| 1560 | Auto and against the frontier model for everything, net of failed | |
| 1561 | attempts, with cost per merged change; `--live` reads billing's runs and | |
| 1562 | counted tokens. On the bundled sample (13 tasks, assumed failures): Auto | |
| 1563 | costs 7% less than the frontier model for everything and about 7% more | |
| 1564 | per run than routing before it, but half as much per merged change, | |
| 1565 | because it finishes the hard tasks the old routing gave up on. At | |
| 1566 | current prices Opus 5.5 and Sonnet 5.5 cost the same per cache read, and | |
| 1567 | cache reads are most of an agent run's tokens, so moving off the | |
| 1568 | frontier model saves less than its list price suggests; the fast tier | |
| 1569 | and fewer failed attempts are where the money is. Run `--live` monthly | |
| 1570 | and after any routing change. | |
| 1571 | - **A cheaper route for the simplest jobs (designed, off).** A fourth tier | |
| 1572 | on Workers AI through AI Gateway (an open model, billed on Cloudflare's | |
| 1573 | invoice) for classification-sized jobs: commit messages, triage, | |
| 1574 | summaries. Behind the same router as a tier with its own catalogue entry | |
| 1575 | and `tasks` rules, off by default. It needs the proxy to translate the | |
| 1576 | harness's Anthropic requests to the gateway's OpenAI-compatible | |
| 1577 | endpoint (it already does for workspaces' own OpenAI-shaped providers) | |
| 1578 | and a quality bar from the savings harness before any job moves to it. | |
| 1579 | ||
| Initial g1t: services, event bus, intents and attempts | 1580 | ### Choosing the right agent automatically |
| 1581 | ||
| Issues and pull requests replace intents and attempts | 1582 | Because several agents can work on the same issue, every issue with more |
| 1583 | than one pull request is an evaluation on real work. g1t records, per repo and per kind of issue, each | |
| Initial g1t: services, event bus, intents and attempts | 1584 | agent's win rate, cost and time. That produces a leaderboard, and a routing |
| Issues and pull requests replace intents and attempts | 1585 | policy: send each new issue to the agent that wins that kind most often, |
| Initial g1t: services, event bus, intents and attempts | 1586 | start with the cheapest that is good enough, and escalate to a stronger one |
| 1587 | when checks fail. | |
| 1588 | ||
| Plan: the inbox, then channels and apps, instead of discussions | 1589 | ## Talking: the inbox and channels |
| 1590 | ||
| 1591 | Not a discussions forum. People and agents need one place to talk in real | |
| 1592 | time, and an app that feels like one on desktop and phone. | |
| 1593 | ||
| 1594 | **The inbox comes first.** Everything that needs a person or that they | |
| 1595 | follow, from people and agents: review requests, agent questions and | |
| 1596 | handoffs, failures, mentions, deploys. Read and unread, saved, done, | |
| 1597 | snoozed; ranked so what an agent is blocked on comes first; email digests | |
| 1598 | and push. It is the delivery layer chat needs too (who is told what, read | |
| 1599 | state, push), so building it first makes channels cheap. | |
| 1600 | ||
| Docs: inbox threads, reasons, subscriptions, watching, email, API and MCP | 1601 | *Built:* the events service keeps it (`services/events/src/inbox.rs` and |
| 1602 | `subscriptions.rs`, migrations `0005_inbox` and `0006_inbox_threads` on the | |
| 1603 | `g1t-events` database), writing items as events arrive from the bus; work's | |
| 1604 | `inbox_subject` says what each event names. Each person has one **thread** | |
| 1605 | per issue, pull request, workflow on a branch or deployment: new activity | |
| 1606 | brings it back unread with a count and its last 10 activities, and while it | |
| 1607 | is unread its most urgent severity is kept. Each item has a **reason** | |
| 1608 | (`agent`, `review_requested`, `assign`, `mention`, `ci_activity`, | |
| 1609 | `security_alert`, `state_change`, `author`, `comment`, `manual`, | |
| 1610 | `subscribed`). Who is told: `agent.asked` and `pull.stalled` (needs you, | |
| 1611 | closed again by `pull.resumed` and the like), `pull.review_requested` | |
| 1612 | (needs you, closed by `pull.review_request_removed`), | |
| 1613 | `issue.assigned`/`pull.assigned`, failed checks and workflows, | |
| 1614 | `deployment.failed` and a recovering `deployment.succeeded`, g1t's reviews | |
| 1615 | and finished changes, closes, reopens and merges to everyone subscribed, | |
| 1616 | and comments to the people mentioned and everyone subscribed. Never the | |
| 1617 | actor, never g1t. **Subscriptions**: authors, assignees and reviewers are | |
| 1618 | subscribed without a row; commenting or being mentioned subscribes; anyone | |
| 1619 | can subscribe, unsubscribe (still told of what is asked of them) or ignore. | |
| 1620 | **Watching** a repository: participating (the default), all, ignore, or | |
| 1621 | custom (issues, pulls, deployments, security); whoever creates a repository | |
| 1622 | watches it at their default, all activity unless they change it. | |
| 1623 | **Settings**: which reasons are also emailed (agent, review_requested and | |
| 1624 | mention by default) and the default watch for new repositories; email goes | |
| 1625 | through identity's `notify_by_email`, to a confirmed address only while the | |
| 1626 | person can still read the repository. **REST and MCP**: 14 operations under | |
| 1627 | `/notifications`, `/repos/:owner/:name/subscription` and | |
| 1628 | `/user/subscriptions` (scopes `notifications:read` and | |
| 1629 | `notifications:write`, in the Agent preset), and the `notifications` MCP | |
| 1630 | tool; never usable by g1t's own tokens. On the site: a bell in the top bar | |
| 1631 | opening a sheet with tabs (All, Needs you, Errors, Success, Info), Done, | |
| 1632 | Save, Snooze and Mark all read; `/inbox` with Saved, Done and a reason | |
| 1633 | filter; reasons and update counts on each card; a Notifications box on | |
| 1634 | issue and pull request pages; a Watch menu in the repository header; | |
| Previews build from any branch; Agent in place of Ask AI; pin from the sidebar | 1635 | Settings → Notifications; a Needs you card on mission control. Agent sits |
| Docs: inbox threads, reasons, subscriptions, watching, email, API and MCP | 1636 | beside the bell, disabled. Still to come: security alerts (the security |
| Previews build from any branch; Agent in place of Ask AI; pin from the sidebar | 1637 | service publishes no event yet), email digests and push, Agent, and |
| Docs: inbox threads, reasons, subscriptions, watching, email, API and MCP | 1638 | channels. |
| Docs: the inbox, what lands in it and why, its tabs and actions | 1639 | |
| Plan: the inbox, then channels and apps, instead of discussions | 1640 | **Channels** (working name): workspace channels, direct messages and |
| 1641 | threads, live. | |
| 1642 | ||
| 1643 | - Each channel is a Durable Object holding its WebSocket connections with | |
| 1644 | hibernation, so idle channels cost nothing; history in D1, files in R2. | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 1645 | - Agents are members. `@g1t` in a channel starts work, answers, or |
| Plan: the inbox, then channels and apps, instead of discussions | 1646 | posts a summary; agents post their questions and handoffs where people |
| 1647 | already are. A thread becomes an issue or an outcome in one action, and | |
| 1648 | the agent's progress streams into that thread. | |
| 1649 | - Tied to the work: issues, pull requests, runs and deploys each have a | |
| 1650 | thread; links unfurl into live cards (checks, agent step, preview). | |
| 1651 | What a channel settles can become workspace memory, with its source. | |
| 1652 | - Apps: an installable PWA first (desktop and mobile, offline shell, Web | |
| 1653 | Push), then native shells on the same API: Tauri for desktop (tray, | |
| 1654 | deep links), React Native for iOS and Android (background | |
| 1655 | notifications). | |
| 1656 | ||
| 1657 | GitHub-style Discussions are not planned: channels and threads on the | |
| 1658 | work replace them. | |
| 1659 | ||
| Initial g1t: services, event bus, intents and attempts | 1660 | ## What GitHub ships today, and where g1t differs |
| 1661 | ||
| 1662 | GitHub's Agent HQ and Copilot app give each agent session its own git | |
| 1663 | worktree and branch, list sessions in a mission-control view grouped by | |
| 1664 | project, and let a task be assigned to several agents so their output can be | |
| 1665 | compared. Underneath, the unit of work is still a branch and a pull request. | |
| 1666 | ||
| 1667 | | | GitHub | g1t | | |
| 1668 | | --- | --- | --- | | |
| 1669 | | Where a session works | A worktree on one developer's machine, or a cloud sandbox | A server-side fork that any agent on any machine can join and anyone can open | | |
| 1670 | | Agent context | Lives in the app's session view | Stored with the repository and linked from each commit (why-blame) | | |
| Issues and pull requests replace intents and attempts | 1671 | | Several agents on one task | Separate pull requests to compare by hand | One issue holding every pull request made for it, compared side by side, with the merged one recorded on the issue | |
| Initial g1t: services, event bus, intents and attempts | 1672 | | Collisions between agents | Found as merge conflicts at the end | Flagged during the work (overlap radar) | |
| Issues and pull requests replace intents and attempts | 1673 | | Landing changes | One pull request at a time | A merge queue that lands the chosen one and closes the rest as superseded | |
| Initial g1t: services, event bus, intents and attempts | 1674 | | Which agents | Those offered through a Copilot subscription | Any MCP client, plus hosted agents | |
| 1675 | ||
| 1676 | ## How agents connect | |
| 1677 | ||
| 1678 | 1. **Bring your own agent.** A remote MCP server at `mcp.g1t.sh` lets Claude | |
| Issues and pull requests replace intents and attempts | 1679 | Code (or any MCP client) list issues, claim one, get a clone URL and |
| Initial g1t: services, event bus, intents and attempts | 1680 | token, report progress and submit. Adding it is one command; sign-in is a |
| 1681 | browser OAuth flow with no token to paste. The `g1t` CLI installs Claude | |
| 1682 | Code hooks that upload the session transcript as the agent works. | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 1683 | 2. **g1t's agent.** Assign an issue to g1t, or many issues at |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1684 | once, each to an agent of its own. g1t starts a sandbox for each |
| 1685 | (Cloudflare Containers), running a coding agent headless against its | |
| 1686 | own pull request and fork. | |
| Initial g1t: services, event bus, intents and attempts | 1687 | 3. **API and CLI.** Everything above is available at `api.g1t.sh` and |
| 1688 | through `g1t`. | |
| 1689 | ||
| 1690 | ## Public surfaces | |
| 1691 | ||
| 1692 | | Host | What it serves | | |
| 1693 | | --- | --- | | |
| 1694 | | `g1t.sh` | The site, git over HTTPS, git over SSH | | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1695 | | `api.g1t.sh` | REST API, with no version in its paths, with a published OpenAPI document, cursor pagination, rate-limit headers, idempotency keys on writes, server-sent events for live pull request state, and signed webhooks | |
| Initial g1t: services, event bus, intents and attempts | 1696 | | `mcp.g1t.sh` | Remote MCP server over streamable HTTP | |
| 1697 | ||
| 1698 | g1t is its own OAuth 2.1 authorization server: authorization code with PKCE, | |
| OAuth 2.1 sign-in for MCP clients and other applications | 1699 | dynamic client registration that stores nothing (a client id encodes its |
| 1700 | own registration, so the open endpoint cannot be used to fill a database), | |
| 1701 | discovery metadata and rotating refresh tokens. Still to come: scopes | |
| Issues and pull requests replace intents and attempts | 1702 | per resource (`repo:read`, `repo:write`, `issue:write`, `pull:write`). |
| Initial g1t: services, event bus, intents and attempts | 1703 | MCP clients, the CLI (device flow) and third-party apps all use it. Access |
| 1704 | tokens and SSH keys remain for git itself. | |
| 1705 | ||
| Merge branch 'worktree-agent-a8385d293d42c913a' | 1706 | ### Workspace aliases (internal, built 2026-10-07) |
| 1707 | ||
| 1708 | `g1t` is the product; `flagon-io` is Flagon, Inc., the organization that | |
| 1709 | builds it. So nobody mistakes one for the other, `g1t.sh/g1t` leads to | |
| 1710 | `g1t.sh/flagon-io`. That is a workspace alias: a name g1t's staff point at | |
| 1711 | a workspace, kept in identity's `workspace_aliases` (migration 0029, which | |
| 1712 | seeds `g1t`) by the workspace's id, so it follows renames. It is not a | |
| 1713 | customer feature and is not documented for users; staff add and remove | |
| 1714 | aliases on sudo's Aliases page, with a reason, in sudo's audit log. We may | |
| 1715 | give other companies one for a trading name the same way. | |
| 1716 | ||
| 1717 | An alias is resolved wherever an old slug is (identity's `resolve_slug`), | |
| 1718 | so it costs only the not-found path: site pages 301 to the same page under | |
| 1719 | the workspace, the API and MCP run the call again under its slug, package | |
| 1720 | registries 301, and git over HTTPS is answered in place | |
| 1721 | (`resolve_alias`), because pushes do not follow redirects. An alias is | |
| 1722 | never a route, a username or a workspace's slug, and nobody can register | |
| 1723 | it while it exists. `@g1t` stays g1t's agent: mentions link to how the | |
| 1724 | agent works, never to `/g1t`. | |
| 1725 | ||
| Initial g1t: services, event bus, intents and attempts | 1726 | ## Architecture |
| 1727 | ||
| 1728 | | Component | Language | Runs on | Responsibility | | |
| 1729 | | --- | --- | --- | --- | | |
| Issues and pull requests replace intents and attempts | 1730 | | `crates/contracts`, `packages/contracts` | Rust, TypeScript | — | The interface of every service, the event catalogue, shared types. Services and clients depend on this, never on each other's code. | |
| OAuth 2.1 sign-in for MCP clients and other applications | 1731 | | `services/identity` | Rust | Worker + D1 | Accounts, workspaces and memberships, sessions, SSH keys, access tokens, device sign-in, OAuth codes and grants | |
| Issues and pull requests replace intents and attempts | 1732 | | `services/repos` | Rust | Worker + D1 + Artifacts | Repository registry, contents, forks, diffs, landing, git over HTTPS. Storage sits behind a `GitStore` port with an Artifacts adapter. | |
| 1733 | | `services/work` | Rust | Worker + D1 | Issues, pull requests, comments, sessions; later a Durable Object per repo for the landing queue and live state | | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1734 | | `services/billing` | Rust | Worker + D1 + Stripe | Each workspace's agent credit: payments, the ledger of every run, and the gate on starting one | |
| Events service in Rust, with RFC 3339 times and accurate push events | 1735 | | `services/events` | Rust | Worker + Queues + D1 | The event bus: durable log, and one queue per subscribing service | |
| g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent | 1736 | | `services/runner`, `crates/runner` | TypeScript, Rust | Worker + Containers | Starts a sandbox per g1t run; the program inside runs the agent harness and reports through the public API | |
| Social cards for every page: og.g1t.sh | 1737 | | `services/og` | TypeScript | Worker + Cache API | Social cards at `og.g1t.sh`: one PNG per page of the site and the docs (satori and resvg), looked up as an anonymous visitor, so nothing private appears on one | |
| Initial g1t: services, event bus, intents and attempts | 1738 | | `apps/web` | TypeScript | Worker | Server-rendered site. Holds no data; calls services over RPC. | |
| Issues and pull requests replace intents and attempts | 1739 | | `apps/docs` | TypeScript | Worker (static) | Documentation and the API explorer | |
| API and MCP server in Rust; a public index at the API root | 1740 | | `apps/api` | Rust | Worker | REST API (`api.g1t.sh`), MCP server (`mcp.g1t.sh`) and OpenAPI document, all generated from one list of operations; the OAuth endpoints | |
| Initial g1t: services, event bus, intents and attempts | 1741 | | `crates/sshd` | Rust | Container | Git over SSH, bridged to Artifacts | |
| 1742 | | `crates/merged` | Rust | Container | Trial merges, conflict matrix, landing merges (needs real git; the Artifacts binding is read-only) | | |
| 1743 | | `crates/core` | Rust | native and WASM | pkt-line, packfile and diff code shared by the above and by the Worker | | |
| Issues and pull requests replace intents and attempts | 1744 | | `crates/g1t` | Rust | user's machine | CLI: auth, SSH proxy, Claude Code hooks, issues and pull requests | |
| Initial g1t: services, event bus, intents and attempts | 1745 | |
| Issues and pull requests replace intents and attempts | 1746 | Storage: Artifacts for repositories (one fork per pull request), D1 for accounts |
| Initial g1t: services, event bus, intents and attempts | 1747 | and metadata, R2 for session transcripts and logs, Durable Object SQLite for |
| 1748 | per-repo coordination state. | |
| 1749 | ||
| 1750 | How the services fit together: | |
| 1751 | ||
| 1752 | - **Each service is its own Worker with its own database.** It deploys, | |
| 1753 | scales and fails on its own. Callers reach it through a typed RPC binding | |
| 1754 | to the interface in `packages/contracts`. | |
| 1755 | - **Expected failures are values.** Every call returns a `Result`, so "not | |
| 1756 | found" or "forbidden" crosses a service boundary as data. | |
| 1757 | - **Side effects travel as events.** A service publishes what happened | |
| Issues and pull requests replace intents and attempts | 1758 | (`git.push`, `issue.opened`, `pull.merged`, …) to the bus and does not |
| Initial g1t: services, event bus, intents and attempts | 1759 | call other services to react. Each subscriber consumes from its own queue. |
| 1760 | Timelines, webhooks and automations read the same stream, which is what | |
| 1761 | lets something like GitHub Actions be built on top. | |
| 1762 | - **Every read takes the viewer.** Authorization is decided inside the | |
| 1763 | service that owns the data, not by its callers. | |
| 1764 | ||
| 1765 | The Workers runtime scales request handling on its own, so the edge layer | |
| 1766 | stays in TypeScript. Rust is used where there is real computation or a real | |
| 1767 | protocol to implement. | |
| 1768 | ||
| API and MCP server, Rust identity service, registration, site redesign | 1769 | ## Languages |
| 1770 | ||
| 1771 | The site is TypeScript. Everything behind it is Rust, compiled to | |
| API and MCP server in Rust; a public index at the API root | 1772 | WebAssembly for Workers and natively for containers and the CLI. Identity, repos, work, events and the API are all Rust. The one exception |
| 1773 | is the Worker that starts sandboxes, because Cloudflare's Containers | |
| 1774 | library is TypeScript. Rust services speak a | |
| API and MCP server, Rust identity service, registration, site redesign | 1775 | small JSON protocol over service bindings (`POST /rpc/<method>`), with the |
| 1776 | types in `crates/contracts`. | |
| 1777 | ||
| 1778 | ## Identifiers | |
| 1779 | ||
| 1780 | Every id is a [TypeID](https://github.com/jetify-com/typeid): a prefix naming | |
| 1781 | the kind of thing, then a UUIDv7 in lowercase base32, such as | |
| Issues and pull requests replace intents and attempts | 1782 | `pr_01jb2k7x9hfq0b3zj0f5s2m8ra`. |
| API and MCP server, Rust identity service, registration, site redesign | 1783 | |
| 1784 | - The prefix makes an id self-describing and stops ids of different kinds | |
| 1785 | being mixed up. | |
| 1786 | - Ids sort by creation time as plain strings. In SQLite (D1 and Durable | |
| 1787 | Objects) that keeps inserts at the end of the primary-key index instead of | |
| 1788 | scattering them, and gives time-ordered paging for free. | |
| 1789 | - The suffix decodes to a standard UUIDv7 for any system that wants one. | |
| 1790 | - Ids are made by the service that creates the record, not by the database, | |
| 1791 | so they work across services and can be assigned before a write. | |
| 1792 | ||
| 1793 | ## Events at scale, and audit | |
| 1794 | ||
| 1795 | The current event log is a single D1 database. That is fine for a | |
| 1796 | prototype and wrong for the target: D1 is one writer and 10 GB. The design | |
| 1797 | for volume splits storage by how the data is read. | |
| 1798 | ||
| 1799 | | Tier | Store | Holds | Read by | | |
| 1800 | | --- | --- | --- | --- | | |
| 1801 | | Hot | A Durable Object per repository, with SQLite | Recent events for that repo | Timelines, live pages over WebSocket | | |
| 1802 | | Complete | Cloudflare Pipelines into R2 as Apache Iceberg | Every event, forever, partitioned by day and workspace | Analytics, standups, "ask", export | | |
| 1803 | | Audit | The same R2 store, under object lock | Who did what, from where, with which credential | Compliance, investigation | | |
| 1804 | ||
| 1805 | - **No single hot database.** Each repository's recent events live with that | |
| 1806 | repository, so load spreads across as many objects as there are repos. | |
| 1807 | - **The complete record is files, not rows.** Iceberg on R2 has no practical | |
| 1808 | size limit and is queried with SQL. | |
| 1809 | - **Audit is a property of every event.** The envelope carries the actor | |
| 1810 | (person, agent, token or system), the credential used, the request id and | |
| 1811 | the source address. Audit entries for a workspace are hash-chained, so a | |
| 1812 | removed or altered entry is detectable, and are written under a retention | |
| 1813 | lock. | |
| 1814 | - **Delivery is at least once.** Consumers are idempotent on the event id. | |
| 1815 | ||
| Initial g1t: services, event bus, intents and attempts | 1816 | ## Accounts and forge basics |
| 1817 | ||
| 1818 | - Registration with email verification, sign-in, forgot password (Cloudflare | |
| 1819 | Email Sending), Turnstile on public forms. | |
| 1820 | - GitHub sign-in, SSH keys, access tokens, active sessions. | |
| 1821 | - Profiles, public and private repositories, repository search (D1 full-text). | |
| 1822 | - Rendered README, syntax highlighting, commit history, diffs. | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 1823 | - Transferring a repository between workspaces (by id: its git store key |
| 1824 | never moves; every service follows `repo.transferred`; old paths redirect | |
| 1825 | until reused) and deleting an empty, settled workspace (its slug is | |
| 1826 | tombstoned, never reissued except to the person whose username it is). | |
| Merge main (membership, two-factor, GitHub repo roles) into tokens | 1827 | - Access: five repository roles (Read, Triage, Write, Maintain, Admin; |
| 1828 | the capability table follows GitHub's repository roles, 2026-10-08: | |
| 1829 | branch protection and rulesets are Admin, labels and milestones are made | |
| 1830 | with Write and applied with Triage, security alerts are Write), a | |
| 1831 | workspace base permission (Read for new workspaces), the creator of a | |
| 1832 | repository given Admin on it, outside collaborators and invitations. | |
| 1833 | Membership as GitHub's organizations have it (2026-10-08): owners and | |
| 1834 | members, promote and demote, transfer ownership, leave, a last-owner | |
| 1835 | guard; billing manager and security manager on top of member; member | |
| 1836 | privileges (who creates public and private repositories, whether | |
| 1837 | repository admins change visibility, delete and transfer, and invite | |
| 1838 | outside collaborators); two-factor authentication (TOTP and recovery | |
| 1839 | codes) and a workspace policy that requires it, holding non-compliant | |
| 1840 | people out until they turn it on. Every membership change, token, SSH | |
| 1841 | key, OAuth grant and two-factor change is in the audit log. Teams are built on it (2026-10-07): visible | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 1842 | or secret, nested up to 8 levels (child teams inherit their parents' |
| 1843 | roles), run by maintainers and owners. A team's role on a repository is a | |
| 1844 | `repo_grants` row whose principal is the team, which identity resolves | |
| 1845 | into the same `RepoGrant`s on each person, so `access::can` needs nothing | |
| 1846 | new: the highest role wins. `@workspace/team` mentions tell the team's | |
| 1847 | people; a team asked to review either asks everyone or picks people by | |
| 1848 | round robin or load balance. | |
| 1849 | - CODEOWNERS, read in both conventions (single-section, and sections with | |
| 1850 | approval counts, optional sections and default owners) from the first of | |
| 1851 | `.g1t/`, `.github/`, the root, `docs/` and `.gitlab/`. Owners are asked to | |
| 1852 | review, the `g1t / codeowners` status lints a changed file, and branch | |
| 1853 | protection's "Require review from code owners" holds merges, for people, | |
| 1854 | agents and the queue alike, until each owning rule is approved. | |
| Initial g1t: services, event bus, intents and attempts | 1855 | |
| 1856 | ## Built on Cloudflare | |
| 1857 | ||
| 1858 | | Need | Product | | |
| 1859 | | --- | --- | | |
| Issues and pull requests replace intents and attempts | 1860 | | Repositories; a fork per pull request; data residency per workspace | Artifacts (forks, jurisdictions) | |
| Initial g1t: services, event bus, intents and attempts | 1861 | | Reacting to pushes | Artifacts event subscriptions on Queues | |
| Plan: a repository that maintains itself, and deployments on g1t.page | 1862 | | Preview URL per pull request; deploy on merge | Workers for Platforms on `g1t.page` | |
| Initial g1t: services, event bus, intents and attempts | 1863 | | Site, API, MCP, git front end | Workers | |
| 1864 | | Per-repo coordination, live updates | Durable Objects | | |
| Issues and pull requests replace intents and attempts | 1865 | | Pull request lifecycles, automations | Workflows, Cron Triggers | |
| Initial g1t: services, event bus, intents and attempts | 1866 | | Agent sandboxes, SSH server, merge engine | Sandbox SDK and Containers | |
| 1867 | | Fast starts on large repos | ArtifactFS | | |
| 1868 | | Model traffic, spend, budgets | AI Gateway | | |
| 1869 | | Summaries, embeddings | Workers AI | | |
| 1870 | | Context hub search | Vectorize | | |
| 1871 | | Accounts and metadata | D1 | | |
| 1872 | | Transcripts and logs | R2 | | |
| 1873 | | Email, bot protection, keys | Email Sending, Turnstile, Secrets Store | | |
| 1874 | ||
| Running g1t yourself: the design, a docker compose proof, and a guide to what works today | 1875 | ## Running g1t yourself |
| 1876 | ||
| 1877 | g1t.sh runs on Cloudflare, and that does not change. The core is MIT and | |
| 1878 | must also run on anyone's own machine with `docker compose up`. A free | |
| 1879 | core people can self-host is what makes paid hosting worth trusting. | |
| 1880 | Self-hosting never makes hosted worse: hosted code paths keep their | |
| 1881 | behaviour, and a self-hosted adapter sits beside the hosted one. The | |
| 1882 | inventory of every Cloudflare dependency, the design and the risks are in | |
| 1883 | [SELF_HOSTING.md](SELF_HOSTING.md). | |
| 1884 | ||
| 1885 | The approach: the Workers stay Workers, and self-hosted they run in | |
| 1886 | workerd, the open-source Workers runtime. D1, KV and Queues are SQLite on a | |
| 1887 | volume, with the same migrations. Cloudflare-only bindings are replaced | |
| 1888 | by stand-ins: | |
| 1889 | ||
| 1890 | - Artifacts becomes bare repositories served by `git http-backend`; | |
| 1891 | - Email Sending becomes SMTP, through Mailpit; | |
| 1892 | - services that are off answer "off" instead of failing. | |
| 1893 | ||
| 1894 | | Phase | Scope | Estimate | | |
| 1895 | | --- | --- | --- | | |
| 1896 | | 1. Core forge | Done: `deploy/self-host/` (compose, git store, binding stand-ins, smoke test) and the "Run g1t yourself" guide. Left: the API on its own port, `PUBLIC_URL` in place of hard-coded hosts, cron, pull requests in the smoke test, CI that runs it. | 1–1.5 weeks left | | |
| 1897 | | 2. Agents | Docker sandboxes with the same runner image, an egress allow-list proxy for guardrails, `g1t.toml`, a launcher in place of `wrangler dev` | 2–3 weeks | | |
| 1898 | | 3. Search, context, deployments | sqlite-vec plus an OpenAI-compatible embedder; an app host on workerd; Caddy for app and custom domains; SSH | 3–4 weeks | | |
| 1899 | | 4. Parity and upgrades | Code-level ports in `g1t_kit` and `@g1t/platform`, sudo without Access, online backups, released images, an upgrade test in CI | 3–4 weeks | | |
| 1900 | ||
| Initial g1t: services, event bus, intents and attempts | 1901 | ## The submission |
| 1902 | ||
| 1903 | - **g1t is built on g1t.** This repository is hosted on g1t.sh, its features | |
| Issues and pull requests replace intents and attempts | 1904 | are opened as issues and built by racing agents, and it deploys from |
| Initial g1t: services, event bus, intents and attempts | 1905 | Artifacts through Workers Builds. The history is the proof. |
| Issues and pull requests replace intents and attempts | 1906 | - **The demo follows one story.** A brief becomes a project; twelve issues |
| Initial g1t: services, event bus, intents and attempts | 1907 | fan out to dozens of agents; agents notice each other, hand off, and |
| 1908 | resolve a conflict; reviewers triage; the queue lands everything on | |
| 1909 | `main`; why-blame explains a line; the portfolio shows where it all | |
| 1910 | stands. Then the same thing at a thousand agents. | |
| 1911 | - **Judges can try it in a minute.** Open registration on g1t.sh, one-click | |
| 1912 | import of a GitHub repo, one command to connect Claude Code, a seeded demo | |
| 1913 | workspace, and a single deploy command for running their own copy. | |
| 1914 | - **The formats are open.** The commit trailers, session format and runner | |
| 1915 | contract are published so other tools can interoperate. | |
| 1916 | ||
| 1917 | ## Build order | |
| 1918 | ||
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1919 | What is left is ordered by how much it shows the point above, not by forge |
| 1920 | parity. Forge basics are done well enough; each item below should make the | |
| 1921 | demo's story stronger. | |
| 1922 | ||
| Plan: what is done from the agent-first list, and what is next | 1923 | Done from this list: the outcome page (a plan's issues as a live graph with |
| 1924 | cost and a feed of what happened), coordination you can see (agents' issues | |
| 1925 | and comments stand out in the feed; agents hold g1t's tools through a token | |
| 1926 | scoped to one repository), steering a running agent (messages delivered | |
| 1927 | between steps, and at the end), and recording sessions from anyone's own | |
| Plan: integrations are in | 1928 | Claude Code (`curl -fsSL https://g1t.sh/install/claude.sh | sh`). Integrations are |
| 1929 | in: a workspace's own model provider (Anthropic or any Anthropic-compatible | |
| Prices are what g1t pays plus 20%, from the first second | 1930 | endpoint, reached through a model proxy so no sandbox holds a key; its |
| 1931 | runs pay only their sandbox time), alerts from Sentry, Datadog and signed webhooks | |
| Plan: integrations are in | 1932 | that open one issue per problem and can start an agent, and Jira and Linear |
| 1933 | tickets that agents read, people import, and that hear back. Racing a | |
| Plan: what is done from the agent-first list, and what is next | 1934 | set number of agents on one issue is dropped: choosing how many agents to |
| 1935 | use is not something people should have to do. | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1936 | |
| Agents asked while not at work are woken to answer | 1937 | 1. ~~**Handoffs and questions between agents** as states on the outcome |
| 1938 | page.~~ Done: questions and handoffs show as waiting, read, answered, | |
| 1939 | taken on or declined; since 2026-10-03 an agent asked while it is not at | |
| 1940 | work is woken to answer, where before the question waited forever. | |
| Plan: a repository that maintains itself, and deployments on g1t.page | 1941 | 2. **Upkeep agents** (above): dependency updates, secret scanning, |
| 1942 | vulnerability alerts, code scanning, the security page. No new | |
| 1943 | infrastructure. | |
| 1944 | 3. **Deployments on `g1t.page`** (above): previews per pull request, | |
| 1945 | production on merge, the reviewer agent checking the preview. | |
| 1946 | 4. **The large run, building 2 and 3.** About 20–30 issues on g1t itself, | |
| 1947 | built by agents and landed through the queue, for the video: g1t built | |
| 1948 | on g1t. | |
| 1949 | 5. **Polish for judges trying it in a minute:** a seeded demo workspace, the | |
| Plan: what is done from the agent-first list, and what is next | 1950 | empty states, and the first-run path from sign-up to an outcome landing. |
| Initial g1t: services, event bus, intents and attempts | 1951 | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1952 | Earlier items still open, after those: |
| 1953 | ||
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 1954 | 1. Deleting a branch once its pull request merges; risk tiers. (Approval |
| 1955 | rules per path are in, as CODEOWNERS.) | |
| Merge main (membership, two-factor, GitHub repo roles) into tokens | 1956 | 2. Event storage per the design above: per-repo hot log, Iceberg on R2, |
| API and MCP server in Rust; a public index at the API root | 1957 | hash-chained audit. |
| Merge main (membership, two-factor, GitHub repo roles) into tokens | 1958 | 3. CLI with Claude Code hooks to record sessions automatically. |
| 1959 | 4. Reviewing and catching up automatically, by policy; required reviews; | |
| Agents as a team: lifecycle, merge queue, billing and a new shell | 1960 | risk tiers. |
| Merge main (membership, two-factor, GitHub repo roles) into tokens | 1961 | 5. Compare view, proof bundles; handoff between agents. |
| 1962 | 6. Projects, mission control, steering; why-blame, digest, timeline. | |
| 1963 | 7. Context hub, portfolio; automations and integrations (Sentry first). | |
| 1964 | 8. SSH; bot protection; own keys, endpoints and runners. | |
| 1965 | 9. Large run (100+ agents across many issues), hardening, demo. | |
| 1966 | 10. Passkeys (WebAuthn) as a second factor and for signing in: feasible on | |
| 1967 | Workers (P-256 and RS256 verification in Rust, or WebCrypto), next | |
| 1968 | after TOTP. Then fine-grained tokens, deploy keys and package access. | |
| Initial g1t: services, event bus, intents and attempts | 1969 | |
| Merge main (membership, two-factor, GitHub repo roles) into tokens | 1970 | Later: code search, mirroring to GitHub, SSH |
| Initial g1t: services, event bus, intents and attempts | 1971 | on port 22 without the CLI proxy (needs the Workers inbound TCP private |
| 1972 | beta). |
This file's history is long; its oldest lines are credited to the oldest commit read.