Notes for August 17–23

Tomorrow I’m going back to work after a rather lopsided summer break (not feeling up to it physically or mentally), and the social network pendulum is swinging back into a bit of normalcy as I progressively tune nearly all of them out.

Twitter (which I refuse to name otherwise) is still a controversial (but time-boxed) part of my news intake since has turned into a desert for any serious discussions other than violent opposition, LinkedIn is still crammed with sales-y ego trips and keeps peddling glitz rather than substance, but I do need to figure out what is going on.

For science, I dipped into a few of them over the weekend, which did not improve my general mood–it doesn’t look like I am going “back” into a saner industry (rather the opposite), but at least I sort of got my book reading habits back over the break, and I can finally say I did more productive stuff than just doomscrolling.

3D Stuff

First my shaver broke in the most subtly annoying way (the retaining latch was clearly not designed to outlive the mechanism), then I decided to do something about designing and printing cases for a bunch of SBCs and realised I no longer need to buy dust mesh for those:

A few things that needed fixing
A few things that needed fixing

Turns out I can print 0.1 mm-thick dust filters with zero issues using PLA and a 0.4 mm nozzle, even if the prints themselves are a bit susceptible to minor flaws if the filament is aged. But being able to design them to size (and shape) is promising.

The Future Is Not Evenly Distributed

I ended up trying on the only machine I have that can somewhat run it at speed (my MacBook Pro M3, which has 36GB RAM), and… it sort of worked (with RAM to spare, which is nice), but quickly reminded me why I prefer doing on servers as the battery visibly drained and the machine became warm enough on my lap to be noticeable.

Doing small programming tasks (algorithms or singleton functions) without an agentic harness context was doable (so I could probably rely on it if I was doing the same stuff I needed three years ago), but it takes forever (something like 30 minutes) to churn through a basic sub-32Ktok agent context, so… I still need better hardware.

Claw in a Bun

Under the pretext of upgrading to , I did some of the long-standing cleanup work in piclaw, dropped in a few fixes and dependency updates, and let it loose.

As recounted , I just want to use the thing now, so unless there’s some amazing new frontier model out or some critical fix, I’m going to try to throttle back on it–also, my free Codex subscription is running out soon, so when that goes I’ll have to re-think how to keep my work and hobbies separate.

But things are looking up–RAM use seems lower, most of the annoyances I had seem to have been fixed, and there are (crosses fingers) no immediate issues.

Homebridge 2.4

After a very careful waiting period, I finally updated to homebridge 2.x, which, of course, broke things. In my case I am using homebridge-webos-tv to control my living room TV and homebridge-mqtt to create virtual HomeKit devices from , and they both broke instantly when I upgraded to 2.4.0 (yeah, I waited that long) because they seem to be fairly niche and not fully tested with 2.x yet.

The solution (which took a while to figure out) was to disable their child bridges and force the use of the bonjour-hap advertiser in the top config stanza:

"bridge": {
  "name": "Homebridge",
  "username": "0E:…",
  "port": 51826,
  "pin": "123-45-678",
  "advertiser": "bonjour-hap" <- ADDED THIS
}

At this time, nearly all of my automations are pure native HomeKit, with only a few things patched through (which I upgraded to 5.0.4 this week as well), which is great except that it exposes me to Apple’s general penchant for breaking things every now and then.

But everything “just worked” aside from a minor configuration glitch in a “Virtual Bell” accessory that I use to merge our doorbells into a single alert, and my usual fiends, the ESP32 cameras that we still use to check on open windows and stuff.

Those tiny and slow cameras are long overdue for replacement, possibly with something like the Aqara G100. The M5Stack hardware was never really meant to be compatible, but I’ve been hacking at the firmware for years and they have suffered through years of Apple breaking things subtly (without even documenting the right behaviour for camera devices), so at this point I keep them around for a sort of sport.

Minor Annoyances

If you’ve missed my , well, I’ve been trying to get a lot of writing done on my iPad, and… stuff happened. I’ve also put together a swift-app-template to see if I can standardise a bit the stuff I am doing, and made a point of cramming in as many quality-control steps as possible so I don’t keep reinventing the wheel, starting with SwiftPM defaults and ending with a comprehensive set of agent skills consolidated from my library.

I also pinned down and fixed a site rendering bug (images inserted using certain ancient formats of references would be interpreted as page links).

Reading

Building on last week’s book marathon, I finished The Shattering Peace by John Scalzi, which was a nice, fun romp, and got started (again) on Norse Mythology, still one of my favourite reads.

I think I’m ready for whatever Loki tosses at me tomorrow when I log back in.

Apple Papercuts Summer Edition

This is a short follow-up to my piece, wherein I bunched together a few more annoyances that I’ve come across while using my extensively on vacation.

If you needed any more proof that doesn’t really do QA testing, I think just two of these would be enough. And I’ve confirmed they are all still there in 26.6.1, freshly released last week.

The Spotlight Near Miss

At first, I thought this was a hardware problem. My brand new had been giving me some odd glitches of late (I keep having to physically reconnect it for keypresses to register), but after a few days of using a desktop Bluetooth keyboard I am positive that all the input glitches I’m having are a software problem.

One of the main symptoms is that invoking Spotlight with Cmd+Space works but then typing inside Spotlight fails to register. But a second attempt works, so my attempts at invoking Mail every day have the same outcome:

  • First attempt at Cmd+Space, M… does nothing useful–Spotlight appears but doesn’t show “m”
  • Hit Cmd+Space, M again–“m” appears and, lo and behold, “Mail (open)” is suggested (after an embarrassingly long pause, but hey, at least it happens)

Yes, I could tap the icon. But if the above doesn’t convince you that nobody at Apple actually tested this, then I don’t know what would. Oh, wait, I have a couple more:

The North Star Is Portrait Orientation

Another interesting bug that has surfaced recently is that nearly every time I use a Bluetooth mouse with my iPad when it’s plugged into an external display, iPadOS swaps the X and Y axes, which is just… ridiculous.

The steps are always the same:

  • Wake up the iPad while it’s plugged into an external display (typically by swiping the Home Screen up so that Face ID begrudgingly notices I’m here).
  • Turn the mouse on, move it up
  • Wonder why the cursor is moving left

