
How This Blog Got Built by a Swarm of Imps
6 July 2026
Here's the actual sentence I typed:
i want to extend this page to include a simple blog, with @giscus comments enabled
That's it. One line, dropped against a single-page React + TanStack Start site with no markdown pipeline, no comments system, no RSS feed. I didn't write a spec. I didn't sketch a schema. I typed a sentence and watched a swarm of agents turn it into this post.
This is what happened in between.
The plugin
The thing doing the work is imps — a Claude Code plugin I built. Install it and it gives you /imps:imps:
claude plugin marketplace add seankoji/claude-plugins
claude plugin install imps@seankojiOne line, four modes. Feed it a task description, a batch of GitHub issue numbers, a Discussion URL, or a checklist file, and it figures out what you meant:
| Input | Example | What happens |
|---|---|---|
| Task description | /imps:imps <task> | Refines the brief, plans, decomposes, dispatches, ships a PR |
| GitHub issue numbers | /imps:imps 42 43 51 | Scouts those issues, dispatches fixes in parallel, opens one integration PR |
| Discussion URL | /imps:imps <discussion url> | Seeds the task from a GitHub Discussion, replies there when done |
| Checklist file | /imps:imps checklist.md | Runs every Verify: / Done when: line as an audit |
This post came from the first mode. The main session stays deliberately thin — it holds plan approval, the push/PR decision, and nothing else. Everything downstream runs inside a separate subagent so a long build never grinds the orchestrator's own context down.
From a sentence to a brief with teeth
A one-liner isn't a brief. The first thing that happens is translation, not code.
prompt-builder sharpens my sentence into something specific: MDX content, /blog and /blog/$slug routes, Giscus wired with a placeholder config, matching the site's existing look. Then five discovery questions land at once — repo and branch, what artifacts I want out (code, a PR), what counts as done, what's off-limits.
I pick the "higher bar" option on acceptance criteria — RSS feed, SEO meta tags, a scroll-reveal animation — and just like that the scope is bigger than "render some markdown."
One question mid-plan matters more than it looks. The site's root layout sets:
<meta name="robots" content="noindex" />everywhere, site-wide. Should the blog override that? No. Keep noindex until the site's actually ready for the public. That single answer is why this post carries full Open Graph and Twitter tags — link previews still need to look good — but no search-engine override.
Two agents go looking before anyone plans
Before a plan gets drafted, two read-only Explore agents run in parallel. Neither writes a line of code. Their whole job is telling the truth about the codebase before anyone commits to an approach.
Agent one comes back with the styling contract: TanStack Router's file-based routes, a Reveal scroll-animation wrapper already in use everywhere, a class-based .dark theme with no React context behind it, and a placeholder "writing" section on the homepage that's been quietly waiting for a real blog to link to.
Agent two comes back with the finding that reshapes the whole plan: this isn't plain Vite + Router, it's TanStack Start — a different SSR framework entirely. No MDX pipeline exists. date-fns is installed but nobody imports it. CI runs format → lint → typecheck → build with no test step. And the static file server has no .xml MIME entry — a detail that means nothing yet, but will matter a lot once an RSS feed shows up.
/imps:imps run, start to PR.The plan gets a bug hunt before I ever see it
The plan comes together as 8 dependency-mapped tasks — a ninth gets folded in after I approve, this post — each one assigned a model by how much judgment it actually needs, not by how big it sounds. Here's the real task table from this run:
{ "id": 1, "label": "Install deps + wire @mdx-js/rollup + ambient types + prettierignore", "model": "sonnet" },
{ "id": 2, "label": "src/lib/blog.ts content loader (getAllPosts/getPostBySlug)", "model": "sonnet" },
{ "id": 3, "label": "Giscus: GiscusComments.tsx + giscus-config.ts + setup docs", "model": "sonnet" },
{ "id": 4, "label": "2 sample MDX posts under src/content/blog/", "model": "haiku" },
{ "id": 5, "label": ".blog-prose CSS (semantic tokens only, no hardcoded colors)", "model": "haiku" },
{ "id": 6, "label": "Blog routes: layout, index, $slug", "model": "sonnet" },
{ "id": 7, "label": "RSS generation Vite plugin -> /rss.xml + server MIME fix", "model": "sonnet" },
{ "id": 8, "label": "Homepage integration: real posts, RSS <link>", "model": "sonnet" }Haiku got the two tasks where the shape was already fully specified — filling in sample content and writing CSS against an exact class-name spec. Everything that required actually deciding something — routing, theme sync, a build plugin — went to sonnet.
Before any of it dispatches, an adversarial reviewer reads the plan file itself, not a summary of it, and re-checks every claim against the real repo. This is the Head Imp — running on opus, arguing to kill the plan, not rubber-stamp it. On this run it came back with three real bugs:
Head Imp findings — CHANGES_REQUESTED
- The RSS feed would download instead of render. The plan said "no app-code changes needed." It was wrong — the server's static-file MIME map has no
.xmlentry, sorss.xmlwould ship asapplication/octet-stream. - Prettier — a required CI gate — actually processes
.mdxfiles. The plan reasoned about excluding blog content from ESLint and never once considered Prettier. First blog post committed, CI goes red, for a reason that has nothing to do with the code. - The RSS generator would race the build. Planned as a
closeBundlehook writing straight todist/client/rss.xml— except that path can not exist yet when the hook fires, on a site with a multi-environment client+server build.
Every one of those gets fixed in the plan file before I ever see it for approval — plus a handful of minors: unescaped XML in feed titles, a pubDate format that needed to be RFC-822 instead of a plain ISO date, and a task dependency gap that would have let the blog listing get "verified" while it was still empty.
Approve once, then it's out of my hands
I approve the plan a single time. There's no second approval pass after the fixes — they land in the same file before I ever look at it.
From there it hands off entirely to a separate Imp Wrangler, which owns everything downstream: dispatching all 9 tasks as background agents in isolated git worktrees so parallel work can't collide, respecting the dependency graph, merging finished branches, running the gates, and running a persona-panel review before a PR ever opens.
Task 6 — the blog routes — waits on four upstream tasks before it can start. Everything else with no incoming arrow starts immediately. That's the whole point of mapping dependencies instead of just running things in a list: the wrangler doesn't wait for task 5 to finish before starting task 7, because nothing about the RSS feed depends on the CSS.
This post is task 9 of that 9. By the time you're reading it, the rest of the swarm already finished building the blog around it.
Comments aren't set up yet.