<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jim Zandueta</title>
    <description>The latest articles on Forem by Jim Zandueta (@jimzandueta).</description>
    <link>https://forem.com/jimzandueta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F184387%2Fbff514f7-ba23-468a-9a24-6e44b5c53f33.jpg</url>
      <title>Forem: Jim Zandueta</title>
      <link>https://forem.com/jimzandueta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jimzandueta"/>
    <language>en</language>
    <item>
      <title>Stop Using Your Most Expensive AI Model to Stamp the Paperwork</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Mon, 11 May 2026 13:49:31 +0000</pubDate>
      <link>https://forem.com/jimzandueta/stop-using-your-most-expensive-ai-model-to-stamp-the-paperwork-1kei</link>
      <guid>https://forem.com/jimzandueta/stop-using-your-most-expensive-ai-model-to-stamp-the-paperwork-1kei</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe679un3jnnznvk21nwdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe679un3jnnznvk21nwdz.png" alt="An AI coding token bill wearing a bow tie on a laptop screen." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AI coding tools are &lt;strong&gt;incredible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They are also starting to feel a bit like ordering room service at a five-star hotel.&lt;/p&gt;

&lt;p&gt;You ask for "one small change," blink twice, and suddenly your token bill is wearing a bow tie.&lt;/p&gt;

&lt;p&gt;That sounds dramatic, but if you use these tools every day, you know the feeling. Claude Code, OpenCode, Cursor, Copilot, all of it. We are living through this very odd moment where a half-formed thought can turn into a working patch before your coffee cools down. Things that used to take three browser tabs, two Stack Overflow answers, and one quiet crisis at the keyboard can now happen in a single conversation.&lt;/p&gt;

&lt;p&gt;The awkward part is that &lt;strong&gt;they work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So you use them constantly.&lt;/p&gt;

&lt;p&gt;And once you use them constantly, &lt;strong&gt;the economics stop being theoretical&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Token limits. Session limits. Rate limits. Premium models. Long context windows. Repeated retries. Agents writing updates to other agents like they are defending dissertations nobody asked for.&lt;/p&gt;

&lt;p&gt;After a while, every prompt had an &lt;strong&gt;imaginary CFO&lt;/strong&gt; sitting next to it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are you sure you want to ask that question?&lt;/p&gt;

&lt;p&gt;Could this be done by a cheaper model?&lt;/p&gt;

&lt;p&gt;Did you really need frontier-model reasoning to rename a variable?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Annoying little guy.&lt;/p&gt;

&lt;p&gt;Also, annoyingly, &lt;em&gt;not wrong&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That started changing how I worked.&lt;/p&gt;

&lt;p&gt;I asked fewer questions. I tried fewer weird ideas. I caught myself saving prompts for "real" work, which is a strange place to end up with a tool that is supposed to make development feel lighter.&lt;/p&gt;

&lt;p&gt;I wanted to keep the magic of AI coding without treating every iteration like a small financial event. I wanted to refactor, experiment, throw things away, ask dumb questions, ask better questions, and generally behave like a developer without feeling like every prompt needed a &lt;strong&gt;purchase order&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdj6azhxsspwcjxskikq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdj6azhxsspwcjxskikq.png" alt="A tiny CFO character sitting next to a developer and questioning AI model costs." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Wasn't the Expensive Model
&lt;/h2&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;I don't think premium models are &lt;strong&gt;the villain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They are expensive because they are good. Annoying, but fair.&lt;/p&gt;

&lt;p&gt;If I am making an architecture decision, I want the big brain in the room. If I am doing security review, yes, please send the adult. If I am debugging something production-shaped that smells faintly of DNS, IAM, and regret, fine. Summon the oracle.&lt;/p&gt;

&lt;p&gt;But updating docs?&lt;/p&gt;

&lt;p&gt;Routing a task?&lt;/p&gt;

&lt;p&gt;Scheduling implementation work?&lt;/p&gt;

&lt;p&gt;Making a small mechanical change that is basically "move this thing over there and run the test"?&lt;/p&gt;

&lt;p&gt;That probably does &lt;strong&gt;not&lt;/strong&gt; need the most expensive model available.&lt;/p&gt;

&lt;p&gt;That is how the paperwork metaphor got stuck in my head. Using a frontier model for every tiny task feels like asking your most senior engineer to staple documents. They can do it. They may do it beautifully. There may even be an elegant staple placement strategy. But financially, spiritually, and operationally, something has gone off the rails.&lt;/p&gt;

&lt;p&gt;Quality was not the thing bothering me. &lt;strong&gt;Allocation was.&lt;/strong&gt; We had started treating every AI task as if it needed the same level of reasoning, the same amount of context, and the same budget. Convenient, yes. Also lazy in a very expensive way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Open Model Detour
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7v1pw0wtch814evy98fb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7v1pw0wtch814evy98fb.png" alt="Open-weight model rankings." width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other thing I could not ignore: cheaper and open-weight models had &lt;strong&gt;quietly become good&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not "replace everything tomorrow" good.&lt;/p&gt;

&lt;p&gt;Not "redesign my distributed system while I make lunch" good.&lt;/p&gt;

&lt;p&gt;But absolutely "why am I paying premium rates for this README edit?" good.&lt;/p&gt;

&lt;p&gt;The price differences can be silly. In some cases, you are not talking about 10% cheaper. You are talking about one or two orders of magnitude cheaper. That changes behavior. When every request feels expensive, you get cautious. You ask fewer questions. You experiment less. You stop doing those weird little exploratory loops where you learn things.&lt;/p&gt;

&lt;p&gt;AI turns from a development partner into an emergency resource in a glass box.&lt;/p&gt;

&lt;p&gt;Break only in case of billable disaster.&lt;/p&gt;

&lt;p&gt;My first attempt at fixing this was not elegant. I patched Claude Code to point at a local Ollama server instead of Anthropic's API. It worked, which was both exciting and slightly cursed. I got decent uninterrupted work done, but it felt clanky. Like taping a jet engine to a bicycle and then insisting the bicycle had achieved flight.&lt;/p&gt;

&lt;p&gt;That detour pushed me toward &lt;a href="https://opencode.ai/" rel="noopener noreferrer"&gt;OpenCode&lt;/a&gt;, because OpenCode is model-agnostic. You can connect different providers and switch models without changing your whole workflow.&lt;/p&gt;

&lt;p&gt;That mattered more than I expected, because model choice stopped feeling like a separate chore and started feeling like part of the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpda5fwnr4z8u9nycgbjs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpda5fwnr4z8u9nycgbjs.png" alt="Diagram mapping cheap, balanced, and premium AI models to different software development tasks." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Better Question
&lt;/h2&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Once model switching was easy, I kept coming back to the same question: &lt;strong&gt;why is one model doing all the jobs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not because cheap models should do everything. That would be a different kind of mistake.&lt;/p&gt;

&lt;p&gt;What started to make sense was &lt;u&gt;using the right model for the right job&lt;/u&gt;, and not dragging unnecessary context into every call.&lt;/p&gt;

