<- All posts

At 6:27 Every Morning, My Mac Studies a Competitor

Will Smith··9 min read

At 6:27 every morning, launchd wakes a headless Claude session on my Mac. It picks one competitor feature, spends the early hours using it inside my own logged-in Chrome, decides whether we should build our own version, sometimes builds it overnight on a branch, writes up what it found, and emails me a digest. Some mornings I wake up to a pull request. One morning I woke up to a log file that was 60 bytes long.

Some background. I run Usero, a user feedback tool, in a category with a lot of incumbents: Canny, Featurebase, Productboard, Savio, Sleekplan, Hotjar, PostHog and more. I used to study them the way everyone does, skimming pricing pages and changelogs and telling myself that counted. It doesn’t. The interesting facts about a competitor’s feature only show up when you use it: where the paywall sits, whether the marquee button works. That takes hours per feature, so I built a loop that spends those hours while I’m asleep.

It has fired 28 times since it went live on July 23. 19 mornings produced a digest. 9 were duds or failures. I want to write up how it works, and the failure log, because the failure log is the honest part.

The plumbing

The scheduler is a launchd job, label com.usero.competitor-loop, not cron, because if the Mac is asleep at 6:27, launchd runs the job on wake, and cron just skips it. The job invokes claude -p headless against a standing run prompt, writing stream-json logs I can dig through later. Those logs are how I know one dead morning left 60 bytes and another left 4.1MB. If the first model is out of credit it falls back to the next, Fable to Opus to Sonnet. It checks that Chrome is listening on its debugging port and skips the night if it isn’t, and it holds a mutex so the other scheduled loops don’t run over it. The 07:13 PM loop now blocks for up to 90 minutes waiting for the competitor process to finish. More on why later.

The deep-dive itself happens in my own logged-in Chrome, driven over the DevTools protocol. On July 23 I sat down and created 10 of the 11 competitor accounts by hand: real accounts, my name on them, free tiers, no payment details. The 11th was Beamer, whose signup froze for me as a human too, so the loop skipped it and studied AnnounceKit instead. No scraping, no terms-of-service games. The agent uses each product the way an evaluating customer would.

Running in my own Chrome instead of a fresh headless browser buys two things. The sessions are real, so the agent lands inside a workspace with history rather than a signup wall. And the free tier is what an evaluating prospect sees, paywalls included. Several of the posts are about exactly where a feature stops being free: Canny’s changelog email subscriptions sit behind Pro, and Maze gates all of its AI behind an Enterprise tier with no published price.

Each run studies one feature hands-on for a few hours, screenshots as it goes, then writes a Field Notes article about what it found. The last step is the digest: a file committed and pushed, and an email in my inbox with the verdict, the draft article, and links to whatever it built. The email is the only part of it I ever look at. I have never watched a run happen; I read about it over coffee. The series lives at /blog/series/field-notes. I vetoed the name “Teardowns” for it. The posts are written to be kind and curious, and the name should match.

The gates

The design decision I’d defend hardest is the verdict gate. After studying the feature, the run has to decide: BUILD, or teardown-only. Run 1 was Canny’s Autopilot, and the very first verdict was teardown-only, because our existing clustering already covered what Autopilot does. It wrote the article, filed a small follow-up task, and wrote no code. The system’s first act was to decline to build. I trust it more for that.

Run 2 was Olvy’s AI release notes, verdict BUILD, and by morning there was a PR drafting changelog entries from our merged pull requests. Run 3 was Savio, verdict BUILD again, and the PR was revenue-weighted prioritization. When it works, that’s the shape of it: study a feature overnight, have our answer sitting in a PR by breakfast, waiting for a human.

Across 19 verdicts so far: 16 BUILD, 1 split, 1 teardown-only, 1 blocked. Yes, that skews heavily toward building. Small product next to big competitors, so there are a lot of gaps. I expect the ratio to shift as the obvious ones close.

When the verdict is BUILD, the feature gets built the same night on a loop/<slug> branch with a pull request. The proof bar is written into the standing prompt: typecheck, unit tests, e2e where it fits, screenshots, and a smoke transcript. The prompt’s own words: “A PR without verification evidence doesn’t meet the bar.”

And then the hard stops: nothing auto-merges or auto-publishes, and nothing gets sent outside the company. Every morning I read the digest over coffee and decide what gets merged and what gets published. The loop only ever proposes. That rule is the whole reason the next section is a list of cheap failures instead of disasters.

The failure log

The first scheduled fire, July 23, died instantly with command not found: claude, exit 127. launchd jobs get a bare PATH. Off to a great start.

July 24 was the 60-byte morning. The log was one line. No error worth the name, no digest, nothing. Silent duds are worse than loud crashes; at least a crash points at something.

