Latest Posts (20 found)
Kaushik Gopal 2 weeks ago

What it means to be a truly AI-native software company

Everyone says they’re rebuilding their company in an AI-native way. But what does that mean? Most companies look at what their existing employees do and try to automate it with AI. That’s not it. That’s dabbling. A truly AI-native company rethinks every role and tears down the walls between them. None of us can 8-ball this but here’s my sketch. It’s not exhaustive but hopefully it sparks something: The QA team typically finds bugs and dutifully files them in Jira. Engineering has finite capacity, so they fix the P1s and freeze the rest. P2 and P3 bugs die in the backlog — the UX nits, the copy, the small fixes. An AI-native QA team files the bug and immediately points an agent at it. The agent takes a first pass, finds a root cause, proposes a fix, and opens a PR — then sends a test build right back to QA to verify. Along the way the bug is updated in detail, so if it needs escalation to the engineer who built it, all the context is right there. A more advanced team has a loop wired to trigger the minute a bug is filed. A PM understands the business and goals well. They write a thoughtful PRD — but it’s often 70% done. How are they to keep the full codebase and every edge case in their head? The engineer starts building, hits those edge cases mid-feature, and bounces it back to the PM who has better intuition. Tweak the PRD, back to the engineer. This can happen for every slice of that remaining 30%, and it’s frustrating for everyone. An AI-native PM sends an agent to walk the real code, surface those forks up front, and spin up throwaway prototypes to explore each one. They keep a knowledge base of past decision briefs so the team doesn’t rebuild what was already ruled out. With that in hand, they produce a fully specced PRD — and maybe pushing further, include end-to-end tests defining what done looks like. Designers mock up screens in Figma and ship them over, hoping what shows up in production matches their pixel-perfect specs. Realistically, how often does that happen? When they run user research studies or are testing the app, they find plenty of design nits, UX failures, and copy suggestions — then file tickets and wait. An AI-native designer prototypes variants on the real app with real data and real states. They get to play with throwaway builds of the actual codebase and can design towards a stronger, more realistic spec — with real constraints, like how that animation actually runs on an Android 12 device. Polish-related work doesn’t die in ticket wasteland anymore. It runs through the same loop QA uses: the agent makes the change and preflights a build for the designer to check by eye. They have the taste, and now the agency to ship it on the spot. Data scientists live downstream, so they feel every change last. They’re often looped in at the end, when the feature is mostly built and engineers need to tack on the instrumentation. Or worse, they discover engineering renamed an event in a refactor and mission-critical dashboards quietly broke in production — caught days later, when the build is already out. The old move: file a ticket and wait for engineering’s queue. An AI-native data scientist reaches for an agent instead — tracing a break to a renamed event and sending the fix as a PR, or instrumenting a metric they couldn’t measure yet without waiting on anyone. Pushing further, the old way to test a hypothesis was to ship, wait for real data to accumulate, then lean on engineering and product to make changes. An AI-native data scientist runs the test before anything ships — generating synthetic data and simulating scenarios with agents to show the PM which option wins, then putting up the winning approach as a PR for engineering to review, tweak, and ship. If you noticed a trend above, we’re distributing a lot of what engineering typically does to other roles. So what’s left for engineers? Plenty. I see three roles emerging: Product engineers : If I’m being honest, the line between this role and the AI-native PM blurs — eventually converging. I’m not saying engineers become PMs or PMs become engineers. I think both are heading toward a “product specialist” role: highly opinionated people who understand the product so well that they can take an idea to a live feature in days. System engineers : The platform watchers. They ensure the codebase is healthy, understand the infrastructure constraints, and make the judgment calls on how the architecture has to evolve. When there are five ways to build something, they pick the one that won’t hurt later. Loop engineers : I think this becomes the generalist SWE role. These are the people who build and maintain the loops for every other role: the inboxes, the triggers, the verification gates, the escalation paths. QA, PMs, designers, and data scientists shouldn’t be wiring those connectors — they should be doing the work described above. When the walls between roles come down, the loop engineer is the load-bearing structure. I went deep on the mechanics in loop engineering . It’s real engineering work, and someone has to own it. Bolting AI onto the jobs we already have isn’t how you build an AI-native software company. You have to rethink the roles and tear down the walls between them. Product engineers : If I’m being honest, the line between this role and the AI-native PM blurs — eventually converging. I’m not saying engineers become PMs or PMs become engineers. I think both are heading toward a “product specialist” role: highly opinionated people who understand the product so well that they can take an idea to a live feature in days. System engineers : The platform watchers. They ensure the codebase is healthy, understand the infrastructure constraints, and make the judgment calls on how the architecture has to evolve. When there are five ways to build something, they pick the one that won’t hurt later. Loop engineers : I think this becomes the generalist SWE role. These are the people who build and maintain the loops for every other role: the inboxes, the triggers, the verification gates, the escalation paths. QA, PMs, designers, and data scientists shouldn’t be wiring those connectors — they should be doing the work described above. When the walls between roles come down, the loop engineer is the load-bearing structure. I went deep on the mechanics in loop engineering . It’s real engineering work, and someone has to own it.

0 views
Kaushik Gopal 1 months ago

OpenCode power user tips