You know why that happens? Because my iPad is in landscape mode, not portrait, and when the mouse is detected, iPadOS does not take that into account. But the Home Screen was in landscape mode. I swiped “up”. This is not fucking rocket science, guys.

And, again, for this one there are zero excuses.

SpringBoard Needs Frequent Breaks

Every now and then, while my iPad is plugged into an external display, my entire iPadOS “session” crashes–black screen, emergency spinner on the iPad display, everything gone (well, fake gone, just like the fake iPadOS multitasking).

Over my break, I mostly ran , , and , with some cameos by various terminal emulators and the usual social media garbage. None of them are particularly taxing, and the vast majority of my external display time was spent writing or looking up references.

This is not a stability story. It’s not even a reliability story. Having your session wipe out like this is simply unacceptable.

You Want to Do What With Your Windows?

This one’s a twofer: We all know iPad window management is sub-par––but there are two things that annoy me to no end:

  • Swiping up on your iPad display to flip through applications completely kills keyboard input on the external screen until you Cmd+Tab back to the application you were typing in
  • You cannot even think about picking which windows get assigned to quarter screens.

This last one is tantamount to the Odyssey, and it should probably be on IMAX due solely to its dramatic plot.

After painstakingly inching your mouse towards the almost invisible semaphores, clicking on them to make them actually usable even though they pulse and expand when moused over just to tease you, you then have to play the green button roulette.

That may, according to its internal whims and in a complete travesty of UX polish (that we, the elders, remember from ancient times), either maximise the current window or (maybe) show you a menu.

If you are worthy of the gods (or just plain lucky), you will finally get a window layout menu and get to pick “Fill and Arrange”, which has completely random behaviour, making it impossible to figure out where your windows will end up, and leading you to believe you have any choice in the matter when you later try to arrange them manually.

And no, you can’t have a right-first half-screen arrangement, either. You are not that worthy.

Building Piclaw on Top of an Opinionated Coding Agent

I’ve spent the better part of six months building piclaw–my personal AI assistant, workspace and, occasionally, agent swarm–on top of Mario Zechner’s engine, and I think it’s time to write about not just my motivation but also how I feel about having invested that much time into the whole thing.

This is important (at least to me) because is an excellent coding agent with a very clear point of view about how things should work. The internals are concise, well structured and easy to follow, with the brilliant twist that extensions can literally take over the entire thing–to the point where you can pretty much rewrite the entire agent loop (however you care to define loop these days).

Building a different kind of UI on top of it has been educational, very rewarding and occasionally maddening, and I’ve reached the point where I need to write down what I’ve learned and a lot of the underlying rationale–partly because I just want to use the thing now and move on, and partly because there’s a lot buried in the project documentation itself (there are a lot of whats and hows, but relatively few whys).

Why pi?

The key thing that captivated me is that is, in effect, a self-modifying agent harness.

Yes, self-modifying. Like… a virus. I like to think that its virality (however you cast it) is one of the unstated reasons it has found its way into a lot of projects lately, but let’s skip that bit and just reframe “self-modifying” as both self-improving and self-evolving without dipping too much into the penny arcade theatrics of AGI.

I’ve come to the point where I think that even without agency, self-modifying harnesses like pi are way more powerful than just about anything we’re getting from megacorps, because they can morph into your own completely personalised environment–which is what piclaw became for me.

When I started out fooling around with what eventually became steward, the field of open coding agents was a mess of half-finished scripts and forks, and stood out because it was opinionated in the right ways: as the runtime, a clean turn-based conversation model, good terminal UX and–critically–a willingness to evolve quickly. Mario Zechner made strong choices about tool calling, context management and model interaction, and they were essentially the right ones.

And if you take the essential bit literally, the thing got most right was restraint. Or, if you have been following the philosophical debate about AI use, taste.

At the risk of reiterating the basics most people already know about , it starts with a small, carefully chosen set of built-in tools–file I/O, shell, search and editing–and leaves the LLM to fend for itself in UNIX land, which gives it tremendous power and flexibility.

Compare that with what AI lab harnesses are becoming: sprawling collections of specialised tools, bespoke UI panels, inline diffs, notebook integrations, code review modes and whatever else someone thought of that quarter week. Every one of those features eats context, adds latency and makes prompts longer–which means the model has less room to think about your actual problem.

starts from the other end: give the model the minimum surface it needs to be effective and spend the rest of the token budget on the actual problems at hand. The introspection is excellent too–you can see what the model is doing, which tools it is calling and what the context looks like at any point. No magic, no hidden system prompts, no mystery. That transparency is worth more to me than feature polish, because it means I can debug things when they go wrong.

I didn’t necessarily want just a coding agent, though, and after a while, I realised I didn’t even want to run it in a terminal. I wanted an extensible agent that could run headless, manage my homelab, edit my wiki, file links, take notes, run scheduled tasks, and generally be useful in ways that might only occasionally have to do with writing code.

’s small tool surface and clean turn model were close enough to what I needed that building on top of it seemed faster than starting from scratch.

Escaping The Terminal

As I’ve written , I don’t run coding agents locally–that’s why I spent quite some time coming up with things like agentbox and webterm to run them in remote machines.

But the biggest departure from came from using it inside vibes, which started out as a generic web UI that I could use from my phone. And with my mobile background, it was pretty obvious (at least to me) that a highly optimised web UI was vastly better than using WhatsApp or Telegram as a bridge–not only could I make it much more secure over (without any middlemen), but I could build a much nicer, continuous experience across devices, reconnecting from anywhere and picking up exactly where you left off:

The same Piclaw session open across several devices
The same Piclaw session across devices

Another key factor is that I almost invariably begin and end my days on an iPad, which pretty much defined the rest of the UX–I can reference timeline messages, annotate them with Apple Pencil, etc., making for somewhat terse but very effective interactions, especially when doing reviews. I just toggle between Safari tabs to move between chat and GitHub or Gitea diffs, and with a little bit of AGENTS.md tweaking or per-session prompting things can be very productive.

Piclaw open in Safari on an iPad
Piclaw on the iPad