July 25, a subagent got killed at a 600-second background-task ceiling in the middle of studying Savio. The nice surprise: the next night’s run found the 13 screenshots the dead run had left behind and resumed from them instead of starting over. I did not design that, and it was the first morning the loop surprised me in a good way.

July 30 taught me something about GitHub I’d never had reason to learn: it builds no merge ref for a conflicted PR, so a conflicted PR receives no CI at all. Three loop PRs sat there looking green-ish while being tested by nobody. When one process opens PRs while I sleep, they accumulate conflicts faster than a team of humans would let them, and I found out how much of my usual review routine had been covering for that.

August 2, the digest email was parked in a background task that got killed, and nothing was delivered. That morning is why a dead-man check now runs after every loop: it verifies the digest file exists and the email is in Gmail’s Sent folder, and if either is missing it sends a [FALLBACK] email itself. August 4, a run completed a 25-screenshot study and then died one step before the verdict gate, leaving a 4.1MB log, 25 screenshots, and no decision. August 5, the model exited instantly with “out of usage credits” and both nightly loops died. The failing payment card had also taken out AWS, so at least it was consistent.

The worst stretch was August 12 to 15. Four dark nights in a row. The outage matcher grepped the logs for “out of usage credits”, and the actual message that time was “You’ve hit your weekly limit”. String match failed, fallback never fired, and the loop stayed down until a human noticed. I had bet the error text would stay the same, and it didn’t.

August 17, GitHub was degraded, the preview deploy got skipped, and the digest cheerfully emailed me a preview URL that 404’d. The rule now is that no URL enters an email without a 200 curled during that same run. The same weekend, the competitor run overran to 08:42 and the 07:13 PM loop read a half-written board file mid-edit, which is why it now waits. Parallel overnight runs also collided on database migration numbers, five doubled numbers now pinned in a validator so it can never happen quietly again.

That’s 9 failed mornings out of 28, a third of them. None of them got past the gates: the cost was always a missing digest, never a bad merge or a wrong email to a real person, because those paths need a human.

What the good mornings find

The reason to run this every night is that hands-on use finds things that are on no pricing page. Olvy markets AI release notes; hands-on, the AI cannot read your PRs at all, it generates from text you paste into a box. Canny’s changelog knows exactly which requests a release answers and never tells the people who voted, while the status-change flow one nav item away does email them. Hotjar accepted our feedback submissions with a 200 on every POST and never surfaced them in the dashboard in over two hours. This morning’s run found that PostHog’s flagship “View recording” link was silently dead on all three surfaces it appears on, while the recording itself played fine at its direct URL.

And sometimes the finding cuts the other way. The Sleekplan run studied their satisfaction score and concluded they were right and we were wrong. We built score-over-time into our own surveys the same night. That run is the one I’d show a skeptic, because a competitor-study loop that only ever finds flaws in competitors is doing marketing, not research.

The kind tone is a research decision before it is a manners one. The tone rule in the prompt is “honest not critical”, because if the write-up is allowed to dunk, the study starts looking for dunks. The Canny changelog post ends by thanking their team for a linked-posts typeahead that is a nicer piece of design than most of what we’ve built, and it means it. The two live Maze studies a run left behind in their product got disclosed in the digest and flagged for deletion, the same way you’d want a stranger poking around your free tier to behave.

The ledger

28 nights. 19 digests, 9 failures. 17 pull requests on the main repo plus 1 on the SDK; 15 merged, 2 open. 18 articles written: 12 published, 4 queued, 2 still sitting on open branches. 1 declined build.

My side of it budgets at about 15 minutes a morning. Read the digest, open the PR, check the screenshots and the smoke transcript against the claim, merge or don’t, publish or don’t. The proof bar is why 15 minutes is enough: I’m checking evidence that was gathered for me, not re-deriving it. On the dud mornings the 15 minutes goes to the log instead, and a few of those logs turned into the fixes in the failure section.

Cost is a flat-rate Claude subscription, so there is no per-night dollar figure to report. The binding constraint is the weekly usage limit, the same one that took out those four nights in August. A budget denominated in tokens per week is a strange thing to plan an engineering calendar around, but here we are.

The part I didn’t plan is that one night’s work keeps landing in three places at once: the study is competitor research, the verdict feeds the roadmap, and the write-up is a published article. I set out to automate the first one and the other two came along for free.

Tomorrow it fires at 6:27 again. There are more BUILD verdicts than merged PRs and more written articles than published ones, so the backlog it generates is now its own small management problem. The thing I’m watching is whether the BUILD ratio comes down as the easy gaps close. If it’s still 16 out of 19 in three months, something has gone soft in the gate.

Build a feedback loop your team actually uses

Usero collects, clusters, and turns user feedback into shipped fixes.

Get started free