<script data-pm-proxy="intercept"></script><?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Vincent’s Substack]]></title><description><![CDATA[Algorithmic failures, calm code, open-source, tricks in Python and many demos. ]]></description><link>https://koaning.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!59fN!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9560f55-6113-4e71-9087-ac330a783924_400x400.jpeg</url><title>Vincent’s Substack</title><link>https://koaning.substack.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 02 Sep 2026 22:05:13 GMT</lastBuildDate><atom:link href="/__u/koaning.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Vincent]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[koaning@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[koaning@substack.com]]></itunes:email><itunes:name><![CDATA[Vincent]]></itunes:name></itunes:owner><itunes:author><![CDATA[Vincent]]></itunes:author><googleplay:owner><![CDATA[koaning@substack.com]]></googleplay:owner><googleplay:email><![CDATA[koaning@substack.com]]></googleplay:email><googleplay:author><![CDATA[Vincent]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[What is Calmcode now? ]]></title><description><![CDATA[It's still going, but so much has changed.]]></description><link>https://koaning.substack.com/p/what-is-calmcode-now</link><guid isPermaLink="false">https://koaning.substack.com/p/what-is-calmcode-now</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Thu, 13 Aug 2026 14:42:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Hf1u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>About 6 years ago I started <a href="https://calmcode.io/">calmcode.io</a> out of frustration. </p><p>Most of the online educational content was mostly a lazy copy of the docs and did a poor job of respecting the viewer&#8217;s time. I felt like something better <a href="https://calmcode.io/story">should exist</a> so I started work on a dead simple resource where a course was <em>just</em> a collection of 3 minute videos so people could learn tools worth learning quickly. </p><p>Oh boy, have things have changed in the meantime. </p><ul><li><p>All of my marketing for calmcode happened on Twitter back in the day. People started sharing and the site grew <em>a lot</em>. Roughly to a million visits after all these years. But Twitter changed and a calmcode update now results in crickets.</p></li><li><p>LLMs happened and it seems to have taken over how people do short-term learning. When people have a pressing issue they don&#8217;t even go to the docs anymore and go straight for the coding agent. Heck, they may not even read the code much anymore either. </p></li><li><p>As a result I wonder how many people are interested in doing the long-term learning for code-related topics. It&#8217;s not completely gone, people still sign up for calmcode even today, but it&#8217;s way less &#8220;interesting for my career&#8221; than before. </p></li><li><p>Some, but certainly not all, of the tools have started showing their age. We didn&#8217;t have uv back we started, and now it&#8217;s pretty much <em>the thing</em> that&#8217;s replaced all the other things. </p></li></ul><p>This has led to a lot of reflection on my end. What should I do with calmcode? <br><br>The simplest answer is that doing nothing is totally fine. Hosting the site is cheap (by design) and I am happy to keep it up if only for the good memories. So many people have reached out to me to tell me how the site has ignited their career, so &#8230; as regular calm coders will know &#8230; &#8220;there is no rush&#8221; to change anything.  <br><br>That said, if I&#8217;m honest I should admit that it has become less fun to make content for calmcode. The fact that it&#8217;s hard to get people to come to the site is a big part of it. It&#8217;s much easier for me to try to make interesting YouTube videos about topics that interest me and to get people to watch that compared to the calmcode site. </p><p>So here&#8217;s where I have landed: I will merge the calmcode mailing list with my personal substack. Most of my stuff on YouTube is similar in spirit to calmcode anyway, so it feels natural to do. That way I can still update people with interesting content and this won&#8217;t required any big changes too. <br><br>Speaking of some interesting content: there&#8217;s a <a href="https://youtu.be/mRbsvcxE9vc">new AnyWidget tutorial</a> that explains how you can make bespoke widgets for Python notebooks. I&#8217;ve also been making a bunch of those widgets and I have some demos of that <a href="https://www.youtube.com/watch?v=qVSeOr3AIbc">here</a>. There&#8217;s a lot of fun that you can have with these widgets, like what I&#8217;m doing here with <a href="https://www.youtube.com/watch?v=-Wdwiyxbp-8&amp;feature=youtu.be">the McNugget Graph</a>. I also made a video on my <a href="https://youtu.be/HIuFkB8_O-Q">new favorite way to share data</a>. So if you want to download some fun old school video game datasets, check <a href="https://datasette.exe.xyz/cnc_units/units">here</a> and <a href="https://datasette.exe.xyz/h3_units/units">here</a>. <br><br>One final thing: this isn&#8217;t me saying that I&#8217;ll never do anything on calmcode again. Who knows, if the right collaborators show up I might be open to revamping it. But until then, I&#8217;m just going to keep the site up and you can keep up to date with my stuff via substack. </p><p>If people want to say &#8220;hi&#8221; they can certainly do that here. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Hf1u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 424w, /__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 848w, /__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Hf1u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png" width="418" height="215.16974169741698" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/127d9c89-f429-4073-9e69-37d38f581916_1084x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:558,&quot;width&quot;:1084,&quot;resizeWidth&quot;:418,&quot;bytes&quot;:63626,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/211044431?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 424w, /__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 848w, /__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Hf1u!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127d9c89-f429-4073-9e69-37d38f581916_1084x558.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Either way, I also wanted to say thanks to everyone who tries to code calmly.  It always makes my day when people tell me that! </p><p>Yours, <br>Vincent </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Deliberate play]]></title><description><![CDATA[Getting better at getting better.]]></description><link>https://koaning.substack.com/p/deliberate-play</link><guid isPermaLink="false">https://koaning.substack.com/p/deliberate-play</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Mon, 01 Sep 2025 09:35:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/dVrkzc_arE8" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a href="https://en.wikipedia.org/wiki/Peak:_Secrets_from_the_New_Science_of_Expertise">Peak</a>, two psychologists talk about the concept of "deliberate practice". The idea is that you don't just "spend 10,000 hours" to become good at something. Instead, it's about being deliberate about how you practice. You should have goals, you should be focussed and you should try and reflect on your weaknesses instead of repeating the one party trick that you're good at. </p><p>I recently made a tool called <a href="https://github.com/koaning/wigglystuff">wigglystuff</a> that ships a `Matrix` widget. It behaves like a numpy array but you're also able to change the numbers by dragging them around in the browser. It effectively turns a matrix into something that could be part of an online form. If you combine such a widget with a reactive notebook it's pretty easy to come up with compelling demos!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Here's a demo of a matrix that represents PCA. There's a `n x 3` matrix of randomly sampled colors that I multiply with a `3 x 2` widget that you can control. This means that you're able to map colors unto a two dimensional plane. Here's what that might look like:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;82ac6b05-d824-42d2-be5b-0580de76190b&quot;,&quot;duration&quot;:null}"></div><p>If you're good at curiosity, this might trigger some questions.</p><ul><li><p>When I move the first number in the matrix the points expand. Why?</p></li><li><p>When I move the second number ... I introduce an angle away from the x-axis. Why?</p></li></ul><p>The widget is great at the interaction bit, but if you're even mildly curious you'll immediately be able to check your knowledge. And you might bounce into things that you might not have expected.</p><p>Let's try one more.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;9e6e90f6-8c53-4025-ba04-d4dffeec0ffc&quot;,&quot;duration&quot;:null}"></div><p>Notice how we get into a perfectly straight line here? Why? There's more than one great argument to be made here: the columns are not independant, but you can also just do the algebra.</p><p>But notice how you just bump into great questions by just playing around? You have to be deliberate about it, mind you, curiosity needs to be activate. But when you do, you're really working on some great motivation to dive deep once you've spotted something curious. Playing can be an act to make something interesting that wasn't before. This feels especially for topics like linear algebra. That single matrix has tonnes of applications, and you should feel free to explore them with some deliberate play.</p><p>Don't get me wrong, there's loads of great YouTube videos now that will teach you linear algebra too ... but videos are a one way street. All you can do is listen. That's note the same as playing and being an active participant.</p><h2>tldr</h2><p>More educational notebooks need to leverage play via widgets. They are a perfect method for deliberate play.</p><p>If you're interested in a longer demo, you'll enjoy this YT tutorial that does a deep dive on matrix widget.</p><div id="youtube2-dVrkzc_arE8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;dVrkzc_arE8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/dVrkzc_arE8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The titanic dataset has a twist]]></title><description><![CDATA[A trick that shouldn't work, but ... does!]]></description><link>https://koaning.substack.com/p/the-titanic-dataset-has-a-twist</link><guid isPermaLink="false">https://koaning.substack.com/p/the-titanic-dataset-has-a-twist</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Mon, 18 Aug 2025 15:03:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/_Y1-CC1jyvA" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Titanic dataset can be seen as the "hello world" of data science. The goal of the dataset is to predict who survived the titanic shipwreck based on a few known passenger properties. The <a href="https://www.kaggle.com/competitions/titanic">Kaggle competition</a> for it has over 1.3M entrants and the dataset is in every introduction course out there as a result.</p><p>And yet, it has a twist that no book talks about.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Model</h2><p>Typically, when tutorials make a model for the Titanic dataset, you'll see features like the number of siblings, the age, and the passenger class go into a model. It might try a few models and (if they bothered to do cross validation the right way and if they added a dummy model) you'd get a table that looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!-cOd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 424w, /__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 848w, /__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 1272w, /__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!-cOd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png" width="1348" height="294" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:294,&quot;width&quot;:1348,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:55496,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/171281653?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 424w, /__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 848w, /__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 1272w, /__u/substackcdn.com/image/fetch/$s_!-cOd!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc7cadbc-c307-42a5-991b-dc454660a1cd_1348x294.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Two models are crossed out, we&#8217;ll get to that in just a bit!</figcaption></figure></div><p>You might look at this table and conclude that the boosted model performs best, albeit without a lot of margin from the other models.</p><h2>But let's now consider a fun twist.</h2><p>Typically the models would focus on features like age, passenger class, gender, and the amount that was paid for the ticket. But the really interesting thing is that you can get a model that's pretty much in the the same ballpark as far as accuracy goes, but just zooming in on one and only one column.</p><p>There is one feature that people forget about ... it's the `name`!</p><p>If you make a pipeline with a CountVectorizer, that one-hot encodes every single token in the name column then you get a model in the same ballpark. You could also repeat the same exercise but with an embedding model from sentence-transformers.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!-HG7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 424w, /__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 848w, /__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 1272w, /__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!-HG7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png" width="1342" height="293" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:293,&quot;width&quot;:1342,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69494,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/171281653?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 424w, /__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 848w, /__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 1272w, /__u/substackcdn.com/image/fetch/$s_!-HG7!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc45e4f84-a943-4dbe-90ff-69d34da09d1f_1342x293.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The histogram boosting model still performs better, but the fact that name model even gets close ... that is friggin' interesting! It only uses **one single feature**! Turns out the name has ample information, it has a title for a person as well as the gender and maybe the last name is a proxy for wealth.</p><p>I never really understood why books would skip this super interesting fact. What if the `CountVectorizer` approach was more accurate? You could easily simulate such a situation by removing a few columns and pretending that those were not available. Would that make the model better? Or would we prefer a model that goes beyond the name?</p><h2>Reflecting</h2><p>Honestly, it's kind of bonkers that this dataset became so popular as a tutorial. There's no practical utility for the dataset what-so-ever and it will never be applied for anything. Given ample business cases for these models it makes a lot more sense to focus on those dataset.</p><p>That said, There is one final comment worth mentioning with regards to vibe coding and these kinds of conclusions. I imagine that there are many other data sets with a fun twist, and my hope is that vibe-coding can actually help us document these. LLMs are good enough to help you write scikit-learn pipelines for these sorts of small blogposts, so I hope more folks will join me to share more of these data science anekdotes. It feels like they're missing on the internet.</p><p>If that sounds interesting, you might enjoy this vibe-coding exercise I did for <a href="https://marimo.io/">marimo</a>. We're working on better LLM integration so we're investigating the space while also recording some vibe-coding exercises.</p><div id="youtube2-_Y1-CC1jyvA" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;_Y1-CC1jyvA&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/_Y1-CC1jyvA?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Introducing: bespoken!]]></title><description><![CDATA[Lego bricks to build a more bespoke claude code.]]></description><link>https://koaning.substack.com/p/introducing-bespoken</link><guid isPermaLink="false">https://koaning.substack.com/p/introducing-bespoken</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Fri, 11 Jul 2025 21:32:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/XLbi00RI0V8" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When used right, <a href="https://www.anthropic.com/claude-code">claude code</a> is a huge productivity boost. Take any brainfart, and you get working tools by just writing English. And yet ... there are moments when it frustrates me. It's very hard to customise the workflow. I need to adapt to claude and I sometimes I want to be able to declare how it should adapt to me. And I can&#8217;t.</p><p>Let's say that I want it to work on a <a href="https://marimo.io/">marimo</a> notebook. In that case I want it to make changes to one, and only one, file. But claude's permissions go <em>way</em> beyond that. It can edit any file, and even has access to all the command line tools, including the ones that can <code>rm -rf</code>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>That example is all about removing capabilities, but sometimes I also want to be able to add them. Let's say that I built a custom Python class that knows where to find the right docs and can fetch it in an effective format ... can I add that to claude loop? No! Instead, we are forced to have claude try and search the web, but why are we wasting our tokens on that?!</p><h2>Enter bespoken </h2><p>It&#8217;s stuff like this where my new tool can help out. For a full demo, you can check this YouTube video:</p><div id="youtube2-XLbi00RI0V8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;XLbi00RI0V8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/XLbi00RI0V8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>You can also check <a href="https://koaning.github.io/bespoken/">the docs</a> for an overview but the main point of the library is to let you write code like this: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!8oX2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 424w, /__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 848w, /__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 1272w, /__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!8oX2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png" width="1456" height="894" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:894,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:256719,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/168109359?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 424w, /__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 848w, /__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 1272w, /__u/substackcdn.com/image/fetch/$s_!8oX2!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77d0c0cc-0940-4940-b584-0433181cc683_1642x1008.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can configure the LLM, but also the tools that it can call. In the above example we constrain the agent by only giving it access to edit one (and only one) file. You&#8217;re also able to add tools that only the human can trigger and all custom tools can generate pretty forms from the terminal. It&#8217;s at version 0 now, but it comes with enough bells and whistles to make it clear what this framework can become. </p><h2>Let me know! </h2><p>I hope this sounds interesting. Feel free to reach out on socials, or <a href="https://github.com/koaning/bespoken/issues">leave a message on Github</a>.  </p><h2></h2><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Nerd sniping with a gamepad]]></title><description><![CDATA[All for the greater good of evals]]></description><link>https://koaning.substack.com/p/nerd-sniping-with-a-gamepad</link><guid isPermaLink="false">https://koaning.substack.com/p/nerd-sniping-with-a-gamepad</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Fri, 27 Jun 2025 12:17:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/aqKUwPKBkB0" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few weeks ago, I released <a href="https://github.com/koaning/mopad">mopad</a>, which is a library that allows you to use a gamepad in Python. </p><p>When I released it, I hinted <a href="https://hamel.dev/">Hamel Husain</a> that you could use it to annotate data and that maybe this way people might finally start to look at their data. Don&#8217;t just make it easy, make it fun. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Turns out this was a total nerd snipe, and Hamel invited me to talk about it on his live-stream <a href="https://www.youtube.com/watch?v=OYGtYLo53qI">here</a>. The benefit of this first link is that it also has dialogue at the start where I showcase my streaming/work setup but you can also see the more polished demo-recording below: </p><div id="youtube2-aqKUwPKBkB0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;aqKUwPKBkB0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/aqKUwPKBkB0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>Announcing <code>molabel</code></h2><p>I figured the livestream was also a great opportunity to showcase a new thing that I had been working on: <a href="https://github.com/koaning/molabel">molabel</a>. The library contains an annotation widget that gives you simple labelling interfaces that work straight from your notebook. It works by letting you pass a custom rendering function to for your examples, after which you can attach labels and notes to each. You can use the mouse for this, as well as keyboard shortcuts or a bluetooth gamepad. </p><p>This is what the widget looks like: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!PxSE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 424w, /__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 848w, /__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 1272w, /__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!PxSE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png" width="903" height="638" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:638,&quot;width&quot;:903,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44639,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/166960053?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 424w, /__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 848w, /__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 1272w, /__u/substackcdn.com/image/fetch/$s_!PxSE!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffdff3133-30d7-406e-a0cf-d8f17bc93269_903x638.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You create this widget with a call like this: </p><pre><code>from molabel import SimpleLabel

