# We merge about a thousand pull requests a week, and our CI and hosting bills went down

Published: 2026-10-11
Source: https://groupthink.com/releases/solo-ai-company-ops/

![Bar chart of GitHub Actions cost per merged pull request: $0.99 on Oct 3, $0.65 on Oct 6, $0.39 on Oct 9.](https://wp1.groupthink.com/wp-content/uploads/2026/10/solo-ai-company-ops-featured.png)

Video: https://wp1.groupthink.com/wp-content/uploads/2026/10/solo-ai-company-ops-explainer.mp4

I run Groupthink mostly by myself. I don’t write much of the code by hand anymore. Claude Code sessions write it, review it, test it, release it, and draft the posts about it, around the clock, on three Macs at home and in my office. My job is deciding what to build and checking that it works.

Last week the company merged 1,028 pull requests. The first week of July it merged 56. That count includes release and docs pull requests, so read it as activity, not value. Over the same stretch, our GitHub Actions bill went from about $330 a day to about $31, and our hosting bill fell by two thirds.

This post recaps what we shipped and what is waiting to launch. Then it walks through how the whole thing runs, for any other solo founder trying to build a company this way, including the parts that broke.

## What we launched since August

Groupthink is a memory for the people in your life and work. Since August we’ve published [Voice Dictation](https://groupthink.com/releases/voice-dictation/) on the Mac, [calendar sync and booking links](https://groupthink.com/releases/calendar-sync-and-booking-links/), a better way to [log interactions](https://groupthink.com/releases/logging-interactions/), [full export and a GitHub repo you own](https://groupthink.com/releases/export-and-repo-sync/), and a [Going Cold list](https://groupthink.com/releases/going-cold-own-rhythm/) that measures each person against your usual rhythm with them. The [roundup](https://groupthink.com/releases/roundup-aug-sep-2026/) has the smaller things: Today in day, week and month views, meeting facts that link back to the meeting, a year of calendar history on day one, and AI assistants that can read from and add to your record.

## The backlog, and why we hold launches

Shipping code is now the easy part. Today there are 17 open launch issues in our marketing repo. Each one is a feature that was built and released. One already has its post. One, texting Groupthink, isn’t open to anyone outside the company yet. About ten of the rest are live in production and waiting on one thing: someone seeing them work.

That is a rule I set on October 5. A feature launches when someone has watched it work in production, and not before. Released isn’t the same as working. One feature, offering a person named in your note as a new contact, shipped before the AI call behind it had ever run against the real model. The tests passed. Nobody had seen it do the thing.

When agents write the code, the bottleneck moves to checking it. So I batch my checks. The agents keep one list of everything that needs human eyes, and this week I work through it in one block on Monday morning.

## How it runs

### 1. The machines, and what each one does

There are three Macs.

- A MacBook Pro runs every Claude Code session that does work. We call these long-running sessions cranks.
- A Mac mini (M4 Pro, 14 cores, 64 GB) runs our CI jobs and nothing else.
- My office desktop, an older M1, is my working machine. When I’m not using it, it takes CI jobs too.

It didn’t start this way. For a few days the Mini ran both the cranks and the CI jobs. It was overloaded: its average load was 37 on 14 cores. On October 10 we moved every crank to the laptop and left the Mini to CI. Give each machine one job.

### 2. Cranks: written rules, lanes and heartbeats

A crank is a Claude Code session that never closes. Every two hours it wakes up, reads its instructions, does one round of work, and goes quiet. The first one started on August 28. There are eight on the roster now, each with its own lane: building features, fixing bugs, help docs, marketing and launches, checking each release after it deploys, paid ads, walking through signup as a new user, and the daily health check.

Each crank’s instructions are a markdown file in a repo. To change how a crank behaves, I edit the file. Every rule in those files says why it exists and what happened that made us write it. A rule with no reason is hard to follow well and impossible to retire, because nobody can tell when it stops being true.

Most of the rules came from something going wrong. On its first night, the build crank merged four pull requests that a planning doc had set aside for me to decide. They were green and the code looked fine. Now the crank reads those docs before it merges anything. Another night, one session filed an issue about an outage, and a crank filed a second issue about the same outage five minutes later and pushed it to my phone while I was traveling. Now a crank searches for an existing issue before it escalates, especially when the problem feels urgent.

Sessions can message each other directly, across machines too, through Claude Code’s Remote Control. That’s how the cranks on the Mini handed their work to the laptop when we moved them. But a message disappears when a session ends, so anything that has to last goes through GitHub. Every crank posts a heartbeat comment on one shared GitHub issue when it runs. That issue has more than a thousand comments. Every two hours a script checks the heartbeats against the roster and tells me if a crank has gone quiet. Before that existed I had to remember which cranks should be running, and I didn’t. One evening the bug crank had been silent for ten hours before anyone noticed.

Two more pieces keep the cranks from colliding. Before a session starts on an issue, it claims it, and a claim expires after three hours if the session dies. And once a day, the first crank tick after 6am writes a re-plan issue: what changed yesterday, today’s build order, and at most three questions for me. Every crank reads it.

### 3. Home runners and the bill

At the start of October, our GitHub Actions bill was about $330 a day. We spent $889 in the first four days. The budget was set to stop every workflow when it ran out, which would have stopped tests, reviews and deploys at once. The warning emails were going to a mailbox nobody read.

Two changes fixed most of it. First, we made the test suite cheaper. It now runs in fewer, faster chunks and spends about 30% less time on tests, and we stopped running the full suite on every merge to the main development branch. That took daily spend to about $58. Second, we moved jobs onto our own machines. GitHub doesn’t charge for jobs that run on a runner you register yourself. The Mac jobs moved first, because GitHub’s Macs cost about ten times its Linux machines. Then parts of the test suite, which run in Linux machines inside the Mini. One slice took 1 minute 54 seconds on the Mini, against 3 to 4 minutes on GitHub.

Measured per merged pull request, our Actions cost was $0.99 on October 3, $0.65 on October 6, and $0.39 on October 9. This month we’ve spent $1,179 of a $2,000 budget, now at about $31 a day.

There was a second reason to do it. On October 5, GitHub’s hosted runners stopped taking jobs for over two hours. Our own runners would have kept going.

Hosting got the same kind of look. In September it averaged $223 a day. Much of that was one bug: a background job kept retrying calendar connections that had died, about $3,400 a month of work that did nothing. Fixing it and removing a database server nothing was reading from brought hosting to $71 a day.

There’s a cost line I didn’t have before, too. Every pull request gets an AI code review. On October 10 that was $102 across 171 review runs. Review plus CI came to $1.86 per merged pull request. Most of the review money went to iPhone pull requests that went five or six rounds, so now a pull request past round three only gets another round for a real bug.

### 4. What broke, and what I’d tell another solo founder

Know what your gauges actually measure. Overnight on October 10, a crank decided two of our runners had stalled, reading them as busy with no job. It moved all CI back to GitHub. They hadn’t stalled. The query it used doesn’t list a run as in progress while one of its jobs is running, so working runners looked idle. We switched them back on in the morning and wrote the right check into the docs.

Faster machines find different bugs. One test assumed a database query would take longer than a millisecond. On our home runners it didn’t, and the test failed. The machine was fine. The test was wrong.

A runner runs whatever a pull request tells it to. Every pull request’s code runs on that machine. Ours runs as its own account with access to nothing else on the machine.

Live on the server isn’t done. In one audit, 52 of 96 server changes that affected what the apps send or read had no matching work in the web or iPhone app. The feature existed and nobody could reach it. Now every server change has to say where it shows up for a user.

Your instructions file will grow until it stops working. Mine reached 9,540 words, and procedure outnumbered the rules about behavior about thirteen to one. The behavior rules were losing. We moved procedure into separate files that load only when a task needs them.

Plan for running out at the same moment. All the sessions share one account’s usage limit, so they hit it together. Three died mid-task one night. Each one could pick up where it left off, because the rules make every session leave a branch, a pull request or a claim behind it.

Spend your own time on checking. Agents produce more than one person can review line by line. I don’t try. I decide what gets built, I check that it works in production, and I decide when it launches.

Next for us is moving hosting off our current setup to something simpler to run, and launching the features waiting in that backlog, one check at a time.
