Skip to content
Brad Johnson, home
All projectsSoftware / 02 of 20

Lan

My personal agent on Pi Durable, with a second model reviewing what it does and native apps on iPhone and Mac.

Category
Software
Updated
2026-11-06
Status
Running on the homelab since November 3
Built with
TypeScript, Node.js, Pi Durable, SQLite, bubblewrap, Swift, SwiftUI, Tailscale
The Lan Mac app: a sidebar of today's threads and pages for reminders, jobs, notes, skills, timeline and archived threads, and a thread where Lan explains why plain integer IDs are fine for Brad's ideas list and offers to switch to an I-14 style.
A real thread in the Mac app, with other thread titles and the server address blurred.

Lan replaced gaidin on November 3, 2026. I ported it from gaidin a module at a time and kept what I used: durable runs that pick up where they stopped after a crash or restart, reminders, scheduled jobs, notes about me in every prompt, search over past conversations, remote MCP connectors, skills, my own allow and ask rules, and SSH into folders on my other machines. I dropped the roster of five agents, which in practice never messaged each other or handed work on, along with Slack and the web app.

Calls that need a decision go to a reviewer, a second model (Sonnet by default) that allows the call, blocks it with a reason or asks me. It sees my messages and the call, never the outside text the agent read, and after three blocks in one run it asks me instead. Some limits hold whatever the reviewer says. Commands run in a bubblewrap sandbox with no network where only Lan’s own folder is writable. Fetching a page is GET-only and refused for private, LAN and tailnet addresses. Credentials are redacted from tool output before it’s stored, spending has daily and monthly limits, and a connector tool set to ask always comes to me.

Jobs like briefings, watches and follow-ups can each name their own model and tools. A job can have a gate, a check the server runs before the job with no model involved, so a job can check every 15 minutes and cost nothing when there’s nothing new. One job sweeps my inbox through eyes-and-ears with only five mail tools, and the first sweep archived 9 messages for about two cents.

It runs on its own VM with no inbound ports. Its API is reachable through tailscale serve and admits only my Tailscale login. I talk to it from the lan command and from SwiftUI apps on iPhone and Mac, which share one core package. Notices arrive through Apple’s push service, and their Allow, Deny, Snooze and Reply actions need Face ID.

In the Wheel of Time, Lan is a Warder (a gaidin), bonded to Moiraine.

Next project, 03loial