widget = SimpleLabel(
    examples=list_of_examples, 
    render=render_function
)</code></pre><p>The <code>list_of_examples</code> can be any Python list of things that you would like to render. You'd typically pass a list of dictionaries, but you're allowed to pass whatever you like. The only thing that the widget cares about is that you also pass a <code>render</code> function that can take each example and turn it into something html-like that the widget can render. You could use a string, but any object that has a <code>_repr_html_</code> would also work. That means that you can also directly use <a href="https://github.com/koaning/mohtml">mohtml</a> and <a href="https://www.fastht.ml/">FastHTML</a>. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!nq6P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 424w, /__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 848w, /__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 1272w, /__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!nq6P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png" width="954" height="544" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c189367c-b160-4ce3-ba77-156ae365279e_954x544.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:544,&quot;width&quot;:954,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:74358,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/166960053?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 424w, /__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 848w, /__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 1272w, /__u/substackcdn.com/image/fetch/$s_!nq6P!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc189367c-b160-4ce3-ba77-156ae365279e_954x544.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If the widget knows how to render, it can take care of the rest. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!UU5h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 424w, /__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 848w, /__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 1272w, /__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!UU5h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png" width="970" height="622" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:622,&quot;width&quot;:970,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124040,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/166960053?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 424w, /__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 848w, /__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 1272w, /__u/substackcdn.com/image/fetch/$s_!UU5h!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc785c780-615f-47e3-bd3d-0318e0b86afd_970x622.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The widget will store all the annotations that you generate and you can wire it up in such a way that data is automatically sent to a database on your behalf. If you have a gamepad at-the-ready you can also give this <a href="https://koaning.github.io/molabel/">demo hosted on GitHub pages</a> a spin right away. It runs a <a href="https://marimo.io/">marimo notebook</a> in <a href="https://docs.marimo.io/guides/wasm/">WASM on the front-end</a>, so you can give the widget a spin without installing anything locally.  </p><h2>Loads of use-cases are covered</h2><p>This widget can feel pretty basic at first glance. There's really only a binary "yes"/"no" choice with an extra option to "skip". While it might seem basic, let's take a step back and appreciate what we've already got covered here. As-is, you can use this for:</p><ul><li><p>binary classification</p></li><li><p>multi-label classification (each label is binary, after all)</p></li><li><p> the "is this a match?" kinds of queries for retrieval</p></li><li><p>comparisons between two choices, one of which is better</p></li></ul><p>Keeping it simple also means less human errors and more labels. I have seen annotation interfaces with <a href="https://youtu.be/S7vhi6RjBZA?si=5ZL_XkJ3u7aWwzvR&amp;t=562">27 classification labels and it's maddening</a>. Having a simpler interface means less cognitive overhead and it will just give you more labels with higher quality. </p><p>Not only that, but we allow you to add plenty of context via the textbox too. So if you want to explain why there is an issue with an example, maybe for finetuning an LLM later, that's totally possible here. You could theoretically even use this widget only to add a note to each example, ignoring the labels all-to-gether. Note that you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API">text-to-speech API from the browser</a> for free here, so you could also use your voice while annotating with a gamepad.</p><h2>Why</h2><p>I have been telling people to take data quality serious for years now and instead of talking about it I now want to start making tools for it. The focus of these tools will be to make it easy to get started, but also to make it fun. I have *literally* found a way for AI engineers to expense a gamepad for work, so hopefully that alone will be enough to finally get more people to use look at their data. </p><h2>ps. a final note</h2><p>Lastly, and this is important, another reason to get excited is that the gamepad is also a great ergonomic device. You can sit in a comfortable chair and use a device that is designed for comfort. I have suffered from RSI in the past and it is something to take serious. I spent over $3000 to figure out what ergonomic boards would work well for me. This led me to start a <a href="https://www.youtube.com/watch?v=Kqgg1k01U5Q&amp;list=PLGj5nRqy15j93TD0iReqfLL9lU1lZFEs6&amp;index=2">YouTube channel</a> where I review ergonomic boards and I am looking forward to reviewing devices/gamepads for annotation in the near future. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[vibe-coding "for realsies"]]></title><description><![CDATA[Do vibe-coding they said, it will be fun they said]]></description><link>https://koaning.substack.com/p/vibe-coding-for-realsies</link><guid isPermaLink="false">https://koaning.substack.com/p/vibe-coding-for-realsies</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Wed, 04 Jun 2025 09:10:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/4fXLB5_F2rg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wanted to test vibe coding seriously. I'd used it for toys like <a href="https://koaning.io/posts/better-bacteria/">boardgames</a>, <a href="https://koaning.io/posts/lanchester/">simulations</a> and <a href="https://koaning.io/posts/terminal-parallax-vibes/">terminal space shooters</a>, but what if you tried to go beyond that? Could it handle production-ready code? What if you tried doing this for real?</p><p>What follows is an anekdote of a Flask app that was functional, but also kept breaking somewhat randomly. It&#8217;s for an app that I do want to release soon, but I had to take a step back and learn something about vibe-coding first.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>A Flask app</h2><p>Imagine that I have a Flask webapp, one that starts like this:</p><pre><code>from flask_sqlalchemy import SQLAlchemy
from flask import Flask 

