A small studio and personal playground. A place for ideas that don't need permission. Design, AI, and engineering experiments that move fast and feel human.

My agents kept stopping. I'd walk away from my laptop, even while docked, and macOS would put it to sleep. I couldn't kick off a long run and go do something else.
So I built latte. A CLI that wraps caffeinate so you never have to remember
the flags. latte on, latte 2h,
latte off. It has an interactive TUI dashboard with live
countdown timers, and works just as well piped into scripts.
Built with Bun, Effect TS, and Ink. Stateless, scriptable, and friendly to both humans and AI agents.

I use git worktrees a lot. Parallel branches, clean separations, no stashing.
But the built-in commands are rough. Creating a worktree means remembering paths, manually symlinking node_modules, copying .env files every time.
So I built wt. A CLI that handles the full worktree lifecycle for you.
It auto-symlinks dependencies, runs hooks from a .wt.toml config, and has an interactive TUI with vim keybindings for navigating and removing worktrees.
Built with Bun, Effect TS, and Ink. Works for both humans and AI agents.

I was in New York using ChatGPT constantly. Asking about places I saw, getting feedback, learning on the go.
I noticed I kept switching models. 4.1 for quick answers. 4o mini for balanced thinking. o3 for long, reflective chats.
That friction sparked Ren.
A chat app that auto routes for you, choosing the right model based on intent, speed, and context.
It uses a vector database for context recall, falls back to an LLM when needed, and defaults to speed when nothing else fits.
The idea behind Ready came from a simple belief I've held for years. Software should never make you wait.
That lesson stuck with me from my startup days and from studying Linear's design philosophy.
When I started working, I tried to spread that same idea, but building it by hand was brutally hard.
So I used React Query's persist layer as a shortcut and built a demo to show what it feels like when everything is already loaded.
I've always believed great software comes from caring about every detail. The UX, the feel, the small touches that make it human.
At some point, I realized everything I build comes from that same belief. I’m a design engineer at heart.
A to-do list. The classic starter project, rebuilt nearly a decade into web development.
Hotkeys for everything. Vim mode. Relative numbers. Animations where they make sense.
Local data handling. Hidden achievements for fun. Even a rough attempt at liquid glass like Apple’s new effects.
Crude in the best way, but made with care.
one.sf.engineering →I came across an app called freewrite by Farza. It was simple, clever, and fun to use, especially the part where it sent your writing to ChatGPT to talk about it.
No servers. No cloud. Your writing lives in your browser, where it should.
And because I like desktop apps, I wrapped it in Tauri too.
write.sf.engineering →I just wanted to work with server components, and the best way to learn is to build something real.
So I built another CRM. I've built three before, so why not one more, this time for personal use.
Super fast, all server components. Mostly an experiment to show that client and server can mix beautifully when done right.
Probably never finished, but I like it that way.
I started using Dia, a browser with built-in search routing. Sometimes it used Google, sometimes AI chat with GPT 4.1.
That got me thinking about building my own version that routed searches the way I would.
Loosely inspired by Theo's Unduck project, I built a custom search engine that decides where your query should go.
It looks at keywords, regex, and semantics to route between models with web tools or straight to Google.
It was tuned to my own preferences and never really deployed, mostly because ChatGPT's web search became good enough.