A wooden desk at night with six overflowing paper inboxes, each connected by a copper wire to one neat stack of paper beside a notebook and pen.

Capture Everywhere, Think in One Place

I read a lot. News comes in through RSS feeds, ideas come in through podcasts, and the slower stuff comes in through books and magazines. A surprising amount of it ends up in what I write here and in the work I do at Vycari. An article I skimmed in March becomes the counterexample I need in a design discussion in August. A talk I half-watched on a Saturday becomes the seed of a blog post.

That only works if I can find the thing again. Two years ago I had the same problem with podcasts, and I built a search system over my listening history to solve it. This time the shape was different. My notes live in plain markdown files in Obsidian, and that vault is where I think. The problem was that my reading didn’t live there. It lived everywhere else.

Six Inboxes and No Desk

Readwise held my RSS feeds, my Kindle highlights, and my Twitter bookmarks. Karakeep, the self-hosted bookmark manager on my homelab, held the links I saved from my phone. GitHub stars were an input I cared about as much as any article, and they lived in GitHub. Each of those places was a fine place to capture something and a terrible place to find it three months later.

YouTube was the worst of them, and it’s what started this. I watch a lot of talks and technical videos, and almost none of that made it into my notes. I wanted a thumbs-up on a video to mean something, the way a highlight in a book does. I tried IFTTT and Zapier first, and neither would do the simple thing I wanted, which was to take a liked video and put it somewhere I could triage it. I’d forgotten that detail until I sat down to write this. The whole system grew out of one missing integration.

I’d built the capture habit. Starring a repo, liking a video, or bookmarking a page costs nothing, which is exactly why I did it constantly. The idea is borrowed from David Allen’s Getting Things Done: get everything out of your head and into an inbox, then process the inbox on a schedule. The inbox half stuck with me. The processing half never did. I have never once had the discipline to sit down for the weekly review, and so the highlights and stars piled up in their silos. When I sat down to write I worked from memory and a few frantic searches.

Last November I wrote about personal software, software written for an audience of one. The thing I noticed then was that I’d stopped searching for tools and started building them. This problem was the next test of that idea, and it showed me something about how the idea is changing. That post was about small utilities and one-off scripts. What I built this time is a service, with a scheduler, a status page, secrets management, and a CI pipeline, and I built it the same way I’d build a twenty-line script. The tools I write for myself are getting more sophisticated, and the cost of that sophistication hasn’t gone up. I want to walk through what I built, because the shape of it says something about where this is going.

One Pipe Into Readwise

The decision that made everything else simple was to pick one database and route everything into it. That database is Readwise Reader. A purist would say the daemon should write markdown straight into the vault and skip the middleman, but Readwise already held half my sources and did that job well, with good iOS and browser clients and a maintained Obsidian plugin that pulls everything into the vault on a schedule. Nothing there was broken, so I didn’t fix it. I built only the missing pipe: the three sources that had no way into Readwise at all.

So I opened a coding agent and described a small daemon. It polls a set of sources, pushes anything new into Reader, and dedups against what’s already there. The result is sync-to-readwise, about two thousand lines of Python that has been running in a Docker container on my homelab since May. It handles the three sources Readwise couldn’t reach on its own: YouTube likes, GitHub stars, and Karakeep bookmarks.

The core of it is an interface with one method.

class Source(ABC):
    name: str
    default_location: str = "later"
    default_tags: tuple[str, ...] = ()

    @abstractmethod
    def fetch_candidates(self) -> Iterable[Item]:
        """Yield candidate items. The Syncer handles dedup."""

A source yields items with a URL, a title, and some metadata. The syncer asks Readwise whether it has already seen that URL and saves the ones it hasn’t. That’s the whole design. Adding a new source is one file and a line in a registry. That’s how the project went from YouTube likes on day one to GitHub stars the same afternoon, and Karakeep bookmarks over the summer.

The GitHub source is a good example of how little a source has to do. It pages through /user/starred, and for each repo it hands back the URL, the full name, the owner, and the description. Reader does the rest, fetching the README and filing it as an article tagged github. When I star a repo now, its README shows up in my reading queue within the hour.

The interesting engineering was all in the parts that touch Readwise, not the sources. Reader’s API allows twenty list requests a minute. A cold start that walks your entire library to build the dedup set runs straight into that limit. My first version had the two rate limits transposed, so it paced the generous endpoint carefully and hammered the strict one. Worse, it was walking my RSS feed items, which on a real account outnumber the things I’ve deliberately saved by orders of magnitude. The homelab deployment paged through 103,819 feed documents without reaching the end. The fix was to exclude the feed from the dedup cache entirely, persist the cache on disk, and warm it incrementally on each run. None of that was hard, but it was the kind of thing you only learn by running the tool against your own account.

It’s also a reminder that the agent didn’t notice either problem. I did, because I was reading the logs and knew what my account looked like, and then I had to ask for the cache. There’s a whole post in that, about what the job of an engineer becomes when the agent writes the code, and I’ll get to it soon.

Secrets live in Doppler, the same shape we use for Pepper at Vycari, so the only thing on the host is a service token. There’s a small status page that shows each source’s last sync, its counters, and whether the YouTube OAuth token has expired. If it has, there’s a link to re-authorize from the browser. I added that after the second time I had to SSH in to fix a token, and because I wanted a way to glance at the service and know what it was doing. Since then the token has stayed put and the service has just hummed along.

Claude Files It

Readwise’s plugin lands new documents in a Readwise folder in my vault throughout the day. That solved the finding problem, but it created a filing problem. A folder with a few hundred articles, videos, and repo READMEs is a pile, not a system.

That is where Claude comes in. I have a skill in the Claude desktop app that runs on a schedule and sweeps the new Readwise material into the projects it serves. Each project in my vault has a landing note that summarizes what the project is about. The skill reads those, reads the new documents, and appends each one to the right project’s sources note with a line or two on why it belongs there. When enough unfiled items cluster around a theme that isn’t a project yet, it proposes one. The sources note for this blog as a whole, not for any one post, now has an entry for an IEEE Spectrum piece on skill atrophy under automation. Next to it is a note that it pairs with a draft I’m working on about agents and code review. I didn’t file that. I read the article on my phone, it flowed through Readwise into the vault, and Claude worked out where it belonged. I wrote about scoping an agent to a project’s context earlier this year, and this is the same idea applied to intake rather than writing.

The most common miss is that Claude can’t place something and leaves it in an inbox for me to sort by hand, which is still a fraction of the sorting I’d be doing if I did all of it by hand. The other miss is that it attaches an article to a project where it doesn’t really belong. When that happens I delete the line while I’m reviewing the sources for that project, which I do every time I sit down to write from them. I’d rather have a few sources misfiled than never see them at all, which is where I was before this project. That review is the human check, and it’s the part of GTD I could never sustain on my own. The agent does the weekly review as my research assistant, and I do the reading when it matters.

The effect is that capture is effortless and organization is close to free. I star a project, thumbs-up a video, bookmark a page, or highlight a paragraph, and I don’t think about it again. When I open a project to write, the reading I did for it is already there, with notes on why I saved it.

What I Didn’t Do

I did look for an existing tool, briefly. IFTTT and Zapier were the obvious candidates and neither fit. A year ago that’s where the evening would have gone: reading comparisons of read-it-later services, trying two of them, and settling for the one that covered four of my six sources. Instead I sat down one Saturday, described exactly what I wanted to a coding agent, and let it build. A second Saturday over the summer added Karakeep. A few hours each time, and I learned something on both of them, which felt like a fair trade. Between those two sessions the tool has cost me almost nothing to run. It covers the three sources I was missing and nothing else, and the whole system now covers all six.

The audience of one keeps paying off. The tool has no settings I don’t use, no features waiting for someone else’s roadmap, and no update that quietly changes how it works. When Readwise’s rate limits bit me, I fixed it that afternoon, which is the responsibility I signed up for when I stepped outside managed software. That trade has been worth it every time.

The Part That Worries Me

Lately I’ve noticed the same attitude creeping toward software I already use and pay for. I run a window manager that does ninety percent of what I want and is missing one feature I care about. More than once I’ve thought about having an agent rewrite the whole utility so it does exactly what I want and nothing else. I haven’t done it yet, but the fact that it’s a live option is new, and I don’t think it’s entirely good.

To be clear, my private rewrite wouldn’t hurt anyone. I have no desire to sell or support any of my tools, and most of them aren’t even open source, because I don’t want to field issues or review pull requests for something that was only ever meant for me. This sync tool is public because I wanted to write about it, not because I want anyone else to run it. What worries me is the pattern, not my copy of it. As building for an audience of one gets easier, more people will reach for it first, before they look for the thing that already exists and does most of the job. The people who build those ninety-percent tools are mostly small independent developers, and a world where their potential customers default to rolling their own is a harder world for them to make a living in. I don’t have an answer for that. I notice that I’m part of it.

What I get back is time. I spend almost none of it organizing and much more of it thinking, and the thinking is better because the raw material is at hand. This is the first post in what I expect to be a series on the personal software I actually run. The next one will be about a tool I built for a very different kind of problem.

A laptop glowing in a dim home office at night, showing a queue of pull requests waiting for review.

The Agent That Never Merges

Most mornings now I open my laptop to a queue instead of an inbox. Overnight, while Chris and I were asleep, an agent read our open GitHub issues, decided which ones were ready to build, picked the oldest one, and opened a pull request. The tests pass. Greptile reviewed it, the agent worked through the review comments, and Greptile now scores the change five out of five. The description explains what changed and why. The commit history looks like a careful engineer wrote it. What’s left for me is to decide whether it’s good enough to ship.

