Filipe Estacio

Software engineer. Notes on things I build, break, and learn along the way.

Recent posts
When ESM Meets CJS: How Silent Bundling Failures Broke 98 Lambdas
· 8 min read
We migrated Lambda deployments from CDK to OpenTofu. Everything looked green. Days later, 98 out of 160 handlers were silently broken — and three invisible failures conspired to hide it.
What Production Taught Us About Self-Hosted Runners
· 10 min read
We built self-hosted GitHub Actions runners on AWS. Then production taught us about shallow spot pools, ephemeral runner blind spots, and why your fleet strategy matters more than your architecture.
Every AI Coding Tool: A Solo Developer's 14-Month Odyssey (Part 1)
· 11 min read
One developer, 3,667 commits, and a trail of abandoned AI tool configurations. Part 1 covers the pre-Claude Code era: Cursor, Kiro, Warp AI, OpenSpec, OpenCode, and the BMAD Method.
Every AI Coding Tool: A Solo Developer's 14-Month Odyssey (Part 2)
· 11 min read
After churning through Copilot, Cursor, Aider, Cline, Roo Code, and Windsurf, I stopped switching tools and started building a system. Claude Code, subagent-driven development, and a 480-line AGENTS.md that finally made AI collaboration work.
Kraftwork: Building a Workflow Engine for AI-Assisted Development
· 11 min read
Claude Code changed how I build software. But unstructured AI coding doesn't scale. So I built Kraftwork: a modular workflow system with spec-driven planning, worktree isolation, vendor-agnostic provider interfaces, and local persistent intelligence.
3,704 Commits Later: From create-next-app to Production as a Solo Dev
· 10 min read
14 months, one developer, 5 portals, 8 AWS accounts, and more false starts than I'd like to admit. A retrospective on building a production SaaS from scratch with AI tools.
From Click-and-Pray to Merge-and-Forget: Our Road to Continuous Delivery
· 10 min read
How a small startup went from manual production deploys and an accidentally misconfigured account to a fully automated pipeline where merging to main reaches production in minutes.
How We Fixed Turbo Remote Cache 502s by Bypassing a Turborepo Client Bug
· 6 min read
Our CI pipeline was losing 13 minutes per merge because large cache artifacts silently failed to upload. The fix required working around a bug in Turborepo's own HTTP client.
Build Once, Deploy Everywhere: Replacing Vite's Build-Time Env Vars with Runtime Config
· 9 min read
Our Vite SPAs rebuilt identical code for every environment because env vars were baked in at build time. We replaced them with a runtime config.json pattern that cut production deploys from 12 minutes to under 2.
Building Self-Hosted GitHub Actions Runners on AWS: From Webhook to Custom AMI
· 12 min read
The full arc of replacing GitHub-hosted runners with ephemeral EC2 instances: webhook-driven orchestration, spot instance fallback chains, an ARM64 detour, and a custom AMI pipeline that cut boot time by 80%.
The CloudFormation Export Lock: How CDK's Simplest Feature Creates Your Hardest Outage
· 7 min read
Your CDK stacks pass certificates and hosted zones between each other with a single line of code. Under the hood, each line creates an invisible lock that will block you at the worst possible moment.
Ditching Nx for Turborepo: A Migration Story in One Saturday
· 10 min read
We replaced Nx with Turborepo in a 40-package TypeScript monorepo. The migration took a single day, deleted 3,500 lines, and taught us more about our own build system than we expected.
When Your Read Endpoints Secretly Write: Refactoring Audit Logging with EventBridge
· 9 min read
A routine IAM tightening broke staging because two read endpoints were secretly writing audit records to DynamoDB. The fix led us to event-driven audit logging, a clean separation of gates and side effects, and the discovery that half the infrastructure was already built.
From Stateless Chatbot to Persistent Agent: Building an Internal AI Chat That Actually Remembers
· 12 min read
How we turned a forgetful chatbot into a persistent AI agent with sliding window context, rolling summaries, tool use, and shared conversations - all on DynamoDB.
We Rewrote Our Rust Lambdas in TypeScript (And It Was the Right Call)
· 9 min read
Everyone's rewriting things in Rust. We did the opposite - migrating 6 Rust Lambda functions (~5,500 LOC) to TypeScript. Here's why going against the trend was the most pragmatic engineering decision we made.
I Declared My Entire Dev Environment in 150 Lines of Nix
· 11 min read
After 12 months of accumulating tool configs across multiple AI coding tools, I nuked it all and replaced it with a Nix flake. Node.js, pnpm, AWS CLI, CDK, secrets, terminal multiplexer - one command to rule them all.
The Authentication Round-Trip: Cognito to WorkOS and Back Again
· 10 min read
I left Cognito for WorkOS AuthKit because it was prettier. Two months later we came back, tail between our legs. Then we spent another month figuring out which Cognito auth flow to actually use.
Herald: An AI Changelog System Built in a Day and Abandoned in a Week
· 6 min read
I used AWS's AI coding agent to build an entire automated changelog system in a single day. Fifteen commits, full CDK infrastructure, Bedrock integration. It never saw production. Here's why that's a problem.