<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>svnscha - productivity</title>
    <subtitle>automating annoying tasks, sharing tips, and embracing less frustration</subtitle>
    <link rel="self" type="application/atom+xml" href="https://svnscha.de/tags/productivity/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://svnscha.de"/>
    <generator uri="https://astro.build/">Astro</generator>
    <updated>2026-06-07T00:00:00+00:00</updated>
    <id>https://svnscha.de/tags/productivity/atom.xml</id>
    <entry xml:lang="en">
        <title>Introducing Native Windows Debugging for VS Code: Kernel &amp; Remote Debugging</title>
        <published>2026-06-07T00:00:00+00:00</published>
        <updated>2026-06-07T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/native-windows-kernel-remote-debugging-vscode/"/>
        <id>https://svnscha.de/posts/native-windows-kernel-remote-debugging-vscode/</id>
        <summary type="html">Last time I had a proof of concept. This time I closed the gap: remote debugging and Windows kernel debugging, straight from VS Code, powered by the same engine as WinDbg. It's open source and on the Marketplace.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/native-windows-kernel-remote-debugging-vscode/">&lt;h2 id=&quot;remember-the-cliffhanger&quot;&gt;Remember the Cliffhanger?&lt;/h2&gt;
&lt;p&gt;A while back I wrote about &lt;a href=&quot;/posts/the-joy-of-writing-a-debugger-adapter-for-visual-studio-code/&quot;&gt;the joy of writing a debugger adapter for Visual Studio Code&lt;/a&gt;. It started with a simple wish - I just wanted a faster way to remote-debug a service running in a VM - and ended with a working proof of concept: VS Code driving WinDbg through a custom Debug Adapter Protocol implementation.&lt;/p&gt;
&lt;p&gt;But that post ended on an honest note:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have not implemented remote debugging or kernel debugging yet, but I now feel ready to take a real shot at both without getting lost in the basics again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well. I took the shot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remote debugging works. Kernel debugging works.&lt;/strong&gt; And the whole thing is now a real, installable VS Code extension: &lt;strong&gt;Native Windows Debugging (dbgeng)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Debug native Windows code - C and C++ programs, services, and even the Windows kernel - straight from Visual Studio Code, using the same engine that powers WinDbg.&lt;/p&gt;
&lt;div style=&quot;position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:1.5rem 0;&quot;&gt;
  &lt;iframe style=&quot;position:absolute;top:0;left:0;width:100%;height:100%;border:0;&quot; src=&quot;https://www.youtube-nocookie.com/embed/bEuCPRmjE8o&quot; title=&quot;Native Windows Debugging (dbgeng) for VS Code&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;That's the whole pitch in under two minutes. Now let me show you what's behind it.&lt;/p&gt;