# Init app
app = Flask(__name__)
app.config = {...}

# Init DB 
db = SQLAlchemy()
db.init_app(app)

# Init the rest
...</code></pre><p>Then I might also have some tests, these use fixtures and might look a little bit like this:</p><pre><code>from app import app as flask_app
from flask import session


@pytest.fixture
def client():
    flask_app.config['TESTING'] = True
    flask_app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'  # Use in-memory SQLite for tests
    
    with flask_app.app_context():
        db.create_all()  # Create all tables
        # Create a test user if needed for your tests
        test_user = User(email='test@example.com', is_verified=True, is_paying=False, message_interval_days=7)
        db.session.add(test_user)
        db.session.commit()
        
    with flask_app.test_client() as client:
        yield client
        
    with flask_app.app_context():
        db.session.remove()
        db.drop_all()  # Clean up after tests</code></pre><p>This `client`-fixture is used all over the place in the test suite, and what's nice here is that it makes sure that each test starts with a fresh database. This feels good, vibe-coding checks out, so let's move on and have it write some more code.</p><h2>Odd behavior</h2><p>What could go wrong, you might ask?</p><p>A lot! It's very subtle, but consider the flask app one more time.</p><pre><code>from flask_sqlalchemy import SQLAlchemy
from flask import Flask 

