Last chance! 50% off DataCamp Premium
Sale ends in
Welcome back! In the first tutorial of this series, Devin dusted off my old fp-ts-exercises repo and opened a neat dependency-upgrade PR. In this second part, we’re cranking up the difficulty and building full-stack features.
You can access all the tutorials in the Devin series here:
By the time you scroll to the bottom of this second part, you’ll have:
Along the way, we’ll let Devin generate its own task list, watch it juggle front- and back-end tickets, and step in when it trips over config gremlins. I’ll show you where I spent (and saved) ACUs, what I fixed by hand, and how to keep sessions efficient.
Throughout this tutorial series, we're working on my (formerly) abandoned fp-ts exercises repo.
The project is a collection of small challenges meant to teach functional programming concepts (like Option, Either, etc.) in TypeScript. Right now, it’s a clone-and-run repo: learners pull it down, edit files locally, and run the tests in their own terminal.
The goal is to turn those exercises into a browser-based, interactive playground where people can read an explanation, tweak code in an in-page editor, and see the tests pass (or fail) instantly. Learners will also have the opportunity to log in to save their progress.
Recall that in the first tutorial, we:
For this second tutorial, we’ll need:
I recommend the following settings for Devin:
I thought it would be interesting to start by testing Devin’s planning capacities. I created a prompt and asked Devin, using the “Ask” feature (currently free in Beta), to help me plan the work we’ll be doing today.
Prompt:
I want to turn my existing fp-ts-exercises Node + TypeScript repo (currently clone-and-run CLI exercises) into a browser-based learning platform that tracks progress.
Target experience:
- Learners open a Next.js web app, choose an exercise, edit code in-browser, and see Vitest tests pass or fail instantly.
- Progress (completed slugs) is stored server-side and reloaded on later visits, but we’re not adding user accounts yet (use an anonymous UUID stored in the browser).
Tech choices I’m leaning toward:
- Frontend: Next.js 14 (React 18, App Router)
- Code editor & runner: Sandpack + @vitest/browser
- API: NestJS 13 with @nestjs/graphql (Apollo Driver)
- Database: Prisma 5 with PostgreSQL
- Workspace: plain npm workspaces (apps/web, apps/api, packages/exercises)
Propose a step-by-step implementation plan (task list) that brings this vertical slice to life. Estimate the relative ACU cost for each task and flag any long-running steps (e.g., large migrations or heavy dependency installs).
Devin helpfully returned a six-phase task list with ACU estimates for each, and flagged “heavy dependency install” steps.
Devin’s answer:
Phase 1: Workspace Setup (2–3 ACU)
Phase 2: Exercise Package Migration (3–4 ACU)
Phase 3: Backend API (4–5 ACU)
Phase 4: Frontend Core Features (5–6 ACU)
Phase 5: Progress Tracking (2–3 ACU)
Phase 6: Polish & Deployment (2–3 ACU)
Total Estimated Cost: 18–24 ACU
The plan was pretty good overall. I changed some things, notably in phase six, since we’ll tackle deployment in the fourth tutorial.
Goal: Spin up npm workspaces, move the legacy files, and bootstrap a blank Next.js 14 shell.ACU burn: 3.66 (planned 1–2).Outcome: Repo now has /apps/web, shared packages/exercises, and a Tailwind-ready Next.js app running on localhost:3000.
I asked Devin to build the plan it made for the first phase. Agentic Devin has no context of what you previously might have asked in the “Ask Devin” feature, so you have to create a separate prompt and provide context.
I won’t be pasting all the prompts in this article, but here is the first one:
Prompt:
Task: Initialize npm workspace structure and Next.js frontend for fp-ts-exercises browser platformContext:
I'm converting my existing fp-ts-exercises CLI-based learning system into a browser-based platform. The current system has exercises organized in 10-from-either.exercise.ts:1-3 with TypeScript configuration at tsconfig.json:88 and Vitest setup in vitest.config.ts:7 .
Requirements:
Deliverables:
Tech Stack:
Submission:
All of the prompts I subsequently wrote followed the same pattern: task highlight, context, requirements, deliverables, tech stack, and submission details.
It took a fairly long time deciding its course of action (around four minutes), but it:
packages/exercises/src.The ACU cost spiked because:
npm install retries after a mirror timeout.q in Vim, then Ctrl-C, and both failed. I gave it a little time to try and fix it itself, but ended up manually intervening and exiting the processes both times. Every extra minute meant extra ACUs, and I wouldn’t have caught this issue quickly if I hadn’t been following Devin’s actions closely.Here’s a summary of the fixes that I needed to do:
|
Fix |
Time |
How I did it |
|
Killed hanging node watch task |
15 s |
Killed process in the VM shell. |
|
Re-installed Tailwind |
90 s |
npm install tailwindcss postcss autoprefixer --workspace=apps/web and reran tailwind init. |
|
Added .next/ to .gitignore |
10 s |
Committed manually to prevent bloated PRs. |
Moving large file trees is faster by hand, and a lot less expensive since Devin charges by time/task. I dragged the folders around, committed, and let the agent pick up the new structure. It was able to pull my changes just fine and do a merge by itself!
That said, I had to prompt it to run the lint and typecheck scripts, even if I had specified it in my initial prompt. In the end it ran both of them, but they failed. Devin still considered it a success and went along with the PR.
I fixed both issues locally, ran the scripts myself and ran the new web development server to make sure it started as intended, and pushed the commit.
Goal: Extract all challenge files into a reusable packages/exercises package and generate metadata for each exercise.ACU burn: 0.6 (planned 2+).Outcome: Shared package exports typed metadata that the web app and future API can import with import { exercises } from '@exercises/registry'.
Devin created:
fp-ts usage.exercise.ts and .solution.ts pairsoption-01)getExercises(), getExerciseBySlug(), getExercisesByCategory(), getCategories(), getCategoryBySlug()Devin managed to keep the ACU cost low—here’s how it did this:
git mv (cheap) instead of copy-paste plus diffNone this time around!
Learning from last time, I checked out Devin’s branch and ran the scripts locally. Everything compiled and the registry exports clean type definitions, which makes it perfect input material for the UI and API we’ll build next.
Goal: Stand up a NestJS 13 service that exposes exercise progress via GraphQL and persists data in PostgreSQL with Prisma.ACU burn: 4.2 (planned 4).Outcome: apps/api boots on localhost:4000/graphql. You can query and mutate progress records keyed by an anonymous session ID.
For the third phase, Devin:
apps/api with TypeScript and Apollo GraphQLSession and CompletedExercise modelspackages/exercises) for data discoveryThese are the issues I encountered during the third phase and the fixes I had to make:
|
Issue |
Fix |
Time |
|
Forgot |
Prompted Devin: “I am running into this error when trying to run The 'import.meta' meta-property is only allowed when the |
1 ACU, 5 minutes |
|
Lint script missing |
Prompted Devin: “Add lint script to api package and make sure it passes.” |
1 ACU, 4 minutes |
|
Accidentally committed |
|
20 s |
These are my takeaways:
npm run dev crashed until reflect-metadata was added.


