Content-Type: text/plain

Welcome to week two of the aforementioned weekly updates.

#web

My websites, web services, and all related infrastructure (as code).

The highlight this week was removal of static internal ports. I mentioned last week that I was thinking about migrating to Unix domain sockets, but that wasn't solving the actual problem: it was replacing a port number with a string label, which really isn't much better.

The kind of internal ports I'm talking about are the ones the Go web servers listen on (one per site) which Caddy reverse-proxies to. They are purely internal, so the port numbers can be assigned dynamically. The network is only used by the containers, so there's no chance of port conflicts, either.

So that's what was done: site definitions moved from a map to a list, in which the index defines the port offset, which is added to a base port to produce the final port that's then fed back into Caddy via environment variables.

Other web-related changes were not quite as satisfying. An influx of requests to non-existent subdomains saturating the logs made me return to static subdomain definitions. I also omitted empty bundles from the HTML output and preloaded fonts to remove a FOUT.

#system

Everything related to my local personal systems and their configuration (as code).

Not many changes to my pi extensions this week, and it's mostly optimisation work.

The bg extension (for agents to manage background processes) now injects a message when a background process starts (user-initiated) or terminates, as there were several instances of agents making incorrect assumptions because they were not aware of state changes.

The task list extension (for agents to manage task lists) had a fragmented toolset, spread out over 7 (!) different tools. This is the problem with incremental design. You need to take a step back sometimes and look at what you've created.

Tool Description
task_list read the list
task_set replace the list
task_add append a task
task_complete mark a task complete
task_restore mark a task incomplete
task_edit edit a task
task_clear clear tasks

These were collapsed into four.

Tool Description Replaces
tasklist_get read the list task_list
tasklist_set replace the list task_set, task_edit, task_clear
tasklist_append append tasks task_add
tasklist_mark toggle task completion task_complete, task_restore

This was possible by making a few changes. Firstly, the tools were updated to work with task titles rather than IDs. Agents are capable of reiterating the task title they want to reference, which means no longer needing to assign tasks persistent IDs.

The task_complete and task_restore tools used to accept a list of IDs, but tasklist_mark now simply accepts an object like { complete: boolean, titles: string[] }, no ID recall necessary.

I thought tasklist_set would be the only setter, but tasklist_append was a must-have for the very common case of adding a task to the end of the list. There's no point in providing surgical insertion tools, though, as for such precise edits it's simpler to regenerate the entire task list afresh.

Finally, task_clear was redundant and is now achieved by passing an empty array to tasklist_set.

#torch

My home automation dashboard, complementary to Home Assistant.

This update turned into its own post, so will follow later in the week. The summary is that energy reporting broke for the smart plug I use to monitor my dryer, and I had some fun fixing it.

#upgrades

My thoughts about a package upgrade vetting process.

I've been reviewing the upgrade process for my machines. Package sources include the official Arch repositories, the AUR, Ruby gems, and more. Each of these is a potential attack vector, and each upgrade brings risk.

Supply chain attacks are on the rise. In my time in the industry, it's always been accepted that vetting dependencies would be a good thing to do, if only we had the time. We may not have more time, but we do have a time compressor in the form of agentic AI.

Now we can gather up the details of a full system upgrade into text form and feed that to an agent to review as thoroughly as needed. Not just for security issues, but also compatibility issues, and anything else you can think of.

A dependency review could range from looking at the changelog to cloning every dependency and transitive dependency, then analysing the source code in extreme depth. However, prompt injection is an important consideration. Frontier models are already very good at detecting it, but they're not perfect.

For now I've encoded this process in the form of a skill as a PoC but I'd like to think about if this could become something more.

#housekeeping

Across various projects:

  • Updated even more pinned URLs in mise.locks after mise changed the domain upstream
  • Moved --color flag after the golangci-lint run subcommand