&lt;h2 id=&quot;get-it-right-now&quot;&gt;Get It Right Now&lt;/h2&gt;
&lt;p&gt;No waiting, no building from source:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Marketplace:&lt;/strong&gt; &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=svnscha.vscode-dap-dbgeng&quot;&gt;Native Windows Debugging (dbgeng)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href=&quot;https://github.com/svnscha/dap-dbgeng&quot;&gt;github.com/svnscha/dap-dbgeng&lt;/a&gt; (MIT licensed)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href=&quot;https://svnscha.github.io/dap-dbgeng/&quot;&gt;svnscha.github.io/dap-dbgeng&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The adapter is &lt;strong&gt;bundled inside the extension&lt;/strong&gt;, so there's nothing separate to build, download, or point at. Install it, write a &lt;code&gt;launch.json&lt;/code&gt;, press &lt;kbd&gt;F5&lt;/kbd&gt;. That's it.&lt;/p&gt;
&lt;h2 id=&quot;four-ways-to-debug---two-of-them-were-never-possible-before&quot;&gt;Four Ways to Debug - Two of Them Were Never Possible Before&lt;/h2&gt;
&lt;p&gt;VS Code has always had great local debugging for plenty of languages. But the moment you wanted &lt;em&gt;native Windows&lt;/em&gt; remote or kernel debugging, you hit a wall. That stack lives in Visual Studio and WinDbg, not in VS Code - because of course it does.&lt;/p&gt;
&lt;p&gt;This extension closes exactly that gap. One adapter, four scenarios:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Local&lt;/strong&gt; - the debugger starts your program and debugs it from launch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attach&lt;/strong&gt; - connect to a process that's already running, by its PID.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote&lt;/strong&gt; - debug a user-mode process on &lt;em&gt;another&lt;/em&gt; machine via &lt;code&gt;dbgsrv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kernel&lt;/strong&gt; - debug kernel-mode drivers and the OS around them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first two are the comfortable ones. The last two are the gap I set out to close. Let's walk through them.&lt;/p&gt;
&lt;h2 id=&quot;local-the-comfortable-starting-point&quot;&gt;Local: The Comfortable Starting Point&lt;/h2&gt;
&lt;p&gt;Start simple. The debugger launches your program and you step through it like any other debugger in VS Code. It's just a &lt;code&gt;launch.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Debug myapp&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;dbgeng&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;request&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;launch&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;program&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;${workspaceFolder}/build/Debug/myapp.exe&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;stopAtEntry&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;program&lt;/code&gt; is the only thing you really have to provide. &lt;code&gt;dbgeng.dll&lt;/code&gt; is found automatically from your installed Windows SDK, so you usually don't even set a path. Set a breakpoint, press &lt;kbd&gt;F5&lt;/kbd&gt;, and you get the full loop: continue, step over, step into, step out, call stack, locals, watch expressions, and a Debug Console that evaluates expressions through the real engine.&lt;/p&gt;
&lt;p&gt;If you use the &lt;strong&gt;CMake Tools&lt;/strong&gt; extension, you can even drop the &lt;code&gt;program&lt;/code&gt; line entirely - the adapter defaults to your selected CMake launch target. Point CMake's debug command at the &lt;code&gt;dbgeng&lt;/code&gt; type and &lt;strong&gt;CMake: Debug&lt;/strong&gt; just works.&lt;/p&gt;
&lt;h2 id=&quot;attach-already-running-just-connect&quot;&gt;Attach: Already Running? Just Connect&lt;/h2&gt;
&lt;p&gt;Sometimes the process is already alive and you don't want to restart it. Attach to it by its process ID:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Attach to myapp&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;dbgeng&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;request&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;attach&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;processId&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;12345&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don't know the PID off the top of your head? Set &lt;code&gt;&quot;processId&quot;: &quot;${command:dap-dbgeng.pickProcess}&quot;&lt;/code&gt; and you get a process picker at debug time. Same familiar VS Code interface, with the real Windows debug engine underneath.&lt;/p&gt;
&lt;h2 id=&quot;remote-my-favorite-part&quot;&gt;Remote: My Favorite Part&lt;/h2&gt;
&lt;p&gt;This was the first scenario I implemented: debugging a user-mode process on &lt;strong&gt;another machine&lt;/strong&gt; while keeping the debug engine and symbols on the local system.&lt;/p&gt;
&lt;p&gt;The trick is the Windows process server, &lt;code&gt;dbgsrv&lt;/code&gt;. You run it on the target, and your machine connects to it over TCP (or a named pipe).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On the target&lt;/strong&gt;, start the process server:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;cmd&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;dbgsrv -t tcp:port=&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;5005&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;On your machine&lt;/strong&gt;, point a &lt;code&gt;launch.json&lt;/code&gt; at it:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Attach on TARGETPC&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;dbgeng&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;request&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;attach&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;processId&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;${command:dap-dbgeng.pickProcess}&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;connectionString&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;tcp:port=5005,server=TARGETPC&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Press &lt;kbd&gt;F5&lt;/kbd&gt;, pick the remote process from the list (the picker now shows processes on the &lt;code&gt;dbgsrv&lt;/code&gt; host), and you're debugging it remotely. The engine and symbols never leave your machine - only the debuggee lives on the other side.&lt;/p&gt;
&lt;p&gt;This is precisely the workflow I wanted at the very beginning: compile locally, deploy to the VM, attach, get back to work. Now it's a one-keystroke thing.&lt;/p&gt;
&lt;h2 id=&quot;kernel-yes-really&quot;&gt;Kernel: Yes, Really&lt;/h2&gt;
&lt;p&gt;And then there's the big one. &lt;strong&gt;Kernel-mode debugging from VS Code.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kernel debugging is whole-machine, so you need two boxes: a &lt;strong&gt;host&lt;/strong&gt; (VS Code + the adapter) and a &lt;strong&gt;target&lt;/strong&gt; being debugged - almost always a throwaway VM, because kernel debugging halts the entire target at breakpoints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On the target&lt;/strong&gt;, enable kernel debugging and reboot:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;cmd&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;bcdedit&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; /debug on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;bcdedit&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; /dbgsettings &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;net&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; hostip:&amp;lt;HOST-IP&amp;gt; port:50005 key:1.2.3.4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;On the host&lt;/strong&gt;, point a kernel config at it:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Debug driver (KDNET)&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;dbgeng&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;request&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;attach&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;kernel&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;connectionString&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;net:port=50005,key=1.2.3.4&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;kernel: true&lt;/code&gt; flips the adapter into kernel mode and turns &lt;code&gt;connectionString&lt;/code&gt; into a kernel transport. There's no &lt;code&gt;processId&lt;/code&gt; here - the session &lt;em&gt;is&lt;/em&gt; the whole machine. Press &lt;kbd&gt;F5&lt;/kbd&gt;, it connects over KDNET, and breaks at &lt;code&gt;DriverEntry&lt;/code&gt;. From the same editor people keep telling me is &quot;just a text editor.&quot;&lt;/p&gt;
&lt;p&gt;Kernel debugging. Just another breakpoint. That still feels a little unreal to type.&lt;/p&gt;
&lt;p&gt;KDNET isn't the only option, either - the same &lt;code&gt;connectionString&lt;/code&gt; field speaks serial (named pipe), 1394, and USB transports too. Whatever your VM or test box gives you.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;
&lt;p&gt;A few things changed since the proof of concept, and they're worth a mention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It talks to the engine natively.&lt;/strong&gt; The adapter uses the real DbgEng APIs throughout - &lt;code&gt;IDebugClient&lt;/code&gt;, &lt;code&gt;IDebugControl&lt;/code&gt;, &lt;code&gt;IDebugSymbols&lt;/code&gt;, &lt;code&gt;IDebugSystemObjects&lt;/code&gt;, with &lt;code&gt;IDebugEventCallbacks&lt;/code&gt; and &lt;code&gt;IDebugOutputCallbacks&lt;/code&gt; for events. No fragile text-scraping of WinDbg console output. When the engine knows something, the adapter asks it directly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The protocol layer is still generated.&lt;/strong&gt; That code-generation step I was so happy about last time paid off again. &lt;code&gt;src/protocol/&lt;/code&gt; is generated from the official DAP schema, so every request, response, and event stays in lockstep with the spec instead of drifting from hand-written DTOs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The POC grew up - and changed language.&lt;/strong&gt; The original proof of concept was C#. Hardening it into something I'd actually ship meant rebuilding the adapter in &lt;strong&gt;C++20&lt;/strong&gt; (CMake + Ninja, vcpkg manifest mode), sitting much closer to the engine it wraps. That was part of the &quot;harden the rough edges&quot; plan, and it made the kernel and remote work far less painful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It records itself.&lt;/strong&gt; There's a built-in session-trace recorder that doubles as the project's replay-test format. Recorded sessions get replayed against real test debuggees in CI, so the behaviors you see in those videos are the same behaviors the test suite asserts on.&lt;/p&gt;
&lt;h2 id=&quot;an-honest-word-on-scope&quot;&gt;An Honest Word on Scope&lt;/h2&gt;
&lt;p&gt;I'm keeping the same promise I made in the first post: the adapter advertises only what it implements &lt;em&gt;correctly&lt;/em&gt;, rather than dangling buttons that misbehave.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What works today:&lt;/strong&gt; line and conditional breakpoints, step over/into/out, continue, pause, instruction-level stepping in the disassembly view, call stack with delayed frame loading, variables and scopes (including registers), set-variable, expression evaluation in the Watch pane and Debug Console, disassembly view, and clean terminate/disconnect.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's planned but not advertised yet:&lt;/strong&gt; function breakpoints, data breakpoints (watchpoints), hit-conditional breakpoints, logpoints, read/write memory, a modules view, evaluate-on-hover, and hex formatting toggles. The engine can do all of these - the adapter just doesn't expose them yet. The &lt;a href=&quot;https://svnscha.github.io/dap-dbgeng/reference/features/&quot;&gt;features reference&lt;/a&gt; keeps the full, deliberately conservative list.&lt;/p&gt;
&lt;p&gt;And here's the escape hatch: anything the UI doesn't surface, you can usually still do by typing native debugger commands straight into the Debug Console. It's the real engine - it'll answer.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;If you want to try it, the whole loop is about ten minutes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;strong&gt;Native Windows Debugging (dbgeng)&lt;/strong&gt; from the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=svnscha.vscode-dap-dbgeng&quot;&gt;Marketplace&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure you have &lt;strong&gt;Debugging Tools for Windows&lt;/strong&gt; (it ships &lt;code&gt;dbgeng.dll&lt;/code&gt;, via the Windows SDK or WDK installer). The adapter finds it automatically.&lt;/li&gt;
&lt;li&gt;Drop a &lt;code&gt;dbgeng&lt;/code&gt; configuration into &lt;code&gt;.vscode/launch.json&lt;/code&gt; - pick the scenario from above.&lt;/li&gt;
&lt;li&gt;Set a breakpoint, press &lt;kbd&gt;F5&lt;/kbd&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;a href=&quot;https://svnscha.github.io/dap-dbgeng/getting-started/&quot;&gt;Getting Started guide&lt;/a&gt; walks through it in detail, and each scenario has its own page in the docs.&lt;/p&gt;
&lt;h2 id=&quot;your-turn&quot;&gt;Your Turn&lt;/h2&gt;
&lt;p&gt;This is open source, and it's at the stage where real-world usage is the most valuable thing it can get. So:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⭐ &lt;strong&gt;Star it&lt;/strong&gt; on &lt;a href=&quot;https://github.com/svnscha/dap-dbgeng&quot;&gt;GitHub&lt;/a&gt; if it's useful to you.&lt;/li&gt;
&lt;li&gt;🐛 &lt;strong&gt;Report a bug&lt;/strong&gt; through the &lt;a href=&quot;https://github.com/svnscha/dap-dbgeng/issues&quot;&gt;issue tracker&lt;/a&gt; - the templates tell you what to include.&lt;/li&gt;
&lt;li&gt;🔧 &lt;strong&gt;Contribute&lt;/strong&gt; if you're into native Windows debugging internals; see &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Last time I closed with &quot;I just want to remote debug a service on a VM.&quot; That was the entire ambition.&lt;/p&gt;
&lt;p&gt;It turned into DAP, a code generator, a &lt;code&gt;dbgeng&lt;/code&gt; wrapper, a pile of state-machine bugs - and now remote debugging, kernel debugging, a published extension, and a documentation site.&lt;/p&gt;
&lt;p&gt;The gap between &quot;VS Code can't do native Windows kernel and remote debugging&quot; and &quot;actually, now it can&quot; is closed. With the same engine that powers WinDbg, sitting quietly behind the editor you already use every day.&lt;/p&gt;
&lt;p&gt;And yes - it still started with &quot;I just want to remote debug a service on a VM.&quot;&lt;/p&gt;
&lt;h2 id=&quot;ps---one-more-thing-about-those-videos&quot;&gt;P.S. - One More Thing About Those Videos&lt;/h2&gt;
&lt;p&gt;While you're here: how did you actually like the videos? Be honest.&lt;/p&gt;
&lt;p&gt;Because here's the fun part - this is the first time I generated end-to-end videos, all the way from Claude to YouTube. No editing suite, no timeline scrubbing, no manual voiceover takes. Just prompting and vibing until it looked right.&lt;/p&gt;
&lt;p&gt;The stack, if you're curious:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.remotion.dev/&quot;&gt;Remotion&lt;/a&gt;&lt;/strong&gt; for the video itself - everything you see is React, rendered to MP4. Code as video turns out to be a really nice fit for the &quot;iterate fast&quot; loop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;My &lt;a href=&quot;/posts/dgx-spark-hello-word/&quot;&gt;DGX Spark&lt;/a&gt;&lt;/strong&gt; doing the heavy lifting locally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/OpenMOSS/MOSS-TTS&quot;&gt;MOSS-TTS&lt;/a&gt;&lt;/strong&gt; for the voice. And here's a little detour: I first deep-cloned &lt;em&gt;my own&lt;/em&gt; voice. The result was genuinely impressive - but not quite perfect, and the &quot;almost me&quot; uncanny gap bugged me more than I expected. So I switched to a fully synthesized voice instead, and I was happier with that than with a not-quite-right clone of myself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think that's pretty cool. A little surreal, honestly. The same &quot;describe what you want, iterate, ship&quot; loop that built the debugger also produced the launch video for it.&lt;/p&gt;
&lt;p&gt;So let me know what you think - of the extension &lt;em&gt;and&lt;/em&gt; of the videos. What worked, what felt off, what you'd want next. There's no comment box here, so just &lt;strong&gt;hit me up&lt;/strong&gt; (&lt;a href=&quot;https://www.linkedin.com/in/svnscha/&quot;&gt;LinkedIn&lt;/a&gt; or &lt;a href=&quot;https://github.com/svnscha/&quot;&gt;GitHub&lt;/a&gt;) or open an issue. I'm genuinely curious.&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>The Joy of Writing a Debugger Adapter for Visual Studio Code</title>
        <published>2026-04-15T00:00:00+00:00</published>
        <updated>2026-04-15T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/the-joy-of-writing-a-debugger-adapter-for-visual-studio-code/"/>
        <id>https://svnscha.de/posts/the-joy-of-writing-a-debugger-adapter-for-visual-studio-code/</id>
        <summary type="html">I only wanted a faster remote debugging workflow for a service running in a VM. Instead, I ended up learning DAP, wrapping WinDbg, and building a working first proof of concept debugger adapter for VS Code.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/the-joy-of-writing-a-debugger-adapter-for-visual-studio-code/">&lt;h2 id=&quot;current-state&quot;&gt;Current State&lt;/h2&gt;
&lt;p&gt;Before I get into the story, here is the current result: Visual Studio Code debugging a C++ application with WinDbg under the hood through my first proof of concept integration.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/screenshots/2026-04-15-dap-windbg.png&quot; alt=&quot;WinDbg running through the VS Code debugger adapter&quot;&gt;&lt;/p&gt;
&lt;p&gt;Right now this is still an early POC, not a finished debugger experience. It proves the architecture works and that VS Code can drive WinDbg through a custom adapter, but it still needs a lot more iteration before I would call it really useful.&lt;/p&gt;
&lt;p&gt;One detail I already like is that the debugger command window is not a fake simplified console. I can type regular WinDbg commands straight into it.&lt;/p&gt;
&lt;h2 id=&quot;why&quot;&gt;Why&lt;/h2&gt;
&lt;p&gt;Because I do what I always do when a workflow annoys me: I build a tool until the annoyance goes away.&lt;/p&gt;
&lt;p&gt;This time the pain point was remote debugging a service application running inside a VM. My ideal flow was simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compile locally&lt;/li&gt;
&lt;li&gt;Deploy to the VM&lt;/li&gt;
&lt;li&gt;Start or restart the service&lt;/li&gt;
&lt;li&gt;Attach a debugger&lt;/li&gt;
&lt;li&gt;Get back to work without ten minutes of clicking around&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That sounded perfectly reasonable: a small helper extension for Visual Studio Code, a bit of automation, some launch configuration glue, and done.&lt;/p&gt;
&lt;p&gt;That was the plan.&lt;/p&gt;
&lt;p&gt;It did not stay the plan.&lt;/p&gt;
&lt;h2 id=&quot;removing-friction&quot;&gt;Removing Friction&lt;/h2&gt;
&lt;p&gt;I started with the pragmatic part first: automate the annoying steps.&lt;/p&gt;
&lt;p&gt;I wired up a helper extension that could compile the service, copy the binaries to the VM, and prepare the remote machine for debugging. This is my favorite kind of productivity work, because the payoff is immediate. Every bit of friction you remove saves time again and again.&lt;/p&gt;
&lt;p&gt;Once the plumbing was in place, I expected the final step to be easy: tell VS Code to remote debug the service and call it a day.&lt;/p&gt;
&lt;p&gt;Instead, I hit a wall.&lt;/p&gt;
&lt;h2 id=&quot;vs-code-is-not-visual-studio&quot;&gt;VS Code Is Not Visual Studio&lt;/h2&gt;
&lt;p&gt;At first glance, this feels like something that should already exist. Visual Studio has mature debugging capabilities. VS Code has debugging. Microsoft builds both. Surely there must be a supported path to do classic remote Windows debugging from VS Code, right?&lt;/p&gt;
&lt;p&gt;Not really.&lt;/p&gt;
&lt;p&gt;The more I dug into it, the clearer it became that the debugging stack in VS Code is a different world. VS Code speaks the Debug Adapter Protocol, or DAP. It expects debugger extensions to implement that protocol and sit between the editor and the actual debugger engine.&lt;/p&gt;
&lt;p&gt;That part is good. DAP is a clean idea.&lt;/p&gt;
&lt;p&gt;The frustrating bit was this: the specific native Windows remote-debugging flow I wanted was not available through a supported public route in VS Code. The Visual Studio native debugger stack is not something you can just plug into from your own VS Code extension and say, &quot;Thanks, I will take remote debugging from here.&quot; And the VS Code side does not magically inherit Visual Studio's remote debugging capabilities just because both products come from Microsoft.&lt;/p&gt;
&lt;p&gt;So after spending time exploring options, the conclusion was simple:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There was no supported way to get the workflow I wanted with the existing pieces.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-it-anyway&quot;&gt;Building It Anyway&lt;/h2&gt;
&lt;p&gt;Once I accepted that I would not be wiring together existing public APIs, the problem changed shape.&lt;/p&gt;
&lt;p&gt;The question was no longer, &quot;How do I enable remote debugging in VS Code?&quot;&lt;/p&gt;
&lt;p&gt;It became:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;What debugger engine can I control myself, and how do I make VS Code talk to it properly?&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That is where WinDbg entered the story.&lt;/p&gt;
&lt;p&gt;WinDbg already knows how to do the important parts. User-mode debugging. Remote debugging. Kernel debugging. Crash dump analysis. It is a serious tool with decades of capability behind it.&lt;/p&gt;
&lt;p&gt;But again, my tool of choice did not give me the VS Code experience I wanted out of the box.&lt;/p&gt;
&lt;p&gt;So the next step was clear:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build a debugger adapter for WinDbg.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;learning-dap&quot;&gt;Learning DAP&lt;/h2&gt;
&lt;p&gt;If you want to integrate a debugger with VS Code, DAP is the contract. Once I sat down and read it properly, a lot of things clicked.&lt;/p&gt;
&lt;p&gt;The official home for it is the &lt;a href=&quot;https://microsoft.github.io/debug-adapter-protocol/&quot;&gt;Debug Adapter Protocol website&lt;/a&gt;, and that site is worth bookmarking because it has both the overview and the actual specification. At the time I was working through this, the important mental model was simple: VS Code and the adapter exchange JSON messages with a very predictable shape, and the protocol defines what those messages are supposed to mean.&lt;/p&gt;
&lt;p&gt;The protocol is straightforward. VS Code sends requests like &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;launch&lt;/code&gt;, &lt;code&gt;attach&lt;/code&gt;, &lt;code&gt;setBreakpoints&lt;/code&gt;, &lt;code&gt;stackTrace&lt;/code&gt;, &lt;code&gt;variables&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, and so on, and your adapter answers them while emitting events like &lt;code&gt;initialized&lt;/code&gt;, &lt;code&gt;stopped&lt;/code&gt;, &lt;code&gt;continued&lt;/code&gt;, and &lt;code&gt;terminated&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That sounds simple enough until you remember that a debugger is mostly state, timing, and edge cases.&lt;/p&gt;
&lt;p&gt;Still, the protocol gave me exactly what I needed: a structured way to make VS Code think in terms of debugging, while I figured out how to translate that into WinDbg behavior.&lt;/p&gt;
&lt;p&gt;This was the moment where the project stopped being a helper extension and became a real debugger adapter.&lt;/p&gt;
&lt;p&gt;To make that a bit more concrete, a minimal launch payload for the current POC looks roughly like this:&lt;/p&gt;
&lt;p&gt;The adapter currently points at the debugging engine directly, so the &lt;code&gt;windbg&lt;/code&gt; setting names the WinDbg stack even though the configured path is &lt;code&gt;dbgeng.dll&lt;/code&gt; rather than &lt;code&gt;windbg.exe&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;dapwdbg&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;request&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;launch&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Launch through WinDbg&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;windbg&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/dbgeng.dll&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;program&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;${workspaceFolder}/build/Debug/testapp.exe&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;stopAtEntry&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;stopAtEntry&lt;/code&gt; flag is a small but useful quality-of-life feature. I added it because it is a familiar debugger option and useful to have. By default it is &lt;code&gt;false&lt;/code&gt;, so the adapter continues after &lt;code&gt;configurationDone&lt;/code&gt;. If you set it to &lt;code&gt;true&lt;/code&gt;, VS Code stays paused at entry and waits for the next command.&lt;/p&gt;
&lt;p&gt;And on the wire, the messages are simple, which is exactly what you want from a protocol. A stop event coming back from the adapter looks roughly like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;seq&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;17&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;event&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;event&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;stopped&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;	&quot;body&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;		&quot;reason&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;entry&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;		&quot;description&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Paused at process entry.&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;		&quot;threadId&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;		&quot;allThreadsStopped&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That might not look exciting, but it is the important part: once VS Code receives something in that shape at the right time, it knows how to show the stack, scopes, variables, and stepping UI around it.&lt;/p&gt;
&lt;h2 id=&quot;step-1-parse-the-schemas-instead-of-hand-writing-everything&quot;&gt;Step 1: Parse the Schemas Instead of Hand-Writing Everything&lt;/h2&gt;
&lt;p&gt;One thing became obvious very quickly: I did not want to manually model the entire protocol by hand in C#.&lt;/p&gt;
&lt;p&gt;That is the kind of task that feels fine for the first ten message types and becomes a waste of time by the next fifty.&lt;/p&gt;
&lt;p&gt;DAP is defined by schemas. Machines should read schemas. Machines should generate code. Humans should not write all of that by hand.&lt;/p&gt;
&lt;p&gt;So one of the first pieces I built was a small toolchain around the protocol definitions.&lt;/p&gt;
&lt;p&gt;The idea was straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Parse the protocol schemas&lt;/li&gt;
&lt;li&gt;Convert them into C# types&lt;/li&gt;
&lt;li&gt;Use generated models for requests, responses, events, and payloads&lt;/li&gt;
&lt;li&gt;Stop wasting time on repetitive plumbing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This bought me two things immediately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better consistency with the protocol&lt;/li&gt;
&lt;li&gt;Faster iteration whenever I needed to expand coverage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also reduced a whole category of annoying bugs where hand-written DTOs silently drift away from the spec.&lt;/p&gt;
&lt;p&gt;That generator phase was not glamorous, but it kept paying off. Every time I added another request handler later, I was very happy not to be hand-authoring another stack of protocol classes.&lt;/p&gt;
&lt;p&gt;The nice part is that the generated code stays very literal. For example, the generated &lt;code&gt;LaunchRequest&lt;/code&gt; model is basically just a strongly typed wrapper around the DAP shape, with &lt;code&gt;Command = &quot;launch&quot;&lt;/code&gt; baked in and a typed &lt;code&gt;Arguments&lt;/code&gt; property. A generated event model like &lt;code&gt;StoppedEvent&lt;/code&gt; then points at a generated &lt;code&gt;StoppedEventBody&lt;/code&gt; class with fields such as &lt;code&gt;Reason&lt;/code&gt;, &lt;code&gt;Description&lt;/code&gt;, &lt;code&gt;ThreadId&lt;/code&gt;, and &lt;code&gt;AllThreadsStopped&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That is exactly the level of abstraction I wanted. The protocol layer should be boring and explicit so the interesting work can happen one layer above it.&lt;/p&gt;
&lt;h2 id=&quot;step-2-a-python-generator-that-produces-c&quot;&gt;Step 2: A Python Generator That Produces C#&lt;/h2&gt;
&lt;p&gt;Yes, the adapter is in C#.&lt;/p&gt;
&lt;p&gt;Yes, I used Python to generate part of it.&lt;/p&gt;
&lt;p&gt;That combination made sense for the job. Python is still one of the fastest ways to build a transformation tool, especially when the task is basically: read structured input, normalize it, and generate source code.&lt;/p&gt;
&lt;p&gt;So I built a Python tool that parsed the protocol definitions and generated the corresponding C# code.&lt;/p&gt;
&lt;p&gt;That generator handled the boring but important parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Request and response classes&lt;/li&gt;
&lt;li&gt;Event payloads&lt;/li&gt;
&lt;li&gt;Shared protocol types&lt;/li&gt;
&lt;li&gt;Optional fields and enum-like shapes&lt;/li&gt;
&lt;li&gt;Enough structure to keep serialization predictable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This turned out to be one of the highest leverage steps in the whole project. Instead of spending my time on protocol plumbing, I could focus on the parts that actually matter: session management, command execution, state transitions, and debugger behavior.&lt;/p&gt;
&lt;p&gt;In other words, I automated the boring part so I could focus on the interesting part.&lt;/p&gt;
&lt;h2 id=&quot;step-3-wrap-windbg-through-dbgeng&quot;&gt;Step 3: Wrap WinDbg Through dbgeng&lt;/h2&gt;
&lt;p&gt;Once the protocol layer was under control, the next question was how to talk to the debugger engine itself.&lt;/p&gt;
&lt;p&gt;For that I went with &lt;code&gt;dbgeng&lt;/code&gt;, the Windows debugging engine behind the debugger family. That is where the real power is. It is also where some of the complexity is.&lt;/p&gt;
&lt;p&gt;On the package side, the current codebase still reflects some iteration. The wrapper layer currently leans on the public DbgEng interop exposed through the ClrMD packages &lt;code&gt;Microsoft.Diagnostics.Runtime&lt;/code&gt; and &lt;code&gt;Microsoft.Diagnostics.Runtime.Utilities&lt;/code&gt;. Separately, the broader adapter codebase also references &lt;code&gt;Microsoft.Debugging.Platform.DbgEng&lt;/code&gt; and &lt;code&gt;Microsoft.Debugging.Platform.DbgX&lt;/code&gt;, which are part of the newer Microsoft debugging platform stack. That split is real in the code today, but I do not want to pretend it is already the final architecture.&lt;/p&gt;
&lt;p&gt;In the wrapper itself, the core interfaces in use right now are &lt;code&gt;IDebugClient&lt;/code&gt;, &lt;code&gt;IDebugControl&lt;/code&gt;, &lt;code&gt;IDebugSymbols&lt;/code&gt;, and &lt;code&gt;IDebugSystemObjects&lt;/code&gt;. For callbacks, I register &lt;code&gt;IDebugEventCallbacks&lt;/code&gt; and &lt;code&gt;IDebugOutputCallbacks&lt;/code&gt;. That gives me the essential surface area I need to launch or attach, execute commands, inspect symbols, enumerate threads, and react to breakpoints, exceptions, exits, and debugger output.&lt;/p&gt;
&lt;p&gt;This wrapper layer became the core of the adapter. Its job was to expose the debugger in a way that fit the expectations of DAP rather than the expectations of a human typing commands into a debugger console.&lt;/p&gt;
&lt;p&gt;That means translating concepts like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launching or attaching to a target&lt;/li&gt;
&lt;li&gt;Resuming and breaking execution&lt;/li&gt;
&lt;li&gt;Enumerating threads&lt;/li&gt;
&lt;li&gt;Building stack traces&lt;/li&gt;
&lt;li&gt;Reading locals and variables&lt;/li&gt;
&lt;li&gt;Handling modules and symbols&lt;/li&gt;
&lt;li&gt;Surfacing exceptions, exits, and other stop reasons&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have ever worked with debugger APIs, you know they do not hide much complexity. You need to be explicit. You need to think about ownership, state, timing, callbacks, and edge cases that often show up only once things are already going wrong.&lt;/p&gt;
&lt;p&gt;One small example was line stepping. I had already enabled source line support and saw source locations show up, so for a moment I thought &lt;code&gt;step over&lt;/code&gt; was working.&lt;/p&gt;
&lt;p&gt;It did not.&lt;/p&gt;
&lt;p&gt;What I had actually proven was that WinDbg could show me line information. That is not the same thing as telling it to do source-based stepping. I had forgotten to enable that part as well. The fix was one extra command:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c#&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; EnableSourceLineSupport&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;	ThrowIfDisposed&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;	ExecuteDebuggerCommand&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;.lines -e&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Could not enable source line support&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;	ExecuteDebuggerCommand&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;l+t&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Could not enable source-based stepping&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was a very debugger-adapter kind of bug. Everything looked correct for just long enough to be misleading.&lt;/p&gt;
&lt;h2 id=&quot;step-4-implement-the-real-requests-and-iterate&quot;&gt;Step 4: Implement the Real Requests and Iterate&lt;/h2&gt;
&lt;p&gt;With the generated protocol types on one side and the WinDbg wrapper on the other, I could finally work on the adapter loop itself.&lt;/p&gt;
&lt;p&gt;At this point, the adapter was useful for actual debugging.&lt;/p&gt;
&lt;p&gt;I began with the core requests: &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;launch&lt;/code&gt;, &lt;code&gt;attach&lt;/code&gt;, &lt;code&gt;setBreakpoints&lt;/code&gt;, &lt;code&gt;configurationDone&lt;/code&gt;, &lt;code&gt;threads&lt;/code&gt;, &lt;code&gt;stackTrace&lt;/code&gt;, &lt;code&gt;scopes&lt;/code&gt;, &lt;code&gt;variables&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt;, &lt;code&gt;pause&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;stepIn&lt;/code&gt;, &lt;code&gt;stepOut&lt;/code&gt;, &lt;code&gt;disconnect&lt;/code&gt;, ...&lt;/p&gt;
&lt;p&gt;On paper that looks like a clean checklist. In reality, each of those requests is a conversation between at least three parties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VS Code and its expectations&lt;/li&gt;
&lt;li&gt;The adapter and its internal state machine&lt;/li&gt;
&lt;li&gt;The debugger engine and its current state&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the implementation loop looked roughly like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add one request&lt;/li&gt;
&lt;li&gt;Run it in VS Code&lt;/li&gt;
&lt;li&gt;Watch it fail in an interesting way&lt;/li&gt;
&lt;li&gt;Fix the translation layer&lt;/li&gt;
&lt;li&gt;Hit the next state mismatch&lt;/li&gt;
&lt;li&gt;Repeat until the experience works the way it should&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is also where you learn that &quot;technically works&quot; and &quot;feels right to use&quot; are not the same thing.&lt;/p&gt;
&lt;p&gt;It is not enough to answer the request. You have to answer it in the right order, at the right time, and with enough fidelity that the editor can build a coherent UI around it.&lt;/p&gt;
&lt;p&gt;That was one of the more interesting parts of the project.&lt;/p&gt;
&lt;p&gt;Here is a tiny slice of what that translation layer looks like today. After launch, the adapter records whether it should remain paused at entry or continue once VS Code finishes sending its setup messages:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c#&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_launchAwaitingConfigurationDone&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_launchStopAtEntry&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;DapArgumentReader&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;TryGetBoolean&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;stopAtEntry&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;	?? &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;DapArgumentReader&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;TryGetBoolean&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;stopOnEntry&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;	?? &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the kind of code that looks harmless until you realize it decides whether the whole session feels smooth or broken.&lt;/p&gt;
&lt;h2 id=&quot;when-it-worked&quot;&gt;When It Worked&lt;/h2&gt;
&lt;p&gt;At some point the pieces clicked together.&lt;/p&gt;
&lt;p&gt;I could launch a debugging session from VS Code, talk to WinDbg through the adapter, and use the editor as if this had always been a normal supported workflow.&lt;/p&gt;
&lt;p&gt;It also stopped being just about the original VM service scenario. Because the adapter sits on top of WinDbg, it opened the door to more than the first use case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Local launch and local attach already work in the adapter&lt;/li&gt;
&lt;li&gt;Dump-file attach is wired in&lt;/li&gt;
&lt;li&gt;Remote attach and kernel scenarios are the next serious end-to-end targets&lt;/li&gt;
&lt;li&gt;Crash dump debugging is now a realistic extension of the same architecture&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That was the point where the project started to feel solid.&lt;/p&gt;
&lt;h2 id=&quot;why-this-was-fun&quot;&gt;Why This Was Fun&lt;/h2&gt;
&lt;p&gt;This was fun for the same reason good tooling work is always fun: it changes how you work.&lt;/p&gt;
&lt;p&gt;You remove friction once, then benefit from it every day after that. And along the way, you learn where the real product boundaries are. Visual Studio and VS Code may look adjacent from the outside, but their debugging plumbing is very different. Once that became clear, the path forward became clear too.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot;&gt;What I Learned&lt;/h2&gt;
&lt;p&gt;This project taught me a few things very clearly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a workflow matters enough, it is often worth productizing it for yourself&lt;/li&gt;
&lt;li&gt;DAP is a really good abstraction for debugger integration&lt;/li&gt;
&lt;li&gt;Code generation is the right answer when a protocol brings lots of repetitive structure&lt;/li&gt;
&lt;li&gt;Debugger adapters are mostly about state, timing, and translation&lt;/li&gt;
&lt;li&gt;WinDbg becomes much more approachable when you put a good UX in front of it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also: if you think you fixed stepping, make sure you actually fixed it and did not just make the debugger show line numbers.&lt;/p&gt;
&lt;p&gt;Most importantly, I was reminded again that some of the best side projects start as practical attempts to make tomorrow less annoying than today.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;I only wanted a better remote debugging workflow for a service running in a VM.&lt;/p&gt;
&lt;p&gt;That turned into DAP, schema parsing, code generation, &lt;code&gt;dbgeng&lt;/code&gt;, and a long series of state-machine bugs.&lt;/p&gt;
&lt;p&gt;The result so far is a working first proof of concept: a WinDbg-backed debugger adapter for Visual Studio Code with local &lt;code&gt;launch&lt;/code&gt;, local attach, dump-file attach, stack traces, scopes, variables, breakpoints, and step commands working well enough to prove the architecture.&lt;/p&gt;
&lt;p&gt;That matters because it means I finally have a base I can build on. I have not implemented remote debugging or kernel debugging yet, but I now feel ready to take a real shot at both without getting lost in the basics again.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;The next step is to use this base for the work I actually set out to do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Harden the current adapter and clean up rough edges in the state machine&lt;/li&gt;
&lt;li&gt;Start implementing the actual remote debugging flow for the VM scenario&lt;/li&gt;
&lt;li&gt;Take a first real implementation shot at kernel debugging too&lt;/li&gt;
&lt;li&gt;Keep the scope under control so the project does not drift again like it did at the start&lt;/li&gt;
&lt;li&gt;Open source the project once the foundation is stable enough&lt;/li&gt;
&lt;li&gt;Keep turning WinDbg power into something that feels normal inside VS Code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And yes, this all started with &quot;I just want to remote debug a service on a VM.&quot;&lt;/p&gt;
&lt;p&gt;That is usually how the best tools start.&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>The Passenger Seat Developer</title>
        <published>2025-10-27T00:00:00+00:00</published>
        <updated>2025-10-27T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/the-passenger-seat-developer/"/>
        <id>https://svnscha.de/posts/the-passenger-seat-developer/</id>
        <summary type="html">Here's what nobody tells you about AI-assisted rapid prototyping: Every prototype feels like success, but success is measured by shipping, not building.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/the-passenger-seat-developer/">&lt;h2 id=&quot;the-great-prototype-experiment&quot;&gt;The Great Prototype Experiment&lt;/h2&gt;
&lt;p&gt;Here's what nobody tells you about AI-assisted rapid prototyping: After six months and nearly 100 projects, I had to face an uncomfortable truth.&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Every prototype feels like success. But is it really?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;why-you-ask&quot;&gt;Why, You Ask?&lt;/h2&gt;
&lt;p&gt;Picture this: Me, armed with Claude, spinning up project after project like I'm some kind of coding machine gun. A productivity suite here, a file manager there, throw in some web scrapers, automation tools, data processors - you name it, I've probably built a prototype of it in the past six months.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nearly 100 projects.&lt;/strong&gt; The dopamine hits were insane. Every idea that popped into my head, no matter how half-baked, could become a working prototype in hours instead of weeks. The velocity felt otherworldly.&lt;/p&gt;
&lt;p&gt;The result took me too long to acknowledge: &lt;strong&gt;out of nearly 100 prototypes, only one reached production.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;One. Literally. One.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That project? &lt;a href=&quot;/posts/ai-meets-windbg/&quot;&gt;mcp-windbg&lt;/a&gt;. And guess what made it special? It's the only one where I spent those classic, grinding hours sitting there, actually understanding every line of code, debugging the edge cases, and wrestling with the gnarly implementation details.&lt;/p&gt;
&lt;h2 id=&quot;the-dopamine-factory&quot;&gt;The Dopamine Factory&lt;/h2&gt;
&lt;p&gt;Let me be real with you about what those early days felt like. I'd wake up with some random idea - &quot;What if I built a tool that automatically organizes screenshots by content?&quot; or &quot;I need a better way to manage my development environments&quot; - and by lunch, I'd have a working prototype.&lt;/p&gt;
&lt;p&gt;Six months ago, I was writing about &lt;a href=&quot;/posts/vscode-vibe-coding/&quot;&gt;vibe coding&lt;/a&gt; like I'd discovered fire. The euphoria was real - watching AI refactor entire codebases, generate complex implementations, solve architectural problems in seconds. I was living in that perfect state where &quot;the barrier between thinking and implementing just got so much thinner.&quot;&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Me: Build me a screenshot organizer that uses OCR to categorize images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Claude: *Generates Python app with OCR integration, file management, GUI*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Me: This actually works perfectly!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rush was incredible. Idea to implementation in hours. No tedious boilerplate. No debugging mysterious dependency issues. No wrestling with documentation. Just pure, frictionless creation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I felt like a goddamn wizard.&lt;/strong&gt; Every prototype that worked felt like validation that I'd cracked some secret code of productivity. Friends would ask what I was working on, and I'd rattle off a dozen projects like I was running a software factory.&lt;/p&gt;
&lt;p&gt;That euphoric beginning? It was exactly six months ago. Time has a funny way of providing perspective.&lt;/p&gt;
&lt;h2 id=&quot;the-reality-check-why-nothing-shipped&quot;&gt;The Reality Check: Why Nothing Shipped&lt;/h2&gt;
&lt;p&gt;After several months, my project folder had grown to nearly 100 directories, but I still had not shipped anything.&lt;/p&gt;
&lt;p&gt;Why? Because &lt;strong&gt;prototypes aren't products.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every time I'd come back to one of these AI-generated prototypes to actually finish it - to handle edge cases, add proper error handling, write tests, or make it production-ready - I'd hit the same wall: &lt;strong&gt;I had no clue how the thing actually worked.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The code looked familiar. The structure made sense at first glance. But when it came time to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debug why it crashed with certain file types&lt;/li&gt;
&lt;li&gt;Add a feature that required understanding the data flow&lt;/li&gt;
&lt;li&gt;Optimize performance bottlenecks&lt;/li&gt;
&lt;li&gt;Handle edge cases the AI hadn't considered&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was lost. Completely, utterly lost.&lt;/p&gt;
&lt;h2 id=&quot;the-one-that-made-it-mcp-windbg&quot;&gt;The One That Made It: mcp-windbg&lt;/h2&gt;
&lt;p&gt;So why did mcp-windbg succeed when 99 others failed? It wasn't because I spent months on it - it was a small weekend project. But I approached it differently.&lt;/p&gt;
&lt;p&gt;I started by vibe-coding with Claude, just like the other prototypes. Got the basic structure working, had it generating and parsing WinDBG commands. But then - and this is the crucial difference - I actually went back and reviewed what the AI had built. Debugged the edge cases myself. Traced through the subprocess communication to understand how it really worked.&lt;/p&gt;
&lt;p&gt;When pytest failures popped up, I didn't just ask Claude to fix them. I sat there and figured out why they were failing. When the CDB interaction got weird with certain commands, I debugged it manually until I understood the communication protocol.&lt;/p&gt;
&lt;p&gt;The result? A weekend project that actually solved a real problem in my daily work. Something I could confidently maintain, extend, and explain to others.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I owned the code because I'd taken the time to understand what Claude had built.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-brutal-truth-about-ai-generated-prototypes&quot;&gt;The Brutal Truth About AI-Generated Prototypes&lt;/h2&gt;
&lt;p&gt;Those 99 failed projects weren't failures because the code was bad. Most of them actually worked pretty well for their basic use cases. They failed because I'd delegated understanding to AI instead of using it as a tool to support my understanding.&lt;/p&gt;
&lt;p&gt;Here is what was happening:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Week 1&lt;/strong&gt;: &quot;Holy shit, look at this amazing prototype!&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Week 2&lt;/strong&gt;: &quot;I should probably clean this up and ship it&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Week 3&lt;/strong&gt;: &quot;Hmm, there are some edge cases I need to handle&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Week 4&lt;/strong&gt;: &quot;Why is this crashing? Let me ask Claude to fix it&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Week 5&lt;/strong&gt;: &quot;The fix broke something else. This is getting messy&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Week 6&lt;/strong&gt;: &quot;Maybe I'll just start a new project instead...&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sound familiar? This cycle repeated so consistently I could set my calendar by it.&lt;/p&gt;
&lt;h2 id=&quot;the-sitting-there-hours-why-they-matter&quot;&gt;The Sitting-There Hours: Why They Matter&lt;/h2&gt;
&lt;p&gt;You know those classic hours every developer has experienced? The ones where you're just sitting there, staring at code, trying to figure out why something isn't working the way you expect? Those moments when you're debugging line by line, tracing execution paths, and slowly building up a mental model of how everything fits together?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Those hours aren't wasted time. They're investment time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When you skip those hours - when you let AI generate the solution and just accept it - you never build that intimate knowledge of your own system. You become a tourist in your own codebase.&lt;/p&gt;
&lt;p&gt;With mcp-windbg, I didn't spend weeks wrestling with it - it was just a weekend project. But during that weekend, when I hit issues with subprocess communication or weird CDB behavior, I actually debugged them myself instead of immediately asking Claude for fixes. I took the time to understand why certain commands failed and how the debugging session management worked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That weekend of actually understanding what I was building made the difference between prototype #99 and shipped product #1.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-false-productivity-trap&quot;&gt;The False Productivity Trap&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;I felt productive while building those 99 prototypes.&lt;/strong&gt; Each working demo felt like progress, and my GitHub activity supported that impression. It did not mean I was finishing useful products.&lt;/p&gt;
&lt;p&gt;But productivity isn't about how much code you generate. It's about how much value you ship. And by that metric, I had a 1% success rate.&lt;/p&gt;
&lt;p&gt;The problem was not AI itself, but how I used it. I treated it as a replacement for understanding instead of a debugger or knowledge base that could help me learn faster.&lt;/p&gt;
&lt;h2 id=&quot;how-i-use-ai-now&quot;&gt;How I Use AI Now&lt;/h2&gt;
&lt;p&gt;I still use AI regularly, but now I treat it like any other development tool.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI as a knowledge base&lt;/strong&gt;: &quot;How does subprocess communication work in Python?&quot; &quot;What are the edge cases for file parsing?&quot; &quot;Show me different approaches to error handling.&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI as a debugging partner&lt;/strong&gt;: &quot;Here's my stack trace, what could be causing this?&quot; &quot;This function isn't behaving as expected, help me trace through the logic.&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI for the boring repetitive stuff&lt;/strong&gt;: Boilerplate code, test scaffolding, documentation generation, refactoring patterns I've done a million times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI as a code reviewer&lt;/strong&gt;: &quot;Does this implementation handle edge cases properly?&quot; &quot;Are there performance issues with this approach?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key difference: &lt;strong&gt;I use AI to accelerate my understanding, not replace it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For anything I might ship, the rule is simple: &lt;strong&gt;If I can't explain how the core functionality works without looking at the code, I don't ship it.&lt;/strong&gt; AI can help me get there faster, but it can't get there for me.&lt;/p&gt;
&lt;p&gt;This isn't about being a purist or rejecting AI assistance - it's about maintaining professional competence and shipping software you can actually support.&lt;/p&gt;
&lt;h2 id=&quot;what-success-actually-looks-like&quot;&gt;What Success Actually Looks Like&lt;/h2&gt;
&lt;p&gt;After six months of this experiment, here's what I've learned about successful AI-assisted development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Delegate the repetitive stuff&lt;/strong&gt;: Boilerplate generation, test scaffolding, documentation, refactoring patterns you've done before.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use it as a knowledge multiplier&lt;/strong&gt;: Research APIs, explore different approaches, get explanations of complex concepts, debug tricky issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep the understanding&lt;/strong&gt;: Architecture decisions, core business logic, data flow design, system integration points.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Invest in the sitting-there hours&lt;/strong&gt;: For anything you plan to ship, spend the time to truly understand how it works.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI is similar to a good debugger or profiler: it can make you more effective, but it does not replace understanding the system you are building.&lt;/p&gt;
&lt;h2 id=&quot;the-uncomfortable-question&quot;&gt;The Uncomfortable Question&lt;/h2&gt;
&lt;p&gt;Here's the question that keeps me up at night: &lt;strong&gt;How many developers are building careers on AI-generated code they don't understand?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is also a matter of professional responsibility. If you own a piece of code, you should be able to explain, modify, and debug it, especially when a production issue occurs and the AI assistant is unavailable.&lt;/p&gt;
&lt;p&gt;I don't have a good answer to that question. I just know I don't want to be that kind of developer.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;After six months and nearly 100 AI-assisted prototypes, only mcp-windbg shipped. The difference was that I used AI to speed up my learning instead of asking it to replace that learning.&lt;/p&gt;
&lt;p&gt;Remember that uncomfortable truth from the beginning? Every prototype feels like success, but success is measured by shipping, not building. The dopamine hits from rapid prototyping are real, but they're not the same as the satisfaction of maintaining code you actually understand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The lesson isn't to use less AI. The lesson is to use it better.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AI is like having a brilliant research assistant, debugger, and code reviewer all rolled into one. Use it to explore ideas faster, understand concepts deeper, and eliminate the boring repetitive work that burns you out. But don't delegate the understanding itself.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;If this resonates with you, here's what I'd suggest doing right now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Audit your current projects:&lt;/strong&gt; Look at your recent work. Can you explain how the core functionality works without looking at the code? If not, spend some time diving into those systems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set a new rule:&lt;/strong&gt; For anything you plan to ship, implement the &quot;explain it without looking&quot; test. If you can't walk someone through how it works from memory, you're not ready to ship.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Change how you prompt:&lt;/strong&gt; Instead of &quot;Build me X,&quot; try &quot;Help me understand how to build X&quot; or &quot;What are the key concepts I need to know for X?&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Embrace the sitting-there hours:&lt;/strong&gt; When you hit a bug or weird behavior, resist the urge to immediately ask AI for a fix. Spend 15-20 minutes trying to understand it yourself first.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Someone still needs to own the code. AI can help you move faster, but it cannot take that responsibility from you.&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>How to extend GitHub Copilot with prompt files</title>
        <published>2025-09-10T00:00:00+00:00</published>
        <updated>2025-09-10T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/howto-extend-copilot-with-prompt-files/"/>
        <id>https://svnscha.de/posts/howto-extend-copilot-with-prompt-files/</id>
        <summary type="html">Because copy-pasting prompts from your notes app is so last year. Let me show you how to turn your best prompts into reusable superpowers.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/howto-extend-copilot-with-prompt-files/">&lt;h2 id=&quot;why-you-ask&quot;&gt;Why, You Ask?&lt;/h2&gt;
&lt;p&gt;Remember when I went absolutely euphoric about &lt;a href=&quot;/posts/vscode-vibe-coding/&quot;&gt;vibe coding&lt;/a&gt;? Well, that honeymoon phase taught me one crucial lesson: &lt;strong&gt;context matters, and you really need to spend time writing good prompts.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At first, I was frantically scribbling prompts in my notes app like some kind of digital hoarder. Then I graduated to GitHub Copilot instruction files, adding rules like &quot;when asked for review, do this and that.&quot; But constantly switching between apps and copy-pasting prompts? &lt;strong&gt;I'm tired of it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GitHub Copilot's prompt files solve this by keeping reusable instructions in the repository.&lt;/p&gt;
&lt;h2 id=&quot;using-promptmd-files&quot;&gt;Using &lt;code&gt;.prompt.md&lt;/code&gt; Files&lt;/h2&gt;
&lt;p&gt;Prompt files turn your best prompts into reusable slash commands. VS Code gives you two flavors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Workspace prompts&lt;/strong&gt; (&lt;code&gt;.github/prompts/&lt;/code&gt;): Travel with your repository, perfect for team-shared helpers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User prompts&lt;/strong&gt;: Stored in your VS Code profile, available everywhere for personal tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both become accessible as &lt;code&gt;/my-prompt&lt;/code&gt; directly in VS Code chat. Instead of hunting through notes for that brilliant review prompt, you just type &lt;code&gt;/svnscha-blog-review&lt;/code&gt; and boom, there it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Prompt files are currently in public preview and may change in future releases.&lt;/p&gt;
&lt;h2 id=&quot;real-world-example-blog-review-prompt&quot;&gt;Real-World Example: Blog Review Prompt&lt;/h2&gt;
&lt;p&gt;Let me show you what this looks like in practice. I use project prefixes for workspace prompts and &lt;code&gt;/my-...&lt;/code&gt; for personal ones.&lt;/p&gt;
&lt;p&gt;For this blog, I created &lt;code&gt;/svnscha-blog-review&lt;/code&gt; - a specialized prompt that understands my writing style:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;mode&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;agent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;Review blog posts for svnscha.github.io with focus on style, grammar, and technical accuracy&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6;font-weight:bold&quot;&gt;# Blog Post Review for svnscha.github.io&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;You are an expert editor reviewing a blog post for svnscha's technical blog.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;Focus on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6;font-weight:bold&quot;&gt;## Writing Style &amp;amp; Tone&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Consider using &quot;Why, You Ask?&quot; openings when it makes sense for the topic (not mandatory for all posts)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Keep the direct, slightly sarcastic but helpful voice&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Ensure smooth transitions between sections&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; End posts with a short summary or practical next steps when they add value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6;font-weight:bold&quot;&gt;## Technical Accuracy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Verify code examples are correct and practical&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Check that technical explanations are clear and accurate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Ensure all file paths and commands are properly formatted&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6;font-weight:bold&quot;&gt;## Grammar &amp;amp; Spelling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Fix any grammatical errors or typos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Improve sentence structure where needed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Maintain consistency in technical terminology&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6;font-weight:bold&quot;&gt;## Content Structure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Ensure headings flow logically&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Verify examples support the main points&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Suggest a brief summary or actionable next steps when appropriate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Check that the conclusion ties back to the opening&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;Provide specific, actionable feedback that maintains the author's voice while improving clarity and correctness.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This becomes available as &lt;code&gt;/svnscha-blog-review&lt;/code&gt; in VS Code, giving me instant access to a specialized editor that knows my style.&lt;/p&gt;
&lt;h2 id=&quot;smart-naming--location-strategy&quot;&gt;Smart Naming &amp;amp; Location Strategy&lt;/h2&gt;
&lt;p&gt;The naming convention is simple: &lt;strong&gt;project prefixes for workspace prompts, &lt;code&gt;/my-...&lt;/code&gt; for personal ones.&lt;/strong&gt; So &lt;code&gt;/svnscha-blog-review&lt;/code&gt; is specific to this blog, while &lt;code&gt;/my-commit&lt;/code&gt; works everywhere.&lt;/p&gt;
&lt;p&gt;Choose your location based on scope:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Workspace prompts&lt;/strong&gt;: Team-shared, project-specific helpers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User prompts&lt;/strong&gt;: Personal tools that follow you across all projects&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;dynamic-prompts-with-variables&quot;&gt;Dynamic Prompts with Variables&lt;/h2&gt;
&lt;p&gt;Make your prompts adapt to context with VS Code variables:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6;font-weight:bold&quot;&gt;# Code Review Prompt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;Review the following code in ${file}:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;${selection}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;Focus on:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Security vulnerabilities in ${fileBasename}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Performance implications &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6796E6&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; Code style consistency with ${workspaceFolderBasename} standards&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The most useful variables include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Workspace&lt;/strong&gt;: &lt;code&gt;${workspaceFolder}&lt;/code&gt;, &lt;code&gt;${workspaceFolderBasename}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File context&lt;/strong&gt;: &lt;code&gt;${file}&lt;/code&gt;, &lt;code&gt;${fileBasename}&lt;/code&gt;, &lt;code&gt;${fileDirname}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selection&lt;/strong&gt;: &lt;code&gt;${selection}&lt;/code&gt;, &lt;code&gt;${selectedText}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the full list of available variables and advanced features, check out the &lt;a href=&quot;https://code.visualstudio.com/docs/copilot/customization/prompt-files&quot;&gt;VS Code prompt files documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-your-prompt-arsenal&quot;&gt;Setting Up Your Prompt Arsenal&lt;/h2&gt;
&lt;p&gt;Getting started is simple:&lt;/p&gt;
&lt;h3 id=&quot;workspace-prompts&quot;&gt;Workspace Prompts&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create &lt;code&gt;.github/prompts/&lt;/code&gt; in your repository&lt;/li&gt;
&lt;li&gt;Add your &lt;code&gt;.prompt.md&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Commit and push - your team now has access&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;user-prompts&quot;&gt;User Prompts&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Open Command Palette (&lt;code&gt;Ctrl+Shift+P&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Run &quot;Chat: New Prompt File&quot;&lt;/li&gt;
&lt;li&gt;Choose &quot;User profile&quot; for location&lt;/li&gt;
&lt;li&gt;Author and save your prompt&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both methods make prompts available with &lt;code&gt;/prompt-name&lt;/code&gt; in GitHub Copilot chat. Workspace prompts travel with your repository, while user prompts sync across devices with Settings Sync.&lt;/p&gt;
&lt;p&gt;For examples and community contributions, check out the &lt;a href=&quot;https://github.com/github/awesome-copilot/tree/main/prompts&quot;&gt;Awesome GitHub Copilot prompts collection&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Prompt files transform good prompting from an exclusive skill into a shared superpower. Your team gets expert-level guidance, your hotfix deployments get proper review, and your collective wisdom becomes instantly accessible with slash commands.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Start small&lt;/strong&gt; - Convert your three most-used prompts to &lt;code&gt;.prompt.md&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose scope wisely&lt;/strong&gt; - Workspace prompts for teams, user prompts for personal tools&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use variables&lt;/strong&gt; - Make prompts dynamic with &lt;code&gt;${selection}&lt;/code&gt;, &lt;code&gt;${file}&lt;/code&gt;, and &lt;code&gt;${input:variableName}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow naming conventions&lt;/strong&gt; - Project prefixes for workspace, &lt;code&gt;/my-...&lt;/code&gt; for user prompts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explore the community&lt;/strong&gt; - Check out &lt;a href=&quot;https://github.com/github/awesome-copilot/tree/main/prompts&quot;&gt;Awesome GitHub Copilot prompts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the docs&lt;/strong&gt; - &lt;a href=&quot;https://code.visualstudio.com/docs/copilot/customization/prompt-files&quot;&gt;VS Code prompt files documentation&lt;/a&gt; has the latest features&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The main benefit is simple: useful instructions live with the project and can be reused without copying them into every chat.&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>Vibe Coding is So Damn Real</title>
        <published>2025-04-27T00:00:00+00:00</published>
        <updated>2025-04-27T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/vscode-vibe-coding/"/>
        <id>https://svnscha.de/posts/vscode-vibe-coding/</id>
        <summary type="html">Because watching GitHub Copilot refactor files with a single prompt is the most satisfying thing you'll see today.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/vscode-vibe-coding/">&lt;h2 id=&quot;why-you-ask&quot;&gt;Why, You Ask?&lt;/h2&gt;
&lt;p&gt;Ever had that moment when your coding flow is so perfect it feels like you and your tools are in some kind of cosmic alignment? That's vibe coding. It's when the friction between thought and implementation practically disappears. And let me tell you, with GitHub Copilot and VS Code, this isn't just a fleeting sensation-it's a consistent reality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I'm tired of writing about theoretical capabilities. Let me show you something concrete.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-childhood-dream-come-true&quot;&gt;A Childhood Dream Come True&lt;/h2&gt;
&lt;p&gt;Let me share something personal: since I first started coding, I've had this recurring dream. A dream where I could simply talk to my computer, tell it what I want in plain language, and watch as it translates my intentions into working code. No syntax gymnastics. No hunting for semicolons. Just pure, frictionless creation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;Hey computer, refactor this module to use dependency injection instead of globals.&quot;&lt;/li&gt;
&lt;li&gt;&quot;Computer, optimize this database query, it's running too slow.&quot;&lt;/li&gt;
&lt;li&gt;&quot;Add translation support to all user-facing strings in this module.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For decades, this remained firmly in the realm of science fiction-something for Star Trek episodes where they casually ask the computer to &quot;reconfigure the deflector dish&quot; and it just... happens.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DAMN, we're just there now.&lt;/strong&gt; Not in some distant future, not as a tech demo, but as a practical, everyday reality in my development workflow.&lt;/p&gt;
&lt;h2 id=&quot;real-world-context-nofidoc&quot;&gt;Real-World Context: Nofidoc&lt;/h2&gt;
&lt;p&gt;A little context: In my free time, I've been pushing the boundaries of what's possible with AI-assisted coding-well beyond just casual experiments. While I also use these workflows at work, Nofidoc has become my personal playground for exploring how far I can take this technology. It's a space where I can try things that aren't always ready for the spotlight, but the results have been too compelling not to share (even if I'm keeping things a bit low-key for now).&lt;/p&gt;
&lt;p&gt;The codebase uses Qt for the UI components, has a wizard-based document import flow, and handles various document formats with a focus on PDFs. It's exactly the kind of mid-sized C++ project where refactoring used to be tedious and error-prone.&lt;/p&gt;
&lt;h2 id=&quot;the-perfect-pairing&quot;&gt;The Perfect Pairing&lt;/h2&gt;
&lt;p&gt;VS Code with GitHub Copilot doesn't just assist your coding-it transforms it. No more wasting precious brain cycles on trivial tasks. No more tedious refactoring operations that make you question your career choices at 2 AM.&lt;/p&gt;
&lt;p&gt;I recently needed to refactor the document import workflow to remove direct database dependencies in the wizard component. Why having that in the first place? Well, getting something proof-of-concept-ish is the answer. Anyways, this is a classic case of improving architecture by decoupling components, but it typically requires careful changes across multiple files and understanding the entire call hierarchy.&lt;/p&gt;
&lt;h2 id=&quot;see-the-entire-workflow-in-action&quot;&gt;See The Entire Workflow In Action&lt;/h2&gt;
&lt;p&gt;I've recorded a full ~6-minute video showing the entire refactoring process from start to finish. You'll see me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Prompt Copilot with my refactoring requirements&lt;/li&gt;
&lt;li&gt;Watch the initial code changes being proposed&lt;/li&gt;
&lt;li&gt;Hit compilation errors (because real-world code is messy!)&lt;/li&gt;
&lt;li&gt;Provide additional guidance to Copilot&lt;/li&gt;
&lt;li&gt;Get a complete, working solution&lt;/li&gt;
&lt;/ol&gt;
&lt;video class=&quot;cast&quot; src=&quot;/casts/2025-04-27-vibe.webm&quot; controls&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
&lt;p&gt;What's remarkable here is not just that Copilot could make the changes, but how the entire interaction feels like working with a senior developer who deeply understands your codebase.&lt;/p&gt;
&lt;h2 id=&quot;the-real-example-documentimportwizard-refactoring&quot;&gt;The Real Example: DocumentImportWizard Refactoring&lt;/h2&gt;
&lt;p&gt;Here's a snapshot of what happened in the video. I needed to update the DatabaseWidget class to use the new API of our DocumentImportWizard that we had refactored to remove direct database dependencies.&lt;/p&gt;
&lt;p&gt;Copilot analyzed the code and came up with this solution:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;cpp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// Before refactoring, direct database dependency:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; DatabaseWidget&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;onDocumentImportWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    auto&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; importWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; DocumentImportWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_database&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    importWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// After refactoring, using callback approach:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt; DatabaseWidget&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;onDocumentImportWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;    auto&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; importWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; DocumentImportWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    importWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;setGetDocumentTypesCallback&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;]() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_database&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; QList&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;DocumentType&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;        auto&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; docTypeService&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;_database&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getDocumentTypeService&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;docTypeService&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt; QList&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0&quot;&gt;DocumentType&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;            &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C586C0&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; docTypeService&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;getDocumentTypes&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;    importWizard&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copilot explained its reasoning:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&quot;I've updated the onDocumentImportWizard() method in DatabaseWidget to use the new refactored API of our DocumentImportWizard class. The key changes were:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;1. Removed passing the _database parameter directly to the DocumentImportWizard constructor&lt;/em&gt;
&lt;em&gt;2. Added a call to setGetDocumentTypesCallback() with a lambda that:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checks if _database is valid&lt;/li&gt;
&lt;li&gt;Gets the document type service from the database&lt;/li&gt;
&lt;li&gt;Returns the document types list from the service&lt;/li&gt;
&lt;li&gt;Returns an empty list if any step fails&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;This completes the refactoring work by updating all the calling code to use the new API. The change maintains the same functionality but with a cleaner design that removes direct dependencies on the database pointer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The implementation follows modern C++ practices by using a lambda to encapsulate the specific functionality needed (getting document types) while keeping the rest of the database access logic out of the wizard class. This makes the code more maintainable and easier to test.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is exactly the kind of architectural improvement that typically takes deep understanding of both the codebase and software design principles. Yet Copilot produced it in seconds.&lt;/p&gt;
&lt;h2 id=&quot;the-key-lesson-human-ai-collaboration&quot;&gt;The Key Lesson: Human-AI Collaboration&lt;/h2&gt;
&lt;p&gt;My main takeaway is simple: &lt;strong&gt;AI tools work best when you bring your own domain knowledge.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just before that, I was debugging a frustrating issue with field registration in that document import wizard. The fields weren't passing values between pages correctly. I asked Copilot to help fix the bug and it initially proposed an overly complex workaround that would have been a maintenance nightmare.&lt;/p&gt;
&lt;p&gt;So I gave it a hint:&lt;/p&gt;
&lt;p&gt;&quot;I think there's an issue with the registerField calls for 'importSuccessCount' and 'importErrorCount'. The implementation doesn't specify the property name correctly.&quot;&lt;/p&gt;
&lt;p&gt;And just like that, it had an &quot;aha!&quot; moment. It immediately identified the real issue:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;cpp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// Before (buggy implementation):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;registerField&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;importSuccessCount&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;// After (Copilot's correct fix):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;registerField&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;importSuccessCount&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;importSuccessCount&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simple fix resolved the entire issue. The fix works because it properly uses the Qt property system (third parameter) as the remaining code and pages expected, whereas Copilot's initial workaround was mega ugly - setting properties directly with setProperty() calls. With just a small hint about the actual problem, we were back on track. This perfectly illustrates why domain expertise remains critical - AI tools can suggest solutions, but knowing which ones make sense in your framework requires human judgment.&lt;/p&gt;
&lt;p&gt;Sometimes AI tools need a gentle nudge in the right direction, and then they're off to the races again.&lt;/p&gt;
&lt;h2 id=&quot;not-always-perfect-magic&quot;&gt;Not Always Perfect Magic&lt;/h2&gt;
&lt;p&gt;Let me be real with you - it's not all sunshine and rainbows. AI assistance sometimes misses the mark, and when it does, you need to steer it in the right direction. But I've found that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The initial attempt is usually close&lt;/li&gt;
&lt;li&gt;AI is exceptionally good at understanding feedback&lt;/li&gt;
&lt;li&gt;With the right hints, it can quickly recover and find the optimal solution&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The collaboration workflow is what makes all the difference. Instead of wrestling with a tool, it feels like having a junior developer who's eager to learn and quick to adapt.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot;&gt;What I Learned&lt;/h2&gt;
&lt;p&gt;This isn't just about saving time (though I saved HOURS). It's about changing how we think about coding. When you can express your intent in natural language and have it accurately translated into code changes, you're no longer programming computers-you're conversing with them.&lt;/p&gt;
&lt;p&gt;The barrier between thinking and implementing just got so much thinner.&lt;/p&gt;
&lt;h2 id=&quot;getting-this-setup-yourself&quot;&gt;Getting This Setup Yourself&lt;/h2&gt;
&lt;p&gt;Want this superpower? Here's what you need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;VS Code&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A clear understanding of your codebase&lt;/strong&gt; - To craft effective prompts&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That's it! No complex configuration, no elaborate plugin chains.&lt;/p&gt;
&lt;p&gt;Oh, which model? Right now I am using Claude 3.7 - it's so good.&lt;/p&gt;
&lt;h2 id=&quot;where-this-is-going&quot;&gt;Where This Is Going&lt;/h2&gt;
&lt;p&gt;You know that saying about technology and magic? This is it. We're witnessing the early days of a transformation in how software gets built. The tools are evolving to understand not just the syntax of our code, but the intent behind it.&lt;/p&gt;
&lt;p&gt;Could I have written a complex bash script to do some of this refactoring? Maybe.
Could I have used search-and-replace with regex? Probably.
Would either approach have understood the semantic meaning of my code well enough to know which strings need translation? Absolutely not.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Vibe coding isn't just some feel-good developer term. It's that perfect state where you and your tools are in sync, where expressing your intent feels natural and immediate. With GitHub Copilot and VS Code, I'm experiencing this daily while building Nofidoc.&lt;/p&gt;
&lt;p&gt;If you're still doing manual refactoring in 2025, you're not just missing out on productivity-you're missing out on the pure joy of frictionless development.&lt;/p&gt;
&lt;p&gt;Try it. Feel it. Vibe code.&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>A Git feature I should've met sooner!</title>
        <published>2025-04-04T00:00:00+00:00</published>
        <updated>2025-04-04T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/git-worktree/"/>
        <id>https://svnscha.de/posts/git-worktree/</id>
        <summary type="html">I was living in stash-hell and didn't even know it.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/git-worktree/">&lt;h2 id=&quot;why-you-ask&quot;&gt;Why, You Ask?&lt;/h2&gt;
&lt;p&gt;Because I thought I knew Git.
Like really. Branches? Merged. Rebased. Cherry-picked. Heck, I've even force-pushed into production (don't judge me). I've danced the &lt;code&gt;git stash&lt;/code&gt; tango more times than I care to admit, and I've rage-quit after realizing I checked out the wrong branch with uncommitted changes.&lt;/p&gt;
&lt;p&gt;But then-then-I discovered &lt;code&gt;git worktree&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And everything changed.&lt;/p&gt;
&lt;h3 id=&quot;the-problem-with-the-normal-way&quot;&gt;The Problem With the &quot;Normal&quot; Way™&lt;/h3&gt;
&lt;p&gt;Let's say you're working on a feature. You're knee-deep in uncommitted changes, and suddenly you need to switch to another branch to hotfix or review something. What do you do?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git stash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git checkout other-branch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Try to remember what you were doing in your branch later.&lt;/li&gt;
&lt;li&gt;Forget what you stashed and why.&lt;/li&gt;
&lt;li&gt;Cry&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the standard Git workflow we all just kind of accept. It's chaotic good at best.&lt;/p&gt;
&lt;h3 id=&quot;enter-git-worktree&quot;&gt;Enter: &lt;code&gt;git worktree&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;What if I told you... you could just check out multiple branches at the same time? Each in its own separate folder. No stash. No backflips. No existential dread.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git worktree&lt;/code&gt; is a built-in Git feature that lets you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check out multiple branches at once&lt;/li&gt;
&lt;li&gt;Work on each one in its own directory&lt;/li&gt;
&lt;li&gt;Keep your mental state and filesystem intact&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;
&lt;p&gt;Create a new worktree for a feature branch&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; worktree&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ../feature-x&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; origin/feature-x&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This checks out the &lt;code&gt;feature-x&lt;/code&gt; branch (fetched from &lt;code&gt;origin&lt;/code&gt;) into a new directory &lt;code&gt;../feature-x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If it's a new feature you start locally, do this:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; worktree&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ../feature-x&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; feature-x&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a new local branch &lt;code&gt;feature-x&lt;/code&gt; from your current &lt;code&gt;HEAD&lt;/code&gt; (usually &lt;code&gt;main&lt;/code&gt;) and checks it out into &lt;code&gt;../feature-x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Wow. 🥳 No more &quot;wait lemme stash real quick.&quot;&lt;/p&gt;
&lt;p&gt;Now you can commit your fix, push it, and go back to your mess later. Like a civilized developer.&lt;/p&gt;
&lt;h4 id=&quot;list-all-worktrees&quot;&gt;List all worktrees&lt;/h4&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; worktree&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because you will forget what you spun up after the third coffee.&lt;/p&gt;
&lt;h3 id=&quot;whats-the-catch&quot;&gt;What's the Catch?&lt;/h3&gt;
&lt;p&gt;Honestly? Not much. A few things to keep in mind:&lt;/p&gt;
&lt;p&gt;You can't check out the same branch twice. Git will yell at you. That's fair.&lt;/p&gt;
&lt;p&gt;Deleting a worktree is easy: just &lt;code&gt;git worktree remove ../feature-x&lt;/code&gt; (the directory) and that's it.&lt;/p&gt;
&lt;h3 id=&quot;why-you-need-this-in-your-life&quot;&gt;Why You Need This in Your Life&lt;/h3&gt;
&lt;p&gt;If you're working on multiple features, doing code reviews locally, fixing stuff mid-feature, or just trying to keep your brain from melting-&lt;code&gt;git worktree&lt;/code&gt; is the gift you didn't know Git included.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No more stash juggling.&lt;/li&gt;
&lt;li&gt;No more &quot;which terminal had which branch again?&quot;&lt;/li&gt;
&lt;li&gt;No more &quot;accidentally committed to main&quot; horror stories.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just clean, parallel workspaces from a single clone.&lt;/p&gt;
&lt;p&gt;Use it. Love it. Regret not learning it sooner.
I know I did.&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>PowerShell with oh-my-posh</title>
        <published>2024-11-16T00:00:00+00:00</published>
        <updated>2024-11-16T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/powershell-oh-my-posh/"/>
        <id>https://svnscha.de/posts/powershell-oh-my-posh/</id>
        <summary type="html">Because a consistent PowerShell setup is the real productivity flex.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/powershell-oh-my-posh/">&lt;h2 id=&quot;why-you-ask&quot;&gt;Why, You Ask?&lt;/h2&gt;
&lt;p&gt;I use PowerShell on Fedora because I like having the same shell across workstations, VMs, dev containers, and Windows. &lt;a href=&quot;https://ohmyposh.dev/&quot;&gt;oh-my-posh&lt;/a&gt; gives that shell a useful and consistent prompt.&lt;/p&gt;
&lt;p&gt;Here is how I set it up with &lt;a href=&quot;https://www.nerdfonts.com/font-downloads&quot;&gt;Cascadia Code Nerd Font&lt;/a&gt; and KDE Konsole.&lt;/p&gt;
&lt;p&gt;Oh and guess what: This all works on Windows using Windows Terminal, too.&lt;/p&gt;
&lt;h3 id=&quot;step-1-install-oh-my-posh&quot;&gt;Step 1: Install oh-my-posh&lt;/h3&gt;
&lt;p&gt;First, we need to install oh-my-posh. It's as easy as running this command:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; https://ohmyposh.dev/install.sh&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script downloads the latest version of oh-my-posh and installs it. Feel free to inspect the script if you're cautious. If you're running Windows the installation is slightly different, but I guess you figure this out.&lt;/p&gt;
&lt;h3 id=&quot;step-2-install-cascadia-code-nerd-font&quot;&gt;Step 2: Install Cascadia Code Nerd Font&lt;/h3&gt;
&lt;p&gt;oh-my-posh relies on a Nerd Font for its icons and styling. I chose Cascadia Code Nerd Mono because it's clean and works beautifully across different environments.&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;oh-my-posh&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; font&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set the Font in KDE Konsole:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open Konsole.&lt;/li&gt;
&lt;li&gt;Go to Settings &amp;gt; Edit Current Profile &amp;gt; Appearance.&lt;/li&gt;
&lt;li&gt;Click Edit Font and select Cascadia Code Nerd Mono.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Set the Font in Windows Terminal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open Settings&lt;/li&gt;
&lt;li&gt;Navigate to Font and choose Cascadia Code Nerd Mono.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-3-configure-powershell&quot;&gt;Step 3: Configure PowerShell&lt;/h3&gt;
&lt;p&gt;To load oh-my-posh in PowerShell, edit your &lt;code&gt;$PROFILE&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt; $PROFILE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the following lines to load oh-my-posh with your configuration:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;oh-my-posh init pwsh --config &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;/path/to/oh-my-posh.json&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Invoke-Expression&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;clear&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This initializes oh-my-posh with your chosen theme and clears the screen for a clean start.&lt;/p&gt;
&lt;h4 id=&quot;step-4-my-oh-my-posh-configuration&quot;&gt;Step 4: My oh-my-posh configuration&lt;/h4&gt;
&lt;p&gt;Here's my oh-my-posh config file. It's simple but does the job perfectly:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;$schema&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;blocks&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;      &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;prompt&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;      &quot;alignment&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;left&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;      &quot;segments&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;properties&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            &quot;cache_duration&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            &quot;style&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;full&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;          },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;template&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;{{ .Path }} &quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;foreground&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;#77E4F7&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;style&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;plain&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;properties&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            &quot;cache_duration&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;          },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;template&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;{{ .HEAD }} &quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;foreground&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;#FFE700&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;git&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;style&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;plain&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;properties&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;            &quot;cache_duration&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;          },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;template&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;$ &quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;foreground&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;#43D426&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;          &quot;style&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt;&quot;plain&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CDCFE&quot;&gt;  &quot;version&quot;&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8&quot;&gt;3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Path Segment: Displays the current directory in a bright cyan.&lt;/li&gt;
&lt;li&gt;Git Segment: Shows the current Git branch in yellow, if applicable.&lt;/li&gt;
&lt;li&gt;Prompt Character: Displays a green $, keeping it clean and minimal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-5-optional-create-a-new-profile-for-powershell-in-konsole&quot;&gt;Step 5: (optional) Create a New Profile for PowerShell in Konsole&lt;/h3&gt;
&lt;p&gt;Let's set up a dedicated profile for PowerShell in Konsole:&lt;/p&gt;
&lt;p&gt;Duplicate an Existing Profile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In Konsole, go to Settings &amp;gt; Manage Profiles.&lt;/li&gt;
&lt;li&gt;Select your default profile and click Duplicate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Configure the PowerShell Profile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rename it to PowerShell.&lt;/li&gt;
&lt;li&gt;Set the command to pwsh.&lt;/li&gt;
&lt;li&gt;Under Appearance, set the font to Cascadia Code Nerd Mono.&lt;/li&gt;
&lt;li&gt;Save your changes.&lt;/li&gt;
&lt;li&gt;Set it as default (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;With oh-my-posh, Cascadia Code Nerd Font, and a dedicated profile in KDE Konsole, my PowerShell setup is consistent, stylish, and super effective. Whether I'm on Fedora, a VM, or a devcontainer, my terminal always feels like home.&lt;/p&gt;
&lt;p&gt;If you're a PowerShell fan like me, give this setup a try. Trust me, your terminal (and your productivity) will thank you.&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>Simplify SSH</title>
        <published>2024-10-03T00:00:00+00:00</published>
        <updated>2024-10-03T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/simplify-ssh/"/>
        <id>https://svnscha.de/posts/simplify-ssh/</id>
        <summary type="html">How to stop typing your SSH Key passphrase every time. (because, let's be real, we're all a little lazy)</summary>
        <content type="html" xml:base="https://svnscha.de/posts/simplify-ssh/">&lt;h2 id=&quot;why-you-ask&quot;&gt;Why, You Ask?&lt;/h2&gt;
&lt;p&gt;I was tired of entering my SSH key passphrase every time I connected to a server. The setup below lets &lt;code&gt;ssh-agent&lt;/code&gt; remember it for the current terminal session and also keeps host settings in one place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It's time-consuming and frustrating. I'm tired of it.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;So, you've got your shiny new SSH key and every time you want to connect to a server, you're greeted with that ever-familiar password prompt. Sure, typing your SSH key passphrase every time is good for security, but, come on  -  who wants to do that? I mean, I don't know about you, but I've got enough passwords to remember without constantly dealing with this nonsense.&lt;/p&gt;
&lt;p&gt;Let's save ourselves some time and effort by getting the SSH agent to remember our keys for us. That way, you can just run your commands like the seasoned developer you are without worrying about the whole &quot;password entering&quot; thing every single time.&lt;/p&gt;
&lt;h2 id=&quot;step-1-start-the-ssh-agent&quot;&gt;Step 1: Start the SSH Agent&lt;/h2&gt;
&lt;p&gt;First things first  -  let's get the SSH agent up and running. It's like your personal SSH butler, here to remember your key so you don't have to.&lt;/p&gt;
&lt;p&gt;Open up your terminal and type:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;eval&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; $(&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ssh-agent&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Boom! Now the agent is running in the background, ready to hold your keys like the responsible little daemon it is.&lt;/p&gt;
&lt;h2 id=&quot;step-2-add-your-key-to-the-ssh-agent&quot;&gt;Step 2: Add your key to the SSH Agent&lt;/h2&gt;
&lt;p&gt;Now that the agent is up, let's give it your key. You only need to do this once per session, and the agent will keep it ready for you.&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ssh-add&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ~/.ssh/your_key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;your_key&lt;/code&gt; with the name of your private key file. Enter the passphrase once and &lt;code&gt;ssh-agent&lt;/code&gt; will remember it for the rest of the terminal session.&lt;/p&gt;
&lt;h2 id=&quot;step-3-configure-your-ssh-setup-to-be-even-lazier-i-mean-efficient&quot;&gt;Step 3: Configure your SSH setup to be even lazier (I mean efficient)&lt;/h2&gt;
&lt;p&gt;Okay, we've got the agent running and the key added, but we can take it one step further. Why not tell SSH exactly what key to use for which server, so you never have to worry about it picking the wrong one?&lt;/p&gt;
&lt;p&gt;To do this, we're going to set up a &lt;code&gt;~/.ssh/config&lt;/code&gt; file. If you don't have this file yet, don't worry  -  it's as easy as creating it:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ~/.ssh/config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, crack open that file with your favorite text editor and set things up like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;Host&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; your-server-alias&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;    HostName&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; your.server.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;    User&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; your-username&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;    IdentityFile&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ~/.ssh/your_key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;    IdentitiesOnly&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;breaking-it-down&quot;&gt;Breaking it down&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Host&lt;/strong&gt;: You can use any alias here that makes sense to you. This is what you'll type when you want to connect to this server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HostName&lt;/strong&gt;: The actual domain or IP address of the server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User&lt;/strong&gt;: Your username on that server, so you do not have to specify it each time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IdentityFile&lt;/strong&gt;: The path to your SSH private key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IdentitiesOnly yes&lt;/strong&gt;: Tells SSH to use &lt;em&gt;only&lt;/em&gt; this key, rather than trying every key it can find in the agent (which is how you avoid that annoying &quot;user mismatch&quot; issue).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;step-4-create-a-wrapper-script-for-ssh-agent-control&quot;&gt;Step 4: Create a wrapper script for SSH Agent control&lt;/h2&gt;
&lt;p&gt;Alright, you want control over when your SSH agent starts up  -  totally understandable! Instead of running the agent automatically on login (which might feel a bit &lt;em&gt;too&lt;/em&gt; autonomous), we'll create a neat little wrapper script. You can trigger it whenever you feel like starting the agent and adding your SSH key for the session.&lt;/p&gt;
&lt;p&gt;Here's how to set that up.&lt;/p&gt;
&lt;h3 id=&quot;create-the-wrapper-script&quot;&gt;Create the wrapper script&lt;/h3&gt;
&lt;p&gt;Let's create a script that starts the SSH agent, adds your key, and gives you control over when it runs. We'll call this script &lt;code&gt;init-ssh&lt;/code&gt;, and we'll stick it somewhere like &lt;code&gt;/usr/local/bin&lt;/code&gt; so it's available from anywhere in your terminal.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create the script:&lt;/strong&gt;
Open your terminal and create the &lt;code&gt;init-ssh&lt;/code&gt; script:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; nano&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; /usr/local/bin/init-ssh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add the script content:&lt;/strong&gt;
Paste the following content into the file:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;# Start the SSH agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;eval&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; $(&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ssh-agent&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;# Add the key to the agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ssh-add&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; ~/.ssh/your_key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A9955&quot;&gt;# Optional: Display agent status for peace of mind&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ssh-add&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; -l&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make the script executable:&lt;/strong&gt;
Give the script executable permissions:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; +x&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; /usr/local/bin/init-ssh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;how-to-use-the-script&quot;&gt;How to use the script&lt;/h4&gt;
&lt;p&gt;Whenever you want to start your SSH agent for a session, just run:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#CE9178&quot;&gt; init-ssh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will start the agent, add your key, and show you a list of the keys currently loaded in the agent. You've got full control  -  start the agent when you want, stop it when you're done, and enjoy a password-free SSH experience for the duration of that session.&lt;/p&gt;
&lt;h3 id=&quot;optional-stopping-the-ssh-agent&quot;&gt;Optional: Stopping the SSH Agent&lt;/h3&gt;
&lt;p&gt;If you want to stop the SSH agent after you're done with it, you can either let it die when you close your terminal or manually kill it with:&lt;/p&gt;
&lt;pre class=&quot;astro-code dark-plus&quot; style=&quot;background-color:#1E1E1E;color:#D4D4D4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;eval&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt; $(&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA&quot;&gt;ssh-agent&lt;/span&gt;&lt;span style=&quot;color:#569CD6&quot;&gt; -k&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That way, you get all the convenience of an SSH agent when you need it, without it running indefinitely in the background. You're now in complete control of your SSH setup, and you can keep things secure and efficient, exactly the way you like it.&lt;/p&gt;
&lt;p&gt;Happy SSH'ing!&lt;/p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>Blog Motivation</title>
        <published>2024-02-10T00:00:00+00:00</published>
        <updated>2024-02-10T00:00:00+00:00</updated>
        <author>
          <name>Sven Scharmentke</name>
        </author>
        <link rel="alternate" type="text/html" href="https://svnscha.de/posts/blog-motivation/"/>
        <id>https://svnscha.de/posts/blog-motivation/</id>
        <summary type="html">Why, You Ask? This is how I blog about automating annoying tasks, sharing tips, and embracing less frustration.</summary>
        <content type="html" xml:base="https://svnscha.de/posts/blog-motivation/">&lt;h2 id=&quot;why-you-ask&quot;&gt;Why, You Ask?&lt;/h2&gt;
&lt;p&gt;We all have those annoying little tasks that pop up a few times a year. They're too rare to make fixing them a big deal but happen just enough to be really annoying. Think about setting up a new laptop, sorting out files, refactor that &lt;code&gt;NULL&lt;/code&gt; to &lt;code&gt;nullptr&lt;/code&gt; or those updates that take forever. It eats up time and patience. &lt;strong&gt;I'm tired of it.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;changing-things-up&quot;&gt;Changing Things Up&lt;/h2&gt;
&lt;p&gt;I started this blog not just to talk tech but to tackle these annoying moments head-on. My goal? To stop saying &lt;em&gt;&quot;it's not worth fixing&quot;&lt;/em&gt; and start finding ways to make these tasks less of a headache. Even those things we do once in a blue moon? Yeah, I want to automate those too. And I'll share every step right here.&lt;/p&gt;
&lt;h2 id=&quot;why-i-share&quot;&gt;Why I Share&lt;/h2&gt;
&lt;p&gt;This blog is my playground and my megaphone. It's where I try out new ideas to make life easier and then shout out what works. Each post starts with my cheeky&lt;/p&gt;
&lt;center&gt;&quot;Why, You Ask?&quot;&lt;/center&gt;
&lt;p&gt;and always circles back to me spilling the beans on how I truly feel, which usually is&lt;/p&gt;
&lt;center&gt;&quot;I'm tired of it.&quot;&lt;/center&gt;
&lt;p&gt;It's my unique approach, sprinkled with a dash of sarcasm, as I navigate through the mayhem, assuring you that behind every vent, there's a solid reason and, believe it or not, a solution waiting to be uncovered.&lt;/p&gt;
&lt;h2 id=&quot;sharing-what-i-learn&quot;&gt;Sharing What I Learn&lt;/h2&gt;
&lt;p&gt;Making things easier is only part of it. I also want to share useful ideas, opinions, and the occasional rant. When I find a good way to avoid repetitive work, I'll write it down here so others can use it too.&lt;/p&gt;
&lt;h2 id=&quot;come-along-for-the-ride&quot;&gt;Come Along for the Ride&lt;/h2&gt;
&lt;p&gt;If that sounds familiar, have a look around and share your own ideas. None of us should spend more time on repetitive work than necessary.&lt;/p&gt;
&lt;p&gt;Welcome to my quest for a smoother, simpler tech life. Here's to less frustration and more time doing what we love. Let's kick those annoying tasks to the curb.&lt;/p&gt;
</content>
    </entry>
</feed>
