<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>developer-workflow on S Anand</title>
    <link>https://www.s-anand.net/blog/tag/developer-workflow/</link>
    <description>Recent content in developer-workflow on S Anand</description>
    <generator>Hugo -- 0.156.0</generator>
    <language>en-us</language>
    <lastBuildDate>Fri, 20 Mar 2026 07:12:47 +0530</lastBuildDate>
    <atom:link href="https://www.s-anand.net/blog/tag/developer-workflow/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Local context repositories for AI</title>
      <link>https://www.s-anand.net/blog/local-context-repositories-for-ai/</link>
      <pubDate>Fri, 20 Mar 2026 07:12:47 +0530</pubDate>
      <guid>https://www.s-anand.net/blog/local-context-repositories-for-ai/</guid>
      <description>&lt;p&gt;When people ask me for connections, I share my &lt;a href=&#34;https://www.linkedin.com/mypreferences/d/download-my-data&#34;&gt;LinkedIn data&lt;/a&gt; and ask them to pick.&lt;/p&gt;
&lt;p&gt;This week, three people asked for AI ideas. I shared my local content with AI coding agents and asked them to pick.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-03-20-local-context-repositories-for-ai.avif&#34;&gt; &lt;!-- https://gemini.google.com/u/2/app/b90eaeb839f3e493 --&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 1: Give access to content&lt;/strong&gt;. I use a &lt;a href=&#34;https://github.com/sanand0/scripts/blob/7e1dc00d7e1fa36a9949a1e061c1b529928cc175/dev.dockerfile&#34;&gt;Dockerfile&lt;/a&gt; and &lt;a href=&#34;https://github.com/sanand0/scripts/blob/7e1dc00d7e1fa36a9949a1e061c1b529928cc175/dev.sh&#34;&gt;script&lt;/a&gt; to isolate coding agents. To give access, I run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dev.sh -v /home/sanand/code/blog/:/home/sanand/code/blog/:ro &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -v /home/sanand/code/til:/home/sanand/code/til:ro &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       -v /home/sanand/Dropbox/notes/transcripts:/home/sanand/Dropbox/notes/transcripts:ro
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This gives read-only access to my blog, things I learned, transcripts, and I can add more. (My transcripts are private, the rest are public.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 2: Ask agents to scan content&lt;/strong&gt;. For &lt;a href=&#34;https://github.com/sanand0/talks/blob/c45b0e272708f82be50a1c48f10791bd0fee8e46/2026-03-18-iitm-office-of-institutional-advancement/prompts.md&#34;&gt;example&lt;/a&gt;, I ask it to read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Required blog posts related to LLMs &lt;code&gt;/home/sanand/code/blog/&lt;/code&gt; (especially with the category &lt;code&gt;llms&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Other relevant transcripts &lt;code&gt;/home/sanand/Dropbox/notes/transcripts&lt;/code&gt; (especially extracted AI advice at &lt;code&gt;/home/sanand/Dropbox/notes/transcripts/extracts/ai/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Things I learnt at &lt;code&gt;/home/sanand/code/til/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;This makes it explicitly aware of the content and can use it to answer questions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 3: Help it do better&lt;/strong&gt;. I often add &amp;ldquo;Use sub-agents as required&amp;rdquo;, which reduces the context and lets them run more in parallel. I also point them to &lt;a href=&#34;https://github.com/sanand0/talks/blob/c45b0e272708f82be50a1c48f10791bd0fee8e46/2026-03-18-iitm-academic-council/ideas-post-mortem.md&#34;&gt;post-mortems&lt;/a&gt; for tips on scanning content effectively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 4: Output as JSON&lt;/strong&gt;. JSON lets me write programs to convert to multiple other formats (e.g. HTML, markdown). I specify the fields I want, how I want them filled, and leave the rest to the agent. &lt;a href=&#34;https://github.com/sanand0/talks/blob/c45b0e272708f82be50a1c48f10791bd0fee8e46/2026-03-18-iitm-academic-council/ideas/ideas.json&#34;&gt;Sample output&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This is not a new technique. It&amp;rsquo;s just context engineering, roughly like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connecting ChatGPT/Claude/Gemini/ to Dropbox/Google Drive/&amp;hellip; and asking it to read the content.&lt;/li&gt;
&lt;li&gt;Enabling web search and asking them to search online.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But I can do this (kind of) safely on my local content and I can also teach it how to scan the content - which is a useful learning.&lt;/p&gt;
&lt;p&gt;Next steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add README.md to each directory on how to scan the content effectively.&lt;/li&gt;
&lt;li&gt;Think about what content repositories I should add&lt;/li&gt;
&lt;li&gt;Explore &lt;em&gt;combining&lt;/em&gt; content repositories cleverly (e.g. &amp;ldquo;Read my blog and apply lessons to my code.&amp;rdquo;)&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    <item>
      <title>AI in SDLC at PyConf</title>
      <link>https://www.s-anand.net/blog/ai-in-sdlc-at-pyconf/</link>
      <pubDate>Thu, 19 Mar 2026 14:58:26 +0530</pubDate>
      <guid>https://www.s-anand.net/blog/ai-in-sdlc-at-pyconf/</guid>
      <description>&lt;p&gt;I was at a panel on &lt;a href=&#34;https://2026.pyconfhyd.org/&#34;&gt;AI in SDLC&lt;/a&gt; at PyConf. Here&amp;rsquo;s the summary of my advice:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Process&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make AI your &lt;em&gt;entire&lt;/em&gt; SDLC loop. Record client calls, feed them to a coding agent to directly build &amp;amp; deploy the solution.&lt;/li&gt;
&lt;li&gt;Record your prompts, run post-mortems, and distill them into &lt;code&gt;SKILLS.md&lt;/code&gt; files for reuse.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Prompting&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ask AI to make output &lt;em&gt;more reviewable&lt;/em&gt;. Don&amp;rsquo;t waste time reviewing unclear output.&lt;/li&gt;
&lt;li&gt;Prefer &lt;em&gt;directional&lt;/em&gt; feedback (feeling, emotion, intent) over implementational.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Also&lt;/em&gt; give AI freedom to do things its way. Learn from that - you&amp;rsquo;ll be surprised.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prefer interns / outsiders over experts. They don&amp;rsquo;t slow the process with preconceptions and leverage AI better.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Stop&lt;/em&gt; learning what AI does well. Learn what AI fails at - using AI. Keep re-assessing these.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Adoption&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Developer using AI are &lt;em&gt;still&lt;/em&gt; accountable for their code. (Agents might become accountable in the future.)&lt;/li&gt;
&lt;li&gt;Start with new projects: less competition, fewer preconceptions, lower risk.&lt;/li&gt;
&lt;li&gt;Start in domains where failure is OK, rather than making AI safe enough for high-risk domains.&lt;/li&gt;
&lt;li&gt;Create safe spaces where hallucinations don&amp;rsquo;t matter and run experiments there to learn what AI can do.&lt;/li&gt;
&lt;li&gt;Plan for where AI&amp;rsquo;ll be a year later. It&amp;rsquo;s growing &lt;em&gt;very&lt;/em&gt; rapidly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The full details of the panel discussion are at &lt;a href=&#34;https://sanand0.github.io/talks/2026-03-15-pyconf-ai-in-sdlc/&#34;&gt;Who Owns the Commit?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://sanand0.github.io/talks/2026-03-15-pyconf-ai-in-sdlc/sketchnote.avif&#34;&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Using Codex to improve Codex</title>
      <link>https://www.s-anand.net/blog/using-codex-to-improve-codex/</link>
      <pubDate>Sun, 01 Mar 2026 18:26:13 +0800</pubDate>
      <guid>https://www.s-anand.net/blog/using-codex-to-improve-codex/</guid>
      <description>&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-03-01-using-codex-to-improve-codex.avif&#34;&gt; &lt;!-- https://gemini.google.com/app/e32860c560c9df57 --&gt;&lt;/p&gt;
&lt;p&gt;Instead of learning and applying &lt;a href=&#34;https://developers.openai.com/codex/changelog/&#34;&gt;new Codex features&lt;/a&gt;, I asked it to analyze my sessions and tell me what I&amp;rsquo;m under-using.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I&amp;#39;d like you to analyze my Codex sessions and help me use Codex better.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sessions/ has all my past Codex sessions.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Search online for the OpenAI Codex release notes for the latest features Codex has introduced and read them - from whatever source you find them.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Then, create a comprehensive catalog of Codex features.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Then, analyze my sessions and see which feature I could have used but didn&amp;#39;t and make a comprehensive list.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Then summarize which features I should be using more, how, what the benefits are, and with examples from my sessions.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Document these in one or more Markdown files in this directory. Write scripts as required. Commit as you go.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It did a thorough job of &lt;a href=&#34;https://github.com/sanand0/datastories/blob/8b7c71230900698ec424ba7e888f4deb74ac6ac6/codex-session-analysis/CODEX_FEATURE_CATALOG.md&#34;&gt;listing all the new features&lt;/a&gt; and &lt;a href=&#34;https://github.com/sanand0/datastories/blob/8b7c71230900698ec424ba7e888f4deb74ac6ac6/codex-session-analysis/CODEX_SESSION_GAP_ANALYSIS.md&#34;&gt;analyzing my gaps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://sanand0.github.io/datastories/codex-session-analysis/&#34;&gt;&lt;strong&gt;Read the full story&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the summary: I&amp;rsquo;m using new models immediately, but not the new features of Codex. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parallel execution&lt;/strong&gt;. Yesterday, I ran ~103 tool calls without the new &lt;a href=&#34;https://developers.openai.com/codex/changelog/#github-release-290476287&#34;&gt;spawn_agents_on_csv&lt;/a&gt; feature from last week, which would have saved a &lt;em&gt;lot&lt;/em&gt; of time running in parallel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Permissions&lt;/strong&gt;. Last week, I ran a script that asked me for permissions 7 times towards the end. Instead, I could have used &lt;code&gt;/permissions&lt;/code&gt; to set early permissions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The best part is that it could just add a few instructions to my &lt;code&gt;AGENTS.md&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Run multiple independent reads in parallel.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;For 20+ tool calls, maintain update_plan throughout.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;For long-running commands/tests, delegate via sub-agents and report checkpoints.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;If blocked by permissions, ask me concise choices.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;If sandbox/config gets in the way, use /permissions and /debug-config early.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;Now, the beauty is that &lt;strong&gt;the tool optimized itself&lt;/strong&gt;. I don&amp;rsquo;t even need to learn how to optimize it!&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Rofi vs Kanata</title>
      <link>https://www.s-anand.net/blog/rofi-vs-kanata/</link>
      <pubDate>Sun, 01 Mar 2026 15:25:48 +0800</pubDate>
      <guid>https://www.s-anand.net/blog/rofi-vs-kanata/</guid>
      <description>&lt;!--
Chats asking for Kanata use cases:
https://chatgpt.com/c/697d67a3-89d8-83a4-ad61-e905d2598abb
https://claude.ai/chat/b29d22da-6189-4c46-93b2-e64502fa6ee7
https://gemini.google.com/app/91a7e0c2ab8e1eae
--&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/jtroo/kanata&#34;&gt;Kanata&lt;/a&gt; might be the most useful tool I can&amp;rsquo;t find a use for.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a cross-platform keyboard mapper. Some cool features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Make any key a modifier&lt;/strong&gt;. Ctrl, Shift, Alt, etc. are modifiers. But we can make it so that pressing Space + I/J/K/L maps to Up/Left/Down/Right.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chords&lt;/strong&gt;. You can map any &lt;em&gt;sequence&lt;/em&gt; of keys to anything else. For example, Alt + G, then C can type &lt;code&gt;git commit -m&amp;quot;Experimenting&amp;quot; [ENTER]&lt;/code&gt;. Ctrl + M, then Down, can reduce the music volume by 10%.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toggles&lt;/strong&gt;. Double-clicking Caps Lock activates capitalization for the current word, and once you type a non-letter, it turns off. Or double-clicking Ctrl can turn on &amp;ldquo;gaming mode&amp;rdquo; where WASD becomes arrow keys, and double-clicking again turns it off.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tap Dance&lt;/strong&gt;. Double-clicking left-shift can turn on Caps Lock. Triple-clicking turns it off. Quadruple-clicking &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; and there&amp;rsquo;s &lt;em&gt;lots&lt;/em&gt; more.&lt;/p&gt;
&lt;p&gt;Unfortunately, I have not been able to find a single use in practice. My main bottleneck is that I don&amp;rsquo;t remember the shortcuts. So, instead, I use &lt;a href=&#34;https://github.com/davatorium/rofi&#34;&gt;rofi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/davatorium/rofi&#34;&gt;Rofi&lt;/a&gt; is a programmable menu launcher. The great thing is that I don&amp;rsquo;t need to remember stuff. When I &lt;a href=&#34;https://github.com/sanand0/scripts/blob/6c7ac7ab91ff726a60b700caf5808213fbb6032a/setup/media-keys.dconf#L45-L61&#34;&gt;map it to keyboard shortcuts&lt;/a&gt;, it pops up a menu and I pick what I need.&lt;/p&gt;
&lt;p&gt;I use it to:&lt;/p&gt;
&lt;p&gt;#1: &lt;strong&gt;&lt;a href=&#34;https://github.com/sanand0/scripts/blob/4e514e2128f25b78b3a7b0ad5324887b4d96161c/rofi-files.sh&#34;&gt;Open any file&lt;/a&gt; or &lt;a href=&#34;https://github.com/sanand0/scripts/blob/4e514e2128f25b78b3a7b0ad5324887b4d96161c/rofi-chrome-tabs.sh&#34;&gt;browser tab&lt;/a&gt;&lt;/strong&gt; with &lt;code&gt;Ctrl + Alt + F&lt;/code&gt;.
This is my most used shortcut. It replaces &lt;a href=&#34;https://www.voidtools.com/&#34;&gt;Everything&lt;/a&gt; for files, and &lt;a href=&#34;https://support.google.com/chrome/answer/2391819?sjid=6582210427121552745-NC#:~:text=find%20the%20specific%20tab&#34;&gt;Chrome Search Tab&lt;/a&gt; with a single shortcut.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-03-01-rofi-ctrl-alt-f-files-browser.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;#2: &lt;strong&gt;&lt;a href=&#34;https://github.com/sanand0/scripts/blob/974d716338563f4a392a61bc67d66db1b99c8262/rofi-prompts.sh&#34;&gt;Paste any prompt fragment&lt;/a&gt;&lt;/strong&gt; with &lt;code&gt;Ctrl + Alt + P&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is especially useful when adding a prompt fragment, like &lt;a href=&#34;https://www.s-anand.net/blog/ai-expert-lens/&#34;&gt;Expert Lens&lt;/a&gt; in the middle of a prompt, or &lt;a href=&#34;https://github.com/sanand0/blog/blob/main/pages/prompts/analyze-call-recording.md&#34;&gt;analyzing call recordings&lt;/a&gt; a dozen times a day.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-03-01-rofi-ctrl-alt-p-prompts.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;#3: &lt;strong&gt;&lt;a href=&#34;https://github.com/sanand0/scripts/blob/974d716338563f4a392a61bc67d66db1b99c8262/rofi-clip.sh&#34;&gt;Edit the clipboard&lt;/a&gt;&lt;/strong&gt; with &lt;code&gt;Ctrl + Alt + M&lt;/code&gt; (for Markdown).&lt;/p&gt;
&lt;p&gt;This is a killer feature. I often use it to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy from email/chat and paste it in ChatGPT as Markdown&lt;/li&gt;
&lt;li&gt;Copy from ChatGPT and remove the em-dashes and non-ASCII characters&lt;/li&gt;
&lt;li&gt;Convert Markdown to Unicode for LinkedIn&lt;/li&gt;
&lt;li&gt;Convert Markdown to rich test for pasting in emails or chat&lt;/li&gt;
&lt;li&gt;Creating a ChatGPT / Claude / Google AI mode link from a piece of text&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-03-01-rofi-ctrl-alt-m-markdown-clipboard.webp&#34;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I&amp;rsquo;m still keen to find a use for Kanata, but for now, my use of Rofi will continue to grow.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;19 Mar 2026&lt;/strong&gt;: The &lt;a href=&#34;https://crescentro.se/posts/compose-key/&#34;&gt;Compose key&lt;/a&gt; is meant to combine two keystrokes to create a new character - which Kanata offers as a feature with &lt;em&gt;any&lt;/em&gt; key.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Voice coding is the new live coding</title>
      <link>https://www.s-anand.net/blog/voice-coding-is-the-new-live-coding/</link>
      <pubDate>Sun, 21 Sep 2025 11:18:17 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/voice-coding-is-the-new-live-coding/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Voice coding is the new live coding&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/ChatGPT-Image-Sep-21-2025-04_46_27-PM.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;In Feb 2025 at PyConf Hyderabad, I tried a new slide format: &lt;a href=&#34;https://www.s-anand.net/blog/command-line-slideshows-in-bash/&#34;&gt;command-line slideshows in &lt;code&gt;bash&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve used this format in more talks since then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/talks0/blob/main/2025-06-pycon-sg/llm-cli.md&#34;&gt;LLMs in the CLI&lt;/a&gt;, PyCon Singapore, Jun 2025&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/talks/blob/main/2025-07-24-pugs-agent-loop/README.md&#34;&gt;Agents in the CLI&lt;/a&gt;, Singapore Python User Group, Jul 2025&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/talks/blob/main/2025-09-13-duckdb-is-the-new-pandas/README.md&#34;&gt;DuckDB is the new Pandas&lt;/a&gt;, PyCon India, Sep 2025&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s my favorite format. I can demo code without breaking the presentation flow.&lt;br&gt;
It also draws interest. My setup was the &lt;a href=&#34;https://github.com/sanand0/talks/blob/main/2025-09-13-duckdb-is-the-new-pandas/README.md#qa&#34;&gt;top question in my PyCon talk&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Sep 2025, at PyCon India, I extended the setup for voice typing. &lt;a href=&#34;https://github.com/sanand0/scripts/blob/54560718bf2f4148d9005d74ab1543de52cff6d9/talkcode.sh&#34;&gt;&lt;code&gt;talkcode.sh&lt;/code&gt;&lt;/a&gt; is a Bash pipeline that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;uses &lt;a href=&#34;https://ffmpeg.org/&#34;&gt;&lt;code&gt;ffmpeg&lt;/code&gt;&lt;/a&gt; to record mic into as 16 kHz mono, voice-optimized &lt;code&gt;.opus&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;sends audio to Gemini via &lt;a href=&#34;https://llm.datasette.io/&#34;&gt;&lt;code&gt;llm&lt;/code&gt;&lt;/a&gt; for transcription&lt;/li&gt;
&lt;li&gt;uses &lt;a href=&#34;https://en.wikipedia.org/wiki/AWK&#34;&gt;&lt;code&gt;awk&lt;/code&gt;&lt;/a&gt; to extract the code fence&lt;/li&gt;
&lt;li&gt;uses &lt;a href=&#34;https://github.com/astrand/xclip&#34;&gt;&lt;code&gt;xclip&lt;/code&gt;&lt;/a&gt; to copy the code to the clipboard&lt;/li&gt;
&lt;li&gt;uses &lt;a href=&#34;https://github.com/jordansissel/xdotool&#34;&gt;&lt;code&gt;xdotool&lt;/code&gt;&lt;/a&gt; to paste it back to the original window&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Mic only, 16 kHz mono, voice filtering, fast Opus&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ffmpeg -hide_banner -v error &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -f pulse -i default &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -ac &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -ar &lt;span class=&#34;m&#34;&gt;16000&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -af &lt;span class=&#34;s2&#34;&gt;&amp;#34;highpass=f=100,lowpass=f=6000&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -c:a libopus -b:a 16k -vbr on &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -compression_level &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -application voip -frame_duration &lt;span class=&#34;m&#34;&gt;60&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -y &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$AUDIO&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Transcribe, extract the code fence and copy to clipboard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;llm -m gemini-2.5-flash -a &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$AUDIO&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; -s &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$SYSTEM_TEXT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tee /dev/tty &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; awk &lt;span class=&#34;s1&#34;&gt;&amp;#39;BEGIN{f=0} /```/{f=!f; next} f{buf=buf$0&amp;#34;\n&amp;#34;} END{print buf}&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xclip -selection clipboard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Bring last window to foreground and paste from clipboard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ACTIVE_WIN&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;:-&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  xdotool windowactivate --sync &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ACTIVE_WIN&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  sleep 0.08
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  xdotool key --clearmodifiers ctrl+shift+v
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;During the workshop, I said, &amp;ldquo;Which (judicial) bench has the longest pending cases,&amp;rdquo; and it generated a DuckDB query that, single-shot, ran correctly on the &lt;a href=&#34;https://github.com/vanga/indian-high-court-judgments&#34;&gt;Indian High Court judgements&lt;/a&gt; dataset.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;But LLMs are slow and break the flow. Here&amp;rsquo;s how I keep the room engaged:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Dictate, don&amp;rsquo;t type.&lt;/strong&gt; Speaking is faster &lt;strong&gt;and&lt;/strong&gt; more engaging. That&amp;rsquo;s why I built this workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid Alt-Tab.&lt;/strong&gt; Bring the LLM &lt;strong&gt;into&lt;/strong&gt; your app. Window-switching and copy-paste break focus for you &lt;strong&gt;and&lt;/strong&gt; the audience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always stream output.&lt;/strong&gt; Narrate as it loads. &lt;code&gt;| tee /dev/tty&lt;/code&gt; streams while piping.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Answer questions while you wait.&lt;/strong&gt; Keep a &lt;a href=&#34;https://www.slido.com/&#34;&gt;Slido&lt;/a&gt; Q&amp;amp;A open and address the top ones while waiting for the LLM.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/posts/sanand0_%F0%9D%97%A9%F0%9D%97%BC%F0%9D%97%B6%F0%9D%97%B0%F0%9D%97%B2-%F0%9D%97%B0%F0%9D%97%BC%F0%9D%97%B1%F0%9D%97%B6%F0%9D%97%BB%F0%9D%97%B4-%F0%9D%97%B6%F0%9D%98%80-%F0%9D%98%81%F0%9D%97%B5%F0%9D%97%B2-%F0%9D%97%BB%F0%9D%97%B2%F0%9D%98%84-activity-7376824026595278848-PxgV&#34;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Meta AI Coding: Using AI to Prompt AI</title>
      <link>https://www.s-anand.net/blog/meta-ai-coding-using-ai-to-prompt-ai/</link>
      <pubDate>Wed, 13 Aug 2025 09:43:24 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/meta-ai-coding-using-ai-to-prompt-ai/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m &amp;ldquo;meta AI coding&amp;rdquo; &amp;ndash; using an AI code editor to create the prompt for an AI code editor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time&lt;/strong&gt;. The task is complex. If the LLM (or I) mess up, I don&amp;rsquo;t want re-work. Review time is a bottleneck.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost&lt;/strong&gt;. Codex is free on my $20 OpenAI plan. Claude Code is ~$1 per chat, so I want value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learning&lt;/strong&gt;. I want to see what a &lt;strong&gt;good&lt;/strong&gt; prompt looks like.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, I wrote a rough prompt in &lt;code&gt;prompts.md&lt;/code&gt;, told Codex:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;prompts.md has a prompt under the &amp;ldquo;# Improve schema&amp;rdquo; section starting line 294.&lt;br&gt;
This is a prompt that will be passed to Claude Code to implement.&lt;br&gt;
Ask me questions as required and improve the prompt so that the results will be in line with my expectations, one-shot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Codex answered:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I read the “Improve schema” section. A few specifics need your call so I can produce a single, precise prompt.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Masters vs layouts: Remove masters entirely and keep a &lt;code&gt;layouts[]&lt;/code&gt;, or remove layouts and keep &lt;code&gt;masters[]&lt;/code&gt; with &lt;code&gt;shapes&lt;/code&gt; acting as the layout? The bullets conflict.&lt;/li&gt;
&lt;li&gt;Shape registry: Confirm &lt;code&gt;.shapes&lt;/code&gt; is an object map keyed by &lt;code&gt;id&lt;/code&gt; at every level (root, master/layout, slide), not arrays. Ordering via &lt;code&gt;z&lt;/code&gt; only?&lt;/li&gt;
&lt;li&gt;Merge semantics: Confirm deep-merge precedence root.shapes &amp;lt; mid-level (master/layout).shapes &amp;lt; slide.shapes, by &lt;code&gt;id&lt;/code&gt;. For arrays like &lt;code&gt;list.items&lt;/code&gt;, replace (not concat)?&lt;/li&gt;
&lt;li&gt;Theme flattening: Move &lt;code&gt;theme.colors&lt;/code&gt; and &lt;code&gt;theme.fonts&lt;/code&gt; to root as &lt;code&gt;colors&lt;/code&gt; and &lt;code&gt;fonts&lt;/code&gt;, or keep &lt;code&gt;theme&lt;/code&gt; but allow root aliases? Which do you prefer?&lt;/li&gt;
&lt;li&gt;Back-compat: Keep support for old schema, or drop and add a migration utility (CLI/script) to transform old→new? If keep, how long to maintain?&lt;/li&gt;
&lt;li&gt;Version: Bump to &lt;code&gt;version: \&amp;quot;2.0.0\&amp;quot;&lt;/code&gt; for the new schema?&lt;/li&gt;
&lt;li&gt;Validation: Add a JSON Schema file and validate inputs in &lt;code&gt;slidegen.html()&lt;/code&gt; (fast fail)? If yes, filename path e.g., &lt;code&gt;schema/slidegen.schema.json&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Tests and samples: Update all decks in &lt;code&gt;tests/&lt;/code&gt; (incl. &lt;code&gt;shapes-demo.json&lt;/code&gt;) and &lt;code&gt;tests/index.html&lt;/code&gt; to new schema only?&lt;/li&gt;
&lt;li&gt;Overrides removal: Confirm &lt;code&gt;slides[].overrides&lt;/code&gt; is removed entirely; all overrides via &lt;code&gt;slides[].shapes&lt;/code&gt; only.&lt;/li&gt;
&lt;li&gt;Any additional fields to normalize while we’re here (e.g., unify &lt;code&gt;unit&lt;/code&gt;, enforce &lt;code&gt;%|px&lt;/code&gt;, formalize border props)?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reply with your choices. I’ll then deliver a single, one-shot prompt for Claude Code with exact schema, merge rules, migration plan, test updates, and acceptance criteria aligned to your coding guidelines.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I replied:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;masters versus layouts: I want you to remove masters entirely and keep a layouts[]. There currently are layouts inside masters, move them up to one level.&lt;/li&gt;
&lt;li&gt;.shapes is not an object map currently. It SHOULD be an object map keyed by &lt;code&gt;id&lt;/code&gt; at every level and not arrays and it should be ordered via z only.&lt;/li&gt;
&lt;li&gt;The deep merge precedence that you have listed is correct.&lt;/li&gt;
&lt;li&gt;For list.items replacement instead of concatenation is correct.&lt;/li&gt;
&lt;li&gt;Since we are flattening the themes, we do not want theme at the root level and we do not want theme.colors/fonts aliases.&lt;/li&gt;
&lt;li&gt;We do not want to support old schema.&lt;/li&gt;
&lt;li&gt;We do not want to migrate from old schema.&lt;/li&gt;
&lt;li&gt;We do not want to bump up the version.&lt;/li&gt;
&lt;li&gt;We do not want to create a json schema file.&lt;/li&gt;
&lt;li&gt;We do want to update all the tests including shapes-demo.json.&lt;/li&gt;
&lt;li&gt;We do want to remove slides.overrides entirely, no other fields to normalize.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any other questions, please ask. Else update prompts.md&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Codex gave an output. I reviewed it and sent one more prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Drop the house rules.&lt;br&gt;
Allow the root .bg to be overridden by layouts[].bg to be overridden by slides[].bg &amp;ndash; and all the .bg values can be { fille, image, image_fit }&lt;br&gt;
layouts must be an object with the .id as key instead of a field. If any of this is unclear, please ask me. Else update prompts.md.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It finally settled on &lt;a href=&#34;https://github.com/sanand0/slidegen/blame/de953817266357b00d80d4fa3e17def02e0de292/prompts.md#L296-L502&#34;&gt;this remarkable prompt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This prompt was so clear it was &lt;strong&gt;easy to review&lt;/strong&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;strong&gt;easy for Claude Code&lt;/strong&gt; to follow (no inconsistencies).&lt;/p&gt;
&lt;p&gt;I plan to use this technique more. You might want to try it, too.&lt;/p&gt;
</description>
    </item>
    <item>
      <title></title>
      <link>https://www.s-anand.net/blog/inferencing-is-the-new-compiling/</link>
      <pubDate>Wed, 21 May 2025 10:46:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/inferencing-is-the-new-compiling/</guid>
      <description>&lt;p&gt;&amp;ldquo;Inferencing&amp;rdquo; is the new &amp;ldquo;Compiling!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I spent a fair bit of today playing Bubble Shooter because Claude spent 10 minutes writing code for an npm package: &lt;a href=&#34;https://www.npmjs.com/package/saveform&#34;&gt;https://www.npmjs.com/package/saveform&lt;/a&gt; and for a bunch of other things.&lt;/p&gt;
&lt;p&gt;5-10 minutes is too short a time to do something meaningful. I do wish these LLMs would take less or more time. We&amp;rsquo;re right now in the zone of bad interruption timing.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2025-05-21-inferencing-is-the-new-compiling-linkedin.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/feed/update/urn%3Ali%3Ashare%3A7330906705276424192&#34;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>How to create a Technical Architecture from code with ChatGPT</title>
      <link>https://www.s-anand.net/blog/how-to-create-a-technical-architecture-from-code-with-chatgpt/</link>
      <pubDate>Sat, 17 May 2025 02:14:09 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/how-to-create-a-technical-architecture-from-code-with-chatgpt/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;How to create a Technical Architecture from code with ChatGPT&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/Mermaid-Chart-Create-complex-visual-diagrams-with-text.-A-smarter-way-of-creating-diagrams.-2025-05-17-021315-scaled.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my current workflow to create technical architecture diagrams from code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 1: Copy the code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a one-liner using &lt;a href=&#34;https://github.com/simonw/files-to-prompt&#34;&gt;files-to-prompt&lt;/a&gt; to copy all files in the current directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fd &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xargs uvx files-to-prompt --cxml &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xclip -selection clipboard
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, you can specify individual files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uvx files-to-prompt --cxml README.md ... &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; xclip -selection clipboard
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;STEP 2: Prompt for the a Mermaid diagram&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.mermaidchart.com/&#34;&gt;Mermaid&lt;/a&gt; is a Markdown charting language. I use this prompt with &lt;a href=&#34;https://chatgpt.com/?model=o4-mini-high&#34;&gt;O4-Mini-High&lt;/a&gt; or &lt;a href=&#34;https://chatgpt.com/?model=o3&#34;&gt;O3&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Create a Mermaid architecture diagram for the files below.&lt;/p&gt;
&lt;p&gt;Make sure that the diagram is rich in visual detail and looks impressive.
Use the &amp;ldquo;neutral&amp;rdquo; theme.
Name nodes and links semantically and label them clearly. Avoid parantheses.
Quote subgraph labels.
Use apt &lt;code&gt;shape: rect|rounded|stadium|...&lt;/code&gt; for nodes.
Add suitable emoticons to every node.
Style nodes and links with classes most apt for them.&lt;/p&gt;
&lt;p&gt;Follow that with a bulleted explanation of the architectural elements that is suitable for adding to a slide.&lt;/p&gt;
&lt;p&gt;Finally, double-check the architecture against the codebase and provide a step-by-step validation report.&lt;/p&gt;
&lt;p&gt;[PASTE CODE]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;STEP 3: Copy the diagram into Mermaid Live Editor&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a sample output that you can paste into a new &lt;a href=&#34;https://www.mermaidchart.com/play#pako:eNqVV01v4zYQ_SsDLQxf4i3adA8VugsE2S0QwG2DdRd7qHtgyJHFmCZVknLiBvnvHYr6dqLYOTgSOR-Pb2Ye7aeEG4FJmsxmT1JLnz7NfY47nKdzjaW3TM2fn2eztc6UeeA5sx6WX9caYDaDpeFMgcA9KlPsUHtAvZfW6PAcbFx5t7GsyGGdRNvPne06CRYQ3P9eJ79KbrTMDovwH8LHx_lOyNSj3UlNIOBBCp9_nP_08xxylJvcV88_fII2MvxVG6-Tf0Js1GKta6i31twj90CBM7mBTCp0I4TX1VZpmZdGuwbeg2V6o9DG3VeQOrkrFFYrLuXKlCJTzOIE6O91WIhxa8QABeNbtsHJbIGX2m6xZ1Yy7Scy3UbLYaI-NdctXvhu7JYw2VJ7uUNgWgBzDv0RVUcuX6NLy1q1Wi--cgxlNuZEtiby1byFJp6gSxHbZeDrnu2Z41YWU5RdFYWSvOoDok10WVyBfCJL6KrFvTN6IvafBeqr2xtYUagu7gPbbNB-u5mkqraaCL6KFvDtpg2NjzTD3H_RojBS-wn0rJATob_EOIGSJtYLvURWaGkCYbn8HRzaveSxjRxye9xHrfkqmrZTp9TuqpCnTJshPtkU8IDkN1NqYQ9wnTMPxH7Hjt6vKmRPE71j-HaKmE7yIMZaJ89HvBAFJfHhKjK8Mep4pGRPFHn19sd0U_PSTuli6LIm6lGhekIMsawVIBJjWCwIDgpJ1Uro5VM1W2maRrOl1NuBJa9lExvzoWKe4TjQvtf9SJ1ceGvS9aVm5NUetlDmEM9K9N-VUomwNUQao4vK1sFeMrhe3pyQZCTaMYzUzjOlKqCUnqhHzWV7VFqlKIJ5NgBaJ4A7zNleGlvVZJC7rs4j8tLjZIHCYrTO6dB03YE1pZeaLj9ja8eROEzECLPc5gsyeLJtI20vlyZMJ2VG22vCEaqG0L3ZtlGjPhxhaMcZFu_Jh5U-N1b-V7m977sdMR8H5QhKN4fN0bQgIvHfEp2nOT6Vx1GYDD3P36Bz5LKXrpvIN0hd-YMKhRaYha903WHoMv-MWfMlqPqjO0ul77JfsgvnLTGcvru8vKyfF5W2pD8WjyN3AgV9d5GJ090D9yN3cUb2UgIM3bNzstMtN3YXeLo7NjdW6454Bvh4DQ6znwE-NkXfnWdvZR-evm0WunzOKVh0aZwWgjn6KWDZIf1w8aHtuyvn5EaDDv1ReWPXdyOxvRhqZuzIzrhqsfDRLYUpqaD0lpoxoKboVsfyQRXvoRiIaVPNbj8qxAsbnbTEGnY7pOUXvWmNj2udPP8PJRGGhw&#34;&gt;Mermaid Playground&lt;/a&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;%%{init: {&amp;#39;theme&amp;#39;:&amp;#39;neutral&amp;#39;}}%%
flowchart TB
  %% Source files
  subgraph &amp;#34;Source Files 📁&amp;#34;
    direction LR
    RT_wr[wrangler.toml 🔧]:::config
    PK_pkg[package.json 📦]:::config
    JS_idx[src/index.js 🖥️]:::code
    JSON_spec[openapi.json 📄]:::assets
    HTML_swagger[swagger.html 📜]:::assets
  end

  %% Build &amp;amp; deploy steps
  subgraph &amp;#34;Build &amp;amp; Deploy 🛠️&amp;#34;
    direction LR
    DEV[&amp;#34;npm run dev / wrangler dev ▶️&amp;#34;]:::action
    SECRET[&amp;#34;npx wrangler secret put LLMFOUNDRY_TOKEN 🔑&amp;#34;]:::action
    DEPLOY[&amp;#34;npm run deploy / wrangler deploy 🚀&amp;#34;]:::action
  end

  %% Runtime environment
  subgraph &amp;#34;Runtime Environment ☁️&amp;#34;
    direction TB
    CF_WORKER[&amp;#34;Cloudflare Worker ✨&amp;#34;]:::worker

    subgraph &amp;#34;Request Processing 🔄&amp;#34;
      direction LR
      API_ROUTER[&amp;#34;API Router 🔀&amp;#34;]:::logic

      subgraph &amp;#34;Endpoints 🌐&amp;#34;
        EXTRACT[&amp;#34;/extract 🚀&amp;#34;]:::endpoint
        OPENAPI[&amp;#34;/openapi.json 📄&amp;#34;]:::endpoint
        DOCS[&amp;#34;/docs (or /) 📘&amp;#34;]:::endpoint
      end

      subgraph &amp;#34;Handlers 🛠️&amp;#34;
        HANDLE[&amp;#34;handleExtract 📝&amp;#34;]:::logic
        SERVE_SPEC[&amp;#34;serveOpenApi (spec) 📑&amp;#34;]:::logic
        SERVE_SWAGGER[&amp;#34;serveSwaggerUI 🖥️&amp;#34;]:::logic
        NOT_FOUND[&amp;#34;404 NotFound ❓&amp;#34;]:::logic
      end
    end

    subgraph &amp;#34;Extraction Flow 🤖&amp;#34;
      PROMPT[&amp;#34;createExtractionPrompt 🤔&amp;#34;]:::logic
      GPT_API[&amp;#34;LLM Foundry API 🔗&amp;#34;]:::external
    end
  end

  %% Connections
  RT_wr --&amp;gt; CF_WORKER
  PK_pkg --&amp;gt; DEV
  JS_idx --&amp;gt; CF_WORKER
  JSON_spec --&amp;gt; CF_WORKER
  HTML_swagger --&amp;gt; CF_WORKER

  DEV --&amp;gt; CF_WORKER
  SECRET --&amp;gt; CF_WORKER
  DEPLOY --&amp;gt; CF_WORKER

  CF_WORKER --&amp;gt; API_ROUTER
  API_ROUTER --&amp;gt; EXTRACT
  API_ROUTER --&amp;gt; OPENAPI
  API_ROUTER --&amp;gt; DOCS

  EXTRACT --&amp;gt; HANDLE
  OPENAPI --&amp;gt; SERVE_SPEC
  DOCS --&amp;gt; SERVE_SWAGGER

  HANDLE --&amp;gt; PROMPT
  PROMPT --&amp;gt; GPT_API

  API_ROUTER --&amp;gt; NOT_FOUND

  %% Styling classes
  classDef config     fill:#f0f0f0,stroke:#333,stroke-width:1px;
  classDef code       fill:#e0f7fa,stroke:#333,stroke-width:1px;
  classDef assets     fill:#fce4ec,stroke:#333,stroke-width:1px;
  classDef action     fill:#fff9c4,stroke:#333,stroke-width:1px;
  classDef worker     fill:#e8f5e9,stroke:#333,stroke-width:1px;
  classDef logic      fill:#e3f2fd,stroke:#333,stroke-width:1px;
  classDef endpoint   fill:#ffebee,stroke:#333,stroke-width:1px;
  classDef external   fill:#ede7f6,stroke:#333,stroke-width:1px;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/Mermaid-Chart-Create-complex-visual-diagrams-with-text.-A-smarter-way-of-creating-diagrams.-2025-05-17-021315-1024x690.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 4: Export the diagram&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you log in, you can export as PNG.&lt;/li&gt;
&lt;li&gt;If not, you can export it as SVG or take a screenshot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: Technically, this is a flowchart, not an architecture diagram. Mermaid does support &lt;a href=&#34;https://mermaid.js.org/syntax/architecture.html&#34;&gt;architecture diagrams&lt;/a&gt;, but they are in beta and don&amp;rsquo;t look good.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;!-- wp-comments-start --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://www.s-anand.net/blog/how-to-create-a-technical-architecture-from-code-with-chatgpt-and-plantuml/&#34;&gt;How to create a Technical Architecture from code with ChatGPT and PlantUML - S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;24 May 2025 9:18 am&lt;/em&gt; &lt;em&gt;(pingback)&lt;/em&gt;:
[…] Earlier, I used Mermaid for technical architectures. But PlantUML seems a better option for cloud architecture diagrams. […]&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- wp-comments-end --&gt;
</description>
    </item>
    <item>
      <title>Automating a podcast from GitHub commits</title>
      <link>https://www.s-anand.net/blog/automating-a-podcast-from-github-commits/</link>
      <pubDate>Sun, 04 May 2025 11:21:20 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/automating-a-podcast-from-github-commits/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Automating a podcast from GitHub commits&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/Weekly-Codecast-Logo-Design.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an &lt;a href=&#34;https://www.s-anand.net/files/codecast-2025-05-04.mp3&#34;&gt;LLM-generated podcast&lt;/a&gt; of what I coded last week. &lt;a href=&#34;https://notebooklm.google.com/&#34;&gt;NotebookLM&lt;/a&gt;-inspired.&lt;/p&gt;
&lt;p&gt;The process proved straightforward.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/sanand0/blob/bfb58a7e53d8071582ef7b209f86ceb275819b44/week/summary.py#L62-L105&#34;&gt;Get my GitHub commits for the week&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/sanand0/blob/bfb58a7e53d8071582ef7b209f86ceb275819b44/week/summary.py#L41-L59&#34;&gt;Get the repositories I committed to&lt;/a&gt; for more context.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/sanand0/blob/bfb58a7e53d8071582ef7b209f86ceb275819b44/week/summary.py#L108-L130&#34;&gt;Have an LLM generate a podcast script&lt;/a&gt;. I&amp;rsquo;m using &lt;a href=&#34;https://platform.openai.com/docs/models/gpt-4.1-mini&#34;&gt;GPT 4.1 Mini&lt;/a&gt; but might shift to Gemini 2.5 Flash or DeepSeek V3.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/sanand0/blob/bfb58a7e53d8071582ef7b209f86ceb275819b44/week/config.toml#L64-L110&#34;&gt;…using a detailed prompt&lt;/a&gt; beginning with &amp;ldquo;You are a podcast script assistant for “Anand’s Weekly Codecast.” This episode is for the week of {WEEK}. …&amp;rdquo;. Here&amp;rsquo;s a &lt;a href=&#34;https://github.com/sanand0/sanand0/blob/bfb58a7e53d8071582ef7b209f86ceb275819b44/week/2025-05-04/podcast.md&#34;&gt;sample output&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sanand0/sanand0/blob/bfb58a7e53d8071582ef7b209f86ceb275819b44/week/summary.py#L133-L177&#34;&gt;Convert the script to audio&lt;/a&gt;. I&amp;rsquo;m using &lt;a href=&#34;https://platform.openai.com/docs/models/gpt-4o-mini-tts&#34;&gt;GPT 4o Mini TTS&lt;/a&gt; with &lt;a href=&#34;https://github.com/sanand0/sanand0/blob/bfb58a7e53d8071582ef7b209f86ceb275819b44/week/config.toml#L112-L130&#34;&gt;customized voices of Ash and Nova&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These now appear on my &lt;a href=&#34;https://github.com/sanand0/&#34;&gt;GitHub repo&lt;/a&gt; as a weekly summary.&lt;/p&gt;
&lt;p&gt;Beyond technical novelty, it reshaped how I think about documentation.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I write for two audiences: informing my future self what changed &lt;strong&gt;and&lt;/strong&gt; explaining &lt;strong&gt;why&lt;/strong&gt; to an LLM that will narrate it. That&amp;rsquo;s an interesting behavioral change.&lt;/li&gt;
&lt;li&gt;Technical debt is audible. When hearing my week&amp;rsquo;s work, architectural issues and potential next steps become clear. It creates an accountability mechanism that code reviews often miss.&lt;/li&gt;
&lt;li&gt;Ambient documentation. I stop documenting when coding fast. Converting signals (commits) to consumable content creates &amp;ldquo;ambient documentation&amp;rdquo; that accumulates with no extra effort. Audio reduces the energy needed to stay up to date.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This could change how we share technical work. Maybe financial analysts &amp;ldquo;narrate&amp;rdquo; spreadsheet changes, designers &amp;ldquo;explain&amp;rdquo; Figma iterations, or operators &amp;ldquo;log&amp;rdquo; settings adjustments - all automated from version control metadata.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Converting activity traces into narratives dramatically lowers cost of knowledge &amp;amp; sharing.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What activity traces do we generate? It&amp;rsquo;s worth exploring what they could become, and how it&amp;rsquo;d change behavior if we knew those signals would become stories.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 16 Feb 2025</title>
      <link>https://www.s-anand.net/blog/things-i-learned-16-feb-2025/</link>
      <pubDate>Sun, 16 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-16-feb-2025/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.connectedpapers.com/&#34;&gt;Connected Papers&lt;/a&gt; shows papers similar to each other based on co-citation and bibliographic coupling for ~50,000 papers.&lt;/li&gt;
&lt;li&gt;Notes from a fireside chat with &lt;a href=&#34;https://www.linkedin.com/in/pchandrasekar/&#34;&gt;Prashanth Chandrasekar&lt;/a&gt;, CEO, StackOverflow, and the StackOverflow team
&lt;ul&gt;
&lt;li&gt;There&amp;rsquo;s a signal that software demand is growing in 2024. Many more students took the StackOverflow survey in 2024. So more students (or other professionals) are shifting into / starting to learn software development.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://aiindex.stanford.edu/report/&#34;&gt;AI Index&lt;/a&gt; is a good resource for AI trends.&lt;/li&gt;
&lt;li&gt;Experts are better able to use AI for writing code. Less experienced developers are more likely to use AI for code reviews, project planning, etc.&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s a 5% &lt;em&gt;decline&lt;/em&gt; in favorability for AI tools compared to 2023, maybe due to disappointing results.&lt;/li&gt;
&lt;li&gt;Pilot groups working on AI are 25-30% more productive. They&amp;rsquo;re the most enthusiastic. For the rest of the company, it drops off to 5-10%
&lt;ul&gt;
&lt;li&gt;#LEARNING Benefit comes from NEW people becoming programmers, not existing ones getting more effective?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;StackOverflow wants to be where the developer is.
&lt;ul&gt;
&lt;li&gt;The programmer workflow was: Google -&amp;gt; StackOverflow -&amp;gt; GitHub.&lt;/li&gt;
&lt;li&gt;Now it&amp;rsquo;s changing to ChatGPT / Cursor -&amp;gt; GitHub.&lt;/li&gt;
&lt;li&gt;StackOverflow has a partnership with OpenAI and working on a plugin. Same with Google&amp;rsquo;s Duet AI, GitHub Copilot, many others. They&amp;rsquo;ll link to StackOverflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;StackOverflow is driving integration actively through an enterprise Overflow API&lt;/li&gt;
&lt;li&gt;Q: What tech have you seen blaze through the ranks?
&lt;ul&gt;
&lt;li&gt;Prashanth: Abstraction wins. Stuff that abstracts away things well and more wins. This includes Gen AI.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://stackoverflow.blog/author/eyepis/&#34;&gt;Erin Yepis&lt;/a&gt;: Rust (from 3% to 12%). AWS has steady growth.&lt;/li&gt;
&lt;li&gt;Erin Yapis: I have a time series spreadsheet that I&amp;rsquo;ll publish.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Q: What technologies are unusually tightly coupled?
&lt;ul&gt;
&lt;li&gt;Prashanth: AWS &amp;amp; Google Cloud are tightly coupled.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Q: We have an engagement problem. Might be India-specific. What are low-effort high-return mechanisms to increase engagement.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.linkedin.com/in/eric-woodring-1823bb84/&#34;&gt;Eric Woodring&lt;/a&gt;: Rather than a static web page, integrate it using the API. #TODO&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.linkedin.com/in/benjaminmarconi/&#34;&gt;Ben Marconi&lt;/a&gt;: Use LLMs to write post mortems and push to StackOverflow. #TODO&lt;/li&gt;
&lt;li&gt;Eric Woodring: &amp;ldquo;Hydrating&amp;rdquo; the community helps.
&lt;ul&gt;
&lt;li&gt;We take repeat questions on Teams / Slack and seed them using LLMs.&lt;/li&gt;
&lt;li&gt;We integrate with the API to auto-add Q&amp;amp;A.&lt;/li&gt;
&lt;li&gt;Transform documentation into Q&amp;amp;A. Potentially &lt;strong&gt;UPDATE&lt;/strong&gt; existing Q&amp;amp;A if it&amp;rsquo;s wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Q: What unexpected lessons about developer behavior have you learned while running StackOverflow?
&lt;ul&gt;
&lt;li&gt;Prashanth: We didn&amp;rsquo;t expect developers moving away from Google. Now it moved to the IDE.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Q: What are you learning about developer learning behavior?
&lt;ul&gt;
&lt;li&gt;Ben Marconi: Generating LLM-based onboarding documents.&lt;/li&gt;
&lt;li&gt;Using StackOverflow for Teams to identify who the experts are to contact for specific topics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Q: Are you thinking about leveraging Stack Overflow&amp;rsquo;s knowledge base for personalized or interactive learning experiences? How?
&lt;ul&gt;
&lt;li&gt;Prashanth: Traditionally, people use StackOveflow for productivity, learning, and flexibility (i.e. to ask/answer questions asynchronously without breaking their flow). So yeah, learning is important for us. (Duh!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Q: Could Stack Overflow’s interactions help evaluate the accuracy and relevance of LLM-generated code? Or provide potential metrics on quality?
&lt;ul&gt;
&lt;li&gt;Prashanth: LLM accuracy improves by ~30%. Upvotes / downvotes are reinforcement learning (RL) in steroids, so that helps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Q: What are your thoughts on reliance on LLMs potentially deskill-ing developers?
&lt;ul&gt;
&lt;li&gt;Prashanth: A real issue for &lt;em&gt;junior&lt;/em&gt; developers, not for senior ones.&lt;/li&gt;
&lt;li&gt;They&amp;rsquo;ll &lt;em&gt;come across&lt;/em&gt; as knowledgeable.&lt;/li&gt;
&lt;li&gt;Make internal evaluations and interviews more rigorous.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Anand&amp;rsquo;s requests for action:
&lt;ul&gt;
&lt;li&gt;Could I get a copy of Erin&amp;rsquo;s spreadsheet? Vivek Narayanan will follow-up.&lt;/li&gt;
&lt;li&gt;Could you help me learn more about hydration? Nick Madison will set up a meeting with customer success group.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I switched to &lt;a href=&#34;https://fishshell.com/&#34;&gt;fish shell&lt;/a&gt; mainly because:
&lt;ul&gt;
&lt;li&gt;Autocomplete and tab completion works perfectly, out-of-box.&lt;/li&gt;
&lt;li&gt;Syntax highlighting is beautiful&lt;/li&gt;
&lt;li&gt;Great multi-line editing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;To format with &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff&#34;&gt;VS Code Ruff&lt;/a&gt;, you need to point the &lt;code&gt;ruff.interpreter&lt;/code&gt; setting to a Python interpreter. You can&amp;rsquo;t run the ruff server without Python, even though ruff itself doesn&amp;rsquo;t need Python.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; checks all paths specified in &lt;a href=&#34;https://pubs.opengroup.org/onlinepubs/9699919799/utilities/cd.html&#34;&gt;&lt;code&gt;CDPATH&lt;/code&gt;&lt;/a&gt; for the directory name and changes to the first match. That&amp;rsquo;s pretty convenient!&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://flipperzero.one/&#34;&gt;Flipper Zero&lt;/a&gt; is now on my list of &amp;ldquo;To Buy&amp;rdquo; tools. It has a variety of hardware devices including NFC, RFID, Bluetooth, Infrared, etc. and is great to reverse engineer or hack devices.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>Leaning into the power of AI coding</title>
      <link>https://www.s-anand.net/blog/leaning-into-the-power-of-ai-coding/</link>
      <pubDate>Wed, 16 Oct 2024 03:55:59 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/leaning-into-the-power-of-ai-coding/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Leaning into the power of AI coding&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/DALL%C2%B7E-2024-10-16-11.52.50-A-colorful-single-panel-comic-strip-in-the-style-of-classic-Calvin-Hobbes.-Calvin-a-young-boy-with-wild-hair-is-wobbling-precariously-on-a-bike-as.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Yesterday (15 Oct 2024), I used &lt;a href=&#34;https://www.cursor.com/&#34;&gt;Cursor&lt;/a&gt; to code more than I ever have. (Doing&#39;s how we learn, I guess. Not just reading.)&lt;/p&gt;
&lt;svg overflow=&#34;hidden&#34; viewbox=&#34;0 0 1697 1288&#34; width=&#34;500&#34; xml:space=&#34;preserve&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M32 18h1621v107H32z&#34; fill=&#34;#C0E6F5&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M521 130h92v82h-92zM521 232h163v82H521zM521 334h526v82H521zM521 437h97v81h-97zM521 539h5v81h-5zM521 641h255v81H521zM521 743h143v81H521zM521 845h342v81H521zM521 946h92v82h-92zM521 1049h169v81H521zM521 1151h1122v81H521z&#34; fill=&#34;#FFB628&#34;&gt;&lt;/path&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;700&#34; transform=&#34;translate(47.4 96)&#34;&gt;Date&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;700&#34; transform=&#34;translate(526.35 96)&#34;&gt;Usage&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 198)&#34;&gt;05&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 198)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 198)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 198)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 198)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 198)&#34;&gt;15&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 300)&#34;&gt;06&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 300)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 300)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 300)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 300)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 300)&#34;&gt;27&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 402)&#34;&gt;07&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.5 402)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.32 402)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.38 402)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.44 402)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 402)&#34;&gt;87&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 504)&#34;&gt;08&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 504)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 504)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 504)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 504)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 504)&#34;&gt;16&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 606)&#34;&gt;09&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 606)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 606)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 606)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 606)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 708)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 708)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 708)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 708)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 708)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 708)&#34;&gt;42&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 810)&#34;&gt;11&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 810)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 810)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 810)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 810)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 810)&#34;&gt;24&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 912)&#34;&gt;12&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 912)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 912)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 912)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 912)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 912)&#34;&gt;57&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 1014)&#34;&gt;13&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 1014)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 1014)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 1014)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 1014)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 1014)&#34;&gt;15&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 1117)&#34;&gt;14&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 1117)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 1117)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 1117)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 1117)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1566.77 1117)&#34;&gt;28&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(47.4 1219)&#34;&gt;15&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(126.46 1219)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(145.27 1219)&#34;&gt;10&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(224.34 1219)&#34;&gt;-&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(248.4 1219)&#34;&gt;2024&lt;/text&gt;&lt;text font-family=&#34;Aptos Narrow,Aptos Narrow_MSFontService,sans-serif&#34; font-size=&#34;78&#34; font-stretch=&#34;semi-condensed&#34; font-weight=&#34;400&#34; transform=&#34;translate(1530.68 1219)&#34;&gt;186&lt;/text&gt;&lt;path d=&#34;M511 18h5v1h-5z&#34; fill=&#34;#E0E0E0&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M32.5 120.5h1621&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M32 120h1621v5H32z&#34; fill=&#34;#44B3E1&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
&lt;p&gt;This was mainly to create and publish 2 libraries on npm over 6 hours:&lt;/p&gt;
&lt;ol class=&#34;wp-block-list&#34;&gt;
&lt;li&gt;&lt;a href=&#34;https://www.npmjs.com/package/asyncsse&#34;&gt;asyncsse&lt;/a&gt; - which converts a &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&#34;&gt;Server-Sent Event&lt;/a&gt; stream into an async iterator that I can use in a &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of&#34;&gt;for await ... of&lt;/a&gt; loop&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.npmjs.com/package/asyncllm&#34;&gt;asyncllm&lt;/a&gt; - which standardizes the Server-Sent Events streamed by the popular LLMs into an easy to use form.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This exercise broke several mental barriers for me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writing in a new language&lt;/strong&gt;. &lt;a href=&#34;https://deno.com/blog/v2.0&#34;&gt;Deno 2.0&lt;/a&gt; was released recently. I was impressed by the compatibility with npm packages. Plus, it&#39;s a single EXE download that includes a linter, tester, formatter, etc. Like all recent cool fast tools, it&#39;s written in Rust. So I decided to use it for testing. Running &lt;code&gt;deno test&lt;/code&gt; runs the &lt;a href=&#34;https://github.com/gramener/asyncsse/blob/main/test.js&#34;&gt;entire test suite&lt;/a&gt;. My prompts included asking it to:&lt;/p&gt;
&lt;ul class=&#34;wp-block-list&#34;&gt;
&lt;li&gt;&lt;code&gt;Create a Deno HTTP server to mock requests for the tests&lt;/code&gt;. This is cool because a single, simple code chunk runs the server within the test suite.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Serve static files from samples/&lt;/code&gt; to move my tests into files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Writing test cases&lt;/strong&gt;. Every line of this code was written by Cursor via Claude 3.5 Sonnet. &lt;em&gt;Every line&lt;/em&gt;. My prompt was, &lt;code&gt;Look at the code in @index.js and write test cases for scenarios not yet covered.&lt;/code&gt; It&#39;s surprising how much of the SSE spec it already knew, and anticipated edge cases like:&lt;/p&gt;
&lt;ul class=&#34;wp-block-list&#34;&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gramener/asyncsse/blob/13b33140f6bc17618789b5075a96f8f85a84c605/test.js#L67-L69&#34;&gt;SSE values might have a colon&lt;/a&gt;. I learnt for the first time that the &lt;code&gt;limit&lt;/code&gt; parameter in &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split&#34;&gt;String.split()&lt;/a&gt; is very different from Python&#39;s str.split. (The splits, then picks the first few, ignoring the rest. Python ensures the rest is packed into the last split.) This helped me find a major bug.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gramener/asyncsse/blob/13b33140f6bc17618789b5075a96f8f85a84c605/test.js#L52-L54&#34;&gt;SSE has comments&lt;/a&gt;. Empty keys are treated as strings. Didn&#39;t know this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was able to use it to generate test cases based on content as well. &lt;code&gt;Based on @index.js and @&lt;a href=&#34;https://github.com/gramener/asyncllm/blob/main/samples/openai.txt&#34;&gt;openai.txt&lt;/a&gt; write a test case that verifies the functionality&lt;/code&gt;  created the entire &lt;a href=&#34;https://github.com/gramener/asyncllm/blob/cbde11155f3a8567794058d01da1bd8d72f996b7/test.js#L25-L34&#34;&gt;test case for OpenAI responses&lt;/a&gt;. (I did have to edit it because LLMs don&#39;t count very well, but it was minimal.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bridging test coverage gaps&lt;/strong&gt;. The prompt that gave me the most delightful result was &lt;code&gt;Are there any scenarios in @index.js not tested by @test.js?&lt;/code&gt; It did a great job of highlighting that I hadn&#39;t covered Groq, Azure, or CloudFlare AI workers (though they were mentioned in the comments), error handling, empty/null values in some cases, tested for multiple tool calls. I had it generate mock test data for some of these and added the tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enhancing knowledge with references&lt;/strong&gt;. I passed Cursor the SSE documentation via &lt;code&gt;@https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&lt;/code&gt; and asked it to find more scenarios my code at &lt;code&gt;@index.js&lt;/code&gt; had not covered. This found a number of new issues.&lt;/p&gt;
&lt;ul class=&#34;wp-block-list&#34;&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gramener/asyncsse/blob/13b33140f6bc17618789b5075a96f8f85a84c605/test.js#L79-L82&#34;&gt;SSE values can be split across multiple lines&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gramener/asyncsse/blob/13b33140f6bc17618789b5075a96f8f85a84c605/test.js#L75-L78&#34;&gt;Fields without values are valid&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/gramener/asyncsse/blob/13b33140f6bc17618789b5075a96f8f85a84c605/test.js#L71-L73&#34;&gt;Empty lines should be ignored&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Generating bindings&lt;/strong&gt;. I avoid TypeScript because I don&#39;t know it. Plus, it requires an compilation step for the browser. But TypeScript bindings are helpful. So I prompted Cursor, using the Composer (which can create new files) to &lt;code&gt;Create TypeScript bindings for @index.js in index.d.ts&lt;/code&gt; - which id did almost perfectly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Check for errors&lt;/strong&gt;. I typed &lt;code&gt;Check this file for errors&lt;/code&gt; on @&lt;a href=&#34;https://github.com/gramener/asyncsse/blob/main/index.d.ts&#34;&gt;index.d.ts&lt;/a&gt;. I don&#39;t know enough to figure this out. It went through the description and said everything seems fine. But I saw a TypeScript plugin error that said, &lt;code&gt;Property &#39;data&#39; of type &#39;string | undefined&#39; is not assignable to &#39;string&#39; index type &#39;string&#39;.ts(2411)&lt;/code&gt;. When prompted, it spotted the issue. (The earlier code assumed all properties are strings. But some can be undefined too. It fixed it.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt;. At first, I asked the Composer to &lt;code&gt;Create a README.md suitable for a world-class professional open source npm package&lt;/code&gt; and it did a &lt;a href=&#34;https://github.com/gramener/asyncsse/blob/main/README.md&#34;&gt;pretty good job&lt;/a&gt;. I just needed to update the repository name. I further prompted it to &lt;code&gt;Modify README based on @index.js and share examples from @test.js&lt;/code&gt; on &lt;a href=&#34;https://github.com/gramener/asyncllm/blob/main/README.md&#34;&gt;asyncllm&lt;/a&gt;, which did an excellent job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code review&lt;/strong&gt;. I asked it to &lt;code&gt;Review this code. Suggest possible improvements for simplicity, future-proofing, robustness, and efficiency&lt;/code&gt; and it shared a few very effective improvements.&lt;/p&gt;
&lt;ol class=&#34;wp-block-list&#34;&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookahead_assertion&#34;&gt;Regex lookaheads&lt;/a&gt; for efficient regular expression splitting, i.e. use &lt;code&gt;buffer.split(/(?=\r?\n\r?\n)/)&lt;/code&gt; instead of &lt;code&gt;buffer.split(/(\r?\n\r?\n)/)&lt;/code&gt; -- and though I haven&#39;t tested this, it looked cool.&lt;/li&gt;
&lt;li&gt;Restructuring complex if-else code into &lt;a href=&#34;https://github.com/gramener/asyncllm/blob/cbde11155f3a8567794058d01da1bd8d72f996b7/index.js#L64-L84&#34;&gt;elegant parsers&lt;/a&gt; that made my code a lot more modular.&lt;/li&gt;
&lt;li&gt;Error handling. It added &lt;code&gt;try {} catch {}&lt;/code&gt; blocks at a few places that helped catch errors that I don&#39;t anticipate but don&#39;t hurt.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Code simplification&lt;/strong&gt;. Several times, I passed it a code snippet, saying just &lt;code&gt;Simplify&lt;/code&gt;. Here&#39;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;events&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;asyncLLM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(...))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;events&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be simplified to&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;events&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fromAsync&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;asyncLLM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(...))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Packaging&lt;/strong&gt;. I copied a &lt;code&gt;package.json&lt;/code&gt; from an earlier file and asked it to &lt;code&gt;Modify package.json, notable keywords and files and scripts based on @index.js&lt;/code&gt; which it did a &lt;a href=&#34;https://github.com/gramener/asyncllm/blob/main/package.json&#34;&gt;perfect job of&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blogging&lt;/strong&gt;. I wrote this blog post with the help of the chat history on Cursor. Normally, such blog posts take me 3-4 hours. This one took 45 minutes. I just had to pick and choose from history. (I lost a few because I renamed directories. I&#39;ll be careful not to do that going forward.)&lt;/p&gt;
&lt;hr class=&#34;wp-block-separator has-alpha-channel-opacity&#34;/&gt;
&lt;p&gt;Overall, it was a day of great learning. Not in the classroom sense of &#34;Here&#39;s something I didn&#39;t know before&#34;, but rather the cycling / swimming sense of &#34;Here&#39;s something I now know to do.&#34;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>From Laptops to Chatbots: Coding at 30,000 ft</title>
      <link>https://www.s-anand.net/blog/from-laptops-to-chatbots-coding-at-30000-ft/</link>
      <pubDate>Sat, 30 Mar 2024 08:23:58 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/from-laptops-to-chatbots-coding-at-30000-ft/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;From Laptops to Chatbots: Coding at 30,000 ft&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/coding-on-a-flight.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Until recently, I could code on flights. This year, I lost that ability. Again.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s happened before. In each case, technology has solved the problem for me. Here&amp;rsquo;s the history.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I need a laptop.&lt;/strong&gt; Since 2001, I&amp;rsquo;ve never been without one on a flight.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I need power.&lt;/strong&gt; Since 2005, I use dark mode and every low power feature available. (I also became good at finding hidden power outlets.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I need documentation.&lt;/strong&gt; Since 2007, I use offline documentation. Windows &lt;code&gt;.CHM&lt;/code&gt;s gave way to &lt;a href=&#34;https://devdocs.io&#34;&gt;devdocs.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I need my notes.&lt;/strong&gt; Since 2010, all my notes (Markdown files) are synced via &lt;a href=&#34;https://dropbox.com/&#34;&gt;Dropbox&lt;/a&gt; automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I need CDNs.&lt;/strong&gt; Since 2014, I&amp;rsquo;ve replaced CDNs with local node modules. &lt;strong&gt;Note to self&lt;/strong&gt;: Get a local caching proxy instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I need GitHub.&lt;/strong&gt; Since 2023, I have two laptops. So, I &lt;code&gt;git pull&lt;/code&gt; manually before flights. &lt;strong&gt;Note to self&lt;/strong&gt;: Find an automated solution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I need ChatGPT.&lt;/strong&gt; Since 2024, I stopped coding without ChatGPT. Now I&amp;rsquo;ve forgotten how to code. Today, I couldn&amp;rsquo;t figure out the SQL syntax to group by &lt;code&gt;duration == 0&lt;/code&gt; vs &lt;code&gt;duration != 0&lt;/code&gt;. &lt;strong&gt;Note to self&lt;/strong&gt;: Get lightweight local code LLMs.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s amazing how the coding technology stack has grown. Also amazing how technology fills the gaps in the scaffolding.&lt;/p&gt;
</description>
    </item>
  </channel>
</rss>
