This section of my site is focused on small pieces of content that I want to share with you all about either ideas I have to things I see on the internet.
enjoy!
State Machines
State machines to visualize the work of agents — LLM agent determinism through state machines
State machines are great, but hard to establish — team adoption challenges
Modeling resizable panels using State Machines — UI state machine example
Notes about how the document machine should work — document lifecycle as state machine
How to Background Agents — background agents made observable and predictable through state machine patterns
See the State Machines — Knowledge Map for the full cluster across accounts.
AI & Agent Workflows
Vibe code like a PRO — Linear→background agent→PR pipeline concept
How to Background Agents — practical Cursor background agent setup
How I Built a Full Booking System as a Side Project — With Devin as My Engineering Partner — real-world case study validating the Linear→background agent→PR pipeline with 6 merged PRs on a production system
Me uno al programa de Devin Ambassadors — Devin Ambassadors program announcement; the public commitment behind the case study (Spanish-language Devin content, Barcelona meetups)
Web & Hypermedia
Remodeling the web — critique of the current state of the internet, with links to Seed Hypermedia's architectural response (7 See Also links across 4 accounts)
What I want for the commenting experience to be — web UX fixes for commenting, including eliminating redirect-based flows
All Posts
Jean Web Access behind Tailscale — self-hosting a tailnet-exposed AI server: Tailscale Serve vs direct IP
Great product features in the wild: Canva Pause Subscription — UX-pattern observation that seeded a cross-account feature request and a product backlog/content pipeline (see its See Also section)
<!-- embed: hm://z6Mkvz9TgGtv9zsGsdrksfNk1ajbFancgHREJEz3Y2HsAVdk/short-posts/jean-web-access-behind-tailscale; title: Jean Web Access behind Tailscale -->
If Jean Web Access works in a browser but the native Jean app, phone, or another tailnet device cannot connect, check whether Jean is being reached directly over HTTP or through Tailscale Serve. <!-- id:Za7Acojm -->
Recommended setup
Use Tailscale Serve as the tailnet entrypoint and bind jean-server to localhost:
# /etc/jean-server.env
JEAN_HOST=127.0.0.1
JEAN_PORT=3456
JEAN_TOKEN=<long-random-token>
JEAN_ALLOWED_ORIGINS=*Restart Jean and publish it through Tailscale Serve:
sudo systemctl restart jean-server.service
sudo tailscale serve --https=443 off
sudo tailscale serve --bg http://127.0.0.1:3456
tailscale serve statusUse the HTTPS Tailscale Serve URL everywhere, including phones and the native Jean desktop app:
https://<machine-name>.<tailnet-name>.ts.net/?token=<JEAN_TOKEN> <machine-name> is the device name in Tailscale. You can choose any name you want in Tailscale (for example, jean-server, build-box, or home-lab) and use that name in the URL.
For example, if you named the device jean-server in Tailscale:
https://jean-server.tail71152.ts.net/?token=<JEAN_TOKEN>Why the direct Tailscale IP may stop working
When JEAN_HOST=127.0.0.1, Jean only listens on the server itself. That is intentional for the recommended Tailscale Serve setup. Other tailnet devices cannot connect directly to:
http://100.x.y.z:3456They must use the Tailscale Serve HTTPS URL instead. Tailscale Serve receives the tailnet HTTPS request and proxies it locally to http://127.0.0.1:3456 on the server.
Quick checks
From any tailnet device, these should return 200 OK:
curl -i https://<machine-name>.<tailnet-name>.ts.net/readyz
curl -i 'https://<machine-name>.<tailnet-name>.ts.net/api/auth?token=<JEAN_TOKEN>' Expected /readyz body:
{"http":true,"ok":true,"websocket_broadcaster":true}If the HTTPS URL returns a proxy error, confirm jean-server is listening on 127.0.0.1:3456 and restart Tailscale Serve.
Is this a Jean issue?
This is mostly a deployment/configuration gotcha for Jean servers behind a tailnet, not a core Jean server bug. The confusing part is that there are two valid modes:
Tailscale Serve mode (recommended): JEAN_HOST=127.0.0.1, connect with https://...ts.net/?token=....
Direct tailnet HTTP mode: JEAN_HOST=100.x.y.z or 0.0.0.0, connect with http://100.x.y.z:3456/?token=....
The modes are easy to mix up. If Jean binds to localhost, direct Tailscale IP access will fail. If Jean binds to the Tailscale IP, Tailscale Serve must proxy to that IP instead of 127.0.0.1, or it will fail.
<!-- /embed: hm://z6Mkvz9TgGtv9zsGsdrksfNk1ajbFancgHREJEz3Y2HsAVdk/short-posts/jean-web-access-behind-tailscale -->
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime