<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Tim talks tech]]></title><description><![CDATA[Tim talks tech]]></description><link>https://techblog.timhilton.xyz</link><generator>RSS for Node</generator><lastBuildDate>Fri, 11 Sep 2026 10:31:49 GMT</lastBuildDate><atom:link href="https://techblog.timhilton.xyz/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Giving Claude Code a /goal]]></title><description><![CDATA[I recently use the /goal command in Claude Code for the first time. I was struggling to reproduce a bug that I already had a theoretical understanding of from investigating the codebase, but had previ]]></description><link>https://techblog.timhilton.xyz/giving-claude-code-a-goal</link><guid isPermaLink="true">https://techblog.timhilton.xyz/giving-claude-code-a-goal</guid><category><![CDATA[claude-code]]></category><category><![CDATA[claude]]></category><category><![CDATA[Google Chrome]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Thu, 30 Jul 2026 11:41:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/05cbfee0-f2ad-4679-9614-4dd05b714125.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently use the <code>/goal</code> command in Claude Code for the first time. I was struggling to reproduce a bug that I already had a theoretical understanding of from investigating the codebase, but had previously been unable to reproduce it despite that. I gave Claude my notes and set it the goal of reproducing the bug, and an hour later it managed it. When asked, it gave me the details of all the actions it took (including those which turned out to be irrelevant) and was able to tell me how to reliably reproduce the bug.</p>
<p>I set up a new Chrome profile for Claude to use, and installed the <a href="https://chromewebstore.google.com/detail/claude/fcoeoabgfenejglbffodgkkbkcdhcgfn">Claude extension</a>. My aim here is to keep Claude away from all the sites I'm logged into, and limit the damage it could do if something went wrong. This is still new territory to me, and I plan to continue being cuatious. With that set up, I ran <code>claude --chrome</code> which gives Claude access to the browser. I opened and logged into the QA site where I wanted the reproduction to happen, and let Claude loose.</p>
<p>I had also recently given Claude read-only access to my Microsoft 365 account, including my emails. I'd done a quick test to verify that it could indeed access them, but hadn't done anything useful with it yet. However, I was glad to have set it up because I'd forgotten that at one point in the bug reproduction I would be sent an MFA code via email, and Claude was able to use it without me needing to intervene.</p>
<p>It was worth keeping an eye on Claude. I wasn't watching it the whole time, but at one point I did notice that it was basically using trial &amp; error to find test data. I told it to write SQL I can run against the QA database to find suitable test data, which was much faster. There were also times that Claude struggled to navigate the UI and work out how to get to specific functionality. On one occasion it did ask me how to find the button it needed to click. On other times I noticed the confusion and proactively stepped in to explain more. I probably needed to intervene about 4 or 5 times in total.</p>
]]></content:encoded></item><item><title><![CDATA[Month in review: June 2026]]></title><description><![CDATA[Things that happened

I received a happy birthday message from our HR system. It gave me the same vibes as the AI-written compliments I mentioned in Month in review: May 2026.

Microsoft ran an "AI sk]]></description><link>https://techblog.timhilton.xyz/month-in-review-june-2026</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-june-2026</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 03 Jul 2026 21:21:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/86917375-4429-4471-860a-59caf58599e4.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Things that happened</h1>
<ul>
<li><p>I received a happy birthday message from our HR system. It gave me the same vibes as the AI-written compliments I mentioned in <a href="https://techblog.timhilton.xyz/month-in-review-may-2026#things-ive-been-thinking-about">Month in review: May 2026</a>.</p>
</li>
<li><p>Microsoft ran an "AI skills fest". There wasn't much of interest to me. The "main stage" event was very cringey. I don't know if it would appeal to an American or global audience, but I can't imagine many Brits enjoyed it. I wasn't very impressed by the content either, it seemed a bit superficial to me, but I guess it's trying to appeal to people who haven't been using AI day-to-day for the past few years so I might not be the target audience for it. I looked through a featured playlist about using GitHub Copilot, because that seemed most relevant to my role, but found it contained very little that I didn't already know. If I had more time available to sink into learning completely new things perhaps I'd have found other things which I could engage with, but from a position of looking for relatively immediate relevance I unfortunately found none.</p>
</li>
</ul>
<h1>Things I learnt</h1>
<ul>
<li>I needed to make changes to how we handled some data we received from an API and I helped define requirements in terms of what seemed most appropriate, but I failed to check the historic data we'd received to test how we would treat that data with the new requirements. Unfortunately there was a gap which no-one foresaw, but with hindsight I could have found it by doing a bit more analysis up-front.</li>
</ul>
<h1>Things I've been thinking about</h1>
<ul>
<li>I used Claude to ponder what goals I could set for my career at the moment. It brought up some interesting things to think about, but was generally less helpful than I'd hoped or expected. I've not really done much with the output.</li>
</ul>
<h1>Things I'm grateful for</h1>
<ul>
<li>A major piece of work I've been doing (on and off) for the past 6 months went into production, with zero issues reported.</li>
</ul>
<h1>Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a href="https://www.schneier.com/blog/archives/2026/06/ai-and-liability.html">AI and Liability - Schneier on Security</a></p>
<ul>
<li><p>"AI agents are agents of the person or organization that deploys them—and should be treated by the law as such. If a company hired human writers to write its summaries, that company would be liable for inaccuracies in those summaries. If a company’s human agent signed contracts in the company’s name, that company would be bound by those contracts. And if a doctor gave dangerously wrong medical advice, they would be liable for <a href="https://www.nature.com/articles/s41746-026-02854-5">malpractice</a>."</p>
</li>
<li><p>I haven't thought through any complicated ramifications of this, but at face value it sounds sensible to me.</p>
</li>
</ul>
</li>
<li><p>Satirical incident reports. Who knew that was a category of writing?!</p>
<ul>
<li><p><a href="https://nesbitt.io/2026/02/03/incident-report-cve-2024-yikes">Incident Report: CVE-2024-YIKES | Andrew Nesbitt</a></p>
</li>
<li><p><a href="https://nesbitt.io/2026/06/26/incident-report-cve-2026-lgtm.html">Incident Report: CVE-2026-LGTM | Andrew Nesbitt</a></p>
</li>
</ul>
</li>
</ul>
<h1>Things I've published</h1>
<ul>
<li><a href="https://techblog.timhilton.xyz/til-capitalising-letters-with-regex">TIL capitalising letters with regex</a></li>
</ul>
<h1>Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>TIL about C# double interpolation</p>
</li>
<li><p>Configuring Azure function apps in-process vs isolated worker model</p>
</li>
<li><p>Passkey concerns — although this has ended up less as concerns, and more as general thoughts about what passkeys are good for and what problems they have/don't solve.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL capitalising letters with regex]]></title><description><![CDATA[Background
My regex skills have improved since I wrote Just enough regex to get going, though I still think it's a good starting point for a developer who is new to regex. 
In that article I wrote thi]]></description><link>https://techblog.timhilton.xyz/til-capitalising-letters-with-regex</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-capitalising-letters-with-regex</guid><category><![CDATA[TIL]]></category><category><![CDATA[todayilearned]]></category><category><![CDATA[Regex]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 03 Jun 2026 08:40:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/0262e018-411d-414c-9711-0320b219f805.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Background</h1>
<p>My regex skills have improved since I wrote <a href="https://techblog.timhilton.xyz/just-enough-regex-to-get-going">Just enough regex to get going</a>, though I still think it's a good starting point for a developer who is new to regex. </p>
<p>In that article I wrote this:</p>
<blockquote>
<p>start simple so that you can get value from using regex in simple use cases. Learn more when you need it.</p>
</blockquote>
<p>I stand by that advice, and I am still learning extra regex tips &amp; tricks as I need them.</p>
<h1>Problem</h1>
<p>I recently came across code where a code analysis auto-fix had messed up some capitalisation. There were comments which had begun with a capitalised acronym, but the auto-fix converted the first letter to lower-case.</p>
<pre><code class="language-csharp">// before:
/// &lt;summary&gt;
/// ABCD identifier.
/// &lt;/summary&gt;
public int AbcdId { get; set; }