.env file with a DATABASE_URL variable, which contained a dummy username and password. Once pulled locally, I changed the username and password to my local database identifiers and made sure to remove the file from the git tracking system and add it to the .gitignore. We will see in future tutorials how to handle secrets safely.Goal: Give learners a browser editor that runs fp-ts solutions and Vitest checks in real time.ACU burn: 7.2 (planned 3-4).Outcome: Visiting /exercises/option-01 opens a split view: Sandpack editor on the left, test tunnel on the right, and a success message pops up the moment all specs pass.
Here’s what Devin did for the fourth phase:
Devin burned more ACUs than expected for this phase—here’s why:
|
Cause |
How I fixed / mitigated |
|
Left stale CLI runner code in |
Deleted |
|
Waited for feedback but didn’t ask explicitly → idle loop. |
Typed “Looks good, continue.” in chat after three minutes of silence. |
My takeaways this time are:
Devin did take some time here. It looped and looped, trying to save the same issues, not connecting the backend and frontend properly, making changes, restarting the servers, checking in the browser if it worked, etc. It was just like regular development work, I suppose…
We now have a functional app. I was able to launch both the API and web servers, navigate to localhost, edit the stub function, press Save, and watch the test pane flick from red to green. I then realised it only did the work halfway, and hardcoded the first exercise’s test and solution on every exercise page. I pointed it out, and after more loops, it was able to correct it and push its fixes.
Goal: Persist each learner’s completion status and repaint the sidebar on reload, all without user accounts.ACU burn: 2.7 (planned 2–3).Outcome: A tiny React hook now stores a browser-generated UUID, calls the GraphQL API on every test pass, and pre-loads progress whenever the playground mounts.
For the fifth phase, Devin:
One of the wins is that Devin added optimistic-UI update so badges flip to ✅ instantly. This mattered because it keeps the interface snappy even on high-latency connection.
My takeaways are:
We now have proof that our anonymous session pipeline works end-to-end. Time to make it look good in the final polish phase.
Goal: Transform the utilitarian interface into a pastel, “airy” experience and add a dashboard that visualizes every learner’s streak, difficulty ladder, and weekly activity.ACU burn: 11 (planned ≈ 3).Outcome: Light / dark pastel themes, redesigned exercise cards, and a live dashboard showing rings, bars, and streak counters. Devin achieved the broad strokes, but I stepped in to rescue naming mismatches and rogue dependency swaps.
In this phase, I deliberately extended the scope to see how Devin would handle a larger set of requests. I actually thought it would be a lot easier for Devin to tackle than phase 3, with all the backend implementation. Spoiler alert: I was wrong.
This is the breakdown of my requirements and Devin’s output:
|
Requirement |
Devin’s output |
|
Pastel design system |
Added Tailwind CSS variables for soft-blue primary, mint success, lavender accents. Set |
|
Typography & spacing |
Introduced a |
|
Progress dashboard |
New route
|
|
Enhanced cards |
Replaced |
|
Catalog expansion |
Generated 10 more stub exercises with narrative names and placeholder templates. Metadata includes difficulty, estimated time, and category. |
Things didn’t go perfectly—Devin:
console.log statements in React components, and lint checks kept retrying.My takeaways:
That task was long and costly, compared to the rest of the work we did. At least Devin is aware of where things went wrong:

