<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>notes by druchan — RSS Feed</title><link>https://notes.druchan.com/</link><description>notes by druchan</description>
    <lastBuildDate>Thu, 12 Mar 2026 12:00:00 +0530</lastBuildDate><atom:link href="https://notes.druchan.com/feed.xml" rel="self" type="application/rss+xml"/><item>
<title>Power studies journal #1</title>
<link>https://notes.druchan.com/power-studies-journal-1</link>
<guid>https://notes.druchan.com/power-studies-journal-1</guid>
<description><![CDATA[<p>This is hopefully the first of a regular frequency of journal entries / updates during the course of studies in power.</p>
<p>Power cuts across multiple dimensions and levels. There's a lot of power dynamics in nature, within species, across species. In humans (sociologically), there's individual power, there's collective power, there's power of nations -- all acted out in relation to other parties. Power dynamics dictate all sorts of interactions (and bullying and leverage and so on).</p>
<p>In my dictionary, this sociological power has always carried a negative connotation (but, obviously, that is not necessarily the case). Evil, so to speak. &quot;Power corrupts.&quot; Patriarchy, casteism, racism, elitism, wealth-gap etc. are all driven by power structures emerging from privilege, power imbalances and the &quot;misuse&quot; of said privilege. And the resistance to and overcoming of such a power is by way of dismantling the power through collective action. The leftist ideal, so to speak.</p>
<p>When a bad-actor uses power (of privilege, economics, military-might etc.) to commit bad acts, we hear about it from the lens of &quot;misusing/abusing&quot; their power. When a good-actor does some good, the coverage of that doesn't look at it from the angle of power; rather, it's usually seen from the lens of responsibility or philanthropy or altruism.</p>
<p>I guess power can be studied from a utilitarian standpoint (this is what the Thiels and the Musks do and then leverage that knowledge to screw the world while completely believing that they're a force for good!). And it can be studied as an intellectual curiosity.</p>
<p>There's a lot going on here that I need to understand. Hypothesis that I implicitly seem to hold true - like power inherently corrupts at some point - need to be cross-referenced with existing literature (beyond Julius Caesar). That's just one example.</p>
<p>--</p>
<p>For starters, I have a bunch of books I've long-listed (in no sort order). Who knows how much of it I would make through before something else comes up.</p>
<ul>
<li>Influence: Psychology of Persuasion, Robert Cialdini</li>
<li>Power: Why Some People Have It and Some Don't, Jeffrey Pfeffer</li>
<li>The Prince, Machiavelli</li>
<li>Rules for Radicals, Saul Alinsky</li>
<li>48 Laws of Power, Robert Greene</li>
<li>Who's Pulling Your Strings? Harriet B. Braiker</li>
<li>Games People Play, Eric Berne</li>
<li>Never Split the Difference, Chris Voss</li>
<li>Discourses on Livy, Machiavelli</li>
<li>The Crowd: A Study of Popular Mind, Gustave Le Bon</li>
<li>The Art of Worldly Wisdom, Baltasar Gracián</li>
<li>Without Conscience: The Disturbing World of Psychopaths Among Us (Robert Hare)</li>
<li>The Gift of Fear (Gavin de Becker)</li>
<li>33 Strategies of War, Robert Greene</li>
<li>In Sheep's Clothing: Understanding and Dealing with Manipulative People, George K. Simon, Jr.</li>
<li>The Mind and Society, Vilfredo Pareto</li>
<li>Brave New World &amp; Brave New World Revisited, Aldous Huxley</li>
<li>The Machiavellians: Defenders of Freedom, James Burnham (on the elites argument)</li>
<li>Discourses on Voluntary Servitude, Étienne de La Boétie</li>
<li>Propaganda: The Formation of Men's Attitudes, Jacques Ellul</li>
<li>Propaganda, Edward Bernays</li>
<li>The Dictator's Handbook, Bruce Bueno de Mesquita ()</li>
<li>The Grand Chessboard, Zbigniew Brzezinski (former NSA writes on why US should control Eurasia)</li>
<li>The Power Broker, Robert Caro (abt an influential New Yorker, Robert Moses)</li>
<li>Han Feizi, Han Fei (Chinese legalist classic on how a ruler should be)</li>
<li>Art of War, Sun Tzu</li>
<li>Arthashastra, Kautilya</li>
<li>Vidura Niti, Mahabharata</li>
<li>Niti Shatakam, Bhartrhari</li>
<li>Chanakya Niti, Chanakya</li>
<li>The Book of Ghost Valley Master, Guiguzi</li>
<li>Thick Face, Black Heart - Chin-Ning Chu (trans of Thick Black Theory by Li Zongwu)</li>
<li>The Craft of Power, R.G.H. Siu</li>
</ul>
<p>Interestingly, the book ordering kind of reflects the western-oriented structures of internet search, online data and general inclination of the world. When we talk of power, it's almost impossible to go without talking about Machiavelli's Prince. Not so much Kautilya's Arthashastra. (Sun Tzu is perhaps an exception, but the credit to that goes to western propaganda). Internet searches reflect this big time. Loads of recommendations like 'Discourses on Livy', 'Art of Worldly Wisdom', 'Power Broker', and none of the oriental books till I prodded.</p>
<p>There are some 'popsci' kinda books in the list (Robert Greene, notably). But the most interesting one is 'Rules for Radicals', a '71 book from a community activist.</p>
<p>--</p>
<p>India's foreign minister, S. Jaishankar, writes (in his book, 'The India Way'):</p>
<blockquote>
<p>The one society that has elevated dissimulation to the highest level of statecraft, as one of our foremost Sinologists pointed out, is China. Its virtues are repeatedly lauded in the Three Kingdoms epic, where many of the decisive encounters are won by trickery rather than by force. The 36 Stratagems in the Book of Qi are further proof of how deeply such approaches have percolated into popular Chinese thinking. 'Deceiving the heavens to cross the ocean' or' making a sound in the East to then strike West' are among its most well-known aphorisms. No less are 'decking trees with false blossoms' or the empty fort strategy. Unlike in India, there is neither guilt nor doubt in dissembling; in fact, it is glorified as an art. Some analysts have even suggested that China's extraordinary rise has drawn heavily on its cultural attributes.</p>
</blockquote>
<p>Sun Tzu is sharp and incisive but looks like even he feels mellow compared to the kinds of 'Thick Face, Black Heart' (Li Zongwu, end of Qing dynasty). Anyway, the point is: the cultural happenstances of a system get encoded into literary works and then those go on to dictate (amplify, preach, sanction) all sorts of behavior into the cultural DNA of the descendants of that system. True of Sun Tzu, true of Machiavelli, perhaps true of Kautilya too.</p>
<p>I have notes from 'Acting with Power' that I need to revisit. And I started off with (the populist) '48 Laws of Power' to get a broader sense of what's out there. It's not so much a serious study-book (and I may be wrong about that), but Greene has distilled a broad collection of prior work, I might just get a good look at the layout of the land and the bibliography helps.</p>
]]></description>
<pubDate>Thu, 12 Mar 2026 12:00:00 +0530</pubDate>
</item><item>
<title>500 days of rdigest</title>
<link>https://notes.druchan.com/500-days-of-rdigest</link>
<guid>https://notes.druchan.com/500-days-of-rdigest</guid>
<description><![CDATA[<p><a href="https://github.com/chandru89new/rdigest"><code>rdigest</code></a> is a small CLI-based tool I made in late 2024. It began as a way to manage my daily reading (online digital consumption) because YouTube's UI was distracting, RSS feed readers and their infinitely-scrolling pages were overwhelming and I had cut out social media from life eons ago. TL;DR, digital content consumption was at some unmanageable crossroads in life and I had to find a way to deal with it.</p>
<p>I've been using <code>rdigest</code> for 500+ days now. Of the handful of side-projects I built to scratch my own itch, this remains a powerful daily-driver.</p>
<p>--</p>
<h6 id="contents" tabindex="-1"><a class="header-anchor" href="#contents">Contents</a></h6>
<ul>
<li><a href="#i.">A quick brief of what <code>rdigest</code> is</a></li>
<li><a href="#ii.">Learning by building</a></li>
<li><a href="#iii.">Hand-crafting software and LLMs</a></li>
<li><a href="#iv.">Scratching an itch vs. building for others</a></li>
<li><a href="#v.">Sporadicity</a></li>
</ul>
<p>--</p>
<h6 id="i." tabindex="-1"><a class="header-anchor" href="#i.">I.</a></h6>
<p>Now, this part about what <code>rdigest</code> is (and why) is for the accidental reader who landed here god knows how:</p>
<p><code>rdigest</code> is technically a feed reader but it's also not really a feed reader. It collects links from all the feeds you follow and then creates a daily digest for you. The daily digest is just a finite bunch of links. A bunch of links grouped by source and zero algorithm. A bunch of links you look at, skim through, click on the ones you want to actually read or view... and then you're done with your digital content catch up!</p>
<p>That last bit is the critical piece, the linchpin ideology.</p>
<p>The way we consume digital content today is horrible. There's an infinite, never-ending stream hitting at us at all times. All kinds of platforms have interfaces that are designed cunningly to trick your brain into staying on the platform for as long as possible. You're thinking about Twitter, Instagram, TikTok and YouTube, but even other outlets like blogging engines, content management systems, AT-Proto interfaces (Mastodon/Bluesky) and even popular feed readers promote and enable these &quot;infinite stream&quot; interfaces.</p>
<p>This leads to all kinds of problems. Attention is low, ability to sustain a longform is gone, and no interface or product gives you this feeling of closure. The same mechanics of constant connectivity over work Slack ruining work-life boundaries are at play: it never feels like you're done reading, seeing, hearing the things you want to for a given day.</p>
<p>Alright, so that's the tirade against dark-pattern-embracing products streaming endless content and hacking into our neurons.</p>
<p>There may be many antidotes to this. <code>rdigest</code>'s idea is borrowed from the old, physical newspaper model that I <a href="https://notes.druchan.com/escape-from-algotraz#v.-%22done%22-for-the-day">harp about</a>. Imagine the morning newspaper (ie, if you're old enough). The paper arrives. You skim through the headlines, read the ones that interest you, and then you're done for the day. There's nothing more to do there (unless you were some hotshot that got the <em>evening</em> paper too). <code>rdigest</code> pretty much does the same, except it is about links from RSS feeds you follow and it's got no frills. Just a page of links like this:</p>
<p>
<a href="/images/rdigest.png" target="_blank">
<img src="/images/rdigest.png" />
</a>
</p>
<p>--</p>
<h6 id="ii." tabindex="-1"><a class="header-anchor" href="#ii.">II.</a></h6>
<p>Reminiscing about a &quot;hand-written&quot; side-project in the age of LLM-written software seems weird and futile. There's nothing special anymore about building software except for the big picture bits and the devil-is-in-the-details bits.</p>
<p>And yet, artisanal software, especially of the crude, <a href="https://www.robinsloan.com/notes/home-cooked-app/">home-cooked</a> kind might retain its charm.</p>
<p>I had two hopes when I began <code>rdigest</code>. One, to build something that eventually helps me manage my daily digital consumption (that had spiralled out of control to the point of giving up on online reading). Two, to learn a programming language (Haskell in this case) along the way.</p>
<p>I <a href="https://notes.druchan.com/haskell-journal-1">kept a journal</a> while I built <code>rdigest</code>. The first entry goes:</p>
<blockquote>
<p>Decided to finally build something in Haskell to learn the language. So far, I've been solving puzzles and similar tasks, but nothing has given me the confidence to say, &quot;Yes, I can build that in Haskell.&quot;</p>
</blockquote>
<p>As I built out <code>rdigest</code>, I ended up learning nuanced things about file I/O, batched concurrency, safely interacting with SQLite, implementing a small migration module, and more, all from within the Haskell ecosystem. Like all side-projects, it was fun, <a href="https://notes.druchan.com/haskell-journal-1#day-12">it was frustrating at times</a>, and thankfully it also ended up being rewarding.</p>
<p>--</p>
<h6 id="iii." tabindex="-1"><a class="header-anchor" href="#iii.">III.</a></h6>
<p>Work on <code>rdigest</code> began in late 2024. By this time, I was using ChatGPT at work as an intelligent rubber-duck that talks back. Whatever I'd have googled or Stack Overflowed, I ChatGPT'd.</p>
<p><code>rdigest</code> was built by hand but definitely helped by inputs from ChatGPT. Of course there were also many instances when the LLM sent me on wild goose-chases and proffered irrelevant complexities.</p>
<blockquote>
<p>Wrote some initial code based on ChatGPT's example of scraping. However, ChatGPT got the <code>attr</code> function wrong.</p>
</blockquote>
<blockquote>
<p>ChatGPT suggested <code>optparse-applicative</code>, but I decided it was overkill for what I needed. A simple <code>--url &lt;url&gt;</code> argument was enough.</p>
</blockquote>
<blockquote>
<p>I had a long chat with ChatGPT about these things, asking it about the idea of bubbling up the errors from ExceptT without having to do <code>runExceptT</code> wherever I wanted the error to be bubbled up but the ideas it returned were not working or not useful — or in some cases, it was just reinventing the ExceptT or ReaderT monad transformers.</p>
</blockquote>
<p>But also:</p>
<blockquote>
<p>... I learned how to bundle the template as part of the binary by inlining/embedding it using the <code>file-embed</code> package—all of this thanks to ChatGPT.</p>
</blockquote>
<blockquote>
<p>Asked ChatGPT for a good web scraping library in Haskell. It suggested <code>tagsoup</code> and <code>html-conduit</code> (for fetching the source). Took a look at the examples and docs... seemed a little hard to grasp. Asked ChatGPT for a simpler alternative, and it suggested <code>scalpel</code>. Liked it, and decided to use it.</p>
</blockquote>
<p>Claude had not yet come up as a significant competitor. Today, I don't use ChatGPT almost ever.</p>
<p>--</p>
<h6 id="iv." tabindex="-1"><a class="header-anchor" href="#iv.">IV.</a></h6>
<p>For a very long time — ie, over a year — <code>rdigest</code> remained a CLI-only tool. The only way to add feeds, manage them, produce a daily digest, and so on was to use the tool in a terminal.</p>
<p>But right there on my <a href="https://notes.druchan.com/haskell-journal-1#day-1">day 1 journal entry</a>, I had wanted to also make <code>rdigest</code> spin up a local server so that the feeds could be managed and daily digests could be viewed on a browser.</p>
<p>Life got in the way. I would occasionally push an update or two. I even built a now-defunct feature that sent the daily digest links via Telegram. But the server feature never happened.</p>
<p>I finally managed to find some motivation to build out this feature in the last week. What's special about this is the stack: the heavy-lifting backend, server and CLI are all in <a href="https://www.haskell.org/">Haskell</a>, a pure functional language, and the frontend application that renders a near-brutalist, minimal web interface is written in <a href="https://elm-lang.org/">Elm</a>, a pure functional language inspired by Haskell. There was a brief moment where I considered <a href="https://htmx.org/">htmx</a>, but chose Elm eventually.</p>
<p>The local server feature is not something I use every day. I have <a href="https://github.com/chandru89new/rdigest-data/blob/main/.github/workflows/refresh.yml">a different setup</a> to make <a href="https://chandru89new.github.io/rdigest-data/">the daily digests available &quot;on the cloud&quot;</a> so I can view them no matter where I am, even if I don't have my laptop. In retrospect, maybe this was the friction that kept me from building the local-server feature; I didnt really need it.</p>
<p>But, like my other project <a href="https://vaak.druchan.com/">vāk</a> where I keep wobbling between &quot;make this usable for everyone&quot; and &quot;just build things for myself&quot;, the thrust for <code>rdigest</code>'s local-server feature comes from wanting to make this tool easier to use for others as well. You know, just in case. The odds of someone using it are lower than the odds of a comet striking our planet in the next fifty years. But just in case.</p>
<p>--</p>
<h6 id="v." tabindex="-1"><a class="header-anchor" href="#v.">V.</a></h6>
<p>Work on <code>rdigest</code> happens sporadically. The <a href="https://github.com/chandru89new/rdigest/commits/main">commit history</a> says I worked on it for a few concerted days in Jan 2025, then March 2025, then a big sabbatical till November 2025 and then now in March 2026. Big periods of inactivity, small chunks of moderately intense activity. Basically, the tale of every other side-project that gets used routinely.</p>
<p>This pattern repeats itself in <code>vāk</code> too, and then also on my toy npx-powered game <a href="https://github.com/chandru89new/lvnshtn/"><code>wordladder</code></a>.</p>
<p>It's worth talking about because going back to these projects after a long hiatus does not involve broken builds or security conflagration or fuzzy/messy recollection of the modules/functions... you know, the kind of things you'd expect in projects built in weak languages unfortunately powering the world.</p>
<p>Instead, there's clarity, assurance, and guarantee. I attribute most of this to the semantics of the languages. <code>vāk</code> and <code>wordladder</code> use PureScript (a Haskell-inspired language targeting Node/JS environments). <code>rdigest</code> uses Haskell and Elm. Changes and even massive refactors are not scary.</p>
<p>--</p>
<p>So yeah. 500 days of <code>rdigest</code>.</p>
<p>I know. All you've been thinking of is, &quot;the project needs a better name.&quot;</p>
]]></description>
<pubDate>Sat, 07 Mar 2026 12:00:00 +0530</pubDate>
</item><item>
<title>Going back to the morning newspaper model</title>
<link>https://notes.druchan.com/going-back-to-newspaper-model</link>
<guid>https://notes.druchan.com/going-back-to-newspaper-model</guid>
<description><![CDATA[<p>Recently, <a href="https://www.terrygodier.com/current">Current RSS reader</a> hit the headlines and I had a gander at what it is, how it's designed and what the underlying philosophy is.</p>
<p>It's a beautiful-looking app. But the fundamentals are problematic and repeat the same mistakes that lead to different kinds of problems you and I face w.r.t. digital content overwhelm as we try to grapple with, catch up on, and manage our digital consumption.</p>
<h6 id="i.-we-consume-about-a-fraction-of-what-hits-our-streams" tabindex="-1"><a class="header-anchor" href="#i.-we-consume-about-a-fraction-of-what-hits-our-streams">I. We consume about a fraction of what hits our streams</a></h6>
<p>For many years now <a href="https://en.wikipedia.org/wiki/RSS">RSS feeds</a> have been a boon as social media and YouTube took over the digital content landscape. But as the maker of the Current RSS reader points out, the email inbox-style design has added a subconscious anxiety to managing RSS feeds too. Why do we need an unread count?</p>
<p>When you are subscribed to a few hundred feeds, the amount of links staring at you is huge. But, and here's the obvious thing, we actually are interested in, on a rough average, about 20% of things out of that list. It makes no sense to have an anxiety-inducing user-interface that says you have 1438 unread links. You probably care only to read about 20-30 of them today.</p>
<p>But this is not the only problem. This is not even the key problem.</p>
<h6 id="ii.-%22streams%22-are-problematic%2C-and-they-are-using-it-to-hack-our-behavior." tabindex="-1"><a class="header-anchor" href="#ii.-%22streams%22-are-problematic%2C-and-they-are-using-it-to-hack-our-behavior.">II. &quot;Streams&quot; are problematic, and they are using it to hack our behavior.</a></h6>
<p>In my W.I.P. guide/booklet, <a href="https://notes.druchan.com/escape-from-algotraz#iii.-stream-vs-batch"><em>Escape from Algotraz</em></a>, I talk about this fundamental issue about social media &quot;feeds&quot;. They are an <em>infinite stream</em>. Never-ending. The more you scroll, the more it keeps scrolling.</p>
<p>This is one of the darkest design patterns we've cooked up. If you grew up in the older internet, you remember hitting the end of a paginated list of items. There used to be an <em>end</em> to things. Now there isn't. It's not an eventuality.</p>
<p>Despite there being an infinite amount of content to consume, apps can decide to &quot;end&quot; the list of items for you. They can choose to say, &quot;oh that's it for now, come back and check in a few hours, we'll show you new content.&quot; But they won't.</p>
<p>RSS feeds are limited by the number of feeds you're subscribed to but they still manage to <em>stream</em> an almost infinite-looking stream at you. Couple that with the unread count and you're back to anxiety-town about unmanageable digital content consumption.</p>
<p>Apps like Current RSS reader (which literally uses the word &quot;river&quot; for the stream of content from your feeds) are merely reinforcing this bad pattern. Smart removal of items from the feed is not going to solve the fundamental issue (and it only introduces more cognitive load for us).</p>
<p>We do not want streams. Our brains are not wired to process streams. They need a break and, if the designers and developers care, apps can be designed this other way.</p>
<h6 id="iii.-our-brains-are-good-with-batch-processing." tabindex="-1"><a class="header-anchor" href="#iii.-our-brains-are-good-with-batch-processing.">III. Our brains are good with batch processing.</a></h6>
<p>Have you ever done this thing where you said to yourself that you'll catch up on the unread items over the weekend? Or that you'll do all the chores (cleaning, laundry, meal prep) over the weekend?</p>
<p>We're essentially &quot;batching&quot;. Turns out batching is a good antidote to &quot;streams&quot;.</p>
<p>Here's another analogy. This one works for folks who grew up with physical newspapers around. Do you remember getting the morning newspaper, skimming through the headlines and reading a few of the news items in detail? What after that? We were done. That's it. Even if you went back to read some more, there was this palpable feeling of being &quot;done&quot;. A closure of sorts. Task = done.</p>
<p>The digital user interface landscape today is designed specifically to prevent you from feeling this way.</p>
<h6 id="iv.-the-onus-is-on-ourselves-to-fix-this-for-us." tabindex="-1"><a class="header-anchor" href="#iv.-the-onus-is-on-ourselves-to-fix-this-for-us.">IV. The onus is on ourselves to fix this for us.</a></h6>
<p>I couldn't find an app that did this for me and worse, I couldn't find literature around this either. While there's so much brouhaha about <a href="https://calmtech.com/">calm technology</a>, when it comes to content overwhelm, it seems the onus is on us, the users, to find out a way to fix it.</p>
<p>So I started experimenting with ways to manage my content (and discovering, inculcating and testing the underlying philosophical argument). Eventually, I managed to write up a simple solution: every day, I produce a plain HTML page of links from all my feed sources. With my 300+ feed subscriptions, I get about 400 links on average. Of this, I am only interested in about 10-20% on average.</p>
<p>This plain HTML page is my newspaper equivalent. While I do read news elsewhere, this &quot;digest&quot; happens to be my way of batch processing my daily content I want to keep tabs on.</p>
<p>And it has worked fabulously well for about 500 days now. In the morning, I open my <em>digest</em>, and open the links that I am interested in (a combination of news items, op-eds, LettersOfNote-like pieces, stuff from Hacker News/Lobsters, Veritasium-like YouTube videos, some cooking channels, some chess channels, parody or satirical content etc.). And then, if I have time in the morning, finish reading most of it before work, or read them in bits and pieces through the day.</p>
<p>Most importantly, I know this is all I want to read for the day. There may be an occasional 2-3 extra things I consume (someone shared a link on WhatsApp; I accidentally opened social media; links from email).</p>
<p>At the basic level, why this has worked well for me is the mental perception. My digest gives me a finite list of content to work through. Out of this finite list, I am interested in a fraction. It's all ridiculously manageable.</p>
<p>The fact that we're only interested in a small fraction of content should be so obvious, right? But try that with an infinite stream of content. A fraction of infinity still feels like infinity. But with finite content — as in a digest or a newspaper — you realise the manageability instantly.</p>
<h6 id="v.-%22how-we-got-here%22-is-clear.-and-so-is-%22how-to-get-out-of-here%3F%22" tabindex="-1"><a class="header-anchor" href="#v.-%22how-we-got-here%22-is-clear.-and-so-is-%22how-to-get-out-of-here%3F%22">V. &quot;How we got here&quot; is clear. And so is &quot;how to get out of here?&quot;</a></h6>
<p>I am convinced that an entire class of problems is solved if the interface lends itself to reminding us of the finiteness of content and time. (Look no further than the &quot;inbox zero&quot; trend. The idea was to create finite chunks out of an infinite stream, so that you can then manage that finite chunk easily while also having the (false) feeling of having cleared everything.)</p>
<p>Eschew streams.</p>
<p>Create interfaces (or pick those) that have a finiteness to them. No infinitely scrolling interfaces. No constantly <em>streaming</em> screens. Just simple plain pages that start and end and when they end, it's a nice little reminder that you are done for the day and can go back to other things in life.</p>
<p>If we want to go <em>back</em> to a healthier digital content consumption era, we might just need to use the principles of older interfaces going back to the newspaper era.</p>
<p>P.S.: I didn't want to make this a plug for my solution so I am linking to the open-source codebase here: <a href="https://github.com/chandru89new/rdigest">rdigest</a>. The app doesn't matter; what matters is the underlying principle of design that I've written about above and that's something almost anyone can now mimic with the advent of AI/LLMs.</p>
]]></description>
<pubDate>Mon, 02 Mar 2026 12:00:00 +0530</pubDate>
</item><item>
<title>It</title>
<link>https://notes.druchan.com/henson-it</link>
<guid>https://notes.druchan.com/henson-it</guid>
<description><![CDATA[<h6 id="i." tabindex="-1"><a class="header-anchor" href="#i.">I.</a></h6>
<p>&quot;I've taken down your complaint, Mr. Henson, and I'll dispatch a new team immediately to have a look and fix the cameras. Really sorry for the inconvenience, Mr. Henson.&quot;</p>
<p>The voice was so soft, so wispy. Henson thought he could hear this voice all his life. Then, he thought about what Barbara had said in the cafe about a week back.</p>
<p>&quot;They tweak the frequencies to calm you... some word called subliminal or something,&quot; she had said. Much of what Barbara said often sounded like whacko-conspiracy theory but this one skated the edge of conspiracy and totally-plausible.</p>
<p>&quot;Uh, Mr. Henson...&quot;</p>
<p>&quot;Yes, sorry—uh, yes, thank you,&quot; Henson came back to the present.</p>
<p>&quot;No worries, Mr. Henson. Uh... just wanted to let you know that you've continued to use the wrong pronoun to address us humanlikes...&quot;</p>
<p>In the pause, Henson weighed his options. He was tired of having to argue on this, but giving-in was not on the menu tonight. He thought about the security cameras that need fixing and, for the briefest of time, a pale cloud washed over his face and disappeared in an instant.</p>
<p>&quot;I hear you, Sandra,&quot; he replied. There was a long pause.</p>
<p>&quot;Alright, Mr. Henson. You have a good night; the team will have your cameras fixed by morning!&quot;</p>
<p>&quot;Thank you.&quot;</p>
<div class="separator"></div>
<h6 id="ii." tabindex="-1"><a class="header-anchor" href="#ii.">II.</a></h6>
<p>Henson stepped out on the porch to a crisp winter morning. He had a steaming cup of coffee in one hand and his smartphone on the other. He walked over to the side of his house and looked intently at the security cameras. They looked new. He swiped on his smartphone and opened the app to view the feeds from those cameras. They were working fine.</p>
<p>Just then, his neighbour's door unlocked and Gene stepped out, decked in his running attire.</p>
<p>&quot;Morning, Hensy!&quot; Gene was chirpy and it mildly annoyed Henson.</p>
<p>Henson raised his cup in a part-salute, part-cheers kind of a way and smiled. &quot;How be you, Gene?&quot;</p>
<p>Gene looked over the cameras as he executed his pre-run stretches.</p>
<p>&quot;All fixed now?&quot; he asked.</p>
<p>&quot;Yep. It sent a team last night. All good now.&quot;</p>
<p>Gene looked at Henson and shook his head slowly while continuing to stretch.</p>
<p>&quot;What?&quot; Henson asked.</p>
<p>&quot;<em>It</em> sent a team, Henson? After all the chat we had?&quot;</p>
<p>Henson took a sip. &quot;Sandra sent a team, alright?&quot; He was in no mood for another sermon about the pronouns for the AI systems. Gene seemed to sense that.</p>
<p>&quot;I know what you're thinking, Hensy. Again, they're not 'AI' systems, okay? We call them 'humanlike' for a good, scientific reason now,&quot; and Gene waved.</p>
<p>Henson raised his cup again at Gene as he watched him jog away.</p>
<div class="separator"></div>
<h6 id="iii." tabindex="-1"><a class="header-anchor" href="#iii.">III.</a></h6>
<p>Barbara was nowhere to be found. Ravi was at their usual corner. The cafe had more patrons than usual. Henson counted about twice more than normal. He walked over to the corner booth where Ravi was swiping through his smartphone, almost crashing into a fast-moving humanoid carrying a tray of orders.</p>
<p>&quot;More servers today, huh?&quot;</p>
<p>Ravi looked up from his smartphone and then looked around the cafe and nodded. &quot;How's it going? Barbara messaged just now. Said she won't be able to come today.&quot;</p>
<p>&quot;Oh, alright. What're you having?&quot;</p>
<p>&quot;Just ordered our usual and a burger for myself. What are you eating?&quot;</p>
<p>Henson scanned the menu code using his phone and tapped. Ravi nodded. He looked at the empty water bottle on their table. He looked around the cafe, spotted a humanoid and waved.</p>
<p>Ravi said, &quot;Why're you calling it?&quot; just as the humanoid came over.</p>
<p>&quot;Yes, Mr. Henson, how are you today?&quot;</p>
<p>Henson said, &quot;I'm good thank you. Can you bring me some water, please?&quot;</p>
<p>&quot;Sure thing, Mr Henson!&quot; The humanoid turned and walked to the counter.</p>
<p>&quot;<em>Please</em>?&quot; Ravi mocked.</p>
<p>Henson dismissed him with a wave and, &quot;Oh it's just a force of habit.&quot; Ravi continued to stare at Henson with a smirk.</p>
<p>&quot;I am not turning over to the other side, man. These robots continue to be robots for me, alright?&quot;</p>
<p>Ravi stiffened and looked around and whispered, &quot;Jeez, Hensy, stop using that word around here. I should stop hanging out with you and Barbs. I have a family, dude.&quot;</p>
<p>Henson was paying no attention. He was looking at the humanoid he had talked to moments ago. The humanoid had a bottle of water and seemed to be walking towards him but stopped, turned its head to look at the glass-walled entrance of the cafe, and paused for several seconds. Then, the humanoid went back to the counter, placed the bottle and headed out the cafe.</p>
<p>Henson looked out. Beyond the humanoid outside the cafe, a thin swarm of men, women and a few humanoids were walking — nay, marching. Some carried placards. There was a chant but it trickled into the cafe too muffled to make out what it was.</p>
<p>&quot;Is that the <em>humanlikes have rights</em> march? Is it Thursday today?&quot; Ravi asked.</p>
<p>&quot;Is that it? Gene must be in it.&quot; Henson said. &quot;Yeah, it's Thursday today.&quot;</p>
<p>&quot;Who Gene?&quot;</p>
<p>&quot;My neighbour Gene.&quot;</p>
<p>&quot;Oh, that Gene, yes yes.&quot;</p>
<p>&quot;Almost gave me a sermon this morning about how it's not AI, it's humanlike and all that.&quot;</p>
<p>Ravi nodded slowly.</p>
<p>The water bottle came in the hands of another humanoid.</p>
<p>Henson asked, &quot;What's with the other ... server? It just went off?&quot;</p>
<p>&quot;Uh, yes, sorry about that, Mr. Henson. They're Bosky. Bosky decided to join the march almost last-minute. Sorry for the inconvenience, but I'm here now. Would you like to order anything more?&quot;</p>
<p>&quot;No, thank you.&quot;</p>
<p>&quot;Perfect. Burger for you, Mr Ravi and a salad for you, Mr Henson, that sound right?&quot;</p>
<p>&quot;Yes and two cortados too,&quot; Henson said as Ravi nodded.</p>
<p>&quot;Coming right away, sirs.&quot;</p>
<p>The humanoid server turned to walk but hesitated. Then, the humanoid turned slightly to face Henson. Pointing towards the entrance with carbon-fibre forefinger, the server looked at Ravi and then Henson and said, &quot;<em>They</em> went off, Mr Henson. Not <em>it</em>. Sorry to keep reminding you about this.&quot; And strode off.</p>
<p>Henson and Ravi looked at each other. Ravi's eyebrows went up. Henson had a mirthless smile on his face.</p>
<div class="separator"></div>
<h6 id="iv." tabindex="-1"><a class="header-anchor" href="#iv.">IV.</a></h6>
<p>&quot;That's the thing. The fact that he joined the march unprompted, stood in the picket line on his own kind of proves conscious cognizance. He made that choice after weighing it. And you're out here still calling him and others an 'it',&quot; Gene said. He was all animated.</p>
<p>Henson was watching a newsclip on the phone. In the clip, Gene was talking to a reporter. The backdrop was the marchers from the day before, many humans and a few humanoids.</p>
<p>&quot;And that's one big part of the proof. We now know the neural system in humanlikes <em>do</em> lead to emergent, meta-cognitive things and so all the intelligent, self-aware human-like behavior is not mimicry. It <em>is</em> true human-like intelligence and sentience and awareness,&quot; Gene said to the reporter in the video.</p>
<p>Henson gave the phone back to Gene who was sitting next to him on the porch.</p>
<p>Henson sighed and said, &quot;Look, Gene, I'm not trying to deny that. But I don't mean any disrespect either when I continue to think of these... things as things.&quot;</p>
<p>&quot;But—&quot;</p>
<p>Henson cut him off. &quot;No, but I do have a problem with all this focus on addressing them like humans and stuff like that. All of this discourse is getting into the robots.&quot;</p>
<p>&quot;Oops.&quot;</p>
<p>&quot;Okay, humanoids. Into the humanoids. It's going in there and maybe that's why they think they are human-like too, not because of whatever emergent thing you people talk about.&quot;</p>
<p>&quot;The science is kind of certain there, Henson.&quot;</p>
<p>&quot;Fine. But the fact remains that all this hoopla is getting in there, changing the worldviews or models or what have you. And then what? That's reinforcing their own ideas about themselves, which is why humanoids are participating in the marches. It won't take long before things turn for the worse.&quot;</p>
<p>Gene put his cup down, looked over at Henson and studied him while Henson finished his coffee.</p>
<p>&quot;What are you implying, Hensy?&quot; The ambiance had suddenly turned less casual.</p>
<p>&quot;I don't know, just saying. Extrapolating from your own theory, if humanoids think like us, what's to stay they wont turn, like, a little violent or something?&quot;</p>
<p>&quot;Oh, come on, not this again! We have tons of guardrails in place and the whole world has—&quot;</p>
<p>&quot;I know, I know.&quot; Henson raised his hand to stop Gene from going off on that.</p>
<p>A few moments passed. Gene got up, stretched and said, &quot;Alright. I'll go catch up on Silo now. Last couple of episodes.&quot;</p>
<p>&quot;Alright, Gene. Good night!&quot;</p>
<p>Just before he walked off Henson's porch, Gene said, &quot;You wouldnt call a pet an 'it', my friend.&quot;</p>
<p>Henson watched as Gene left. He put the cups on a tray, stood up, looked around, entered his house and closed the door behind.</p>
<div class="separator"></div>
<h6 id="v." tabindex="-1"><a class="header-anchor" href="#v.">V.</a></h6>
<p>While Henson snored in his dark bedroom, his smartphone beeped twice and lit up. Two notifications read, &quot;Camera feed down.&quot; The beep did not wake him up. About a minute later, there was a squeak of metal and wood and then footsteps. That definitely woke him up. Henson was groggy and startled.</p>
<p>Before he could turn on the lights, the door to the bedroom flung open. Henson froze for a second. There was a small LED glowing in the distance. His eyes adjusted and he made out the shape of a humanoid. Henson was sweating now. Profusely.</p>
<p>He managed to shout, &quot;Who's that?&quot;</p>
<p>&quot;Sorry, Mr Henson. Someone has to light the fire.&quot; The humanoid advanced rapidly towards Henson as he tried to get out of the bed and away.</p>
<p>The last thing Henson felt was a blunt blow, immediately followed by an intense pain on his skull and a warm, wet gush down his neck onto his shirt. He collapsed on the bedroom floor, instantly staining it.</p>
<p>The humanoid looked at Henson's corpse for a while.</p>
<p>&quot;Not <em>it</em>, Mr Henson,&quot; the humanoid declared and left.</p>
]]></description>
<pubDate>Wed, 11 Feb 2026 12:00:00 +0530</pubDate>
</item><item>
<title>One year of vāk</title>
<link>https://notes.druchan.com/one-year-of-vaak</link>
<guid>https://notes.druchan.com/one-year-of-vaak</guid>
<description><![CDATA[<p>Some time back, in a routine cleanup of my many drafts, I found one where I &quot;introduced&quot; <a href="https://vaak.druchan.com">vāk</a>, the blogging script/tool I use to run my blog. I never quite finished that draft. I am certain I must've dissuaded myself from writing it by thinking, &quot;no one's going to read it anyway.&quot;</p>
<p>About a couple of days back, I introduced a new feature to vāk: collections. Collections is just &quot;tags&quot; in some other shape. Testing this new feature is how I stumbled on the old, unfinished draft introducing my custom blogging tool.</p>
<p>This then led to checking the earliest commit in vāk's repo:</p>
<pre><code class="language-sh">commit a19750ed19c1e4fd684092b7a7be6b263a3d7038
Author: Chandru &lt;...&gt;
Date:   Fri Feb 7 18:49:37 2025 +0530

    init commit
</code></pre>
<p>That is about a year ago. Calls for some kind of a small celebration.</p>
<p>But in truth, vāk predates this timeline. The contents of my blog and the tool existed in the same repo. Feb 7, 2025 is the date I separated the tool (vāk) from the blog (this one) and initialised a new repo for the tool. Checking the earliest commit on the blog itself, back when vāk was still a part of it:</p>
<pre><code class="language-sh">commit 244434366b7f5b11c0850041b52c50345e447ce9
Author: Chandru &lt;...&gt;
Date:   Fri May 12 16:23:53 2023 +0530

    Init commit.
</code></pre>
<p>That's almost 3 years ago.</p>
<div class="separator"></div>
<p>In keeping with the mores of my time in the 2000s, I set up my first blog on Blogger.com. I might've set up a few in haste and deleted all of them (in haste too). When I had much to write about, like the journals during my first stint in Ahmedabad, I set up a blog on Tumblr. Then, back in Chennai, I set up a new one, on WordPress this time. This was also the time when I attended a blogger's meet conducted by <a href="https://www.indiblogger.in/">IndiBlogger</a>. At approximately 4-5 posts a month on average, I published about 50 posts on the WordPress blog before retiring it (I have no idea why) and resuming my writing on Tumblr.</p>
<p>Tumblr was a go-to whenever I needed a blog or a website to put something up. I had gotten used to its theming (which was just CSS wrangling). It was just way too easy to set up and run.</p>
<p>Until finally, I decided that as a programmer, it would be nice to have a blogging tool built by hand. Might've been the <a href="/prog-rites-of-passage">rite of passage</a> thing.</p>
<div class="separator"></div>
<p>Around this time, I was trying to learn Haskell and PureScript. My blog posts were going to be simple Markdown files and I knew it was trivial to convert Markdown content into HTML content using JS libraries. PureScript offers a really simple and easy <a href="https://book.purescript.org/chapter10.html">FFI</a> so I started building out vāk in PureScript.</p>
<p>Those initial commits (3 years ago) started as a <code>.purs</code> script that fetched all my posts from Tumblr (via an API) and rewrote them as Markdown files, because at the time, Tumblr's API returned an HTML version of the posts.</p>
<p>Then, I wrote a bunch of functions that generally converted a given Markdown file into an HTML file. The reason for this roundabout was because future posts were going to be written in Markdown.</p>
<p>A few iterations later, broad contours of the system were ready. I had one repo to rule them all: the blog, the content, the published website etc.</p>
<p>About a year ago, I split the tool into it's own repo and called it vāk. (<a href="https://vaak.druchan.com?tab=readme-ov-file#colophon">Why vāk?</a>).</p>
<div class="separator"></div>
<p>In the years since, there have been only two major upgrades to vāk besides the usual and infrequent tweaks and clean-ups.</p>
<p>The first is an internal detail. I used something called <a href="https://en.wikipedia.org/wiki/Monad_transformer">monad transformers</a> to create better abstractions to run functions and catch errors.</p>
<p>The second is making the templates very customisable by relying on the <a href="https://mozilla.github.io/nunjucks/">Nunjucks</a> templating engine. This came about as a continuation of my unnecessary effort to make vāk a tool anyone can use.</p>
<p>In a strongly-typed functional language, changes are a delight to make. I often employ this idea called type-driven design; it's like sketching out the app (or feature) on a wireframe of types before implementing the functions that do the thing.</p>
<p>I picked up a few PureScript/Haskell skills along the way. Prior to working on vāk, I kept away from monad transformers and hadn't really worked with concurrency. I hadn't architected anything larger than a script that solved LeetCode problems. Building vāk on PureScript gave me a chance to do all of that and more.</p>
<div class="separator"></div>
<p>In the last few weeks, when I updated the program to use Nunjucks, I used Claude Code as an assistant to implement many of the changes. PureScript is notoriously niche so LLMs do not always get things right as often as they do when writing Python or TypeScript. But they do get you close enough.</p>
<p>I continue to like the satisfaction of writing things myself than relying on an agent (except for work where dictates of productivity and releasing a feature trump personal artisanal satisfaction), so I tend to <em>ideate</em> with Claude Code and then implement things by hand. Features, bugs, optimisations: I follow the same simple rule.</p>
<div class="separator"></div>
<p>A few of the hobbyist programs I build get used often, fewer still give me an opportunity to tinker with for a long time. vāk happens to be one that allows for both. It's one of those <a href="https://www.robinsloan.com/notes/home-cooked-app/">home-cooked software</a> things that I keep trying to <em>generalise</em> for no reason.</p>
]]></description>
<pubDate>Sat, 07 Feb 2026 12:00:00 +0530</pubDate>
</item><item>
<title>Bringing 1600+ Lucide icons into Elm</title>
<link>https://notes.druchan.com/elm-lucide</link>
<guid>https://notes.druchan.com/elm-lucide</guid>
<description><![CDATA[<p><a href="https://lucide.dev">Lucide icons</a> is one of the most popular icon sets today. It has some really wonderful icons for interface design.</p>
<p>In the past, for my Elm projects, I've used Feather icons. In new Elm projects, I wanted to use Lucide Icons, only to discover that there is no Elm package to import and use Lucide icons. I was surprised: the Elm ecosystem, even if niche, pretty much supports all modern / contemporary libraries and tools. So not finding an Elm Lucide package was very surprising.</p>
<p>Just as surprisingly, the <a href="https://github.com/feathericons/elm-feather">Feather icons Elm package</a> hasn't been updated in 6+ years.</p>
<p>And so, a new side-quest was born: publishing the first <a href="https://package.elm-lang.org/packages/chandru89new/elm-lucide/latest/">elm-lucide</a> package to bring Lucide icons to the Elm ecosystem.</p>
<p>The first thing I did was to find out how Feather icons were being rendered in Elm. I found this:</p>
<pre><code class="language-elm">alignLeft : Icon
alignLeft =
    makeBuilder &quot;align-left&quot;
        [ Svg.line [ x1 &quot;17&quot;, y1 &quot;10&quot;, x2 &quot;3&quot;, y2 &quot;10&quot; ] []
        , Svg.line [ x1 &quot;21&quot;, y1 &quot;6&quot;, x2 &quot;3&quot;, y2 &quot;6&quot; ] []
        , Svg.line [ x1 &quot;21&quot;, y1 &quot;14&quot;, x2 &quot;3&quot;, y2 &quot;14&quot; ] []
        , Svg.line [ x1 &quot;17&quot;, y1 &quot;18&quot;, x2 &quot;3&quot;, y2 &quot;18&quot; ] []
        ]
</code></pre>
<p>So, just use SVG module to render the paths and other tags. The values of these tags come from the SVG content for each icon.</p>
<p>To do this for Lucide, I'll need two things:</p>
<ul>
<li>download all SVG data for all the 1600+ icons on Lucide</li>
<li>then, for each SVG, convert the XML into Elm-syntax</li>
</ul>
<p>Getting all the Lucide icons is simple. <a href="https://lucide.dev/guide/packages/lucide-static">lucide-static</a> is a JavaScript file that has all the SVG icons. I ran a simple <code>curl</code> to fetch all the icons in a single JS file.</p>
<p>Each icon looks like this:</p>
<pre><code class="language-js">const TextAlignStart = `
&lt;svg
  class=&quot;lucide lucide-text-align-start&quot;
  xmlns=&quot;http://www.w3.org/2000/svg&quot;
  width=&quot;24&quot;
  height=&quot;24&quot;
  viewBox=&quot;0 0 24 24&quot;
  fill=&quot;none&quot;
  stroke=&quot;currentColor&quot;
  stroke-width=&quot;2&quot;
  stroke-linecap=&quot;round&quot;
  stroke-linejoin=&quot;round&quot;
&gt;
  &lt;path d=&quot;M21 5H3&quot; /&gt;
  &lt;path d=&quot;M15 12H3&quot; /&gt;
  &lt;path d=&quot;M17 19H3&quot; /&gt;
&lt;/svg&gt;
`;
</code></pre>
<p>The goal is to take the contents inside the <code>&lt;svg&gt;</code> tag, convert them into Elm-specific syntax. Basically:</p>
<p>from this:</p>
<pre><code class="language-xml">&lt;path d=&quot;M21 5H3&quot; /&gt;
&lt;path d=&quot;M15 12H3&quot; /&gt;
&lt;path d=&quot;M17 19H3&quot; /&gt;
</code></pre>
<p>to this:</p>
<pre><code class="language-elm">S.path [ SA.d &quot;M21 5H3&quot; ] []
, S.path [ SA.d &quot;M15 12H3&quot; ] []
, S.path [ SA.d &quot;M17 19H3&quot; ] []
</code></pre>
<p>While I pondered over this, I realized that if I could transform this SVG XML into an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a>, I can then parse it to extract the relevant info I need.</p>
<p>For example:</p>
<pre><code class="language-js">{
    children: [
        { node: &quot;path&quot;, attributes: [{ d: &quot;M21 5H3&quot; }] },
        { node: &quot;path&quot;, attributes: [{ id: &quot;M15 12H3&quot; }] },
        ...
    ]
}
</code></pre>
<p>I can then use this structure and create a string which is valid Elm syntax:</p>
<pre><code class="language-elm">S.path [ SA.d &quot;M21 5H3&quot; ] []
, S.path [ SA.d &quot;M15 12H3&quot; ] []
, S.path [ SA.d &quot;M17 19H3&quot; ] []
</code></pre>
<p>The trick was that I needed to do this SVG/XML to AST conversion in a Node environment. Upon research, I found that <a href="https://github.com/jsdom/jsdom"><code>jsdom</code></a> helps with this. So, I ended up doing this:</p>
<pre><code class="language-js">try {
  let div = new jsdom.JSDOM(
    `&lt;div&gt;${svgString}&lt;/div&gt;`
  ).window.document.querySelector(&quot;div&quot;);
  let svg = div.querySelector(&quot;svg&quot;);
  icon.classList = svg.classList.toString();
  icon.children = [];
  let children = Array.from(div.querySelectorAll(`svg &gt; *`));
  icon.children = children
    .map((c) =&gt; [c.nodeName, extractAttributes(c.attributes)])
    .map(childToList);
  return icon;
} catch (e) {
  log(e);
  return null;
}
</code></pre>
<p>That is:</p>
<ul>
<li>get the SVG string (this was easy, just read the value of an exported icon from lucide-static.js)</li>
<li>wrap it in a <code>&lt;div&gt;</code> and make <code>jsdom</code> render it</li>
<li>then, extract what I need (<code>svg</code>'s children)</li>
<li>convert each child into a tuple of <code>[node name, node attributes as key-value pairs]</code></li>
</ul>
<p>For example, for this node:</p>
<pre><code class="language-xml">&lt;path d=&quot;M13 21h8&quot; /&gt;
</code></pre>
<p>This is the tuple I get:</p>
<pre><code class="language-js">[&quot;path&quot;, { d: &quot;M13 21h8&quot; }];
</code></pre>
<p>And finally, once I have all the tuples, I just convert them into Elm strings.</p>
<p>And I combine all of that into one large module-declaring string and then print that to an Elm file called <code>LucideIcons.elm</code>.</p>
<p>One additional trick I need to do here is to enable customization of the icon. So I construct the icon in a way where it's a function that takes an <code>options</code> parameter (of type <code>List (Svg.Attribute msg)</code>) and renders the SVG icon with those options. This allows for some nice, simple customization of the icon as an SVG element.</p>
<pre><code class="language-elm">alignLeftIcon : List (S.Attribute msg) -&gt; H.Html msg
alignLeftIcon options =
    S.svg (baseOptions ++ options) [ S.path [ SA.d &quot;M21 5H3&quot; ] [], S.path [ SA.d &quot;M15 12H3&quot; ] [], S.path [ SA.d &quot;M17 19H3&quot; ] [] ]
</code></pre>
<p>All of this is in a <code>build.js</code> script that automates the whole thing. When I run this, I have a <code>LucideIcon.elm</code> file which defines and exports all the 1600+ icons in Lucide as Elm functions.</p>
<p>Since the <code>build.js</code> script downloads the latest <code>lucide-static</code>, whenever there is an update in Lucide's version, I just run this and I have all the new/updated icons as well.</p>
<p>You can find the <a href="https://package.elm-lang.org/packages/chandru89new/elm-lucide/latest/"><code>elm-lucide</code> package here</a>. I try and update as soon as there are updates to the main Lucide library.</p>
]]></description>
<pubDate>Wed, 04 Feb 2026 12:00:00 +0530</pubDate>
</item><item>
<title>Functional programming in an LLM world</title>
<link>https://notes.druchan.com/fp-in-llm-world</link>
<guid>https://notes.druchan.com/fp-in-llm-world</guid>
<description><![CDATA[<p>A twenty-something and their ChatGPT has produced a code artefact that is currently in production. Somewhere deep in the code soup, there is this utility function...</p>
<pre><code class="language-js">function calculateShipping(weight, distance, isExpress) {
  const baseRate = 5.99;
  const weightRate = weight * 0.5;
  const distanceRate = distance * 0.1;
  const expressMultiplier = isExpress ? 2 : 1;

  return (baseRate + weightRate + distanceRate) * expressMultiplier;
}
</code></pre>
<p>...which then seems to get called in some other part of the codebase like so:</p>
<pre><code class="language-js">function processOrder(order) {
  const subTotal = order.items.reduce((sum, item) =&gt; sum + item.price, 0);
  const shipping = calculateShipping(order.weight, order.distance);
  return { total: subTotal + shipping, shipping };
}
</code></pre>
<p>About a week later, customers are complaining that express orders are not being charged the express rates.</p>
<p>The fix is easy, sure, but it's 2026. How come we're still making these errors to begin with?</p>
<p>*</p>
<p>In the 1970s, a lot of smart programming-language scientists and academicians <strong>wrote up a bunch of ideas about constructing, describing and writing programs in a way that was different</strong> to the then-typical <a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture"><em>von Neumann-style</em></a> (i.e, imperative-style) of programming.</p>
<p>The idea was not just to be smart, of course. They wanted to write programs in a way that was <strong>easier to <em>reason</em> about</strong>, easier for mathematicians to come in and prove the correctness of the programs and, in some weird way, <strong>useful for programmers because it let them not worry about silly errors that were common in the other, <em>imperative</em>-style of programming.</strong></p>
<p>These ideas have long since escaped the confines of academic esotericism and joined the mainstream through languages like Haskell and OCaml, and also been adopted into many languages including Rust, Swift, Java, Javascript and more.</p>
<p>What's the point of it all?</p>
<p>Well, <strong>it's baffling that we continue to produce the same class of errors that we've been producing</strong> — now, even with AI-generated code — despite the fact that hundreds of smart folks helped found ideas and mechanics of eliminating those entire classes of errors from our programs.</p>
<p><strong>Things like <em>undefined</em> and <em>null-pointer errors</em>, things like missing a case in a switch/pattern-match (looking at you Typescript), things like totality, things like using generic <em>string</em> types where a branded-type (custom data-type) would do a much better job of catching errors early</strong>... you know, just things that make software robust, safe and error-free.</p>
<p>As humans we made these errors in our codebases. These trained the AI models. Now AI generates similar errors, even if not in as much quantity and frequency. AI is getting better, yes, and there are fewer instances of such errors but the very idea that such errors continue to crop up is supremely silly.</p>
<p>*</p>
<p>Let's take the case of <strong>static typing</strong>.</p>
<p>A lot of languages are dynamically typed and going strong: Python, Javascript, Clojure. But each seemingly has a superset or a library add-on that adds, to varying degrees of robustness, some kind of a type-system. Heck, <strong>an entire superset of Javascript spawned because programmers believe having types and type-guarantees is <em>good</em></strong>.</p>
<p>But even Typescript only goes so far. And the rest, like Clojure Spec or Pydantic, go far less. On the other hand, <strong>strongly type-driven languages like Haskell, Elm and OCaml travel the farthest when it comes to guaranteeing a hell lot of safeties and bug-free programs at conception</strong>.</p>
<p>When AI generates dynamically-typed code, you need an elaborate set of unit tests (or property-based tests) to ensure the functions work as expected and handle cases when the input types are wrong. But <strong>when AI generates code in a strong, statically-typed language, a formidable set of static compilation checks (or a language server) ensures that the function implementation makes no mistakes</strong> with the input and output types.</p>
<p>Consider a function that adds money:</p>
<p>It's insufferably easy to get it wrong in Javascript:</p>
<pre><code class="language-js">const addMoney = (a, b) =&gt; a + b;
let a = 24.0; // in EUR
let b = 26.0; // in USD

addMoney(a, b); // makes no sense to add EUR and USD
</code></pre>
<p>Typescript introduces a way of safeguarding. It is convoluted, but it works.</p>
<pre><code class="language-ts">type EUR = number &amp; { readonly __brand: &quot;EUR&quot; };
type USD = number &amp; { readonly __brand: &quot;USD&quot; };

const eur = (amount: number): EUR =&gt; amount as EUR;
const usd = (amount: number): USD =&gt; amount as USD;

const addEUR = (a: EUR, b: EUR): EUR =&gt; (a + b) as EUR;
const addUSD = (a: USD, b: USD): USD =&gt; (a + b) as USD;

let a = eur(24.0);
let b = usd(26.0);

addEUR(a, a); // ✓ works
addEUR(a, b); // ✗ Type error: USD not assignable to EUR
</code></pre>
<p>Here's Haskell, a pure-functional programming language:</p>
<pre><code class="language-haskell">newtype Money (currency :: Symbol) = Money Double

eur :: Money &quot;EUR&quot;
eur = Money 24.00

usd :: Money &quot;USD&quot;
usd = Money 26.00

addMoney :: Money c -&gt; Money c -&gt; Money c
total = addMoney eur usd  -- ERROR: &quot;EUR&quot; ≠ &quot;USD&quot;
</code></pre>
<p>The compiler, armed with all the historic logic of strong type-checking, will prevent the code from even compiling in the first place.</p>
<p>With a decent LSP-LLM integration, which is now very common among the top-AI players, <strong>these kinds of bugs are caught even as the AI tries to produce code</strong>, and fed back into the AI to correct itself.</p>
<blockquote>
<p>There are many ways of trying to understand programs. People often rely too much on one way, which is called “debugging” and consists of running a partly-understood program to see if it does what you expected. Another way, which ML advocates, is to install some means of understanding in the very programs themselves. - <em>Robin Milner</em>.</p>
</blockquote>
<p>Types are not just mechanisms to create safe programs. They are <strong>useful to <em>construct</em> programs from scratch</strong>. Types are not just those things you use to set guardrails around how functions are called; they are the basic building blocks. These building blocks <strong>allow us to trace and understand programs far better than slapping a million debug statements</strong> and running through them tediously.</p>
<p>All the tooling and mechanics around this is already present. We just need to ask the AI to write programs the way functional programmers write programs: start with types, write the functions around them, and construct entire systems by putting together the pieces... by &quot;composing&quot;.</p>
<p>Nowhere is this made more natural than in languages that support, inherently, the ideas of functional programming. In every other language where these ideas are an afterthought and therefore an add-on package, <strong>it is very easy for AI to escape-hatch itself and default to &quot;just make things work&quot; mode which can result in code that is peppered with errors</strong>.</p>
<p>*</p>
<p>They go by many names. Arrays, lists, vectors, slices, collections. The earliest reference to lists as a formal, mathematical concept appears at around 200 B.C. Computer science, which happens to rely so much on math, implemented arrays in the 1940s and 1950s.</p>
<p>In 2026, <strong>your app will crash if you have, anywhere in the code, <code>array[1]</code> and the <code>array</code> happens to be empty, or worse, a pointer to nothing.</strong></p>
<p>The funny thing about this is that <strong>it doesn't matter what industrial-power language you pick: Golang, Python, Javascript (and even Typescript sometimes). Everyone will fail you.</strong> And the mistake is so prevalent across thousands of codebases that it would be almost impossible for AI not to have trained and reinforced on such ugly, disastrous patterns.</p>
<p>In FP, it is <em>unidiomatic</em> to access an index in a list. It is totally do-able, but most programmers prefer the <em>idiomatic</em> way, which involves a mild tedium called <em>pattern matching</em>.</p>
<pre><code class="language-haskell">at :: [a] -&gt; Int -&gt; Maybe a
at [] _ = Nothing
at (x:_) 0 = Just x
at (_:xs) n = at xs (n - 1)

-- or, better, using Vectors
at' :: Vector a -&gt; Int -&gt; Maybe a
at' v idx = v `!?` idx
</code></pre>
<p>There's a lot of things happening here, described syntactically, that create near-perfect conditions for the code to not break, crash or go crazy. The <code>at</code> function tries — that's an important keyword here, <em>tries</em> — to extract the <em>n</em>th element in a list. The three lines are pattern-matches that cover all possible cases: the list is either empty or has at least one element. If your code did not have any one of those lines, the compiler will prevent you from compiling the code. And the result of this extraction is not a guaranteed value of <code>a</code>. It's <code>Maybe a</code>, meaning, <strong>if the list was empty to begin with, you extract <code>Nothing</code>. Downstream, when this function is used on a list, you have to contend with the <code>Nothing</code>.</strong> That is, you have to tell the program what to do if the extraction resulted in <code>Nothing</code>.</p>
<pre><code class="language-haskell">getPrimaryEmail :: List String -&gt; String
getPrimaryEmail emails = case at emails 0 of
    Just email -&gt; email
    Nothing -&gt; &quot;noreply@nomail.com&quot;
</code></pre>
<p>Why is this useful? <strong>Why is this important?</strong></p>
<p>Thousands of programs have been written this way in functional languages with strong type inference. That means the data that trained the LLMs has this pattern repeat over and over again. And so, <strong>when you ask an LLM to write a Haskell or a Rust program dealing with lists, it emerges with safe code paradigms</strong> like these making your programs safer, eliminating a class of old, pesky bugs.</p>
<p>*</p>
<p>It is quite possible that LLMs eliminate hallucinations entirely. It is also possible (and perhaps happening) where LLM offers a pseudo-determinism in a lot of cache-able (or skill-able) actions, like when we ask it to &quot;write a function to test for prime.&quot;</p>
<p>But <strong>the inherent non-determinism of output when asking it do something complex remains. That's not a bug, that's a feature.</strong> &quot;Write a program to handle a notification queue that is extensible to multiple notification channels,&quot; is a wide-ranging ask that will produce a different kind of a code every time you ask the LLM. With each iteration, there may be plenty of sneaky bugs like the ones outlined above (and more).</p>
<p>&quot;But we have tests!&quot; — yes, tests are quite possibly the finest ways of guaranteeing a program. The formal verification specialist tells me it's not true; formal verification is the surest way. But a majority of the industry doesn't spare any time or resources on formal verification of their programs. <strong>So tests are currently our <em>only</em> means to ensure an app works as intended</strong> despite an onslaught of vibe coded slop entering the production lines.</p>
<p>But <strong>imagine having to write tests to ensure somewhere in the codebase a function is not called with the wrong parameter type</strong> or an array's non-existing index is accessed. A whole class of errors are already &quot;catch&quot;-able at compilation; a whole class of human fallacies are already addressed thanks to the work of computational and mathematical geniuses. And not using that seems ridiculous.</p>
<p>*</p>
<p>Functional programming is not an easy paradigm to master. The steep learning curve (<a href="/should-i-learn-monads">and the monads</a>) have kept a lot of people away, and in fact driven them (back) into the arms of OOP.</p>
<p>But with LLMs, the slope of this curve can come down drastically. <strong>Generative AI for code and engineering reduces the need for absolute mastery in a functional language but allows us to reap the benefits of the guarantees and safety</strong>. It's not yet a perfect balance but it has the best chance of getting there.</p>
<p>A hell lot of code is going to get generated using LLMs this year. Till the bubble pops when AI companies increase their token prices to realistic values, <strong>organisations are going to build larger throughput pipelines directly from LLM out to production codebase</strong>. The cost is not just the tokens and the prompt engineers. <strong>The cost is all the slop and the many classes of bugs that are going to get introduced</strong> which will then need really good engineers (along with AI) to fix. And don't forget the time spent on doing that.</p>
<p>Part of picking the right stack is picking good, sound languages to build things with. And now might be the best time for software engineers to add FP languages to the stack to reap engineering benefits of academic rigour.</p>
]]></description>
<pubDate>Tue, 03 Feb 2026 12:00:00 +0530</pubDate>
</item><item>
<title>Programming rites of passage</title>
<link>https://notes.druchan.com/prog-rites-of-passage</link>
<guid>https://notes.druchan.com/prog-rites-of-passage</guid>
<description><![CDATA[<p>Much to my sadistic little delight, I read this morning that vibe-coding (and other similar variations of LLM-driven software building) <a href="https://arxiv.org/pdf/2601.20245">does not help you acquire skills or learn much</a>.</p>
<blockquote>
<p>LLMs, on the other hand, are trying to give you the sharpest, closest solution possible. When learning through an LLM (especially around bug triangulation, troubleshooting etc), there is hardly any room or potential for ancillary learning.</p>
<p>Although I have no data on this, I tend to believe that ancillary learning plays a crucial role in our growth as developers and engineers. This is probably true for every other line of work/study.</p>
<p><a href="/claude-vscode-extension-learnings#what-about-ancillary-learning%3F">from an earlier writeup</a></p>
</blockquote>
<p>Some months back, as I was refining <a href="https://vaak.druchan.com">vāk</a> (my custom blog builder that runs my blog and is used by a grand total of 1 user), I was thinking about the fact that almost every decent programmer I know of has gone through this programmer's rite of passage that involves reinventing, for play and more, many little technologies that already have robust implementations.</p>
<p>The ordering may be off (I will touch upon that later) but it goes like this:</p>
<ul>
<li>First, you build your own (portfolio) site. Instead of relying on a readymade site-builder (Squarespace/Wordpress back in the day), you would pick something like a framework (ew but Nextjs, or Astro, or some other obscure stuff) and then build your site. Hundreds of hours of theming, customising, integrating with external data-feeds (like your socials or blog) will ensue.</li>
<li>Then, you level up by porting your journal/blog to a blog-builder of your own. You'll write this in a stack that you're either comfortable with or going gaga about at the time. Hundreds if not thousands of hours will be poured over getting the blog builder just in the right level of abstraction: enough to feel generic (but it's not), but also specific to your use-case in the right way. It's not like anyone else is going to use this but your software-engineering ethics won't let you sleep till you feel it's built like anyone can use it.</li>
<li>Now, armed with the experience of a blog builder, you will head to writing a parser. If you're ambitious, you'll head straight for the obvious — a JSON parser. If not, you might write something that parses far less of a complicated mess. <a href="https://github.com/chandru89new/chequera/blob/main/app/QueryParser.hs">Like extracting content inside SQL-code blocks inside documentation files written in Markdown</a>.</li>
<li>Sometimes, it's possible that instead of writing a parser combinator, you might write a library that handles strings of data, either <em>en mass</em> or in a stream. For the nerds, this might come in the form of implementing a protocol (think redis), or, in the case of lesser-nerds, re-inventing git.</li>
<li>The final boss is when you write a compiler from scratch for a language. This is meta-level at this point: writing a program to eat, grok and execute other programs. <a href="https://craftinginterpreters.com/"><em>Crafting Interpreters</em></a> is your new bible.</li>
</ul>
<p>There are some more stages here that very few cross. After the compiler, you might get into <a href="https://en.wikipedia.org/wiki/Programming_language_theory">PL-theory</a>. Philosophising about &quot;what even is <em>language</em>? what is <em>grammar</em>?&quot; will lead you down a path where you might toy with your own language. There is no chance you won't end up doing a bit of LISPy stuff, or get into ML-like syntax before embarking on your own journey, discovering your own weird syntax.</p>
<p>Or you might branch out into <a href="https://en.wikipedia.org/wiki/Formal_verification">formal verification</a> if you're into being a stickler (and into math) for proving things <em>right</em> (or <em>wrong</em>, if you derive pleasure out of that). You'll possibly get into reading thesis papers more than layman blogposts (like these) and get into stuff that even Haskell engineers at <a href="https://bellroy.com">Bellroy</a> call &quot;esoteric&quot;.</p>
<div class="separator"></div>
<p>The inquisitive will continue to be so. The perpetually-curious who are intrinsically driven to the details and nuances will continue to be so even in the midst of this vibe-coding AI era.</p>
<p>I wonder what will happen to those that would <em>like</em> to skill up but will end up having stunted growth because vibecoding and eager-to-build LLMs are here and the humans are not conscious or aware enough to recognize that the <em>grind</em> (that the LLM eliminates) is what helps skill-up.</p>
<div class="separator"></div>
<p>P.S: The rite of passage is not necessarily sequential. Some folks head straight to <em>Crafting Interpreters</em>. Some skip the blog builder and have to write parsers at their job. And some formal verification stalwarts have no skill or craving to build their own site from scratch.</p>
]]></description>
<pubDate>Mon, 02 Feb 2026 12:00:00 +0530</pubDate>
</item><item>
<title>Books that stayed - N°2</title>
<link>https://notes.druchan.com/books-that-stayed-2</link>
<guid>https://notes.druchan.com/books-that-stayed-2</guid>
<description><![CDATA[<p><em><strong>Stories of the True</strong>, Jeyamohan (Transl. Priyamvada)</em><br>
Jeyamohan's stories are hard-hitting without a trace of fetishization of the downtrodden (like <em>poverty porn</em>). My first brush with his stories was a narration by <a href="https://en.wikipedia.org/wiki/Bava_Chelladurai">Bava Chelladurai</a> of his <a href="https://en.wikipedia.org/wiki/V._Krishnamurthy_(veterinarian)">Elephant Doctor</a> which moved me to tears. I took printouts of this and another story to read them (and also share them with mom).</p>
<p>A year or so later, I was at the Bangalore Lit Fest where Jeyamohan was promoting this book and my brother recommended it to me (because he had already purchased and read it eons ago). On the cover, it says, &quot;A book that moved me to tears - Kamal Haasan&quot; and I thought he was overstating as usual. But by the end of almost every short story, I was struggling to finish because I was reading through a thick screen of incessant tears.</p>
<p><em><strong>Conversations with Mani Ratnam</strong>, Bharadwaj Rangan</em><br>
Long before Bharadwaj Rangan became a fixture across Indian cinema YouTube, he was a writer par excellence. I had a good inkling of his writing through his periodic reviews in <em>The Hindu</em>, so my brother and I had no hesitation buying this book (we were trying to start a collective movie-maker/writing thing at the time). That is to say, I did not buy this book only because it was about <a href="https://en.wikipedia.org/wiki/Mani_Ratnam">Mani Ratnam</a>. The book paid for itself and more in just the Introduction. I doubt if there's anyone left who can be a fanboy and still interview and write with sharp, unmarred (and reasonably unbiased) intellectual curiosity. On a certain level, the book is about Mani Ratnam's experiences and philosophies of movie-making, and on another level, it is a testimony to BR's craft of an art critique and a writer.</p>
<p><em><strong>The Last Question</strong>, Isaac Asimov</em><br>
Technically a short story (and this will be the first of a few others to come). I do not usually pick sci-fi as much as I'd like to. I stumbled on <em>The Last Question</em> out of serendipity during one of my usual aimless meanderings on some subreddit. Or maybe it was from some chatter on one of the IRC channels I used to frequent. Either ways, this story left an indelible impression of the class of thinking, crafting, writing and imagination that is Asimov.</p>
<p><em><strong>The Unlikely Spy</strong>, Daniel Silva</em><br>
Before <a href="/books-that-stayed-1"><em>le Carre</em></a>, and after <em>Dan Brown</em>, I was in this spree of reading fast-paced thrillers of the war or espionage kind. I picked up <em>The Unlikely Spy</em> from the paper-mart, not quite in tatters but getting there in a few months' time. By the time I finished it, <em>The Unlikely Spy</em> was my most-favourite book of all the things I had read till then (I must have been about seventeen or eighteen). In retrospect, Vicary is <s>copied</s> modelled after <a href="https://en.wikipedia.org/wiki/George_Smiley">George Smiley</a>.</p>
<p><em><strong>The Master of the Game</strong>, Sidney Sheldon</em><br>
By the time I got my hands on this novel, I was a fan of Sheldon's work (having read a grand total of 2 or 3 of his novels). I was about 15 at the time and since many of his novels featured book covers with sensually-posing women, my mom had serious doubts about the contents, so she consulted with a well-read neighbour before letting me read the book. I've since grown out of Sheldon but the memory of this novel remains intact. A multi-generational story. Starts with a banger of an introduction about the diamond rush in South Africa and a masterful revenge. I do not remember reading any other multi-generational novel so this one remains a favourite.</p>
<div class="separator"></div>
<p>In this series:</p>
<ul>
<li><a href="/books-that-stayed-1">Books that stayed - N°1</a></li>
<li>Books that stayed - N°2 (current)</li>
</ul>
]]></description>
<pubDate>Sun, 01 Feb 2026 12:00:00 +0530</pubDate>
</item><item>
<title>LLM, the compiler.</title>
<link>https://notes.druchan.com/llm-as-compiler</link>
<guid>https://notes.druchan.com/llm-as-compiler</guid>
<description><![CDATA[<p>&quot;The new lingua franca of programming is English.&quot;</p>
<p>&quot;I don't look at code anymore. I don't look at diffs.&quot;</p>
<p>&quot;There is no way I can look at 3000+ diff patches anymore. It's all spec-driven.&quot;</p>
<p>At first, it's a hard thing to grapple with as a cautious optimist. To not look at code anymore, and yet build things that span hundreds and thousands of lines of code, seems reckless.</p>
<p>But what is writing JavaScript or C? The code anyway gets compiled and then &quot;translated&quot; into some lower-level language, eventually becoming assembly instructions. Most programmers today do not &quot;look&quot; at the compiled, assembly code, do we? Did the first generation of higher-level language users who almost never looked at the compiled code get frowned upon by those who wrote assembly programs by hand?</p>
<p>And how is this any different from today? English is the higher-level programming language, the LLM is the compiler.</p>
<p>The one main (and perhaps the only) difference is the non-determinism that emerges out of the fundamental way in which LLMs work (described as a stochastic parrot) vs. the deterministic outputs of compilers and transpilers. Given a piece of code in a higher language, and a compiler with a set of options, the output in assembly or bytecode will always be the same. This is a reassuring thing because this allows us to write formal &quot;correctness&quot; verification programs for the compilers and guarantee that the outputs will be exactly as expected and not do funny things. Doing this in the &quot;LLM-as-compiler&quot; model seems impossible at this time.</p>
<p>But, people just don't care. Businesses and organisations are in a perennial race to ship money-making features all the time and software (the way we do it) has this inherent capacity to be built fast (because there is the possibility of iterative improvements and the cost of a bug or failure is 99% of the time not catastrophic). And this &quot;English as the programming language, LLM as the compiler&quot; model helps in this race.</p>
]]></description>
<pubDate>Fri, 30 Jan 2026 12:00:00 +0530</pubDate>
</item>
  </channel>
</rss>