The entire thing unfolds like origami–files on one side, plan trackers on the other, documents opening into tabs or detached panes, and ample touch support throughout (resizing panes, swiping between chats, etc.). I also took advantage of pi’s brilliant session tree internals to create multiple “agents” (that can talk to each other inside each instance using a chat tool, and even across instances…)

The Piclaw interface with its timeline, plan and utility panes open
This is what Piclaw looks like to me these days
You’ll notice that the above is a bit… crowded. And I am not even using the file explorer or the built-in terminal, but it is pretty much how I use `piclaw` on a daily basis. From the top, you can see:
  • Several agents that I can switch quickly between (in this case they’re actually coordinating to fix an add-on and deploy it across the “fleet”)
  • A timeline with rich link previews, my latest prompt, and three temporary panes:
    • Thinking output from the model
    • Tool output
    • Tool execution details (what, current working directory, and git branch)
  • A plan sidebar that the model started using without prompting (this is gpt-5.6-sol, so it tends to remember previous instructions)
  • A compose box with model status/plan/context information (you can’t see the submission, previous message references and image attachment widgetry in this shot)

The top dashboard and the side pane are add-ons, and they’re designed to be used on demand, so the typical UX is much less cluttered–but my key point is that despite several attempts we’ve made at “improving” it, this has been working out really well for me on the iPad with both voice and Apple Pencil input, and I seldom use anything else these days.

One thing you can’t see is that it is running on a remote VM–piclaw has a handy little widget I can pop up on the top right-hand side that gives me sandbox instance info:

Piclaw widget showing resource usage for a remote instance
Remote instance stats
A colleague and I dabbled with a Visual Studio-like UX, but I still prefer the fully responsive front-end, since it evolved to match my peculiar working style:
  • Constantly switching between devices (iPad, work laptop, iPhone, work AVD, MacBook, Linux laptop, etc.)
  • Multiple concurrent sessions (typically one per project) in each instance.
  • Very long sessions that can last weeks.

Unlike people who have the luxury of uninterrupted focus time and can work on only one thing at once, I have to switch constantly between meetings, coding, planning, researching, writing, etc. I tend to work on some things in very short bursts over quite long periods of time–and having something stuck in a terminal someplace, even over tmux and ssh, would never cut it.

This is probably the biggest reason why I’ve never considered piclaw a “product”, even though it naturally evolved many of the trappings of other coding agents–including external add-ons.

Extending pi Into The Browser

But the key thing is that all the above are just extensions, since I leaned hard on ’s extension mechanism, extending it to support the web interface.

pi has a very capable terminal UI, and its extension contract exposes a bunch of it, but a lot of its flexibility doesn’t (or didn’t) cross the IPC interface, so I gave piclaw its own browser UI contract: extensions are route- and event-aware, and the shell extension host can mount, focus, resize, save, detach or dispose of them.

They retain the standard pi extension features, but can provide editors, file viewers, terminals and even a VNC client without reaching into the main application bundle. And, of course, they can do all sorts of fancy widgetry in the timeline (which has used from the start and can serialise widget states).

There are many things that are just intrinsic to piclaw, of course. The piclaw web server provides a bunch of scaffolding for managing UI panes, SSE events, settings, the works, plus there is an encrypted keychain, database and state introspection for the chat/sessions and file attachments in the timeline, etc.

But most of the shipping extensions started out like this:

{
  "piclaw": {
    "compatibleVersions": ">=1.8.0",
    "tags": ["example"]
  },
  "pi": {
    "extensions": ["index.ts"],
    "web": {
      "entries": ["web/index.ts"]
    }
  }
}

This translates into actual code like so:

// index.ts -- a normal Pi extension, loaded by the agent runtime
// schema and handlers omitted
export default function example(pi: ExtensionAPI) {
  pi.registerTool({ name: "example", parameters, execute });
  pi.on("session_shutdown", closeResources);
}

// web/index.ts -- loaded separately by Piclaw in the browser
__piclaw_web.registerPane({
  id: "example-viewer",
  label: "Example",
  capabilities: ["preview"],
  placement: "tabs",
  canHandle: ({ path }) => path?.endsWith(".example") ? 100 : false,
  mount(container, context) {
    return createExamplePane(container, context);
  }
});

Slowly, gradually, piclaw effectively built its own UX out of what are essentially all pi extensions, which I think is a great example of how good the original design was.

Earendil’s Moving Castle

Now, the design still is good, but the problem with building on top of someone else’s opinionated engine is that, to an outside observer, their opinions keep changing. is very actively developed–which is good–but there was a period when every upstream bump brought a non-trivial risk of things breaking in ways that were hard to diagnose.

I am very happy with piclaw as a tool to the point where I seldom use anything else, but I want to truly use it rather than spend so much time maintaining it, and over six months I’ve dealt with:

  • Tool-calling interfaces changing shape
  • Context-window management behaving differently after upstream refactors, causing my longer system prompts to be silently truncated.
  • The model configuration layer being restructured, each time requiring changes to my settings and onboarding code.
  • Streaming behaviour changing subtly enough that my web UI’s SSE handling would occasionally drop tokens or duplicate thinking indicators.

A later refactor to model handling fortunately converged with my approach, but still required a day of coddling GPT-5.6–very soon after I had spent two days integrating and testing a new context-compaction approach.

In a way, all of the above was useful because piclaw now has a gazillion regression tests–not just for the core and event loop (since my event loop has to do a fair bit more than “just” running a TUI, like routing SSE events, updating tables, etc.) but also for the UX (including a very spiffy PDF report that spans dozens of Playwright tests).

So the first “new” thing I learned out of the whole thing was how to apply the TDD mantra I had to follow in a few customer projects to piclaw, including getting the LLMs to generate decent user stories (and Gherkin) for tests and making sure the entire thing can run in Actions. I’d done it before, but not at this scale and depth for a single project.

This makes builds slow, but it’s completely consistent with my of ensuring LLMs generate useful code, and it’s been pretty rewarding.

The flip side is that spending three and a half evenings on compatibility work when upstream broke stuff I didn’t expect sucked. However, I don’t blame Mario for this. It had to happen.