# Init app
app = Flask(__name__)
app.config = {...}

# Init DB 
db = SQLAlchemy()
db.init_app(app)

# Init the rest
...</code></pre><p>The fixture overrides `app.config` variables, but these changes happen <em>*after*</em> `db` is initialized. So if you accidentally have a `SQLALCHEMY_DATABASE_URI` environment variable pointing to production... the fixture will still use it! And notice the fixture's cleanup code:</p><pre><code>    ... 

    with flask_app.test_client() as client:
        yield client
        
    with flask_app.app_context():
        db.session.remove()
        db.drop_all()  # Clean up after tests</code></pre><p>Imagine debugging this. Tests don't fail or prevent this - all you see is production user tables drop randomly.</p><p>I initially suspected a misconfigured migration. The AI assistant suggested Docker deployment issues. A bunch of time was wasted here.</p><h2>The fix?</h2><p>The quick fix, suggested by the bot, after pointing out that `pytest` was the culprit was to add this to the `conftest.py` file:</p><pre><code>import os

# This runs before any tests are collected
def pytest_configure(config):
    # Explicitly override DATABASE_URL to ensure we never connect to a real database
    os.environ["DATABASE_URL"] = "sqlite:///:memory:" </code></pre><p>This will prevent the database losing tables when running pytest, but it doesn't address the fact that the project itself needs to be more strict with regards to separating local/production environments.</p><h2>My conclusion</h2><p>So who'se fault is it that the setup broke?</p><p>It is easy to blame the AI here, but that would be silly. The project was set up in the wrong way because *I did not pay attention to it*. I could have easily been more safe, and pragmatic even, by strictly following two `.env.prod` and `.env.local` files. I could have taken the time to set up the project and get the deployments in order before I even write the app. But I allowed the assistant, and myself, to YOLO around. Unit tests are simply not enough.</p><p>So in short, vibe-coding ... it is both extremely impressive and extremely untrustworthy at the same time. It's stuff like the story above, but also things like "forgetting about csrf-tokens" in web forms that constantly reminds me of this. But at the end of the day, the lesson here isn't that "vibe coding sucks", but rather that "you need to get better at these tools if you want to use them".</p><p>That means vibe coding defensively, thinking ahead and maybe investing in a solid cookiecutter as a solid starting point. Do that right, and you&#8217;ll get more productive for sure now. </p><p>ps. Just to give one example of something that I was finally able to wrap up thanks to vibe-coding defensively: you can now use gamepads from Python!</p><div id="youtube2-4fXLB5_F2rg" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;4fXLB5_F2rg&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/4fXLB5_F2rg?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Rethinking tools so we can dream a little]]></title><description><![CDATA[domain specific environments > domain specific models]]></description><link>https://koaning.substack.com/p/rethinking-tools-so-we-can-dream</link><guid isPermaLink="false">https://koaning.substack.com/p/rethinking-tools-so-we-can-dream</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Wed, 07 May 2025 14:47:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!J5sM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let&#8217;s say that there is a dataset with numbers related to <strong>smoking</strong>, <strong>age</strong> and <strong>health outcome</strong>. Given such a dataset, you might be interested in running some queries. You could use SQL to describe what you want, but if you've taken a course in probability theory then you might write this on a piece of paper instead. </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P(\\text{outcome} \\mid \\text{smoker}=\\texttt{Yes}, \\text{age}>40)&quot;,&quot;id&quot;:&quot;OJROTMRBRI&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I know this is going down the &#8220;probability nerd snipe&#8221; territory, but I was wondering how close I could get a Python API to this notation. After all, this is *very* compact compared to any SQL that you might write.  </p><h2>Enter <code>peegeem</code></h2><p>I wrote a small library in Python that allows for <em>*exactly*</em> this. Not only does it give you the fancy notation, you're also able to declare the probabilistic graphical model that outlines the causal relationships between your variables.</p><pre><code>from peegeem import DAG

