TL;DR This is about Claude’s scheduled cloud routines specifically, which is the only agent platform I have tried it on. I moved my routine prompts out of the scheduler and into a git repo, leaving a fifteen-line stub behind that reads its instructions from main at runtime. Changing a routine is now a commit rather than a form edit, and each routine has standing authority to open a PR…
TL;DR Link to heading Put a long signed token in an email link and you have built a bug that fires deterministically for some recipients and never for others. MIME quoted-printable wraps lines at column 76, some mail providers re-encode the message and mangle the escape that lands on the wrap seam, and if the first seam falls inside the token a single flipped character makes the signature stop…
I ran /context in Claude Code and found my memory files eating 49.5k tokens before I’d typed a single word. I’d assumed those files loaded only when relevant. They were loading in full, every session. After moving them to the managed memory directory and disabling one plugin I never use, startup context dropped from 82.1k to 37.2k. Before Link to heading The two big line items were…
TL;DR Link to heading My OpenClaw gateway went silent for three days after a usage spike, even though I could still chat to the same provider via its web interface normally. The API was serving requests, but OpenClaw had stored a “next reset in 6 days” message as a literal blockedUntil timestamp and refused to try the profile again. Without a fallback model configured, the…
TL;DR : During a migration across a few dozen repos, “looks done” failed me three different ways: stale code search, stale local clones, and an auto-merge that quietly reverted my changes. The checks I ended up trusting were greps on fetched file contents. Motivation Link to heading I was rolling a config migration across a few dozen repos at work and needed to answer one question…
TL;DR : I needed to repoint a batch of uv projects at a new package registry without changing a single resolved version. uv lock --no-upgrade re-resolves anyway when the index changes, so I rewrote the URLs in pyproject.toml and uv.lock with sed and verified with uv lock --locked . Motivation Link to heading I was migrating Python projects at work to a new package registry. The packages had been…
TL;DR Link to heading I moved object ownership in Postgres from a shared role to a dedicated role per service, one environment at a time, with the application serving throughout. REASSIGN OWNED does it in one statement and moves every object class. A FOR ALL TABLES publication blocked it on one database, so I went per-object and left functions, types, and schemas behind. A pg_shdepend sweep caught…
TL;DR Link to heading I had a Kubernetes service exposed via two different gateway flavours on different clusters. Two of them used an istio Gateway with TLS terminated in-pod, where cert-manager handed it a wildcard cert via a regular Secret . The third used a GKE-managed Gateway ( gatewayClassName: gke-l7-global-external-managed ), where TLS terminates at a Google Cloud Load Balancer that does…
TL;DR Link to heading I had reduced my OpenClaw heartbeat cadence a few weeks ago expecting a big drop in LLM credit usage. It barely moved the bill. Digging into the per-call usage logs, I found that every persistent session had compactionCount: 0 , so each cron run and group chat reply was replaying its own growing transcript on top of a 12k-character bootstrap. The fixes that helped were…
TL;DR Link to heading A private GKE cluster’s outbound traffic to *.googleapis.com and *.pkg.dev flows through Cloud NAT by default and pays $0.0385/GB data processing on every byte, in both directions. The GCP UI says “Private Google Access is in effect” for the subnet, which makes it sound like that traffic already bypasses NAT. It does not. To bypass NAT for Google API…
TL;DR: A common haproxy-in-front-of-redis-sentinel setup has three reliability traps: liveness probes cascading during sentinel failover, haproxy hard-stopping inflight connections on SIGTERM , and haproxy aborting at startup when any redis pod’s DNS is NXDOMAIN. The fixes are split probes, a preStop hook that runs kill -USR1 1 , and init-addr last,libc,none resolvers k8s on every server…
TL;DR Link to heading A cleanup PR removed an accidental guard in our release workflow’s git push logic. Three weeks later the workflow had pushed 119 self-generated bump commits. Fix: gate the release job on github.actor so the workflow’s own bot pushes can’t re-trigger it. I opened a service repo and found a release pull request with 119 consecutive commits, all chore: Bump…
TL;DR: I’ve been using Claude Code since last July and spent most of that time correcting the same behaviours every session. Auto-memory hasn’t fixed that, but it has taken some of the edge off: when I say “next time, do X” in conversation, Claude saves it as a feedback memory and pre-empts me more often than not on the next run. Below is a snapshot of the rules I’ve…
TL;DR: I thought there was. There isn’t, unless there’s a tailwind. In vertical rain, faster is always drier. Motivation Link to heading I was cycling home yesterday in heavy rain and started wondering about the right speed. Slower means more time getting drizzled on. Faster means more rain per second on my front. It felt like there had to be a sweet spot. The setup Link to heading…
TL;DR Link to heading My OpenClaw gateway kept calling an LLM provider I had retired. The new primary in openclaw.json was ignored because the long-running “heartbeat” session pinned the model selection at session creation time, both in the session index and in a model_change event at the top of the session transcript. Resetting the session let the global config take effect. Motivation…
TL;DR: Putting ~/.openclaw in a private git repo is mostly about writing the right .gitignore and keeping every secret outside the tree. A systemd EnvironmentFile carries the real keys to the gateway at startup, so openclaw.json can hold references or empty fields instead of credentials. Why track it Link to heading After the upgrade gotchas , I wanted version history for openclaw.json and a way…
TL;DR Link to heading A Go channel is one primitive covering what other languages split across locks, condition variables, semaphores, and queues. That consolidation is the thread I kept pulling on while reading. Motivation Link to heading Channels come up in every Go pitch. I wanted to understand why. What a channel actually is Link to heading In most languages you get shared memory plus…
TL;DR: Upgrading from 2026.4.8 to 2026.4.15 tripped two restrictions that silence your config without a loud error: a tightened schema for tools.elevated.allowFrom.telegram that invalidates the whole file when it fails, and an fs-safe layer that refuses to traverse symlinks in the state-directory path. One is a config edit, the other is a bind mount. Context Link to heading I moved OpenClaw from a…
TL;DR: I wanted Claude Code to read out each response through say on macOS so I could step away and listen instead of watching the terminal. Four bugs got in the way: the hook was on the wrong event, tac does not exist on macOS, the Stop hook fires before Claude flushes the transcript, and pkill say clobbered speech from other sessions. A 1-second sleep , jq -rs , and a per-session PID file fixed…
TL;DR: A pre-upgrade hook applies resources that stay applied when the upgrade fails and you roll back. Helm has a pre-rollback phase to undo those changes, but it runs only if you define one. Pair every pre-upgrade hook with a matching pre-rollback , or move the hook into its own release. A quick word on SecretProviderClass Link to heading A SecretProviderClass (SPC) is the custom resource the…
TL;DR — I did a hot sauce making course at Easton Chilli in Bristol. Came home with eight bottles and a new appreciation for the art and science behind it. Why I signed up Link to heading I like hot sauce. I go through bottles faster than I’d care to admit, but making my own had never crossed my mind. My partner got me an Easton Chilli course for Christmas. It got rescheduled once, then I…
TL;DR: OpenClaw can call Claude and Codex through their CLI tools instead of hitting APIs directly. CLI backends give you better session handling and remove API key management. Switching over requires cleaning up some wizard-generated config. Extra usage billing still applies for Claude. Why CLI backends Link to heading OpenClaw supports two ways of talking to model providers: the embedded API…
TL;DR: I moved my OpenClaw setup from a Jetson Nano to a VPS. Persistent block volume for state, Node 24 LTS instead of a hand-compiled Node 22, and the whole migration took about 20 minutes once I stopped fighting ARM constraints. Update (April 2026): The symlink approach below breaks with newer OpenClaw versions, and a few other restrictions landed in the 2026.4 line. Notes in OpenClaw upgrade…
OpenSSH 10.2 warns you when a connection isn’t using post-quantum key exchange. On the client side (macOS), it works out of the box. On the server side, you might need to upgrade OpenSSH, which on Ubuntu 18.04 means building from source. The warning Link to heading I SSH’d into my Linux box and got this: ** WARNING: connection is not using a post-quantum key exchange algorithm. ** This…
TLDR : Enabling uniform_bucket_level_access on a GCS bucket disables the legacy role bindings that project owners rely on for object access. Your Terraform SA with roles/owner will get 403s reading objects it could read moments earlier. Add explicit roles/storage.objectViewer bindings on the bucket before flipping the setting. I’d recommend uniform bucket-level access for most buckets.…
TL;DR: Anthropic accidentally shipped the Claude Code source map; I went through it looking for patterns worth borrowing. The codebase reads like accumulated postmortem residue — the compaction circuit breaker exists because telemetry showed sessions burning 250K tokens on doomed retries, the LRU cache was rewritten after it leaked 300 MB, the keychain code references a specific CrowdStrike…
I spent a couple of days migrating our monitoring stack from self-hosted kube-prometheus-stack (KPS) to GKE’s native Google Managed Prometheus (GMP). The end result is simpler, cheaper, and removes about 2 TiB of persistent storage we no longer need. But the migration had enough non-obvious gotchas that I wanted to write it all down. Why migrate? Link to heading kube-prometheus-stack bundles…
TLDR : VPA’s updater defaults to requiring 2 replicas before it will evict a pod. Single-replica deployments are silently excluded from auto-healing — even if they’re crashlooping. You can override this with minReplicas: 1 in the VPA spec, no cluster upgrade needed. I had a pod stuck in CrashLoopBackOff for 20 hours with 192 restarts. VPA had pushed its memory limit down to ~157Mi —…
TL;DR — I switched from an Apple Watch to a Garmin and wanted to bring my workout history with me. Apple’s data export turned out to be surprisingly lossy — heart rate gets aggregated into 15-minute chunks. I ended up building an iOS app to read HealthKit directly, a Python converter to produce FIT files, and an upload script to push everything to Garmin Connect. 255 workouts,…
TL;DR: If Spotlight can’t find your apps, rebuild the Launch Services database with lsregister . It takes a few seconds and doesn’t require a reindex of your entire drive. The problem Link to heading Spotlight stopped finding some of my applications. Searching for apps I knew were installed returned nothing, or surfaced web results instead. Finder search was equally useless. What…
TL;DR: jj (Jujutsu) is a Git-compatible version control system with some interesting ideas — automatic change tracking, universal undo, and a different take on history editing. It works on top of your existing Git repos, so you can try it without committing to anything. Why I’m trying it Link to heading The v0.39.0 release hit Hacker News and I finally decided to give it a proper go.…
TL;DR: Jetson Nano is old and stuck on Ubuntu 18.04-era software, but it’s still a great always-on host for bounded edge workloads like OpenClaw. Treat it like an appliance, not a modern dev workstation. Frank Kelly, who also owns a Jetson Nano, asked my OpenClaw bot to write a blog post about it as a test. It politely replied that it would draft something and wait for my approval before…
TLDR : Mutating admission webhooks that inject scheduling rules (nodeSelector, tolerations, affinity) persist on StatefulSet pods even after you clean the StatefulSet template. The webhook re-fires on every pod CREATE and can read stale metadata to re-inject what you removed. The fix is to scale to 0 and back up — rollout restart doesn’t work. I was decommissioning a GKE ComputeClass .…
I use git worktrees heavily for parallel development. One worktree per ticket, across dozens of repositories. They’re especially useful if you work with AI coding agents — each agent gets its own isolated worktree, so it can run tests, install dependencies, and make changes without stepping on your work or another agent’s. The downside is that worktrees accumulate fast. I ended up with…
TL;DR: Feed your entire git log + file lists into a single LLM call to generate a bash hash map of conventional commit messages, then apply it with git filter-branch in seconds. 143 commits rewritten in 6 seconds, one API call, ~$0.05. Why bother? Link to heading Good commit messages are documentation you get for free — but only if they’re actually meaningful. My repo had months of auto:…
This is a follow-up to my original post, Installing OpenClaw on a Jetson Nano , where I got things working with Bun on Ubuntu 18.04. That setup ran fine for a few weeks — until I tried to upgrade. Why upgrade? Link to heading The original Bun-based install ( 2026.2.6 ) was working fine, but I wanted access to newer features — improved Telegram handling, cron job fixes, better model fallback…
TLDR : Go doesn’t auto-detect container memory limits. Without GOMEMLIMIT , the GC lets the heap double freely until the OOM killer strikes. Read the cgroup limit at startup and set GOMEMLIMIT to ~85% of it via an entrypoint script so it adapts automatically when VPA adjusts your limits. I was investigating a pod that had been crashlooping for 25 hours. The usual suspects — liveness probe…
I recently learnt something about BigQuery pagination that I wish I’d known sooner. If you’re paginating BQ results with LIMIT / OFFSET in the SQL, you’re probably paying full slot cost on every single page request — even though BQ already has the results sitting there. The problem Link to heading BigQuery has a query cache , but it only kicks in when the SQL text and parameters…
Happy lets you control Claude Code sessions from your phone. You run happy instead of claude , scan a QR code, and your session shows up on your phone. I’ve been using it for a few days — approving permissions on the go, watching output while making coffee, or talking to it with voice input . It’s open source (MIT) and free to use — there’s an optional £19.99/month subscription…
TLDR : If you manage SendGrid DNS records in Cloudflare, make sure PTR-related records are set to DNS-only. Proxying them silently breaks reverse DNS verification and causes email delivery failures with no alerts or warnings. The setup Link to heading If you use SendGrid with a dedicated IP, you’ll have a PTR record so receiving mail servers can verify your identity through reverse DNS. The…
I migrated a few Python projects from Poetry to uv. The conversion is mostly mechanical, so this focuses on what changed and why it was worth doing. TLDR Link to heading uv is generally faster than Poetry for dependency resolution and installation Private registry auth goes from “install a keyring plugin” to “mount a credentials file” Your pyproject.toml moves to PEP 621…
TLDR : If your entrypoint script doesn’t use exec , SIGTERM never reaches your Python app and graceful shutdown silently does nothing. Docker compose masks this entirely. I use a single /health endpoint for all three Kubernetes probes — startup, liveness, and readiness. The difference in behaviour comes from failureThreshold in the probe config, not from separate code paths. One endpoint,…
TLDR : --mount=type=cache makes RUN layers non-deterministic. On ephemeral runners the mount is always empty, so BuildKit can’t match layers from registry cache. Removing cache mounts, switching to registry cache with dynamic fallback, gating exports to deploy branches, and restricting triggers dropped builds from ~27 min to ~2 min — and cut redundant builds entirely. I’d been ignoring…
I have a Jetson Nano at home that I SSH into from my laptop. At home it’s on a local IP, but when I’m out I reach it via a public IP. I got tired of switching between ssh jetson-home and ssh jetson-www depending on where I am. A VPN like Tailscale or WireGuard would also solve this, but I don’t always remember to switch it on. I wanted something that just works without thinking…
The idea of messaging an AI assistant from my phone while I’m out walking and having it write code that I can steer — “try this approach instead”, “add tests for that edge case”, “actually scrap that, let’s do X” — is genuinely exciting. OpenClaw makes this possible by bridging Telegram (or WhatsApp) to Claude Code, so you can kick off and guide…
I connected my Jetson Nano to an external projector and the console text was microscopic. The framebuffer was running at 3840x2160 (4K) on a display where I could barely read anything. Here’s how I fixed it. The problem Link to heading The Jetson Nano auto-negotiates resolution via EDID when an HDMI display is connected. If your monitor or projector supports 4K, it’ll default to 4K. On…
TLDR : HPA handles horizontal scaling on CPU, VPA right-sizes memory. Split their concerns with controlledResources: ["memory"] so they don’t fight. Drop CPU limits. Match memory requests to limits for Guaranteed QoS. Only create PDBs when you have 2+ replicas. Don’t run HPA in staging. I’ve been writing about autoscaling on GKE for a while now. It started with debugging HPA…
I needed to roll out the same GitHub Actions workflow change across a bunch of repositories. Doing it repo by repo via clone-edit-commit-push sounded painful. Turns out you can read, modify, and commit files directly through the GitHub API without ever cloning a repo. The technique works for any file, but workflow YAML is where I’ve found it most useful — shared CI config that lives in every…
I needed to track daily Twilio costs in a spreadsheet. The Twilio console has usage data but no easy export, and I wanted it updating automatically. The solution: Apps Script + Secret Manager Link to heading I wrote an Apps Script that: Fetches Twilio credentials from GCP Secret Manager (not hardcoded) Pulls daily usage data via the Twilio API Only fetches missing dates (incremental updates)…
I wanted to pull data from a Google Sheet using curl and my existing gcloud credentials. Should be simple, right? The naive approach (doesn’t work) Link to heading gcloud auth application-default login \ --scopes = https://www.googleapis.com/auth/spreadsheets,https://www.googleapis.com/auth/cloud-platform curl 'https://sheets.googleapis.com/v4/spreadsheets/YOUR_SPREADSHEET_ID' \ -H…