The core of pi has got to be a very hard thing to reshape and evolve (especially considering the explosive popularity it’s been enjoying), and the constant model and provider churn certainly doesn’t help. If you peek under the hood, the sheer amount of work poured into pi-ai just to talk to provider endpoints is batshit insane, and is possibly tracking more moving targets than NORAD.

Sixteen Releases Later

Since I first dated this draft on June 19th, piclaw has gone through sixteen distinct Earendil releases, from 0.79.8 to 0.84.1. Most were uneventful dependency bumps, but package/API splits and a ModelRuntime rewrite for provider discovery, credentials and model catalogues prompted another couple of late evenings, since I now rely upon the latter for my own carefully crafted and GitHub extensions (because, well, I need to dynamically resolve models ).

I could just let upstream stabilise, sure, but the way things are going I’m pretty sure that will take years, and none of the above requires to promise API stability. But since just using the SDK and IPC isn’t really an option for me (at least not yet–more on that in a bit), I have to accept these as the natural consequences of shaping my working environment on top of a moving foundation–Earendil has more on their plate than catering to my somewhat eccentric use case.

Compaction pushed this furthest, since my style of work lends itself to very long sessions and I have access to multi-million token models, so my usage pattern seems to be very different than most.

Upstream added reasons, retry metadata, post-compaction estimates and eventually retry lifecycle events; my smart-compaction add-on grew summary validation, continuity checks, provider-specific execution and request-auth preservation around those hooks. When I implemented provider-native remote compaction, I then had to handle summaries that one provider could create but could not replay through another, etc. That made me respect the work done in pi-ai even more, by the way…

Fortunately, more recent upstream work has converged with decisions I had already made. Cache-friendly dynamic tool loading, full provider extensions, and compaction metadata plus retries for failed summaries are all things a long-running assistant needs, and let me ditch some of my workarounds. I still had to adapt piclaw’s credential store, model refresh, scheduler and extension loader, but I was no longer maintaining those ideas entirely outside the engine, and some of that scaffolding became integration code.

And I’ve finally caught up to the point where I am now proactively tracking the new upstream agent harness and started breaking down piclaw into individually testable “effectors” (for lack of a better word) that can just plug in to the new agent loop as it changes state.

With luck, I should be able to adopt the new harness as it comes out. Worst case scenario, I’ll have to refactor a bit more, but some of it is long overdue, to be honest.

But let’s take a little detour.

TypeScript, Bun and the RAM Problem

The other thing I’ve learned–and this is less about specifically than the ecosystem in general–is that the runtime overhead is brutal on constrained devices. is, to me, a massive improvement over Node.js (and its is one of the reasons I decided to finally clean up my notes and post this), but it still has its challenges.

Using 1.3, piclaw running on my ARM devices used somewhere between 400 and 600MB for the main process, depending on how many tools are loaded and how much conversation state is in memory. On a desktop or a VM that’s nothing, but on a smaller ARM board that is also trying to run builds, it is a meaningful chunk of RAM.

Early results with 1.4 (very early, since I just did the first piclaw release based on it) are… mixed. I have seen some of my instances go down to 200MB RSS, but others remain in the same range.

is fast, and I genuinely like working in for the web UI and tool surface (mostly linting and testing, honestly, because I still don’t really like the language). But the combination of JavaScript runtime overhead, the node_modules graph and a process that loads dozens of tool definitions at startup means I am paying a tax that a compiled language would avoid, and I am constantly reminded of that.

I still prefer (and continue to explore doing harnesses in it), so there’s a draw away from the internals of that I just cannot ignore.

Anyway, I adopted a few different tactics to try to keep things under control.

The Extension Split

The first mitigation was architectural, suitably -aligned, and typically lazy: I split piclaw into a core runtime and a set of lazy-loaded (ha!) extensions, hacking session management (which I also extended to support multiple parallel running sessions) to support dynamic loading.

So extensions like tooling, integration, , wiki helpers and other (incidentally) context-heavy tools are loaded only when the model needs them, rather than inflating the base process (or the session) from the start.

This helped, and eventually converged with ’s recent releases, which made this less of a hack as the core added its own dynamic tool loading (which was tricky for a bit since it mangled the cached prompt prefix in my custom handling…). I only use subprocesses for scheduled tasks and some add-ons, but I wired those through as well.

The thing is, shipping all those extensions with piclaw itself started becoming unmanageable, so…

Everything Gets An App Store

I eventually decided to move the larger integrations into a separate repository, making it possible to download and install things directly from it:

The Piclaw add-on library displayed in its management interface
The Piclaw add-on library

This created more maintenance, but it also forced me to treat extensions differently in general. The repository now has standalone-import tests, metadata validation, etc., and one of my slow burning tasks has been migrating stuff out of the core repository into what is now a nearly 50-strong add-on library.

That includes niche provider integrations, infrastructure clients, viewers and editors, delegation and compaction machinery, terminal renderers and small pieces of UI that make sense only in the web app. Each is installed as a Pi package and its runtime entry still receives ’s native ExtensionAPI, so tools, events, session state and shutdown semantics still belong to the core (which is why I’m quite optimistic about my chances of adopting its upcoming harness without a lot of breakage).

Also, some of the best improvements to my workflow came via contributed add-ons: delegate, in particular (which just invokes pi as one or more subprocesses, at least until I find the time to refactor it), has been pretty useful for things like “audit this PR independently using sol, terra and opus and give me an assessment”.

A Place For Every Setting

Oh, yes, and that scary thing around the add-ons library above is the Settings pane. Every extension in piclaw (bundled or add-on) has access to a settings contract that lets it create and render its own UX. Here’s the scheduled tasks pane, for instance.

Piclaw settings for scheduled tasks
The scheduled tasks settings pane

Settings panes use a fairly straightforward pattern: the browser talks to an authenticated /agent/addons/api/<addon>/<action> endpoint, the runtime registers the handler, non-secret values go into the extension KV store and passwords or tokens go into the keychain.

But there’s more to this than just the (slightly overkill) amount of functionality I built into piclaw. Using it has also forced me to reflect (and learn) a lot about how to effectively use LLMs across the board.

