BUILDING · AGENTS

Building CP Buddy with Droid, from an hour of watching to a day of not

Originally published on Medium ↗
Contents

Making practice easier to start

Competitive programming used to be a much bigger part of my routine when I was actively competing. After I started working full time and stopped competing seriously, keeping a consistent solving routine became much harder.

The friction was usually in starting: decide to practice, open Codeforces or AtCoder or wherever, find a suitable problem, prepare my environment, then finally solve. None of that is hard, but it’s often easier to just keep doing whatever I’m already working on. I’ve heard the same thing from friends who stopped competing seriously.

CP Buddy started as an idea to reduce that friction. For the MVP, I reduced it to a simple workflow: give me a suitable problem I haven’t solved before, start a focused solving session, and detect when I get it accepted.

When Omarchy Quattro launched with its plugin competition, that gave me the idea of making it the starting point for CP Buddy. I could participate, explore a new area, and have fun at the same time. I knew it was too niche for the competition and probably wouldn’t compete with the other amazing plugins the community had built, but I felt like: why not have fun building something I actually want? Instead of another app I have to remember to open, it’s a couple of clicks, and it looks really cool!

It also became my first proper Droid experiment. Omarchy plugins were new territory for me, so I wanted to use a real project to see how well Droid could help me through the full process: researching, planning, iterating on prototypes quickly, and finally shipping before the deadline.

CP Buddy in OmarchyAnimation plays only when you choose.
The first released CP Buddy plugin running in Omarchy — See on GitHub

Building the first version with Droid

I knew what an Omarchy plugin looked like from the outside, but I had no experience building one.

I pointed Droid to the guides for developing and submitting plugins, then gave it a strategy instead of a feature list: get the smallest real plugin running inside the system first, even if it barely does anything, then build on top of something we already know works.

That turned into a series of small steps: build the plugin’s foundation, get the Codeforces integration working, connect it to the UI, add the solving sprint timers, then detect accepted submissions to end the sprint.

Droid handled most of the unfamiliar implementation details while I was having fun watching it explore examples and coordinate work across agents. That left me spending more time experimenting with the actual plugin, deciding what direction I wanted to take it in, and noticing what would make me actually use it. It took about 49 minutes of active Droid work to get the first full loop working.

After that, most of the improvements came from actually using it: timer presets, tiled and floating modes, UI details, and local history so it stopped recommending problems I had solved long enough ago that they had fallen out of the recent-submissions window.

I could start with the product itself, see it working, and decide what I wanted from it before I had to know anything about QML.

Shipping it exposed what the spec had missed

Getting the first working version was the easy part. Using it like a real plugin exposed the more interesting problems.

A nonexistent Codeforces handle could leave the UI waiting forever. A helper process could get stuck without a deadline. If something crashed during an active sprint, the error path still had to preserve enough state for the session to continue correctly.

At that point I started seeing the cost of me rushing through the prototype. A few missing cases were enough to leave the plugin hanging or break the state of an active session.

I had specified the successful flow much better than the failures. That’s survivable when the cycles are short and I’m watching, especially during the first iterations when I’m still exploring the idea. But once I wanted something I could actually publish in the marketplace, I couldn’t keep relying on myself to notice those cases afterward.

The next specs had to make those cases part of the task itself.

Not every step needs the best model

I was already hitting Droid Pro’s usage limits, so running the strongest available model for every task didn’t make sense. I started relying on cheaper models through Droid Core for most of the work.

Those cheaper models are very good when I’m working on scoped or lightweight stuff, but for decisions and planning I still wanted a stronger model in the loop.

I didn’t want that to ruin the Droid experiment, and since I already had a separate Codex subscription, I added a /consult-codex skill. Droid could keep coordinating the task and ask Codex for a second opinion on architectural or design decisions when it was worth it.

The pattern I liked throughout that build was using cheaper models for exploration and implementation, stronger reasoning for design decisions, and keeping verification with the parent Droid session.

Giving Droid something too big to watch

A couple of days later I wanted to see what Droid Missions actually did differently from the “Goal” modes I had tried in other agents.

So I gave it a much bigger spec and deliberately planned to steer as little as possible. I wanted to see how far it could go on its own. Droid recommends using a flagship model like GPT or Opus as the orchestrator, but me not having enough quota to keep that running for the whole Mission, I leaned on cheaper models to keep it moving.

Before implementation, I asked the orchestrator to consult Codex during the architecture planning and initial docs generation. It did, organized the work, and then I left it running and went to sleep.

When I came back, a big chunk of the work was already done, but the Mission eventually got stuck. At first I thought that was probably the end of the experiment. I left it for a while, then interrupted the run and tried to see what “resume” actually meant.

I expected it might start over, or at least lose a lot of progress. Instead, it looked at the logs, docs, and current repository state, then continued from around where it had stopped.

That was the part that made the long run feel different to me. I wasn’t continuously steering it, and an interrupted request didn’t mean throwing away the Mission state.

The full run ended up doing about 23.6 hours of active Droid work across roughly a day and a half.

Droid Mission progress for the CP Buddy web companion
22 hours into the CP Buddy web Mission.

What I put in a spec now

For the next Mission sessions, I’m going to spend much more time on the spec before pressing go.

With short interactive turns, I can leave parts vague and correct them as I see the result. That gets much more expensive when the task keeps running for hours. I need to have a much clearer picture of the end state before I hand it over.

I started keeping a small checklist for that:

  • Do I actually know what I want to end up with, or is this still a research task to explore different shapes of the idea?
  • What should the whole flow look like when everything goes right?
  • What failures would ruin the experience, add enough friction that I don’t like the result, or make me consider the run disappointing?
  • What can the agent verify by itself while it’s working to make sure it’s still going in the right direction?

I expect that checklist to keep changing as I run more experiments and notice what I forgot.

Where CP Buddy is now

The Omarchy plugin is live on the marketplace, which I’m pretty happy about. I use it myself, other people can try it in a couple of clicks, and I already have a long list of things I want to add before I’d call it a proper daily companion.

The web companion is still private while I refine the core experience and figure out how it should work alongside the plugin instead of being tied only to Omarchy.

I’m getting more comfortable giving long-running agents ideas to work on while I’m busy with something else. I even set up Droid on my dev VPS so I can start a task there and check on it later from wherever I am.

I’m still not completely comfortable merging code I haven’t read. For non-critical experiments, though, I’m becoming more willing to accept that gap while I look for ways to trust the process more.

I don’t really know what the optimal version of this workflow looks like yet. I think the only way I’m going to find out is to keep trying it, notice where it sucks, fix one part, and repeat.

Links: CP Buddy on GitHub · Omarchy plugin page