DEV Community

Cover image for 4,524 commits in 7 weeks: what I learned shipping a real product with Claude Code
Crime Brasil
Crime Brasil

Posted on • Originally published at crimebrasil.com.br

4,524 commits in 7 weeks: what I learned shipping a real product with Claude Code

TL;DR

  • 4,524 git commits in 7 weeks (~92/day)
  • ~42,000 lines of code across Python backend + Next.js frontend
  • ~3M records ingested, 79,024 neighborhoods geocoded, zero-downtime production deploys, E2E smoke tests, APScheduler jobs, SEO snapshot system
  • Total spend: ~$500 (Claude Max $200 × 2 months + Hetzner ~$30 × 2 months)
  • Built alone. Shipped.

I'm not going to tell you Claude Code is magic. It isn't. But if you treat it like a very fast, very literal colleague who forgets things between sessions, you can ship more than you'd think. Here's the workflow that worked for me.

The product is Crime Brasil — an open-data platform for Brazilian crime statistics. Doesn't matter for this post. What matters is the process.

Workflow that actually worked

1. Plan mode before anything non-trivial

Before any change touching >3 files or introducing new abstractions, I forced a /plan pass. No code, just a tree of what changes where and why.

This cut the "Claude confidently wrote 400 lines of the wrong thing" bug in half. The other half came from me being sloppy about what I was actually asking for.

Pattern:

1. Tell Claude the goal
2. Ask for a plan (no code)
3. Push back on anything that feels wrong — usually scope creep
4. When the plan feels right, say "implement"
Enter fullscreen mode Exit fullscreen mode

Boring. Works.

2. Sub-agents for parallel anything

Independent work ran in parallel sub-agents. Research + implementation + QA could all run concurrently instead of me waiting for each to finish.

  • research agent — "understand how X works, come back with a map"
  • implement agent — "apply the diff described"
  • qa agent — "verify the fix, run the regression tests"
  • review agent — "is this safe to merge"

I'd fire three of these in parallel and get stitched output in a third the wall time.

3. Session scratchpad as an anti-compaction tool

Claude Code compacts its context when conversations get long. After compaction you can lose crucial decisions from earlier.

Fix: every session writes to a scratchpad file (~/claude-sessions/session_<topic>.md) with timestamped entries. Key decisions, user preferences, things we tried that failed. Before spawning any sub-agent I inject the relevant scratchpad entries into the prompt.

This alone probably saved a dozen hours of "wait, why did we decide not to do that again?"

4. Memory system for permanent preferences

Claude Code has a memory system that persists across conversations. I ended up writing ~80 memory files over 7 weeks, categorized:

  • user — who I am, what I work on, what I already know
  • feedback — rules I've enforced ("never push to main directly", "always chrome-verify fixes, not just curl")
  • project — state of ongoing work
  • reference — where external resources live (dashboards, tokens, API docs)

Every time I corrected Claude on the same thing twice, I saved a memory rule. Examples from my actual file:

  • Never slow bot renders for SEO — fixed a bad server-side bot-detection idea
  • No lossy analytics filters — never exclude geographic data to "clean up" analytics
  • Wait-loop pattern — use while pgrep not until ... && ! kill -0 (the latter busy-waits)
  • No arbitrary safeguards — don't add population floors to hide bad data, fix the data
  • Never substitute solutions — if user asks to fix X, fix X, don't silently solve by changing Y

That last one came up repeatedly. Claude loves to pivot to an "easier" problem.

5. Hooks for guardrails

Some rules can't be enforced by just asking nicely. For those, I used Claude Code's hook system to block certain actions entirely.

Examples I ended up needing:

  • Block any git commit --no-verify (never bypass pre-commit hooks)
  • Block rm on data files without explicit confirmation
  • Warn on any git push origin main — all changes must go through dev branch + staging first

Hooks turned bad defaults into impossible-by-default. Worth the setup time.

6. Verification before declaring "done"

Claude loves to say "fixed!" based on an API test passing. That's not the same as the feature actually working in a browser.

I ended up with a rule: every UI-touching change gets Chrome-verified before being marked complete. A Playwright script clicks through the real flow and screenshots the result. If the screenshot looks wrong, it's not done.

Memory file: "NEVER report a fix as done without Chrome visual verification."