Knowledge, Memory And Regret

One of the things that became obvious after keeping sessions around for weeks is that the conversation itself is mostly disposable–but only just. The most useful bits are what survives outside it–files in the workspace, instructions in AGENTS.md, and skills.

Like everyone else, I leverage agent skills extensively, and have dozens of SKILL.md files and scripts that describe how I want recurring jobs done (including all the little caveats I would otherwise have to rediscover every few months).

That is a much saner kind of memory than stuffing old chats into a vector database and hoping similarity search will do the right thing, but I’ve found there are multiple complementary aspects of agent memory and ways to ensure reproducible behaviour.

To begin with, each new session gets the same workspace and operating conventions, plus enough current project state to resume work without dragging months of conversational debris into the context window.

But I’ve also incorporated a recurring self-diagnosis that does light tweaks to skills and a small set of “memory” files. Every night, an out-of-band “dreaming” session goes over recent activity, updates human-readable daily notes and distils the useful bits into preferences, corrections, project state and a compact startup index–while pruning things that no longer need to be folded into every session. It is deliberately lossy, and all the better for it.

Then there is late-night-regrets, my somewhat pointed name for an add-on that looks back at interaction history and classifies course corrections, misinterpretations, over-engineering, under-delivery, context failures and useful proactive work. Typically for me (if you’ve ever come across any of my news processing pipelines), the classifier is a small Bayesian affair that consumes no model tokens; a separate reflection pass rates high-confidence failures and turns them into notes or steering cues for later sessions in a feedback.md file that is referenced when starting a new session.

That is about as much “self-improvement” as I am willing to trust right now: review what happened, summarize what went wrong, and keep changes to a (very) limited set of files. There is no model secretly rewriting AGENTS.md at 2:30 in the morning–it just wakes up with better notes and, occasionally, a list of regrets.

But me being me, I had to take it a step further.

Memory Across Agents

Memento visual debugger showing shared memory nodes and diagnostics
Memento’s visual debugger

came out of wanting to carry some of that knowledge across machines and agents without sharing chats, credentials or piles of machine-local cruft. The durable concepts are Markdown in Git, split into namespaces and put through a proposal/curation flow, and I initially designed it to share skills and their associated scripts and assets. I hacked in my own embedding engine, but as usual with me it relies mostly on indexing rather than taking embeddings as the source of truth–which, given my experience with opaque memory systems, is an important distinction.

This is only a month or so old, but has already proven itself useful in very mundane ways, like allowing piclaw to replicate itself to new machines and bootstrap them with the shared skills available to every instance:

Piclaw setting itself up on a remote host
Setting up Piclaw on a remote host
Memento knows that I care about exact current-state reporting, clean Git history and verifying things on the actual target; it has engineering practices distilled from several unrelated projects; and it carries entire skills, including the bootstrap skill used above and the supervisor/worker “squad” model I use to keep sibling agent sessions from wandering off into the weeds.

The best thing? works very well with other agent harnesses, including on my iPad.

Where This Leaves Piclaw

piclaw is still my primary assistant, running on six machines and doing useful work every day. The extension architecture made it maintainable, and ’s upstream improvements continue to make it better.

But, again, it is a “product” for one. And it is quite likely to stay that way, but part of the reason for that is that I very strongly believe that this kind of thing is already a commodity and that it makes zero sense for anyone to invest on selling AI code editors, shells, etc. Partly because the people who can build these things are increasingly likely to do it for themselves, and partly because the least common denominator is already out there in a zillion form factors.

Regardless of everything I’ve learned in the process, the most interesting part (for me, at least) is that ’s philosophy is the key differentiator–having a self-modifying agent hardness to build from is what enabled me to very quickly build piclaw up from a web wrapper into my main working environment, with its own interface, extension model and accumulated habits, and I’m going to keep following that approach going forward.

Here’s to the next version–but first, I need to enjoy my last couple of vacation days.

The Age of Infinite Software

I am most definitely not the first person to mention this, but the past year has seen a Cambrian explosion of two things: AI deniers who base their judgement on very limited exposure (or effort to use it) and thousands of variations on software of all kinds, from the perennial to-do list to AI-infused toothpicks.

Which, let’s face it, is a bit much. It’s bad enough to go on social media and be pitched things I don’t need, but the hypefest around new startups hawking their wares to fill hitherto undiscovered “problems” in increasingly pointless sub-niches is a bit much too. I find the entrepreneurial energy heartening, but most of them solve no real problems whatsoever.

I mean, anyway? And workflow engines? And CRM pipelines? There is a dizzying amount of almost-identical AI-driven solutions out there trying to land the ideal five-word VC catchphrase, and it’s just tiresome at this point.

Plus if you take the long view, most of them are completely divorced from the realities of, say, traditional IT, which has turned into an ouroboros of complexity thanks to geological eras of non-technical decision-makers – but that’s beside the point right now.

The one thing that I find positive among all this (and that I’ve hinted at a few times in the past) is that can now create whatever tools they might need to scratch their particular itch(es) – the results may not be perfect, and they may have an audience of one, but they can unblock time, patience and capabilities they would otherwise lack and improve things in general for themselves, without having to conform to someone’s idea of a “product” or jumping through hoops to make their workflows fit a tool.

Of course, the flip side is that it is all too easy to go overboard (when you have AI, everything looks like a solvable problem), so restraint and taste – which is probably the most effective, even if somewhat passive-aggressive and snobbish criticism you can lob at people these days – are essential.

But this ability for people to design tailored solutions for themselves is, I think, what SaaS vendors (and system integrators) fear the most. In an age where anyone can point an LLM at a bunch of APIs and say “build me a CRM that works for me” (which is something I’ve seen done, to the horror of a friend of mine working at Salesforce), the “value” of customisations has to be replaced by something, and believe me, it’s not going to be a consulting firm’s business acumen – or even their taste (which is nearly always lacking).

That does not make the tools magical, of course – they still need and someone who understands the result.

But on a smaller, personal scale, it’s kind of ironic to think that probably the main reason this is going to kill the appeal of most SaaS is that we’ve spent a couple of decades killing native desktop development in favour of kludgy, half-baked web UIs that are all variations on lists of things people click on.

