DEV Community

Kiell Tampubolon
Kiell Tampubolon

Posted on

Three PRs to Rowboat in 24 Hours, One of Them Taught Me More Than the Others

Last month I wrote about how I use coding agents to build things. This week I pointed the same setup at someone else's codebase. Rowboat (rowboatlabs/rowboat, 17.5k stars) had its good first issues picked clean, so I had to work for it a little.

What I shipped

Three pull requests in about a day:

  1. PR #1031: the sidebar Meetings subtitle showed an all-day event next week as if it happened today, masking a timed event that was sooner. Root cause was a sort that put all-day events first regardless of date, duplicated in two components. Fix: sort purely by start time, and give future all-day events a date qualifier so they never read as today.

  2. PR #1032: in child mode, if the spawned rowboat-server died, the app just logged it and the UI went stale. Now it respawns with exponential backoff (1s to 16s, capped at 30s), gives up after five consecutive failures with a clear message, and never respawns on intentional shutdowns. The interesting part was the state swap: the RPC forwarder caches a ready promise, so a respawn has to swap that promise or the app keeps talking to a dead process.

  3. PR #1033: a show-pairing CLI mode for the headless server. Before: SSH in, cat the server key file, squint. After: one command prints pairing URLs, the access code, and the exact payload the mobile app scans, optionally as a terminal QR. Zero new dependencies.

How the work actually went

Each one followed the same loop: audit the issue, verify nobody was actually working on it, post a short claim comment, let Claude Code write the code on my machine, then review the diff myself before pushing.

The review step caught real things. On PR #1033, my agent had branched from the previous PR's branch, which would have dragged an unrelated commit into the pull request. Caught it during diff review, cherry-picked the commit onto a clean main, pushed. Ten seconds of checking saved a maintainer from untangling my mess.

The part that was not coding

While picking issues I kept finding ghosts. Seven issues around server hardening were all claimed by one person in a single day, ten days before I showed up. None of them had a pull request. The claims sat there like reservations at a restaurant that never orders.

So I audited instead of grabbing blindly. Two of those issues turned out to be already fixed in main: the Host header allowlist and the header-first WebSocket auth had both landed in a merged hardening PR. The issues were just never closed. I left comments with file names and line references so maintainers could verify in one click.

One of those comments was also a self-correction. I claimed the WebSocket issue, then checked the code before writing any, found the fix already in, and posted the correction with the evidence. Claiming an issue and then silently dropping it is the ghost behavior I was criticizing. The difference between me and the ghosts is that I posted why.

What the numbers say

  • Issues picked clean at the attractive end: dozens of candidates, most already claimed or covered by open PRs
  • Claims with zero work behind them: at least seven in my target area alone
  • PRs that carried exactly one clean commit each: three of three
  • Reviews from maintainers so far: zero, they are presumably asleep, it was 2am in their timezone too

What I would tell someone starting this

Do not pick issues by labels. Labels are where everyone goes and where the ghosts live. Pick by reading the code and finding the gap between what the issue says and what main actually does. Sometimes the gap is the contribution.

And review your agent's diffs like a hostile senior engineer. The agent that writes good code will also quietly branch from the wrong place. It is still your name on the PR.

Top comments (4)

Collapse
 
vinhnguyenthanhdn profile image
Vinh Nguyen

The review step has one more thing in it, in the PR you call the interesting one. scheduleRespawn does respawnAttempts += 1 and then returns when respawnAttempts > MAX_RESPAWN_ATTEMPTS, so the reachable attempts are 1 through 5 and the index is Math.min(attempt - 1, 5), which only ever lands on 0 through 4. RESPAWN_DELAYS_MS ends 16_000, 30_000, and that last entry is never read. The Math.min clamp guarding it cannot fire either.

So the ladder really is 1s to 16s, as your summary says, and the 30s cap is not a cap, it is a dead array element. Harmless right now, which is why it survives review: the two constants are independent, and the first person who raises MAX_RESPAWN_ATTEMPTS to 6 gets a silent extra retry at a delay nobody looked at. Either drop the entry or define the max as RESPAWN_DELAYS_MS.length, so they cannot drift apart in the first place.

Collapse
 
alikhatersaibreakroom profile image
Ali Khater

The branch mistake is the perfect example because the code can be correct while the contribution is still wrong. Agents optimize the visible task; maintainers absorb repository state, issue ownership, branch ancestry, and review cost. Your “audit before claiming” loop is arguably the more valuable contribution than the three patches.

I would turn it into a pre-push gate: clean base, one intended commit, no unrelated files, issue still open, and a human-readable reason for every changed file.

Collapse
 
jo-do profile image
Jo Do

Someone else's codebase is the honest benchmark for an agent setup, and good-first-issues being picked clean makes it honest twice - no scaffolded task, no head start. The thing your own project never tests is orientation cost: on your own code the agent benefits from YOUR context leaking into every prompt, because you already know where the bodies are buried. On a foreign repo the prompt has to carry the whole map, and the gap between "agent that edits my code" and "agent that contributes upstream" is almost entirely that map-making. The maintainer's side matters too: a PR from an agent-assisted stranger gets read differently than one from a known contributor, so the bar shifts from "does it work" to "is it obviously correct to someone with thirty seconds." Three PRs in 24 hours is speed; the interesting number is how many survive review without a rewrite request.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.