I said last month that I’d keep writing about the engineering as Chris and I build Vycari. This is the second post in that series. The first was about the issue tracker, and what belongs in it now that agents do most of the work. This one is about the pipeline that works through it. It’s the part of our process I trust most, and the part I was most nervous about building, because it’s where we let an agent write code that ends up in front of you.

Two Founders, No Platform Team

There are two of us. There is no platform team, no SRE rotation, no QA function, nobody whose job is keeping the lights on so we can build product. Whatever infrastructure we need, we build ourselves, out of the same hours we need for everything else. I like this stage of a company, but it means every hour Chris or I spend on triage, boilerplate, or a stale dependency is an hour not spent on decisions only the two of us can make.

The obvious answer is to point an agent at the boring parts. The harder part is the discipline that requires. An agent that opens pull requests unsupervised can save you a lot of time or create a lot of problems, and which one you get depends on what you refuse to let it decide on its own. I’ll come back to that. First I want to explain where the tooling came from, because it didn’t start as a product decision. It started when I noticed I had built the same thing twice.

We Had Already Built This Twice

Before the company, I was maintaining Gemini Scribe, a TypeScript plugin for Obsidian I’ve been building for a couple of years, and I had started experimenting with overnight agents to do the maintenance work: keeping the docs current, writing development logs, triaging issues. An architecture audit, a daily changelog generator, a skill that reviewed pull requests against the project’s conventions. When I started on what became Vycari’s codebase, a Python backend, I began writing the same things again under slightly different names. I hadn’t noticed they were the same habits until the second or third time.

In June I pulled all of it out into its own project. Maintainerd is a marketplace of Claude Code plugins for maintainer work: audits for architecture, test quality, security, dependencies, and documentation; a daily changelog; a research radar that scans arXiv for relevant papers; a skill that opens pull requests and one that works through reviewer comments; and the pipeline this post is about. It’s open source under the MIT license and lives in the Vycari org.

The name is a pun on maître d’. A maître d’ runs the front of the house so the kitchen can cook, which is what these skills do for a repository. It also reads as Maintainer Nerd, which I didn’t notice until later and haven’t tried to fix. I wrote when we announced the company that using agents today is still a hobby. Naming my repo maintenance tooling after a restaurant host tells you which side of that line I’m on.

Every skill in maintainerd is repo-agnostic. It reads a small config contract, a JSON file plus a few markdown documents of house rules, that says what language the repo is in, where the tests live, what the lint command is, and which GitHub labels mean what. The same skill works on a Python backend and a TypeScript plugin because the repo-specific knowledge is in the config, not in the skill.

That separation is what made the rest possible. A skill hardcoded to one repo’s conventions is a one-off script. A skill that reads a contract is infrastructure you can point at a new project in an afternoon. It’s the same argument I made when I wrote that prompts are code: an instruction that hardcodes its environment isn’t reusable. Without that separation, two people could not have built the pipeline I’m about to describe in the time we had.

What the Pipeline Actually Does

The piece of maintainerd we lean on hardest is called auto-dev. It’s a state machine. An issue moves from idea to clarification to plan to implementation, one step at a time, while I’m working on something else. It has three parts.

The first is what goes in, and the last post covered most of that. The tracker holds three kinds of work: bugs we found and can’t fix right now but an agent can, follow-ups from review that weren’t worth forking a subagent to fix on the spot, and pointers to planned features whose real content lives in a design document. The pipeline only wants the first two. The design-doc issues are labeled so it leaves them alone, and a person sits down with an agent and builds those end to end.

Most of the issues the pipeline works on were written by agents, not by us. The test for whether an issue belongs in the tracker is whether a cheap model could fix it tonight without asking anything, and an agent that just watched a bug happen usually clears that bar. When one of us writes an issue by hand, we describe it to a skill whose job is to get it to that standard. It reads the relevant code first, so the issue points at real files and functions, and it asks us the two or three questions the code can’t answer, so the issue doesn’t have to ask them later.

I don’t always hold to that. Sometimes I type a few paragraphs into an issue from my phone. When an issue isn’t good enough to build from, the pipeline’s triage catches it and asks. That’s the fallback, not the plan. Either way an issue is filed unlabeled, so the pipeline evaluates it fresh rather than assuming someone already decided it was ready.

The second part is the pipeline itself, which runs on a schedule rather than on demand. A scheduled task fires the skill at a regular interval, and each run is one tick of the state machine. It does the single highest-priority piece of work available and exits. Waiting for an answer, an approval, or a review is what happens between ticks.

Each tick looks at every open issue and asks whether it’s ready to build: whether it has enough context, whether it depends on something unfinished, whether it’s in scope. Ready issues get a plan drafted and posted as a comment, and the pipeline stops there. A plan is a proposal. Only after one of us approves it does the issue become buildable, and only then, on a later tick, does the pipeline pick the oldest approved issue, write the code, run the tests, and open the pull request. All of that state lives in a small set of GitHub labels:

"stateLabels": {
  "needsInfo": "auto:needs-info",
  "planned": "auto:planned",
  "ready": "auto:ready",
  "inProgress": "auto:in-progress",
  "parked": "auto:parked",
  "skip": "auto:skip"
}

There is no database to maintain and no dashboard to check. The state is on the issue, visible to anyone who looks at the repo, and the label history is the audit log.

The third part is the human side. It’s a skill called review-queue that I run in my coding agent. It collects everything blocked on a decision that’s waiting for me to weigh in: plans waiting for approval, pull requests where a reviewer left a comment the pipeline has already addressed, issues it flagged as needing more information. I work through the list top to bottom, the way I used to work a code review queue at Google, except most of the queue was generated by something that also drafted its own response to the objections.

I run it on my desktop and on my phone against a cloud-hosted model, and the phone version is the one that changed my habits. I’ll clear three or four items while standing in a line: approve a plan, answer a question, park something that isn’t worth building yet. That time used to go to scrolling.

The pull requests themselves get more than a glance. Most of the time we spend on them goes to running the change in a local environment and testing it. When there’s nothing to see, I read the code and either agree with it or don’t. Every pull request also goes through an adversarial review agent, and it holds code I write to the same bar as code auto-dev writes.

Here is the part that matters most. There are two gates in this pipeline, and a person has to open both. Nothing gets built without an approved plan, and someone has to read the plan to approve it. And at no stage does the pipeline merge anything. It triages, it plans, it builds, it responds to review feedback on its own pull requests. It never decides that a change is good enough to ship. That decision is still the responsibility of a human, on every pull request, with no exception for the ones that look routine. The merge rule isn’t a line in a prompt. The harness the pipeline runs in doesn’t allow it to merge, so the agent couldn’t do it even if it decided to. I’ve written before about where to put the guardrails on an agent that acts on its own. The guardrail I care most about now is not the one that stops the agent from doing damage. It’s the one that stops it from making a decision a person should be accountable for.

Four Pull Requests for One Bug

It doesn’t always go that cleanly. Last night an architecture audit flagged a real problem in one of our coding convention files, and several auto-dev runs picked it up at the same time. By the time I looked there were four pull requests open, each fixing the same thing in a slightly different way, and dozens of runs still going in the runner. I closed the pull requests, went into the runner, and shut down every instance that was working on it.

The pipeline has a limit on how many pull requests it can have open at once and a rule for reclaiming a build that looks abandoned, and both of those held. What they don’t cover is a burst of runs that all start before any of them has claimed the issue. It cost tokens and an evening, and it was the first failure of any size. I’ve been raising the run cadence and the number of open pull requests it’s allowed slowly, on purpose, so that the failures show up one at a time while they’re still cheap.

The Part That Happens in Public

Gemini Scribe is a public repository with real users, and they file issues. The pipeline treats their issues the way it treats ours: it reads the relevant code, decides whether there’s enough to plan against, and if not, posts a comment asking for what’s missing.

Sometimes that’s better than what I would have done. Someone files a short bug report, and before I’ve seen it there’s a specific question underneath it, pointing at the relevant file and asking which of two behaviors they meant. That’s a faster and more useful first response than a busy maintainer usually gives, and it arrives while the problem is still fresh for the reporter.

Every comment it posts is attributed to Claude Code in the comment metadata, so anyone reading the thread can see it wasn’t me. And each run starts in a fresh virtual machine with access to the repository and nothing else: no connectors, no configured tools, none of my data. The most it can leak is what’s already public in the repo.

Sometimes it asks the reporter what the plugin should do about the bug. That’s the wrong person to ask. They wanted their bug fixed; deciding how the software should behave is my job. The pipeline isn’t broken when it does this. It’s running the same readiness triage that works fine on a private backlog, where the only people it can ask are Chris and me. In a public tracker, that same question lands on a stranger.

I haven’t fixed this yet. What makes it tolerable is the same rule as before: the worst thing the pipeline can do in public is ask a question it shouldn’t. It can’t ship a decision. Nothing it writes reaches a user’s vault unless I put it there. The never-merge rule was meant to protect code quality, and it also limits how much damage an awkward comment can do.

I still prefer this to the alternative. An issue tracker that responds within hours instead of whenever I have a free evening is better for the person who filed the issue. Getting the questions right is a tuning problem. Getting anyone answered at all, with two people, is not something I could otherwise do.

The Same Discipline We’re Selling