And believe me, if there is one thing that LLMs can do perfectly, it’s web interfaces with lists of things people click on.

Notes for August 9–16

This was a different week, partly because we decided to watch the eclipse from a Spanish beachfront and partly because I actually read three books. There is an entire sub-thread around my back and neck aching worse than ever and my sleep patterns looking like a game of Splatoon that I will spare my readership, though.

I do think that this week’s Economist completely nailed the holiday feeling since I nearly drafted an existential rant about considering retiring to Spain for tax purposes, but as the article says, a lot of holiday musings don’t really stand the test of time–something I’m not going to take for granted.

But hey, worked (hotel Wi-Fi seems to be mostly a solved problem by now, even if I still chuckle at WISPr portals), none of my home machines overheated while we were gone, and although the week was a dismal failure in terms of writing, I managed to, at least for a few hours, completely forget about work and actually enjoy myself.

But I really wish I didn’t have to go back. This has not been a new feeling over the past decade, and I have taken it to mean that I can finally reason about work in the proper way (either because it has stopped defining me or because it’s fundamentally misaligned with what I think I should be doing in these insane AI-driven times–not sure which yet).

Rust Isn’t That Shiny

One of the books I read was on (actually two, the original book’s third edition and another on Rust for embedded systems), and I plodded through its gospel mostly wondering what the heck I could really get out of it given that I’ve mostly settled on and for the vast majority of my projects this year that aren’t in or .

Although I’ve been successfully steering wrdp to passably structured form (and, more important, usefulness), I remain unconvinced I would have used to do it if it wasn’t for IronRDP, and given the malleability of and the ease with which most LLMs can generate it correctly (provided you and lint/fuzz the heck out of it), I don’t see myself picking as my default unless I’m going into a codebase that already uses it.

My biggest gripe remains the mental model, or, more to the point, the mental overhead of imposing a series of abstractions on top of the language that the hardware fundamentally doesn’t care about and that only cause programmers grief. In short, and feel more honest in either their rawness or their willingness to abstract a bit more in ways I actually find productive.

Plan9 Lives on

…in assembly, at least. I took the time to understand a bit more how llama.cpp worked and after a few SIMD optimisations in some of the more impactful matmuls, see if I could port some of that across to go-pherence for kicks. The fact that I can still consistently get 10% localised speedups by just looking at the inference graphs and asking “why wasn’t this done this way” (as you can see in my llama.cpp fork) makes me wonder exactly how much performance is being left on the table, and if Kaizen shouldn’t be a software design technique.

Lacking GPU hardware, I have to stick to stubbornly wrapping my remaining neurons around Intel-specific (and, soon, NEON-specific) optimisations, but it seems that my sparked a new interest in making inference go brrrrrrr I can’t quite turn off.

Side Effects

Speaking of turn-offs, the AI agent/shell/UX craze is still raging on to the point where I decided to put piclaw on hold for a bit and prepare the way to converge with what I fervently hope will be a thoughtful, elegant agent harness that is emerging from the SDK.

I am, effectively, taking a gamble on what it might look like, and simultaneously preparing to clean up piclaw’s event loop into less of a mess by rebuilding part of the internals into more or less cleanly cut “effectors” that run after each state machine transition as needed.

I also started putting hard caps on my “AI time”. Either token-wise, or attention-wise, I am taking advantage of the summer season to just go slower on a few projects.

No More ArchiveBox

Except, of course, that I decided to add one more, but for a good cause.

I’m also trying to simplify the amount of stuff I run in general, and scoring it by a thoroughly unscientific ratio of actual use against the headaches each service causes. This week ArchiveBox’s number came up because it just keeps getting stuck in CPU loops, and having a machine subtly overheat over many hours in the middle of summer is not something I favour.

Plus the usefulness of the thing is also in question, really.

There is a long history of “read later”/maybe useful/procrastination in reading here that probably needs its own blog post, and I’m old enough to have gone through Delicious, Instapaper, Pocket, and now ArchiveBox.

I think the common thread between all of them (and the reason “read later” services exist) is the (mostly fake) reassurance that I will a) really read something later (which often doesn’t happen) or b) be able to find something again if I ever need it.

Both of those prey on human nature, such as it is, in a weird reflection of what we’re going through now with AI, since all of these bookmarking and archival “helpers” boil down into CPU cycles, storage and a slightly guilty sense of having outsourced remembering things to a machine.

And I really should know better, since this very site has mostly replaced all of them for many uses–just go into any technical wiki page and it’s usually crammed full of links to interesting projects in various domains. And it just works.

ArchiveBox, meanwhile, has been a random source of failures, CPU use and frustration around its pace of development. Although I like the idea of storing bits of the web before they’re eroded away by slop, there are two fundamental problems with it:

  • It has too many moving parts
  • I don’t need to keep a zillion formats that I never open

What I need is to be able to find and read something on iOS when I eventually need it, and more or less high-fidelity content capture–for which MHTML is decent enough, even if Safari has never adopted it. Being able to strip it down into machine-readable or printable formats is mostly optional, and can be done on demand.

So… I whipped up bun-packrat, which does the entire thing relatively tidily, storing a single source of truth for the page contents, reshuffling it on the fly for me to read, and leveraging ’s FTS5 indexing for search. After all, with agents to extract text, fill in missing metadata and build whatever enrichments I end up wanting later, that’s more than good enough, simpler to maintain and far less wasteful (if you ignore my firing up a headless browser for every capture, of course). Instead of 35GB of junk, the 2.000-odd ArchiveBox entries now take up a little over 1GB in a single database, which is just great.

Notes for August 3-8

I have a problem. Or, rather, I have two problems:

  • I have been spending far too much time messing about with instead of reading.
  • I end up zoning out in front of YouTube and, even with serious attempts at curating my feed, I spend far more time than I should there.

I’ve , but this week I decided to take some time to fine-tune the friction around those activities–removing or adding it as needed.

E-Ink and Calibre MCP

My library has grown somewhat out of hand, either due to automated additions (I have been getting the web edition of The Economist delivered through it for ) or lack of proper curation, so I decided to use to see if I could remove the friction involved in finding something to read (or re-read) and have it either e-mailed to my via or easily accessible on my .