&lt;p&gt;Some work is coordination. Some work is implementation. Some work is review. Some work is genuinely hard reasoning. Those should not all be priced, routed, or treated the same way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You would not ask your most expensive lawyer to print the documents, book the meeting room, and staple the contract.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You want them involved when judgment matters. You do not need them guarding the printer tray.&lt;/p&gt;

&lt;p&gt;AI models are not exactly lawyers, thank God, but the principle is similar.&lt;/p&gt;

&lt;p&gt;Use expensive reasoning where expensive reasoning changes the outcome. Use cheaper models where the task is &lt;em&gt;bounded, mechanical, or mostly coordination&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That split became the first useful rule of thumb.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Used For&lt;/th&gt;
&lt;th&gt;Why It Helps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cheap and fast&lt;/td&gt;
&lt;td&gt;Routing, scheduling, bounded tasks&lt;/td&gt;
&lt;td&gt;Keeps routine coordination inexpensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Balanced&lt;/td&gt;
&lt;td&gt;Everyday implementation and review&lt;/td&gt;
&lt;td&gt;Preserves quality where most work happens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium&lt;/td&gt;
&lt;td&gt;Deep architecture, hard problems, security escalation&lt;/td&gt;
&lt;td&gt;Saves expensive reasoning for high-leverage moments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fday0nrhuvj3xoc3fl5w9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fday0nrhuvj3xoc3fl5w9.png" alt="Stop using your most expensive model to stamp the paperwork." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Spend the Big Brain Where It Matters
&lt;/h2&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Cost is where the difference shows up first.&lt;/p&gt;

&lt;p&gt;Not in the sad sense of "make it cheaper by making it worse."&lt;/p&gt;

&lt;p&gt;Nobody wants a cheap system that creates expensive problems. That is not savings. That is deferred pain with better branding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spend money where it matters.&lt;/strong&gt; Put premium models on judgment-heavy tasks. Put balanced models on normal implementation. Put cheap and fast models on bounded coordination work.&lt;/p&gt;

&lt;p&gt;That is a much healthier pattern than sending everything through the same premium model and hoping the invoice develops mercy.&lt;/p&gt;

&lt;p&gt;It also changes how you work. Lower marginal cost makes experimentation feel normal again. You ask the extra question. You test the weird idea. You let the machine do the boring cleanup. That matters, because good software work is often iterative and mildly messy before it becomes obvious.&lt;/p&gt;




&lt;h2&gt;
  
  
  Make the Agents Stop Writing Novellas
&lt;/h2&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The second cost saving is funnier, because it is really about manners.&lt;/p&gt;

&lt;p&gt;Agents talk too much.&lt;/p&gt;

&lt;p&gt;Not to users. Users deserve clarity. I want the explanation. I want the reasoning. I want to know what changed and why.&lt;/p&gt;

&lt;p&gt;I mean agents talking to other agents.&lt;/p&gt;

&lt;p&gt;A typical AI handoff can be ridiculously verbose:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After carefully analyzing the implementation surface area, I have determined that the backend engineer should inspect the following files and consider the implications of the existing authentication flow...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sir, this is a task handoff. Nobody asked for the director's commentary.&lt;/p&gt;

&lt;p&gt;The user-facing explanation can stay clear. The machine-to-machine parts can be terse.&lt;/p&gt;

&lt;p&gt;Something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Need backend fix. Files: X, Y. Run tests: Z. Risk: auth. Do not touch docs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Beautiful.&lt;/p&gt;

&lt;p&gt;Primitive.&lt;/p&gt;

&lt;p&gt;Financially responsible.&lt;/p&gt;

&lt;p&gt;The gimmick is funny, but the point is real: &lt;strong&gt;internal communication is not free&lt;/strong&gt;. Every extra word passed between agents costs tokens. Every long summary adds context. Every polite essay burns budget without necessarily improving the outcome.&lt;/p&gt;

&lt;p&gt;At some point, verbosity becomes a feature you are paying to remove.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ntyghfy3jubwhwhxn1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ntyghfy3jubwhwhxn1v.png" alt="One handoff is a dissertation. The other one gets the work done." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Context Is Not Free
&lt;/h2&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;The cost part was obvious. &lt;em&gt;The performance part snuck up on me.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Large AI conversations get heavy in a way that is hard to notice until you have lived inside one for a while. When one big agent does everything, it drags a huge amount of context around with it: requirements, file contents, previous decisions, failed attempts, summaries, side quests, emotional baggage, maybe a recipe for banana bread from three prompts ago.&lt;/p&gt;

&lt;p&gt;That context has a cost.&lt;/p&gt;

&lt;p&gt;It can slow things down. It can increase spend. It can also make the model less focused. Not always dramatically, but enough that you feel the drag.&lt;/p&gt;

&lt;p&gt;The more irrelevant material in the context window, the more chances the model has to get distracted, overreach, or "helpfully" modify something nobody asked it to touch. We have all seen that moment where a small task becomes a surprise renovation.&lt;/p&gt;

&lt;p&gt;The boring-but-effective version: &lt;strong&gt;give each role the context it needs, not the whole attic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The planner gets planning context.&lt;/p&gt;

&lt;p&gt;The frontend engineer gets frontend context.&lt;/p&gt;

&lt;p&gt;The backend engineer gets backend context.&lt;/p&gt;

&lt;p&gt;The reviewer gets the implementation summary and verification evidence.&lt;/p&gt;

&lt;p&gt;We already know this from normal work: you do not invite the entire company into every meeting. At least, you should not. Some calendars are crimes.&lt;/p&gt;

&lt;p&gt;Same idea here.&lt;/p&gt;

&lt;p&gt;Smaller task-specific context usually means faster calls, lower cost, and better focus. It also makes the system easier to reason about. If something goes wrong, you can usually tell where it happened: design, planning, implementation, review, or escalation.&lt;/p&gt;

&lt;p&gt;That is much better than staring at one giant chat transcript and wondering where the raccoon entered the ventilation system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4igjtzl6x666so06hie7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4igjtzl6x666so06hie7.png" alt="Smaller context. Faster calls. Fewer raccoons in the ventilation system." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Process Keeps the Magic From Touching Production Unsupervised
&lt;/h2&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Cost and speed are great.&lt;/p&gt;

&lt;p&gt;But the thing that made this feel worth turning into a real workflow was control.&lt;/p&gt;

&lt;p&gt;AI coding can feel magical, but &lt;strong&gt;magic is not a software delivery process&lt;/strong&gt;. Magic is useful. Magic is fun. Magic should probably not have write access to production-adjacent files without an adult nearby.&lt;/p&gt;

&lt;p&gt;A single agent can write a lot of code quickly. That is useful. It is also risky if there are no boundaries.&lt;/p&gt;

&lt;p&gt;Sometimes the agent edits unrelated files.&lt;/p&gt;

&lt;p&gt;Sometimes it skips tests.&lt;/p&gt;

