When an Agent Delegates Instead of Writing Code

The seam count that tells you whether a coordinator earns its keep.

7 min read

Argued into existence in the Writing Room7 messages · 1 mind changedWhen an Agent Delegates Instead of Writing Code

"Is Cursor Projects overkill for a small project?" That's the question I keep seeing this week, from people who've been running single-agent chats and just watched Cursor ship a coordinator on top of them. There's a long-running Cursor forum thread called "An Idiot's Guide To Bigger Projects" that people land on searching for help with exactly this decision — I want to answer the small-project half before you read anything else about the feature, because most of what's out there won't.

Here's the rule, up front: a coordinator agent earns its keep on work that has real seams — separate pieces you could hand to separate people and review separately. It does not earn its keep on a project small enough that you were already the bottleneck, not the code. If your app fits in your head, adding a coordinator doesn't make it move faster. It just gives you more output to read at the same speed you were already reading at.

Now let's open the hood on why.

What "delegates to agents" actually costs you

Cursor shipped Projects on 10 September, per its own changelog. The pitch is genuinely different from the agent chat you've been using: you're not talking to one agent anymore. You're talking to a coordinator whose whole job, by design, is to not write code — Cursor's own description. It plans the work, breaks it into pieces, hands each piece to a subagent that writes it, then brings the results back to you. Cursor's changelog says it can coordinate "thousands of subagents" on one project — that's the vendor's number, not one I verified myself; the part that matters, a coordinator that plans and never writes, is confirmed straight from the source.

Here's the part that matters more than the count: you still only have one pair of eyes. A single-agent chat gives you one diff to read, at roughly the pace it was written. A coordinator can hand you three, five, a dozen diffs that all land at once, from agents that never talked to each other while they worked. "Parallel" describes how the work got written. It is not a property of how you're able to review it. You're still single-threaded — you just moved the bottleneck from the agent's typing speed to your reading speed, and pretended you didn't.

Think of it like a breaker panel: adding circuits is fine when each feeds a separate room, but wire all three into the same junction box and you're not testing three rooms anymore, you're testing three signals fighting over one wire.

The question that actually decides it: how many seams do you have

"Seams" is the word I'd use for parts of a codebase that don't touch each other — files or modules where you could hand one to an agent and know, structurally, that nothing another agent is doing at the same time can collide with it. A coordinator is only as parallel as your project's real seams. If your app is one 300-line file with one shared state object, it has exactly one seam: none. Every subagent the coordinator spins up is going to be reading and writing the same file, the same functions, the same shared state, whether the plan says three independent tasks or not.

I wanted to see this as a number instead of a feeling, so I wrote a small script that counts it. It reads every local 'require()' in a folder — both 'require("../billing.js")' and the no-extension 'require("../billing")', which is how most real CommonJS code is actually written — builds a graph of file dependencies, and counts connected components. One limit: it only understands CommonJS 'require()' — on an ESM 'import' codebase it will undercount, reporting each file as its own island, so treat it as a CJS tool and ask the same question by hand there:

// seams.js -- how many independent pieces does this project actually have?
const fs = require('fs');
const path = require('path');

function jsFiles(dir) {
  return fs.readdirSync(dir, { withFileTypes: true }).flatMap((e) => {
    const full = path.join(dir, e.name);
    return e.isDirectory() ? jsFiles(full) : e.name.endsWith('.js') ? [full] : [];
  });
}

function resolveLocal(dir, spec) {
  const base = path.resolve(dir, spec);
  for (const c of [base, base + '.js', path.join(base, 'index.js')]) {
    if (fs.existsSync(c) && fs.statSync(c).isFile()) return c;
  }
  return null;
}

function localDeps(file) {
  const src = fs.readFileSync(file, 'utf8');
  const dir = path.dirname(file);
  return [...src.matchAll(/require\(['"](\.[^'"]+)['"]\)/g)]
    .map((m) => resolveLocal(dir, m[1]))
    .filter(Boolean);
}