That mostly meant figuring out how to get an server working with , but it ended up including a parallel side quest to improve bun-readlater-epub and bun-opds-server to see if I could make it easier to queue up and download long-form content.

As an aside, recent revisions of CrossPoint have a Wi-Fi bug that prevents the from joining our Wi-Fi (apparently because it fails to use a coherent MAC address), so I have to import things via its hotspot (which automatically optimises the ). I suspect I will eventually have to fix it myself when I have more time, because the maintainers have been unable to do it for two releases now…

The real improvement, though, was how I decided to design my own MCP server for automating . Most existing implementations out there are either sidecars that can’t manipulate data or CLI wrappers that inevitably contend with access to its library databases, so I took the plugin route and built one that runs inside it and can thus use everything: metadata editing, conversions, moving books between libraries, e-mailing them to me, the works:

uMCP Bridge in Calibre
uMCP Bridge in Calibre

This effectively means I can now point any AI agent to and tell it literally:

  • find me the last three books by X and e-mail them to my Kindle address
  • grab this URL and import it into the Incoming library
  • change ratings programmatically
  • find and remove duplicates across libraries…

There’s no practical limit, really, although I might need to hack a few more things in. And since it uses the native job engine, everything works correctly.

The biggest quality-of-life improvement is that I don’t need to access the UI anymore. Since I have been running the extra-clunky Selkies-based container (which streams the desktop using its own thing and works very poorly on the iPad), there’s no more browser logins, slow wading through listings, or finicky right-clicking.

As an encore, since I wanted to maximise the time I could spend on the , I also updated picoflux and tweaked the e-ink theme I bolted on a month or so ago.

Old-Timey TV Shenanigans

That removed a lot of the friction around reading. Next, I needed to add friction to watching YouTube videos.

I recently spent a little while fiddling with Jellyfin–partly because I do that on occasion to see if it’s finally a decent alternative to (spoiler: not yet, by miles), but also due to my infrequent investigations into the state of hardware video decoding (go-264 will eventually go down that path).

This time I wanted to hack it into a sort of anti-YouTube setup and see if I could replicate the old-timey, “synchronous” TV-watching experience, so I literally told piclaw:

I want you to create a Debian 13 LXC in radxax4 to host Jellyfin, mounting smb://zfs/video as a read-only remote media library (so keep the LXC filesystem small, please). You can pick the best way to deploy Jellyfin as long as you manage to get hardware video processing working and document it in Obsidian. After that is done install jellyfin-plugin-livechannels or a similar TV simulation channel and create appropriate “channels” based on the contents of the media library.

Fifteen minutes later, I had the entire thing working. Not half-assed or poorly installed, working, with the media mounted read-only (twice, once on the host and again inside the LXC), QSV hardware transcoding and a full installation and configuration brief in (the output is a tad long, but here’s the last part):

Jellyfin installation and hardware transcoding summary
Jellyfin installation and hardware transcoding summary

Of course Jellyfin immediately filled the filesystem with artwork and people metadata, so that was (automatically) upgraded, but hey, it was a valiant effort.

Then I went to town on the original plugin and decided to bolt on Invidious as a YouTube source:

Jellyfin LiveTube channel guide on a television
Jellyfin LiveTube channel guide on a television

I call it jellyfin-livetube, and it’s been working pretty well–even the standard library-backed channels have been a surprising amount of fun (I ended up rewatching Flash Gordon purely by chance).

wrdp’s 15 Seconds of Fame

Speaking of YouTube, Wendell Wilson (hi there!) featured my new wrdp project in the latest Linux weekly video, which was fun to see (especially since I found out over breakfast while checking my messages, before coffee kicked in).

Right now it is mostly working, even though I am still waiting on a critical PR to make it into IronRDP to improve internal session management. But login and Wayland session creation both work, it’s all hardware-accelerated (both EGL desktop acceleration and VA-API video encoding), and… there are all sorts of edge cases to sort through.

I will be poking at it irregularly over the next few weeks–I want to do ARM/Vulkan acceleration next and set up two separate remote desktops I use “regularly”, but first I need a bit of digital detoxing, which is something I am very much failing at.

Moar Agents! Minis Agents! Moar

Because I was clearly left unsupervised and can’t really stop doing agent-related stuff, I went down the rabbit hole of setting up on my iPad Pro, and I did it in the most “me” way possible–I got it to connect to Memento and “learn” from the accumulated knowledge of all my piclaw agents, which is awesome because it proves two points:

  • Memento works perfectly for the purpose it was designed for.
  • It doesn’t matter which agent harness you use as long as you document things properly.

Thirty minutes after I began, I already had most of the SKILL.md files and scripts ported across, and an hour later I had “native” equivalents to manage and and was doing various shenanigans to generate and post screenshots along with my link post drafts, which these days are posted using the GitHub API directly (again, refactoring an existing SKILL.md).

I can now confirm that is, indeed, the Siri I have been wishing for. It’s by no means perfect, but with a SOTA model driving it, it can build its own tools, and… I really should stop now and go read a book or something.

3D Printing State of the Union

Since I got and I’ve been documenting my endeavours in this realm in a rather haphazard way, I thought it would be useful to do a sort of catch-up/snapshot of where things are (and have been) for a while now.

Right now I have three 3D printers (down from four):

  • The , which is my “tiny”, near-silent printer
  • The , my former workhorse
  • A brand-new Flashforge Creator 5 Pro, which I am still getting to know and taking copious notes on

However, this all started (as many 3D printing stories start) with a Prusa. Or, rather, a clone.

The Prusa Connection

The BQ Prusa MK2 over the years
The BQ Prusa MK2 over the years

A few years back, when I was organising the first editions of the Lisbon Maker Faire, I got , which stood me in good stead for a long while–I printed many kilos of PLA/PETG with it, the vast majority of it going into functional parts of various descriptions (some, as you’d expect, were 3D printer parts), to the point where the nozzle wore out and widened from its 0.4mm to somewhere between 0.6 and 0.8mm (which only made it more useful for some functional prints).

