About
I build systems so I can build tools. I can't build a good tool without first understanding the problem it models.
What I build
I have an intolerance for half-measures. A Go TUI for a productivity system I actually use; a Tauri desktop app where the real problem was making XSD validation semantically aware rather than structural; a Neo4j-backed fiction engine where the relationships between characters are the data model.
In fac-cra, I turned a blunt approval queue into a set of configurable segments with their own independent logic. In Workwise, I replaced a tangle of loading booleans with a discriminated-union state machine.
How I work
I was a theatre director. I wrote a book on interactive theatre ("Creating Worlds", Nick Hern Books, 2017), and ran courses at drama schools. During lockdown I started learning ink, Inkle's scripting language for interactive narrative, and kept going from there.
Left to my own devices, I take things further than anyone asked. Iris is built on a single TypeScript core driving three completely different interfaces: an OpenTUI terminal UI, direct CLI commands, and a Tauri desktop app in Rust. Wyrd has its own Cypher-subset parser and a binary merge driver for conflict resolution, because I wanted a proper graph query language over JSON files rather than a workaround. This portfolio tracks itself through a bespoke git-metrics CLI with a typed JSON Schema contract, because I have ADHD and it is genuinely easier for me to build the infrastructure to automate the maintenance than to do the maintenance.
On team projects I tend to land between architecture and delivery.
The toolkit
TypeScript for anything where state needs to be modelled explicitly: discriminated unions, exhaustive type narrowing, no runtime surprises from a function that lies about what it returns. Go when the output should be a binary. Svelte 5 with runes on the frontend; PostgreSQL when the relationships are incidental, Neo4j when they are the model. I have written enough Rust to ship a Tauri desktop app and know when to stop.