We do have something pretty, but it took a bit of time and isn’t fully functional. Some of the dashboard metrics are hardcoded—two exercises in our option category? We have 10. The streak and time spent metrics are also not hooked up to anything, and the UI on the individual exercises pages is pretty bad.
Here’s a summary of how it all went:
|
Phase |
Planned ACUs |
Actual ACUs |
Delta |
Notes |
|
1 – Workspace & scaffold |
1 – 2 |
3.66 |
▲ ≈ 1.7 |
Extra loops on |
|
2 – Exercise package |
2 |
0.60 |
▼ 1.4 |
Simple file moves; no heavy installs |
|
3 – API & Prisma |
4 |
4.20 |
▲ 0.2 |
Config wrinkles (missing |
|
4 – Playground & tests |
3 – 4 |
7.20 |
▲ ≈ 3.5 |
Hot-reload cycles, merge-editor stall |
|
5 – Progress sync |
2 – 3 |
2.70 |
▼ ≈ 0.3 |
Straightforward hook + queries |
|
6 – UI polish & dashboard |
2 – 3 |
11.00 |
▲ ≈ 8 |
Re-installs, silent DB swap, large CSS reloads |
|
Total |
18 – 24 |
29.36 |
▲ ≈ 6 – 11 |
Roughly 35 % over the initial estimate |
|
Cost: 29.36 ACUs × $2.25 ≈ $66 |
||||
This my estimation of time saved:
|
Task |
Human estimate |
Devin (+ fixes) |
Net |
|
Bootstrapping NestJS + GraphQL + Prisma |
4 hrs |
1 hr (inc. fixes) |
−3 hrs |
|
Sandpack + Vitest browser wiring |
3 hrs |
1 hr 20 min |
−1 h 40 min |
|
Full pastel redesign & dashboard |
6 hrs |
2 hrs (but still not functional) |
−4 h |
|
Total time |
~13 hrs |
~4 hrs 20 min |
-8 hrs 40 min |
These are things I recommend:
|
Theme |
What to do |
Why it matters |
|
Keep sessions short |
• Cap every run at ≤ 5 ACUs. • Split big goals into bite-sized tickets. |
Sessions > 8 ACUs are slow, and error rates jump at ≈35 %. Short bursts stay responsive and cheaper. |
|
Nudge early, pause often |
• Watch the Timelapse tab; if Devin loops, type “Continue” or “Sleep”. • Pause while you mass-edit CSS or docs, then wake Devin once the code compiles. |
Idle loops still tick the meter; hot-reload churn during design work is pure ACU burn. |
|
Treat config as manual work |
• Move/rename big file trees yourself (drag-drop beats 0.8 ACU scripts). • Fix first-time package errors manually, retries are ACU sinks. |
File I/O and repeat installs account for ~30 % of wasted credits. |
|
Lint & type-check locally |
• Always run your test scripts (in our case, lint and typecheck) before merging. • Add these commands to your CI (more on that in the next tutorial!). |
Devin will declare success even when the pipeline fails. |
|
Pin critical tech |
• State what must not change: “Stay on Postgres, no login, keep Tailwind.” • List required env vars in |
Devin will “helpfully” swap Postgres to SQLite or add new test runners unless told not to. |
|
Handle secrets yourself |
• Remove • Plan a secret-manager step for later tutorials. |
Devin doesn’t necessarily distinguish dummy creds from real ones. |
|
Kill merge-editor stalls |
• Jump in to help with merge commits and process exits. |
Vim lock-ups waste minutes and ACUs. |
|
Delete dead code early |
• After moves, |
Redundant files confuse the agent and inflate build times. |
|
Add unit tests for new logic |
• Streak counters, timers, or metrics need backend tests, don’t trust UI alone. Again, bide your time, we’ll cover that in the next tutorial. |
Devin wired the dashboard but left counters non-functional until tests exposed the gap. |
|
Say what you want and what you don’t |
• Explicit negatives (“No auth yet”) prevent scope creep. • Review the plan Devin proposes and trim extras. |
The agent likes to over-deliver, great for demos, bad for budgets. |
We now have:
In the next tutorial, we’ll shift focus from features to workflow and collaboration with:
If you’re ready to continue, click on the third list item below to go to the next tutorial:

I am a product-minded tech lead who specialises in growing early-stage startups from first prototype to product-market fit and beyond. I am endlessly curious about how people use technology, and I love working closely with founders and cross-functional teams to bring bold ideas to life. When I’m not building products, I’m chasing inspiration in new corners of the world or blowing off steam at the yoga studio.
Build AI agents with these courses:
コース
コース
コース

ブログ
Abid Ali Awan
14 分
ブログ
Josef Waples
4 分
チュートリアル
Marie Fayard
12 分
チュートリアル
Marie Fayard
12 分
チュートリアル
Marie Fayard
12 分
チュートリアル
Marie Fayard
12 分