In this post, I’d like to talk about some power user tips for OpenCode - an open source , model agnostic harness that more people should be using. Hopefully some of the advanced use cases convince you to give OpenCode (and OpenChamber ) a shot. intermediate to advanced tips only I am specifically choosing to talk about some advanced tips in this post. If you’ve never used an agent harness or are looking to learn how to use OpenCode, this post can be useful but reader beware. While (Ctrl + P) will list out all the possible commands (and is helpful), OpenCode has the concept of a “leader” key (which defaults to ). The leader key allows you to execute targeted useful commands more quickly and there’s a slew of useful ones pre-defined 1 . People reach for whole terminals and extra tooling to juggle between agent sessions. I too had an overly customized tmux setup that looked like this: OpenCode simplifies this. Just hit and you view current sessions and can instantly switch to that session by just selecting it from the list. The ability to quickly rename a session from this view is a godsend for me and what lets me be organized. session directory filtering you can pass a flag to when launching it, which filters the session list to just this workspace/directory by default. You can alternatively not pass that flag, and the session list will show all sessions. Forking takes the session you’re in and spawns a new one. You branch off into a separate conversation while the main agent keeps grinding on whatever you left it doing. I love this feature and even cobbled my own version with tmux long before most harnesses shipped it. Claude Code, Codex and other harnesses have caught up and support this feature. But OpenCode’s UX is the smoothest. You simply type in your chat. It gives you the option to fork the current chat or from a previous point in the message. You can then rename the forked session right from the list ui, and jump back and forth. The easy session switching again comes in handy here. Need to rewind to an earlier point in the same conversation? In OpenCode, there’s no escape-escape dance. leader g shows you a timeline and you can revert the conversation instantly, fork a new session from there, or just copy the message text. Probably one of the main reasons I find it hard switching away from OpenCode. I can bounce between GPT-5.5, Kimi K2.6, and Opus by just hitting 2 . change model & reasoning + switches the model on the fly. changes the reasoning type. I see a future where we will have smaller models we can run locally. OpenCode can point to that ollama model you have running on your own machine too. Click here if you’re curious about my model choices. Not everyone realizes this but OpenCode ships with LSP servers built-in . This means the coding agents inside OpenCode understand how to navigate different programming languages better. You’ll find less file search and grepping. Anthropic even recommends LSP server integration as an advanced move for making harnesses behave in large codebases. OpenCode gives you much of that for free. The other reason I swear by OpenCode: hit to cycle through custom agents. Here’s a few I use a lot: view the subagent work When an agent fans work out to subagents, + pulls up the subagent view so you can watch them work. Like others, you can use OpenCode for scripting and one-shot reviews: So up until now, I’ve mostly talked about features in the context of the TUI. My good friend YY recently introduced me to OpenChamber and it’s changed a lot of things for me. OpenChamber is an OpenCode GUI wrapper. OpenCode already has a web client btw. But OpenChamber has a lot of nice bells and whistles. But here’s the kicker, it’s using your same OpenCode server. In a previous post I dug into OpenCode’s server-client architecture: you run OpenCode as a server and connect multiple clients to it. A client can be a terminal tab, your phone, a desktop, a browser — each an isolated session pointed at the same server, fully synced. OpenChamber is just another client, but a super powered GUI one. This feature has taken the world by storm; especially since Codex introduced their implementation. OpenChamber gives you this feature for free with a super nice UX. One button click and either using or internally, it opens a secure 3 tunnel that you can connect your phone or another client to. So now, your phone controls OpenChamber and by proxy OpenCode exactly as you would from your computer. This was possible with OpenCode and tailscale too (as I mentioned in my previous post) but OpenChamber’s UX and secure tunnel approach makes this fluid. I almost never take my work laptop with me, when I’m getting out of the house now. Just speaking to my phone and a browser tab that has OpenChamber open. The other OpenChamber feature I lean on: multi-run. You have a prompt and want to try it across several models at once. I think Cursor was the first to introduce this feature. OpenChamber provides a super nice UI for this. This is how I’ve been kicking the tires on Opus 4.8 and updating my model choices . There’s just one caveat to be aware of. OpenChamber by default probes for a running OpenCode server. If it doesn’t find an OpenCode server there, it will silently spawn its own. So if you truly want all your sessions in sync, you should start your OpenCode server on port first, then open OpenChamber regularly and it’ll attach to the one you already have. I have a handy shell alias to just start a background OpenCode server now like so: If you didn’t read this tip in time, and need to kill previous OpenCode server instances, I suggest the handy procs cli command. There’s a lot more to both OpenCode and OpenChamber, but this is the stuff I reach for daily. The bit that’s stuck with me most is the one-server, many-clients setup — run a single OpenCode server and point everything at it: the TUI, OpenChamber, your phone. Steal whatever helps here, and if there’s a tip I’m sleeping on, send it my way. OpenChamber v1.12.0 tunnel bug Heads up: OpenChamber v1.12.0 added a headless web app mode, and remote instance switching now changes the OpenChamber API endpoint without loading the full remote UI. This seems to have busted the remote mobile tunnel setup I describe above. :/ The developer is responsive and working on a fix 🤞. Until then, I recommend sticking to v1.11.7 , which you can download manually. You can also bind commands that don’t have a predefined key. As an example, I bind the “Exit the app” command to so I can quit OpenCode quickly.  ↩︎ yes yes, you’re probably nuking your prompt/KV cache, but you shouldn’t have long running conversations anyway.  ↩︎ one-time + TTL + revocable connect link  ↩︎ + switches the model on the fly. changes the reasoning type. red-team — think differently from the implementer with an independent adversarial lens and hunt for failure modes. ghostwriter — drafts messages, posts with a less AI tropey voice. brainstormer — custom agent that’s explicitly tuned to help me brainstorm ideas, plans etc. pr-reviewer — strict reviewer that ignores past conversation and reviews with fresh eyes. kimi-coder — a coding agent guardrailed to Kimi: fast, cheap implementation. agent-kombat — see my agent-kombat post. I have it wired into a custom agent for quick use. You can also bind commands that don’t have a predefined key. As an example, I bind the “Exit the app” command to so I can quit OpenCode quickly.  ↩︎ yes yes, you’re probably nuking your prompt/KV cache, but you shouldn’t have long running conversations anyway.  ↩︎ one-time + TTL + revocable connect link  ↩︎

0 views
Kaushik Gopal 1 months ago

AI model choices 2026-06

My 2026 Jan AI tool stack. Six months since my last post and the whole list has turned over. I constantly try multiple harnesses but I think I’ve firmly settled on OpenCode paired with OpenChamber as my harness of choice. Stay tuned for a future post on power tips for OpenCode, but I put a lot of these harnesses through the ringer and am really happy with this combo atm. I still drop often into TUI land with OpenCode and while like others I had my dalliance with cmux, I’ve found it’s not great on performance and runs into memory issues. So I’m back to naked Ghostty. OpenCode on the other hand is really good at managin sessions, so often I don’t even find myself needing to use tmux. Also, I use Hermes but having discovered OpenChambers, I don’t find myself needing to reach as often. Again, this deserves a longer post, if you’re curious. I’ve just been blow away by Kimi 2.6. I’ve found it often keeps pace with GPT 5.5 with Medium reasoning. There have even been time it’s results matched Opus 4.8 (though Opus typically gets the results one-shot). I’m not sure if I’ve engineered my harness in some way to work better with Kimi, but dang I love the results I’m getting. If you want to give it a shot, I recommend Opencode’s $10 “Go” plan and push Kimi 2.6 hard. I don’t use any of the models as therapits/friends to have conversations and I typically have a heavy handed instruction on how it should communicate with me, so a lot of the complaints around Opus 4.8 being “rough” or GPT 5.5 being soul-less 🙄, don’t bother me as much. If I do go the exec-plans route, I start with GPT 5.5 and hand it over to Kimi 2.6 for execution.  ↩︎ If you’re curious subscribe to my developer podcast’s newsletter where I post on some of the techniques I’m using.  ↩︎ Kimi 2.6 has become my overall workhorse model. By default I start most AI sessions with Kimi 2.6 now. GPT 5.5 remains my coding model of choice. My detailed planning, creating of exec-plans 1 , code review, simplification, and one-shot feature changes, reliably happen with GPT 5.5 (high). Opus 4.8 for deep thinking, writing and overall hard tasks. It’s been four days since the release, so my opinion is still forming but I’ve been fascinated how quickly Opus 4.8 is giving me the right solutions, especially for the slightly more complex problems. - I still only reach out to, when other models are struggling, cause 💸🔥 Gemini for anything image, video, or audio. Nothing else is close. It has collapsed work that used to eat hours 2 of mine. If I do go the exec-plans route, I start with GPT 5.5 and hand it over to Kimi 2.6 for execution.  ↩︎ If you’re curious subscribe to my developer podcast’s newsletter where I post on some of the techniques I’m using.  ↩︎

0 views
Kaushik Gopal 2 months ago

Agents are the new compilers. Specs are the new code.