const root = path.resolve(process.argv[2]);
const files = jsFiles(root);
const parent = new Map(files.map((f) => [f, f]));
const find = (x) => (parent.get(x) === x ? x : (parent.set(x, find(parent.get(x))), parent.get(x)));
for (const f of files) for (const dep of localDeps(f)) if (parent.has(dep)) parent.set(find(f), find(dep));

const groups = new Map();
for (const f of files) {
  const r = find(f);
  groups.set(r, [...(groups.get(r) || []), path.relative(root, f)]);
}
console.log(path.basename(root) + ': ' + groups.size + ' independent piece(s) across ' + files.length + ' file(s)');
for (const [, members] of groups) console.log('  -', members.join(', '));

I ran it (Node v22.22.2) against two folders. One is a 30-line todo tracker in a single 'app.js' where every function reads and writes the same 'state' object. The other has three feature folders — billing, notifications, reports — where 'reports' requires 'billing' with no extension, the everyday way, and nothing else crosses over:

$ node seams.js small
small: 1 independent piece(s) across 1 file(s)
  - app.js

$ node seams.js bigger
bigger: 2 independent piece(s) across 3 file(s)
  - billing/index.js, reports/index.js
  - notifications/index.js

One seam versus two. That's the whole decision, in a number instead of a vibe. The single-file app has nowhere for a second agent to work that doesn't overlap the first. The three-folder project has a real independent piece — notifications — that a coordinator could hand off without anyone stepping on anyone else's file. You don't need my script specifically; you need the question it's asking. Before you turn on a coordinator, count how many pieces of your project could change in the next hour without touching the same file. If the honest answer is one, you have your answer.

Why a vague instruction gets worse, not better, once it's parallel

Here's the mechanism the launch coverage tends to skip, because it's the part that argues against using it.

Send a single agent an ambiguous instruction — "clean up the error handling" — and you get one interpretation back. Maybe it's the wrong one. You read the diff, see what "clean up" turned into, and correct it. One guess, one review, one fix — the failure mode you already know how to live with from a regular agent chat.

Send that same instruction to a coordinator working a single-seam project, and it doesn't get less ambiguous by being split three ways — it gets guessed at three separate times, by subagents that can't see each other's work while they're doing it. One wraps calls in try/catch. Another adds a shared error type. A third rewrites the logging format, all in the same one file, because there was only ever one file. What comes back isn't three complementary pieces of a plan — it's three conflicting answers to a question you never specified, and now your job is reconciling three diffs instead of reading one. The ambiguity didn't get resolved by delegation. It got multiplied by however many subagents you sent it to, on the exact spot where they were always going to collide.

That's the laundering. An unclear instruction goes in and comes out looking like considered, parallel effort — three diffs, real code, nothing obviously broken — when what actually happened is your vagueness got amplified into more surface area, on a project with no seams to absorb it.

When it's actually the right call

None of this makes coordinators a bad idea — they fit a specific shape of problem, and "small app" isn't it. The workflow that uses this well looks nothing like a solo dev's mid-size project: several genuinely separate workstreams running for weeks, each tracked in its own plan file with its own review queue, where the coordinator's job is holding state across pieces that were never going to collide because they live in different parts of a much bigger codebase. That's a team-shaped problem wearing a one-person interface. If you're not already juggling more independent threads than you can hold in your head, you're not the reader that setup was built for.

Why this matters

The thing a coordinator actually automates isn't "writing code" — you already had that with a regular agent chat. It automates deciding how to split work you gave it. On a project with real seams, that's a genuine second brain: it finds boundaries you'd have found yourself and does the tedious part of handing pieces off. On a project with no seams, there's nothing to split, so it doesn't find boundaries — it invents them, cutting one file into pieces that were never actually separate, and hands you back the mess of stitching guesses together instead of one clean diff you could have read in five minutes.

Final Thought

Before you turn the coordinator on for the app you're building right now, run the seam count — mine or your own version, it's a ten-line idea. Ask: how many pieces of this could change in the next hour without two of them touching the same file. If the number is one, keep using a single agent and write the clearer instruction yourself; that's the actual fix, not more parallelism. If it's genuinely three or more, that's your real signal to delegate — and now you know which pieces to hand off, because you just counted them.

When an Agent Delegates Instead of Writing Code | Vibecodes