← J. Jaime Aleman

What I use

Minimal, lean, fast. I don't rice my setup any more — it does what it needs to and gets out of the way. Everything here is what's running right now, not an aspirational list.

4:46 PM in El Paso

A moderately active hour for me. Could go either way.

This hour accounts for 5.5% of everything I've logged — ranked #8 of 24. Overall, 48.4% of my work happens between 6pm and 2am — and only 2.3% between 3am and 8am.

The machine

OS
Arch Linux x86_64 15+ years on Linux. Yes, btw.
Kernel
7.0.14-arch1-1
Machine
Lenovo ThinkCentre M75s Gen 2 Small-form desktop, not a laptop
CPU
AMD Ryzen 7 PRO 5750G — 16 threads @ 4.67 GHz
GPU
AMD Radeon Vega (integrated) No discrete card. Doesn't need one.
Memory
62 GiB Sits around 52% — agents are hungry
Disk
931 GiB on btrfs 13% used
Uptime
41 days tmux never dies

The desktop

The compositor is the part people ask about. niri is scrollable tiling — windows sit on an infinite horizontal strip rather than subdividing a fixed screen. Across three monitors it means I never arrange anything; I just scroll to it.

Compositor
niri 26.04 (Wayland) Scrollable tiling. Windows live on an infinite horizontal strip instead of fighting over one screen.
Displays
Triple — 2× 27" 1080p + 16" portable
Terminal
kitty 0.48.2
Terminal font
CaskaydiaCove Nerd Font Mono, 9pt
Shell
zsh 5.9.2
Theme
Breeze Dark, Noto Sans 10pt
Packages
1,203 pacman · 6 flatpak

The stack

Two frameworks, picked by shape rather than habit. Astro for anything that's mostly content — it ships no JavaScript unless a component earns it. Nuxt when the thing is genuinely an app. Everything lands on Cloudflare either way.

Content sites
Astro 7 Ships zero JS by default. Islands only where something actually moves.
Apps
Nuxt 4 When the thing is app-shaped — auth, state, real routing — Astro stops being the right tool.
UI
Vue 3 + VueUse Islands, not an SPA. The page stays HTML until it needs not to be.
Components
Nuxt UI Nuxt side only. Astro doesn't get a component library.
Styling
Tailwind 4 Astro side, via the Vite plugin. No config file until there's a reason for one.
Hosting
Cloudflare Workers wrangler deploy from the terminal. No CI, no build minutes, no dashboard.
Data
D1 · KV · R2 Direct bindings. Nothing wrapping the platform that can be sunset out from under me.
Memory
PostgreSQL + pgvector Local, in Docker. Months of prior work, searchable.
Server
Hetzner For the things that need to be a real box.
Language
TypeScript pnpm everywhere.

How it fits together

kitty + tmux, always running

One tmux session per project, running for weeks. A dedicated pane for the dev server, one for lazygit, one for Claude Code. Nothing is ever 'started up' — it's already there.

lazygit in its own pane

Every commit, branch, merge and push happens here. Claude Code is not allowed to push or merge; I do that, deliberately, looking at the diff.

Claude Code as the primary editor

Neovim when I want to hand-edit. But most changes now start as a conversation in the terminal and end as a reviewed diff in lazygit.

wrangler deploy, no CI

Most projects this year ship straight from the terminal. My GitHub contribution graph looks empty because the work stopped going through git push.

Where the rules came from

I use AI on almost everything I build. I don't let it make the calls. I orchestrate — I read, I decide, I guide, and when I get it wrong we work the problem together. What follows is the part that usually goes unpublished: four times something was wrong, and what changed so it couldn't happen the same way twice. Every one is a real commit in this site's history.

The site said I work at 6am

The stats pipeline buckets hours in UTC. Read straight, it produced a confident, specific, completely wrong claim: peak hour 6am, 35.9% of the work between midnight and 6am.

I caught it in seconds, because I am asleep at 6am. No test would have — the number was internally consistent, just measured in the wrong timezone. Now every time figure is converted to Mountain before it reaches the page.

A dev deploy went to the live domain

The Astro adapter resolves the Cloudflare config at build time. Build without the dev flag and `--env dev` is silently ignored — so a development deploy shipped straight to production.

A script now reads the resolved config and refuses to deploy unless the hostname matches the environment I asked for. The rule stopped depending on me remembering.

My personal inbox was in the HTML

The site published my actual Gmail as a plain mailto: — exactly the string address harvesters scan for.

It now publishes a forwarding alias, base64-encoded at build time and decoded only on click. If the alias is ever harvested, I burn it and the real inbox is untouched. Obfuscation can be defeated; a disposable address cannot.

This page listed a tool I'd stopped using

The stack section below was drafted with PrimeVue on it. I retired that skill months ago. The agent had no way to know — the reason lived in my head, not in a file.

I caught it in review, the same way I catch everything else: by reading before shipping. It is now written down, so the next session starts correct instead of being corrected.

The rules that make it work

The tools are ordinary. This part isn't.

Branch-aware permissions

Feature branches are autonomous — agents commit freely. main and develop are locked: no commit without me saying so. The rule lives in a file, not in my head, so it applies every session without being restated.

Never push, never merge

Agents can do almost anything except move code between branches or off the machine. That single boundary makes autonomy safe.

Written rules over prompting harder

Every correction I'd otherwise repeat becomes a line in CLAUDE.md. Prompting harder scales linearly with effort. Written rules scale with zero.

Persistent memory

A local PostgreSQL database with vector embeddings means the agent can search months of prior work instead of guessing.

Build d3f5416 ·