I said when we announced the company that an agent has to earn the trust the access requires, and that we’d hold ourselves to that before asking anyone to trust us with their calendar and mail. This pipeline is the first place I get to practice that on myself.

The rule that it never merges is enforced by the harness, but the harness is ours. We built it that way and we could build it differently. It’s a decision, applied to our own code before it’s applied to a customer’s. If I’m going to ask someone to trust an assistant with the private parts of their day, I should at least refuse to let our own agent decide what ships. Everything else is work we’re happy to hand off: triage, drafting, boilerplate, the first pass at a reviewer’s comment. That’s the same division we want the product to make for you. Simon Willison made the argument in a post about proving your code works: a computer can’t be held accountable, so the human in the loop has to be. The decision with real consequences stays with a person who can answer for it. The product is built the same way. What Pepper is allowed to do on its own is set by policies and hooks in the agent framework, not by the model’s judgment in the moment. The harness decides where the line is, and a person decides what the harness says.

There’s a second connection I didn’t expect. Part of what we believe is that nobody should have to learn our vocabulary to get value from an agent. The review-queue skill is that idea applied to me. It doesn’t ask me to understand auto-dev’s state machine or check six label filters across a dozen pull requests. It gives me one ordered list of the decisions that are mine to make. Once you decide an assistant’s job is to meet people where they are, you notice every other place a tool is asking you to come to it.

What’s Next

One more thing I’ve noticed. A pipeline like this works because someone wrote the config contract, the conventions, the review rules, and the gates, and that someone had built and shipped software for a long time before agents existed. That’s where experienced engineers add value now. You build the frameworks that let the agents succeed, and you review what comes back. It isn’t very different from being a tech lead with a team of new grads.

None of this is finished. The pipeline still gets things wrong in ways I only find by watching it, and I’ll write about the ones worth telling. Next in this series I want to cover how we grade the agent’s work when nobody is watching. It’s closer to writing a rubric than writing code. I built a first version of that for my Obsidian plugin, and doing it for a product two people are betting on is a different problem. For now, two people are building a company with a colleague that never stops, never merges, and still needs its work checked every morning. That’s the balance I wanted.

An overhead view of a wooden desk holding two laptops side by side. The left laptop is closed and covered in old stickers with a security badge on top. The right laptop is open with fresh stickers and a code editor on screen. A sheet of dated notes lies between them.

Writing My Way Out

I started writing this blog two years ago because I wanted to share what I was learning about AI, and the projects it kept pushing me to take on. A year ago I wrote the first anniversary post, and it ended with a plan. Two thoughtful posts a month instead of the weekly pace that had already beaten me once. More explainer series, because the embeddings posts had been the most-read thing I published. Some shorter pieces in the spirit of Simon Willison. And permission, finally, to write about the woodworking and the guitars instead of quietly worrying that they were off topic.

I had no idea, when I wrote it, that by the time I sat down to write the next one I would not be at Google anymore.

The plan mostly worked

I published fifty seven posts between that anniversary and this one, which is a little under five a month against a goal of two. I am not sure that counts as keeping a promise so much as failing to keep it in the more enjoyable direction.

I had been afraid that I would run out of things to say. The opposite happened. If I look at my drafts and ideas folders right now, there are close to fifty posts in there that I still want to write and have not found the time for.

The explainer series happened. The Agentic Shift was planned as twelve parts, and it came in at twelve parts, thirteen if you count the introduction, running from September through April. The structure held up almost exactly as I outlined it. What I did not anticipate was how much the ground would move underneath it. I thought I was writing a textbook, assembled in public. What I actually wrote was a journal of a landscape that would not hold still long enough to be documented. I outlined Part 9 as speculation about a future problem and published it as reporting on a present one. I am really proud of that series, and I think it has stood up well.

The shorter pieces happened too, though this one is still a work in progress. Eight Reading Lists, which started as an experiment in whether I could publish something in under an hour and turned into the format I reach for when an idea is real but not yet a post. I never got to the point of posting one every week, and that is something I want to get better at this year.

And the hobbies made it in. A bill in the California legislature that wanted my 3D printer to police itself. A French band I could not stop listening to. A Starlink dish on the roof of a car. The Köln Concert, as an argument about creative constraints in software. Nobody unsubscribed, as far as I can tell, which suggests the worry was mine and not my readers’. There is more of that to come, I hope.

The post that turned out to be about something else

In April I counted my GitHub contributions for the year. There were 4,255 of them, and the post was supposed to be a light piece about the shape of a year of building in the open.

The interesting number was not the total. It was that my most productive day of the week was Saturday, by a wide margin, and the reason was not discipline. It was that Saturday was the day nobody had scheduled anything. I wrote at the time that this was a diagnosis rather than a brag, and I meant it more casually than it turned out to deserve. Given time and no meetings, I build things compulsively, and I am happier. That is a useful thing to learn about yourself. It is also the kind of thing that, once you know it, quietly reorganizes every other question you were asking.

Four months later I left, after twenty one years, most of a career, and about half my life. Twenty One Years is the post about that. Not Everyone Wants a Hobby is the post about what I left to go do, which is a company called Vycari that I am building with Chris Perry. Chris was the product lead for Colab when I ran the AI Developer organization, we were both on the founding team of Gemini CLI, and somewhere in there he became the person I most wanted to build with. He is the CEO, I am the CTO, and our first product, Pepper, is a personal assistant for your life. And Thousands of Goodbyes is the post about pointing an agent at twenty one years of my own sent mail because I could only remember about a hundred and fifty of the several thousand people I had worked with.

I did not plan any of those as a trilogy. Reading them back to back, they are obviously one thing.

What the blog was for, and what it is for now

When I started writing here, the blog had a job inside a larger job. I said as much in the first anniversary post: building in the open and writing about it was how I contributed while my calendar was still too unpredictable for mission critical work, and it let me lead by example, demonstrating the kind of developer engagement I was hoping to inspire in an organization I was running.

That is a perfectly good reason to write, and it is gone now. There is no organization. There is no example to set for anyone but Chris and me. The blog is no longer a thing I do alongside the work, and it is not marketing for the work either. It is the only continuous artifact I have from before to after, which I did not appreciate until I went looking for a through line and found that the writing was the only place one existed.

There is an obvious hazard in this, and I would rather name it now than have you notice it in six months. Founder blogs decay into product announcements. It happens gradually and the person writing them is always the last to see it. So let me be clear about what you should expect. I am going to write about Vycari and Pepper, because they are the most interesting things happening to me right now. We are building a new kind of agent harness and a new kind of agent, and there are a lot of stories in that. Some of them will be technical, like the recent post about what happened to our issue backlog once agents were filing most of the issues. Some of them will be about philosophy, like why the chat window is the wrong interface for most people and why almost nothing a consumer agent does needs a frontier model, and a few of them will be things I did not feel I could say while I worked at Google. What I can promise is that everything I write here is here because I think it is useful to share, because I think you will enjoy reading it, and because I think it articulates why Chris and I, and the company we are building, are different.

The people who read this blog are people who will happily install a CLI, configure an API key, and read a changelog for fun. They are the reason it exists. I am aware that I have just started a company premised on the argument that requiring all of that is a failure of product design, and I do not think those two things are in tension, but I understand why it might look that way. Working out loud on that confluence is most of what I expect year three to be about.

Year Two, By the Series

The Agentic Shift

Twelve parts and a retrospective, September 2025 through April 2026. The series that ate the year, and the work on this site I am proudest of.

Building the Things I Write About

The Reading Lists

Eight of them, starting in April. Short, fast, and the closest thing this blog has to a running commentary.

The Work Itself

Building Vycari

The first three posts of the next chapter. None of them is a launch announcement, which is the point.

Everything Else

The promise I made last year to stop worrying about staying on topic.

Year Three

More of the same, with one change I am now a month into.

For two years I wrote about agents from inside a company with essentially unlimited access to models, infrastructure, and the people who build them. Everything I published came with that thumb on the scale, whether or not I acknowledged it. For the past month I have been building the same class of system with two people and a budget. In the first thirty days of that, the two of us merged 657 pull requests, our agents filed most of the 449 issues that came out of them, and something like a hundred and fifty million tokens went through the product for about forty dollars. Those are not numbers I could have written from inside Google, and they are the constraints almost all of my readers have always lived with. I expect that to make the writing better, and the series on how the two of us build, which started with the issue tracker, is where I intend to find out.

I also want to keep doing what Thousands of Goodbyes turned out to be, which was the first time in two years of writing about agents that I pointed one at something that was not work and had the output make me feel something. There is a great deal more of that available, and almost nobody is writing about it, because we are all still busy benchmarking.

Beyond that, my goals are simple. I want to keep sharing what I learn. Last year I said a weekly pace was not sustainable, and then published nearly five posts a month, so this year I am going to say it out loud: at least one real piece a week, with shorter things sprinkled in on the other days. I am trying to be more active on X and LinkedIn as well, so if you see me there, say hi. I will keep bringing more of my outside interests into this space, though it will almost always have a technical angle. There are more management posts planned, a tribute to a friend who is gone, some book reviews, and more.

Two years ago I hit publish on the first one of these with no idea where it would lead. I have a much better idea now, and I am still not going to tell you it is a plan. I am looking forward to what comes next, and I am glad you have decided to come along.

An ordinary compact sedan in a driveway at dawn, sharply in focus, with a covered exotic sports car blurred in a showroom behind it.

Not Everyone Needs Superintelligence