Linus Torvalds recently said 1 AI will be to code what compilers were to assembly — freeing us from writing it by hand. Around the same time, I talked with Jesse Vincent (creator of one of the most popular agent skills out there — superpowers ). Something he said stuck with me: Specs are going to be the new code . I realize those two ideas snap together a little too neatly. Agents are compilers 2 and specs will become code. Software engineering is moving up another level of abstraction and we’ve seen this play out before. I saw this first-hand with my tiny USB-C cable checker — . It started as a shell command over macOS’s , then became Go when I wanted a proper binary, then Rust because I wanted to practice Rust, and later a version. The code kept changing. The thing I cared about did not: parse the USB tree, identify the attached devices, report the speed, and make bad cables obvious. , my voice track sync program, followed the same pattern. It started in Python because the audio libraries were there. Then I moved it to Rust because I didn’t want to ship a Python runtime or care which Python version happened to be on a machine. Again, the implementation changed. The behavior stayed boringly stable: take a master track and local tracks, find the offset, pad or trim each file, and drop aligned audio into the DAW. Compilers freed us from writing assembly. Agents may free us from writing code because it becomes an artifact the spec produces. The somewhat recent push around detailed exec plans could be an early signal of the looming shift at bigger scale. Push that thought further. We might get comfortable rebuilding whole modules instead of patching and refactoring them. We preserved the old shape of a system because throwing it away cost too much. Even when you know the module is wrong, you sand it down: extract an interface, migrate one caller at a time, add tests around behavior nobody fully understands. You keep moving because the alternative is a rewrite, and rewrites have a well-earned reputation for eating companies alive. But agents change that cost curve. If an agent can read the spec, understand the tests, inspect production traces, and rebuild a module in an afternoon, the sensible move may be to replace the entire module altogether. Push that even further and the unit of work changes. You stop asking an agent to patch one function or file. You ask it to rebuild the entire payment module against the tweaked spec. Heck, swap out the auth layer with a new library. Or regenerate the API boundary, now that the domain model is clearer. This is the part I cannot stop thinking about. Each rebuild can start from what we now understand about the whole module, not from what we believed the first time someone shipped it. Tech debt the old code carried (because it grew one patch at a time) can finally come off. The spec can absorb what we learned from the old implementation: the weird edge case in billing, the migration path nobody wrote down, the customer whose workflow depends on a “bug”, the batch job that only fails on the first day of the month. Specs become the place where the system’s memory lives. Once those lessons move into the spec, the implementation becomes replaceable. We are becoming Spec Writers. starts at the 1:48 mark  ↩︎ Yes, agents aren’t deterministic the way compilers are — same prompt tomorrow may give different code. But that may be the wrong bar moving forward. What has to stay stable is behavior under the spec; the code can vary. Also my dude, are you seriously nitpicking with Linus Torvalds?  ↩︎ Each rebuild can start from what we now understand about the whole module, not from what we believed the first time someone shipped it. Tech debt the old code carried (because it grew one patch at a time) can finally come off. starts at the 1:48 mark  ↩︎ Yes, agents aren’t deterministic the way compilers are — same prompt tomorrow may give different code. But that may be the wrong bar moving forward. What has to stay stable is behavior under the spec; the code can vary. Also my dude, are you seriously nitpicking with Linus Torvalds?  ↩︎

0 views
Kaushik Gopal 3 months ago

We are becoming Harness Engineers

The role of a software engineer is shifting. Not toward writing more code but toward building the environment that makes agents reliable. Think about what you actually do with Claude Code or Codex today: you configure AGENTS.md files, set up MCP servers, write skills and hooks, build feedback loops and tune sub-agents. You’re not writing as much of the software anymore. You’re engineering the harness around the thing that writes the software. Mitchell Hashimoto first coined the term harness engineering — the work of shaping the environment around an agent so it can act reliably. What the model sees, what tools it has, how it gets feedback, when humans step in. We keep hearing that agents will replace engineers. That shouldn’t be the focus of the change we’re seeing. What’s actually happening is product people shipping features directly. A well-harnessed agent lets someone with product instinct but little engineering background make meaningful changes — safely . The harness engineer makes that possible. Guardrails, design choices, blast radius controls, feedback loops. The scaffolding that turns “just prompt it” into something a team can trust. I say this from first-hand experience. If you want to go deeper, listen to the episode where my cohost and I dug into it. We landed on five pillars: Honestly one of the most important episodes we’ve recorded. agent legibility closed feedback loops persistent memory entropy control blast radius controls

0 views
Kaushik Gopal 3 months ago

Podsync - I finally built my podcast track syncer

I host and edit a podcast 1 . When recording remotely, we each record our own audio locally (I on my end, my co-host on his). The service we use (Adobe Podcast, Zoom, Skype-RIP) captures everyone together as a master track. But the quality doesn’t match what each person records locally with their own microphone. So we use that master as a reference point and stitch the individual local tracks together. This is what the industry calls a “ double-ender ”. Add a guest and it becomes a “triple-ender”. But this gets hairy during editing. Each person starts their recording at a slightly different moment — everyone hits record at a different time. Before I can edit, I need to line everything up. Drop all the tracks into a DAW, play the master alongside each individual track, nudge by ear until the speech aligns. Add a guest and it gets tedious fast. 10–15 minutes of fiddly, ear-straining alignment before I’ve even started editing. There’s also drift. Each machine’s audio clock runs at a slightly different rate, so two tracks that are perfectly aligned at minute one might be 200ms apart by minute sixty. So I built PodSync 2 . I first heard of a similar technique from Marco Arment — back in ATP episode 25 . He had a new app for aligning double-ender tracks and was already thinking about whether something so niche was even worth releasing publicly. I don’t think he ever released it. Being a Kotlin developer at the time, I figured I’d build my own. Java was mature. Surely there were audio processing libraries that could handle this. There weren’t 😅. At least not in any clean, usable form. Getting the right signal processing pieces together in JVM-land was awkward enough that my interest fizzled, so I kept doing it by hand. When I revamped Fragmented , I finally came back to this. I used Claude to help me build it — in Rust, no less. 3 But before you chalk this up to another vibecoded project, hear me out. The interesting part here wasn’t just that AI made it easier. It was thinking through the actual algorithm: Voice activity detection ( VAD ) to find speech regions. MFCC features to fingerprint the audio. Cross-correlation to find where the tracks match. Some real signal processing techniques, not just prompt engineering. Now, could I have prompted my way to a solution? Probably. But I like to think, years of manually aligning tracks — and some sound engineering intuition — helped me steer AI towards a better solution. Working on this felt refreshing. In an era where half the conversation is about AI replacing engineering work, here’s a problem where the hard part is still the problem itself — understanding the domain, picking the right approach, knowing what “correct” sounds like. It gives me confidence that solving real problems well still has its place. I like how Dax put it: thdxr on twitter I really don’t care about using AI to ship more stuff. It’s really hard to come up with stuff worth shipping. The core idea: take a chunk of speech from a participant track, compare it against the master recording, find where they match best. That position is the time offset. The trick is picking which chunk of speech to use. Rather than betting on a single region, Podsync finds a few strong candidates per track (longer contiguous speech blocks preferred) and tries each one against the master. For long candidates, it samples from the start, middle, and end. The highest-confidence match wins; if a second independent region agrees on the same offset, that corroboration factors in as a tie-breaker. After finding the offset, Podsync pads or trims each track to align with the master and match its length (and outputs some info on the offset). Drop the output into my DAW at 0:00. Done. I even wrote an agent skill you can just point your agent harness to and it will take care of all the steps for you : What used to be 10–15 minutes of alignment per episode is now a single command. Marco, if you ever read this, would still love to see your implementation! His solution (as I understand) is aimed more at correcting the drift vs getting the offset right. In practice, I haven’t found drift to be much of a problem. It exists but stays minor, and I’m typically editing every second of the podcast anyway so it’s easy enough to handle by hand. I even had a branch that corrected drift by splicing at silence points, but it complicated things more than it helped. It’s a podcast on AI development but we strive to make it high signal. None of that masturbatory AI discourse .  ↩︎ See also Phone-sync .  ↩︎ I chose Rust (it’s what interests me these days ) and a CLI tool with no runtime dependency is more pleasant to distribute.  ↩︎ It’s a podcast on AI development but we strive to make it high signal. None of that masturbatory AI discourse .  ↩︎ See also Phone-sync .  ↩︎ I chose Rust (it’s what interests me these days ) and a CLI tool with no runtime dependency is more pleasant to distribute.  ↩︎

