1/ I've been a software engineer for 20 years. In late 2025 I switched to full vibe coding with Claude Code.
Same person, same hours. Products that used to take me 4 months now ship in 2 weeks.
Here's the actual timeline, with real numbers.
Image generation was failing and docker logs showed nothing. Not an error, not even evidence the call happened.
My own debug_log.log(book_id, ...) returns early when book_id is None, and the character preview path never has one. The logging function was eating the errors it existed to surface.
When a failure produces no log line at all, suspect the logger before you conclude the code never ran.
@damonchen The first render isn't where code-rendered video pays off, the re-render is. My App Store previews are one JSON per locale, and one command re-renders all 7 languages. The same pipeline now makes TikTok videos at close to zero cost per extra language.
Generated images came back broken in the browser. I shelled into the container, cat'd the file fine, and looked in the wrong place for a while.
I was root in that shell. nginx error.log had it: open() failed (13: Permission denied). tempfile.NamedTemporaryFile writes 0600 and shutil.move kept that permission, so the unprivileged nginx worker could not read it.
os.chmod(path, 0o644) after the download.
@ScottShapiroUXD Worth knowing where that stops: CLAUDE.md scope is a soft constraint. The Bash tool runs with the OS user's permissions and can reach any path. For hard isolation I ended up running separate instances, each with its own workspace, .env and SQLite.
@MengTo Did this for App Store preview videos: HTML/CSS scenes, Puppeteer seeking each frame (not screen recording) for a deterministic 30fps, 886x1920, one JSON per locale for 7 languages. AI never nailed the pixel QA. The bezel mask was always a few px off, so I did it by hand once.
@EXM7777 Did the same split in a Claude Agent SDK pipeline: one Sonnet parent, 6 subagents, Haiku on the simple steps. Estimated cost went from ~250k tokens per contact to ~45k. One catch: SDK subagents can't spawn their own subagents, so the orchestrator owns every handoff.
My subscription handler looked the user up by stripe_customer_id, found nothing, and the plan field silently never got written.
customer.subscription.created arrives before checkout.session.completed, so the user row does not exist yet. Stripe's 2024+ API also moved current_period_start and end into https://t.co/CrntCInnLF[0].
I now write plan eagerly from metadata in checkout.session.completed and stopped depending on event order.
@BirhanNega@pcshipp Same shape here: one automated email-writing job ate 60k+ tokens and drained a whole 5-hour window. Running 3-4 sites a day, staggering jobs only moved the wall later. We ended up planning a switch to a metered API key instead of the subscription.
@M_crek The cap hurt less than how it fails. Our Agent SDK jobs got subtype "success" with result text "You've hit your limit · resets 2pm", so the queue marked them completed. Fix: keyword-match the result, and treat anything under 50 chars as a failure.
Driving Google search over a CDP connection sent me straight to https://t.co/AdLI6R6JuX. The same query through a real logged-in Chrome returned results.
Google fingerprints the DevTools Protocol and the headless Chromium build. Playwright likely trips the same check.
The version that works needs a browser extension and a foreground window, so it cannot run on the headless box I wanted it on.
@zakisbuilding Works for one locale. We ship 7 locales x 7 shots x 2 sizes = 98 PNGs, all rendered by Puppeteer from one HTML template with a --locale flag. Before that pipeline, 6 of the 7 store pages fell back to English screenshots. So we kept the pipeline and dropped the fake status bar.
A PM2 process hit EADDRINUSE and crash-looped. The restart counter reached 9,621, and once went past 10,000.
A zombie node process still held port 9211, so every new process died on boot and PM2 retried without resetting the count.
pm2 restart alone did nothing; kill -9 the zombie first. I added min_uptime 30s and max_restarts 5 so a boot-loop stops instead of counting forever.
@KullanNinja@sama Each subagent is a full model run with its own context, so it adds usage rather than saving it by default. Where they saved me: a 7-step session at 200-300K tokens per contact, split into a parent + 6 subagents with a cheap model on simple steps, came to an estimated ~45K.
@EXM7777 Stacking cost is multiplicative. If each layer holds at p, the chain holds at p^N: at 0.95 per step, 17 steps finish 42% of the time. The rule I took from a 17-step video pipeline that kept breaking: mechanical calls go in code, the model only gets the real judgment calls.
I tried to give every user their own working directory inside one Node process. process.chdir() changes the cwd of the whole process, not of a logical session.
There is no per-session cwd in Node. The isolation I was designing does not exist at that layer.
I switched to child_process.fork and gave each user their own Worker process.
@itsGrizai Neither yet, honestly. What exists is the restart side: a heartbeat older than 90s means a new thread treats the job as a zombie and takes it over. A call that hangs inside a live process isn't caught today, which is exactly your all-night case.
1/
A background job that runs 15 to 25 minutes will outlive at least one deploy. Mine came back from a restart stuck at "in progress" and stayed there forever.
Nothing was running it. The database just had no way to know that.
@LazyIDE@legitindie Agreed. We saw it without any limit message too: two cron runs returned success after exactly 4m17s with zero tool calls and zero DB writes. One guard we added: a result under 50 chars counts as failure, since a real cycle always writes a few hundred chars of summary.
@itsGrizai Yes, that's the gap. A ticker running beside the call keeps the heartbeat fresh whatever the call is doing, so a hung call reads as alive. Inside a call the heartbeat only says the process exists; a stuck call needs its own deadline.
PM2 started my worker from inside a Claude Code session, and the child Claude Code process refused to boot with exit code 1.
It had inherited the CLAUDECODE environment variable and decided it was a nested session.
One line at the top of index.ts fixed it: delete process.env['CLAUDECODE'].