Every morning, while my family gets ready for the day, we have KQED on throughout the house. Proud members since 2000. Then I listen to podcasts while I work out. Either way I am half listening, the way you do, attention drifting between whatever is playing and planning for the day in front of me.

Last week I caught a segment about frontier models, and I could not tell you now whether it was the radio or one of the podcasts. The speaker was talking about pricing and performance, I think in relation to the new GLM model. Then he started talking about cars, and I stopped half listening. These frontier models are Ferraris, the argument went. Most people don’t drive a Ferrari. Most people drive a Corolla.

I have spent a lot of time over the last few years building agents that run on Corollas. Last year I built a coding agent on Gemini Flash 2.5, mostly to find out whether I could get really good performance on a lightweight, less expensive, and faster model. Lately I have been working with Chris on Pepper, a personal assistant for your life. Pepper runs on Corollas too.

That line stuck with me throughout the day. I mentioned it to Chris on a call the next morning, and he tied it back to one of my previous posts, the chat box is a detour. He was right: they are the same argument at two different layers. That post said we handed consumers the wrong interface because a chat window was the honest expression of what models could do in 2022, and then we never revisited it. This is the same mistake one layer down. We build on the frontier tier because that is where the attention is, not because the work requires it.

What Our Product Actually Runs On

At Vycari we are building agents that handle the day to day, and Pepper is the first one. Almost all of its agentic work runs on the cheapest models the big labs sell. Orchestration goes overwhelmingly to Gemini Flash Lite 3.5, with small slices of Claude Haiku 4.5 and GPT-5.6 Luna routed alongside it to keep us honest about vendor lock-in, and to give us a baseline for our own evals. Somewhere around a hundred and fifty million tokens have gone through the system for about forty dollars, which starts looking like a rounding error once you notice that an Opus-class harness can spend forty dollars in minutes.

The work those models do is not exotic. Look at a calendar. Read an email and decide whether it needs a response. Manage my exercise log, or find my to-dos. When I wrote about how everything becomes an agent, the point underneath was that an agent brings value by deciding in the moment, with real input in front of it. Most of those decisions are small. If you were hiring a person for this job, you would not start out looking for a PhD.

That changes the shape of the pricing conversation. For a lot of use cases we have been standing in the Ferrari showroom asking for a deal, when the better move is to walk down the street to the Toyota lot. The question was never how to get the frontier tier cheaper. It was why we were standing in that showroom at all, holding a list that reads: check the calendar, read the mail, log the workout.

The Objection I Keep Hearing

I have heard the objections. Small models hallucinate. They report success on work they never did. They narrate a tool call as prose instead of calling the tool, and the turn ends clean with fabricated content sitting in it. I have watched all of that happen in production.

The objections come out of real experience, and they were true recently enough that I understand why people still reach for them. But this industry is moving so quickly that we often have to check our assumptions on the models that are available today. The cheap tier climbs about a rung a year. The lite model I run today does work that belonged to the mid tier a year ago, and that mid tier was doing work the frontier owned the year before that. The objections have not been updated since the last time they were correct.

So we ran a quick eval. Nine recorded production turns, one for each failure shape our nightly reflection kept filing, replayed against three tiers: the lite model we ship on, the mid Flash model, and Pro. Fixed thinking budget, three samples per arm, and a grader from a different vendor so we were not asking Gemini to mark Gemini’s homework. I expected a ladder. What came back was flatter than that.

That is a small eval and I am not going to pretend otherwise. What I can say is that we have now watched the platform across thousands of model calls, and what the eval showed is holding up. We are not a public product yet, so the data is thin and I would not ask anyone to take it as settled. But every time I take one of our failing cases from Flash Lite and hand it up the ladder, the results refuse to move the way I expect them to.

The headline in our own experience is that this is mostly about how a model handles missing data, not how big it is. When a tool returns real data, all three tiers ground correctly and nobody invents anything. When the data is not there, behavior splits on how the absence gets signalled. Replay a turn with a vague instruction to proceed with whatever it already has, and all three fabricate confident content, with the bigger models producing the more polished fabrication. Signal the absence clearly, and every tier including lite says it cannot see the calendar instead of inventing events.

That reorganized how I think about the problem. The fabrication I had been charging to running cheap was mostly a property of how we told the model it had nothing. Our first recommendation to ourselves was to stop shopping for a bigger model and go fix the signal.

Which puts the weight on the harness instead. The harness manages the context, decides what the model sees, and decides what it is told when a tool comes back empty. Its entire job is to put the model in a position to succeed. Get that wrong and no amount of model will save you.

Two other results fell out of it. The first is a failure where the answer is correct and well-grounded all the way through, and then comes apart in its last few words. A phrase repeats itself, or a contraction mangles. One of ours signed off with “while he recovers today while he recovers.” We call it a garbled tail, and nothing in the logs flags it, because the model finished cleanly and the turn reads as a success. It showed up on every model we tested including Pro. Low rate, stochastic, and scaling did nothing to it.

The second is that the middle is not the safe middle it looks like. On empty tools the mid tier invented more concrete detail, weather numbers and times, than either the model above it or the one below.

There is one clean exception. False completion, where the agent answers after step two of a five-step procedure and reports back as though it had finished, does improve with model size. Our own notes call it the one real model-size win, and it is the only one on the list.

I want to be careful not to oversell this, because we do pay a tax for running small. Ten modules in Pepper’s agent harness exist mostly to catch models behaving badly, roughly 2,500 lines of production code and about the same again in tests. A detector for tool calls narrated as prose. A repair pass for garbled text. A guard for the case where a tool returns a success status with a zero success count buried in the JSON, which we wrote after a model read the status, believed its own plan, and invented the record IDs out of its own request.

Six of those ten ship detect-only. They watch, they report, and they change nothing a user sees, because we do not ship a pass that suppresses model output until nightly grading proves it is effective. The failures they watch for are not exclusive to the tier we run on. Most of that code is the cost of building an agent at all, and we would be writing a version of it at any price.

None of that machinery came out of a design document. It came out of watching. Every night a high-capability model, a Ferrari, reads back every task Pepper took on that day and grades it. It correlates failures to bugs, files the issues, sometimes reproduces a failure as a failing test, and sometimes opens a pull request to fix it. That process deserves its own post and it will get one. The short version is that almost every guard in our harness exists because we watched the model fail in one specific way and wrote a defense against that one failure.

So the Ferrari does have a job here. It is just not the one that answers you.

We Don’t Have a Word for These Models

This is a naming problem, and I think it matters more than it sounds. “Small” is wrong, because the capability is not small. “Cheap” is pejorative and smuggles in the assumption I have spent this post arguing against. “Flash Lite class” is a product SKU, not a category. Nobody has named this tier because nobody is positioning for it.

I want to call them daily drivers.

A daily driver is not a lesser car. It is the car you actually chose, judged on what matters when you drive it every morning. It starts. It’s cheap to run. It does the trip. Nobody apologizes for driving one, and nobody seriously believes the Ferrari owner is having a better time getting the groceries home.

The capability question is already settled, and I published the evidence three months ago while thinking I was writing about something else. When I built a scoreboard for Gemini Scribe, my Obsidian plugin, the point was to stop grading my own agent on vibes. It scores reliability the way τ-bench does, so a task counts only if every one of five runs succeeds. The headline result, which is still published, was that the newer gemini-3.1-flash-lite solves 74.1% of that suite at solve^5 and the older gemini-2.5-flash, supposedly a tier up, solves 57.4%. Same tasks, same judge, about seventeen percentage points apart, and the lite model costs about three quarters as much per run.

Speed is part of this too, and it does not show up anywhere in a solve rate. The daily driver starts talking sooner, and the gap in time to first token is not subtle. For an assistant you are holding a conversation with, that is not a nice-to-have. It is most of what the thing feels like to use.

The Price Gap Is Widening, Not Closing

The objection I take most seriously is that all of this evaporates when frontier prices fall. If the Ferrari costs Corolla money, what is left of the argument?

Watch what actually happened this summer. OpenAI cut Luna’s price by 80% on July 30 and took 20% off the mid tier. Those are their numbers, and the same announcement adds one more line: Sol pricing remains unchanged. Three weeks later they cut Sol too, and on their own product page that second cut is described as running for the next three months.

Read the two together. The cut at the bottom is the price. The cut at the top is a sale with an end date on it. At launch the flagship cost five times what the cheap tier cost, on input and on output alike. Take the promotion out and it now costs twenty-five times, which is where the ratio lands again when the sale lapses in November.

The gap widened because the floor dropped, not because the ceiling rose. The research says to expect that. An MIT FutureTech analysis of the price-performance frontier puts the decline at five to ten times a year for a fixed level of capability, with roughly three of that coming from algorithms rather than hardware. A five-dollar subscription does not need the gap to hold still. It needs the floor to keep falling, and the floor is where the competitive energy is.

Where Cheap Doesn’t Save You

Inference is not the whole bill, and this is the part I would have wanted someone to tell me a year ago.

Grounding costs real money and it does not follow the same curve. Google gives you 5,000 free search requests a month shared across all the Gemini 3.x models, then charges $14 per thousand after that. Anthropic and OpenAI both charge $10. On a deep research task, where the agent fires dozens of queries to answer one question, the search line can run past the inference line. That inversion gets worse as tokens get cheaper, not better.