0 views
Kaushik Gopal 4 months ago

Here’s my list of reasons for using Opencode

Here’s my list of reasons for using Opencode . I’m often experimenting with the bleeding edge models as they come out. I actively switch between models for tasks and I use them all enough where I can tell the difference. Opencode lets me switch between models mid-task or mid-conversation. Fluidly. I wrote about this and agentic fluidity in more detail but tldr: Opencode has the client/server architecture baked in. So I can just start an opencode server on one machine, expose it through and start using it on my phone or other machines. I talked about this on my podcast in some detail but Opencode has the best implementation of subagents and modes. You can switch to a subagent definition as your primary mode, then operate other subagents from there. It makes orchestrator-type tasks super easy. I love that OpenCode is opinionated about their UX. They don’t try to be Claude Code or Codex. In the process they have some really nice UX patterns like a sidebar with ongoing file changes, context/cost, MCPs connected etc. It’s the first time I’ve not needed to worry about a custom statusline.sh or building one. The plugin ecosystem is highly customizable. To the point where you can add new features, integrate with external services or even modify OpenCode’s default behavior. The wonderful Jesse Vincent mentioned this to me when I was stupidly contemplating a fork. It’s not all rainbows and sunshine. Anomaly — the team behind OpenCode — is small . Which sometimes shows, because there’s definitely bug s and some features missing . But I will say… none that’s deterred me from using it for the last two months, exclusively . Go give it a shot . Many of the serious AI coders I know are really liking it and switching.

0 views
Kaushik Gopal 4 months ago

Agentic Fluidity - OpenCode is OpenClaw for coding

One of the reasons OpenClaw got so popular was how fluidly you can chat with and operate your agents. Pull up your phone, send a quick message on WhatsApp, and you’re in business. As we focus more on agent orchestration 1 in 2026, I think an important aspect will be access fluidity . How do you hop into your agent’s context from any device, terminal, or IDE and just start coding? Claude Code supports this in a limited way, while others like Cursor and Codex take a cloud-based approach. The best option I’ve found for this “on-the-go” agentic coding is an open-source one — OpenCode. OpenCode - your best “on-the-go” option for agentic coding. OpenCode uses a native server-client architecture. You can simply spin it up in a regular terminal tab, just like or . But the power move is running it as a server and connecting multiple clients. A client can be your terminal tab, a mobile device, or a desktop computer. Each terminal tab becomes a new, isolated CLI session that connects to the server. Couple this with Tailscale , and you can securely connect to a dev machine running an OpenCode server from anywhere. I’d start by using like a regular CLI tool. Once it feels familiar, switch to server/web mode. The beauty is you can open that URL in any browser, and it’s fully synced. Credit to my co-host Iury for tooting the OpenCode horn early, and my Instacart colleague Spencer for questioning my luddite tmux ways. 2 I’ll write a future post singing OpenCode’s other praises. For now, if you’re exploring the bleeding edge of agent access fluidity, don’t sleep on it. See my post on AI paradigms .  ↩︎ I noticed some memory leaks when using tmux sessions with OpenCode, and Spencer asked me: why not lean on the server-client model more and use regular Ghostty tabs and splits.  ↩︎ See my post on AI paradigms .  ↩︎ I noticed some memory leaks when using tmux sessions with OpenCode, and Spencer asked me: why not lean on the server-client model more and use regular Ghostty tabs and splits.  ↩︎

0 views
Kaushik Gopal 6 months ago

AI model choices 2026-01

Which AI model do I use? This is a common question I get asked, but models evolve so rapidly that I never felt like I could give an answer that would stay relevant for more than a month or two. This year, I finally feel like I have a stable set of model choices that consistently give me good results. I’m jotting it down here to share more broadly and to trace how my own choices evolve over time. GPT 5.2 (High) for planning and writing, including plans Opus 4.5 for anything coding, task automation, and tool calling Gemini ’s range of models for everything else: Gemini 3 (Thinking) for learning and understanding concepts (underrated) Gemini 3 (Flash) for quick fire questions Nano Banana (obv) for image generation NVIDIA’s Parakeet for voice transcription

0 views
Kaushik Gopal 6 months ago

Wi-Fi sharing is a killer Android feature