# Define the DAG for the PGM, nodes is a list of column names, edges is a list of tuples
dag = DAG(nodes, edges, dataframe)

# Get variables out
outcome, smoker, age = dag.get_variables()

# Use variables to construct a probabilistic query
P(outcome | (smoker == "Yes") &amp; (age &gt; 40))

# Latex utility, why not?
P.to_latex(outcome | (smoker == "Yes") &amp; (age &gt; 40))</code></pre><p>It's pretty darn neat! It's really like writing down maths and you get a data-list out with all relevant probability values. But want to know the real kicker? You can use this in a notebook together with some widgets!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!J5sM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 424w, /__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 848w, /__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 1272w, /__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_webp, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!J5sM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif" width="800" height="421" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:421,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:280787,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://koaning.substack.com/i/163059114?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_424, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 424w, /__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_848, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 848w, /__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_1272, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 1272w, /__u/substackcdn.com/image/fetch/$s_!J5sM!, /__u/koaning.substack.com/w_1456, /__u/koaning.substack.com/c_limit, /__u/koaning.substack.com/f_auto, /__u/koaning.substack.com/q_auto:good, /__u/koaning.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F22db5734-a03b-47f3-b53c-d0e4c9af4220_800x421.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Again, it helps to be a probability nerd here, but one clever thing we can do is combine our query ability with the ability to use reactive components and charts. By doing this, you kind of get a <strong>domain specific environment</strong> instead of just a <strong>domain specific language</strong> to interface with. </p><p>This is super exciting and I hope to work on more projects like this one. If you're keen to learn more, and see an extensive demo, you might enjoy this <a href="https://marimo.io/">marimo</a> livestream that I did for it last week. </p><div id="youtube2-tw6InlykH7o" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;tw6InlykH7o&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/tw6InlykH7o?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Code with Vibes, Vibes with Discipline]]></title><description><![CDATA[Exploring three rules for more meaningful vibe coding]]></description><link>https://koaning.substack.com/p/code-with-vibes-vibes-with-discipline</link><guid isPermaLink="false">https://koaning.substack.com/p/code-with-vibes-vibes-with-discipline</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Sun, 13 Apr 2025 20:39:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/j9jh46R0ryY" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Vibe-coding is trending these days. I'm definitely part of that crowd now but I've started setting some boundaries. I can have fun with these tools, and I am, but there are risks. It's pretty easy to throw together a zero-shot demo, but if I end up with a pile of abandoned projects, then I'm not really doing myself any favours. I also want to make sure that I don't become overly dependant on these tools, so I set myself some rules. </p><p><strong>I'm happy to generate code, but I am unwilling not to learn from it.</strong> The other day I vibe-coded my favourite board game for my blog (<a href="https://koaning.io/posts/study-those-claude-vibes/">link</a>) but I was amazed at how the technology was applied. The game involves stacking buildings and I would've assumed that HTML canvas would be required. But Claude was able to do it all with CSS and HTML divs directly. Skipping such lessons would be a waste.</p><p><strong>I&#8217;m happy to experiment, but I am unwilling to ignore my productivity.</strong> It&#8217;s really never been easier to write tools for yourself to make your life easier. So maybe you should? I wrote a new backend for my blog in a few evenings and it&#8217;s really gotten to the point where I love writing again. I wrote about the new layout <a href="https://koaning.io/posts/bespoke-new-static-blog-engine/">here</a>, but I also started working on a system for <a href="https://koaning.io/posts/parsing-python-web-components/">Python based webcomponents</a> that integrates with the blog. I also made <a href="https://koaning.io/posts/introducing-mopaint-more-seriously/">mopaint</a>, which is a widget that looks like MSPaint that you can use from a notebook to draw. All relatively small projects, but huge boost to my productivity! </p><p><strong>I&#8217;m happy to toy with code, but I am unwilling not to toy with ideas. </strong>If implementation becomes easier, maybe we should take more time brainstorming ideas. Instead of thinking &#8220;I want to write code that does X for me&#8221; you might want to think &#8220;What API makes it more enjoyable for me to write code that does X for me?&#8221; first. The best example of this has been the <a href="https://github.com/koaning/smartfunc">smartfunc library</a> that I made that makes it easier for me to interact with LLMs for rapid prototyping. It&#8217;s been featured on <a href="https://simonwillison.net/search/?q=smartfunc&amp;sort=date">Simon Willisons blog</a> and also started trending a little bit on <a href="https://youtu.be/j9jh46R0ryY">YouTube</a> and <a href="https://news.ycombinator.com/item?id=43619884">hackernews</a>. </p><div id="youtube2-j9jh46R0ryY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;j9jh46R0ryY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/j9jh46R0ryY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>I&#8217;m curious to hear if I&#8217;m the only one exploring such boundaries, but can recommend folks to at least consider it. It&#8217;s certainly seems to have made me enjoy the ride more *and* more productive. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Starting a substack]]></title><description><![CDATA[Why?]]></description><link>https://koaning.substack.com/p/starting-a-substack</link><guid isPermaLink="false">https://koaning.substack.com/p/starting-a-substack</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Tue, 01 Apr 2025 14:34:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/cNYw32X-WAU" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi all.</p><p>Jack Conte, of <a href="https://www.patreon.com/">Patreon</a> and <a href="https://www.youtube.com/@Pomplamoose">Pomplamoose</a> fame, recently stated that <a href="https://www.youtube.com/watch?v=cNYw32X-WAU">&#8220;we might be witnessing the death of the follower&#8221;</a>. Where from 2019-2023 you would have had a good time on social media by gaining a large following you now need to make sure that you get picked up by the algorithm of whatever platform you are on. In short, that means that the fact that you follow me no longer guarantees that you&#8217;ll be able to hear me anymore. It&#8217;s a good interview, I can recommend a listen!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div id="youtube2-cNYw32X-WAU" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;cNYw32X-WAU&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/cNYw32X-WAU?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Fact of the matter is that a few people started pointing this out to me, asking me if I stopped posting ever since I became a dad, which is not the case. The discovery mechanism of the internet has changed and it seems to favor content that is willing to adapt to the platform. You may have noticed this on YouTube and on LinkedIn. Thumbnails and titles really matter more and posts that share links get downvotes by the algorithm because it leads people off the platform. </p><p>In short: it seems like maintaining an email list is pretty much the only way for me to really guarantee that folks can be kept up to date with stuff that I do. </p><p>Just to name a few things that I&#8217;ve done in the past few weeks. </p><ul><li><p>I revamped my personal blog by vibe-coding a personal editor in Flask. Details can be found <a href="https://koaning.io/posts/bespoke-new-static-blog-engine/">here</a>. It also features a basic RSS feed that people can follow. </p></li><li><p>I learned about some CSS tricks while implementing the santorini board game for HTML. Details, and the live game, are on my <a href="https://koaning.io/posts/study-those-claude-vibes/">blog</a>.</p></li><li><p>I built a &#8220;newspaper&#8221; that make summaries of popular hackernews discussions. You can find it on <a href="https://thedailybin.com/">thedailybin.com</a> and you can learn all about how it&#8217;s made on <a href="https://youtu.be/AD_re1aAqJw">YouTube</a> or on <a href="https://koaning.io/posts/the-daily-bin-is-out/">my blog</a>. It&#8217;s been an entertaining way for me to keep up to date without getting distracted/sucked into a lot of threads. </p></li><li><p>I made a new tool that I pretty much use daily called `mohtml`. It&#8217;s a library with 50 lines of Python that can generate most of HTML in a functional style. There&#8217;s a <a href="https://calmcode.io/shorts/mohtml">calmcode course</a> for it and a <a href="https://www.youtube.com/watch?v=VWafIv36mtc">YouTube deep dive</a>. </p></li><li><p>I also made a Python notebook widget called <a href="https://github.com/koaning/mopaint">mopaint</a> that allows you to draw images in a MSPaint themed drawing utility. Once drawn, you can use the drawing to pass it forward to other tools. This includes vision models!</p></li></ul><p>And this is just my personal stuff, not even mentioning some of the things that I am doing over at <a href="https://marimo.io/">marimo</a>. So I guess there&#8217;s plenty of material for me to share.</p><p>The goal of my newsletter will be to keep folks in the loop via email. That way you should hear a signal from me even if I cannot reach you over social media anymore. Substack seems like the simplest provider to set this up, but I might switch in the future. Time will tell if I like the platform.  </p><p>Hope you like it!</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://substack.com/refer/vincent.475?utm_source=substack&amp;utm_context=post&amp;utm_content=160342782&amp;utm_campaign=writer_referral_button&quot;,&quot;text&quot;:&quot;Start a Substack&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Start writing today. Use the button below to create a Substack of your own</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://substack.com/refer/vincent.475?utm_source=substack&amp;utm_context=post&amp;utm_content=160342782&amp;utm_campaign=writer_referral_button&quot;,&quot;text&quot;:&quot;Start a Substack&quot;,&quot;hasDynamicSubstitutions&quot;:false}" data-component-name="ButtonCreateButton"><a class="button primary" href="/__u/substack.com/refer/vincent.475?utm_source=substack&amp;utm_context=post&amp;utm_content=160342782&amp;utm_campaign=writer_referral_button"><span>Start a Substack</span></a></p></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Vincent&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Coming soon]]></title><description><![CDATA[This is Vincent&#8217;s Substack.]]></description><link>https://koaning.substack.com/p/coming-soon</link><guid isPermaLink="false">https://koaning.substack.com/p/coming-soon</guid><dc:creator><![CDATA[Vincent]]></dc:creator><pubDate>Tue, 01 Apr 2025 14:32:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!59fN!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9560f55-6113-4e71-9087-ac330a783924_400x400.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is Vincent&#8217;s Substack.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://koaning.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="/__u/koaning.substack.com/subscribe"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>