[{"data":1,"prerenderedAt":489},["ShallowReactive",2],{"projects":3},[4,72,148,382],{"id":5,"title":6,"body":7,"description":54,"extension":57,"meta":58,"navigation":59,"path":60,"seo":61,"sortOrder":62,"stem":63,"tagline":64,"thumbnails":65,"titleColor":70,"__hash__":71},"work\u002Fwork\u002Fairtable-as-backend.md","Airtable as Backend",{"type":8,"value":9,"toc":53},"minimark",[10,15,23,29,43,48],[11,12],"hero-image",{"alt":6,"src":13,"subtitle":14,"title":6},"\u002Fimages\u002Fwork\u002Fairtable\u002Fthumb.png","Nuxt + Airtable",[16,17,19],"title-block",{"subtitle":18},"A one-time event site. APIs, auth, and the whole data layer.",[20,21,22],"p",{},"I built the backend",[24,25,26],"side-note",{},[20,27,28],{},"Under NDA. No screenshots, just the technical work.",[30,31,32,40],"text-block",{},[20,33,34,35,38],{},"I took on a project with a fixed launch date: a one-time event site with registration, info, and a hub element. They needed someone to build out all the backend functionality: APIs, auth, and the connection between the frontend and their data. The client was already familiar with Airtable and wanted to use it as the data layer.",[36,37],"br",{},[36,39],{},[20,41,42],{},"I started with Airtable itself. I designed the full base from scratch: tables, linked records, field types, the whole schema. On top of that, server-side APIs behind session auth and middleware, so the frontend never touched the data directly and every request was gated. A single field-map translated between Airtable's column names and the domain model, which turned out to matter a lot: the client kept changing their mind about what fields they needed, and adding or removing one became a one-line change instead of a hunt through the codebase. On the frontend side, I wrote all the composables that consumed those APIs and wired them into the static site, so the data flow from Airtable to the rendered page was end-to-end mine.",[24,44,45],{},[20,46,47],{},"Airtable is not a database, and you feel it eventually: no joins, no aggregation, no transactions, rate limits you have to engineer around. For an event in the hundreds with a fixed shelf life, those limits didn't bite. The layer I built was designed so that if the project ever outgrew Airtable, the backend could be swapped without touching the frontend.",[30,49,50],{},[20,51,52],{},"I'm a full-stack engineer, and that means the unglamorous parts too: setting up a client's database by hand, wiring auth middleware into a site that'll be taken down in a month, checking ownership on every mutation for an event that happens once. All of it's the job.",{"title":54,"searchDepth":55,"depth":55,"links":56},"",2,[],"md",{},true,"\u002Fwork\u002Fairtable-as-backend",{"title":6,"description":54},4,"work\u002Fairtable-as-backend","Backend for [REDACTED]",[13,66,67,68,69],"\u002Fimages\u002Fwork\u002Fairtable\u002Fthumb-lightgrey.png","\u002Fimages\u002Fwork\u002Fairtable\u002Fthumb-red.png","\u002Fimages\u002Fwork\u002Fairtable\u002Fthumb-green.png","\u002Fimages\u002Fwork\u002Fairtable\u002Fthumb-yellow.png",null,"QhhNeT7pWLBCJLmAVZsJtlYSjrS3RIVeOu2ax5zmVtk",{"id":73,"title":74,"body":75,"description":54,"extension":57,"meta":139,"navigation":59,"path":140,"seo":141,"sortOrder":142,"stem":143,"tagline":144,"thumbnails":145,"titleColor":70,"__hash__":147},"work\u002Fwork\u002Fcart-validator.md","Cart Validator",{"type":8,"value":76,"toc":137},[77,81,87,92,98,108,113],[11,78],{"alt":74,"href":79,"src":80,"title":74},"https:\u002F\u002Fllm-cart-validator.vercel.app\u002F","\u002Fimages\u002Fwork\u002Fcart-validator\u002Fthumb.png",[16,82,84],{"subtitle":83},"It was one of the most complicated and fragile systems in the codebase, and I kept thinking there had to be a better way.",[20,85,86],{},"At a previous job, I worked on a custom promotional deals engine",[30,88,89],{},[20,90,91],{},"Promotional deals look simple from the outside, but the parameters multiply fast: quantities, brands, categories, logic conditions, subset pricing, exclusions, stacking rules. Every new campaign meant engineering work. Every edge case meant more code.",[16,93,95],{"subtitle":94},"This isn't actually a hard problem for a human.",[20,96,97],{},"The insight...",[30,99,100],{},[20,101,102,103,105,107],{},"Show a person a cart and a deal in plain English, and they can tell you in seconds whether it applies and how much to discount. The difficulty isn't the logic, it's translating fuzzy language into formal rules. Which is exactly what LLMs are good at.",[36,104],{},[36,106],{},"\nSo I built a prototype. Send Claude a cart and a deal description, and it returns whether the cart qualifies and the discount amount. It works, even with vague phrasing.",[24,109,110],{},[20,111,112],{},"Not every \"replace logic with an LLM\" pitch deserves to win. But when rules originate as English in a marketing brief and only become code because someone had to implement them, keeping them in English is an easier path.",[30,114,115,122],{},[20,116,117,118,120],{},"The payoff isn't really about saving engineering time. It's independence from a rules engine vendor, speed to launch new deals, and non-technical teams that can build and ship on their own. It's also a template for how to think about AI optimization more broadly: a lot of the rigid systems we've built over the years were rigid because natural language wasn't a viable runtime. That constraint has quietly lifted, and it's worth looking around for other places the same shift applies.",[36,119],{},[36,121],{},[20,123,124,131,132],{},[125,126,130],"a",{"href":79,"rel":127,"target":129},[128],"nofollow","_blank","Live"," | ",[125,133,136],{"href":134,"rel":135,"target":129},"https:\u002F\u002Fgithub.com\u002Ftbunz\u002Fllm-cart-validator",[128],"Repo",{"title":54,"searchDepth":55,"depth":55,"links":138},[],{},"\u002Fwork\u002Fcart-validator",{"title":74,"description":54},3,"work\u002Fcart-validator","Pushing on the edges of what AI can handle",[80,146,80,146,80,146],"\u002Fimages\u002Fwork\u002Fcart-validator\u002Fthumb2.png","RzL01UP0pfPDcraE4CNX5faLnUmdWeBaqcHN9vvwyi4",{"id":149,"title":150,"body":151,"description":54,"extension":57,"meta":372,"navigation":59,"path":373,"seo":374,"sortOrder":55,"stem":375,"tagline":376,"thumbnails":377,"titleColor":156,"__hash__":381},"work\u002Fwork\u002Fhow-i-use-ai.md","How I Use AI",{"type":8,"value":152,"toc":370},[153,157,162,167,173,265,286,292,307,312,359,365],[11,154],{"alt":150,"src":155,"title":150,"title-color":156},"\u002Fimages\u002Fwork\u002Fai\u002Fthumb1.png","light",[30,158,159],{},[20,160,161],{},"I use AI heavily for production code, but not uniformly. How heavily depends on the stakes of the task. Here are the ways I work with Claude day to day, plus one setup I built that's made to run autonomously.",[24,163,164],{},[20,165,166],{},"As of writing this in April 2026, the only model I use for writing code is Claude Opus 4.7 via Claude Code (to the surprise of nobody).",[16,168,170],{"subtitle":169},"A one-sided partnership: Claude writes, I think and review.",[20,171,172],{},"Pair Programming with AI",[30,174,175,186,202,205,212,229,232,239,262],{},[20,176,177,178,180,182],{},"This is my general strategy for production-level web projects. I use VS Code and run Claude Code within it via the official extension. I break down the work into three task types:",[36,179],{},[36,181],{},[183,184,185],"strong",{},"Translating static UI components from Figma into code base",[187,188,189,193,196,199],"ul",{},[190,191,192],"li",{},"Use Figma MCP connection so Claude can extract values for design primitives (color palette, type definitions, etc.) and set them up in the style system.",[190,194,195],{},"Ask Claude to create static UI components one by one, directly from the Figma file.",[190,197,198],{},"I find that it does not always get the details pixel perfect. I have to review very carefully during this task. For example, it may use a different color or padding from what is present in Figma.",[190,200,201],{},"Despite the higher-than-usual mistake rate, it's still a boost to use AI here.",[20,203,204],{},"This flow is much slower than the others. It's important to get all of these details correct, down to the last pixel. If components aren't spaced right, or type is off, nothing in the design is going to line up later and it's going to be confusing.",[20,206,207,209],{},[36,208],{},[183,210,211],{},"Medium Complexity Tasks",[187,213,214,217,220,223,226],{},[190,215,216],{},"I give Claude the task with full edit permissions. It starts working.",[190,218,219],{},"I go do other things while it works (plan the next task, reply to Slack, review code).",[190,221,222],{},"Claude finishes and reports back.",[190,224,225],{},"I quickly review, note any areas to double check or any issues. Claude revises if needed.",[190,227,228],{},"All approved, next task.",[20,230,231],{},"I use this for tasks where a bug would reveal itself quickly as we continue development. For example: button hover animations, form components, moderately complex JS, etc.",[20,233,234,236],{},[36,235],{},[183,237,238],{},"High Complexity Tasks and Critical Code",[187,240,241,244,247,250,253,256,259],{},[190,242,243],{},"I explain the task thoroughly to Claude, starting in plan mode.",[190,245,246],{},"Claude formulates a plan, which I carefully review. We go back and forth on revisions until I'm satisfied with it.",[190,248,249],{},"I tell Claude to break the plan into logical phases, and to STOP after each phase and check in with me before proceeding.",[190,251,252],{},"Claude executes each phase, pausing for me to review each chunk. We fix any issues at each step, and continue through all phases.",[190,254,255],{},"When I am fully satisfied with the code, I start a new Claude instance with clean context to code review the new feature.",[190,257,258],{},"I have the review instance check for bugs, but also write test code that breaks the new feature and exposes any issues.",[190,260,261],{},"I pass the review back to the original Claude instance to finish and approve.",[20,263,264],{},"I used this flow on a recent app where the client required Airtable as the backend. Airtable's JS client handles basic operations fine, but I needed a layer on top to bundle higher-level logic. The phase-by-phase review let me push Claude toward structures that could be extended later, not just ones that worked now. The client changed data requirements several times over the project, and that foresight paid off. Each change slotted in cleanly instead of forcing a rewrite.",[24,266,267],{},[20,268,269,270,272,274,275,277,279,280,285],{},"In my experience, Opus 4.7 has a difficult time writing quality tests on its own. It often creates trivial tests, and inverts the meaning of PASS\u002FFAIL (e.g. assert PASS when the bug is present).",[36,271],{},[36,273],{},"\nThe most reliable solution is to carefully pair program alongside and mostly write the test code yourself. Test driven development is already a proven paradigm and this would give a solid check point for your development Claude to hit.",[36,276],{},[36,278],{},"\nBut if we still want to automate test writing: It's extremely important to have a test writing ",[125,281,284],{"href":282,"rel":283,"target":129},"https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fskills",[128],"skill file"," with explicit step-by-step instructions for Claude. For even better results, have a test reviewer skill file for a separate instance to independently audit the suite.",[16,287,289],{"subtitle":288},"Deploying AI on the cloud with full permissions, giving it guidance through Telegram messages.",[20,290,291],{},"Using AI as an Autonomous Worker",[30,293,294],{},[20,295,296,297,299,301,304,306],{},"When the OpenClaw mania erupted, I too became interested in using AI more autonomously. However, I didn't want to use it for two reasons: I already pay for a Claude subscription, and I had security concerns.\nSo while on a trip to California I took an afternoon and set up my own autonomous agent.",[36,298],{},[36,300],{},[183,302,303],{},"Setup",[36,305],{},"\nI run a cheap cloud server ($10\u002Fmonth) with a Claude Code instance that's always live and has full permissions on the machine. The server runs a script that's connected to a Telegram channel, so I can message Claude any time I want from my phone. It runs constantly and checks back in once it's done with a task, ready for another.",[24,308,309],{},[20,310,311],{},"A few weeks after I created this, Anthropic released their native version of autonomous Claude Code with messaging capability. I still use my setup because, why not? And I can add any features I need easier.",[30,313,314,337,356],{},[20,315,316,319,321,322,324,326,327,329,331,334,336],{},[183,317,318],{},"Usage",[36,320],{},"\nI have mostly used this setup for one secret personal side-project (write up coming soon). The main insight is that this setup is dramatically faster at writing code (however with more issues and security concerns — see below). The project is related to financial markets, of which I am not an expert. So, it's not so important to me that I understand every last detail of the theory and code. I just check in on progress from Claude reporting back, test suites, code reviews by other instances, and actual performance metrics in production.",[36,323],{},[36,325],{},"\nFor this project in particular, it is very useful for Claude to watch over things. It's a service that runs 24\u002F7 executing trades. Claude manages the whole thing — it'll even kill the process if something goes wrong.",[36,328],{},[36,330],{},[183,332,333],{},"Limitations",[36,335],{},"\nDespite the speed-up, I would not recommend this setup for most projects. The security risks and likelihood of critical bugs in code make it too unreliable for important systems. However, it could work well for:",[187,338,339,342,345,348],{},[190,340,341],{},"prototypes",[190,343,344],{},"side projects",[190,346,347],{},"projects with minimal damage in the worst case scenario",[190,349,350,351,355],{},"projects ",[352,353,354],"em",{},"without"," API keys, credentials, secrets",[20,357,358],{},"My secret personal project is highly complex but ultimately small in scope. With a few safeguards and kill switches, I feel comfortable giving Claude full autonomy in this case. In the worst case where Claude leaks everything, destroys the code, and loses all the money that the code manages, I'll be okay.",[16,360,362],{"subtitle":361},"but you have to understand its limitations.",[20,363,364],{},"AI is faster...",[30,366,367],{},[20,368,369],{},"The through-line across all of this is matching the tool to the stakes. For a hover animation, let Claude rip. For critical data flow, slow down, review each phase, have a second instance check the first. For a side project you don't mind losing, give it the keys.",{"title":54,"searchDepth":55,"depth":55,"links":371},[],{},"\u002Fwork\u002Fhow-i-use-ai",{"title":150,"description":54},"work\u002Fhow-i-use-ai","Faster, with caveats",[155,378,379,380],"\u002Fimages\u002Fwork\u002Fai\u002FClaudeIcon-Square.png","\u002Fimages\u002Fwork\u002Fai\u002Fterminal_abstract.png","\u002Fimages\u002Fwork\u002Fai\u002FClaude Spark - Clay.png","s1i_w_VNE9meL5xwWY2NIRPw3rFrQk3YkZ1I_J6ixsM",{"id":383,"title":384,"body":385,"description":54,"extension":57,"meta":477,"navigation":59,"path":478,"seo":479,"sortOrder":480,"stem":481,"tagline":482,"thumbnails":483,"titleColor":70,"__hash__":488},"work\u002Fwork\u002Fthe-manifest.md","The Manifest",{"type":8,"value":386,"toc":475},[387,392,403,408,413,422,427,433,447,451,456,462],[11,388],{"alt":384,"href":389,"src":390,"subtitle":391,"title":384},"https:\u002F\u002Fthemanifest.fyi\u002F","\u002Fimages\u002Fwork\u002Fmanifest\u002Fhero.png","Nuxt + Storyblok",[16,393,395],{"subtitle":394},"They wanted a place to record hard-earned wisdom, and dive deeper into the minds of their team and industry collaborators.",[20,396,397,402],{},[125,398,401],{"href":399,"rel":400},"https:\u002F\u002Fstudiofreight.com",[128],"Studio Freight"," pulled me in to dev a \"ledger of creative deconstruction\"",[30,404,405],{},[20,406,407],{},"The first thing I noticed was that the design was deliberately quiet. Mostly black and white, perfect alignment, square edges. It was clear that this platform was meant to serve the content, not compete with it. The assets and content of each article were to drive the vibe of the piece, while the site framed everything in place.",[409,410],"image-gallery",{":columns":411,":images":412},"4","[{\"src\":\"\u002Fimages\u002Fwork\u002Fmanifest\u002Fimage.png\",\"alt\":\"The Manifest\",\"caption\":\"Charter\",\"link\":\"https:\u002F\u002Fthemanifest.fyi\u002F\",\"linkText\":\"The Manifest\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fmanifest\u002Fimage1.png\",\"alt\":\"The Manifest\",\"caption\":\"Landing\",\"link\":\"https:\u002F\u002Fthemanifest.fyi\u002F\",\"linkText\":\"The Manifest\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fmanifest\u002Farticle1.png\",\"alt\":\"The Manifest\",\"caption\":\"Article\",\"link\":\"https:\u002F\u002Fthemanifest.fyi\u002F\",\"linkText\":\"The Manifest\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fmanifest\u002Farticle2.png\",\"alt\":\"The Manifest\",\"caption\":\"Article\",\"link\":\"https:\u002F\u002Fthemanifest.fyi\u002F\",\"linkText\":\"The Manifest\"}]",[30,414,415],{},[20,416,417,418,421],{},"The articles needed to be modular. ",[125,419,401],{"href":399,"rel":420},[128]," wanted to assemble new content quickly from mix-and-match pieces: text blocks, Q&As, image galleries, pull quotes — all the building blocks of a digital magazine. For the content manager, the experience had to feel fast and intuitive, ready to fill from day one.",[409,423],{":columns":424,":images":425,"aspect":426},"2","[{\"src\":\"\u002Fimages\u002Fwork\u002Fmanifest\u002Farticleport1.png\",\"alt\":\"The Manifest article portrait\",\"link\":\"https:\u002F\u002Fthemanifest.fyi\u002F\",\"linkText\":\"The Manifest\"},{\"src\":\"\u002Fimages\u002Fwork\u002Fmanifest\u002Farticleport2.png\",\"alt\":\"The Manifest article portrait\",\"link\":\"https:\u002F\u002Fthemanifest.fyi\u002F\",\"linkText\":\"The Manifest\"}]","tall",[16,428,430],{"subtitle":429},"and started matching the logical components from the design 1 to 1 in the Storyblok CMS.",[20,431,432],{},"So I got to work...",[30,434,435],{},[20,436,437,438,441,442,444,446],{},"The blocks were simple to map and add variations to. I spent a lot of time building up the CMS alongside the code components. I love the ",[352,439,440],{},"details"," when it comes to crafting the CMS. A cool site means nothing if the content system is too cumbersome for the content manager to use.",[36,443],{},[36,445],{},"\nI ended up with twelve content blocks, each with variation options. The image gallery was the most complicated block in the code. It needed seven different image grouping variations, but always had to maintain the same total layout space. However, from the content manager's perspective, it was dead simple. Add an image gallery block. Select the layout you wanted from a list (one up, two up, two up offset, three up, etc.). Add photos.",[409,448],{":columns":449,":images":450,"aspect":426},"1","[{\"src\":\"\u002Fimages\u002Fwork\u002Fmanifest\u002Fsb.png\",\"alt\":\"Storyblok CMS\",\"caption\":\"Storyblok CMS\"}]",[30,452,453],{},[20,454,455],{},"In the code base, I kept the gallery as a single component. It parsed the correct layout and adjusted the images within accordingly, while keeping all the general properties of the gallery centralized. This made it easy to extend if they decided mid-development that they needed a new image layout (quintuple up offset alternating spinning...). I would just add the option to the CMS, then extend the image gallery component to accommodate the option.",[16,457,459],{"subtitle":458},"an interactive landing page.",[20,460,461],{},"The finishing touch...",[30,463,464],{},[20,465,466,467,469,471,472],{},"The site's restraint made the landing page a chance to do something more expressive. We used GSAP for the text animations, but getting the physics to feel right was going to take a lot of fiddling — and that kind of fiddling lives more naturally in the designers' hands than mine. So I set them up with a live deployment where they could tweak all the parameters themselves: timing, easing, stagger, spring values, whatever they wanted. They dialed it in, I locked the values into the code, and we launched.",[36,468],{},[36,470],{},"\nCheck it out! ",[125,473,384],{"href":389,"rel":474,"target":129},[128],{"title":54,"searchDepth":55,"depth":55,"links":476},[],{},"\u002Fwork\u002Fthe-manifest",{"title":384,"description":54},1,"work\u002Fthe-manifest","Digital magazine platform built for editorial freedom",[390,484,485,486,487],"\u002Fimages\u002Fwork\u002Fmanifest\u002Fchecker.png","\u002Fimages\u002Fwork\u002Fmanifest\u002Flanding.png","\u002Fimages\u002Fwork\u002Fmanifest\u002Fchecker2.png","\u002Fimages\u002Fwork\u002Fmanifest\u002Fstage1.png","xdluncgyQM3D7IW6rnHYzZ6oDyXcIvLU5qRKA-LEr1E",1776963590369]