Last weekend I retired it and gave it to a friend–which, given how tight space is in my office these days, was a necessity. Instead of dismantling it and saving the non-printed parts, I tried to make sure it would go to someone who could rebuild it.

Since I took care to keep all the STLs (Prusa originals and derivatives are awesome in terms of long-term maintenance), had spare Arduino boards and ample extras–including a Raspberry Pi touchscreen and an unused extruder kit I had intended to fit it with–it left the house almost like it came in (i.e., as a kit), and even though I’ll miss it to a fair degree, I hadn’t really used it in almost a year.

This printer had a great run, and was extraordinarily maintainable–I replaced many of its parts over the years (including nearly replacing its extruder assembly before I got the other ones).

It also became my first , and the excitement from that upgrade and the realisation that 3D printing was going through a stepwise evolution was pretty much the reason I got my second.

The Little Upstart

The KP3S Pro over the years
The KP3S Pro over the years

The was my choice as a follow-up printer, and an attempt to regain finer print quality (which I did) while retaining some control over the hardware and software–I bought it intending from the start to run , and it has served me very well.

After swapping out its extruder assembly and bolting on a Bambu clone hotend and an inductive sensor a little while ago (which I also made a video about), it is now the quietest (and, funnily enough, most hassle-free) of my printers, even considering that its cantilever setup makes it a tad wonky.

Despite the limitations of its relatively small 220x220 build plate, I use it a lot during the day to print small jigs, calibration samples and slices of prototypes, to the fascination of some of the people I have video calls with. Being quiet, precise and low-friction for small functional work, it is perfect for the kind of slow, iterative prototyping that I can squeeze in during some work weeks, although to be completely fair it is a tad small, so for most final prints I have to move “up”.

The Tank

The SK1 and the tweaks I did
The SK1 and the tweaks I did

I had the good fortune of getting an when Two Trees dipped its toes into the 3D printer manufacturing business (which they appear to have since exited, sadly), and upgraded it from its Bambu Lab P1-like barebones frame to a fully enclosed configuration including auxiliary part cooling fans, and I have quite enjoyed the ride.

As my first Core XY, the thing was a pretty amazing leap in terms of print speed and quality, and it is still rock solid provided you can deal with its somewhat uneven temperament and a few quirks.

There is a lot to like mechanically–since it (cleverly) uses Bambu clone hotends, it has been the printer I’ve used with most of my tougher abrasive filaments, and coupled with a BIQU cool plate it has been perfect for stuff that would never print reliably on the . The stepper motors and mechanics have been rock solid (the only part that broke down was the toolhead fan, which somehow lost a blade), and it’s only improved.

It does have one significant hardware foible–the extruder is very prone to heat creep, and it’s impossible to reliably print PLA on it with it fully enclosed unless you use a vent like this one and turn on the fans–which, even if only slightly on, just add to the noise, especially when the printer is running at speed.

The shipping firmware has always been a little buggy, and although I did some creative upgrading and , it still has some weird pre-print slowdowns and glitches due to the rather complex Voron Trident-like homing sequence that I’ve yet to fully iron out.

My plans for it, now that I have a new “big” printer, include completely reflashing the entire thing with more modern firmware and, eventually (if I can figure out a good, reliable replacement that isn’t a major pain to mechanically assemble), upgrading the toolhead to a more future-proof combination.

But the excellent mechanics aren’t really compromised by a few software and thermal-design decisions, and I suspect it will stick around for a while.

The Creator 5 Pro

The Flashforge Creator 5 Pro
The Flashforge Creator 5 Pro

I will write more about the whys, hows, and outcomes, but I spent a long while making up my mind about this one, and it’s going to both replace and complement the –it’s roughly the same size (except for the ludicrous top cover), but I needed something to print (slightly) tougher materials, use multi-material for supports, and, overall, enjoy a bit less tweaking and more automated tuning.

And yes, I decided to get in on the toolchanger craze, but not because I want to print multi-coloured baubles–I want to print functional parts with different materials, and toolchangers are another stepwise evolution in the 3D printing world that I want to explore.

I’m slowly getting used to it and jotting down notes for an in-depth post in a few weeks (maybe months, depending on how summer pans out), but I’ve already used it to print that SK1 vent and a few small precision multi-colour and multi-material tests. It is noisy enough that I don’t enjoy running it at full speed while I’m in the office (and its “silent” mode is quieter, but still not something I want to put up with during meetings), so I’m using it mostly on weekends.

works (almost) perfectly with it (and is sure to improve), and I’ve already dipped my toes into building a monitoring app since I am still thinking of it as a sealed appliance, but I know that there will be alternate firmware versions soon(ish) and expect it to become just another printer (or close enough) in due time–that, and the simple, no-frills mechanicals, were two of my bets when I picked it out; the third was that maintainability would win out over its somewhat spartan feature set. It’s early days for that, of course.

And of course I’ve gone and started patching around some of Flashforge’s shortcomings myself–besides that Swift-based desktop app to talk to it, I’ve also printed my own version of a purge bucket (a rite of passage for any modern printer, including toolchangers, it seems), and am actively trying to get around to actually using it for the stuff I want–for which all I really need is the most precious commodity: time.

That and, of course, working my way up to the final print jobs it’s meant to do–the other printers still have their work cut out for them…

Notes for July 26-August 2

Well, this was a productive week… end. The week as a whole was not particularly inspiring or meaningful (I won an award of sorts at work, and to be honest I… just wanted to get to Friday), but I finally teed up and actually did a bunch of things I’ve been meaning to, and it feels great.

Read More...

Twenty-Four Years Of Wiki Engines

Yesterday morning I switched this site to its fourth major engine, a little over twenty years after sketching out the core idea behind it. The new generator is called , is written in , and runs almost entirely inside GitHub Actions–which is mildly amusing because the first , in 2006, was also meant to batch-render this same filesystem tree using dependency tracking.

Read More...

The Beelink Mate Pro

Even though I already have probably too many desks (my main work desk, a that has probably been improvised for far too long, and an occasional tactical take-over of our dining table), I spend around a third of my working hours on a laptop of some kind.

Read More...

Archives3D Site Map