Before this rule: "fixed!" → deploy → user finds it broken → revert. After: "fixed, verified on /cidade/rs/porto-alegre, panel shows 509K crimes, screenshot attached."

Specific bugs Claude caused

Honest list. These are patterns; I saw each of them multiple times.

"Let me also refactor while I'm here"

Ask for a small bug fix, get back 400 lines of unrelated cleanup. Sometimes broke unrelated features.

Memory rule: "Don't add features, refactor, or introduce abstractions beyond what the task requires. Three similar lines is better than a premature abstraction."

Inventing API endpoints

Asked Claude to "call the API to get X data." It wrote code calling /api/thing that didn't exist. Tests failed. When pushed: "oh right, that endpoint doesn't exist. Let me write it first."

Fix: when consuming an API, I started forcing it to read the actual source files first. Read src/api/routes.py, then write the client. Slower, zero hallucinations.

Silent feature deletion

Twice Claude "fixed" a bug by removing the buggy feature. Asked to fix a map polygon render issue, got back code that just disabled polygons entirely. Clean green tests. Feature gone.

Memory rule: "NEVER remove features unless user explicitly says to. 'bugado' means fix, not remove."

Overclaiming completion

The biggest pattern. "Done!" → I check → 2 of 4 items done, 2 untouched. Claude was genuinely under the impression it had finished.

Fix: I stopped taking "done" at face value. Every "done" got a follow-up "walk me through what you changed file-by-file, and show me the diff for each." Usually the second response corrected the first.

What Claude can't do (yet)

  • Architect from scratch. Given a vague brief like "build a data platform for X," Claude produces a generic Django blog. Needs strong direction.
  • Know your domain. Took months to teach it Brazilian bairro-name quirks — there's no substitute for local knowledge, and Claude will confidently generalize from Stack Overflow examples that don't apply.
  • Remember across sessions without help. Compaction + context limits mean every session is partial amnesia. The scratchpad + memory system is the only thing that saved me.
  • Decide what not to build. Claude will happily implement bad feature ideas. Saying "no" is still human work.

Cost breakdown (~$500)

Item Cost
Claude Max subscription ($200/mo × 2) $400
Hetzner dedicated server ($30/mo × 2) $60
Resend email API (free tier) $0
Cloudflare (free tier) $0
Domain $12
Total ~$472

For reference: a single senior contract dev week at market rates is $4-6K. I shipped this in 7 weeks of evenings + weekends for ~$472 in tools + hosting.

The caveat: this is a solo project. I didn't have to coordinate with anyone, and nobody needed to review my work. That's a rare situation.

Lines of code

Category Lines
Python backend (FastAPI + scrapers + ingest + APIs) 23,559
TypeScript frontend (Next.js + Leaflet) 18,762
MDX content (articles) 6,165
Total 48,486

92 commits/day sounds insane. In practice most commits are small and auto-checkpointed. Real "unit of work" commits are maybe 20-30/day.

What I wouldn't skip if doing it again

In priority order:

  1. Scratchpad files. Save at least 10x their cost in "wait, what did we decide?" time.
  2. The /plan discipline. Every non-trivial change gets a plan first. Boring, works.
  3. Memory rules for every recurring correction. Rule of twos: if you correct Claude on the same thing twice, write it down.
  4. Chrome-verify before declaring done. API tests don't cover UI. UI bugs always happen on the last Friday.
  5. Hooks for dangerous defaults. Anything you really don't want — make it impossible by default, not just discouraged.

What I'd do differently

  • Start the memory system earlier. I was 2 weeks in before I realized it existed. Week 1 was slower than it needed to be.
  • Spin up sub-agents sooner. For a while I was doing everything sequentially in the main agent. Parallel work is a huge speed-up.
  • Write the CLAUDE.md from day 1. A per-project CLAUDE.md explaining architecture and conventions prevents a lot of drift.

Closing

Crime Brasil is live at crimebrasil.com.br. It serves ~3M records across 497 municipalities, gets Google traffic for specific city and neighborhood queries, and was built almost entirely in a Claude Code harness.

I'm happy to answer questions about the workflow. The answer to "can AI replace developers" is still no, but "can a developer with AI replace two developers without AI" is absolutely yes, and that's interesting enough.


Follow along on X at @Crime_Brasil if you want to see what ships next.

Top comments (0)