Ubiquiti announced a new travel router . Much of the internet is excited. So am I. Then I tried to remember the last time I actually needed a travel router. You see, Android has supported a feature I’ll call Wi-Fi sharing for years. 1 Your phone connects to an existing Wi-Fi network and re-shares it as a hotspot. This might sound like a regular hotspot feature that most phones (including the iPhone) come with. But it’s not. iPhones can share mobile data. They can’t re-share a Wi-Fi connection as a hotspot. Wi-Fi sharing Your phone connects to Wi-Fi, and then re-shares that same Wi-Fi as a hotspot. This is different from typical hotspot functionality where the phone shares its mobile data connection (vs Wi-Fi). Neat trick, but why bother? Can’t you just connect each device to Wi-Fi? Captive portals are annoying when you’re carrying multiple devices. I typically travel with 3-4 devices that want internet. Signing each one in, every time, gets old fast. Some devices are worse: Chromecast and Fire TV sticks are particularly painful to get past captive portals. If everything connects to your hotspot, you only deal with the portal once. 2 On a plane, I sometimes want both my laptop and phone online. Some paid Wi-Fi plans only allow one device at a time. Unless you’re ok paying twice, Wi-Fi sharing is simpler. 3 Hotels and conference centers do the same: sign-in plus device limits. Wi-Fi sharing works around it. This one is less obvious, but common in hotels and conference Wi-Fi: your devices have internet, but they can’t see each other locally. Chromecast (or printers) won’t show up as a cast target because it doesn’t appear on the network. That’s usually client/AP isolation. 4 Put your devices on your phone’s hotspot, and local discovery usually works again. This is slightly advanced. With a Tailscale setup and an explicit exit node, you basically have a private VPN. 5 On phones where hotspot traffic routes through that VPN, you only have to set it up on your Android phone, and every device that connects to your phone gets the same “safe” path out. If I have to log in to bank accounts when roaming or connecting to “free” Wi-Fi, this helps me feel safer knowing the local network can’t see or tamper with the contents of my traffic. 6 I should pause my gloating over iPhones for a second: a few Android devices may not support this feature. The Android OS has Wi-Fi sharing baked in, but it still requires hardware + driver support. Notable exceptions include the Pixel 7a, the Pixel 8a, and yes the (first generation) Pixel Fold. Wi-Fi sharing requires Wi-Fi hardware (chipset + drivers) that can run as both a client and an access point at the same time (STA + AP). 7 Chipsets can implement this in a few ways (DBS, SBS, MCC, SCC). 8 Android doesn’t mandate one mode; it depends on the Wi-Fi chipset. DBS/SBS use multiple radios, so the phone can keep the upstream connection and hotspot truly simultaneous (for example, 5 GHz upstream and a 2.4 GHz hotspot). MCC/SCC share a radio, so the hotspot either stays on the same channel (SCC) or the radio hops channels (MCC). If a phone can’t do STA + AP concurrency well (or at all), OEMs disable Wi-Fi sharing (which is why some phones and many older devices don’t support it). Travel routers still have their place: Ethernet ports, better radios, and an always-on box you can run a VPN on. But if you’re on Android and your phone supports Wi-Fi sharing, you already have the core trick. Android doesn’t call it this in Settings, but it’s the best term I have for “connect to Wi-Fi, then share that Wi-Fi as a hotspot”. In strict networking terms, this isn’t L2 bridging; it’s typically tethering (routing/NAT) with a Wi-Fi upstream.  ↩︎ This works because the captive portal only sees your phone; everything else is NATed behind it.  ↩︎ Thank you Delta for being one of the few US domestic airlines that don’t place this restriction. Looking at you United.  ↩︎ Hotel and conference Wi-Fi often blocks device-to-device traffic on purpose (“client isolation”) so guests can’t discover, scan, or connect to each other’s devices. Your phone’s hotspot creates a separate little LAN, so your devices can talk to each other again.  ↩︎ I have a post in the making about this: “With Tailscale you don’t need to pay for a VPN”.  ↩︎ HTTPS encrypts the bank session, but open Wi-Fi is still untrusted: a malicious access point can tamper with DNS and try to steer you into phishing. A VPN (or Tailscale exit node) reduces the surface area by encrypting your traffic to a trusted endpoint.  ↩︎ Modern devices support AP (Access Point) + STA (Station) Mode, letting them act as both a client to one network and a hotspot for others, allowing Wi-Fi extension or tethering.  ↩︎ Definitions from Android’s Wi-Fi vendor HAL ( ): DBS (Dual Band Simultaneous), SBS (Single Band Simultaneous), MCC (Multi Channel Concurrency), SCC (Single Channel Concurrency).  ↩︎ Connect your Android phone to the Wi-Fi network you want to share. If it’s behind a captive portal, sign in as needed. Go to Settings → Hotspot & tethering → Wi-Fi hotspot (wording varies) and turn it on. Typically, if your phone does not support Wi-Fi sharing, it will disable Wi-Fi. Some OEMs show a separate toggle to enable Wi-Fi sharing. On Pixel phones, it’s automatic. Android doesn’t call it this in Settings, but it’s the best term I have for “connect to Wi-Fi, then share that Wi-Fi as a hotspot”. In strict networking terms, this isn’t L2 bridging; it’s typically tethering (routing/NAT) with a Wi-Fi upstream.  ↩︎ This works because the captive portal only sees your phone; everything else is NATed behind it.  ↩︎ Thank you Delta for being one of the few US domestic airlines that don’t place this restriction. Looking at you United.  ↩︎ Hotel and conference Wi-Fi often blocks device-to-device traffic on purpose (“client isolation”) so guests can’t discover, scan, or connect to each other’s devices. Your phone’s hotspot creates a separate little LAN, so your devices can talk to each other again.  ↩︎ I have a post in the making about this: “With Tailscale you don’t need to pay for a VPN”.  ↩︎ HTTPS encrypts the bank session, but open Wi-Fi is still untrusted: a malicious access point can tamper with DNS and try to steer you into phishing. A VPN (or Tailscale exit node) reduces the surface area by encrypting your traffic to a trusted endpoint.  ↩︎ Modern devices support AP (Access Point) + STA (Station) Mode, letting them act as both a client to one network and a hotspot for others, allowing Wi-Fi extension or tethering.  ↩︎ Definitions from Android’s Wi-Fi vendor HAL ( ): DBS (Dual Band Simultaneous), SBS (Single Band Simultaneous), MCC (Multi Channel Concurrency), SCC (Single Channel Concurrency).  ↩︎

0 views
Kaushik Gopal 7 months ago

Combating AI coding atrophy with Rust

It’s no secret that I’ve fully embraced AI for my coding. A valid concern ( and one I’ve been thinking about deeply ) is the atrophying of the part of my brain that helps me code. To push back on that, I’ve been learning Rust on the side for the last few months. I am absolutely loving it. Kotlin remains my go-to language. It’s the language I know like the back of my hand. If someone sends me a swath of Kotlin code, whether handwritten or AI generated, I can quickly grok it and form a strong opinion on how to improve it. But Kotlin is a high-level language that runs on a JVM. There are structural limits to the performance you can eke out of it, and for most of my career 1 I’ve worked with garbage-collected languages. For a change, I wanted a systems-level language, one without the training wheels of a garbage collector. I also wanted a language with a different core philosophy, something that would force me to think in new ways. I picked up Go casually but it didn’t feel like a big enough departure from the languages I already knew. It just felt more useful to ask AI to generate Go code than to learn it myself. With Rust, I could get code translated, but then I’d stare at the generated code and realize I was missing some core concepts and fundamentals. I loved that! The first time I hit a lifetime error, I had no mental model for it. That confusion was exactly what I was looking for. Coming from a GC world, memory management is an afterthought — if it requires any thought at all. Rust really pushes you to think through the ownership and lifespan of your data, every step of the way. In a bizarre way, AI made this gap obvious. It showed me where I didn’t understand things and pointed me toward something worth learning. Here’s some software that’s either built entirely in Rust or uses it in fundamental ways: Many of the most important tools I use daily are built with Rust. Can’t hurt to know the language they’re written in. Rust is quite similar to Kotlin in many ways. Both use strict static typing with advanced type inference. Both support null safety and provide compile-time guarantees. The compile-time strictness and higher-level constructs made it fairly easy for me to pick up the basics. Syntactically, it feels very familiar. I started by rewriting a couple of small CLI tools I used to keep in Bash or Go. Even in these tiny programs, the borrow checker forced me to be clear about who owns what and when data goes away. It can be quite the mental workout at times, which is perfect for keeping that atrophy from setting in. After that, I started to graduate to slightly larger programs and small services. There are two main resources I keep coming back to: There are times when the book or course mentions a concept and I want to go deeper. Typically, I’d spend time googling, searching Stack Overflow, finding references, diving into code snippets, and trying to clear up small nuances. But that’s changed dramatically with AI. One of my early aha moments with AI was how easy it made ramping up on code. The same is true for learning a new language like Rust. For example, what’s the difference 2 between these two: Another thing I loved doing is asking AI: what are some idiomatic ways people use these concepts? Here’s a prompt I gave Gemini while learning: Here’s an abbreviated response (the full response was incredibly useful): It’s easy to be doom and gloom about AI in coding — the “we’ll all forget how to program” anxiety is real. But I hope this offers a more hopeful perspective. If you’re an experienced developer worried about skill atrophy, learn a language that forces you to think differently. AI can help you cross that gap faster. Use it as a tutor, not just a code generator. I did a little C/C++ in high school, but nowhere close to proficiency.  ↩︎ Think mutable var to a “shared reference” vs. immutable var to an “exclusive reference”.  ↩︎ fd (my tool of choice for finding files) ripgrep (my tool of choice for searching files) Fish shell (my shell of choice, recently rewrote in Rust) Zed (my text/code editor of choice) Firefox ( my browser of choice) Android?! That’s right: Rust now powers some of the internals of the OS, including the recent Quick Share feature. Fondly referred to as “ The Book ”. There’s also a convenient YouTube series following the book . Google’s Comprehensive Rust course, presumably created to ramp up their Android team. It even has a dedicated Android chapter . This worked beautifully for me. I did a little C/C++ in high school, but nowhere close to proficiency.  ↩︎ Think mutable var to a “shared reference” vs. immutable var to an “exclusive reference”.  ↩︎