// after:
/// &lt;summary&gt;
/// Gets or sets aBCD identifier.
/// &lt;/summary&gt;
public int AbcdId { get; set; }
</code></pre>
<p>In the context of this codebase, ABCD is a known acronym with a specific meaning. This change begs the question whether an aBCD is somehow different from an ABCD. In my opinion the change makes the comment less useful, not more useful.</p>
<h1>Solution</h1>
<p>This felt like something which could be fixed easily with a regex find &amp; replace, but I didn't know if regex could capitalise a lowercase letter. Happily, it can!</p>
<p>The find pattern is the string "Gets or sets ", then a single lowercase letter, then a single uppercase letter.</p>
<pre><code>Gets or sets ([a-z])([A-Z])
</code></pre>
<p>The replace pattern uses <code>\u</code> to uppercase the following character, which is the captured lowercase letter in this case.</p>
<pre><code>Gets or sets \u\(1\)2
</code></pre>
<p>As always there's probably a caveat that not all regex engines support the same features and syntax, so I can't promise this works globally, but it worked for me.</p>
]]></content:encoded></item><item><title><![CDATA[Month in review: May 2026]]></title><description><![CDATA[Things I learnt

A HashSet is for storing unique elements. The point is that it has O(1) lookups like a Dictionary does. It uses the same basic mechanism as a Dictionary does (hashing objects then usi]]></description><link>https://techblog.timhilton.xyz/month-in-review-may-2026</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-may-2026</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Mon, 01 Jun 2026 17:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/5ab5d681-9545-46fe-b72e-8356ccd3f4df.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Things I learnt</h1>
<ul>
<li>A <code>HashSet</code> is for storing unique elements. The point is that it has O(1) lookups like a <code>Dictionary</code> does. It uses the same basic mechanism as a <code>Dictionary</code> does (hashing objects then using modulo arithmetic to convert the hash into an index to jump directly to the relevant data). <ul>
<li>Understanding different collections and algorithmic complexity has always been a weak area for me, perhaps because I didn't study computer science at university so no-one has ever taught me this stuff. I've learnt about it over the years working as a professional programmer, and I've learnt as it's been useful, but it's meant I've learned in a slow (and probably incomplete) way.</li>
</ul>
</li>
</ul>
<h1>Things I've been thinking about</h1>
<ul>
<li>A client sent some positive feedback to my company which was clearly human-written. It was exactly the sort of message a senior person in a company tends to write — it was full of typos and minor mistakes they chose not to fix because it's not the best use of their time. Nevertheless, it was clearly heartfelt and we appreciated it. One of my colleagues replied with a message which was much more polished and free from such sloppiness, but was also clearly (to my mind) written by an AI. (On a whim I ran it through an AI detector which gave it a score of 100% definitely AI–generated. I have no idea how reliable the detector is.) I had mixed feelings about it. I know this colleague enough to be confident that the sentiment was genuine. The appreciation and gratitude he was expressing was real. But the medium is the message, and despite knowing the sentiment would be real I nevertheless felt that the use of AI undermined it. What particularly struck me was that this was not an intellectual process for me. I didn't consciously evaluate his writing to determine whether or not it was AI–generated then decide how to react to it. I just read the message and immediately felt a little disappointed, and I only thought about it being AI–generated as I worked through my instinctive emotional reaction. I don't know whether the client will notice, and if they do I don't know if they'll care. Certainly this colleague does lots of good work and I'm sure the client will care much more about that than the use of an LLM to reply to an email, but I've never before been struck so forcefully by an AI–generated response to a human–authored message.</li>
<li>I'm jumping about quite a bit between different tickets, being in a support role and being busy. I'm trying to be disciplined to take a short break between tickets, even just at the level of getting some water or staring out of a window for 10 seconds. I quite enjoy bouncing between tickets (when I'm making progress on them) and moving fast, but it also leaves me feeling frazzled at the end of the day so I'm trying to slow down a little and give myself room to decompress during the day. It's a bit tricky to know what to do about timesheets though. If I have a slightly longer break (e.g.  5 minutes) after bouncing around between several tickets, which does the time get booked to? That's a much easier question if I've spent a long time focusing on one ticket, but is less clear if the time has been very broken up (especially where it's only a few minutes on each ticket).</li>
</ul>
<h1>Things I've published</h1>
<ul>
<li><a href="https://techblog.timhilton.xyz/til-how-to-find-latitude-and-longitude-of-a-geolocation-stored-in-sql-server">TIL how to find latitude and longitude of a geolocation stored in SQL Server</a></li>
</ul>
<h1>Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li>TIL why dictionary lookups are O(1)<ul>
<li>This is related to my above comment about learning about the use of a <code>HashSet</code>.</li>
</ul>
</li>
<li>Passkey concerns</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL how to find latitude and longitude of a geolocation stored in SQL Server]]></title><description><![CDATA[I was recently working with an EF Core entity which contained a C# Point property representing a geolocation. This was stored in a single column in a SQL Server database. (I think this uses NetTopolog]]></description><link>https://techblog.timhilton.xyz/til-how-to-find-latitude-and-longitude-of-a-geolocation-stored-in-sql-server</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-how-to-find-latitude-and-longitude-of-a-geolocation-stored-in-sql-server</guid><category><![CDATA[todayilearned]]></category><category><![CDATA[TIL]]></category><category><![CDATA[SQL Server]]></category><category><![CDATA[geolocation]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Thu, 07 May 2026 08:22:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/7b592cb9-00c0-49b7-b40f-e755b2749bd2.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was recently working with an EF Core entity which contained a C# <code>Point</code> property representing a geolocation. This was stored in a single column in a SQL Server database. (I think this uses <code>NetTopologySuite</code>, judging by the <a href="https://learn.microsoft.com/en-us/ef/core/modeling/spatial">EF Core Spatial Data documentation</a>.)</p>
<p>I wanted to know where this geolocation actually is, and the easiest way I know is to convert it to latitude and longitude then look it up online. That raises the question, how can I get the latitude and longitude from the value in the SQL Server database?</p>
<p>If you look at the value of the geolocation in the database, it looks like this:</p>
<pre><code>0xE6100000010C635A400D847555403847C263E4453440
</code></pre>
<p>That, of course, is gibberish to me, but happily there is an easy way to get the latitude and longitude from this value. Today I learnt it's built–in functionality within SQL Server!</p>
<pre><code class="language-sql">SELECT TOP 1
    GeoLocation.Lat  AS Latitude,
    GeoLocation.Long AS Longitude,
    GeoLocation
FROM MyTable;
</code></pre>
<table>
<thead>
<tr>
<th>Latitude</th>
<th>Longitude</th>
<th>GeoLocation</th>
</tr>
</thead>
<tbody><tr>
<td>85.8361848</td>
<td>20.2730162</td>
<td>0xE6100000010C635A400D847555403847C263E4453440</td>
</tr>
</tbody></table>
<p>SSMS also has a Spatial Results tab which looks interesting. I'm not sure what to do with it, and I haven't looked into it because I didn't need it for what I was trying to do, but as always I like to know what tools exist that might be useful to me in the future.</p>
<p>As an aside, if you're struggling to find this geolocation on a map, that might be because it's in the Arctic Ocean. In the Northern hemisphere, latitude is a number from 0 (equator) to 90 (North Pole) so a latitude of 85 is pretty far North. This is why I ended up investigating this particular value in the database, because the location which this is <em>intended</em> to represent is, in fact, on land and nowhere near the North Pole.</p>
]]></content:encoded></item><item><title><![CDATA[Months in review: March & April 2026]]></title><description><![CDATA[I've really not done much reading or thinking about tech in recent months, so this will be very brief!
Things that happened

I've tasked Claude with writing explanation of a few codebases I work with.]]></description><link>https://techblog.timhilton.xyz/months-in-review-march-april-2026</link><guid isPermaLink="true">https://techblog.timhilton.xyz/months-in-review-march-april-2026</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 01 May 2026 07:58:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/b95cdb4b-b245-4769-8602-99a78b4ce4fa.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've really not done much reading or thinking about tech in recent months, so this will be very brief!</p>
<h1>Things that happened</h1>
<ul>
<li>I've tasked Claude with writing explanation of a few codebases I work with. The documents, as always, look good. The problem is that I want the documents because I am lacking in domain knowledge, but this also makes it difficult to evaluate the accuracy of what Claude has written. I'm optimistic that the documents will still be useful for giving me a starting point in understanding these unfamiliar domains, but I plan to be sceptical of the details. Hopefully I'll be able to treat these as living documents, updating any errors as I find them.</li>
</ul>
<h1>Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a href="https://lalitm.com/post/building-syntaqlite-ai/#sn-ref-no-sense-of-time">Eight years of wanting, three months of building with AI - Lalit Maganti</a></p>
<ul>
<li>An interesting write up of a software project which was enabled by AI. I like the level-headed evaluation of AI for this task. It was clearly complex, and the author notes both what did and what didn't work well.</li>
</ul>
</li>
<li><p><a href="https://simonwillison.net/2026/Apr/7/project-glasswing/#atom-everything">Anthropic’s Project Glasswing—restricting Claude Mythos to security researchers—sounds necessary to me</a></p>
<ul>
<li>This is a concrete step towards the sorts of security problems that people have been predicting for a while. Given our huge reliance on computers for everything, it is a worrying thought to imagine a dramatic increase in the number of serious security vulnerabilities being found in everyday software. Having said that, it's not something I can do a lot about, so I just have to trust that people in the security industry are working on solving these problems.</li>
</ul>
</li>
</ul>
<h1>Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Google form email certificate</p>
<ul>
<li>I helped my wife set up an automation based on someone else's blog post, and we took it a step further. I'd like to put online what we did so that it might help the next person with the same problem.</li>
</ul>
</li>
<li><p>Using multiple desktops in windows 11 breaks the ability to set different monitor backgrounds</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Month in review: February 2026]]></title><description><![CDATA[Things that happened

I've installed https://github.com/johncmunson/claude-code-transcripts which is handy for copying formatted content from Claude Code into Obsidian. (I installed this rather than S]]></description><link>https://techblog.timhilton.xyz/feb-month-notes</link><guid isPermaLink="true">https://techblog.timhilton.xyz/feb-month-notes</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Tue, 03 Mar 2026 09:02:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/0a94d8c4-dfa7-4ad0-b8e8-0b0995600705.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Things that happened</h1>
<ul>
<li><p>I've installed <a href="https://github.com/johncmunson/claude-code-transcripts">https://github.com/johncmunson/claude-code-transcripts</a> which is handy for copying formatted content from Claude Code into Obsidian. (I installed this rather than Simon Willison's original version because I don't have python tooling installed.) I've used it a few times if I've wanted to copy something from the transcript and retain the formatting, and it's worked well so far.</p>
</li>
<li><p>The guy who has taken the lead on AI adoption at work was speaking to the whole company recently and I was really encouraged by some of what he was saying. It seems there is a bottom-up desire for transparency around when AI has been used, which I thought was a good sign of responsible usage. He was also quite positive about having varied adoption rates around the business, and happy for people to use AI as much or as little as they find helpful. I was glad of that attitude, as opposed to trying to push AI on people who don't find it useful. His emphasis was very much on making tools and training <em>available</em> to everyone, but leaving it up to individuals how helpful they find those tools while doing their work.</p>
</li>
</ul>
<h1>Things I learnt</h1>
<ul>
<li>I needed to update some data in a data model I wasn't familiar with. I used AI too much, and it took a long time to verify what AI produced. I ended up changing tack, and just using AI to find the relevant database tables. I then manually verified that no other tables were relevant by checking foreign keys, and manually worked out what the data change should be. It was definitely a case where using AI slowed things down.</li>
</ul>
<h1>Things I've been thinking about</h1>
<ul>
<li>With the coding agent space moving so quickly, there's always something new to try. It's impossible to keep on top of all the new developments. One impact of this is that the industry holds out the perpetual hope that salvation is just around the corner. Even if you hit frustrations actually using an agent for your work, a week later some new shiny <em>thing</em> will come out with the promise of making everything better. For example, I often vibe code <a href="https://www.timhilton.xyz/user-scripts">user scripts</a> (pieces of javascript which run in the browser when using a specified website, in order to customise its appearance or functionality). This is very hit–and–miss, presumably at least partly because the LLM agent has no way to verify whether the script is behaving as intended. Now there is a chrome extension for Claude which can be used by Claude Code to interact with the browser. This would probably make Claude better at this sort of work (although it also introduces security risks and I haven't yet read up on the mitigations which are in place, so I currently have no plans to install it). But it's another thing to install, another thing to try. It's <em>yet another</em> implicit message that the good stuff is just around the corner, and that even if you've found AI not to be useful you should try it again — and again, and again, and again, increasing your mental lock–in each time.</li>
</ul>
<h1>Things I've published</h1>
<ul>
<li><p><a href="https://techblog.timhilton.xyz/first-impressions-of-claude-code-after-using-github-copilot">First impressions of Claude Code after using GitHub Copilot</a></p>
</li>
<li><p><a href="https://techblog.timhilton.xyz/powershell-script-to-download-azure-devops-project-wiki">Powershell script to download Azure DevOps project wiki</a></p>
</li>
</ul>
<h1>Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Finding undeployed changes</p>
</li>
<li><p>TIL how PasswordHasher handles salt</p>
</li>
<li><p>Giving Claude Code readonly access to a database</p>
</li>
<li><p>TIL why dictionary lookups are O(1)</p>
</li>
<li><p>Claude Code forking and rewinding</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Powershell script to download Azure DevOps project wiki]]></title><description><![CDATA[Azure DevOps has two types of wikis:

Code wikis (Git-backed) - which you can clone

Project wikis (non-Git) - stored in Azure DevOps' internal storage


The Azure DevOps UI gives you the URL to clone]]></description><link>https://techblog.timhilton.xyz/powershell-script-to-download-azure-devops-project-wiki</link><guid isPermaLink="true">https://techblog.timhilton.xyz/powershell-script-to-download-azure-devops-project-wiki</guid><category><![CDATA[Powershell]]></category><category><![CDATA[azure-devops]]></category><category><![CDATA[wiki]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 27 Feb 2026 16:58:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61c353cac0206b3f41f54486/1b531860-35d9-45ca-b2e9-d626b2076b19.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Azure DevOps has two types of wikis:</p>
<ol>
<li><p><strong>Code wikis</strong> (Git-backed) - which you can clone</p>
</li>
<li><p><strong>Project wikis</strong> (non-Git) - stored in Azure DevOps' internal storage</p>
</li>
</ol>
<p>The Azure DevOps UI gives you the URL to clone a code wiki locally, but does not provide a way to download a project wiki. Using Claude, I vibe coded a powershell script to download a project wiki. I’ve only tested it a couple of times so I can’t guarantee it generalises well to all wikis, although it's worked every time I've used it.</p>
<p>This script will download the files into a <code>wiki-backup</code> directory (in the working directory where you run the script) which you can then rename as appropriate.</p>
<p>It requires a PAT token. You can create these from <a href="https://dev.azure.com/%7BYour_Organization%7D">https://dev.azure.com/{Your_Organization}/_usersSettings/tokens</a>. The only permission necessary is <code>Wiki (Read)</code>. When adding a new PAT token, you'll need to click Show All Scopes then scroll to the bottom of the list to find it.</p>
<h1>The script</h1>
<p>For some reason, Hashnode (the platform which powers this blog) has messed up the formatting of this powershell script and tried to escape lots of characters. There shouldn't be any backslash characters (<code>\</code>) in the script, so if you remove all of them then it should work.</p>
<pre><code class="language-powershell">$org = "your-org"
$project = "your-project"
$wikiId = "your-wiki-id"
$pat = "your-personal-access-token"

Write-Host "Starting wiki backup..." -ForegroundColor Green

\(base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":\)pat"))
\(headers = @{Authorization = "Basic \)base64AuthInfo"}

# Get all pages
\(pagesUrl = "https://dev.azure.com/\)org/\(project/_apis/wiki/wikis/\)wikiId/pages?recursionLevel=full&amp;api-version=7.0"
Write-Host "Fetching pages from: $pagesUrl" -ForegroundColor Cyan

try {
    \(result = Invoke-RestMethod -Uri \)pagesUrl -Headers $headers
    Write-Host "Wiki structure retrieved" -ForegroundColor Green
} catch {
    Write-Host "Error fetching pages: $_" -ForegroundColor Red
    exit
}

# Function to recursively process pages
function Process-WikiPage {
    param($page)
    
    # Skip the root page (path = "/")
    if ($page.path -ne "/") {
        Write-Host "Downloading: \((\)page.path)" -ForegroundColor Yellow
        \(pageUrl = "https://dev.azure.com/\)org/\(project/_apis/wiki/wikis/\)wikiId/pages?path=\((\)page.path)&amp;includeContent=true&amp;api-version=7.0"
        
        try {
            \(content = Invoke-RestMethod -Uri \)pageUrl -Headers $headers
            
            # Save to file
            \(filePath = "wiki-backup\)($page.path).md"
            \(directory = Split-Path \)filePath -Parent
            if (\(directory -and !(Test-Path \)directory)) {
                New-Item -Path $directory -ItemType Directory -Force | Out-Null
            }
            \(content.content | Out-File -FilePath \)filePath -Encoding UTF8
            Write-Host "Saved: $filePath" -ForegroundColor Green
        } catch {
            Write-Host "Error downloading \((\)page.path): $_" -ForegroundColor Red
        }
    }
    
    # Process subpages recursively
    if (\(page.subPages -and \)page.subPages.Count -gt 0) {
        foreach (\(subPage in \)page.subPages) {
            Process-WikiPage -page $subPage
        }
    }
}

# Start processing from the root
Process-WikiPage -page $result

Write-Host "Backup complete!" -ForegroundColor Green
</code></pre>
]]></content:encoded></item><item><title><![CDATA[First impressions of Claude Code after using GitHub Copilot]]></title><description><![CDATA[Background
I’m a long-time user of GitHub Copilot as a professional programmer, as my employer gave me access when we first started trialling its use in our company. I’ve used it mainly through Rider, which is the IDE I generally prefer, although I h...]]></description><link>https://techblog.timhilton.xyz/first-impressions-of-claude-code-after-using-github-copilot</link><guid isPermaLink="true">https://techblog.timhilton.xyz/first-impressions-of-claude-code-after-using-github-copilot</guid><category><![CDATA[claude-code]]></category><category><![CDATA[claude.ai]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[copilot]]></category><category><![CDATA[agentic AI]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Tue, 03 Feb 2026 14:00:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769678312304/8a7fdf31-3386-4e9f-ae69-a1450397ebde.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-background">Background</h1>
<p>I’m a long-time user of GitHub Copilot as a professional programmer, as my employer gave me access when we first started trialling its use in our company. I’ve used it mainly through Rider, which is the IDE I generally prefer, although I have used Copilot in both Visual Studio and VS Code as well to a lesser extent.</p>
<p>A week or two ago I was given access to Claude Code as well, so I’ve been using it fairly heavily for some upgrades I’ve been working on. It’s not a piece of work I’ve chosen to be representative of my normal workflow, it’s just what I’ve happened to be working on, but it’s been interesting to compare and contrast Claude Code with GitHub Copilot.</p>
<p>Here are my initial thoughts (which are, of course, all subject to change over time).</p>
<h1 id="heading-planning">Planning</h1>
<p>The single feature which has most impressed me has been Claude Code’s plan mode. Plans are very thorough and clear, and the default behaviour is to clear context before implementing the plan, which makes sense to me. It’s nice to have written plans without the overhead of managing all the markdown files containing the plans, as Claude does it for you. They are just saved to disk, so you can find the plans and copy them elsewhere if you want to.</p>
<p>Claude does take a long time to write plans, so in that sense I suspect it's slower than Copilot. It results in high quality stuff though. This may also be down to a difference in which model is being used, I haven’t really paid attention to the models too much. I tend to default to Claude Sonnet 4.5 in Copilot to try and balance a powerful model with a low quota usage. Claude Code is using Opus 4.5 most of the time, so this difference may well be the model rather than the method of interacting with it. I suppose the more significant difference is how my model selection has been shaped by the defaults built into each product, and the way that usage quotas are determined. Even if this is an unfair comparison when looking narrowly at what each product <em>can</em> do with the same model, I think it’s a fair comparison of how I have <em>actually</em> used the two products while trying to get work done.</p>
<p>I love the commit messages which Claude Code writes. Again this may be because it defaults to using Opus rather than Sonnet, but they’re very clear and contain a lot of detail. I’ve already benefited from this, searching my commit history for 'Google' when a Google maps integration broke, and immediately finding the commit which broke it.</p>
<h1 id="heading-ui">UI</h1>
<p>The biggest surprised for me has been how much I enjoy the Claude Code UI. I <em>should</em> prefer Copilot. I like having everything in a single IDE and I generally prefer GUIs to CLIs, yet I still prefer Claude Code to Copilot. Admittedly Copilot doesn’t have the best support in Rider, Microsoft have clearly prioritised adding features to Copilot in VSCode rather than in their Rider plugin, but this has still been a surprise to me. Claude Code somehow seems well thought through in way that Copilot doesn’t. I would struggle to articulate the specific features which have given me this impression, but it’s a surprisingly strong impression. Copilot feels a bit clunky, whereas Claude Code feels enjoyable.</p>
<p>I think one advantage of Claude Code (and presumably the other agentic coding CLI tools) is that they are consistent regardless of what IDE a developer prefers, whereas Copilot is very different in VSCode / VS / Rider (and presumably also other IDEs), depending on where Microsoft are up to with implementing new features in the relevant plugin. I get the impression VSCode leads the pack in terms of getting new copilot features, then other IDEs may or may not get the same features later, whereas a CLI tool gives everyone access to new features at the same time.</p>
<p>When I want to copy the agent’s output and paste it elsewhere, I’ve found that it’s easier to copy from Claude Code than the Copilot plugin in Rider. It seems like very simple functionality, but the formatting always seems to get messed up when copying from Copilot in Rider (and I would like a button to copy a response with a single click, though I appreciate that in agent mode it would be a little ambiguous exactly which messages should be included).</p>
<p>Claude Code is good for working with long prompts. The Copilot UI in Rider struggles with this, and normal keyboard shortcuts for navigating around a long piece of text don’t always work as expected. Claude Code has the shortcut CTRL+G to open the prompt in a separate text editor without disrupting the workflow at all, giving you full access to whatever text editing tooling you’re used to while writing prompts. I have found this very helpful. The same shortcut works when reviewing a plan produced by Claude Code, so you don’t have to read it in the terminal window or manually copy the plan elsewhere.</p>
<p>I prefer Claude Code’s approach to approving file changes and command line tools. Claude Code has 3 modes — plan mode (in which no files can be edited), auto–edit mode (in which all project files can be edited), and default (in which the user is prompted to approve edits to files). There’s a keyboard shortcut to cycle through them, making it very easy to allow Claude to make extensive changes when you want it to. Copilot (in Rider) doesn’t seem to have the option to auto–approve file edits, and the nearest setting I could find is to auto–approve after a short delay. As far as I can tell, you have to open the settings window every time you want to turn this on or off, which introduces much more friction than Claude Code.</p>
<p>Similarly, Copilot (in Rider) manages tool approval via the settings window. To be honest I’m not super confident with how (or if) it works, I’ve set up various approvals but still get asked for approval for those tool calls. Claude Code makes it really easy to approve specific commands without breaking flow, as the approval is done inline with the rest of the conversation. By default this is saved to <code>.claude/settings.local.json</code> in the directory where you are running Claude, but it’s also possible to save these settings to the <code>.claude/settings.json</code> in your user directory if you want them to apply to all directories (e.g. if you’re happy for claude to run <code>git log</code> in one project, you’re probably happy for it to run <code>git log</code> in all projects).</p>
<p>Copilot wants you to approve changes to files, but it’s already made the changes so they may have been picked up by external tools. You might build on top of them but the codebase is in a weird limbo state until you accept/reject the changes. This is disruptive to the workflow, and can cause code to be reverted unexpectedly if the approval/rejection comes a while later. I think it also causes Copilot to get confused when running <code>git add</code> or <code>git commit</code> sometimes. I’ve used auto-approve mode for Claude Code when I’m ready for it to make changes, and this has been a much smoother workflow.</p>
<p>Copilot has a nasty habit of opening multiple terminals in Rider, especially if it’s not getting the results it expects from the commands its running. It seems to like opening a new terminal to ensure it has a clean slate, but it doesn’t tidy up after itself by closing them again. Claude Code, of course, already runs in a terminal, so when it executes commands it doesn’t need to open a terminal elsewhere, keeping everything clean. Ironically, one of the advantages of Claude Code is that, being a CLI tool, it’s easy to run multiple instances in different directories. I’ve found this helpful for asking questions of a codebase without opening it in an IDE, something which Copilot can’t do.</p>
<p>Possibly the only thing (so far) that I’ve found I prefer in the Copilot UI is the ability to add files to the prompt. I find the UI somehow more intuitive than using <code>@</code> in Claude Code.</p>
<h1 id="heading-frustrations">Frustrations</h1>
<p>As I suspect is common to pretty much all LLM tools, Claude Code is sometimes prone to going off on strange tangents and being useless. My impression is that it does this less than GitHub Copilot, but still more than I’d like. It can waste a lot of time ‘thinking’ before reaching a useless conclusion.</p>
<p>Also, when I use Claude Code via windows command prompt it keeps creating <code>nul</code> files. If that happens to you, there are instructions for deleting them at <a target="_blank" href="https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code">https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code</a>.</p>
<h1 id="heading-concerns">Concerns</h1>
<p>These are my main concerns about the impact of using Claude Code:</p>
<ol>
<li><p>Will I stop learning? This is a broader concern about the use of LLMs generally, but I think it’s even more pronounced for Claude Code. The workflow around planning then implementing is great, but it doesn’t have a space for learning. Of course, you can still use Claude Code in others ways for learning, but it’s not baked into that (otherwise very helpful) workflow. I found that Copilot, lacking an obvious workflow, is easier to ask questions while in the flow of making other changes, blending a mixture of learning and implementing at the same time.</p>
</li>
<li><p>Is it too fun? Will I waste time playing around rather than doing useful work? There’s no denying that Claude Code feels to me like magic in a way that GitHub Copilot doesn’t, and I have no idea why that is!</p>
</li>
<li><p>As with all LLM tools, I am wary of the danger that the tool will feel fast but actually take longer than doing the work myself.</p>
</li>
</ol>
<h1 id="heading-conclusion">Conclusion</h1>
<p>I am aware that Claude Code isn’t the only CLI for agentic coding, but I’ve not played around with Gemini CLI / Copilot CLI / any others, so I don’t know how much my experiences are related to Claude Code itself, and how much they apply more generally to CLI agents.</p>
<p>I think the fact I’ve been working on upgrades recently has played in favour of Claude Code. AI tools are generally most impressive when working with a topic which is well documented online, but about which you don’t know too much. That gives much more room for them to impress you than a topic in which you are already well–versed. Some of the upgrades I’ve been doing have been in this territory, so I suspect my opinions may change as I use Claude Code for a more diverse set of tasks over time, some of which fall more within my technical comfort zone.</p>
<p>Having said that, so far it’s been a great tool that I’ve enjoyed using, and it has replaced GitHub Copilot as my go–to coding agent. I don’t know how my AI use will evolve, but I may use Claude Code for planning and implementing bigger changes, Claude web view or GitHub Copilot for more general research and learning, and Copilot for quick inline things in my IDE.</p>
<p>If you’ve used Claude Code, how do you experiences fit with what I’ve described above?</p>
]]></content:encoded></item><item><title><![CDATA[Month in review: January 2026]]></title><description><![CDATA[Things that happened

From a technical point of view, the main thing that happened in January is that I got access to Claude Code and have been playing around with that. I hope to write up my thoughts soon.

Things I learnt

I’ve published a number o...]]></description><link>https://techblog.timhilton.xyz/month-in-review-january-2026</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-january-2026</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Mon, 02 Feb 2026 17:45:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/TGeFx4x4NHU/upload/d9d7c8626cd7ad854ab15892943de625.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li>From a technical point of view, the main thing that happened in January is that I got access to Claude Code and have been playing around with that. I hope to write up my thoughts soon.</li>
</ul>
<h1 id="heading-things-i-learnt">Things I learnt</h1>
<ul>
<li>I’ve published a number of short Today I Learnt blog posts. I’ll link to them below so won’t repeat them here.</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a target="_blank" href="https://codemanship.wordpress.com/2025/12/30/the-ai-ready-software-developer-18-productivity-you-keep-using-that-word/">The AI-Ready Software Developer #18 – “Productivity”. You Keep Using That Word. – Codemanship's Blog</a></p>
<ul>
<li>This points out the misaligned incentives in the software industry, which I've noticed over the course of my career so far, and applies the insights to the impact of AI coding.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://codemanship.wordpress.com/2026/01/10/walking-skeletons-devops-drills/">Walking Skeletons, Delivery Pipelines &amp; DevOps Drills – Codemanship's Blog</a></p>
<ul>
<li>I love the idea of deliberately practicing starting new projects. I'm comfortable with the DevOps aspects of this but have long been aware I have never set up authentication from scratch on a greenfield project (though I have made substantial changes to existing authentication, like changing to a different authentication provider). I can imagine there could be a few things like that which I tend to take for granted, and might take a bit more effort than I'd expect if I were to create something substantial from scratch.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://ploum.net/2026-01-19-exam-with-chatbots.html">Giving University Exams in the Age of Chatbots</a></p>
<ul>
<li><p>This is a very interesting approach, allowing LLMs but giving clear rules about accountability.</p>
</li>
<li><p>Learning was, in this case, inversely correlated with LLM usage. This seems like bad news for me and my career (and other developers who have leaned into using LLM coding agents). I need to think more about this. What's the smart use of LLMs for me to ensure I still learn and stay sharp over the long term?</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-installing-a-net-sdk-can-break-net-maui-builds">TIL installing a .NET SDK can break .NET MAUI builds</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-rider-can-show-a-diff-of-a-directory-between-two-branches">TIL Rider can show a diff of a directory between two branches</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-the-format-for-pasting-environment-variables-into-a-rider-run-configuration">TIL the format for pasting environment variables into a Rider run configuration</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-c-property-overrides-are-separate-for-getters-and-setters">TIL C# property overrides are separate for getters and setters</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code">Deleting <code>nul</code> files created in error by Claude code</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/finding-a-bug-by-checking-git-history-one-commit-at-a-time">Finding a bug by checking git history one commit at a time</a></p>
</li>
<li><p><a target="_blank" href="https://techblog.timhilton.xyz/til-about-typescript-typing-as-const">TIL about typescript typing <code>as const</code></a></p>
</li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>First impressions of Claude Code after using GitHub Copilot</p>
</li>
<li><p>TIL why C# classes sometimes have multiple Dispose methods</p>
</li>
<li><p>TIL how to get a git diff between 2 branches within a folder</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL about typescript typing `as const`]]></title><description><![CDATA[I knew that typescript supports a type being a specific string, rather than the string type, so (for example) a function parameter can only receive the string “foo” and not a different string. Today I learnt that this can be done by using the as cons...]]></description><link>https://techblog.timhilton.xyz/til-about-typescript-typing-as-const</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-about-typescript-typing-as-const</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 28 Jan 2026 13:09:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/pXjpJhdOSdk/upload/33cfea943a3fe46eef6158d9da215dfb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I knew that typescript supports a type being a specific string, rather than the <code>string</code> type, so (for example) a function parameter can only receive the string “foo” and not a different string. Today I learnt that this can be done by using the <code>as const</code> syntax.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Foo {
  <span class="hljs-comment">// prop1 is typed as string</span>
  <span class="hljs-keyword">static</span> prop1 = <span class="hljs-string">'foo'</span>;

  <span class="hljs-comment">// prop2 is typed as 'foo'</span>
  <span class="hljs-keyword">static</span> prop2 = <span class="hljs-string">'foo'</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;

  <span class="hljs-keyword">static</span> func1 = <span class="hljs-function">(<span class="hljs-params">input: <span class="hljs-keyword">typeof</span> Foo.prop1</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Input was <span class="hljs-subst">${input}</span>`</span>);
  <span class="hljs-keyword">static</span> func2 = <span class="hljs-function">(<span class="hljs-params">input: <span class="hljs-keyword">typeof</span> Foo.prop2</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Input was <span class="hljs-subst">${input}</span>`</span>);
}