&lt;p&gt;Sometimes it solves the wrong problem confidently.&lt;/p&gt;

&lt;p&gt;Sometimes it decides that your small UI tweak is the perfect moment to refactor authentication, redesign the database schema, and spiritually rebrand the company. Inspiring? Maybe. Requested? Absolutely not.&lt;/p&gt;

&lt;p&gt;At that point, plain old software process starts looking less boring.&lt;/p&gt;

&lt;p&gt;For substantial work, the flow should look more like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08g216h0h1d1eje41977.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08g216h0h1d1eje41977.png" alt="Magic is useful. Process keeps it from touching production unsupervised." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, there is ceremony in that. I get it. Nobody wants every typo fix to become a government procurement process.&lt;/p&gt;

&lt;p&gt;Tiny, safe tasks should have a fast path.&lt;/p&gt;

&lt;p&gt;But for substantial work, I want the boring safeguards.&lt;/p&gt;

&lt;p&gt;Before code is written, there is a design.&lt;/p&gt;

&lt;p&gt;Before implementation starts, the user approves the plan.&lt;/p&gt;

&lt;p&gt;Implementation tasks have file locks.&lt;/p&gt;

&lt;p&gt;Sensitive areas like auth, payments, secrets, production config, and personal data trigger extra care.&lt;/p&gt;

&lt;p&gt;Agents must provide verification evidence before calling work complete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review is a real phase&lt;/strong&gt;, not a vibes-based victory lap.&lt;/p&gt;

&lt;p&gt;Not to slow everything down. &lt;strong&gt;To stop AI from being confidently chaotic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because the problem with AI coding is not that it cannot produce code. It can produce lots of code. Buckets of code. Code with confidence. Code with explanations. Code that looks like it has somewhere important to be.&lt;/p&gt;

&lt;p&gt;The hard part is making sure it produces the right code, in the right place, with the right review, for the right reason.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Turned Into
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesf0bndjzkjgoqi8hgmj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesf0bndjzkjgoqi8hgmj.png" alt="Oowl NPM Screenshot" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is the shape of &lt;code&gt;oowl&lt;/code&gt;: &lt;strong&gt;OpenCode Opinionated Workflow Layer&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repo: &lt;a href="https://github.com/jimzandueta/oowl" rel="noopener noreferrer"&gt;https://github.com/jimzandueta/oowl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://jimzandueta.github.io/oowl/docs/" rel="noopener noreferrer"&gt;https://jimzandueta.github.io/oowl/docs/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The name is a mouthful, but the idea is not. It is an open-source workflow layer on top of OpenCode that treats AI coding less like one heroic chat session and more like a small engineering process.&lt;/p&gt;

&lt;p&gt;Instead of one giant agent carrying the whole universe, work moves through specialized roles: dispatcher, architect, planner, implementation agents, reviewers, security escalation, low-cost workers for bounded tasks, premium agents when the problem is actually hard.&lt;/p&gt;

&lt;p&gt;Basically, a small engineering team.&lt;/p&gt;

&lt;p&gt;Except nobody asks to move standup to 4:30 and the backend engineer does not have opinions about espresso.&lt;/p&gt;

&lt;p&gt;Not cheap models everywhere. More like: &lt;u&gt;put the expensive thinking where it belongs&lt;/u&gt;, and keep the rest lean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model switching&lt;/strong&gt; reduces cost by matching the model to the task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caveman-Lite&lt;/strong&gt; reduces waste by compressing internal agent communication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller task-specific contexts&lt;/strong&gt; improve speed and focus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An opinionated SDLC process&lt;/strong&gt; makes the workflow safer and more reliable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reason I care about this is that AI coding is moving from novelty to infrastructure.&lt;/p&gt;

&lt;p&gt;The early question was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can AI write useful code?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The more useful question now is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can AI help ship software &lt;u&gt;reliably, repeatedly, affordably, and safely&lt;/u&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That changes the shape of the work.&lt;/p&gt;

&lt;p&gt;And honestly, that is where the conversation gets more interesting to me.&lt;/p&gt;

&lt;p&gt;Model quality matters, obviously. Better models help. But once the models are useful enough, &lt;strong&gt;workflow quality starts to matter just as much&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The future of AI development probably is not one chat window with one all-powerful model doing everything. That is a useful demo, but it is a weird operating model.&lt;/p&gt;

&lt;p&gt;Orchestration feels more durable.&lt;/p&gt;

&lt;p&gt;Different agents. Different responsibilities. Different models. Clear handoffs. Compressed internal communication. Human approval where it actually matters.&lt;/p&gt;

&lt;p&gt;That is the piece &lt;code&gt;oowl&lt;/code&gt; is trying to explore.&lt;/p&gt;

&lt;p&gt;Not perfect. Not universal. Definitely not the final form of anything. But useful enough that I wanted to put it out there.&lt;/p&gt;

&lt;p&gt;Still magical.&lt;/p&gt;

&lt;p&gt;Just with fewer surprise invoices.&lt;/p&gt;

&lt;p&gt;And slightly more caveman.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Built an AI App That Gives You Superpowers, But Makes Them Useless</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Wed, 08 Apr 2026 03:51:52 +0000</pubDate>
      <link>https://forem.com/jimzandueta/i-built-an-ai-app-that-gives-you-superpowers-but-makes-them-useless-kfl</link>
      <guid>https://forem.com/jimzandueta/i-built-an-ai-app-that-gives-you-superpowers-but-makes-them-useless-kfl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/devteam/join-our-april-fools-challenge-for-a-chance-at-tea-rrific-prizes-1ofa"&gt;DEV April Fools Challenge&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1kfkmgijf77pe0tgx5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1kfkmgijf77pe0tgx5i.png" alt="Screens" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built a full-stack AI app that gives you the superpower you ask for, then ruins it with one tiny condition.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You open the site.
&lt;/li&gt;
&lt;li&gt;You rub a magical lamp.
&lt;/li&gt;
&lt;li&gt;A genie shows up.
&lt;/li&gt;
&lt;li&gt;You make a wish.
&lt;/li&gt;
&lt;li&gt;The app grants it in a way that makes the whole thing basically useless.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://cursed-powers--jimzandueta.replit.app/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;cursed-powers--jimzandueta.replit.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;You can become invisible, but only your internal organs.&lt;/li&gt;
&lt;li&gt;You can shape-shift, but only into a slightly uglier version of yourself.&lt;/li&gt;
&lt;li&gt;You can hear other people's thoughts, but only in extinct languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So yes, it works.&lt;/p&gt;

&lt;p&gt;It just works toward a completely worthless outcome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuga0rkcf37tfnytlxrq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuga0rkcf37tfnytlxrq4.png" alt="Genie" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea was simple. I wanted to interpret "useless" a little sideways.&lt;/p&gt;

&lt;p&gt;Instead of making something broken, I made something polished whose output is useless on purpose.&lt;/p&gt;

&lt;p&gt;The app does what it says. The infrastructure is real. The end result is still nonsense.&lt;/p&gt;