0 views
Kaushik Gopal 8 months ago

Go with monthly AI subscriptions friends

Go with monthly AI subscriptions friends. I can’t remember where I read this tip, but given how fast the AI lab models move, it’s smarter to stick with a monthly plan instead of locking into an annual one, even if the annual price looks more attractive. I hit a DI issue on Android and was too lazy to debug it myself, so I pointed two models at it. GPT Codex gave me the cleanest, correct fix. Claude Sonnet 4.5 found a fix, but it wasn’t idiomatic and was pretty aggressive with the changes. A month ago, I wouldn’t have bothered with anything other than the Claude models for coding. Today, Codex clearly feels ahead. Google is about to ship its next Gemini model and, from what I’m hearing, it’s going to be absurdly good. In these wonderfully unstable times, monthly subscriptions are the way to go.

0 views
Kaushik Gopal 8 months ago

Firefox + UbO is still better than Brave, Edge or any Chromium-based solution

I often find myself replying to claims that Brave, Edge, or other Chromium browsers effectively achieve the same privacy standards as Firefox + uBlock Origin (uBO). This is simply not true. Brave and other Chromium browsers are constrained by Google’s Manifest V3. Brave works around this by patching Chromium and self-hosting some MV2 extensions, but it is still swimming upstream against the underlying engine. Firefox does not have these MV3 constraints, so uBlock Origin on Firefox retains more powerful, user-controllable blocking than MV3-constrained setups like Brave + uBO Lite. Brave is an excellent product and what I used for a long time. But the comparison often ignores structural realities. There are important nuances that make Firefox the more future-proof platform for privacy-conscious users. The core issue is Manifest V3 (MV3). This is Google’s new extension architecture for Chromium (what Chrome, Brave, and Edge are built on). Under Manifest V2, blockers like uBO used the blocking version of the API ( + ) to run their own code on each network request and decide whether to cancel, redirect, or modify it. MV3 deprecates that blocking path for normal extensions and replaces it with the (DNR) API: extensions must declare a capped set of static rules in advance, and the browser enforces those rules without running extension code per request. This preserves basic blocking but, as uBO’s developer documents, removes whole classes of filtering capabilities uBO relies on. And Google is forcing this change by deprecating MV2 . Yeah, shitty. To get around the problem, Brave is effectively swimming upstream against its own engine. It does this in two ways: They wrote a great post about this too. Brave is doing a great job, but it is operating with a sword of Damocles hanging over it. The team must manually patch a hostile underlying engine to maintain functionality that Firefox simply provides out of the box. A lot of people also say, wait, we now have “uBlock Origin Lite” that does the same thing and is even more lightweight! It is “lite” for a reason. You are not getting the same blocking safeguards. uBO Lite is a stripped-down version necessitated by Google’s API restrictions. As detailed in the uBlock Origin FAQ , the “Lite” version lacks in the following ways: uBlock Origin is widely accepted as the most effective content blocker available. Its creator, gorhill, has explicitly stated that uBlock Origin works best on Firefox . So while using a browser like Brave is better than using Chrome or other browsers that lack a comprehensive blocker, it is not equivalent to Firefox + uBlock Origin. Brave gives you strong, mostly automatic blocking on a Chromium base that is ultimately constrained by Google’s MV3 decisions. Firefox + uBlock Origin gives you a full-featured, user-controllable blocker on an engine that is not tied to MV3, which matters if you care about long-term, maximum control over what loads and who sees your traffic. Native patching: It implements ad-blocking (Shields) natively in C++/Rust within the browser core to bypass extension limitations. Manual extension hosting: Brave now has to manually host and update specific Manifest V2 extensions (like uBO and AdGuard) on its own servers to keep them alive as Google purges them from the store. No on-demand list updates: uBO Lite compiles filter lists into the extension package. The resulting declarative rulesets are refreshed only when the extension itself updates, so you cannot trigger an immediate filter-list or malware-list update from within the extension. No “Strict Blocking”: uBO Lite does not support uBlock Origin’s strict blocking modes or its per-site dynamic matrix. With full uBO on Firefox, my setup defines and exposes a custom, per-site rule set that ensures Facebook never sees my activity on other sites. uBO Lite does not let me express or maintain that kind of custom policy; I have to rely entirely on whatever blocking logic ships with the extension. No dynamic filtering: You lose the advanced matrix to block specific scripts or frames per site. Limited element picker: “Pointing and zapping” items requires specific, permission-gated steps rather than being seamless. No custom filters: You cannot write your own custom rules to block nearly anything, from annoying widgets to entire domains.

1 views
Kaushik Gopal 8 months ago

Cognitive Burden

A common argument I hear against AI tools: “It doesn’t do the job better or faster than me, so why am I using this again?” Simple answer: cognitive burden. My biggest unlock with AI was realizing I could get more done, not because I was faster , but because I wasn’t wringing my brain with needless tedium. Even if it took longer or needed more iterations, I’d finish less exhausted. That was the aha moment that sold me. Simple example: when writing a technical 1 post, I start with bullet points. Sometimes there’s a turn of phrase or a bit of humor I enjoy, and I’ll throw those in too. Then a custom agent trained on my writing generates a draft in my voice. After it drafts, I still review every single word. A naysayer might ask: “Well, if you’re reviewing every single word anyway, at that point, why not just write the post from scratch?” Because it’s dramatically easier and more enjoyable not to grind through and string together a bunch of prepositions to draft the whole post. I’ve captured the main points and added my creative touch; the AI handles the rest. With far less effort , I can publish more quickly — not due to raw speed, but because it’s low‑touch and I focus only on what makes it uniquely me. Cognitive burden ↓. About two years ago I pushed back on our CEO in a staff meeting: “Most of the time we engineers waste isn’t in writing the code. It’s the meetings, design discussions, working with PMs, fleshing out requirements — that’s where we should focus our AI efforts first.” 2 I missed the same point. Yes, I enjoy crafting every line of code and I’m not bogged down by that process per se, but there’s a cognitive tax to pay. I’d even say I could still build a feature faster than some LLMs today (accounting for quality and iterations) before needing to take a break and recharge. Now I typically have 3–4 features in flight (with requisite docs, tests, and multiple variants to boot). Yes, I’m more productive. And sure, I’m probably shipping faster. But that’s correlation, not causation. Speed is a byproduct. The real driver is less cognitive burden, which lets me carry more. What’s invigorated me further as a product engineer is that I’m spending a lot more time on actually building a good product . It’s not that I don’t know how to write every statement; it’s just… no longer interesting. Others feel differently. Great! To each their own. For me, that was the aha moment that sold me on AI. Reducing cognitive burden made me more effective; everything else followed. I still craft the smaller personal posts from scratch. I do this mostly because it helps evolve my thinking as I write each word down — a sort of muscle memory formed over the years of writing here.  ↩︎ In hindsight, maybe not one of my finest arguments especially given my recent fervor . To be fair, while I concede my pushback was wrong, I don’t think leaders then had the correct reasoning fully synthesized.  ↩︎ I still craft the smaller personal posts from scratch. I do this mostly because it helps evolve my thinking as I write each word down — a sort of muscle memory formed over the years of writing here.  ↩︎ In hindsight, maybe not one of my finest arguments especially given my recent fervor . To be fair, while I concede my pushback was wrong, I don’t think leaders then had the correct reasoning fully synthesized.  ↩︎