Foo.func1(<span class="hljs-string">'bob'</span>); <span class="hljs-comment">// works fine</span>
Foo.func2(<span class="hljs-string">'bob'</span>); <span class="hljs-comment">// Argument of type '"bob"' is not assignable to parameter of type '"foo"'.</span>
</code></pre>
<p>However, calling <code>typeof</code> will still return <code>'string'</code> rather than <code>'foo'</code>. That’s because using <code>as const</code> only affects how typescript checks types, not the javascript output which is produced from the typescript source code.</p>
]]></content:encoded></item><item><title><![CDATA[Finding a bug by checking git history one commit at a time]]></title><description><![CDATA[I’m far from a command line wizard, but am gradually picking up more tricks and tips as time goes by.
I recently found a styling bug I was confident I’d introduced in the previous few commits, but I wasn’t sure which one. In the past I’ve used git bi...]]></description><link>https://techblog.timhilton.xyz/finding-a-bug-by-checking-git-history-one-commit-at-a-time</link><guid isPermaLink="true">https://techblog.timhilton.xyz/finding-a-bug-by-checking-git-history-one-commit-at-a-time</guid><category><![CDATA[command line]]></category><category><![CDATA[Git]]></category><category><![CDATA[Bugs and Errors]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Tue, 27 Jan 2026 10:40:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/iLrMmnIL8x4/upload/b4c2524a6b482a8efad6508b2695e072.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’m far from a command line wizard, but am gradually picking up more tricks and tips as time goes by.</p>
<p>I recently found a styling bug I was confident I’d introduced in the previous few commits, but I wasn’t sure which one. In the past <a target="_blank" href="https://techblog.timhilton.xyz/how-to-find-buggy-code-using-git-bisect">I’ve used git bisect</a> but on this occasion I took a different approach. I knew I wouldn’t have to go back many commits, but I wasn’t sure how far back to go in order to be confident of finding working code (which is necessary for git bisect). I decided to go back through my git history one commit at a time and test each time. The bug was in a vue app and I wasn’t confident whether or not hot reloading would work given the nature of the changes, so I stopped the app each time and served it again.</p>
<p>The approach I took was to simply run the following command repeatedly, testing the app each time:</p>
<pre><code class="lang-bash">git checkout HEAD~1; npm run serve
</code></pre>
<p>This checks out the previous commit (which is what <code>HEAD~1</code> means) then runs the <code>serve</code> script from the project’s <code>package.json</code> file. While the bug was still present, I simply stopped the script and reran it which moved me back again to the previous commit.</p>
<p>I don’t often use the <code>HEAD~1</code> syntax in git but I’m becoming more familiar and confident with it, and finding more occasions where it’s useful to me. I’m also becoming gradually more confident combining commands using <code>;</code>, and this was a good example of a case when even a short time ago I wouldn’t have been able to do this so simply.</p>
]]></content:encoded></item><item><title><![CDATA[Deleting `nul` files created in error by Claude code]]></title><description><![CDATA[I’ve recently been given access to Claude Code at work, so I’ve been trying it out to see how I get on with it. I tend to run it from a Windows Command Prompt, and I’ve noticed that it keeps creating files named nul with 0KB size. Worse, when I try t...]]></description><link>https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code</link><guid isPermaLink="true">https://techblog.timhilton.xyz/deleting-nul-files-created-in-error-by-claude-code</guid><category><![CDATA[claude-code]]></category><category><![CDATA[Windows]]></category><category><![CDATA[Command prompt]]></category><category><![CDATA[command line]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Sat, 24 Jan 2026 15:25:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/HjBcAVWlxnE/upload/51231dc434290cda481f3d5d7d35e64c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’ve recently been given access to Claude Code at work, so I’ve been trying it out to see how I get on with it. I tend to run it from a Windows Command Prompt, and I’ve noticed that it keeps creating files named <code>nul</code> with 0KB size. Worse, when I try to delete them I have to provide admin credentials, and even as an admin the file isn’t actually deleted and reappears after refreshing Windows Explorer.</p>
<p>Claude Code sometimes runs commands which contain something along the lines of <code>&gt; ./nul</code>, which I assume does something meaningful in Bash but not in Windows Command Prompt. Windows creates a file instead of whatever the intended behaviour is. Something about the filename <code>nul</code> means the normal Windows operations for deleting a file can’t be used. So how can I get rid of the file?</p>
<p>Happily, once I explained the problem to Claude, it gave me a Windows Command Prompt command to delete the file:</p>
<pre><code class="lang-bash">del <span class="hljs-string">"\\?\%CD%\nul"</span>
</code></pre>
<p>This command needs running in the same directory as the <code>nul</code> file.</p>
<p>Apparently, the <code>\\?\</code> prefix bypasses Windows' normal checks for reserved filenames, allowing you to directly access and delete the <code>nul</code> file. Admin permissions are not required. I’ve updated Claude’s instructions to try and avoid it creating more of these <code>nul</code> files in the future, but I suppose I’ll need to wait a while to see how that turns out!</p>
]]></content:encoded></item><item><title><![CDATA[TIL C# property overrides are separate for getters and setters]]></title><description><![CDATA[I recently hit an interesting gotcha with some code in a C# codebase i was working with. It baffled me because I didn’t understand how this could compile.
MyClass.Foo has a getter but no setter, yet an instantiated MyClass can have the Foo property s...]]></description><link>https://techblog.timhilton.xyz/til-c-property-overrides-are-separate-for-getters-and-setters</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-c-property-overrides-are-separate-for-getters-and-setters</guid><category><![CDATA[C#]]></category><category><![CDATA[override]]></category><category><![CDATA[getter and setter]]></category><category><![CDATA[TIL]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Sat, 24 Jan 2026 15:17:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_BBZMuDnOPQ/upload/c796fb3e51034c085134b5aed4df6a81.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently hit an interesting gotcha with some code in a C# codebase i was working with. It baffled me because I didn’t understand how this could compile.</p>
<p><code>MyClass.Foo</code> has a getter but no setter, yet an instantiated <code>MyClass</code> can have the <code>Foo</code> property set! How is that happening, and what does it do?</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span> : <span class="hljs-title">LibraryClass</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> OtherProperty { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">string</span> Foo =&gt; OtherProperty; <span class="hljs-comment">// getter-only, no way to set the value</span>
}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DoThing</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">var</span> myClass = <span class="hljs-keyword">new</span> MyClass
        {
            <span class="hljs-comment">// How does this compile? There is no setter for Foo.</span>
            Foo = <span class="hljs-string">"I'm setting this property"</span>
        };
    }
}
</code></pre>
<p>It turns out that even though the <code>Foo</code> property only has a getter defined within <code>MyClass</code>, there’s a setter on the <code>Foo</code> property within <code>LibraryClass</code>, and this means it’s valid to write to the property within <code>MyService</code>.</p>
<p>The reason is that the <code>override</code> keyword is only overriding the getter, not the whole property. The setter therefore still exists in its original form, and can be used. What this does it write the set value to the backing field, but it’s not possible to get that value back out and do anything with it. It’s not useful, but it is valid and it does compile.</p>
]]></content:encoded></item><item><title><![CDATA[TIL the format for pasting environment variables into a Rider run configuration]]></title><description><![CDATA[Summary
I was editing a run configuration in Rider and needed to add several environment variables to it. There’s a button in the dialogue to paste them in, but no guidance regarding the format of the data, and no feedback if you paste the wrong form...]]></description><link>https://techblog.timhilton.xyz/til-the-format-for-pasting-environment-variables-into-a-rider-run-configuration</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-the-format-for-pasting-environment-variables-into-a-rider-run-configuration</guid><category><![CDATA[#rider]]></category><category><![CDATA[jetbrains rider]]></category><category><![CDATA[Environment variables]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 14 Jan 2026 14:20:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bw8iOoOzjc0/upload/92afa526c213118e3aebf4c34fd4e14a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-summary">Summary</h1>
<p>I was editing a run configuration in Rider and needed to add several environment variables to it. There’s a button in the dialogue to paste them in, but no guidance regarding the format of the data, and no feedback if you paste the wrong format.</p>
<h1 id="heading-what-is-a-run-configuration">What is a run configuration?</h1>
<p>Rider allows you to create run configurations, which can be selected from a dropdown and have Run/Debug/Stop buttons next to them. When you open a solution, Rider populates these with several defaults depending on the types of projects in your solution, but you can edit these and add more of your own. It’s this section of the UI:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768400152415/e0619f4e-f4f6-4ac0-a294-34e810c9a070.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-how-to-define-environment-variables">How to define environment variables</h1>
<p>In my case, the relevant project was an Azure function. Editing the run configuration for it, there is a field for Environment Variables. You can type directly into this textbox, but if you click the icon on the right then you can add them as Name/Value pairs, and there’s an icon for pasting the data in.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768400365468/3987f93f-b78a-4811-98aa-7754fbfee3f4.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-what-format-to-use">What format to use</h1>
<p>To paste environment variables into the run configuration, you need your variables in this format:</p>
<pre><code class="lang-plaintext">ThingEnabled=true;MySetting=foo;OtherSetting=bar
</code></pre>
<p><a target="_blank" href="https://www.jetbrains.com/help/rider/Run_Debug_Configuration.html#envvars-progargs">https://www.jetbrains.com/help/rider/Run_Debug_Configuration.html#envvars-progargs</a> does hint at this format. It says “In the Environment variables field, type the variable name and value: <code>&lt;name&gt;=&lt;value&gt;</code>. If you add several variables, they should be separated with semicolons.” but doesn’t mention pasting so it’s easy to miss. More significantly, there’s no guidance within the IDE so you have to go looking for the documentation to find out the format.</p>
]]></content:encoded></item><item><title><![CDATA[TIL Rider can show a diff of a directory between two branches]]></title><description><![CDATA[Today I learnt that you can right–click on any project or directory within the Solution panel, and under the Git menu there is the option to Compare with Branch or Tag (or a separate option to Compare with Revision). This allows you to easily find al...]]></description><link>https://techblog.timhilton.xyz/til-rider-can-show-a-diff-of-a-directory-between-two-branches</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-rider-can-show-a-diff-of-a-directory-between-two-branches</guid><category><![CDATA[jetbrains rider]]></category><category><![CDATA[#rider]]></category><category><![CDATA[Git]]></category><category><![CDATA[Diff]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 14 Jan 2026 11:30:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KFJSGahF6hg/upload/22e671c829f2416f0bb9c4848f2245e7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today I learnt that you can right–click on any project or directory within the Solution panel, and under the Git menu there is the option to Compare with Branch or Tag (or a separate option to Compare with Revision). This allows you to easily find all changes between two branches within a specific folder.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768389953657/6e80cdd9-999a-491e-86cc-043e5743a038.png" alt class="image--center mx-auto" /></p>
<p>Clicking this opens a new panel containing the list of changed files, and clicking on the files shows the diffs in the same UI as other diffs within Rider.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768390067867/51d58c1a-5afd-4372-81cf-683dbab3bd98.png" alt class="image--center mx-auto" /></p>
<p>I always like to find new features and tools which I already have access to. This feature was useful for me today, and I daresay it will be useful again.</p>
<p>As an aside, this is the git command to get a diff of all changes within a specified directory on the current branch since it diverged from <code>develop</code>.</p>
<pre><code class="lang-bash">git diff develop...HEAD -- Path/To/Directory
</code></pre>
<p>If there’s a lot, you can append <code>| clip</code> to copy the output to your clipboard, or append <code>&gt; diff.txt</code> to put it in a new text file.</p>
]]></content:encoded></item><item><title><![CDATA[TIL installing a .NET SDK can break .NET MAUI builds]]></title><description><![CDATA[Introduction
I was flummoxed when working with a .NET MAUI app when I opened the application and it wouldn’t build. I had previously worked on it a month or so ago and had set everything up on my laptop so it would build, yet without any code changes...]]></description><link>https://techblog.timhilton.xyz/til-installing-a-net-sdk-can-break-net-maui-builds</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-installing-a-net-sdk-can-break-net-maui-builds</guid><category><![CDATA[#maui]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[claude.ai]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Mon, 12 Jan 2026 09:37:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/uh0u8OH4zuE/upload/47b6b8472267a2c77cc5e90044be5ff6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>I was flummoxed when working with a .NET MAUI app when I opened the application and it wouldn’t build. I had previously worked on it a month or so ago and had set everything up on my laptop so it would build, yet without any code changes there were suddenly 5 build errors.</p>
<p>After a lot of time wasted trying to fix the problem, I eventually realised the key piece of information I hadn’t considered — the previous day, I had installed the .NET 10 SDK on my laptop for the first time. This broke the build for my .NET MAUI app, and this blog post explains why that happened. At the end, I reflect on my use of AI in solving this problem, and how it both helped and hindered.</p>
<h1 id="heading-build-errors">Build errors</h1>
<p>I got 5 build errors, two of which were basically the same (<code>NETSDK1202</code> for two different workloads).</p>
<blockquote>
<pre><code class="lang-plaintext">9&gt;Microsoft.NET.EolTargetFrameworks.targets(38,5): Error NETSDK1202 : The workload 'net8.0-android' is out of support and will not receive security updates in the future. Please refer to https://aka.ms/maui-support-policy for more information about the support policy.
9&gt;ProjectName.App.csproj: Error NU1012 : Platform version is not present for one or more target frameworks, even though they have specified a platform: net8.0-android, net8.0-ios
9&gt;ProjectName.App.csproj: Error NU1015 : The following PackageReference item(s) do not have a version specified: Microsoft.Maui.Controls, Microsoft.Maui.Controls.Compatibility
9&gt;Microsoft.NET.EolTargetFrameworks.targets(38,5): Error NETSDK1202 : The workload 'net8.0-ios' is out of support and will not receive security updates in the future. Please refer to https://aka.ms/maui-support-policy for more information about the support policy.
9&gt;Microsoft.NET.TargetFrameworkInference.targets(252,5): Error NETSDK1135 : SupportedOSPlatformVersion 11.0 cannot be higher than TargetPlatformVersion 1.0.
</code></pre>
</blockquote>
<h1 id="heading-explanation">Explanation</h1>
<p>At the root of my solution was a <code>global.json</code> file which looked like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"sdk"</span>: {
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"8.0.0"</span>,
    <span class="hljs-attr">"rollForward"</span>: <span class="hljs-string">"latestMajor"</span>,
    <span class="hljs-attr">"allowPrerelease"</span>: <span class="hljs-literal">false</span>
  }
}
</code></pre>
<p>The application was using .NET MAUI 8, which is why <code>version</code> is set to 8.0.0. However, it uses <code>"rollForward": "latestMajor"</code>. This means it uses the latest .NET SDK which is installed. Installing the .NET 10 SDK effectively changed what version the application is using. Using the later version, the dotnet workloads which the MAUI project used weren’t compatible.</p>
<p>Running <code>dotnet workload restore</code> installed workloads which were compatible with .NET 10, but that broke things in the project because it’s not yet upgraded to .NET 10.</p>
<h1 id="heading-solution">Solution</h1>
<p>Once I understood this problem, the fix was a simple change to the json. I used <code>"rollForward": "latestFeature"</code> instead, which means it uses the latest version of v8, but doesn’t upgrade to later major versions. Once I’d cleaned the output directories, the build then ran as it had before I’d installed the .NET 10 SDK and passed.</p>
<h1 id="heading-lessons-about-using-ai">Lessons about using AI</h1>
<p>I used AI tools in trying to fix this problem, because to begin with I had no idea what was wrong. AI was both a help and a hindrance, but definitely more of a hindrance overall. Because I was out of my comfort zone, I was too slow to abandon the use of AI even though I could see it wasn’t making any progress.</p>
<p>I started by trying to get GitHub Copilot to fix the build errors. Unfortunately it dug itself into a hole making unsuitable changes, and couldn’t get out of it. It ran the build repeatedly, seemingly unable to believe the build was still broken, and determined to think that it could fix them by clearing package caches one more time. With hindsight, I wonder if GitHub Copilot, as a coding agent, has been biased toward action too much for this problem. It failed to do any diagnosis, and because I didn’t realise what had caused the problem I wasn’t able to provide that information.</p>
<p>I had much more success asking Claude (via the web chat interface) about the errors. It’s hard to say how much the difference was caused by using Claude rather than Copilot, as by this point I’d realised the possibility that the .NET SDK installation was the root cause, and this was critical information. Either way, it was able to explain the root cause and how to fix it, and was much more useful.</p>
]]></content:encoded></item><item><title><![CDATA[Month in review: December 2025]]></title><description><![CDATA[Not much this month, as it's been a busy month outside of technical thinking.
Things that happened

I launched my website — https://www.timhilton.xyz/. It's vibe–coded slop, but it gives me a dumping ground for random bits and bobs. It's mostly techn...]]></description><link>https://techblog.timhilton.xyz/month-in-review-december-2025</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-december-2025</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Wed, 31 Dec 2025 21:38:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/5AiWn2U10cw/upload/c68b162a6355d1d8205bb569411e9c81.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Not much this month, as it's been a busy month outside of technical thinking.</p>
<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li>I launched my website — <a target="_blank" href="https://www.timhilton.xyz/">https://www.timhilton.xyz/</a>. It's vibe–coded slop, but it gives me a dumping ground for random bits and bobs. It's mostly technical at the moment, though I may find time for putting other things on it in the future.</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a target="_blank" href="https://lyra.horse/blog/2024/05/stealing-your-telegram-account-in-10-seconds-flat/">Stealing your Telegram account in 10 seconds flat Ʊ lyra's epic blog</a></p>
<ul>
<li>It feels magical that there are no images on this blog post, even though there are (what appear to be) screenshots. Each one is actually handcrafted HTML &amp; CSS, which is mindblowing! As Teller (of Penn and Teller fame) said, “Sometimes magic is just someone spending more time on something than anyone else might reasonably expect.”</li>
</ul>
</li>
<li><p><a target="_blank" href="https://mikelovesrobots.substack.com/p/wheres-the-shovelware-why-ai-coding">Where's the Shovelware? Why AI Coding Claims Don't Add Up</a></p>
<ul>
<li>I thought this was a helpfully evidence–based analysis of LLM coding. It's inspired me to try and track a little more objectively what impact using an LLM has on my own productivity. I've often thought it's unclear if the overall impact is positive or negative for me, though there are definitely <em>some</em> tasks which are far faster with an LLM. I don't expect to completely abandon using LLMs, but it's possible I may use them for fewer tasks or only specific tasks.</li>
</ul>
</li>
<li><p><a target="_blank" href="https://codemanship.wordpress.com/2025/11/25/the-future-of-software-development-is-software-developers/">The Future of Software Development is Software Developers – Codemanship's Blog</a></p>
<ul>
<li>I can't remember what struck me about this, but I'm sharing it anyway 😅</li>
</ul>
</li>
</ul>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li>Nothing this month.</li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>Claude fixing an image</p>
<ul>
<li>This was an interesting case of Claude fixing a problem which I would have had no idea how to approach.</li>
</ul>
</li>
<li><p>Sharing github copilot prompts across multiple IDEs</p>
</li>
<li><p>What keyboard shortcuts I use as a professional programmer</p>
<ul>
<li>I'm hoping to publish this at some point, but have only just started analysing what shortcuts I use most.</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Month in review: November 2025]]></title><description><![CDATA[Things that happened

I was working on an intermittent bug, trying to find the precise conditions which cause it by reading through code. I make notes in Obsidian as I go. I think I need to get better at creating summaries and headlines which clearly...]]></description><link>https://techblog.timhilton.xyz/month-in-review-november-2025</link><guid isPermaLink="true">https://techblog.timhilton.xyz/month-in-review-november-2025</guid><category><![CDATA[Monthly review]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 05 Dec 2025 19:00:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/E-EEQSjDdck/upload/cf3da8bba7904c10ad4243f0d504968b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-things-that-happened">Things that happened</h1>
<ul>
<li><p>I was working on an intermittent bug, trying to find the precise conditions which cause it by reading through code. I make notes in Obsidian as I go. I think I need to get better at creating summaries and headlines which clearly communicate things I'm learning from the code. At the moment I'm good at recording all the details, and I'm good at creating overall summaries, but I don't do anything to create summaries in the middle. For example, perhaps the high level summary is that a piece of code uses a particular setting, and the detailed version lists all the method calls which the execution path takes. I could do with summaries of those code paths, saying things like 'this code gets this setting from the database' without spelling out how that works.</p>
</li>
<li><p>I've removed a few apps from running on Windows startup, and have instead written a batch script to open them. I run that script manually from a desktop shortcut and it opens the apps much faster than the Windows startup routine did. It was previously slow enough that I would sometimes be waiting 5–10 minutes for apps to open. Now they open in seconds.</p>
</li>
<li><p>I've started trying to consolidate my Keyboard Shortcuts across the different apps I commonly use.</p>
</li>
<li><p>My company has started holding in-person engineering discussions, and this month is the first time I was able to go to one. It was a good discussion, though I'll wait to see some concrete changes come out of the discussion before giving it an unqualified thumbs–up.</p>
</li>
</ul>
<h1 id="heading-things-i-learnt">Things I learnt</h1>
<ul>
<li><p>I was surprised how badly Claude did trying to summarise 2 documents for me in preparation for a meeting. The process of going through the documents and creating my own summary was invaluable in preparing for the meeting, but until I'd done that I didn't know what information I wanted in the summary. Claude wasn't able to work it out, and also added (incorrect) information which wasn't in the documents.</p>
</li>
<li><p>I've twice asked GitHub Copilot to find the exact bit of code which did something, using Claude Sonnet 4.5 both times. I've been very impressed by the output — it has provided a markdown document with a lot of useful detail and code snippets, even though I hadn't specified any of this. I've not yet verified the accuracy of these documents, although (as always) they look plausible.</p>
</li>
<li><p>My company has started using Dependency Track for keeping on top of the libraries we depend on. I think it's a great idea, and it's a while since it was first suggested, so it's nice seeing it come to fruition. I knew nothing about it beyond the basic concept, but I was asked to set it up for one of our projects, so I had the chance to learn more about how it works.</p>
</li>
<li><p>A colleague wrote a SQL script using <code>OPENJSON</code> which I wasn't familiar with. It was interesting to see how this could be used to convert some JSON data into a table.</p>
</li>
<li><p>Azure DevOps pipelines can run based on a definition hosted in GitHub.</p>
</li>
<li><p>EF Core includes <a target="_blank" href="https://learn.microsoft.com/en-us/ef/core/querying/related-data/eager#filtered-include">Filtered Includes</a>. This has been available functionality for a while, but I wasn't aware of it. I sounds like a very useful performance improvement, and is definitely something I want to be mindful of when writing EF queries.</p>
</li>
</ul>
<h1 id="heading-things-ive-read-watched-listened-to">Things I've read / watched / listened to</h1>
<p><em>These are my own reflections from the content, not necessarily the main point of the content.</em></p>
<ul>
<li><p><a target="_blank" href="https://lukeplant.me.uk/blog/posts/why-im-not-letting-the-juniors-use-genai-for-coding/">Why I’m not letting the juniors use GenAI for coding -</a> <a target="_blank" href="http://lukeplant.me.uk">lukeplant.me.uk</a></p>
</li>
<li><p><a target="_blank" href="https://diataxis.fr/">Diátaxis</a> — A systematic approach to technical documentation authoring.</p>
<ul>
<li><p>I like this concept and the categories it creates.</p>
</li>
<li><p>I'm not keen on the use of Action, Cognition, Acquisition and Application. I find those terms too cerebral to be intuitive without more context. I think I prefer the ideas of 'working' vs 'learning', and 'understanding' vs 'doing'.</p>
</li>
<li><p>I'll definitely want to give this more thought in my professional life.</p>
</li>
<li><p>See also: <a target="_blank" href="http://documentation-writer.prompt.md">documentation-writer.prompt.md</a> <a target="_blank" href="https://github.com/github/awesome-copilot/blob/main/prompts/documentation-writer.prompt.md">· github/awesome-copilot</a> (which is where I came across this framework).</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-things-other-people-said">Things other people said</h1>
<p><em>Quote of the month</em></p>
<p>"My basic rule of thumb for LLMs is that I use them only in contexts where:</p>
<ul>
<li><p>accuracy and reliability does not matter (some "creative writing" type use cases), or,</p>
</li>
<li><p>the nature of the task forces me to immediately verify the accuracy, and doing so is easy (such as some software development uses)."</p>
</li>
</ul>
<p><a target="_blank" href="https://lukeplant.me.uk/blog/posts/should-we-use-llms-for-christian-apologetics/">Should we use AI and LLMs for Christian Apologetics? -</a> <a target="_blank" href="http://lukeplant.me.uk">lukeplant.me.uk</a></p>
<h1 id="heading-things-ive-published">Things I've published</h1>
<ul>
<li><a target="_blank" href="https://tjhilton.hashnode.dev/til-rider-can-show-sql-results-inline-within-query">TIL: Rider can show SQL Results inline within query</a></li>
</ul>
<h1 id="heading-things-i-havent-published">Things I haven't published</h1>
<p><em>Most ideas I have for blog posts never see the light of day because I don't find the time to write them. Here's what I didn't get round to.</em></p>
<ul>
<li><p>How to manage email templates in Outlook</p>
</li>
<li><p>Asking GitHub copilot to explain code and comparing different models</p>
</li>
<li><p>Opening my startup applications faster on Windows 11</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[TIL: Rider can show SQL Results inline within query]]></title><description><![CDATA[I use JetBrains Rider as my primary IDE, and I like to use it for as much of my development process as possible. I prefer to avoid jumping around between multiple different applications if I can, so when I want to run some SQL I typically use Rider r...]]></description><link>https://techblog.timhilton.xyz/til-rider-can-show-sql-results-inline-within-query</link><guid isPermaLink="true">https://techblog.timhilton.xyz/til-rider-can-show-sql-results-inline-within-query</guid><category><![CDATA[#rider]]></category><category><![CDATA[jetbrains rider]]></category><category><![CDATA[SQL]]></category><category><![CDATA[IDEs]]></category><dc:creator><![CDATA[Tim Hilton]]></dc:creator><pubDate>Fri, 14 Nov 2025 11:01:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763118456807/224ed301-9987-4358-95aa-8c575bd9de98.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I use JetBrains Rider as my primary IDE, and I like to use it for as much of my development process as possible. I prefer to avoid jumping around between multiple different applications if I can, so when I want to run some SQL I typically use Rider rather than opening SSMS or Azure Data Studio (or the VS Code plugin which is replacing it).</p>
<p>Today I learnt that Rider contains an option to display the results of a query inline within the SQL window. I don’t think this will be my default way of viewing SQL results, I think I’ll stick with a table of data at the bottom of the window, but I can definitely see this being useful for debugging long queries by checking the results at each step of a lengthy process. I always like to know what tools are available even if I don’t have imminent plans to use them, because it opens up more possibilities for the future.</p>
<p>Details of how to enable this (either per–file or for all queries) are in the <a target="_blank" href="https://www.jetbrains.com/help/rider/Viewing_Query_Results.html#in_editor_results">official documentation</a>.</p>
]]></content:encoded></item></channel></rss>