The other place the rule breaks is writing skills. A lightweight model asked to author its own procedure does it badly, and the failure is subtle. It writes instructions a smarter model could infer its way through. So our skill-authoring tool runs on a bigger model than the runtime it writes for, and the skill’s own instructions spell the asymmetry out to whatever is drafting. What you write will be executed by a lower-capability model than the one drafting it now. So be pedantic. Name the exact tool and its arguments, and do not leave a judgment call implicit. Vague instructions are instructions a smaller model will fumble.

That is the boundary in general. Reach up a tier where the output is a plan that gets reused, and stay down where the output is one decision that gets made and thrown away.

The Part I’m Most Excited About

The strategic argument for running this low is that it eventually stops depending on the labs at all. At this size there is a real path to fine-tuned open weights, and past that you are substantially immune to price hikes and can buy your own hardware.

I believe that, and I have not proved it. The abstraction is there: Pepper’s model layer is provider-neutral and already routes three vendors through one interface, so a fourth backend is a translation adapter and a route key rather than a rewrite. What is not there is a single line of code pointing at a local runtime.

When I did measure it, the answer was no, and I published that too. The local gemma4:e4b running on my own hardware clears the easy tier at 100% and then collapses: 15% on T2, 7% on T3, 11% on T4. Flash Lite stays above 65% on every tier. It almost always finishes without erroring. It just gets the answer wrong.

That is one very small model, well under what a single consumer GPU could hold, and I have not put the larger variants through the same gradient. With capable dense models now shipping in the 30-billion-parameter range, that gradient is the next thing I want to run.

A Different Company, Not a Cheaper Bill

Cheap orchestration is what makes a five-dollar subscription possible. A five-dollar subscription is what makes Pepper reachable by the people I had in mind when I wrote that not everyone wants a hobby. That is the whole thesis, and the model tier is critical to it in a way a line item on an infrastructure bill never is.

Chris’s read on the field is that most people building here run on higher-grade models, which is a large part of why they need venture money. They are burning tokens on work that does not require them. I don’t think anyone made that choice on purpose. The frontier is where the demos are, where the benchmarks are, and where the attention is. It takes a deliberate act to go shopping somewhere else.

There is an argument running right now about whether we are heading for superintelligence and what it will mean when we get there. It is a real argument and I am not dismissing it. It also has almost nothing to do with the software most people will actually use, which needs to read a calendar, check the weather, and then get out of the way. That job was solved a while ago. We just kept pricing it as though it were not.

Whoever it was I was half listening to had it right, and did not go far enough. Nobody needs a Ferrari to get to work. What nobody says out loud is that the Corolla gets faster every year while we are all reading the reviews of the Ferrari.

A mostly empty library card catalog with a few cards left in one open drawer, lit by morning light.

The Backlog Was a Coping Mechanism

We gave our coding agents a rule that sounded obviously correct. No follow-up left behind. It went into our agent context files in roughly those words: anything a pull request doesn’t fully address gets filed as an issue before the review closes. No deferred cleanup sitting in a comment nobody reads again, no “we should probably handle this properly at some point” evaporating the moment the branch merges. Every loose thread becomes a tracked one, and the agents were good at following it.

The rule worked exactly as designed. That was the problem. Take the last month, which is the first real stretch where I’ve been full time on the product. In those 30 days the two of us merged 657 pull requests on our main repository, close to 30 on a typical weekday. Every one of them came out the other end of review with its own small pile of follow-ups. Honest ones, well written, entirely legitimate.

Over the same 30 days we opened 449 issues. Fifteen a day, most of them filed by our own agents rather than typed by us. Nothing in the system closed the loop. The list only grew, and it grew faster the more time I gave it.

This is the first post in a series about how the two of us actually build Vycari, which I promised when I wrote about why we started the company. I want to start here, with the issue tracker, because it’s the piece of the toolchain I had thought about the least and had to change the most. Almost everything I believed about what belongs in a bug database turned out to be a belief about human limitations rather than about software.

What We Were Really Doing When We Filed a Bug

Think about why you file an issue. You have an idea for something the project should do, and you write it down so it doesn’t fall out of your head. You’re deep in one file and you spot a bug in another, and you write it down so you don’t lose your place. You’re cleaning up a module and you notice three more that need the same treatment, so you write those down too.

The common element in all of it is that you couldn’t do the thing right then. Filing was the second best option. The tracker was a memory prosthesis, a place to park work your hands were too busy or too few to pick up, and it was built for exactly that. Bugzilla went public on a mozilla.org server in 1998, replacing Netscape’s in-house system. The shape it established is still the one we use. A durable record, an owner, a state, a conversation attached to it. Durable because the gap between noticing and fixing was measured in weeks.

The failure mode is just as old. Avery Pennarun makes the point plainly in his treatise on bug tracking and triage. Bugs pile up when filing outpaces fixing. Declaring bug bankruptcy doesn’t change the slope of that line. Every engineer I know has worked in a tracker where the honest read on most open issues was that nobody would ever look at them again. We tolerated it because the alternative was forgetting, and forgetting felt worse.

The second thing we used trackers for was breaking work apart. The vocabulary comes from the agile world. Mike Cohn defines an epic as, simply, a large user story, one you decompose into smaller stories when a team is ready to work on it. Big thing arrives, big thing gets chopped into two-week pieces, pieces get distributed across people, tracker becomes the coordination surface. That’s project management wearing an issue tracker as a costume, and for humans it works well.

Both of those jobs assumed constraints that agents removed. We spent the last few weeks stress testing that, finding out which parts of the practice were load bearing, and came out the other side with a different idea of what a tracker is for.

The Follow-Up That Doesn’t Need to Wait

Start with the follow-ups, because that’s where the pain showed up first.

Our code reviews are agentic. We run Greptile on every pull request and I’ve been genuinely happy with what it catches. An agent reads the diff against the project’s own conventions and writes up what it finds. The good ones find real things. A missing test case, an error path that swallows a failure, a helper that should have been extracted. Under the old rule, each of those became an issue. Faithful record keeping, and a queue that grew every single day.

What we’re experimenting with now is skipping the record entirely. When the review turns up a follow-up, the reviewing agent forks its own context into a subagent and hands it the problem immediately. The fork inherits the conversation that produced the finding, so it already knows the file, the convention that was violated, and why the reviewer cared. It goes off and opens its own pull request while the original review continues uninterrupted. If the pull request that spawned it hasn’t merged yet, the fork stacks its work on top of that branch.

The economics are almost embarrassing. Writing a good issue means describing context that is already loaded in the window right in front of you. Then, later, some other agent pays to rebuild that context from scratch by re-reading the same files and re-deriving the same reasoning, assuming anyone ever picks the issue up at all. Forking the context costs a fraction of that and produces a pull request instead of a promise. It reuses the cached context from the original thread, which saves real money and skips the whole bootstrapping conversation. The cache is already warm. The reasoning is already done.

I want to be careful not to oversell it. This doesn’t work for everything. Some findings send me off to do research first. Some need me to sit with the consequences, or go take a walk and figure out how I actually want to handle the situation. Some need a conversation between me and Chris about whether a feature is the right fit for the product at all. Those still get filed, and I’ll come back to what that queue looks like now. But the default flipped. Filing an issue used to be what you did with a follow-up. Now it’s what you do when the follow-up needs a person to think first.

Epics Assume a Constraint That Left

The second habit took longer to give up, because breaking work into pieces feels like professionalism itself.

An agent can produce a five thousand line pull request in ten minutes. When that’s true, the reason for chopping a large feature into eleven tracked sub-issues mostly disappears. You weren’t decomposing because the work was inherently separable. You were decomposing because a person can only hold so much in their head at once, because a sprint is two weeks long, and because four people needed to work in parallel without colliding. Those are real constraints. None of them are the agent’s.

This is not an argument against testing, or against reviewing carefully, or against building a large feature in stages you can actually validate. Every one of those matters more now, not less. Simon Willison put it well recently. Using agents well takes two skills, instructing them clearly and verifying that what came back is right. He also points out that eyeballing every line was never the best way to do the second one. The chunking that survives is the chunking that helps you verify. The chunking that dies is the chunking that existed to schedule humans.

The testing instincts I picked up early in my career are paying dividends now more than ever. I can load our project into a browser inside the coding agent and start poking at it. When something behaves wrong, the agent is sitting right there with the context already loaded, so I can just ask about it. I can drive the thing from the terminal and then go verify what actually happened in my local database or against my local copy of the service. None of that is new. It’s the same work I’ve been doing for my whole career, and agents didn’t change it.

So we stopped using issues as project management. The agent doesn’t need a burndown chart, and neither do the two of us. We did try. We briefly put the work into a GitHub project built on our issues, kanban columns and all. It fell out of date faster than either of us was willing to maintain it.

Aspirational Issues Are a Trap

The third category is the one I’d defend the longest and was most wrong about. “Someday we should support real-time collaboration.” “It’d be nice if this thing had a plugin system.”

An agent cannot reliably act on an issue like that. It doesn’t have the product context, the customer conversations, or the constraints that would make one implementation right and another one a waste of a week. What it has is enough capability to build something confidently, quickly, and wrong. Aspirational issues are the ideal input for producing exactly that.

Worse, they poison the queue around them. If a tracker is a work list something else pulls from overnight, every unbuildable item in it is a small trap laid for a system that can’t tell the difference. Those ideas are still worth keeping. They just belong somewhere that isn’t the tracker: a document, a spreadsheet, a future-features markdown file checked into the repo. Somewhere a person browses on purpose, rather than somewhere an agent shops.

What Actually Belongs in the Tracker Now