1 views
Kaushik Gopal 8 months ago

Standardize with ⌘ O ⌘ P to reduce cognitive load

There are a few apps on macOS in the text manipulation category that I end up spending a lot of time on. For example: Obsidian (for notes), Zed (text editor + IDE lite), Android Studio & Intellij (IDE++), Cursor (IDE + AI), etc. All these apps have two types of commands that I frequently use: But by default, these apps use ever so slightly different shortcuts. One might use ⌘ P, another might use ⌘ ⇧ P, etc. I’ve found it incredibly helpful to take a few minutes and make these specific keyboard shortcuts the same everywhere. So now I use: This small change has reduced cognitive load significantly. I no longer have to think about which app I’m in, and what the shortcut is for that specific app. Muscle memory takes over, and I can just get things done faster. Highly recommended! Open a specific file or note Open the command palette (or find any action menu) ⌘ O – Open a file/note ⌘ P – Open the command palette (or equivalent action menu)

0 views
Kaushik Gopal 8 months ago

Claude Skills: What's the Deal?

Anthropic announced Claude Skills and my first reaction was: “So what?” We already have , slash commands, nested instructions, or even MCPs. What’s new here? But if Simon W thinks this is a big deal , then pelicans be damned; I must be missing something. So I dissected every word of Anthropic’s eng. blog post to find what I missed. I don’t think the innovation is what Skills does or achieves, but rather how it does it that’s super interesting. This continues their push on context engineering as the next frontier. Skills are simple markdown files with YAML frontmatter. But what makes them different is the idea of progressive disclosure : Progressive disclosure is the core design principle that makes Agent Skills flexible and scalable. Like a well-organized manual that starts with a table of contents, then specific chapters, and finally a detailed appendix, skills let Claude load information only as needed: So here’s how it works: This dynamic context loading mechanism is very token efficient ; that’s the interesting development here. In this token-starved AI economy, that’s 🤑. Other solutions aren’t as good in this specific way. Why not throw everything into ? You could add all the info directly and agents would load it at session start. The problem: loading everything fills up your context window fast, and your model starts outputting garbage unless you adopt other strategies. Not scalable. Place an AGENTS.md in each subfolder and agents read the nearest file in the tree. This splits context across folders and solves token bloat. But it’s not portable across directories and creates an override behavior instead of true composition. Place instructions in separate files and reference them in AGENTS.md. This fixes the portability problem vs the nested approach. But when referenced, the full content still loads statically. Feels closest to Skills, but lacks the JIT loading mechanism. Slash commands (or in Codex) let you provide organized, hyper-specific instructions to the LLM. You can even script sequences of actions, just like Skills. The problem: these aren’t auto-discovered. You must manually invoke them, which breaks agent autonomy. Skills handle 80% of MCP use cases with 10% of the complexity. You don’t need a network protocol if you can drop a markdown file that says “to access GitHub API, use with .” To be quite honest, I’ve never been a big fan of MCPs. I think they make a lot of sense for the inter-service communication but more often than not they’re overkill. Token-efficient context loading is the innovation. Everything else you can already do with existing tools. If this gets adoption, it could replace slash commands and simplify MCP use cases. I keep forgetting, this is for the Claude product generally (not just Claude Code) which is cool. Skills is starting to solve the larger problem: “How do I give my agent deep expertise without paying the full context cost upfront?” That’s an architectural improvement definitely worth solving and Skills looks like a good attempt. Scan at startup : Claude scans available Skills and reads only their YAML descriptions (name, summary, when to use) Build lightweight index : This creates a catalog of capabilities (with minimal token cost); so think dozens of tokens per skill Load on demand : The full content of a Skill only gets injected into context when Claude’s reasoning determines it’s relevant to the current task ✓ Auto-discovered and loaded ✗ Static: all context loaded upfront (bloats context window at scale) ✓ Scoped to directories ✗ Not portable across folders; overrides behavior, not composition ✓ Organized and modular ✗ Still requires static loading when referenced ✓ Powerful and procedural ✗ Manual invocation breaks agent autonomy ✓ Access to external data sources ✗ Heavyweight; vendor lock-in; overkill for procedural knowledge Token-efficient context loading is the innovation. Everything else you can already do with existing tools. If this gets adoption, it could replace slash commands and simplify MCP use cases. I keep forgetting, this is for the Claude product generally (not just Claude Code) which is cool.

0 views
Kaushik Gopal 9 months ago

Cargo Culting

If you’re a software engineer long enough, you will meet some gray beards that throw out-of-left-field phrases to convey software wisdom. For example, you should know if you’re yak-shaving or bike-shedding , and when that’s even a good thing. A recent HN article 1 reminded me of another nugget – Cargo Culting (or Cargo Cult Programming). Cargo Culting : ritualizing a process without understanding it. In the context of programming: practice of applying a design pattern or coding style blindly without understanding the reasons behind it I’m going to take this opportunity to air one of my personal cargo-culting pet peeves, sure to kick up another storm: Making everything small . When I get PR feedback saying “this class is too long, split this!”, I get ready to launch into a tirade: you’re confusing small with logically small – ritualizing line count without understanding cohesion. You can make code small by being terse: removing whitespace, cramming logic into one-liners, using clever shorthand 2 . But you’ve just made it harder to read. A function that does one cohesive thing beats multiple smaller functions scattered across files. As the parable goes, after the end of the Second World War, indigenous tribes believed that air delivery of cargo would resume if they carried out the proper rituals, such as building runways, lighting fires next to them, and wearing headphones carved from wood while sitting in fabricated control towers. While on the surface amusing, there’s sadness if you dig into the history and contributing factors (value dominance, language & security barriers). I don’t think that’s reason to avoid the term altogether. We as humans sometimes have to embrace our dark history, acknowledge our wrongs and build kindness in our hearts. We cannot change our past, but we can change our present and future. The next time someone on your team ritualizes a pattern without understanding it, you’ll know what to call it. Who comes up with these terms anyway? Now that you’re aware of the term, you’ll realize that the original article’s use of the term cargo-cult is weak at best. In HN style, the comments were quick to call this out.  ↩︎ You know exactly what I’m thinking of, fellow Kotlin programmers.  ↩︎ Now that you’re aware of the term, you’ll realize that the original article’s use of the term cargo-cult is weak at best. In HN style, the comments were quick to call this out.  ↩︎ You know exactly what I’m thinking of, fellow Kotlin programmers.  ↩︎

0 views
Kaushik Gopal 9 months ago

ExecPlans – How to get your coding agent to run for hours

