Developer Tooling
Internal tools built to remove friction from daily engineering work.
These are three tools I built for myself rather than for a user: a command-line suite for the daily admin of a working day, a self-hosted ticket tracker an AI agent can address directly, and a governor that paces spending across two AI coding budgets. None of them is a product. Each one exists because a chore repeated often enough to be worth deleting.
The through-line is the order of operations. In every case the measurement came first and the automation second: the tool started by reporting a number I was guessing at — hours logged against target, tickets actually open, budget burned this window — and only once the number was visible did it become obvious what deserved automating. Instrument, then automate. Building it the other way round produces automation that optimises the wrong thing.
All three are private, and all three are in daily use. That second fact is the only success measure I trust for a personal tool: not that it was built, but that I still run it months later without thinking about it.
The command-line suite is Python, spread across a dozen modules behind six entry points that are symlinked onto the PATH. Each command owns one system and shares nothing but a config file, so a change to attendance cannot break time logging. The snapshot command is the only one that reads across all of them, and it degrades to a partial report rather than failing when one upstream is unreachable.
The tracker side is two pieces. The tracker itself runs as a systemd service on the same machine that does the work, so there is no network hop and no hosted account to expire. In front of it sits a Model Context Protocol server in TypeScript, with schema validation on every tool it exposes, which is what lets an agent address a ticket by number and get a typed answer instead of scraping a page.
The pacing governor is Bash on purpose: it has to run from a shell hook on every prompt, so process startup cost is the binding constraint and a runtime would have been the wrong trade. It is built as separate quota probes per provider, a scoring script that turns those readings into one policy decision, actuators that act on it, a work queue drained whenever an engine goes idle, and per-job telemetry. Its model choices are pinned from measured comparisons rather than reputation, and the measurements are kept in the repository next to the pins so a stale pin is visible.
All three repositories are private, so there is nothing to link here. That is a deliberate consequence of what they are: they hold configuration and workflow details for real work, and none of that belongs in public. What is shown above is the architecture, not the source.