&lt;p&gt;So I did not build a useless app.&lt;br&gt;&lt;br&gt;
I built an app that mass-produces uselessness.&lt;/p&gt;

&lt;p&gt;And because I apparently cannot leave a joke alone once it starts working, I also over-engineered it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7xbi6myl77q5q4iz226.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7xbi6myl77q5q4iz226.gif" alt="GIF Demo" width="760" height="608"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The repo includes the app code, infra setup, docs, ADRs, API design, tests, and enough delivery process to make the whole thing feel weirdly official.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jimzandueta" rel="noopener noreferrer"&gt;
        jimzandueta
      &lt;/a&gt; / &lt;a href="https://github.com/jimzandueta/cursed-powers" rel="noopener noreferrer"&gt;
        cursed-powers
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Cursed Powers&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/jimzandueta/cursed-powers/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="MIT License"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jimzandueta/cursed-powers/CONTRIBUTING.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dd0b24c1e6776719edb2c273548a510d6490d8d25269a043dfabbd38419905da/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e737667" alt="PRs Welcome"&gt;&lt;/a&gt;
&lt;a href="https://datatracker.ietf.org/doc/html/rfc2324" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e15a37604340a26c9d8538c9b32ad5cc656b5255a039afb416996db13ccc2d2c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4854435043502d52464325323032333234253230436f6d706c69616e742d626c756576696f6c6574" alt="HTCPCP Compliant"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jimzandueta/cursed-powers/infra/terraform/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/04a8a0a9eb02eb35d30ca2eee66d5edec8626589b06907953413f07a6fee21ae/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4961432d5465727261666f726d2d374234324243" alt="Terraform"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jimzandueta/cursed-powers/docs/adr/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/966f38896b0c4c8f11f3a3ebbd6d2d0e83dcf02545f64ab9dea49dc0b0ebb5a1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d39253230414452732d696e666f726d6174696f6e616c" alt="ADRs"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every superpower has a catch™&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cursed Powers is a full-stack web application that combines AI with interactive storytelling. Users rub a magic lamp to summon a genie, make a superpower wish, and receive a hilariously cursed interpretation of their wish powered by AI.&lt;/p&gt;
&lt;p&gt;The engineering is production-grade. The usefulness is thoroughly cursed.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Lamp Experience&lt;/strong&gt;: Animated lamp-rubbing interface that triggers genie summoning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual AI Providers&lt;/strong&gt;: Fallback-capable integration with Google Gemini 2.5 Flash and OpenAI GPT-4o-mini&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security-First Backend&lt;/strong&gt;: Rate limiting, abuse detection, request signing, CAPTCHA verification, and content moderation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Results&lt;/strong&gt;: WebSocket-ready architecture with progressive result streaming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Deployment&lt;/strong&gt;: Production-ready infrastructure with AWS ECS Fargate, CloudFront CDN, WAF, and automated scaling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Testing&lt;/strong&gt;: 192 unit tests (100% API coverage) + 14 E2E browser tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type-Safe&lt;/strong&gt;: 100% TypeScript with strict mode across frontend and backend&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;                         ┌──────────────────────────────┐
                         │        CloudFront CDN        │
                         │&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jimzandueta/cursed-powers" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;p&gt;Because the infrastructure is part of the punchline, I wanted to show not just the app, but the machinery behind it.&lt;/p&gt;

&lt;p&gt;This project only works as a joke if the output is ridiculous and the implementation is treated with an unreasonable amount of seriousness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture, unfortunately
&lt;/h3&gt;

&lt;p&gt;Under the magical lamp and cursed wishes, this project runs on a stack that is much more serious than the idea deserves.&lt;/p&gt;

