<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>David Jarman's Blog</title><link href="https://davidjarman.net/" rel="alternate"/><id>https://davidjarman.net/</id><author><name>David Jarman</name></author><updated>2026-05-31T05:34:41.7130000+00:00</updated><entry><id>https://davidjarman.net/archive/2026/05/30/obsidian-publish</id><title>Publishing blog posts from Obsidian</title><updated>2026-05-31T05:43:38.5550000+00:00</updated><content type="html">&lt;p&gt;I&#39;ve been publishing blog posts from an authenticated /admin page on this site using GitHub credentials to authenticate myself. This has always been concerning to me as a security vulnerability. I wrote the C# auth handler myself but I&#39;m no security expert especially when it comes to OAuth. I&#39;ve had a lot of exposure to it but have never considered myself an expert on it.&lt;/p&gt;
&lt;p&gt;The second issue with the admin page is that it has been eating my blog posts lately. I would author a post in the admin page and when I hit submit, the form would submit and the post would just get silently dropped. I tried debugging it for a while but decided the complexity and security of the admin page wasn&#39;t worth it anymore.&lt;/p&gt;
&lt;p&gt;In the spirit of simplifying the hosting (removing postgres and migrating to fly.io), I decided I could author posts in Obsidian instead and write a plugin to publish directly to the blog&#39;s storage blob store (using Azure blob storage). This is the first post being written in Obsidian!&lt;/p&gt;
&lt;p&gt;I&#39;m now realizing that I&#39;m back to where I started back in 2023 when I first used &lt;a href=&quot;https://obsidian.md/publish&quot;&gt;Obsidian Publish&lt;/a&gt; to host a small blog. I rarely posted on it (even less often than this blog) and shut it down eventually.&lt;/p&gt;
&lt;p&gt;One annoying thing with creating the obsidian plugin was that I wanted to use the official &lt;a href=&quot;https://www.npmjs.com/package/@azure/storage-blob&quot;&gt;Azure JavaScript SDK&lt;/a&gt; for the blob storage uploads, but it thinks that Obsidian is a browser and blocks using a shared credential key as the authentication mechanism. It only allows it in NPM runtime environments. I understand why they have to add this check, but it did force me to write my own slim blob store SDK.&lt;/p&gt;
&lt;p&gt;With this change, I used AI way less than in the past. Partly because I cancelled my Claude Pro subscription last month and partly because I wanted to learn and understand the Obsidian plugin API and TypeScript development. I originally started this blog to &lt;em&gt;learn&lt;/em&gt; and that was happening less and less as I was relying on AI more. I didn&#39;t completely abstain however. I used &lt;a href=&quot;https://opencode.ai/&quot;&gt;OpenCode&lt;/a&gt; and &lt;a href=&quot;https://openrouter.ai/&quot;&gt;OpenRouter&lt;/a&gt; for some parts such as the blob store sdk. I&#39;ve written my own Blob Store SDKs in C# before and it&#39;s just tedious to set up the auth correctly. It was nice to use open router as it allowed me to try out different models, such as DeepSeek V4 and Kimi 2.5. However, there is a reason people flock to Opus and GPT5.5. DeepSeek was very disappointing, it actually felt like GPT 3.5 days in some ways. It would just quite in the middle of work with no notification. I ended up going back to Sonnet 4.6 to finish up some work and the increase in capability was so immediately clear.&lt;/p&gt;
&lt;p&gt;I&#39;m glad I got to try out some different tools. At work I use &lt;a href=&quot;https://github.com/features/copilot/cli&quot;&gt;Copilot CLI&lt;/a&gt; and can choose between several different models. I tend to use GPT5.5 for planning and Opus 4.7 for executing the implementation specs as it plays to their strengths. I was using Claude Code at work until &lt;a href=&quot;https://www.theverge.com/tech/930447/microsoft-claude-code-discontinued-notepad&quot;&gt;the licenses were cancelled&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;note&lt;/strong&gt;: I don&#39;t use AI to write posts and I don&#39;t ever plan to. Writing is sacred to me and helps me think. The point of authoring posts manually is to help me clarify my own thoughts.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2026/05/31/obsidian.png&quot; alt=&quot;How I wrote this post&quot; /&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/05/30/obsidian-publish" rel="alternate"/><published>2026-05-31T05:34:41.7130000+00:00</published><category term="colophon" /><category term="dev-notes" /></entry><entry><id>https://davidjarman.net/archive/2026/05/29/last-fm-is-now-independent</id><title>Last.fm is now independent</title><updated>2026-05-29T15:15:24.4652483+00:00</updated><content type="html">&lt;p&gt;The last.fm staff posted a small announcement that they are now independent. I&#39;ve been on last.fm since 2008 and didn&#39;t realize they were owned by the CBS corporation that entire time. Apparently &lt;a href=&quot;https://blog.last.fm/2007/05/30/lastfm-acquired-by-cbs&quot;&gt;CBS bought last.fm in 2007&lt;/a&gt;. In that post about the acquisition is this line&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CBS understands the Last.fm vision, the importance we place on putting the listener in charge, the vibrant and vocal community, the obsession with music stats, and our determination to offer every song ever recorded.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I imagine last.fm had huge ambitions in their early days. There was no Spotify or major streaming services at that time, so they were in a potential position to become the central place where people came to listen to and discover music.&lt;/p&gt;
&lt;p&gt;Looking back at my own music habits at that time, I was either spending money in iTunes to buy albums or individual tracks for $0.99, but that was also locking me into the Apple ecosystem because all music on iTunes was protected with DRM (they later introduced music without DRM and thus increased the price to $1.29, which is still the price to this day). I remember signing up for last.fm for the ability to internet radio streaming and discovering music. It was pretty unimpressive looking back, but at the time it felt amazing.&lt;/p&gt;
&lt;p&gt;I haven&#39;t used last.fm much since then, I had a brief time from 2014-2016 where I had scrobbling set up with Spotify, but something broke and I never noticed or bothered to fix it. With this announcement of them becoming independent, it&#39;s reignited my interest in scrobbling and tracking the music I&#39;m listening to. I&#39;ve also been working on moving away from Spotify and going back to manually managing my music like its the year 2006.&lt;/p&gt;
&lt;p&gt;Here is my last.fm profile: &lt;a href=&quot;https://www.last.fm/user/jmanator&quot;&gt;https://www.last.fm/user/jmanator&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/05/29/last-fm-is-now-independent" rel="alternate"/><published>2026-05-29T15:01:06.0000000+00:00</published><category term="music" /></entry><entry><id>https://davidjarman.net/archive/2026/05/13/browser-cycling-training-app</id><title>In-browser Indoor Cycling Training App</title><updated>2026-05-13T20:31:43.2687213+00:00</updated><content type="html">&lt;p&gt;I cancelled my Zwift subscription recently. It&#39;s not that Zwift is bad, I just don&#39;t use it often enough to justify the monthly price. I&#39;ve been looking for a free alternative that I can use whenever I feel like riding inside (very rare these days).&lt;/p&gt;
&lt;p&gt;But then I found BullWatt in a &lt;a href=&quot;https://www.reddit.com/r/cycling/comments/15jt3am/free_zwift_alternative/&quot;&gt;Reddit thread&lt;/a&gt;. It&#39;s exactly what I want, even though I didn&#39;t realize it at first. It runs locally in your browser and uses the Bluetooth API to connect to your trainer. Unfortunately, it appears that only Google Chrome has any decent support for this API so I had to install that first, which pains me to see it next to Firefox.&lt;/p&gt;
&lt;p&gt;The best part is that because it runs locally in the browser, there are no accounts or sign ups. You can just start using it immediately. Absolute cinema.&lt;/p&gt;
&lt;p&gt;I just finished a &lt;a href=&quot;https://www.strava.com/activities/18495564528&quot;&gt;25 minute session&lt;/a&gt; and it did exactly what it advertised. It let me pick a workout and set my FTP, and then it used the ERG mode of my trainer to automatically set the resistance.&lt;/p&gt;
&lt;p&gt;The source is on &lt;a href=&quot;https://github.com/canssens/bullwatt&quot;&gt;GitHub&lt;/a&gt;. I&#39;m going to poke around there later to see how it works in more detail.&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/05/13/browser-cycling-training-app" rel="alternate"/><published>2026-05-13T20:31:43.2687213+00:00</published><category term="cycling" /></entry><entry><id>https://davidjarman.net/archive/2026/05/06/programming-still-sucks</id><title>Recommended reading</title><updated>2026-05-07T04:18:25.9537560+00:00</updated><content type="html">&lt;blockquote&gt;
&lt;p&gt;AI didn&#39;t take our jobs. Greed did.&lt;/p&gt;
&lt;/blockquote&gt;
</content><link href="https://davidjarman.net/archive/2026/05/06/programming-still-sucks" rel="alternate"/><published>2026-05-07T04:18:25.9537560+00:00</published><category term="writing" /><category term="ai" /></entry><entry><id>https://davidjarman.net/archive/2026/04/06/markdown-posts</id><title>Removing Postgres and storing posts as Markdown files</title><updated>2026-04-07T05:17:21.5690337+00:00</updated><content type="html">&lt;p&gt;Now that Heroku is on the deprecation path, I&#39;ve been looking to move this blog to another provider. One thing I quickly realized is that managed SQL servers are usually not this cheap. I&#39;m currently paying $5 a month for the cheapest tier but I haven&#39;t seen another provider with that good of a price point. This got me thinking, why use SQL at all for this simple site? Why not just store posts as markdown with YAML frontmatter?&lt;/p&gt;
&lt;p&gt;I&#39;ve been wanting to try out the acclaimed &lt;a href=&quot;https://github.com/obra/superpowers&quot;&gt;superpowers&lt;/a&gt; plugin for claude code, and this was just the right feature to use it on. Did a long brainstorm session with the agent to flesh out the idea, then using the subagent-driven development method, had Claude implement it. A bunch of subagents got to work and had the whole thing working end-to-end pretty quickly. One thing I forgot to flesh out was the replacement of my custom image-upload JS from my old WYSIWYG editor, trix. We replaced it with &lt;a href=&quot;https://github.com/ionaru/easy-markdown-editor&quot;&gt;EasyMDE&lt;/a&gt; and all I had to do was point it at my image upload endpoint and change a bit of formatting on the server side.&lt;/p&gt;
&lt;p&gt;I&#39;m very impressed with superpowers. I paired it with Simon Willison&#39;s &lt;a href=&quot;https://github.com/simonw/rodney&quot;&gt;Rodney&lt;/a&gt; CLI so the agents could test out their changes and &amp;quot;see&amp;quot; the actual impact of their code in a headless browser. I now have much &lt;em&gt;less&lt;/em&gt; code running on the blog and no Postgres dependency, so I should be free to switch to another provider, such as &lt;a href=&quot;https://fly.io&quot;&gt;fly.io&lt;/a&gt; and hopefully halve my hosting cost.&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/04/06/markdown-posts" rel="alternate"/><published>2026-04-07T05:17:21.5690337+00:00</published><category term="colophon" /><category term="dev-notes" /><category term="claude-code" /><category term="superpowers" /></entry><entry><id>https://davidjarman.net/archive/2026/03/26/claude-code-pwsh-tool</id><title>Claude Code PowerShell tool</title><updated>2026-03-26T17:52:44.9635990+00:00</updated><content type="html">&lt;p&gt;You can now opt-in to a new built-in PowerShell tool in Claude Code as of &lt;a href=&quot;https://github.com/anthropics/claude-code/releases/tag/v2.1.84&quot;&gt;v2.1.84&lt;/a&gt; by setting the CLAUDE_CODE_USE_POWERSHELL_TOOL environment variable.&lt;/p&gt;
&lt;p&gt;Until this release, Claude Code on Windows would use Git Bash to run commands, which has caused some weird issues for me in the past, such as running the roslyn-language-server dotnet tool, because the entrypoint is a .cmd file which can&#39;t be run in a git bash shell.&lt;/p&gt;
&lt;p&gt;Now, Claude Code will see an additional tool called &amp;quot;PowerShell&amp;quot;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  Built-in Tools

  - Read — Read files from the filesystem
  - Write — Write/create files
  - Edit — Make exact string replacements in files
  - Bash — Execute shell commands
  - Glob — Find files by pattern
  - Grep — Search file contents with regex
  - Agent — Launch specialized subagents
  - Skill — Invoke user-defined skills
  - ToolSearch — Fetch schemas for deferred tools
  - PowerShell — Execute PowerShell commands
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It doesn&#39;t &lt;em&gt;replace&lt;/em&gt; the Bash tool, it just adds PowerShell, so you may find that the agent defaults to using Bash for most things unless you ask it to use PowerShell explicitly.&lt;/p&gt;
&lt;p&gt;You can also add { &amp;quot;defaultShell&amp;quot;: &amp;quot;powershell&amp;quot; } to your settings.json file to make !commands run in PowerShell. This means you can now run cmdlets directly. For example: ! Write-Host &amp;quot;Hello&amp;quot; now works.
&lt;a href=&quot;https://linkblog.blob.core.windows.net/images/2026/03/26/17/52/17/image.png&quot;&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2026/03/26/17/52/17/image.png&quot; alt=&quot;hello world&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/03/26/claude-code-pwsh-tool" rel="alternate"/><published>2026-03-26T17:52:44.9635990+00:00</published><category term="powershell" /><category term="claude" /><category term="ai" /><category term="windows" /></entry><entry><id>https://davidjarman.net/archive/2026/02/02/we-are-the-art</id><title>We are the art by Brandon Sanderson</title><updated>2026-02-03T04:44:20.0876350+00:00</updated><content type="html">&lt;p&gt;Brandon Sanderson offers his view on why AI art is not art. I highly recommend watching the whole video, it’s very entertaining and he makes a lot of good points from the perspective of those who make art.&lt;/p&gt;
&lt;p&gt;I’m more of a consumer than a creator (although I do play guitar which scratches the itch), and my view on art and AI is that what makes art valuable to me is the context in which the art is made. It’s why I can hear the same song played by two different musicians and one version moves you more than another.&lt;/p&gt;
&lt;p&gt;My example of this is listening to Townes Van Zandt play covers of songs, and they hit different. Knowing who he was as a person and the struggles he had throughout life really change how you experience a song. The pain is something you can hear in a raspy voice that is the result of years of smoking and hard living.&lt;/p&gt;
&lt;p&gt;To echo, but slightly modify, Brandon’s point here, no matter how good AI gets at making art, it won’t have the same impact on me as a consumer because it’s completely void of any context that would give it meaning.&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/02/02/we-are-the-art" rel="alternate"/><published>2026-02-03T04:44:20.0876350+00:00</published><category term="pontificating" /><category term="ai" /></entry><entry><id>https://davidjarman.net/archive/2026/01/31/blog-feature-paging</id><title>New blog feature: paging</title><updated>2026-02-01T04:20:55.4425830+00:00</updated><content type="html">&lt;p&gt;When scrolling to the bottom of the home page, you now should see an &amp;quot;older posts&amp;quot; button which will take you to the next page of posts. This feature has been on my TODO list since day 1 and am happy it&#39;s finally implemented. It&#39;s much easier now that all posts are cached in memory in the blog, so I can just use LINQ statements to &amp;quot;Skip&amp;quot; and &amp;quot;Take&amp;quot; over the full post collection to emulate paging.&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/01/31/blog-feature-paging" rel="alternate"/><published>2026-02-01T04:20:55.4425830+00:00</published><category term="colophon" /><category term="dev-notes" /></entry><entry><id>https://davidjarman.net/archive/2026/01/09/claude-code-notifications-wsl</id><title>Get notifications from Claude Code on Windows with WSL</title><updated>2026-01-09T23:36:56.4094330+00:00</updated><content type="html">&lt;p&gt;I&#39;ve been looking for a way to get notified when Claude Code needs my input or is finished. Big shout out to u/Ok-Engineering2612 on Reddit for this post:&#160; &lt;a href=&quot;https://www.reddit.com/r/ClaudeAI/comments/1m2qscz/wsl_toast_notifications_with_hooks_in_claude_code/&quot;&gt;WSL Toast Notifications with Hooks in Claude Code : r/ClaudeAI&lt;/a&gt;. I had been trying to do the same thing with BurntToast but I forget the way WSL interops with Windows.&lt;/p&gt;
&lt;p&gt;The settings from the Reddit thread did need a little tweaking ($PAYLOAD is no longer supported and now Claude Code sends the JSON structure via stdin). Here&#39;s my change to the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &amp;quot;command&amp;quot;: &amp;quot;input=$(cat) &amp;amp;&amp;amp; powershell.exe -NoProfile -Command \&amp;quot;Import-Module BurntToast; New-BurntToastNotification -Text &#39;Claude Code Notification&#39;, &#39;$(echo \&amp;quot;$input\&amp;quot; | jq -r &#39;.message&#39;)&#39;\&amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is the full documentation for hooks:&#160;&lt;a href=&quot;https://code.claude.com/docs/en/hooks#notification-input&quot;&gt;Hooks reference&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/01/09/claude-code-notifications-wsl" rel="alternate"/><published>2026-01-09T23:31:51.4534450+00:00</published><category term="wsl" /><category term="claude" /><category term="ai" /><category term="windows" /></entry><entry><id>https://davidjarman.net/archive/2026/01/07/file-pilot</id><title>File Pilot - Fast file explorer for Windows</title><updated>2026-01-08T15:06:20.7990520+00:00</updated><content type="html">&lt;p&gt;It’s 2026 and you can buy a lightweight, super fast file explorer for windows for $250. I kind of love it.&lt;/p&gt;
&lt;p&gt;The price obviously seems really high for a file explorer, but apparently it’s taken the developer 3 years to get to this point. You can also pay $50 but that only gets you a years worth of updates.&lt;/p&gt;
&lt;p&gt;This project has got me thinking about an alternate reality where you have to pay for basic features of the OS. What if each program like notepad, paint, or task manager were priced this way? Or worse you had to pay a subscription! I’m actually shocked we didn’t end up in this world. Thankfully nerds write software for the love of the game and give it away. This puts downward pressure on the bugs corps to not nickel and dime software. All that said, I’m happy the file pilot dev values their own work and has priced this tool accordingly. If nothing else, I think it shows the windows team how software should run (fast) with few dependencies.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://linkblog.blob.core.windows.net/images/2026/01/08/03/42/23/IMG_7526.png&quot;&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2026/01/08/03/42/23/IMG_7526.png&quot; alt=&quot;Screenshot&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/01/07/file-pilot" rel="alternate"/><published>2026-01-08T03:41:04.2778750+00:00</published><category term="windows" /><category term="software" /></entry><entry><id>https://davidjarman.net/archive/2026/01/05/dotnet-dev-wsl-ubuntu</id><title>Setting up a dotnet dev environment with WSL and Ubuntu 24.04</title><updated>2026-01-06T17:32:13.2976590+00:00</updated><content type="html">&lt;p&gt;I just knew 2026 was going to start off this way... A complicated setup to do something that should be simple.&lt;/p&gt;
&lt;p&gt;Ok, so you want to do some .NET dev work with &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/wsl/about&quot;&gt;WSL&lt;/a&gt;? Better not choose Ubuntu 24.04 as your distro. I guess this version doesn&#39;t ship with some important packages that are needed to make some interop work between Windows and Linux. Anyways, let&#39;s get to the steps!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configure Git for authentication with Azure DevOps&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure you have installed Git For Windows on your host machine. Your git installed in Linux will need to use the credential manager in Windows.&lt;/li&gt;
&lt;li&gt;Configure the credential helper: git config --global credential.helper &amp;quot;/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe&amp;quot;&lt;/li&gt;
&lt;li&gt;Configure using HTTP: git config --global credential.https://dev.azure.com.useHttpPath true&lt;/li&gt;
&lt;li&gt;Clone a repo hosted in Azure DevOps&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Install Dotnet&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install dotnet: wget &lt;a href=&quot;https://dot.net/v1/dotnet-install.sh&quot;&gt;https://dot.net/v1/dotnet-install.sh&lt;/a&gt; -O dotnet-install.sh &amp;amp;&amp;amp; chmod +x ./dotnet-install.sh &amp;amp;&amp;amp; ./dotnet-install.sh --jsonfile global.json&lt;/li&gt;
&lt;li&gt;Edit ~/.bashrc to add dotnet to the PATH&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;export DOTNET_ROOT=$HOME/.dotnet
export PATH=$PATH:$DOTNET_ROOT:$DOTNET_ROOT/tools
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Configure dotnet for authentication with Azure DevOps&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;a href=&quot;https://github.com/microsoft/artifacts-credprovider&quot;&gt;Artifacts CredProvider&lt;/a&gt;: wget -qO- &lt;a href=&quot;https://aka.ms/install-artifacts-credprovider.sh&quot;&gt;https://aka.ms/install-artifacts-credprovider.sh&lt;/a&gt; | bash&lt;/li&gt;
&lt;li&gt;Set environment variable in ~/.bashrc to force a dialog to popup for authentication so you don&#39;t end up using Device Flow (which some tenants, like mine, disallow)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;export NUGET_CREDENTIALPROVIDER_FORCE_CANSHOWDIALOG_TO=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Install packages that allow the browser to be opened from MSAL&lt;/strong&gt;This part is crucial. When you run dotnet restore --interactive, MSAL will want to open your system&#39;s browser so you can use OAuth to sign in and provide credentials for your Azure DevOps instance. Install these packages, which no longer ship with Ubuntu:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;apt update&lt;/li&gt;
&lt;li&gt;apt install xdg-utils&lt;/li&gt;
&lt;li&gt;apt install wslu&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/wslutilities/wslu&quot;&gt;wslu&lt;/a&gt; is a discontinued project that consisted of utilities for WSL and xdg-open is a program that will open the system&#39;s browser.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit: If WSL interop stops working&lt;/strong&gt;You may need to add a WSL interop config (&lt;a href=&quot;https://github.com/microsoft/WSL/issues/8843#issuecomment-1337127239&quot;&gt;source&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /usr/lib/binfmt.d/WSLInterop.conf
Add this line:
:WSLInterop:M::MZ::/init:PF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, restart systemd-binfmt&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart systemd-binfmt 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Final step&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet restore --interactive
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should open your browser and you can sign in and restore packages! This only took me a full morning to figure out :(&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://linkblog.blob.core.windows.net/images/2026/01/05/21/49/33/elmo.gif&quot;&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2026/01/05/21/49/33/elmo.gif&quot; alt=&quot;me in 2026&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.microsoft.com/en-us/windows-server/blog/2015/05/06/microsoft-loves-linux&quot;&gt;Microsoft Loves Linux - Microsoft Windows Server Blog&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/01/05/dotnet-dev-wsl-ubuntu" rel="alternate"/><published>2026-01-05T21:49:52.5319310+00:00</published><category term="programming" /><category term="ubuntu" /><category term="wsl" /><category term="dotnet" /><category term="linux" /></entry><entry><id>https://davidjarman.net/archive/2026/01/04/gifs</id><title>GIFs!</title><updated>2026-01-05T06:28:54.6433640+00:00</updated><content type="html">&lt;p&gt;I added GIF support today. And now that I have to go back to work tomorrow, I’ll be using this one multiple times a day again&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://linkblog.blob.core.windows.net/images/2026/01/05/06/28/31/IMG_7524.gif&quot;&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2026/01/05/06/28/31/IMG_7524.gif&quot; alt=&quot;Elmo Fire&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/01/04/gifs" rel="alternate"/><published>2026-01-05T06:28:54.6433640+00:00</published><category term="gifs" /></entry><entry><id>https://davidjarman.net/archive/2026/01/04/llm-side-effects</id><title>LLMs - unexpected side effects</title><updated>2026-01-04T16:25:27.1822590+00:00</updated><content type="html">&lt;p&gt;+1 to what Simon is saying. I’ve been able to do a lot more on side projects now especially as a busy parent. I will kick off a prompt on Claude code (on my phone sometimes with Claude code web) and then go back to playing with my daughter or cooking or dishes. I can prototype ideas I have and look at the results whenever I have time. It’s really made me fall in love with programming again! I just wish I could find a better workflow for it at work. I’m struggling to get out of the “small toy projects” phase and into using it on larger projects. Probably less of a me problem and more of a tech / organization problem.&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2026/01/04/llm-side-effects" rel="alternate"/><published>2026-01-04T16:23:49.4273400+00:00</published><category term="llms" /><category term="claude" /><category term="ai" /></entry><entry><id>https://davidjarman.net/archive/2025/12/30/split-mkv-by-chapter-ffmpeg</id><title>Splitting MKV files by chapter using ffmpeg</title><updated>2025-12-31T04:26:21.6286170+00:00</updated><content type="html">&lt;p&gt;Created a small PowerShell scripts to split up MKV files by chapters. I wanted to avoid downloading yet another tool (handbrake or MKVToolNix) and I like the idea that I can use ffmpeg to do everything. For context, I have a DVD of Weird Al&#39;s ultimate music video collection that I got in middle school that I want available in Plex. I used MakeMKV to rip the DVD but all the music videos are in a single file, separated by chapters.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://linkblog.blob.core.windows.net/images/2025/12/31/04/26/13/image.png&quot;&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2025/12/31/04/26/13/image.png&quot; alt=&quot;Weird Al&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2025/12/30/split-mkv-by-chapter-ffmpeg" rel="alternate"/><published>2025-12-31T04:25:47.7829890+00:00</published><category term="tools" /><category term="powershell" /><category term="ffmpeg" /></entry><entry><id>https://davidjarman.net/archive/2025/12/26/yoto-player-image-gen</id><title>Yoto Player Image Converter</title><updated>2025-12-26T17:59:55.7703320+00:00</updated><content type="html">&lt;p&gt;Santa brought my daughter a &lt;a href=&quot;https://us.yotoplay.com/&quot;&gt;Yoto player&lt;/a&gt; so she can choose the music she listens to. The music is linked to cards that you insert to the player. The cards don&#39;t hold any actual data are instead just an NFC chip that tells the player what music and artwork to download and play. It&#39;s a clever little device and I really like it so far. Another great feature is that you can create custom cards from MP3s and your own pixel artwork.&lt;/p&gt;
&lt;p&gt;My daughter is obsessed with Marty Robbins &amp;quot;Gunfighter Ballads and Trail Songs&amp;quot;. It&#39;s a really great album that we listen to on vinyl all the time. So my first task on Christmas was to load a custom card with the album and make some custom artwork. I won&#39;t go into detail on how I did the MP3s, but for the background image, I decided to vibe code a tool to take an image and downscale it to a 16x16 pixel png file. I used Claude Code to create the tool and had to go through quite a few iterations to work the bugs out of the crop selection tool.&lt;/p&gt;
&lt;p&gt;Anyways, here is the final result showing good ol&#39; Marty going for his &amp;quot;Big Iron&amp;quot; on the Yoto!
&lt;a href=&quot;https://linkblog.blob.core.windows.net/images/2025/12/26/17/52/33/C574CE5A-C745-4BDB-970E-68E8C483E764_1_102_o.png&quot;&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2025/12/26/17/52/33/C574CE5A-C745-4BDB-970E-68E8C483E764_1_102_o.png&quot; alt=&quot;Yoto Player Background&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2025/12/26/yoto-player-image-gen" rel="alternate"/><published>2025-12-26T17:59:55.7703320+00:00</published><category term="tools" /><category term="hacks" /><category term="toys" /></entry><entry><id>https://davidjarman.net/archive/2025/12/17/aspire-13-1</id><title>Aspire 13.1</title><updated>2025-12-18T06:27:46.6208460+00:00</updated><content type="html">&lt;p&gt;Another minor release from the Aspire team. I&#39;ve updated the blog to use it, which you can see here: &lt;a href=&quot;https://github.com/david-jarman/link-blog/pull/8&quot;&gt;https://github.com/david-jarman/link-blog/pull/8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s the main highlight for me:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automatic instance deletion&lt;/strong&gt; - I&#39;m always running multiple shell instances and often I&#39;ll forget I already had aspire running somewhere else. This new feature will let me run aspire again from anywhere and stop the other instance instead of getting an error!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://linkblog.blob.core.windows.net/images/2025/12/18/06/21/57/autodelete.png&quot;&gt;&lt;img src=&quot;https://linkblog.blob.core.windows.net/images/2025/12/18/06/21/57/autodelete.png&quot; alt=&quot;Screenshot&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2025/12/17/aspire-13-1" rel="alternate"/><published>2025-12-18T06:27:35.0213820+00:00</published><category term="aspire" /><category term="dotnet" /></entry><entry><id>https://davidjarman.net/archive/2025/12/17/aspire-ef-core-migration</id><title>FYI: Automatically apply EF core migrations in Aspire</title><updated>2025-12-18T05:58:27.4649320+00:00</updated><content type="html">&lt;p&gt;If you are using Aspire and EF core to manage the schema of your database, this documentation is a great starting place to make the two work together.&lt;/p&gt;
&lt;p&gt;The core concept is that you add a worker service that is dedicated to running migrations, creating the initial database, and seeding data to the database. Essentially any operation that should be performed before the actual web app starts up. I implemented this in the blog this evening with the help of Claude Code while I watched Twin Peaks.&lt;/p&gt;
&lt;p&gt;One prerequisite was that I had to move my DbContext and Entity classes to a shared library so that the web app and worker services could both access them. I had actually tried to do this when I first created the blog but ran into issues and decided to simplify the design. I first told Claude to separate out the database entities, migrations, and contexts to a separate project. I was surprised how long this actually took. But in the end, something like 20+ files were touched, but all tests passed and the changes looked good.&lt;/p&gt;
&lt;p&gt;Next, I started a new chat with Claude (/new command), and gave it the same link provided in this post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Follow the instructions at the following url to automatically apply migrations when running locally: &lt;a href=&quot;https://aspire.dev/integrations/databases/efcore/migrations/&quot;&gt;https://aspire.dev/integrations/databases/efcore/migrations/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It then proceeded to one-shot the changes and everything just worked. Here are the full changes: &lt;a href=&quot;https://github.com/david-jarman/link-blog/pull/7&quot;&gt;https://github.com/david-jarman/link-blog/pull/7&lt;/a&gt;&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2025/12/17/aspire-ef-core-migration" rel="alternate"/><published>2025-12-18T05:58:27.4649320+00:00</published><category term="fyi" /><category term="aspire" /><category term="dotnet" /></entry><entry><id>https://davidjarman.net/archive/2025/12/16/dotnet-outdated-tool</id><title>FYI: dotnet-outdated</title><updated>2025-12-17T04:08:04.2984970+00:00</updated><content type="html">&lt;p&gt;I hate having to update package dependencies in projects. Fortunately there is a handy dotnet tool that will report and update packages that are out of date. I used this to update all the packages in the link-blog source code this evening and was pleasantly surprised it just worked. Only issue I found was that because I create a msbuild property to store the OpenTelemetry version (there are three OTel packages with the same version), the tool updated the PackageVersions directly instead of just updating the property. Not a big deal, and I would have been shocked if it was able to handle a corner case like that.&lt;/p&gt;
&lt;p&gt;Now I need to see if I can get this to run as a daily CI task.&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2025/12/16/dotnet-outdated-tool" rel="alternate"/><published>2025-12-17T04:08:04.2984970+00:00</published><category term="fyi" /><category term="tools" /><category term="dependencies" /><category term="dotnet" /></entry><entry><id>https://davidjarman.net/archive/2025/12/13/music-theory-interval-trainer</id><title>Music theory - Interval trainer</title><updated>2025-12-14T04:08:55.6939740+00:00</updated><content type="html">&lt;p&gt;Over the past few months, I have been getting back into playing guitar after a fairly long hiatus. I even started taking guitar lessons. My practice has involved playing a lot of bluegrass fiddle tunes and learning carter-style arrangements of old country and bluegrass songs.&lt;/p&gt;
&lt;p&gt;Playing bluegrass with others involves playing solos, or &amp;quot;taking breaks&amp;quot;. This just means improvising over the melody of the song. As I&#39;ve been inching closer toward working on my own improvisational skills, I&#39;ve realized that I don&#39;t have as much intuition about what each interval in the chromatic scale truly sounds like. I want to get to the point where I can listen to a song and recognize when the 4th chord is played vs the 5th or in a break when someone adds in a flat 5.&lt;/p&gt;
&lt;p&gt;To help myself train my ear to recognize each interval, I vibe coded a tool using Claude code. The page has two main parts: play each interval at your own pace and a quiz that will play intervals at random and you have to choose the correct one. I also added some descriptions to the intervals to help myself think about what those intervals feel like. There is also a toggle to show the &amp;quot;blue notes&amp;quot;.&lt;/p&gt;
&lt;p&gt;This is one part of my journey to being able to both improvise better but also transcribe music faster.&lt;/p&gt;
</content><link href="https://davidjarman.net/archive/2025/12/13/music-theory-interval-trainer" rel="alternate"/><published>2025-12-14T04:08:55.6939740+00:00</published><category term="theory" /><category term="tools" /><category term="hacks" /><category term="music" /></entry><entry><id>https://davidjarman.net/archive/2025/11/12/david-fowler-aspire-version</id><title>Quoting David Fowler</title><updated>2025-11-12T16:57:28.2645220+00:00</updated><content type="html">&lt;blockquote&gt;
&lt;p&gt;13 is bigger than 10 and less than 14 and is a prime number. The versioning scheme signifies a break away from .NET versioning and a direction change in the product to be evergreen (latest version is what matters) and going polyglot&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidfowl&quot;&gt;David Fowler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><link href="https://davidjarman.net/archive/2025/11/12/david-fowler-aspire-version" rel="alternate"/><published>2025-11-12T16:57:28.2645220+00:00</published><category term="quotes" /><category term="aspire" /><category term="dotnet" /></entry></feed>