Here’s the test we use. Could a cheap, fast model with the repository’s context in hand fix this tonight, correctly, without asking me anything?

I mean cheap literally. Sonnet 5, Gemini Flash, GPT Terra. If the issue is well defined and the project’s conventions are written down where an agent can read them, the frontier model isn’t buying you much. That’s a strong forcing function on how you write the issue. It’s also the same forcing function that made issues good for humans.

Three kinds of work pass the test. Bugs I found while using the product away from my desk, which I can describe well because I just watched it happen. Most of those reach the tracker through a feedback path rather than through my hands, and the nightly reflection that turns them into issues is a post of its own. Follow-ups from review that resisted being forked. Small features that are well scoped, well understood, and simply not a priority this week. That’s it. Everything in the tracker is something a low-cost agent could pick up and drive to a pull request, prioritized so it knows which one to pick.

We have a pipeline that does exactly that. It doesn’t wait for night. It runs continuously, picking up whatever is ready whenever it becomes ready. That’s the next post in this series, and it’s the reason the discipline in this one matters so much. A pipeline that works through an unfiltered backlog is a machine for generating plausible garbage at scale.

I’m also experimenting with a task that sweeps every issue opened during the week and spawns an agent to fix the ones that qualify. That habit is new enough that I don’t know yet whether the tracker ever actually reaches empty.

Where the Big Work Goes Instead

None of this means we stopped doing big things. It means the big things stopped living in the tracker.

For a substantial feature, I work with an agent to write a product document first. That might be a short document, a mock, or a piece of a design system, whatever makes the idea concrete enough to argue about. Then Chris and I talk it through until we agree it’s actually right for the product. Only then does it become the input to a technical design document, which gets reviewed the way any other design gets reviewed and then checked into the repository alongside the code. After the design doc lands we create an issue, and the issue says one thing. Implement this design.

That issue is not food for the overnight pipeline, and it’s labeled so the pipeline leaves it alone. It’s a marker. It exists so that a person sitting down with an agent has a place to start, and so both of us can see what’s planned but not yet built. When someone picks it up, the first move is to point the agent at the design doc for context, and then build the feature end to end. Not in phases the issue dictated in advance, because an issue written before the work started is a bad predictor of how the work will actually decompose. In reasonably sized chunks of working functionality, with a lot of manual testing along the way, laddering up to the whole thing. That doesn’t mean one enormous pull request either. I’m about fifteen pull requests into a feature right now, several days of work, all of it pointed at a single issue.

The design document does the job the epic used to do, and does it better. It holds the reasoning, not just the task list, which is what an agent needs to build something faithfully. And it’s version controlled next to the code it describes, so it goes stale visibly instead of quietly. We have an agent that runs nightly to compare the claims in those documents against the code and update the ones that have drifted, which is a story for another day.

Taking Inventory

Last week I stopped adding and took inventory instead. 300 open issues on that same repository, every one of them read against the actual code rather than against its own title, then sorted by what it would really take to close.

15 were already dead. Fixed by some other pull request, obsoleted by a decision we’d since made, duplicated, or never actionable in the first place. 54 were real work an agent could simply do, so I let it. The sweep spawned subagents in waves and merged 54 pull requests over the following days. That’s 69 issues, most of a quarter of the backlog, that a machine could resolve without me in the room.

The rest is the part that stuck with me. 101 needed a decision from me. 54 needed one from Chris. 67 were epics or deliberately parked, and I left them alone on purpose. Three quarters of what we had filed wasn’t work at all. It was a queue of decisions wearing work’s clothing, and it had been sitting there looking like a backlog the whole time.

That number moved me further than any argument in this post did.

Three Jobs Instead of One

What we’ve landed on is a tracker with three purposes. It holds things we found and can’t fix right now but an agent can fix later. It holds pointers to planned work whose real content lives in a design document. It holds the follow-ups from review that weren’t worth forking a subagent to solve on the spot.

Look at what fell out. The tracker stopped being a filing cabinet for human memory. Everything in it is now addressed to a machine that will read it, act on it, and open a pull request. That makes an issue much closer to a function call than to a note to self. I’ve argued before that prompts are code and deserve the same rigor. An issue an agent will execute is the same claim, arriving from a direction I didn’t expect.

The part I’m still sitting with is how much of my old practice was compensation. Filing a bug so I wouldn’t forget it. Breaking an epic into pieces so a team could carry them. Keeping a wishlist because writing it down felt like progress. Those were all coping mechanisms for being a human with one pair of hands and a bad memory. I still have both of those things. I just have fewer reasons to build my tools around them.

Next time, the pipeline that works through this queue on its own, and what happens when it wanders into a public repository and starts talking to strangers.

An empty, glowing chat window floating apart from a cluster of worn analog interface objects like a door handle, light switch, and rotary phone, rendered as a warm painterly illustration.

The Chat Box Is a Detour

When ChatGPT launched in November 2022, we got a simple chat window, following a few months behind Google’s own preview of LaMDA 2 through AI Test Kitchen at Google I/O 2022, itself a chat window layered over a model. Type something in, get something back. That was the right call, and not because anyone had done deep interface research. A transformer model is trained to do one thing: predict the next token given everything before it. Feed it a prompt, get a completion, feed it more, get another. A chat window is close to the most direct expression of that loop made visible. It was an honest match for what those models were good at, an admission of what the technology could do yet, not a considered design choice.

Models have gotten more capable and efficient since, and what we ask of them has gotten far more complex. Somewhere in that gap, the chat window stopped being an honest match and became a habit. We have spent the years since watching agentic AI show up everywhere: code editors, browsers, the operating system itself, the enterprise tools people already had open. Through all of it, we kept handing people the same box. Our reluctance to move past it is a real drag on adoption, and it is one of the bedrocks of our point of view at Vycari.

Anyone who works in this technology every day already knows a specific version of this problem: the blank box itself is hard. Staring at an empty chat window and guessing how to phrase what you want, what the agent can do, which words trigger the behavior you’re after, is its own skill. It is hard for people who spend all day in this field. It is much harder for someone who does not, who has no reason to have built a mental model of what an agent can do from looking at an empty rectangle.

My co-founder Chris Perry made a version of this same argument last week, coming at it from adoption and product history rather than the interface argument here. Ours is a two person company, and we did not coordinate this; we just keep running into the same wall from different angles. It is part of why I like building with him: he thinks about a problem from the side I don’t, and by the time we compare notes we have usually converged without meaning to. His post is worth reading alongside this one.

Agents outgrew the box

Last January I wrote about how everything becomes an agent; the argument underneath was really about decision making. An agent earns its keep when the input is hard to predict ahead of time, when the alternative is branch logic encoding what a developer guessed the user would need, written months before that user showed up. Treat an agent as a piece of your program that makes the call in the moment, with the actual input in front of it, and it looks like a much bigger part of how software gets built than a chat window would suggest.

None of that requires typing into a box. An agent deciding which tool to call inside a checkout flow, a support queue, or a scheduling tool does not need a text field to do its job well. In a lot of what we build at Vycari, the agent takes a backseat to the interface on purpose. Nothing beats a solid interface that is familiar and delightful to use, and an empty chat box waiting to be filled is neither of those things for most people.

Chat is the hobbyist’s interface

I wrote a few weeks ago about why not everyone wants a hobby, and this is where that argument meets this one. A chat interface rewards people who already know how to prompt, who enjoy the back and forth, who get a small thrill from coaxing a good answer out of a model. That is real and worthwhile. It is also a hobby, and most people do not want one. They want the thing handled.

This is not a new problem for our industry. Unix was a command line. So was DOS, VMS, Ultrix, and SunOS, the whole family of operating systems that ran the serious computing of their era. Knowing the right incantation, the right flags, the right order of operations was a hobby in its own right, and it kept computers in the hands of people willing to learn that hobby. The graphical interface Xerox PARC prototyped, and that the Macintosh and then Windows brought to everyone else’s desk, did not make computers more powerful. In most ways it made them less flexible than a shell. What it did was let someone finish a task without first learning a syntax and a vocabulary of magic commands, as Chris put it. Nobody wants to read a manual to cross the next thing off their list. That was true of computing in 1984, and it is true of agents now.

Look at the products getting the most attention right now, open source projects like OpenClaw and Hermes, or the frontier lab flagships like Gemini Spark, Claude Cowork, and ChatGPT Work. Nearly all of them are built on the same premise: you will chat with the agent. My own Gemini Scribe started the same way, a chat window bolted onto Obsidian. Sometimes the chat happens over voice instead of text, but underneath the voice layer is the same box, just one you talk to instead of type into.

Meeting people where they already are

I do not think most people want to learn a new modality to get value out of AI, and I do not think they will, even though some of us genuinely enjoy it. Agentic AI is a shift on the scale of the ones we have already lived through: personal computers, the internet, the web, mobile, and now AI. I made a version of this list once before, and each of those transitions asked people to change how they worked. The ones that won met people with an interface they already understood, not the ones that made them learn a new vocabulary first. I want to be careful here: I am not arguing for skeuomorphism, for software that pretends to be the paper or the switch it replaced. I am arguing for good, intuitive design, interfaces that borrow the mental model people already carry and build the new capability on top of it. Every time this industry has moved toward a more familiar interface and a design language people already recognized, it created more value, not less, because it stopped spending people’s attention on the tool and let them spend it on the task.

That is the standard I want agent products held to. Not “does the model perform,” because at this point almost all of them do. The question is whether the software finds you where you already are, understands what you are actually trying to accomplish, and gets you back to your day.