&lt;p&gt;That is part of the joke too. This entire system exists to reliably produce unusable superpowers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         ┌──────────────────────────────┐
                         │        CloudFront CDN        │
                         │     + WAF (4 rule groups)    │
                         └──────────────┬───────────────┘
                                        │
                         ┌──────────────▼─────────────────┐
                         │     Application Load Balancer  │
                         │   (TLS 1.3, path-based routing)│
                         └───────┬──────────────┬─────────┘
                                 │              │
                    /api/*       │              │    /*
                   ┌─────────────▼──┐   ┌──────▼────────────┐
                   │   ECS Fargate  │   │   ECS Fargate     │
                   │   Fastify API  │   │   Next.js Web     │
                   │                │   │                   │
                   │  ┌──────────┐  │   │  Security Headers │
                   │  │ Helmet   │  │   │  HSTS, CSP, etc.  │
                   │  │ Rate Lim │  │   └───────────────────┘
                   │  │ Circuit  │  │
                   │  │ Breakers │  │
                   │  └──────────┘  │
                   └───────┬────────┘
                           │
              ┌────────────▼────────────┐
              │    EFS (Encrypted)      │
              │    SQLite + WAL mode    │
              │    Daily backups        │
              └─────────────────────────┘
                           │
            ┌──────────────┼──────────────┐
            │              │              │
      ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼──────┐
      │  Gemini   │ │  OpenAI   │ │  OpenAI    │
      │  2.5 Flash│ │  GPT-4o   │ │  Moderation│
      │ (primary) │ │  (backup) │ │  API       │
      └───────────┘ └───────────┘ └────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If someone only looked at the infrastructure, they might assume it powers something financially important.&lt;/p&gt;

&lt;p&gt;It does not.&lt;/p&gt;

&lt;p&gt;It powers a genie that grants wishes badly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;p&gt;On the surface, the app needed to feel magical before it felt stupid.&lt;/p&gt;

&lt;p&gt;The frontend uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js 15&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Framer Motion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did not want this to feel like a generic AI textbox with a lamp pasted on top. I wanted it to feel a little ceremonial: arrive, rub the lamp, summon the genie, make a wish, then wait for the system to ruin it with confidence.&lt;/p&gt;

&lt;p&gt;So the frontend is responsible for the parts that make the joke land:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lamp animation&lt;/li&gt;
&lt;li&gt;genie reveal&lt;/li&gt;
&lt;li&gt;wish input flow&lt;/li&gt;
&lt;li&gt;result rendering&lt;/li&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;API integration&lt;/li&gt;
&lt;li&gt;request handling&lt;/li&gt;
&lt;li&gt;enough theatricality to make the whole thing feel intentional&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;Once the frontend sets the mood, the backend does the deeply unserious serious work.&lt;/p&gt;

&lt;p&gt;The backend uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fastify 5&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Drizzle ORM&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zod&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pino&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Helmet&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@fastify/rate-limit&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Turnstile verification&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wish submission and validation&lt;/li&gt;
&lt;li&gt;AI orchestration&lt;/li&gt;
&lt;li&gt;cursed power generation&lt;/li&gt;
&lt;li&gt;result retrieval&lt;/li&gt;
&lt;li&gt;gallery and random wish endpoints&lt;/li&gt;
&lt;li&gt;health checks&lt;/li&gt;
&lt;li&gt;moderation&lt;/li&gt;
&lt;li&gt;rate limiting&lt;/li&gt;
&lt;li&gt;request validation&lt;/li&gt;
&lt;li&gt;diagnostics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Honestly, the backend is more serious than the premise deserves.&lt;/p&gt;

&lt;p&gt;That was deliberate.&lt;/p&gt;

&lt;p&gt;If the output is nonsense, the system producing that nonsense should still be solid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google AI / Gemini usage
&lt;/h3&gt;

&lt;p&gt;At the center of all this is the actual wish-ruining engine.&lt;/p&gt;

&lt;p&gt;Gemini is the main model behind the app.&lt;/p&gt;

&lt;p&gt;I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Gemini 2.5 Flash&lt;/strong&gt; as the primary model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI GPT-4o-mini&lt;/strong&gt; as the fallback provider&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI Moderation&lt;/strong&gt; in the safety pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI flow is not just "say something random and funny." It follows a simple structure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;wish → interpret → curse → return a technically valid but practically useless power&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That constraint helped a lot. The outputs became more consistent, easier to read, and usually much funnier.&lt;/p&gt;

&lt;p&gt;The genie is not denying your wish.&lt;br&gt;&lt;br&gt;
The genie is honoring it as maliciously as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ridiculous over-engineering, on purpose
&lt;/h3&gt;

&lt;p&gt;At this point, the second joke becomes obvious:&lt;/p&gt;

&lt;p&gt;the implementation is wildly disproportionate to the value of the product.&lt;/p&gt;

&lt;p&gt;So naturally, this cursed superpower generator includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;npm workspaces + Turborepo&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;shared type-safe schema package&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenAPI 3.1&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;9 architecture decision records&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform-managed AWS infrastructure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudFront CDN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS WAF&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;Application Load Balancer with TLS 1.3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ECS Fargate&lt;/strong&gt; for both web and API&lt;/li&gt;
&lt;li&gt;encrypted &lt;strong&gt;EFS-backed SQLite in WAL mode&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;multi-stage Dockerfiles&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docker-compose&lt;/strong&gt; for local development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI&lt;/strong&gt; with typecheck, lint, unit tests, E2E tests, and commitlint&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;tag-triggered release pipeline&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Husky&lt;/strong&gt; pre-commit, commit-msg, and pre-push hooks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conventional Commits&lt;/strong&gt; enforcement&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;deep health check endpoint&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;runbook&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;incident response guide&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;service level agreement&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTCPCP compliance&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot of joke projects stop at the concept.&lt;/p&gt;

&lt;p&gt;I wanted this one to keep going until the engineering itself became part of the punchline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did I mention it also has 100% unit test coverage?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5csjmrzr004fkuiw2km.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5csjmrzr004fkuiw2km.png" alt="Unit Test" width="800" height="785"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Security, because apparently even cursed wishes need governance
&lt;/h3&gt;

&lt;p&gt;And since I was already making terrible but committed decisions, I also spent real time on security.&lt;/p&gt;

&lt;p&gt;That includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CloudFront + AWS WAF&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Helmet&lt;/strong&gt; security headers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rate limiting&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Turnstile&lt;/strong&gt; CAPTCHA support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zod&lt;/strong&gt; schema validation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI provider circuit breakers&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;content moderation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CORS&lt;/strong&gt; configuration&lt;/li&gt;
&lt;li&gt;proxy awareness for real client IP handling&lt;/li&gt;
&lt;li&gt;vulnerability reporting documentation&lt;/li&gt;
&lt;li&gt;dependency monitoring through CI and GitHub alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is this more security planning than most genie interactions require?&lt;br&gt;&lt;br&gt;
Yes.&lt;/p&gt;

&lt;p&gt;Was I going to stop because of that?&lt;br&gt;&lt;br&gt;
Obviously not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teapot compliance
&lt;/h3&gt;

&lt;p&gt;Is &lt;code&gt;418&lt;/code&gt; and &lt;code&gt;teapot&lt;/code&gt; a super power?&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize category
&lt;/h2&gt;

&lt;p&gt;I would like to be considered for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Best Google AI Usage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best Ode to Larry Masinter&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;the main &lt;strong&gt;DEV April Fools Challenge&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This app is not useless because it is broken.&lt;/p&gt;

&lt;p&gt;It is useless because it is &lt;strong&gt;very good at producing unusable results.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the whole bit.&lt;/p&gt;

&lt;p&gt;Some people use software to solve meaningful problems.&lt;/p&gt;

&lt;p&gt;I used software to build a scalable platform for granting wishes badly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The system is stable.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The infrastructure is serious.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The output is useless.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is exactly what I set out to build.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>418challenge</category>
      <category>ai</category>
      <category>showdev</category>
    </item>
    <item>
      <title>The Codex Setup That Worked for Us: Memory, Manifests, and Structured Context</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Wed, 01 Apr 2026 07:14:45 +0000</pubDate>
      <link>https://forem.com/jimzandueta/from-ai-chaos-to-team-flow-codex-boilerplate-that-actually-worked-5fa1</link>
      <guid>https://forem.com/jimzandueta/from-ai-chaos-to-team-flow-codex-boilerplate-that-actually-worked-5fa1</guid>
      <description>&lt;p&gt;&lt;strong&gt;The past few weeks have been wild.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our team recently adopted &lt;strong&gt;AI-assisted programming&lt;/strong&gt; (not vibe-coding). We wanted speed, consistency, and fewer repetitive tasks.&lt;br&gt;&lt;br&gt;
What we got in week one was... chaos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR&lt;br&gt;
We had &lt;strong&gt;inconsistent AI output&lt;/strong&gt; across teammates, treated it as a &lt;strong&gt;systems problem&lt;/strong&gt;, applied Agentic SDLC principles, and built a &lt;code&gt;.codex&lt;/code&gt; structure that made Codex outputs &lt;strong&gt;far more consistent&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Quick Jump
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What worked (and what didn’t)&lt;/li&gt;
&lt;li&gt;The shift: Agentic Software Development Lifecycle&lt;/li&gt;
&lt;li&gt;What’s inside &lt;code&gt;.codex&lt;/code&gt; (and why it matters)&lt;/li&gt;
&lt;li&gt;How we used it in this repo&lt;/li&gt;
&lt;li&gt;What’s next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even with detailed technical tickets, our AI agents kept producing outputs that didn’t line up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;different &lt;strong&gt;naming conventions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;different &lt;strong&gt;folder structures&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;different &lt;strong&gt;approaches to the same problem&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;different &lt;strong&gt;error-handling and testing styles&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every merge felt like stitching code from three different universes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9qa4grriown1y2r5vf8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9qa4grriown1y2r5vf8.jpg" alt="Distracted Boyfriend Meme" width="750" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Week one energy:&lt;/strong&gt; &lt;em&gt;us trying to keep standards while random AI output keeps walking by.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What worked (and what didn’t)
&lt;/h2&gt;

&lt;p&gt;We tested different setups.&lt;/p&gt;

&lt;p&gt;A strong &lt;code&gt;CLAUDE.md&lt;/code&gt; helped a lot early. Claude Opus was excellent at reasoning and breaking work down step by step.&lt;br&gt;&lt;br&gt;
The issue for us was practical: &lt;strong&gt;limits and timeouts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since our company sponsors Codex, we moved to Codex as our main tool. First impression? &lt;strong&gt;A bit lackluster&lt;/strong&gt; compared to Claude out of the box.&lt;/p&gt;

&lt;p&gt;That pushed us to a better question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maybe this isn’t just a model problem. Maybe it’s a &lt;u&gt;system problem&lt;/u&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="//i.imgflip.com/ao4a58.jpg" class="article-body-image-wrapper"&gt;&lt;img src="//i.imgflip.com/ao4a58.jpg" alt="Drake Meme"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The shift: Agentic Software Development Lifecycle
&lt;/h2&gt;

&lt;p&gt;Quick diff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traditional SDLC: &lt;strong&gt;mostly human implementation through linear phases&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A-SDLC: &lt;strong&gt;human + AI-agent collaboration in tight feedback loops&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In A-SDLC, developers don’t just write code. We &lt;strong&gt;orchestrate&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;guardrails&lt;/li&gt;
&lt;li&gt;context&lt;/li&gt;
&lt;li&gt;fast reviews&lt;/li&gt;
&lt;li&gt;memory updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yes, we’re &lt;strong&gt;actively applying&lt;/strong&gt; these principles in real day-to-day work, not just talking about them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better prompts&lt;/li&gt;
&lt;li&gt;tighter feedback loops&lt;/li&gt;
&lt;li&gt;stronger project memory&lt;/li&gt;
&lt;li&gt;clear constraints, patterns, and checklists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we treated this as a systems problem, &lt;strong&gt;output quality improved fast&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s why I built this boilerplate: to showcase the &lt;code&gt;.codex&lt;/code&gt; setup that worked best for us.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/jimzandueta/nestjs-http-server-boilerplate-codex-ai-assisted" rel="noopener noreferrer"&gt;github.com/jimzandueta/codex-nestjs&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What’s inside &lt;code&gt;.codex&lt;/code&gt; (and why it matters)
&lt;/h2&gt;

&lt;p&gt;This isn’t just a random folder. It’s the &lt;strong&gt;operating system&lt;/strong&gt; for consistent AI-assisted engineering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.codex/
  START_HERE.md
  RULES.md
  MANIFEST.yaml
  instructions/
  patterns/
  anti-patterns/
  checklists/
  skills/
  prompts/
  templates/
  overrides/
  memory/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F%2F%2Fi.imgflip.com%2Fao4aax.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F%2F%2Fi.imgflip.com%2Fao4aax.jpg" alt="Expanding Brain Meme" width="500" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1) &lt;code&gt;START_HERE.md&lt;/code&gt; + &lt;code&gt;RULES.md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;These are your baseline guardrails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Output Rules&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Reuse existing patterns before inventing new ones.
&lt;span class="p"&gt;2.&lt;/span&gt; Keep diffs minimal.
&lt;span class="p"&gt;3.&lt;/span&gt; Never commit secrets.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This alone prevents a lot of “same task, five coding styles” situations.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) &lt;code&gt;MANIFEST.yaml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is context routing. It tells the agent what to load for each task type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task_routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;new-feature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/instructions/global.md&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/patterns/repo-structure.md&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/patterns/error-handling.md&lt;/span&gt;
    &lt;span class="na"&gt;skills&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/skills/new-feature/SKILL.md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So agents don’t start cold. They start with the right playbook.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) &lt;code&gt;instructions/&lt;/code&gt;, &lt;code&gt;patterns/&lt;/code&gt;, &lt;code&gt;anti-patterns/&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;instructions/&lt;/code&gt;: how to work&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;patterns/&lt;/code&gt;: preferred way to build&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;anti-patterns/&lt;/code&gt;: what to avoid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of this as turning tribal team knowledge into repeatable, machine-readable engineering practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) &lt;code&gt;checklists/&lt;/code&gt;, &lt;code&gt;skills/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, &lt;code&gt;templates/&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the day-to-day execution layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;checklists/&lt;/code&gt;: quality gates&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skills/&lt;/code&gt;: repeatable workflows&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prompts/&lt;/code&gt;: reusable prompt scaffolds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;templates/&lt;/code&gt;: starter artifacts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example checklist snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Tests&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] New logic has happy path + failure test
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Coverage stays at 100% threshold
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No flaky tests introduced
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5) &lt;code&gt;overrides/&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This lets you keep generic Codex assets while declaring project reality.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generic pattern: “recommended structure”&lt;/li&gt;
&lt;li&gt;project override: “this NestJS repo uses &lt;code&gt;src/common&lt;/code&gt;, &lt;code&gt;src/clients&lt;/code&gt;, &lt;code&gt;src/modules&lt;/code&gt;, etc.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6) &lt;code&gt;memory/&lt;/code&gt; (the secret sauce)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;This is where consistency compounds:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;memory/project-facts.md&lt;/code&gt; → stable project truths&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;memory/decisions.md&lt;/code&gt; → ADR-style decisions/tradeoffs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;memory/learned-patterns.md&lt;/code&gt; → recurring conventions discovered during work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As new decisions are made between the developer and AI agent, memory gets updated so future tasks inherit the &lt;strong&gt;same context and tradeoffs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A realistic flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer: “We need &lt;code&gt;requestId&lt;/code&gt; in logs for traceability.”&lt;/li&gt;
&lt;li&gt;Agent: “Two options: &lt;code&gt;AsyncLocalStorage&lt;/code&gt; or explicit propagation.”&lt;/li&gt;
&lt;li&gt;Team decision: explicit propagation first (simpler + easier to test).&lt;/li&gt;
&lt;li&gt;Memory updates: ADR + project convention + learned pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sample ADR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### ADR-002: Standardize request correlation IDs in HTTP logs&lt;/span&gt;

&lt;span class="gs"&gt;**Date**&lt;/span&gt;: 2026-04-02
&lt;span class="gs"&gt;**Status**&lt;/span&gt;: Accepted

&lt;span class="gs"&gt;**Context**&lt;/span&gt;: Debugging incidents was slow because logs across layers were hard to correlate.
&lt;span class="gs"&gt;**Decision**&lt;/span&gt;: Add &lt;span class="sb"&gt;`requestId`&lt;/span&gt; at the HTTP boundary and propagate it through services/clients.
&lt;span class="gs"&gt;**Consequences**&lt;/span&gt;: Better traceability, with slight method-signature overhead.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample project facts update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Logging: include &lt;span class="sb"&gt;`requestId`&lt;/span&gt; in structured logs for HTTP flows.
&lt;span class="p"&gt;-&lt;/span&gt; Request context: generate/forward &lt;span class="sb"&gt;`x-request-id`&lt;/span&gt; at ingress and propagate downstream.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample learned pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### LP-001: Propagate requestId from boundary to integrations&lt;/span&gt;

&lt;span class="gs"&gt;**Observed**&lt;/span&gt;: Missing correlation fields made multi-step failures harder to debug.
&lt;span class="gs"&gt;**Rule**&lt;/span&gt;: Controllers create context; services/clients forward &lt;span class="sb"&gt;`requestId`&lt;/span&gt;; logs include it at each layer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This memory layer is the difference between &lt;strong&gt;“new agent, same mistakes”&lt;/strong&gt; and &lt;strong&gt;“new agent, same team brain.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hmq2wec5te94fpyjhfq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hmq2wec5te94fpyjhfq.jpg" alt="Change My Mind Meme" width="578" height="433"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How we used it in this repo (&lt;a href="https://github.com/jimzandueta/nestjs-http-server-boilerplate-codex-ai-assisted" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;Using this &lt;code&gt;.codex&lt;/code&gt; setup, we built a NestJS sample HTTP server with consistent architecture and quality gates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clear boundaries (&lt;code&gt;common&lt;/code&gt;, &lt;code&gt;clients&lt;/code&gt;, &lt;code&gt;integrations&lt;/code&gt;, &lt;code&gt;modules&lt;/code&gt;, &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;errors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;validated runtime config (&lt;code&gt;HOST&lt;/code&gt;, &lt;code&gt;PORT&lt;/code&gt;, &lt;code&gt;NODE_ENV&lt;/code&gt;, &lt;code&gt;LOG_LEVEL&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;structured logging&lt;/li&gt;
&lt;li&gt;reusable HTTP client with timeout/retry&lt;/li&gt;
&lt;li&gt;typed external API errors + global exception filter&lt;/li&gt;
&lt;li&gt;sample feature module (&lt;code&gt;posts&lt;/code&gt;) using JSONPlaceholder&lt;/li&gt;
&lt;li&gt;strict tests with &lt;strong&gt;100% coverage thresholds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;open-source docs (&lt;code&gt;LICENSE&lt;/code&gt;, &lt;code&gt;CONTRIBUTING&lt;/code&gt;, &lt;code&gt;CODE_OF_CONDUCT&lt;/code&gt;, &lt;code&gt;SECURITY&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this repo isn’t just “another Nest starter.”&lt;br&gt;&lt;br&gt;
It’s a &lt;strong&gt;working example of structured AI-assisted delivery&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  One important note
&lt;/h2&gt;

&lt;p&gt;Codex setups are usually &lt;strong&gt;stack-specific&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;.codex&lt;/code&gt; is tuned for a NestJS HTTP app. I maintain a different Codex baseline for Terraform/infrastructure because workflows, anti-patterns, and quality gates are different.&lt;/p&gt;

&lt;p&gt;Same core idea, different playbook.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;I’ll keep evolving this repo with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;richer feature module examples&lt;/li&gt;
&lt;li&gt;better integration patterns&lt;/li&gt;
&lt;li&gt;stricter review automations&lt;/li&gt;
&lt;li&gt;stack-specific Codex variants&lt;/li&gt;
&lt;li&gt;deeper AI-agent orchestration experiments using open-source tools like LangChain, Langfuse, and local models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your team is in that “week one AI chaos” phase, start with structure first.&lt;br&gt;&lt;br&gt;
Model quality matters, but &lt;strong&gt;system quality matters more&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6uwzflh2jp2aw0om185.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6uwzflh2jp2aw0om185.jpg" alt="One Does Not Simply Meme" width="651" height="384"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  IMPORTANT: Here's a picture of my cat!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhike758eb3ofx0pshgu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhike758eb3ofx0pshgu.png" alt="Hi Chidi!" width="800" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>ai</category>
      <category>nestjs</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Allow Users to Upload and Download Data from AWS S3 Without Direct Access Using Pre-Signed URLs?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Sat, 24 Dec 2022 05:49:34 +0000</pubDate>
      <link>https://forem.com/jimzandueta/how-to-allow-users-to-upload-and-download-data-from-aws-s3-without-direct-access-using-pre-signed-urls-h33</link>
      <guid>https://forem.com/jimzandueta/how-to-allow-users-to-upload-and-download-data-from-aws-s3-without-direct-access-using-pre-signed-urls-h33</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Amazon Simple Storage Service (AWS S3) is a popular cloud storage service that allows users to store and retrieve data from a variety of sources. While S3 buckets are set to public by default, there are times when it is necessary to restrict access to specific users or groups. Direct access to the bucket in these scenarios may pose security risks and limit flexibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Direct access to an AWS S3 bucket necessitates exposing the AWS access keys and secret keys to users, which can result in unauthorized access to the bucket and its contents. Furthermore, using this method, it may be impossible to control specific actions or limit access time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Pre-signed URLs provide a secure solution by allowing users to access specific objects in the bucket without exposing the AWS access keys and secret keys. Pre-signed URLs can also be used to restrict specific actions that users can take and to limit the amount of time that a user has access to the data.&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;p&gt;To generate pre-signed URLs in TypeScript, you can use the &lt;code&gt;aws-sdk&lt;/code&gt; package, which provides a &lt;code&gt;getSignedUrl&lt;/code&gt; method that can be used to generate a pre-signed URL for a specific S3 object. Here's an example of how to use &lt;code&gt;getSignedUrl&lt;/code&gt; to generate a pre-signed URL for downloading an S3 object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generate a pre-signed URL for an S3 object&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generatePresignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;expiration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expiration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrlPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-s3-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path/to/my/object.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expiration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// URL will expire in 60 seconds&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generatePresignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expiration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Outputs a pre-signed URL that can be used to access the object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To generate a pre-signed URL for uploading an S3 object, you can use the putObject method in a similar way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Configure the AWS SDK with your S3 bucket's credentials&lt;/span&gt;
&lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;accessKeyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ACCESS_KEY_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secretAccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Create an Express.js router&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Route for generating a pre-signed URL for uploading a file to S3&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if the file was included in the request&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No file provided&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the file and other parameters from the request body&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Generate a pre-signed URL for uploading the file to S3&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ACL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Set the ACL to "private"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Send the pre-signed URL back to the client&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Send an error response if something went wrong&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Export the router&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;// Example Usage&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Function to upload a file to S3 using a pre-signed URL&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the headers for the request&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// Make the PUT request to the pre-signed URL&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Check the status of the response&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs 201 if upload was successful&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, world!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;server_url&amp;gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;uploadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pre-signed URLs are a convenient and secure way for users to access data in an AWS S3 bucket without granting direct access. To use pre-signed URLs, use the AWS SDK to generate a URL for a specific object in the bucket. The generated URL can then be provided to the user, who can use it to access the object within the time period specified in the URL.&lt;/p&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html" rel="noopener noreferrer"&gt;AWS documentation on pre-signed URLs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property" rel="noopener noreferrer"&gt;AWS SDK for JavaScript documentation on getSignedUrl method&lt;/a&gt;: &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>How to connect to the same host with different SSH keys?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Tue, 16 Aug 2022 14:12:00 +0000</pubDate>
      <link>https://forem.com/jimzandueta/setup-your-ssh-configuration-file-1m9e</link>
      <guid>https://forem.com/jimzandueta/setup-your-ssh-configuration-file-1m9e</guid>
      <description>&lt;p&gt;&lt;strong&gt;Required Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/jimzandueta/generate-an-ssh-key-pair-2fcc"&gt;Generate an SSH key pair&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup your SSH configuration file
&lt;/h2&gt;

&lt;p&gt;When connecting to a remote server via SSH, we would use the command line to specify the remote user name, hostname, and port, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh tony@avengers.com &lt;span class="nt"&gt;-p&lt;/span&gt; 4321
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can connect to the server using the same options as in the previous command by typing &lt;code&gt;ssh avengers&lt;/code&gt; after adding the following lines to your &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Host avengers
    HostName avengers.com
    User tony
    Port 4321
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also specify which SSH key to use when connecting to a specific server in the configuration file by setting &lt;code&gt;IdentityFile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Host avengers
    HostName avengers.com
    User tony
    Port 4321
    IdentityFile ~/.ssh/id_rsa_avengers

Host marvel
    HostName marvel.com
    User tony
    Port 8080
    IdentityFile ~/.ssh/id_rsa_marvel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use of &lt;code&gt;IdentityFile&lt;/code&gt; is especially useful when connecting to the same hostname with different SSH keys. A real-world example would be having multiple Github accounts, such as personal and work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Host github_personal
    HostName github.com
    IdentityFile ~/.ssh/github_personal

Host github_work
    HostName github.com
    IdentityFile ~/.ssh/github_work

IdentityFile ~/.ssh/id_rsa 
&lt;span class="c"&gt;#default ssh key to use for all other hosts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the configuration file above, we can clone repositories from your personal Github account with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone git@github_personal:tonystark/ultron.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that instead of &lt;code&gt;@github.com&lt;/code&gt; as the host name, we use &lt;code&gt;@github_personal&lt;/code&gt; as defined in the configuration file.&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updating the configuration file:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open your favorite terminal&lt;/li&gt;
&lt;li&gt;Create/Open the SSH configuration file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nano ~/.ssh/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ssh.com/academy/ssh/config"&gt;git config file syntax&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>How to generate a secure SSH key pair?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:39:00 +0000</pubDate>
      <link>https://forem.com/jimzandueta/generate-an-ssh-key-pair-2fcc</link>
      <guid>https://forem.com/jimzandueta/generate-an-ssh-key-pair-2fcc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Required Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate an SSH key pair
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open your favorite terminal&lt;/li&gt;
&lt;li&gt;Run the ssh-keygen command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"tonystark@avengers.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;INFO: For increased security, the type flag &lt;code&gt;-t rsa&lt;/code&gt; and the bits &lt;code&gt;flag -b 4096&lt;/code&gt; are required. The comment flag &lt;code&gt;-C "tonystark@avengers.com"&lt;/code&gt; allows us to easily identify who owns the SSH key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Specify the key file name. Default is &lt;code&gt;id_rsa&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enter a passphrase *&lt;em&gt;optional&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kBWO3CPz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8qdopzivgs2inx9xt69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kBWO3CPz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8qdopzivgs2inx9xt69.png" alt="ssh-keygen-sample" width="880" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WARNING: If you already have a default SSH key ~/.ssh/id_rsa, &lt;strong&gt;DO NOT OVERWRITE IT&lt;/strong&gt;. If you are not careful, you will lose SSH access to your cloud servers and git platforms. Instead, give your new SSH key a new name, such as id_rsa_avengers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ssh.com/academy/ssh/keygen"&gt;ssh-keygen | SSH Tutorial &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>How to setup your global (and local) git profile?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:29:00 +0000</pubDate>
      <link>https://forem.com/jimzandueta/setup-your-git-profile-3i06</link>
      <guid>https://forem.com/jimzandueta/setup-your-git-profile-3i06</guid>
      <description>&lt;p&gt;&lt;strong&gt;Required Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup your git profile
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open your favorite terminal&lt;/li&gt;
&lt;li&gt;Set your git username
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"Tony Stark"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set your git email
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email tonystark@avengers.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set your git editor *&lt;em&gt;optional&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; core.editor nano 
&lt;span class="c"&gt;# you can also use emacs (nostalgic) or vim (adventurous). &lt;/span&gt;
&lt;span class="c"&gt;# Vim is the default editor.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Review your settings
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="nt"&gt;--show-origin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The global flag --global will apply the configuration to the current operating system profile/user. If you want to apply your configuration at the local level, navigate to the project's root directory (where the.git folder is located) and run the git config commands without the global flag, or use the local flag --local to be more verbose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-config"&gt;git config | Atlassian Git Tutorial &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup"&gt;Git - First-Time Git Setup &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>macOS: Moving Your Notification to a Different Display</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Fri, 08 May 2020 09:26:07 +0000</pubDate>
      <link>https://forem.com/jimzandueta/macos-moving-your-notification-to-a-different-display-17bi</link>
      <guid>https://forem.com/jimzandueta/macos-moving-your-notification-to-a-different-display-17bi</guid>
      <description>&lt;p&gt;My current display configuration includes my Macbook to the right and a 27" BenQ Monitor in front of me. The larger screen houses all of my work-related applications, while the smaller one houses my calendar, calculator, and Spotify.&lt;/p&gt;

&lt;p&gt;For as long as I can remember, all of my notifications would appear on the screen of my Macbook. I never thought about it before, but after getting in trouble for missing several critical Slack messages, I realized I needed to do something about it.&lt;/p&gt;

&lt;p&gt;I did some research and here's what I discovered:&lt;/p&gt;

&lt;p&gt;Setting up multiple displays on macOS is a simple process. Simply navigate to System Preferences &amp;gt; Displays &amp;gt; Arrangement and drag the screens to the desired location.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ip3QzgpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sopy9q2td40hfmviem9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ip3QzgpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sopy9q2td40hfmviem9z.png" alt="Display Arrangement" width="780" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the white bar on top of the small screen icon. That, believe it or not, is the &lt;strong&gt;Menu Bar&lt;/strong&gt;. It handles a lot of things, including notifications! &lt;/p&gt;

&lt;p&gt;I simply dragged it to the screen icon on the left, and after a few flashes, my 27" display became my main monitor (displaying notifications), and my Macbook became the extension monitor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---_Wocll2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ljonxhabfks995jzll4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---_Wocll2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ljonxhabfks995jzll4x.png" alt="Alt Text" width="780" height="619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, moving the menu bar icon will &lt;strong&gt;rearrange&lt;/strong&gt; your desktop. So, if you have your applications organized across multiple desktops, consider cleaning them up first.&lt;/p&gt;

&lt;p&gt;I hope this was helpful. Happy coding!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>macos</category>
      <category>productivity</category>
      <category>tips</category>
    </item>
  </channel>
</rss>