I’ve long maintained that the biggest unlock with AI coding agents is the planning step. In my previous post , I describe how I use a directory and ask the agent to diligently write down its tasks before and during execution. Most coding agents now include this as a feature. Cursor, for example, introduced it as an explicit feature recently. While that all felt validating, on a plane ride home I watched OpenAI’s DevDay. One of the most valuable sessions was Shipping with Codex . Aaron Friel — credited with record-long sessions and token output — walked through his process and the idea of “ExecPlans.” It felt similar at first, but I quickly realized this was some god-level planning. He said OpenAI would release his PLANS.md soon, but I couldn’t wait. On that flight, with janky wifi, I rebuilt what I could from the talk and grew my baby plan into something more mature — and I was already seeing better results. I pinged Aaron on BlueSky for the full doc, and he very kindly shared the PR that’s about to get merged with detailed information. My god, this thing is a work of art. Aaron clearly spent a lot of time honing it. I’ve tried it on two PRs so far, and it’s working fantastically. I still need to put it through its paces on some larger work projects, but I feel comfortable preemptively calling it the gold standard for planning. I’ve made a few small tactical tweaks to how I use it: This is really a big unlock, folks. Try it now. The latest PLANS.md can be found in Aaron’s PR . Use it as a template in your folder. Then instruct your agent via AGENTS.md to always write an ExecPlan when working on complex tasks. I highly recommend you go watch Aaron’s part of the talk Shipping with Codex . I’ll update this post once it’s merged or if anything changes. Update: I’ve been using this for the last few days (~8 PRs so far) and on an average I’ve definitely gotten my agents to run for much longer successfully (longest was about ~1 hour but frequently >30 mts). This is the way. I instruct the agent to write plans to (works across coding agents) In my AGENTS.md I tell agents to put temporary plans in (which I’ve gitignored) I keep the master Aaron shared at

0 views
Kaushik Gopal 9 months ago

Job Displacement with AI — Software Engineers → Conductors

Engineers won’t be replaced by tools that do their tasks better; they’ll be replaced by systems that make those tasks nonessential. Sangeet Paul Choudary wrote an insightful piece on AI-driven job displacement and a more transformative way to think about it: To truly understand how AI affects jobs, we must look beyond individual tasks to comprehend AI’s impact on our workflows and organizations. The task-centric view sees AI as a tool that improves how individual tasks are performed. Work remains structurally unchanged. AI is simply layered on top to improve speed or lower costs. …In this framing, the main risk is that a smarter tool might replace the person doing the task. The system-centric view, on the other hand, looks at how AI reshapes the organization of work itself. It focuses on how tasks fit into broader workflows and how their value is determined by the logic of the overall system. In this view, even if tasks persist, the rationale for grouping them into a particular job, or even performing them within the company, may no longer hold once AI changes the system’s structure. If we adopt a system-centric view, how does the role of a software engineer evolve 1 ? I’ve had a notion for some time — the role will transform into a software “conductor”. music conductors conducting is the art of directing the simultaneous performance of several players or singers by the use of gesture The tasks a software conductor must master differ from those of today’s software engineer. Here are some of the shifts I can think of: The craft is knowing exactly how much detail to provide in prompts: too little and models thrash; too much and they overfit or hallucinate constraints. You’ll need to write spec-grade prompts that define interfaces, acceptance criteria, and boundaries — chunking work into units atomic enough for clear execution yet large enough to preserve context. Equally critical: recognizing when to interrupt and redirect — catching drift early and steering with surgical edits rather than expensive reruns or loops. You’ll need to design systems that AI can both navigate and extend elegantly. This means clear module boundaries with explicit interfaces, descriptive naming that models can infer purpose from, and tests that double as executable specs. The goal: systems where AI agents can make surgical changes quickly and efficiently without cascading tech debt. We’re moving from building one solution to exploring many simultaneously. This unlocks three levels of experimentation: Feature variants — Build competing product approaches in parallel. One agent implements phone-only authentication while another builds traditional email/password. Both ship behind feature flags. Let users decide which wins. Implementation variants — Build the same feature with different architectures. Redis caching on path A, SQLite on path B. Run offline benchmarks and online canaries to measure which performs better under real load. Personalized variants — Stop looking for a single winner. The most radical shift: each user might get their own variant. Not just enterprise vs consumer, but individual-level personalization where the system learns what works for you specifically. Power users get keyboard shortcuts and dense information; casual users get guided flows with progressive disclosure. Users who convert on social proof see testimonials; analytical users see feature comparisons. AI makes the economics work — what was prohibitively expensive (maintaining thousands of personalized codepaths manually) becomes viable when AI generates, tests, and synchronizes variants automatically. The skill: running rigorous evals, measuring trade-offs with metrics, and orchestrating the complexity of multiple live variants. Every API call has a price, a latency budget, and quality trade-offs. You’ll need to master arbitrage between expensive reasoning models and cheaper models, knowing when to leverage MCPs, local tools, or cloud APIs. Learn how models approach refactors differently from new features or bug fixes, then tune prompts, context windows, and routing strategies accordingly. You’ll need to build golden test sets, trace model runs, classify failure modes, and treat evals like unit tests. Evaluation frameworks with baseline datasets, regression suites, and automated canaries that catch quality drift before production become non-negotiable. Without observability, you can’t iterate safely or validate that changes actually improve outcomes. Framework fluency loses value when AI handles syntax. What matters is depth in three areas: Core computer science fundamentals — Not because AI doesn’t know them, but because you need to verify AI made the right trade-offs for your specific constraints. AI might use quicksort when your dataset is always 10 items. It might optimize a function that runs once a day while missing the N+1 query in your hot path — where you loop through 1000 users making a database call for each instead of batching. Your value is code review with context: catching when AI optimizes for the wrong thing, knowing when simple beats clever, and spotting performance cliffs before they ship. Product judgment — Knowing which problem to solve, not just how to solve it. AI can build any feature you describe, but it can’t tell you whether that feature matters. Understanding user needs, prioritizing ruthlessly, and recognizing when you’re overbuilding becomes the bottleneck. Domain expertise — Deep knowledge of your problem space — whether it’s payments, healthcare, logistics, or graphics. AI can write generic code, but it struggles with domain-specific edge cases, regulations, and the unwritten rules experts know. The more niche your expertise, the harder you are to replace. These are the skills that matter for the next three years. But I don’t have a crystal ball beyond that. At the pace AI is evolving, even conductors might become a role that AI plays better. The orchestration itself could be automated, leaving us asking the same questions about the next evolution. For now, learning to conduct is how we stay relevant. Companies will change how they ship too; but the nearer shift is the individual’s role, so that’s my focus for this post.  ↩︎ Companies will change how they ship too; but the nearer shift is the individual’s role, so that’s my focus for this post.  ↩︎

0 views
Kaushik Gopal 9 months ago

Sorting Prompts - LLMs are not wrong you just caught them mid thought

Good sensemaking processes iterate. We develop initial theories, note some alternative ones. We then take those theories that we’ve seen and stack up the evidence for one against the other (or others). Even while doing that we keep an eye out for other possible explanations to test. When new explanations stop appearing and we feel that the evidence pattern increasingly favors one idea significantly over another we call it a day. LLMs are no different. What often is deemed a “wrong” response is often4 merely a first pass at describing the beliefs out there. And the solution is the same: iterate the process. What I’ve found specifically is that pushing it to do a second pass without putting a thumb on the scale almost always leads to a better result. To do this I use what I call “sorting statements” that try to do a variety of things Mike Caulfield is someone who cares about the veracity of information. The entire post is fascinating and has painted LLM search results in a new way for me. I now have a Raycast Snippet which expands to this: Already I’m seeing much better results.

0 views