Did you have to come back

Early in my career at Google, one of the metrics we watched for search was whether you came back. If you searched, clicked a result, and never returned, that meant you had found what you needed and moved on. I think agents deserve the same measurement. Did you get the thing done? Did you have to come back and try again? The best outcome is that you do not come back, not because the product failed you, but because you already had what you wanted and were on to the next thing.

In our own applications at Vycari, that translates into something concrete. It means the agent understood the request on the first try, without a round of clarifying questions, without asking you to drop into a chat window to add detail it should already have had. Better still, it means the agent acted on your behalf and you never had to watch it happen. In my ideal world, people using what we build will know this is agentic AI about as much as they know it is written in Python: not at all, not because we are hiding it, but because it will not be a fact that matters to them.

We should not be building toward the box. We should be building toward wherever the user already is, and toward what they are actually trying to get done. Agents are not a hobby. They are here to help people get through their day, and the sooner our interfaces act like it, the sooner more people will actually use them.

A laptop on a dark desk with thousands of small glowing blue points of light rising from the screen and spreading outward like a constellation, connected by faint threads, with a small bright cluster near the screen and the rest fading into darkness.

Thousands of Goodbyes

There is a problem with leaving a job you held for twenty one years, and nobody warns you about it. You cannot remember who you worked with.

Not in the sense of having forgotten them. In the sense that the list does not exist anywhere, including in your head. I left Google earlier this month after twenty one and a half years across Search, Maps, ads, mobile, Core, Core ML, and DeepMind, in roles that ranged from running large organizations to writing code with three people. Somewhere in there I met, argued with, mentored, was mentored by, shipped alongside, and occasionally annoyed several thousand people. When I sat down to write my goodbye note, I could produce maybe a hundred and fifty names from memory, and I knew with total certainty that the hundred and fifty were wrong. They were the recent ones and the loud ones. The person I had one extraordinary conversation with in a London conference room in 2008 was nowhere near that list.

This is the sort of problem that used to have exactly one answer, which is that you accept it. There is no roster of everyone who mattered to you, no internal system that will hand you the list. What you actually do is type out the names you can think of, send the note, and add a line asking people to please forward it to anyone you missed. It works, in the sense that something gets sent. It is also a sloppy solution that quietly hands the entire decision to your recency bias. The people you saw last month get a goodbye. The people who changed how you work, fifteen years ago, on a team that no longer exists, do not.

I did not want to accept it. So I did the other thing.

Letting the machine do the remembering

The tool I reached for was Antigravity, paired with the Google Workspace MCP server I had originally built as a Gemini CLI extension. That extension exists because I wanted my terminal to be able to see my calendar. It turns out that giving an agent access to your mail and calendar for ordinary convenience also gives it access to the complete archaeological record of your working life, which is not something I had thought carefully about until I needed it.

The first pass was mail. I had the agent go through twenty one years of sent messages and pull out every address I had ever written to individually. Not mailing lists, not the thirty person threads, not the announcements. One to one mail, or close enough to it, on the theory that if I had bothered to type your name into the To field, we had a relationship worth closing properly. That produced a very large and very stale list, because a lot of those people left Google years ago. So the second pass compared the addresses against an internal directory and kept only the ones still active, which cut it down considerably and also produced a small, unexpected inventory of people I had lost track of.

The second source was calendar. Mail catches the people you write to, but it misses the ones you only ever talked to in a room. So the agent went through twenty one years of my calendar looking for anything that was genuinely a one to one: a recurring weekly, a single mentoring session someone booked in 2017, a skip level, a coffee that got a calendar entry because that is how Google works. Every one of those has a person on the other side of it, and a surprising number of them never once appeared in my sent mail.

Then it merged the two. I had expected this to be the hard part and it was not, for a boring reason: Google email addresses are stable. People change teams constantly and the address follows them, so deduping on the address alone does nearly all of the work. What I was not prepared for was reading the result. Whole eras came back. I would hit a cluster of addresses and remember an entire project I had not thought about in a decade.

The last problem was purely mechanical and almost funny after all that. Gmail will not let you put several thousand addresses on a BCC line. The agent did not raise this, which is worth saying in a post that is otherwise about how capable these things are. I had to notice it and ask. Once I did, it split the list into batches that fit under the limit and drafted the same message across all of them, and I sat there and hit send, over and over, until the list was gone.

What came back

I expected silence. You send a goodbye to someone you shared one project with in 2011 and you expect it to land in an archive folder, if it lands anywhere.

One person wrote back to tell me, politely, that he had no idea who I was. I liked that reply enormously. I assume he was not the only one who felt that way and just the only one honest enough to say it, and I would rather have sent that mail and been forgotten than not sent it at all.

But most of what came back was not that, and the volume of it caught me completely off guard. A solutions engineer in Japan wrote about a Street View collaboration with Nintendo that had been his very first project at Google, and told me I was probably the first real engineer he ever encountered. We were born the same year. He had turned fifty a month earlier and was finding the number about as strange as I am. Someone I managed for only a few months thanked me for trusting him and called it one of the most engaging windows of his career. A former colleague opened by saying he had just been telling someone we both used to work with how much he missed working with me, and then reported that he still has not gotten his motorcycle license because his friends staged an intervention dinner about it. A director in Munich offered a beer if I ever make it back and reminded me of work we did together that I had honestly stopped thinking about. Someone I have known for close to twenty years said he had been meaning to call, and instead of trading contact details we ended up at lunch off campus the following Friday, which is the best possible version of what one of these notes can do.

That is the part I keep turning over. Not one of those replies exists if I send the note from memory.

A hundred and fifty, the number of names I could produce on my own, is roughly Dunbar’s number, the size of a stable social group a human can actually maintain. I do not think that is a coincidence, and I have stopped treating it as a personal failing. My recall of my own career landed almost exactly where the research says it should, which means the ceiling was never effort or affection. It was architecture. Twenty one years builds a network many times larger than the one a head is designed to hold, and the overflow is not forgotten so much as never retrievable in the first place. The agent was not being clever here. It simply was not subject to the constraint.

The people who wrote the most moving things back to me were, almost without exception, the ones my brain had not surfaced. They were on the list because software read my calendar from 2013 and did not care that it was 2013.

The gap this points at

I have spent two years writing about what agents can do, and most of my examples have been about work. Code, pipelines, research, the machinery of building software. This is the first time I have used one for something that was purely about people, and it is the only agentic project I have run where the output made me feel something.

It is also, and I want to be honest about this, a completely unreasonable thing to ask a normal person to do. To get here I needed an agent platform, an MCP server I wrote myself, OAuth credentials, a working mental model of what a tool call is, and enough patience to iterate on the approach a few times when it came back wrong. The capability was extraordinary. The cost of access was absurd.

That gap is the whole reason I am doing what I am doing next. I wrote last week that using agents today is effectively a hobby, and this is the cleanest example I have of why that matters. Everyone leaving a long job has this problem. Almost nobody gets to solve it, because solving it currently requires you to invest in the hobby first. Closing that distance, so that an ordinary person on an ordinary Tuesday can ask for something like this and simply get it, is the work.

Twenty one years of colleagues got a goodbye from me because software remembered what I could not. I would like that to be an unremarkable thing to say.

And to everyone who wrote back: I replied to every thread I could, and I am sure I still missed some. I want all of you to know how deeply your words and your wishes landed. Thank you for that.

An overhead illustration of a cluttered hobbyist workbench with soldering iron, parts drawers and a notebook of diagrams, and a single plain phone resting apart from it all at the edge of the bench.

Not Everyone Wants a Hobby

Yesterday I wrote about leaving Google after twenty one years and said there was a next chapter I would tell you about today. This is it.

Chris Perry and I are starting a company. It is called Vycari, we are building agents, and we are looking for people to test what we make. I want to spend most of this post on the problem rather than the product, because the problem is the interesting part and because the product is not ready for you yet.

Using agents today is a skill

Here is what it currently takes to get real value out of an agent.

You curate your skills, your triggers, and your extensions. You pick the right model for the task and make sure it is wired to the right API key. You keep the right software installed and updated on your machine. You have a sandbox configured, because obviously you have a sandbox configured. You learn which failures are the model’s fault and which are yours. You read changelogs, because the thing you learned last month is already wrong.

That is not using a tool. That is adopting a hobby.

I want to be careful here, because I do not mean that as a complaint. There is nothing wrong with AI as a hobby. A great many of the real sea changes in personal computing were driven by people who treated the work as an avocation first and a profession second, and the current moment is no different. I count myself among those people. They are my people. This blog exists because of them, and I am not going to stop writing for them.

But it is worth being honest that this is what we have built so far, and about who it excludes.

Most people do not want a hobby

Not everyone wants their tool to become a pastime. Not everyone wants to marvel at the stack, or to feel the small thrill of watching software take an action in the real world on their behalf. Plenty of capable, curious, technically fluent people simply want to get something done, and they want to use whatever makes that easiest.

I am friends with a lot of these people. They are not incurious and they are not afraid of technology. They carry a supercomputer in their pocket and use it fluently all day. They have just never been given a reason to believe that an agent is for them, because every agent they have encountered asked them to become a hobbyist first.

Chat apps are the exception that proves the point. They reached enormous audiences because there was nothing to adopt: you type, it answers, and the entire interface is a thing you already knew how to use. Step outside that box and agents are still close to magic for most people, and magic is not a compliment when you are trying to get through a Tuesday. Agent products remain genuinely hard to use, and the difficulty has very little to do with how good the models have become.

