I built Accelerator HQ — a production-grade workforce-management platform for behavioral-health licensure candidates — solo, in eight weeks of focused build time, while running my day job. It is, today, the most ambitious piece of software I've shipped. It almost died in week three.
This is the build log: what worked, what nearly killed it, and the architectural decisions I'd make the same way again.
The setup
Behavioral-health licensure is a 23-month gauntlet for the candidate: clinical hours to be logged, supervisor sign-offs to be collected, milestone gates to clear, payments to trigger, leave to be handled. The funder side is its own gauntlet: an ROI calculator, an Impact page, a one-pager that has to compute live from the cohort because that's the artifact every program funder is actually asking about — including HPSA placement, which is the metric that actually matters in this category.
The existing LMSes in this category handle, generously, 30% of the actual job. I'd watched two programs try to bend a generic LMS into doing the work, and both gave up after six months. The gap was specific enough that I decided to build it.
Stack constraint: Next.js 16, Tailwind v4, Supabase (Postgres + Auth + real-time), Resend for transactional email, Anthropic Claude for the AI surfaces, Vercel for hosting. No agent loops, no tool use, no orchestration framework. Just APIs and React.
Week 1 — Schema first, ugly UI
The 5-day data model
I spent the first five days drawing the candidate-journey data model on paper before writing a line of code. The 23-month journey, milestone gates, clinical-hours pacing, leave handling, supervisor assignments — all encoded as Postgres types and constraints before any UI existed.
This is the single most important decision in the build. Every operational mistake I'd watched the existing LMSes make traced back to a schema that couldn't represent the actual licensure model. They'd modeled "courses" and "users" because that's what an LMS framework gives you for free. The actual primitives are candidate, cohort, milestone, clinical-hours-record, supervisor-relationship, leave-period. None of those map cleanly to a course.
End of week one: a working flow from candidate creation through first milestone gate to first reflection prompt. UI was hideous — Tailwind defaults, no design pass. Backend was correct. Live on Vercel.
Schema first wins. Every operational mistake the existing LMSes made traced back to a schema that couldn't represent the licensure model.
Weeks 2-3 — The funder side, and the moment it almost died
The Impact page that broke the schema
I built the funder side next, ahead of more candidate features, because the funder artifacts (Impact page, ROI calculator, one-pager) were the actual sales surfaces for the platform. If those didn't work, no funder would care how clean the candidate UX was.
The build was straightforward in week two: SQL queries against the cohort table, computed metrics, a clean React surface. By the end of week two, I had an Impact page rendering live numbers from a seeded test cohort.
Week three is when it almost died.
Funder questions about metrics started shifting. "How are you defining HPSA placement?" "Is that gross or net of attrition?" "Is leave time counted toward the 23-month clock or paused?" Each question implied a different metric formula, which implied a different SQL query, which sometimes implied a different schema, because some metrics required tracking events I hadn't modeled.
I spent four days chasing schema changes. Each new metric definition broke an old metric. The system started to fight me. I was three weeks in, with a partially-broken Impact page and no candidate-side momentum, and seriously considered killing the project.
The save was a single document.
The metrics catalog that saved the project
On a Wednesday afternoon, instead of writing more code, I opened a blank Markdown file and wrote down every funder-facing metric in three columns: name, formula, data dependencies. I wrote about forty metrics in that doc. Then I stared at the dependencies column.
Three things became obvious:
- Most metrics depended on the same six underlying data types. I'd already modeled five of them. The sixth —
leave_periodwith acounts_toward_clockflag — was the missing primitive. - Several "different metrics" funders were asking about were the same query with different filters. They didn't need separate code paths.
- A few of the metrics couldn't be answered with the data we'd ever collect, and I should be transparent about that rather than build elaborate stand-ins.
I added the leave period type, deleted a half-dozen stand-in queries, and froze the schema as of that Friday. The metrics catalog became the spec for everything downstream.
Funder questions are the actual product spec. Write them down before you write the SQL.
Lesson, retrospectively obvious: when funders are the customer, the funder questions are the spec. I'd been treating them as nice-to-have validation. They were the requirements doc, and I should have written that document in week one rather than week three.
Weeks 4-5 — Four AI surfaces, four narrow prompts
Why I didn't use an agent
Accelerator HQ ships four AI surfaces today:
- At-risk diagnosis + draft outreach for staff. Reads recent activity, supervisor flags, and cohort context; outputs a one-paragraph diagnosis plus a draft outreach message.
- Context-aware coach chat for candidates. Has access to the candidate's milestones, hours logged, and recent reflections; helps them think through where they're stuck.
- Admin-side cohort-pulse synthesis. Reads the peer feed (anonymized check-ins, group reflections) and surfaces themes for the admin team.
- Personalized weekly reflection prompts. Generates a prompt for each candidate based on their last week of activity and where they are in the journey.
The architectural decision that made all four shippable solo: each surface gets its own narrow system prompt and its own retrieval scope. No agent loops. No tool use. No orchestration framework.
Each surface is a single Anthropic API call. The application code does the retrieval (a Supabase query for the relevant context), assembles a system prompt and a user prompt, and calls Claude. The response is parsed (mostly as plain text, sometimes as structured JSON) and rendered.
That's it. No LangChain, no Autogen, no agent framework, no MCP, no tool-calling loop.
What this bought me
- Reliability. Each surface is one call. If it fails, it fails atomically. There's no half-completed agent state to debug.
- Debuggability. When a surface produces a weird output, I can replay the exact prompt and response. There's no chain of agent thoughts to reconstruct.
- Cost. One call per surface, cached aggressively. Nothing in the loop is calling itself recursively.
- Speed of iteration. If the at-risk diagnosis is producing bad outputs, I edit one system prompt and re-test. It's a 30-second iteration loop.
Narrow AI surfaces beat agent loops. Especially when you're shipping solo, especially when the surfaces are doing different things.
I am not anti-agent. There's a class of problems where an agent loop is the right answer — multi-step research, multi-system orchestration, code generation. The four surfaces in Accelerator HQ are not in that class. Each one is a single transformation from context to output. The minimum viable architecture for that is exactly one API call.
The biggest mistake I see solo builders make in 2026 is reaching for an agent framework when they actually need a prompt and a database query. The framework adds complexity without adding capability for this kind of build.
Week 6 — Supervisor assignments and leave handling (the boring week)
Where 80% of the work lives
The hardest week was the boring one. Supervisor assignments — many-to-many relationships with effective dates, role types, sign-off authority — and leave handling — pause the clinical-hours clock, optionally pause the journey clock, handle re-entry without losing prior progress.
None of this is technically interesting. All of it is operationally critical. Get it wrong and a candidate's licensure timeline is wrong, which means a payment trigger fires at the wrong moment, which means the funder sees a metric that's off, which means the program loses credibility.
I spent five days on the boring week. The boring week is where the project stopped being a demo and started being software.
80% of the work is operational glue. The schema is interesting, the AI is shiny, but the actual difference between a project that ships and a project that demos is the boring week — the leave-handling, the supervisor-assignment, the edge case where a candidate transfers between cohorts.
If you're scoping a build like this, budget the boring week. Probably budget two boring weeks.
Week 7 — Polish, real-time, email
The integration week
With the data model and AI surfaces stable, week seven was integration: real-time updates via Supabase channels (so admins see candidate activity live), transactional email via Resend (welcome flows, milestone notifications, weekly reflection prompts), and a final design pass on the candidate-facing UI.
Real-time was easier than expected. Supabase ships with channels out of the box. Subscribing a React component to a row-level channel is a five-line hook. The hard part was deciding what should be real-time and what should be on a refresh cycle. I landed on: candidate activity is real-time for admins; cohort metrics refresh on demand. Real-time metrics would have been over-engineered for the volume.
Email took most of the week — not technically, but in the writing. Templating eight different transactional emails to feel personal, not robotic, while pulling correctly from the candidate's actual context. Claude wrote the first drafts. I rewrote each one.
Week 8 — Launch and first cohort
What launch actually meant
Launch was unglamorous: invite the first cohort, watch the dashboards, fix what breaks. Three things broke in the first week:
- A candidate signed up using a Google account whose email didn't match the invite list. Authentication-fallback flow needed work.
- One supervisor's calendar timezone caused milestone deadlines to be off by a day for that supervisor's cohort. Fixed with explicit timezone handling.
- Resend rate-limited the welcome email send because I'd queued a hundred of them simultaneously. Fixed by adding a small delay between sends.
None of these were dealbreakers. All of them were patched within hours. The system held.
The lessons, condensed
Four things I'd carry forward to any solo build
- Schema first. Spend a week on the data model before you write any UI. Wrong primitives propagate forward and cost weeks later. Right primitives compound.
- If the funder is the customer, the funder questions are the spec. Write the metrics catalog in week one, not week three.
- Narrow AI surfaces beat agent loops. One API call per surface. Aggressive retrieval upstream of the call. No frameworks. The shipped surface is the entire architecture.
- 80% of the work is operational glue. Budget the boring weeks. They're where the project becomes software.
What I'd do differently
Two things.
Start the metrics catalog earlier. The four-day stall in week three was the closest the project came to dying. If I'd written down the funder questions on day one — even if I didn't have the data to answer them yet — the schema decisions would have been right the first time, and I wouldn't have rewritten anything.
Pick fewer AI surfaces and ship them better. Four production surfaces is a lot for week-five-of-eight. I shipped all four and they all work, but the cohort-pulse synthesis is the one I'd cut if I had to. It's useful but not load-bearing. The other three are doing real operational work; the synthesis is doing nice-to-have storytelling. If I'd cut it, I'd have had a week to build something more durable elsewhere.
The macro point, since this is a portfolio essay
Eight weeks. Solo. Production. Real cohort, real funder pages, four AI surfaces, all running on Claude. While running my day job.
This was not a demo. It was not a Figma deck. It was not a "look what AI can do" experiment. It was a real piece of software, with real users, doing real work, in a category where the existing tools handle 30% of the actual job.
The reason I could ship it solo in eight weeks — and not, say, with a five-person team in eighteen weeks — is the same reason any operator with the right toolkit can now ship things that previously required a team. Claude does not write Accelerator HQ. I write Accelerator HQ. Claude makes the writing-of-it possible at one person's pace.
That is the version of the AI-builder thesis I actually believe. Not "AI replaces engineers." Not "AI builds your software." More like: the cost of a person becoming the builder collapsed, and the rate-limiting step is now domain knowledge plus willingness, not technical skill.
Which is the role I sell.
Have a category where the existing software handles 30% of the actual job?
That's the gap I build into. Embedded part-time, production code, your stack, your ownership. Most engagements ship a working tool in week one — and the long ones look like Accelerator HQ.
Book a 15-min intro call Email me