I'm not a full-time developer. Over two days and 110 commits I've been running an experiment: I describe what I want in plain Korean, and an AI coding agent (Claude Code) does the planning, coding, deployment, debugging, images and short videos. The result is a Korean information site with 1,360 static pages that rebuilds itself every hour — and the server/API bill is $0 (domain and the AI subscription are separate).
The $0 constraint
- Hosting: GitHub Pages (static HTML) — free
- Login, bookmarks, visit counter, web-push subscriptions: Cloudflare Workers + D1 free tier
- Photo-to-ingredients recognition for a "what can I cook with my fridge" tool: a public vision model on Workers AI, capped per day to stay inside the free allocation
- Data: publishers' public RSS feeds (only where robots.txt allows), Upbit's public crypto API, Google Trends RSS
- Character art: open models on my own GPU
- Automation: Windows Task Scheduler on my PC, every hour: collect → process → build → git push
Things I found interesting
Grouping the same story across 15 news outlets. The first version linked articles in a chain (A≈B, B≈C), which merged completely different stories A and C. Switching to "compare everything against a seed article" fixed it.
A "verification signals" score, not a fact-check verdict. Each article gets points for cross-reporting, named (vs anonymous or social-media) sources, whether numbers and double-quoted quotes in the headline actually appear in the body, and a flag when outlets report different casualty numbers for the same event. The page always says this is a reading aid, not a final judgement.
Analyst reports as nodes. One brokerage-report article = one node (firm, direction, old → new price target, reason tags). Nodes roll up into per-stock "reasons up / reasons down" trees.
Where the AI got it wrong
- A year-old article without a date slipped into an RSS feed and showed up as "today's report". Fix: resolve dates from RSS → URL → page metadata, drop anything older than 7 days, and flag implausible price-target jumps.
- Single quotes used for emphasis in Korean headlines were treated as quotations and penalised. Fix: only compare double-quoted text.
- Generated characters with odd hands. Fix: only hand-checked images are used.
The full cost table, architecture and the actual instructions I gave are on the build log page (in Korean): https://sungprofile.cloud/ailog/?src=devto
Update (Oct 18, evening)
- The home page is now four themed entrances; news, money, contests, everyday-life and the AI build log each became a separate screen with its own colours and menu. The entrance matching where you came from (?src=) is shown first.
- Per-theme chatbots that run entirely in the browser (no model): today's issues and questionable articles; crypto prices and price-target upgrades/downgrades; subsidy search and housing-lottery schedules. Data loads only when the panel is opened.
- Housing-lottery helper: enter your situation → score (out of 84) + supply types worth trying + matching notices open right now.
- Money section: an investment-policy table checked against official sources, general age-based principles, and on-the-record expert comments grouped by topic, side by side when they disagree (not investment advice).
- Search clean-up: RSS feed, sitemap lastmod that only changes when a content hash changes, noindex on thin auto-generated pages, and pre-rendering JS-drawn screens to static HTML (text visible to crawlers went from 687 to 13,605 characters).
- Analytics: channels grouped by first touch; automated health-check traffic from overseas servers excluded (12 hits had slipped in on day one).
- Updated numbers: 2 days · 110 commits · 1,360 pages (about 2,400 old multilingual pages removed). Server/API cost is still $0.
Top comments (4)
the "Where the AI got it wrong" section is the most important part of this post. manually writing a custom fix rule for every single hallucination (like the RSS date issue or the single quotes) is exactly why agents are so hard to put in production.
you basically had to build a manual validation layer after the fact. doing that at the message/tool level before it hits the live site is the only way to scale this without losing your mind.
Thanks, that's a fair read. Right now the fixes really are reactive rules added after each failure showed up (the date resolution order and the 7-day cutoff, for example). A pre-publish validation step is the obvious next improvement: a build-time check that fails the build and keeps the previous version live if a page breaks a rule like a missing date or a stale item, instead of patching symptoms afterward. If you validate at the tool-call level in your own setup, I'd be curious which rules you found worth enforcing first.
yeah, a pre-publish check is definitely the right move. reactive rules will pile up until it's unmanageable.
for tool-call rules, the first one I always enforce is schema/type validation. If the agent tries to pass a string where an integer ID should be, kill it immediately.
the second is a loop check. if the agent starts repeating the same action—or gets into a cycle of reviewing its own work without changing state—halt it. step limits don't catch this because the tokens keep changing, but the state isn't.
I actually wrote a breakdown on that specific loop failure mode here if you're interested: dev.to/belalshafeq/the-coder-agent...
Schema validation as rule one is right, and cheap: it fails on the call instead of after the side effect.
On loop detection I would add one refinement from running this unattended. Counting repeated actions catches the obvious cycle, but the limit I find more useful is a cap on side-effecting calls per run rather than on iterations. Reading, searching and re-reviewing are cheap and sometimes genuinely needed; writes, publishes and external posts are what you actually cannot take back. Budget those separately and a confused agent burns tokens instead of doing damage.
The other thing that helped was giving the stop condition a third value. If the agent cannot tell whether the action succeeded, "unresolved" has to be a real state, otherwise the retry logic picks one of success or failure and is wrong half the time. Unresolved means stop and leave evidence for the next run: the request id, the timestamp, what was expected. That turns a hallucinated "done" into a question the next session can answer in one call.