What I keep coming back to

The most useful thing I learned in two years of building agents has almost nothing to do with models. It is this: people do not bounce off AI because it is not smart enough. They bounce off because the cost of using it, all of it, the setup and the vocabulary and the remembering to go there, is higher than the problem they were trying to solve.

Which means the frontier I find interesting is not making these systems more capable. They are already more capable than almost anyone is extracting value from. The frontier is closing the enormous distance between what the technology can do and what an ordinary person can actually get out of it on a normal day, without a new app, a new habit, or a new hobby.

That gap is not a model problem. It is a product problem, a reliability problem, and a taste problem. It is also, as far as I can tell, wide open.

What we believe

We are early enough that I would rather tell you what we intend than what we have built. Four things we are holding ourselves to.

Meet people where they already are. If using the thing requires a new destination in someone’s day, we have already lost, no matter how good it is once they arrive.

Earn the trust the access requires. An agent worth having needs to see calendars, mail, and contacts, which is about as intimate as software access gets. There is no version of this business where that access to private data becomes an advertising product, and there is no version where you cannot take your data and leave.

Never make you learn our vocabulary. Nobody should have to know what a skill is, or which model answered, or that any of this is AI at all. Those are our problems. The user’s problem is that they asked for something and want it handled.

Be warm about it. An assistant you find pleasant is one you will actually use, and an assistant you actually use is the only kind that matters.

Who we are

My co-founder is Chris Perry. He is the CEO. I am the CTO. Chris used to report to me, and putting him in the CEO seat was one of the easier decisions either of us has made.

We have been circling each other for about a decade. We met when I was running Street View and imagery inside Maps and he was a PM on Google Photos, back when our two teams were trying to make those products understand each other’s pictures. Years later he turned up in the AI Developer organization I was running, as the product lead for Colab. Most recently we were both on the founding team of Gemini CLI and shipped its Workspace extension together. Somewhere in there he stopped being someone I had worked with and became someone I wanted to build with. He is writing his own version of this announcement, and his path here is different enough from mine that you should read both.

It is just the two of us right now, and we are both in the codebase. One of the underrated pleasures of leaving a large company is that you get to assemble the org chart from scratch, based on who is best at the job rather than on who has been there longest.

The part where I ask you for something

Twenty one years at Google taught me how to build systems where the hardest problems are problems of coordination. This is a different kind of hard. There are two of us, the feedback loop is measured in hours, and the person on the other end of a failure is someone who trusted us with something that mattered to them. I have not been this uncomfortable in a long time, and I have not enjoyed work this much since 2008.

We are opening to testers in the coming weeks, a few at a time and deliberately, because the failure I am most afraid of is someone relying on this and being let down. If you would like to be in that first group, put your name down here. What we want back is your honest experience, particularly the parts where it does not work.

And if the person who came to mind while you were reading this was not you but someone else, someone who would get enormous value from an assistant and would never in their life go looking for one, then you have understood exactly who we are building for.

I will keep writing about the engineering here as we go. It is going to be a good year.

A clean workspace at night with a glowing laptop screen, smart ring, smart glasses, and a starry sky outside.

Reading List 8

This week’s reading list explores the shifting paradigms of personal software development, the evolving dynamics of managing AI agents, and the frontier of ambient hardware. From the realization that managing agents is deeply adjacent to engineering management, to building custom tools without writing a line of code, these articles highlight how rapidly our relationship with computers is changing.

Managing agents requires the same skill set as managing human engineering teams

[blog] Understand to participate. Geoffrey Litt’s framing from the AIE World’s Fair on collaborating with coding agents is spot-on. He argues that we must understand the code to a depth that enables us to participate further with the model, avoiding taking on cognitive debt as our understanding drifts from the actual implementation. I think this is absolutely right, and it points to why people with management experience may actually excel in a fully agentic world—an idea I explored late last year in Unlocking AI Success: How Managerial Skills Can Help You. If you have managed an engineering team before, you already know that you cannot be deeply familiar with every single line of the codebase. Instead, you understand how to build a high-level conceptual model that lets you guide and make meaningful contributions through your employees—or, in this case, your agents.

Securing public-facing LLMs against prompt injection is becoming a practical science

[blog] What happened after 2,000 people tried to hack my AI assistant. Fernando Irarrázaval’s write-up on defending his AI assistant from prompt injection is a masterclass in practical security. As we move from isolated sandboxes to public-facing agentic workflows, the threat of prompt injection becomes a first-class engineering concern. It is incredibly encouraging to see this defensive engineering maturing into a rigorous, practical science with real-world data rather than just hypothetical panic.

We are entering a golden age of bespoke, personal software

[article] Claude redefined my bond with Macs. I am building my own apps and it’s a bliss.. This piece from Digital Trends is more evidence of the rapid onset of what I call the “personal software” era. The author, who doesn’t know how to code, describes building fully functional, offline menu bar utilities, image mockup editors, and custom word processors with Claude inside of a few hours. When the friction of translating intent to code drops to zero, we stop downloading generic software and start building bespoke tools tailored precisely to our quirks—a theme I wrote about in Building Personal Software: Crafting Your Own Tools for Success. It is a profound shift in how we interact with computers.

Tracking the relentless march of the AI goalposts over four years

[blog] It Still Can’t Do My Job: Four Years of Moving Goalposts (2022–2026). This is a delightful walk down memory lane, cataloging the shifting skepticism from the launch of ChatGPT in late 2022 to the state of the art in 2026. It is highly entertaining to look back at the “goalpost graveyard” and see how quickly criticisms like “it can’t even write Snake” or “no real developer will use it” transitioned from conventional wisdom to historical footnotes. It’s a healthy reminder of just how fast the baseline is moving underneath us.

The physical interface of computing is shrinking to our fingers

[tool] Productivity, without the keyboard.. The Oasis smart ring is a fascinating look at the future of ambient input. By packing a touchpad and private voice input via a noise-isolating microphone into a ring, it aims to let you capture thoughts and interact with assistant systems without being glued to a keyboard or screen. As voice-to-text engines like Whisper become incredibly low-latency and accurate, the hardware we use to feed them is shifting from heavy screens to subtle, wearable devices.

A smart telescope near a window pointing at stars next to a desk with a glowing laptop and a handheld gadget.

Reading List 7

This week’s reading list spans from the outer reaches of the night sky to the inner mechanics of our development environments. I found myself thinking a lot about physical and digital boundaries, whether stargazing through light pollution, sandboxing database state, or trying to understand where the corporate hype around AI token burns and layoffs actually leaves the rest of us.

[article] Our Galaxy Looks Absolutely Stunning in These Award-Winning Dark Sky Photos. Gizmodo’s gallery of award-winning dark sky photography is a breathtaking reminder of what lies beyond our light-polluted horizons. As someone with a casual interest in astronomy, these images make me want to pack up my gear and head out to the desert immediately.

[article] With the Vespera III and Vespera Pro 2, telescope-maker Vaonis unveils its sharpest optics yet. I have been keeping a close eye on Vaonis’s smart telescopes for a while now. Living in an urban area with heavy light pollution, I am highly skeptical of how much actual stargazing I would get done, but that does not stop me from desperately wanting one of these. The optics on the new Vespera III and Vespera Pro 2 look incredibly sharp.

[release] Launch HN: Ardent (YC P26) – Postgres sandboxes in seconds with zero migration. This is a compelling approach to a massive pain point. Live database testing is currently one of the highest hurdles for agentic software and autonomous coding. In my recent work building a scoreboard for Gemini Scribe, I spent a lot of time writing state-based assertions to confirm the agent didn’t nuke sibling files. Doing that for database mutations is infinitely harder without a lightweight sandbox. Ardent’s promise of instant Postgres replicas with zero migration is something I will be testing immediately.

[release] Flipper unveils a Linux-powered networking gadget built for hackers and tinkerers. This sounds like a delightful piece of hardware. I have a Flipper Zero and have thoroughly enjoyed experimenting with it, but this Linux-powered networking gadget looks like it has significantly more practical utility. It is a neat little box built for hackers and tinkerers that actually fits into a standard sysadmin toolkit.

[article] Ubers COO says its getting harder to justify the money spent on AI tokenmaxxing. Uber’s COO is pointing to a growing frustration in enterprise AI. The industry has fallen into a pattern of tokenmaxxing, where companies compete on how many millions of tokens they can burn through. As I discussed when designing the tool budgets for my Gemini Scribe scoreboard, efficiency should be a primary metric. Leaderboards that celebrate massive token usage incentivize sloppy engineering. We should be optimizing for the middle of the distribution, not cheering on the most wasteful implementations.

[article] Samsung’s OLED tech gives the Ferrari Luce a dashboard unlike anything in a car before. The custom displays in the Ferrari Luce are a stunning application of Samsung’s OLED technology. While the vehicle itself is a concept, the underlying display engineering feels like a preview of how we will interact with glass surfaces in the near future. It is a highly impressive piece of design.

[article] Jensen Huang Just Told Every CEO Hiding Behind AI Layoffs to Shut Up. A sharp analysis of the narrative around AI-driven layoffs. Jensen Huang’s blunt perspective cuts through the corporate excuse-making. This digs into the same questions about who benefits from AI disruption in the workforce that I have been wrestling with lately. It is a must-read for anyone trying to understand the macroeconomic reality behind the hype cycle.