<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jeff Triplett</title><link>http://example.com/</link><description>Latest posts from jefftriplett.com</description><atom:link href="http://example.com/feed.xml" rel="self"/><language>en-us</language><lastBuildDate>Sat, 13 Jun 2026 16:04:52 +0000</lastBuildDate><item><title>How I Work From Anywhere Without Losing My Place</title><link>http://example.com/posts/how-i-work-from-anywhere-without-losing-my-place/</link><description>I’ve been running a new remote development setup for the last month or so, and the goal is simple: move between all of my devices without losing my place.

The way I think about it, I have three default states:

- At my desk on my Mac Studio
- Home or out somewhere with my laptop or an iPad and a portable keyboard
- Only my phone, at practice or running errands

I wanted a setup that works across all three without rebuilding anything when I switch. I’d rather grab my iPhone or iPad with a portable keyboard than lug a laptop everywhere. If I’m at one of my kids’ practices and want to quickly follow up on something or implement an idea, I always have my phone with me.

The stack is basically:

- [Tailscale](https://tailscale.com) - glues all of my devices onto one secure network
- [tmux](https://github.com/tmux/tmux) - keeps my dev environment alive so I can leave and come back without rebuilding
- [Mosh](https://mosh.org) - keeps remote connections resilient across flaky WiFi and network changes
- [cmux](https://cmux.com) - Ghostty + Workspaces for macOS, the desktop side of this
- [Moshi](https://getmoshi.app) - the best iPhone and iPad shell I have found

The first three are the foundation. They work the same no matter which device I’m sitting at. cmux is how I connect from a desktop or laptop, and Moshi is how I connect from my phone or iPad.

Tailscale ties the machines together
------------------------------------

Start with Tailscale. I’ve used Tailscale for almost a decade because it’s free, has clients for everything like my phone, iPads, Macs, Linux boxes, and even routers and TVs. It’s a low-friction way to access all of your devices from anywhere securely and privately.

Tailscale gives me a private network across my devices, so I can connect to my Mac Studio at the office, my Mac Mini at home, my MacBook Air, and Linux boxes without opening SSH to the public internet.

That’s a big part of why I’m comfortable with this setup.

These machines are not sitting there with public SSH ports open. They’re only reachable from my tailnet. Tailscale handles the secure network piece, and I don’t have to mess with WireGuard directly.

It just works.

tmux keeps the work alive
-------------------------

tmux is the core of the setup. I’ve been running it for the last couple of months because I wanted something I could reconnect to later, similar to screen, but better suited to the way I actually work.

A lot of the time, I have something running for work, a client, or one of my own projects. I might have Django in one pane, logs in another, and Claude Code or Codex running somewhere else. With tmux, I can leave that entire development environment in place and come back to it later. Being able to do that has been worth the switch on its own.

I’m probably not using 90% of what tmux was built for. Mostly I’m using it to create sessions, connect to them, and disconnect without losing my place. I can split panes and move between them when I need to, but I find myself doing that less and less. The persistence is the part that actually matters to me.

Some alternatives to tmux are [Zellij](https://zellij.dev) and [Herdr](https://herdr.dev). I attempted to use Zellij, but struggled with the basics, so I bailed and went back to tmux. I haven’t tried Herdr, but I’ve seen people talking about it and wanted to include it.

Mosh makes remote sessions feel less fragile
--------------------------------------------

The bigger improvement came when I added Mosh.

Before I left for PyCon US, I decided I didn’t want to spend the week fighting flaky hotel, airport, and conference WiFi.

I remembered that Mosh solves a lot of the disconnect problems SSH has, so I installed it on my server, my work Mac Studio, my home Mac Mini, and my MacBook Air before I left (Homebrew on macOS, your package manager of choice on Linux).

I connected to a session before getting on the plane. About an hour into the flight, I opened my laptop, and the session resumed automatically. I didn’t have to rebuild anything or start over. It worked better than I thought it would.

Mosh and tmux make a great pair. Mosh keeps the connection resilient, and tmux keeps the actual working state alive.

On a desktop or laptop, cmux ties it together
---------------------------------------------

When I’m at a real keyboard, cmux is how I connect. It gives me Ghostty terminals and workspaces on macOS, which makes it easy to keep several machines and sessions organized at once.

Where cmux really earns its place is how it handles agents and shared sessions. One workflow I’ve come to rely on: I’ll start a tmux session on a remote machine, then connect to it in a second terminal window in cmux. Then I’ll have Claude or Codex connect to that same machine and attach to the same tmux session to do the actual work, like setting up a new Linux box or installing packages.

The nice part is that when Claude hits an interactive prompt, I can just take over the tmux session directly. I’m already attached. I can paste in API keys, answer prompts, or make changes that I wouldn’t want to hand off to an agent. Claude normally tries to handle those moments itself, and it doesn’t always do it well. This way I stay in control of the sensitive parts without losing the automation for everything else.

On my phone or iPad, Moshi is the missing piece
-----------------------------------------------

When I only have my phone or iPad with me, the part I was missing was a good way to connect to my remote sessions.

I had tried Termius before, and it was decent, but I kept running into small UI issues. CLI apps are not really designed for phones and tablets, so little things like getting to the right key at the right time can become annoying fast.

Then I tried [Moshi](https://getmoshi.app).

Moshi is an iOS and iPad app for remote terminal connections. It also runs on Apple Silicon Macs as an iPad app, which is a nice bonus.

Moshi has really good tmux support, and probably other multiplexers I haven’t tried yet. When I connect to a server that has tmux sessions running, Moshi prompts me with a list of those sessions before I even get to a shell. I don’t have to remember the command or go hunting around. I just pick the session and I’m back where I left off. That’s the feature that made the whole setup click.

Moshi also has a good mobile UI for this kind of work. I created a couple of shortcuts, one for space and one for enter, and that gets me through most of what I need when I’m using Claude Code or Codex from my phone.

Codex still has a few spots where it wants escape, and I haven’t fully figured that out yet. That may have been a connection issue, or it may be something I need to configure better.

But for most of what I’m doing, it works shockingly well. I can open my phone, connect to an existing tmux session, check logs, nudge an agent, review what changed, or keep something moving without opening my laptop.

### Setup was easier than expected

Moshi also handles setup nicely.

When you connect to a server, it can show a QR code. You scan that from your phone, and it handles creating and copying the SSH key for you.

That makes setup about as easy as I think it can be.

On Apple devices, Moshi can also share connection settings across devices on the same Apple account. Once I had it set up, connecting from my iPad was painless. I hit the button, picked my session, and I was in.

There is an Android version too. I haven’t tested it because I don’t have an Android device, but it’s there if you need it.

Moshi is a paid app, unlike the rest of this stack, which is free or open source. It runs around $30 a year or around $80 for lifetime access, which felt reasonable given how much I’m using it.

### Voice input

Moshi also supports voice input, which ended up being a bigger deal than I expected.

On my Mac, I already use voice input a lot. I use tools like MacWhisper because voice to text has become a really good input method for me.

Moshi brings that same idea to my phone and iPad.

It can use Apple’s voice to text, and it can also run a Whisper model. That means I can connect to a remote session from my phone and use voice input to interact with the tools I already have running.

Claude Code has voice support on the Mac, but that doesn’t really help when I’m remotely connected into another machine. Moshi having voice support built in makes the whole thing much more useful.

Where I’m using it
------------------

So far, I’ve been using this setup on Django TV, my job board, client work, and a bunch of one-off projects.

I have a Mac Studio at the office and a Mac Mini at home, and I’m constantly moving between them from my MacBook Air. I’ve also been playing with [direnv](https://direnv.net) so I can jump into a project and have the right environment load on the right machine. It’s not really part of this stack, but it pairs well with it.

The split helps me keep things organized. Client work lives on the Mac Studio at the office. Side projects and personal work live on the Mac Mini at home. I can connect to whichever one I need without mixing everything together on my laptop. It also helps my MacBook Air battery, because the heavier work is happening somewhere else.

And because the sessions are always running, I don’t have to worry about rebooting my MacBook Air or losing a Claude Code or Codex session mid-task. If one machine is having a problem, I can exit and switch to the other one while everything I care about stays up and running.

Review has also gotten easier. I can pull up GitHub’s web interface or the GitHub desktop app from wherever I am and review pull requests without needing my full dev environment in front of me. The work is already staged. I just need a browser.

I can still work locally when I want to. There’s nothing wrong with that. But keeping these remote sessions open all the time has been a much better experience.

The databases are already connected. The processes are already running. The agents are already in context. I can leave things in progress and come back later without rebuilding the whole setup.

The glue code
-------------

I’ve also been writing some shell aliases and scripts to smooth over the rough edges, because I don’t want to memorize tmux’s command flags.

I have a set of `tmux-*` aliases that handle the things I actually do: create a new session, resume an existing one, and kill one when I’m done. That covers most of what I need without having to look anything up.

On the cmux side, I’ve been experimenting with its CLI and API. I wrote [`cmux-dump`](https://github.com/jefftriplett/dotfiles/blob/main/home/bin/cmux-dump) and [`cmux-restore`](https://github.com/jefftriplett/dotfiles/blob/main/home/bin/cmux-restore) commands to save and reload workspace layouts. The idea is to build out profiles for each project so I can get everything running the way I want it with one command. That might mean starting a tmux session on a remote machine and connecting to it over Mosh, all from a single alias.

All of this lives in my [dotfiles repo](https://github.com/jefftriplett/dotfiles) and will keep changing as I figure out what actually works. I’m still early in this part of the setup.

When and why you need each tool
-------------------------------

You don’t have to adopt all five of these at once. Each one solves a specific problem, and you can add them as you hit that problem.

- **Tailscale** is the one to start with if your machines aren’t already on a shared network. You need it the moment you want to reach a machine that isn’t sitting in front of you without exposing SSH to the public internet. If all of your work happens on one machine, you can skip it for now.
- **tmux** is what you need when losing your terminal state hurts. If closing a laptop lid or dropping a connection means rebuilding your dev environment, restarting servers, or losing an agent session mid-task, tmux fixes that. It’s also the piece that lets two terminals, or you and an agent, share the same session.
- **Mosh** matters when your network is unreliable. Hotel WiFi, airports, conferences, tethering, or just moving between home and office. If you only ever connect over a stable wired network, plain SSH is fine. The moment you roam, Mosh is the difference between a session that survives and one you have to reconnect constantly.
- **cmux** is for the desktop side, when you’re juggling several machines and sessions and want them organized into workspaces instead of a pile of terminal windows. Any terminal works here, but cmux makes the multi-machine setup easier to live in.
- **Moshi** is for the phone and iPad side. You need it when you want to check on or nudge work from wherever you are. Its tmux session picker, key shortcuts, and voice input are what make a phone a usable terminal instead of a frustrating one.

The short version: Tailscale gets you to the machine, tmux keeps the work alive on it, Mosh keeps the connection from breaking, and cmux and Moshi are the front doors from a desk and from a phone.

This is not about working all the time
--------------------------------------

The real reason I like this setup is not because I want to maximize every spare minute of my life.

It’s almost the opposite.

This setup gives me more flexibility.

If I have 15 minutes at my son’s track meets or baseball practice, I can pull out my phone and reconnect to something already in progress. If I’m waiting on slow tests, client feedback, or a deploy, I don’t have to sit glued to my desk.

I can make dinner. I can pack lunch. I can pick up one of my kids. I can run an errand.

Then, when something is ready, I can check in, make the next change, and keep moving.

It makes the work less jarring. I don’t have to reset everything on my laptop just to make one small change or direct an agent for two minutes.

The best part is that I can just close my laptop or walk away from my desk and know that my Claude and Codex sessions are going to keep running. When I come back, whether it’s on my phone or back at my desk, I can resume right where I left off without worrying about a disconnected session or a timed-out agent.

Why this feels different
------------------------

The built-in remote options from tools like Claude Code and Codex work sometimes, but I kept running into connection weirdness when one laptop was trying to coordinate across multiple machines.

What I wanted was something that didn’t require rebuilding context every time I moved. This stack gives me that. The connection doesn’t break. The session doesn’t disappear. The agents don’t lose their place.

That’s a different kind of flexibility than I had before. It’s not about squeezing more work into more hours. It’s about not paying a tax every time I pick up where I left off.

This is what’s working well for me right now, but I’m genuinely curious what you’re using. If you have a tool that replaces one of these or collapses a few layers into one, I want to hear about it. If you try any of this and it works for you, let me know. And if I’m holding one of these tools wrong and there’s a better way, I’m all ears for that too.

---

Written by Jeff via a mix of voice transcription and typed notes. Edited with Claude Code.

Originally posted on: https://micro.webology.dev/2026/06/13/how-i-work-from-anywhere/</description><pubDate>Sat, 13 Jun 2026 16:04:52 +0000</pubDate><guid>http://example.com/posts/how-i-work-from-anywhere-without-losing-my-place/</guid></item><item><title>Django Chat Podcast: E201</title><link>http://example.com/posts/django-chat-podcast-e201/</link><description>This week, I joined [Will Vincent](https://wsvincent.com) and [Carlton Gibson](https://noumenal.es) on the [Django Chat](https://djangochat.com) podcast for [DjangoCon Europe Recap + Other News](https://djangochat.com/episodes/djangocon-europe-recap-other-news-jeff-triplett). You can also watch it on [DjangoTV via YouTube](https://djangotv.com/videos/djangochat/2026/djangocon-europe-recap-other-news-jeff-triplett/).

On this episode, we discussed [DjangoCon Europe](https://2026.djangocon.eu), which Carlton had attended. We caught up on what’s going on with [Django News](https://django-news.com) and the [Django Software Foundation](https://www.djangoproject.com). We also spent a good chunk of time on AI workflows and tooling. And I got to have a little soapbox rant at the end, which is always fun for me.

Projects I Recommended
----------------------

- [Pydantic AI](https://github.com/pydantic/pydantic-ai) is the Django ORM for accessing LLM providers
- [CodexBar](https://github.com/steipete/CodexBar) - If you are on a Mac, CodexBar will let you easily track and see your token usage across 20+ providers
- [Ghostty](https://ghostty.org) - After almost two decades of using iTerm2, I switched.
- [cmux](https://cmux.com) - Built on Ghostty but a nice UX to switch between Agent sessions
- [MacWhisper](https://goodsnooze.gumroad.com/l/macwhisper) - Still my favorite voice to text Mac app

Books I Recommended
-------------------

At the end of the episode, I recommended these two books:

- [The Greatest Bedtime Story Ever](https://www.simonandschuster.co.uk/books/The-Greatest-Bedtime-Story-Ever/Jessie-Sima/9781665974523) by Jessie Sima
- [Enshittification: Why Everything Suddenly Got Worse and What to Do About It](https://us.macmillan.com/books/9780374619329/enshittification/) by Cory Doctorow *(I recommended this one, but maybe not for the reasons you might think)*

Conclusion
----------

I’m always excited and honored to be invited on the show, and I always enjoy it. I hope it was a good listen, and I especially appreciated getting to step on the soapbox one more time at the end.

Originally posted on: https://micro.webology.dev/2026/04/30/djangochat-podcast-e/</description><pubDate>Thu, 30 Apr 2026 18:10:04 +0000</pubDate><guid>http://example.com/posts/django-chat-podcast-e201/</guid></item><item><title>DjangoCon US Talks I'd Like to See 2026 Edition</title><link>http://example.com/posts/djangocon-us-talks-i-d-like-to-see-2026-edition/</link><description>This is my annual list of DjangoCon US talks I’d like to see. I have been doing this since 2015, and it’s one of my favorite traditions.

[DjangoCon US 2026](https://2026.djangocon.us) is in Chicago this year, August 24-28.

**The [CFP](https://pretalx.com/djangocon-us-2026/cfp) is open. The deadline is March 23, 2026 at 11 AM CDT. Submit a talk!**

### Past editions

- [2024 Edition](https://micro.webology.dev/2024/04/28/djangocon-us-talks.html)
- [2023 Edition](https://jefftriplett.com/2023/djangocon-us-talks-i-d-like-to-see-2023-edition/)
- [2022 Edition](https://jefftriplett.com/2022/djangocon-us-talks-i-d-like-to-see-2022-edition/)
- [2018 Edition](https://jefftriplett.com/2018/djangocon-us-talks-i-d-like-to-see-2018-edition/)
- [2017 Edition](https://jefftriplett.com/2017/django-talks-id-like-to-see/)
- [2016 Edition](https://jefftriplett.com/2016/djangocon-us-talks-id-like-to-see/)
- [2015 Edition](https://gist.github.com/jefftriplett/cdda63bf42c592b1a6c8)

Drew’s Topics
-------------

[Drew Winstel](https://winstel.dev) published a great list of [talk ideas for DCUS ‘26](https://winstel.dev/2026/01/05/talk-ideas-for-dcus-26/) with over 20 ideas. Here are some of my favorites from his list. Any of these would make good talk ideas, so check out Drew’s full list too.

- GPTs, LLMs, and AIs, oh my!
- Deployment at any size
- Unexpected use cases, especially ones that make the world better
- Clever hacks (such as Carlton Gibson’s single-file Django project)
- Using Django in machine learning projects
- New features in Django 6.x
- Development and testing techniques that help you build better code
- Convincing product management that you don’t need a SPA or yet another mobile app
- Personal growth: how the community helped you in some way and you’d like to pay it forward
- Adapting communities to changes in life

My Topics
---------

Here are some topics that I’d personally like to see this year.

### What’s coming in Python and Django

With some big shifts coming in Python 3.15 and 3.16, it would be really interesting to see more about what Django developers would benefit from knowing about what’s coming up. Something a little more core to Python would be interesting.

I’d also love to see more Django talks, whether it’s from the Steering Council or anybody working on features for the Django 7 series. What’s coming? What are the big features being tackled?

### Django’s deployment story

Last year I was on a panel called [Two Decades of Django: The Past, Present, and Future](https://djangotv.com/videos/djangocon-us/2025/panel-discussion-two-decades-of-django-the-past-present-and-future-with-velda-kiara/). During that panel, I challenged people to really look into Django’s deployment story and find ways to improve it. If we can remove one or two steps along the way, we can make the deployment story better.

A couple of projects came out of that conversation that I really liked, including [Django Prod Server](https://github.com/nanorepublica/django-prodserver). Anything that makes deployments better and reduces the number of steps is worth exploring. If anybody has topics around improving Django’s deployment experience, that would be a great one to discuss.

### Rust in our ecosystem

I’d like to hear more about Rust in our ecosystem. Tools like uv, Ruff, and Pydantic are all built with Rust. Pydantic led to Django Ninja and other applications built around it. Are you using Rust in your Django applications? Why? Where are you building with it? How is it improving your workflow? Is it for linters? Code formatters? Are you solving performance bottlenecks with Rust? What should Django learn from Rust? Which parts of Django would be better if rewritten in Rust? That story is really fascinating to me.

### LLMs and Django

I’d like to see more LLM talks about the amazing things people are building. This could be with Pydantic AI, creating model agents, or things you’re building that either run Django websites or help people do amazing things with agents. What does it look like to give a functional brain to a Django app? That would be an interesting talk idea.

### Agent skills and productivity

I’d also like to hear about agent skills. How are you improving your productivity? How are you taking some of the drudge work out of working with Django? What skills do you use? What problems are you solving that a skill helps you with? What should Django learn from LLMs, skills, and agents? That would be another interesting topic.

### Real talk about LLMs and team productivity

There are a lot of talks about the negative things about LLMs and AI, and I think that is respectable and understandable. But it has become taboo for some weird reason that people who use LLMs every day aren’t speaking out about it and aren’t talking about the productivity gains they get. Especially if you’re on a small team doing a lot of stuff.

If you’re working with a bigger team and everybody’s using these tools, how are you managing it? How are you getting through pull review processes? How are you making your code better? What’s working? What didn’t work? What’s scaled up for you?

Everything is changing in our industry whether we like it or not. Agents are here. The companies as of today are not going anywhere and the bubble hasn’t burst. I’m really curious about team productivity. What do you like? What don’t you like?

### Defending and embracing LLM traffic

On the flip side with LLMs, so many things have changed in the last year that we have to be a little more defensive with our websites, whether that’s using CDNs like Cloudflare or Fastly. I’m really interested in what people are doing to scale their servers now with LLMs in mind.

Some people may or may not want to make their websites more LLM friendly. There are definitely advantages and disadvantages to doing that. Writing a website to be consumed by LLMs is an interesting topic, both defensively and in terms of how you take advantage of it.

Submit a talk
-------------

You can always go back to my [2024 list](https://micro.webology.dev/2024/04/28/djangocon-us-talks.html) and of course there’s [Drew’s list](https://winstel.dev/2026/01/05/talk-ideas-for-dcus-26/) too. Some of the best topics that will be submitted will be things that don’t fit either of our lists. The whole idea is just to give people a starting point for things we’d both personally like to see, but that shouldn’t limit your imagination.

Outside opinions are great. Not everything needs to be about Django. We always get a bunch of community talks and talks that don’t have to be about the tech. But I think it’s an exciting year to really dig deeper into some of the tech because so much is changing on a weekly basis.

**[Submit your talk for DjangoCon US 2026!](https://pretalx.com/djangocon-us-2026/cfp)**

Originally posted on: https://micro.webology.dev/2026/03/19/djangocon-us-talks-id-like/</description><pubDate>Thu, 19 Mar 2026 20:54:26 +0000</pubDate><guid>http://example.com/posts/djangocon-us-talks-i-d-like-to-see-2026-edition/</guid></item><item><title>How I Use django-simple-nav for Dashboards, Command Palettes, and More</title><link>http://example.com/posts/how-i-use-django-simple-nav-for-dashboards-command-palettes-and-more/</link><description>I first got exposed to [django-simple-nav](https://github.com/westerveltco/django-simple-nav) while working with [Josh Thomas](https://github.com/joshuadavidthomas) at [the Westervelt Corporation](https://github.com/westerveltco) over the last two or three years. It quickly became a go-to library in my toolkit. django-simple-nav lets you define nav items and groupings in Python, then hand them off to a Django template to render. I use it for sidebars, headers, dashboards, and other spots where I need a menu.

Since then, I have also started using it on a lot of personal projects. It has been a great fit every time.

Defining nav items once and reusing them everywhere
---------------------------------------------------

Recently I wanted to reuse parts of a menu nav without having to update a bunch of different files. I had a dashboard with a sidebar full of links, and I also wanted a command palette that could search across all those same options when you hit Command-K from any page. django-simple-nav was a natural fit because you define your items once in Python and render them with whatever template you want.

Here is an example of what that looks like in Python:

&lt;div class="highlight"&gt;```python
&lt;span style="color:#f92672"&gt;from&lt;/span&gt; django_simple_nav.nav &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Nav
&lt;span style="color:#f92672"&gt;from&lt;/span&gt; django_simple_nav.nav &lt;span style="color:#f92672"&gt;import&lt;/span&gt; NavGroup
&lt;span style="color:#f92672"&gt;from&lt;/span&gt; django_simple_nav.nav &lt;span style="color:#f92672"&gt;import&lt;/span&gt; NavItem

NAV_ITEMS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
    NavItem(title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"Home"&lt;/span&gt;, url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"home"&lt;/span&gt;),
    NavItem(title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"Dashboard"&lt;/span&gt;, url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"dashboard"&lt;/span&gt;),
    NavGroup(
        title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"Admin &amp; Tools"&lt;/span&gt;,
        items&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[
            NavItem(title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"Admin"&lt;/span&gt;, url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"admin:index"&lt;/span&gt;, permissions&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;"is_staff"&lt;/span&gt;]),
        ],
    ),
    NavItem(title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"Login"&lt;/span&gt;, url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"login"&lt;/span&gt;),
    NavItem(title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"Logout"&lt;/span&gt;, url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"logout"&lt;/span&gt;),
]


&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DashboardNav&lt;/span&gt;(Nav):
    template_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;"nav/dashboard.html"&lt;/span&gt;
    items &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NAV_ITEMS


&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CommandPaletteNav&lt;/span&gt;(Nav):
    template_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;"nav/command_palette.html"&lt;/span&gt;
    items &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NAV_ITEMS


```

&lt;/div&gt;Flexible URLs and named routes
------------------------------

A few things to notice here. When you create a nav item and you have a URL, you can either use the URL’s name or you can give it the path to it and it will figure out what it is. So if I want a nav item for the Django admin, I can use `"admin:index"` as the URL.

Handling permissions without template logic
-------------------------------------------

Another nice feature is the `permissions` parameter. The Admin link uses `permissions=["is_staff"]`, which means it only shows up for staff users. You can use this to hide things based on whether someone is staff, a superuser, or has specific Django permissions. This makes it nice to keep all of your nav options in one place without having to write special conditional logic in your templates to show or hide items for different users.

Rendering a dashboard nav with Django templates
-----------------------------------------------

The other thing to notice is the two Nav classes at the bottom: `DashboardNav` and `CommandPaletteNav`. They both use the same `NAV_ITEMS` list but point to different templates. This is where the reuse really shines.

Here is an example nav template at `templates/nav/dashboard.html`:

&lt;div class="highlight"&gt;```html
&lt;&lt;span style="color:#f92672"&gt;nav&lt;/span&gt;&gt;
  {% for item in items %}
    {% if item.items %}
      &lt;&lt;span style="color:#f92672"&gt;span&lt;/span&gt;&gt;{{ item.title }}:
        {% for subitem in item.items %}
          &lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"{{ subitem.url }}"&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;subitem&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;active&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;%}&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"active"&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endif&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;%}&lt;/span&gt;&gt;
            {{ subitem.title }}
          &lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&gt;
        {% endfor %}
      &lt;/&lt;span style="color:#f92672"&gt;span&lt;/span&gt;&gt;
    {% else %}
      &lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"{{ item.url }}"&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;active&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;%}&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"active"&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;{%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endif&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;%}&lt;/span&gt;&gt;
        {{ item.title }}
      &lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&gt;
    {% endif %}
  {% endfor %}
&lt;/&lt;span style="color:#f92672"&gt;nav&lt;/span&gt;&gt;

```

&lt;/div&gt;Then in your base template, you can render it with the template tag:

&lt;div class="highlight"&gt;```html
{% load django_simple_nav %}

{% django_simple_nav "myapp.nav.DashboardNav" %}

```

&lt;/div&gt;Building a command palette from the same nav items
--------------------------------------------------

Because the `CommandPaletteNav` class uses the same `NAV_ITEMS` list but with a different template, we can render the same nav data as JSON for a command palette. Here is an example template at `templates/nav/command_palette.html`:

&lt;div class="highlight"&gt;```html
{% load django_simple_nav %}

&lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"application/json"&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;"command-palette-data"&lt;/span&gt;&gt;
[{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;item&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;items&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;items&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;subitem&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;item&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;items&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
  {&lt;span style="color:#e6db74"&gt;"title"&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;"{{ subitem.title }}"&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;"url"&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;"{{ subitem.url }}"&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;"group"&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;"{{ item.title }}"&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;not&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;forloop&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;last&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;or&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;not&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;forloop&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;parentloop&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;last&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;},{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endif&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endfor&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
  {&lt;span style="color:#e6db74"&gt;"title"&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;"{{ item.title }}"&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;"url"&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;"{{ item.url }}"&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;not&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;forloop&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;last&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;},{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endif&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endif&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;endfor&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
]
&lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&gt;

```

&lt;/div&gt;This also lent itself well when I was trying to do something quickly with Claude. I don’t know how to build a command palette, but I was able to just have Claude create one. I asked it to use HTMX to keep everything pretty lightweight.

Final thoughts
--------------

All in all, django-simple-nav is a nice library to have in your toolkit. I like using it for headers, menus, dashboard navigation links, and even footer text. If you need flexible, reusable navigation in Django, give it a look.

---

Written by Jeff. Edited with [Grammarly](https://grammarly.com) and [Claude Code](https://claude.ai/code).

Originally posted on: https://micro.webology.dev/2026/02/26/how-i-use-djangosimplenav-for/</description><pubDate>Fri, 27 Feb 2026 02:56:51 +0000</pubDate><guid>http://example.com/posts/how-i-use-django-simple-nav-for-dashboards-command-palettes-and-more/</guid></item><item><title>Jordan Baird's Ice beta fixed my macOS Tahoe menu bar issues</title><link>http://example.com/posts/jordan-baird-s-ice-beta-fixed-my-macos-tahoe-menu-bar-issues/</link><description>If you use a Mac, you’ve probably noticed that the menu bar fills up with icons pretty quickly. [Bartender](https://www.macbartender.com) and [Ice](https://github.com/jordanbaird/Ice) (sadly, now an unfortunate name) are apps that let you manage and hide unwanted icons from your macOS menu bar so it stays clean and uncluttered.

About a year ago, I switched from Bartender to Ice, which just happens to be open source, because there was [some drama](https://micro.webology.dev/2024/06/04/bartender-mac-app.html). Since then, I’ve been very happy with Ice.

A couple of months ago, I upgraded to macOS Tahoe, and my menu bar stopped working correctly. The icon colors were all this weird shade of blue, so I couldn’t customize anything. After months of trying to figure it out, I noticed that it had been a while since Ice released a new version. That’s how open source goes sometimes.

I was getting to the point of deciding whether to go back to Bartender or stick with Ice. Today, I noticed that there’s a Homebrew package for `jordanbaird-ice@beta`. I decided to give it a try, removed the old version, installed the beta, and to my surprise and delight, the problem was fixed.

&lt;div class="highlight"&gt;```shell
&lt;span style="color:#75715e"&gt;# remove the stable version&lt;/span&gt;
brew remove jordanbaird-ice

&lt;span style="color:#75715e"&gt;# install the beta&lt;/span&gt;
brew install jordanbaird-ice@beta

```

&lt;/div&gt;I’m hoping there’s a more official release soon. The new Bartender looks good too, so if Ice doesn’t keep getting updated, I might switch back. If you’ve run into this same issue, give the beta a try and let me know how it goes. And if you know of any alternatives to Bartender and Ice, I’d love to hear about those too.

Originally posted on: https://micro.webology.dev/2026/02/19/jordan-bairds-ice-beta-fixed/</description><pubDate>Thu, 19 Feb 2026 14:00:00 +0000</pubDate><guid>http://example.com/posts/jordan-baird-s-ice-beta-fixed-my-macos-tahoe-menu-bar-issues/</guid></item><item><title>My displays keep rearranging and displayplacer fixed it</title><link>http://example.com/posts/my-displays-keep-rearranging-and-displayplacer-fixed-it/</link><description>Today I learned about [displayplacer](https://github.com/jakehilborn/displayplacer) - “macOS command line utility to configure multi-display resolutions and arrangements.”

In December, I upgraded to MacOS Tahoe and picked up the TS4 dock for my work machine.

While my upgrade was painless, the biggest issue I’ve had is with my displays. Every time my displays go to sleep and then I come back from lunch or come back the next day to work, my orientation of my displays changes and it puts them in a random order.

My displays should be arranged like this:

&lt;div class="highlight"&gt;```shell
&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;2&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;span style="color:#f92672"&gt;[&lt;/span&gt;3&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;4&lt;span style="color:#f92672"&gt;]&lt;/span&gt;

```

&lt;/div&gt;But after waking from sleep, they end up like this:

&lt;div class="highlight"&gt;```shell
&lt;span style="color:#f92672"&gt;[&lt;/span&gt;2&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;span style="color:#f92672"&gt;[&lt;/span&gt;3&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;4&lt;span style="color:#f92672"&gt;]&lt;/span&gt;

```

&lt;/div&gt;It’s really annoying. It takes a minute to fix and it’s just frustrating.

I tried displayplacer today. I had Claude Code actually run the `displayplacer list` command. It figured out which displays and which settings needed to be changed. I had it record that and then I tried it out a few times where I manually dragged my displays around, put them in the wrong order, then ran the command, and it just magically worked.

I saved the working configuration to a shell script:

&lt;div class="highlight"&gt;```shell
&lt;span style="color:#75715e"&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;# Restore display layout: 4 monitors (2x 16" 1920x1080, 2x 73" 2048x1280)&lt;/span&gt;

displayplacer &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;  &lt;span style="color:#e6db74"&gt;"id:F4AB0D6C-8E85-4E84-B5AB-C5B388536E3D res:1920x1080 hz:60 color_depth:8 enabled:true scaling:off origin:(0,0) degree:0"&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;  &lt;span style="color:#e6db74"&gt;"id:C9240C8E-A9D2-418A-89AC-28D3B5DEE5FC res:1920x1080 hz:60 color_depth:8 enabled:true scaling:off origin:(-1920,0) degree:0"&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;  &lt;span style="color:#e6db74"&gt;"id:B43E3352-ACB7-4163-A25B-2DDAE0174571 res:2048x1280 hz:60 color_depth:8 enabled:true scaling:off origin:(0,-1280) degree:0"&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;  &lt;span style="color:#e6db74"&gt;"id:B32F530C-62CF-4F0D-9997-80BF2B812AC8 res:2048x1280 hz:60 color_depth:8 enabled:true scaling:off origin:(-2048,-1280) degree:0"&lt;/span&gt;

```

&lt;/div&gt;I also tried setting it up as a Stream Deck key and for some reason I couldn’t get that to work. But it’s fine. I can run a shell script and that takes a lot less time to get it in the right order.

Originally posted on: https://micro.webology.dev/2026/02/18/my-displays-keep-rearranging-and/</description><pubDate>Wed, 18 Feb 2026 22:54:47 +0000</pubDate><guid>http://example.com/posts/my-displays-keep-rearranging-and-displayplacer-fixed-it/</guid></item><item><title>🤖 Trying Out GLM with Claude Code</title><link>http://example.com/posts/trying-out-glm-with-claude-code/</link><description>My friend [Trey Hunner](https://treyhunner.com) showed me the GLM set of models before Thanksgiving. While traveling to see family, I somehow messed up my Claude Code setup because of a wrapper I have with [mise-en-place](https://mise.jdx.dev). I couldn’t use it for a while, and that made me realize I really need a backup for Claude Code.

Why GLM?
--------

[Z.AI](https://z.ai)’s GLM model is better than Gemini but not quite as good as Claude Code. It’s really fast (about twice as fast as Claude Code), seems like 90+ percent as good, and it’s really cheap. You can get an annual subscription for around $26-28 for the first year, and I’ve read online that it’s very hard to hit the limit even on the lowest tier subscription.

This is a great option for folks who can’t quite justify the $100/mo Claude plan but occasionally hit limits on the $20/mo Claude plan. I actually subscribe to the $100/mo plan, but I ended up getting the GLM Pro Plan because I like the amount of usage it gives me. The plan I’m on has five times as much token usage as the base tier.

Running Both Side by Side
-------------------------

There’s a [wrapper tool](https://github.com/JoeInnsp23/claude-glm-wrapper) that lets you use Z.AI’s models as Claude Code’s backend, so you can run both Claude and Z.AI’s GLM in two different windows. Having a reasonable backup that I can switch between or run in parallel is nice.

I never find speed to be an issue with Claude Code, but I’m definitely a fan of having options.

API Access
----------

Claude doesn’t include API key access without paying extra. GLM solves this problem by giving you a raw API for a set price per month. Their API is OpenAI compatible, so I can work on agentic scripts using Open Coder or other applications without paying extra for Anthropic tokens.

Getting Started
---------------

To get started, run:

&lt;div class="highlight"&gt;```bash
bunx claude-glm-installer

```

&lt;/div&gt;This will give you bash aliases that let you run various GLM models while still letting Claude default to the Anthropic backend:

&lt;div class="highlight"&gt;```bash
ccg              &lt;span style="color:#75715e"&gt;# Claude Code with GLM-4.6 (latest)&lt;/span&gt;
ccg45            &lt;span style="color:#75715e"&gt;# Claude Code with GLM-4.5&lt;/span&gt;
ccf              &lt;span style="color:#75715e"&gt;# Claude Code with GLM-4.5-Air (faster)&lt;/span&gt;
cc               &lt;span style="color:#75715e"&gt;# Regular Claude Code&lt;/span&gt;

```

&lt;/div&gt;Trey also told me about [claude-code-router](https://github.com/musistudio/claude-code-router), which lets you change models on the fly without restarting Claude Code. This might work well if you want to switch between models mid-session.

If you find yourself running out of Claude Code tokens a couple of times a week or even a couple of times a day, it might be worth checking out GLM as a backup or alternative.

If you want to try out Z.AI’s GLM models, please use [my invite link](https://z.ai/subscribe?ic=GLMN4NLXLV) (affiliate) or feel free to use [Trey Hunner’s invite link](https://z.ai/subscribe?utm_medium=edm&amp;utm_content=blackfriday&amp;_channel_track_key=PJg2GPj2) (affiliate) instead.

Resources
---------

- [Claude GLM Installer tool on Reddit](https://www.reddit.com/r/ClaudeCode/comments/1nv64g5/i_made_a_tool_to_use_zais_glm_models_with_claude/)
- [claude-glm-wrapper on GitHub](https://github.com/JoeInnsp23/claude-glm-wrapper)
- [claude-code-router on GitHub](https://github.com/musistudio/claude-code-router)

---

Written by Jeff. Edited with [Grammarly](https://grammarly.com) and [Claude Code](https://claude.ai/code).

Originally posted on: https://micro.webology.dev/2025/12/10/trying-out-glm-with-claude/</description><pubDate>Thu, 11 Dec 2025 01:43:48 +0000</pubDate><guid>http://example.com/posts/trying-out-glm-with-claude-code/</guid></item><item><title>🤖 How I Accidentally Spent Over 62 Million OpenAI Tokens</title><link>http://example.com/posts/how-i-accidentally-spent-over-62-million-openai-tokens/</link><description>I’ve been fighting a runaway [OpenAI](https://openai.com) bill for the last few weeks. I was worried I was leaking one of my API keys in a non-obvious way, possibly in one of my public projects.

Two weeks ago, I deleted all my keys and contacted OpenAI support. I created new keys for every project, making it easier to track usage and identify any leaks. I had already been doing this, but I was a bit lax on a few projects while migrating from [Digital Ocean](https://www.digitalocean.com) to [Hetzner](https://www.hetzner.com). More on that migration soon.

Fast forward two weeks, and OpenAI notified me again that I hit my very low recharge threshold. With granular keys in place, it only took a minute to narrow down the culprit: my [DjangoTV.com](https://djangotv.com) project.

I use the [OpenAI API](https://platform.openai.com/docs/api-reference/introduction) to help parse presenter names and clean up titles whenever we add new videos. I had recently added [DjangoCon US](https://djangotv.com/videos/djangocon-us/2025/) videos and [Wagtail Space](https://djangotv.com/videos/wagtail-space/2025/) videos during the last two weeks, both on the same day our LLM usage spiked.

I checked my [Django-Q2](https://github.com/django-q2/django-q2) logs and noticed several tasks failing because they were timing out after 90 seconds. The task accepts a list of video IDs and loops through them, parsing each one using [Pydantic AI](https://ai.pydantic.dev) and the OpenAI API. When I ran it from the command line, I never hit a timeout. But when I created a Django Admin Action to bulk process videos, I was trying to process them all in one call instead of fanning them out into individual tasks.

What Went Wrong?
----------------

I didn’t have just one bug - I had two, possibly three bugs that weren’t obvious at the time:

1. **Timeout issues**: Tasks were timing out after 90 seconds when processing large batches
2. **Bulk processing**: Processing all videos in one call instead of individual async tasks
3. **Infinite retries**: I failed to set a maximum number of retry attempts. I assumed that not having a default meant there was a fixed number of retries, not infinite

That third bug was the killer. My job ran for over 24 hours, burning through over 32 million tokens in the process. In total, I spent over 62 million tokens in November before I found and fixed the issue. Thankfully, my out-of-pocket costs were more than reasonable.

What Changed?
-------------

I could blame this on vibecoding since DjangoTV is &amp;gt;99% vibe coded, but the project was built using sensible defaults and this wasn’t obvious at the time.

Here’s what I changed:

- Set `max_attempts` to limit retries
- Kept my 90 second `timeout`
- Spaced out `retry` attempts to a few minutes between tries
- Adjusted my `parse_presenters_with_ai` and `parse_titles_with_ai` Django Admin Actions to queue up one `async_task` per Video instead of processing them all in one call

Sometimes the most expensive bugs are the ones that combine multiple small issues into one perfect storm. Granular API keys for tracking, sensible retry limits, and proper task queuing are now non-negotiable in my projects.

Computers!

---

Written by Jeff. Edited with [Grammarly](https://grammarly.com) and [Claude Code](https://claude.ai/code).

Originally posted on: https://micro.webology.dev/2025/11/22/how-i-accidentally-spent-over/</description><pubDate>Sun, 23 Nov 2025 05:01:54 +0000</pubDate><guid>http://example.com/posts/how-i-accidentally-spent-over-62-million-openai-tokens/</guid></item><item><title>The "Vibe Coding Keyboard" How I Made My Walk-and-Talk Setup Even More Awesome</title><link>http://example.com/posts/the-vibe-coding-keyboard-how-i-made-my-walk-and-talk-setup-even-more-awesome/</link><description>So, picture this: you’re working at a walking desk, you’ve got a cool voice-to-text tool like [MacWhisper](https://goodsnooze.gumroad.com/l/macwhisper) running, and you want to control it all with just a couple of dedicated keys. That was the dream that led me to build what I now call my “Vibe Coding Keyboard.”

### Why Voice Control in the First Place?

Before I get into the keyboard itself, let me explain why I’ve gotten so into voice control. A considerable part of my day involves Slack and Discord conversations, and voice mode is high-speed for firing off replies. I also use it to drive Claude Code sessions and other workflows, and it’s just become second nature.

But the real game changer is the walking desk. When you’re walking and working, typing gets awkward fast. Your arms are in weird positions, and trying to maintain your stride while reaching for your keys just looks clumsy. With voice mode, I can quickly dictate a response to an email or message, clean it up if needed, and keep moving. It’s way more natural than contorting myself to type while walking.

### Why a Dedicated Keyboard?

I already had an Apple Magic Keyboard that I loved. It’s sleek and all, but I kept running into a minor but annoying problem: I was running out of keys to assign to all my voice-control shortcuts. I tried using the function key as a makeshift “vibe” key, but it just wasn’t cutting it.

So I went looking for the smallest possible external keyboard I could find. I wanted something that would just plug in like a regular HID keyboard, no extra drivers or fancy setup. I originally tried to find a two-key keyboard, but I couldn’t find any that were USB-C. So I went with the [BTXETUEL 4-Key Mechanical Keyboard](https://www.amazon.com/dp/B0BW15CPTY) instead, and it turned out to be perfect. Its small enough that it doesn’t take up much space, and having four keys actually gives me a bit more flexibility than I originally thought I needed.

![The BTXETUEL 4-Key Mechanical Keyboard vibing](https://cdn.uploads.micro.blog/137490/2025/b388258f45.png)### Setting Up the Vibe Keys

Here’s how I configured it:

- **Key 1:** My “vibe” key. This one toggles MacWhisper’s dictation mode on and off. I just tap it, and boom, I’m in voice mode.
- **Key 2:** Enter key. Super handy for confirming commands or just hitting “enter” without reaching for my main keyboard.
- **Key 3:** Backspace. Because voice-to-text sometimes needs a quick correction.
- **Key 4:** Escape key. Just a nice little “get me out of here” button if I need to exit a mode or cancel something.

And because I wanted a bit of flair, each key has an LED that can change color. I made the vibe key cycle through a rainbow pattern, so it stands out and literally “vibes.”

### The Fun of Customization

The best part is how customizable this little gadget is. I even 3D-printed some LEGO keycaps just for fun. It’s become a hobby project, and it has made voice coding even more enjoyable for me.

### A Boost to Productivity (and Fun)

In the end, it’s not something you absolutely need, but it’s been a surprisingly nice productivity boost. Plus, it’s just plain cool to have a dedicated vibe key that lights up in rainbow colors while you work. If you’re into voice mode coding or want a fun little side project, give something like this a try!

---

Written by Jeff. Dictated via [ChatGPT 5.1](https://chatgpt.com). Edited with [Grammarly](https://grammarly.com) and [Claude Code](https://claude.ai/code).

Originally posted on: https://micro.webology.dev/2025/11/19/the-vibe-coding-keyboard-how/</description><pubDate>Thu, 20 Nov 2025 00:37:48 +0000</pubDate><guid>http://example.com/posts/the-vibe-coding-keyboard-how-i-made-my-walk-and-talk-setup-even-more-awesome/</guid></item><item><title>📅 Office Hours for November</title><link>http://example.com/posts/office-hours-for-november/</link><description>I’m hosting office hours on the next two Fridays in November.

Office Hours Schedule
---------------------

- **[Friday, November 14, 2025, 2:30 pm to 4:30 pm CT](https://time.is/0230PM_14_November_2025_in_CT)**
    - Starting at 2pm CT, I’ll be working on some community/open source projects if anyone wants to see Claude Code or Claude Code on the web in action
- **[Friday, November 21, 2025, 2:30 pm to 4:30 pm CT](https://time.is/0230PM_21_November_2025_in_CT)**
- 🦃 **Friday, November 28th - No office hours due to US Thanksgiving**

Join Us
-------

These sessions are open to anyone, especially those working remotely who wants to connect with others. It’s a collaborative space for discussions, catch-ups, or just hanging out while you work.

While we have a bunch of Python and Django developers who regularly attend, anyone is welcome to join even if you don’t use either of these things.

Whether you’re a first-time attendee or a regular, you’re welcome to drop in anytime during the session. No need to stay for the full two hours, come and go as your schedule allows.

How to Join
-----------

The Zoom link is available in the gist from our previous sessions. Feel free to reach out if you need the details.

ℹ️ Meeting Guidelines
---------------------

- 🔕 Please mute when someone else is talking 👈
- 👍 Be respectful to other people and mute when not talking
- 👍 Be mindful of the spirit of the [Python Code of Conduct](https://policies.python.org/python.org/code-of-conduct/)
- 👍 Be mindful and respectful of everyone’s time.
- 👍 Join because you want to work on something with a small group
- ⚠️ No marketing your product or service
- ⚠️ No meeting/recording bots. Humans are welcome. Meeting bots are not.
- ⚠️ Mute!

See you there!

Originally posted on: https://micro.webology.dev/2025/11/13/office-hours-for-november/</description><pubDate>Thu, 13 Nov 2025 23:08:22 +0000</pubDate><guid>http://example.com/posts/office-hours-for-november/</guid></item><item><title>Default Apps 2025</title><link>http://example.com/posts/default-apps-2025/</link><description>2025-10-29 Default Apps 2025
============================

Here are my Default Apps 2025, which builds from my [Default Apps 2024](https://jefftriplett.com/2024/default-apps-2024/) and [Default Apps 2023](https://jefftriplett.com/2023/default-apps-2023/) posts.

🤖 AI Coding Assistant: [Claude Code](https://claude.ai/code) + [GitHub Copilot CLI](https://github.com/features/copilot/cli) + [Codex](https://openai.com/codex/)⚙️ Automation: [Hammerspoon](https://www.hammerspoon.org)🎒 Backups: [Backblaze](https://www.backblaze.com)🔖 Bookmarks: [Raindrop.io](https://raindrop.io)🌐 Browser: [Vivaldi](https://vivaldi.com)📆 Calendar: Apple Calendar 💬 Chat: Apple Messages (family &amp;amp; friends), [Discord](https://discord.com/) (friends), [Slack](https://slack.com/) (work and community work), [Telegram](https://telegram.org) (weird bots) 📁 Cloud File Storage: iCloud Drive + [Syncthing](https://syncthing.net)🧑‍💻 Code Editor: [Sublime Text](https://www.sublimetext.com/) + [Zed](https://zed.dev)🤖 Containers: [OrbStack](https://orbstack.dev) + [Docker Compose](https://www.docker.com)✍️ Grammar: [Grammarly](https://grammarly.com)🚀 Launcher: [Alfred 5](https://www.alfredapp.com)📨 Mail Client: [Mimestream](https://mimestream.com) (Gmail only and not very often) 📮 Mail Server: [Fastmail](https://www.fastmail.com) (I pay for it but still don’t use it enough) + Gmail 👔 Menu Bar: [Ice](https://icemenubar.app)🎵 Music: [Apple Music](https://www.apple.com/apple-music/) + [Spotify](https://spotify.com)🔐 Password Management: [1Password](https://1password.com/)🎤 Podcasts: Apple Podcast 📑 Read It Later: [Raindrop.io](https://raindrop.io)🔗 Remote Access: [Tailscale](https://tailscale.com)🗓️ Scheduling + Booking: [Cal.com](https://cal.com)🖼️ Screenshots: [Xnapper](https://xnapper.com)🔍 Search: [Kagi](https://kagi.com)🐚 Terminal: [iTerm2](https://iterm2.com) + [Ghostty](https://ghostty.org)🌐 Terminal Proxy: [VibeTunnel](https://vibetunnel.sh)🎙️ Transcription: [MacWhisper](https://goodsnooze.gumroad.com/l/macwhisper)🗃️ Version Control: [Tower](https://www.git-tower.com)📹 Video Calls: [Zoom](https://zoom.us) + [Cal.com](https://cal.com) + [Meeter](https://www.trymeeter.com)✈️ VPN: [Mullvad](https://tailscale.com/mullvad)📝 Writing: [Obsidian](https://obsidian.md/)

Commentary
----------

The biggest changes for me this year were the addition of more AI tooling like coding assistants, VibeTunnel, and the MacWhisper voice translating app. A year ago, I was writing my own AI coding tools with Python. Today, I use voice-to-text to interact with multiple coding assistants that I can access from any browser connected to my Tailscale Tailnet. It’s a mouthful to explain, but coding looks very different now than it did a year or two ago for me.

I’m not using Google Apps as much as I was a few years ago, though I still need to switch between Google Orgs for work and community organizations.

Changes from 2024
-----------------

**New Additions:**

- AI Coding Assistant (Claude Code, GitHub Copilot CLI, Codex)
- **VibeTunnel** for accessing my terminal through any browser on my Tailnet
- I started using **Ghostty** to run my AI sessions, but I find its lack of find (⌘f) support to be terribly frustrating.
- I have used MacWhisper for years, but now it’s a daily driver. I can hold down the globe (fn) key on my keyboard and talk to my computer and quickly reply to people or even write blog posts with my voice. It’s incredibly cool and powerful.

**Apps Removed:**

- I dropped **Polypane** (Browser category)
- I managed to not use **Overcast** (Podcasts category) for most of the year, but I’m still not happy with Apple’s Podcast app. I might be switching back.

Previously inspired by: “Apps I’ve been using regularly this year.” Heavily inspired by [Matt Stein](https://mattstein.com/thoughts/default-apps-2023/) and cataloged by Robb Knight’s [App Defaults](https://defaults.rknight.me)

Originally posted on: https://micro.webology.dev/2025/10/29/default-apps-here-are-my/</description><pubDate>Wed, 29 Oct 2025 23:55:03 +0000</pubDate><guid>http://example.com/posts/default-apps-2025/</guid></item><item><title>🤖 On GitHub Copilot CLI and prompts as code</title><link>http://example.com/posts/on-github-copilot-cli-and-prompts-as-code/</link><description>I checked out William Vincent’s [The Secret Prompts in GitHub Copilot CLI](https://wsvincent.com/copilot-cli-secret-prompts/) tonight, and I wanted to share a few tips and what stood out to me.

GitHub Copilot CLI uses Claude Sonnet 4.5 by default
----------------------------------------------------

&gt; No luck other than confirming it is using Claude models by default. Apparently, you can change the underlying model, for example, to ChatGPT 5, by updating the environment variable `COPILOT_MODEL=gpt-5`; however, we will work with the defaults here.

You can Copilot CLI’s default model via the `/model` command and it will also let you pick between three models.

&lt;div class="highlight"&gt;```shell
 Select Model

 Choose the AI model to use &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Copilot CLI. The selected model will be persisted and used &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; future sessions.

 ❯ 1. Claude Sonnet 4.5 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;default&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;(&lt;/span&gt;current&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
   2. Claude Sonnet &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
   3. GPT-5
   4. Cancel &lt;span style="color:#f92672"&gt;(&lt;/span&gt;Esc&lt;span style="color:#f92672"&gt;)&lt;/span&gt;

 Use ↑/↓ to navigate, Enter to &lt;span style="color:#66d9ef"&gt;select&lt;/span&gt;, Esc to cancel

```

&lt;/div&gt;I’m somewhat surprised that GitHub CLI isn’t shipping with `gpt-5-codex` model support yet. From my testing, it appears to be OpenAI’s best coding model, but it may be shipping soon.

The “You are” trick
-------------------

&gt; Well, what we “really” care about are any prompts that start with “you are” since those are instructions from Copilot CLI to the model.

The “you are” tip is one I shared with Will and [Simon Willison](https://simonwillison.net), which I have used for a few years when trying to find a tool’s system prompt, which is always buried and obfuscated in their JavaScript files.

Simon and I were invited to Microsoft HQ last month for an AI Insider’s summit (I prefer not to use the term influencer), where we were given early access to GitHub Copilot CLI before the public release. The first thing we both did was dive into the system prompt to see what it contained. Every system prompt has “You are” buried in it somewhere, which makes it much easier to find that paging through 10k lines of JavaScript.

Use Xml tags in your prompts
----------------------------

Will posted the Copilot CLI’s system prompt, and one thing that stood out to me was the various XML-tagged sections, such as `&lt;tips_and_tricks&gt;` and `&lt;style&gt;`, which Anthropic has encouraged for years. They documented the technique in the [Use XML tags to structure your prompts](https://docs.claude.com/en/docs/build-with-claude/prompt-engineering/use-xml-tags) section of their docs.

Natural language prompts are becoming the universal programming interface
-------------------------------------------------------------------------

I have been experimenting with LLMs since the release of GPT-2. While I understand why it pains many developers to admit this, natural language prompts have become a language-agnostic way to program. Somebody could build the same app I’m building using Django with the same prompts in Laravel, Rails, or any other well-documented web framework and underlying programming language.

For many people who are new to development, this is more obvious:

&gt; Prompts are code.

Languages like Python aren’t going away, but it’s much easier and faster to develop when pairing with an LLM assistant who is always online and can instantly answer any questions that you might have.

The more I examine tools like GitHub Copilot CLI, the clearer it becomes: understanding how these tools prompt their models matters not just for curiosity’s sake, but because knowing how the prompt works helps you work better with the tool. Next time you’re using an AI coding assistant, use the “You are” trick to peek under the hood. You might be surprised by what you find.

Originally posted on: https://micro.webology.dev/2025/10/04/on-github-copilot-cli-and/</description><pubDate>Sun, 05 Oct 2025 01:57:19 +0000</pubDate><guid>http://example.com/posts/on-github-copilot-cli-and-prompts-as-code/</guid></item><item><title>⛔ I Do Not Want Discord's Nitro</title><link>http://example.com/posts/i-do-not-want-discord-s-nitro/</link><description>I do not want Discord’s Nitro.  
I do not want it, friend or foe.

I will not boost, I will not pay,  
I do not want it any day.

I do not want it on my phone,  
I do not want it when I’m alone.

I do not want it for more emoji,  
I do not want it—it feels too showy.

I will not take it on a stream,  
I will not buy it for a meme.

I do not want it, Sam-I-Post.  
Discord Nitro? Not even close.

---

Written by Jeff and ChatGPT. Edited with [Grammarly](https://grammarly.com) and [Claude Code](https://claude.ai/code).

Originally posted on: https://micro.webology.dev/2025/09/24/i-do-not-want-discords/</description><pubDate>Wed, 24 Sep 2025 23:20:24 +0000</pubDate><guid>http://example.com/posts/i-do-not-want-discord-s-nitro/</guid></item><item><title>My DjangoCon US 2025 Plans (and How to Find Me)</title><link>http://example.com/posts/my-djangocon-us-2025-plans-and-how-to-find-me/</link><description>I will be in Chicago this Saturday through next week for [DjangoCon US 2025](https://2025.djangocon.us) (September 8-12). I hope to see people there in person. If you can’t make it, please consider getting an [online ticket](https://ti.to/defna/djangocon-us-2025). They are relatively inexpensive, you get three full days out of them, and they help support the conference. More importantly, it helps support future conference events so we can continue to offer virtual attendance. It’s important that our online sales do well enough to help us cover our online costs and help fund our grants, along with our annual Django Software Foundation donation.

With an online ticket, you get to watch talks live and after the fact, probably a month before they come out on YouTube. You’ll have more interaction with people who are at the conference than you would get otherwise, plus the convenience of watching whenever you want. You can watch them live or on a time delay. You can join late, watch while we’re on breaks and at lunch, catch up, and join us in real time. Buying a ticket gives you the ability to watch whenever you want. If you are buying your own ticket, they’re $99. If your employer is buying you a ticket, it’s $199. So please buy a [virtual ticket](https://ti.to/defna/djangocon-us-2025) and enjoy over 50 excellent talks over three days. I’ll even be on a panel.

If you’re in Chicago and want to meet up at the conference, let me know. I will be around the venue all week and hope to sprint on some new and old projects, including work on [Django Packages](https://djangopackages.org). If you want to talk about the Django News projects I’ve been working on, like [Django News](https://django-news.com), [Django TV](https://djangotv.com), [Django News Jobs](http://jobs.django-news.com), and [Awesome Django](https://awesomedjango.org).

DjangoCon US has been a good excuse for me to launch a few projects over the years, including [Django News Jobs](http://jobs.django-news.com) two years ago and [Django TV](https://djangotv.com) last year. This year, I’m working on something too, and I’m probably going to release it sooner than I would typically do. I’m trying to figure out what would be a fun and useful project for the community. I’d love to talk to people about what that project is.

Topics I’d Love to Discuss at DjangoCon US
------------------------------------------

I really enjoy meeting new people whom I’ve met online, but I know that’s sometimes hard for people whom we have never met in person before. Conferences can be awkward and scary; we’ve all been there. Here’s a list of topics to help break the ice in case you find any of these interesting and want to talk more about them.

### Django Development

- Side projects and making them sustainable
- The deployment story for Django
- Better production defaults in Django
- Better ways to run a project and get projects up quickly
- Growing Django community projects to the next level

### AI and LLM Topics

- What MCP looks like for Django
- AI-driven development with Claude Code
- Projects built with LLMs (I’ve got several that are 99%+ AI-written)
- How AI can help with open source development

### Django Software Foundation &amp;amp; Sustainability

We just hired a Django fellow for the Django Software Foundation, and fundraising is really top of mind. As we’ve grown to have three fellows and an assistant, we need to make the fellowship program more sustainable and fundraise for an executive director who can help guide Django’s future. I’ve been on the board for less than a year, and it’s way more work than any of us expected. We have a very engaged board, but we need to make this more sustainable for the next board.

I’d love to talk about:

- How to make it more engaging for companies to support the DSF
- Making the fellowship program and Django community projects more sustainable
- Growing projects I’ve been working on with Will Vincent to provide more community value

New Django releases are great and help drive a lot of good, but I’d also love to see our side projects grow to that next level of sustainability.

How to Reach Me
---------------

Feel free to reach out to me - I’m on [Mastodon](https://mastodon.social/@webology), which is probably the best way to get a hold of me. I’ll also be on the conference Slack. I’ll be helping to organize a bit, but I hope to have plenty of time to talk to and meet people in person. I am definitely open and available if people want to connect and meet in person.

I’m also a partner and a consultant at [REVSYS](https://www.revsys.com) in Lawrence, Kansas. If you’re having company problems and you would like to talk to either me, [Frank Wiles](https://frankwiles.com), or one of my [colleagues](https://www.revsys.com/about/), we’d love to talk to you. You may be experiencing problems that we can help with, or your company is too busy, and you could use an extra set of hands. Or maybe you need some advice on how to get AI working with your company. We’ve done a lot of real-world projects for a while, and I’ve spent a couple of years with AI. I’m always happy to talk about that.

Originally posted on: https://micro.webology.dev/2025/09/03/my-djangocon-us-plans-and/</description><pubDate>Thu, 04 Sep 2025 02:03:11 +0000</pubDate><guid>http://example.com/posts/my-djangocon-us-2025-plans-and-how-to-find-me/</guid></item><item><title>🗓️ Office Hours for Late August</title><link>http://example.com/posts/office-hours-for-late-august/</link><description>I’m hosting office hours on the next two Fridays in August.

Office Hours Schedule
---------------------

- **[Friday, August 22, 2025, 2:30 pm to 4:30 pm CT](https://time.is/0230PM_22_August_2025_in_CT)**
- **[Friday, August 29, 2025, 2:30 pm to 4:30 pm CT](https://time.is/0230PM_29_August_2025_in_CT)**

Join Us
-------

These sessions are open to anyone, especially those working remotely who wants to connect with others. It’s a collaborative space for discussions, catch-ups, or just hanging out while you work.

While we have a bunch of Python and Django developers who regularly attend, anyone is welcome to join even if you don’t use either of these things.

Whether you’re a first-time attendee or a regular, you’re welcome to drop in anytime during the session. No need to stay for the full two hours, come and go as your schedule allows.

How to Join
-----------

The Zoom link is available in the gist from our previous sessions. Feel free to reach out if you need the details.

ℹ️ Meeting Guidelines
---------------------

🔕 Please mute when someone else is talking 👈 👍 Be respectful to other people and mute when not talking 👍 Be mindful of the spirit of the [Python Code of Conduct](https://policies.python.org/python.org/code-of-conduct/)👍 Be mindful and respectful of everyone’s time. 👍 Join because you want to work on something with a small group ⚠️ No marketing your product or service ⚠️ No meeting/recording bots. Humans are welcome. Meeting bots are not.

See you there!

Originally posted on: https://micro.webology.dev/2025/08/21/office-hours-for-late-august/</description><pubDate>Thu, 21 Aug 2025 23:54:44 +0000</pubDate><guid>http://example.com/posts/office-hours-for-late-august/</guid></item><item><title>Syncthing 2.0 Upgrade Notes</title><link>http://example.com/posts/syncthing-2-0-upgrade-notes/</link><description>[Syncthing 2.0](https://github.com/syncthing/syncthing/releases/tag/v2.0.0) was released last week, and I upgraded my Macs and my Intel NUC. I’m pleased with the performance. I never had complaints about it being slow, but the new app is much faster. I like that they’re using a SQLite database, which makes it easier to write hacks or tools to check the data.

Upgrading wasn’t terrible. I used [Homebrew](https://brew.sh) to upgrade it, which seemed to work initially, but I had problems with the service when I restarted it. I took the following steps: stopped Syncthing, removed it, reinstalled it, and then started the service. I’ve never managed to get a service to work correctly on macOS when I write them by hand, so I let Homebrew handle the services. It understands how to write the right templates and format, and gets it right. After running these commands, everything just worked:

&lt;div class="highlight"&gt;```shell
brew services stop syncthing  
brew remove syncthing  
brew install syncthing  
brew services start syncthing

```

&lt;/div&gt;One pro tip: once everything has stopped, you can run `syncthing` manually instead of invoking the service to see it migrate each folder to the new SQLite database format.

I had over 100 shared folders because I was treating each of my projects and client projects as their separate shares. I’ve recently changed that and have been migrating everything into my own “Projects” folder and keeping client stuff in a “Clients” folder. That way, everything separates. I have more control over what I have on my home or personal laptop versus what I have on my work computer. This makes a nice separation of work and home life.

I prefer Syncthing over other tools because it runs well even on ancient hardware. It works on every operating system—I mostly use macOS and Linux, but I’ve even run it on a Raspberry Pi. I’m currently running it across four or five systems, which makes file sharing seamless. The sync speed is excellent, I’m not locked into any services like Dropbox, and I don’t have to pay for features I don’t need. The usability and speed hit the sweet spot for me.

My only complaint about Syncthing is the CLI experience for adding folders. Even after years of using it, I haven’t figured out if it’s possible or if I’m just doing it wrong. Maybe this changed in 2.0, but most forum discussions suggest editing the raw XML configuration directly. I only spent a few minutes looking into the 2.0 CLI, and it hasn’t clicked yet.

---

Written by Jeff. Edited with [Grammarly](https://grammarly.com) and [Claude Code](https://claude.ai/code).

Originally posted on: https://micro.webology.dev/2025/08/13/syncthing-upgrade-notes/</description><pubDate>Thu, 14 Aug 2025 03:45:10 +0000</pubDate><guid>http://example.com/posts/syncthing-2-0-upgrade-notes/</guid></item><item><title>🤖 VibeOps: Using Claude Code on Cheap VPS Servers</title><link>http://example.com/posts/vibeops-using-claude-code-on-cheap-vps-servers/</link><description>Today I came across [Pieter Levels' post](https://x.com/levelsio/status/1953022273595506910) about “VibeOps,” a workflow that involves SSHing to a cheap VPS server and installing Claude Code directly on it. I’m running this setup on a cheap Hetzner box. While this approach might sound risky at first, when combined with a secure networking solution like [Tailscale](https://tailscale.com) and properly configured as a Tailnet, it becomes both safe and worth experimenting with.

I’ve also been exploring a complementary tool called [Vibe Tunnel](https://vibetunnel.sh), which integrates well with Tailscale and my existing Tailnet setup. It provides an elegant way to remotely create or connect to an existing Claude Code session from my browser. I like the idea of letting Claude handle some routine remote tasks.

Security is essential here. My Hetzner box uses their firewall product to block all ports except for SSL (443) and only allows me to access the box via Tailscale. If you aren’t using a firewall and a VPN product like Tailscale, you should not use a product like Vibe Tunnel to allow access to a running shell on your servers.

While trying to install Vibe Tunnel, I ran into a PAM error, so I did what anyone would do with Claude Code available on the server: I let Claude fix it for me. I thought Claude could figure it out, but after 5 to 10 minutes of noble efforts, I found [issue #499](https://github.com/amantus-ai/vibetunnel/issues/499) and [pull request #521](https://github.com/amantus-ai/vibetunnel/pull/521), which point to a bigger issue with a potential fix coming soon.

While I was on my server, I asked Claude to look at my Caddy setup for a bunch of parked domains, and it found some actionable changes and even fixed a few broken paths that weren’t obvious. This is exactly the kind of routine server maintenance where having Claude available directly on the server proves helpful.

I also had Claude check to see if the machine was out-of-date, and I watched it install a month’s worth of updates. Claude even wrote a nice summary for me to share in this post:

```
Analysis: The system is running a current Long Term Support release of Ubuntu with extended support until 2029. All installed packages are current with no pending updates available. No maintenance required at this time.

Action Taken: System audit only - no changes were made to the system.

```

All in all, I am a fan, even if I wouldn’t recommend this for any clients or just anyone.

Originally posted on: https://micro.webology.dev/2025/08/06/vibeops-using-claude-code-on/</description><pubDate>Thu, 07 Aug 2025 00:05:47 +0000</pubDate><guid>http://example.com/posts/vibeops-using-claude-code-on-cheap-vps-servers/</guid></item><item><title>Ditching Cloud APIs: How I Set Up Local Text-to-Speech with Kokoro TTS and Python</title><link>http://example.com/posts/ditching-cloud-apis-how-i-set-up-local-text-to-speech-with-kokoro-tts-and-python/</link><description>Today, I fired up the [Voices](https://github.com/nazdridoy/kokoro-tts) macOS app, which I occasionally use to convert blog posts or documentation text to audio files that I can take on the go. I usually use one of OpenAI’s Whisper APIs, but today I noticed there was a new option called Kokoro, which is a local voice model. I was interested in the model and tried out a few voices. Two or three of them were amazing for a local model.

After trying out a few blog posts and listening to them, I decided to find a Python version of the model. It might be slow to run, but at least I can create a pipeline to automate the process of generating voice files from arbitrary text files I have lying around.

That’s when I found the [Kokoro TTS](https://github.com/nazdridoy/kokoro-tts) application. I downloaded it and noticed that it needed a few things. Things like NumPy required to be installed, and a couple of things were out of sync, but the project mostly just worked. While it wasn’t quite as fast as a native Mac app, it was still good enough for me to run text files through it very quickly.

Tonight, I decided to write up my notes on how to bootstrap and run the project.

Installation
------------

&lt;div class="highlight"&gt;```shell
git clone https://github.com/style-bert-vits2/kokoro-tts.git

cd kokoro-tts

uv add numpy

uv sync

wget https://github.com/nazdridoy/kokoro-tts/releases/download/v1.0.0/voices-v1.0.bin

wget https://github.com/nazdridoy/kokoro-tts/releases/download/v1.0.0/kokoro-v1.0.onnx

```

&lt;/div&gt;Basic Usage
-----------

Once installed, you can use Kokoro TTS from the command line:

&lt;div class="highlight"&gt;```shell
echo &lt;span style="color:#e6db74"&gt;"Hello, this is a test of Kokoro TTS"&lt;/span&gt; | ./kokoro-tts /dev/stdin example-streaming.mp3 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;	--format mp3 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;	--voice af_heart

```

&lt;/div&gt;If you already have an existing text file:

&lt;div class="highlight"&gt;```shell
./kokoro-tts textfile.txt example-textfile.mp3 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;	--format mp3 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt;    --voice af_heart

```

&lt;/div&gt;Conclusion
----------

Kokoro TTS is a solid local text-to-speech option that runs entirely on your machine without requiring API calls or internet connectivity. While it may not be as fast as native Mac apps, the quality is impressive for a local model, and the ability to automate voice file creation from text files makes it valuable for anyone who wants to convert written content to audio format.

One major advantage I discovered is that unlike most cloud APIs like Whisper that limit posts to around 3000 characters, Kokoro didn’t seem to have an upper limit on any of the content I tried it with. This makes it particularly useful for longer blog posts and documentation.

The setup process is straightforward once you handle the missing dependencies, and the command-line interface makes it easy to integrate into existing workflows or automation scripts.

---

*Written by Jeff. Edited with [Grammarly](https://grammarly.com) and [Claude Code](https://claude.ai/code).*

Originally posted on: https://micro.webology.dev/2025/07/02/ditching-cloud-apis-how-i/</description><pubDate>Thu, 03 Jul 2025 00:06:57 +0000</pubDate><guid>http://example.com/posts/ditching-cloud-apis-how-i-set-up-local-text-to-speech-with-kokoro-tts-and-python/</guid></item><item><title>🤖 Building with AI: A Summer Reading Collection</title><link>http://example.com/posts/building-with-ai-a-summer-reading-collection/</link><description>I’ve been diving deep into AI-assisted development this summer, and I’ve collected some of the best articles I’ve found on the topic. This reading list focuses heavily on Claude Code and practical AI coding workflows, featuring insights from developers who are actively using these tools in their daily work. Whether you’re just getting started with AI coding assistants or looking to refine your approach, these articles are a good jump start. ## Claude Code ### [Claude Code is My Computer](https://steipete.me/posts/2025/claude-code-is-my-computer)Peter Steinberger describes using Claude Code with a dangerous permissions flag, transforming AI into a universal computer interface that can perform complex tasks, such as system migrations, content generation, and code management. By granting broad system access, he has found that Claude can automate numerous computing tasks, saving him significant time and operating at a fundamentally higher level of abstraction compared to traditional development tools. ### [How I Use Claude Code](https://spiess.dev/blog/how-i-use-claude-code)Philipp Spiess shares his experiences and strategies for effectively using Claude Code, an AI coding assistant that has transformed his programming workflow. He emphasizes techniques like starting new threads frequently, creating precise prompts, breaking complex tasks into smaller steps, and maintaining a balance between AI automation and human oversight to maximize productivity. ### [Basic Claude Code](https://harper.blog/2025/05/08/basic-claude-code/)Harper Reed discusses his workflow for using Claude Code, an AI coding assistant, which involves generating project specifications, using AI to create and implement prompts, and leveraging test-driven development (TDD) and pre-commit hooks. He emphasizes the importance of defensive coding practices like testing, linting, and creating project-specific configuration files to improve code quality and AI coding efficiency. Reed shares his team’s experience using Claude Code, noting increased test coverage and more effective development processes. ### [Field Notes From Shipping Real Code With Claude](https://diwank.space/field-notes-from-shipping-real-code-with-claude)The article explores how to effectively use AI, specifically Claude, in software development by establishing clear boundaries, documentation, and workflows. The author emphasizes that AI is a powerful tool for generating code, but human oversight, particularly in writing tests and maintaining code quality, remains crucial. The piece provides a comprehensive guide to vibe-coding, a collaborative approach where humans direct AI to enhance productivity while maintaining rigorous engineering standards. ### [My First Open Source AI Generated Library](https://lucumr.pocoo.org/2025/6/21/my-first-ai-library/)Armin Ronacher created a sloppy XML parsing library entirely using AI (specifically Claude), which generated around 1,100 lines of code, 1,000 lines of tests, and handled package configuration. The project was an experimental exploration of AI’s capabilities in software development, resulting in a functional library that solved his immediate technical need of parsing imperfect XML output from language models. ## AI Development Workflows ### [My LLM codegen workflow atm](https://harper.blog/2025/02/16/my-llm-codegen-workflow-atm/)Harper Reed describes a comprehensive workflow for using Large Language Models (LLMs) to generate code, which involves three main steps: idea honing, planning, and execution. The workflow can be applied to both greenfield (new) and existing code projects, utilizing tools like Claude and Aider to iteratively develop software with minimal manual intervention. Reed emphasizes the importance of careful planning, testing, and maintaining context to effectively leverage AI in software development. ### [An LLM Codegen Hero’s Journey](https://harper.blog/2025/04/17/an-llm-codegen-heros-journey/)Harper Reed describes a progressive journey of adopting AI-assisted coding, starting from basic autocomplete to increasingly sophisticated AI coding tools like Cursor and Aider. The article outlines a step-by-step evolution of using Large Language Models (LLMs) for code generation, emphasizing that developers should embrace the technology incrementally and be open to its potential, ultimately reaching a point where AI agents can handle significant coding tasks with minimal human intervention. ### [How I program with Agents](https://sketch.dev/blog/programming-with-agents)The article explores how Large Language Model (LLM) agents, defined as a for loop that contains an LLM call, can significantly improve programming by providing environmental feedback and tools like bash commands, web searching, and compiler interactions. The author argues that agents transform LLMs from whiteboard-style code generation into powerful programming assistants that can navigate codebases, fix errors, and complete tasks more efficiently despite current limitations in speed and cost. ## AI Industry Perspectives ### [AI Changes Everything](https://lucumr.pocoo.org/2025/6/4/changes/)Armin Ronacher explores the profound impact of AI on work, creativity, and society, describing how AI tools like Claude are transforming his programming workflow. He argues that AI represents a revolutionary technological shift comparable to electricity or the printing press, and encourages embracing this change with curiosity and optimism rather than fear, believing AI can dramatically increase human agency when used well. ### [Builder.ai did not “fake AI with 700 engineers”](https://blog.pragmaticengineer.com/builder-ai-did-not-fake-ai/)The viral claim that Builder.ai used 700 engineers to manually pretend to be an AI system was false. In reality, the company built a code generation platform called Natasha using AI models like GPT and Claude, with a small team of about 15 engineers. The company collapsed due to alleged accounting fraud and misrepresentation of revenue to investors, not because of a fake AI scheme. ## The Future Is Now (And It’s Iterative) What strikes me most about these articles is how quickly we’ve moved from “Can AI write code?” to “How do I optimize my AI coding workflow?” The common thread isn’t just about technology getting better but about developers becoming smarter about how they collaborate with AI. Whether it’s Harper’s methodical approach, Armin’s experimental libraries, or Peter’s all-in computer replacement strategy, AI coding is changing how we develop applications.

Originally posted on: https://micro.webology.dev/2025/06/25/building-with-ai-a-summer/</description><pubDate>Thu, 26 Jun 2025 01:38:11 +0000</pubDate><guid>http://example.com/posts/building-with-ai-a-summer-reading-collection/</guid></item><item><title>🗓️ Office Hours for June</title><link>http://example.com/posts/office-hours-for-june/</link><description>I’m hosting a regular afternoon edition **tomorrow (Friday, May 30)** to wrap up the month of May.

After that, I’ll be away on vacation, so I’m skipping the first **two** Fridays in June and the first Friday in July.

Here’s the plan:

- **Friday, June 6, 2025:** No office hours (vacation)
- **Friday, June 13, 2025:** No office hours (vacation)
- **Friday, June 20, 2025, 2:30 pm – 4:30 pm** ([Time.is link for CT](https://time.is/0230PM_20_June_2025_in_CT))
- **Friday, June 27, 2025, 2:30 pm – 4:30 pm** ([Time.is link for CT](https://time.is/0230PM_27_June_2025_in_CT))
- **Friday, July 4, 2025:** No office hours (US Holiday)

High‑level details
------------------

ℹ️ **Anyone** is welcome to join office hours. Many join because they work remotely, miss seeing faces, and enjoy the spontaneous conversations that occur when a small group gathers.

ℹ️ It’s a collaborative space where we discuss ongoing projects, catch up, and finish the week on a productive note.

🙏 Everyone is welcome, whether you’re a regular or it’s your first time. If you’re curious, reach out.

✅ Need more details? Send me a message or check the gist from previous sessions, where you’ll always find the most recent Zoom link ⚠️

Originally posted on: https://micro.webology.dev/2025/05/29/office-hours-for-june/</description><pubDate>Thu, 29 May 2025 14:18:30 +0000</pubDate><guid>http://example.com/posts/office-hours-for-june/</guid></item></channel></rss>