I'm an embedded software engineer at Johnson & Johnson MedTech, where I
work on the Automated Impella Controller, the console that drives the Impella
CP, RP and 5.5 heart pumps.
Most of my day is C and C++ on QNX, and the split is roughly 50% documentation,
30% debugging, and 20% designing new features. The documentation share tends to
surprise people, but on a regulated medical device it is most of the job. If it
isn't documented, it didn't happen.
Outside of work I mostly tinker, and it has grown well past what I originally
intended. The small things are unchanged: a mod when something in a game bothers
me, a Python script to scratch one specific itch. But the home server I started
has become the largest thing I have built, and I am partway through teaching
myself Godot and shaders properly.
Not all of it is software. I make things with my hands too, including a jester
costume for the Renaissance Faire. A lot of this is still me learning as I
go.
Principal Embedded Software EngineerMar 2026 - Present
Senior Embedded Software EngineerJun 2024 - Mar 2026
Embedded Software Engineer IIDec 2022 - Jun 2024
The same role continuing, after the acquisition.
Before this came Abiomed, where I worked from 2018. Johnson &
Johnson completed its acquisition of Abiomed on 22 December 2022, but I had already
been promoted to Engineer II six months earlier, so the role simply carried across
the change of ownership.
Abiomed2018 - 2022
Danvers, Massachusetts · On-site
Embedded Software Engineer IIJun 2022 - Dec 2022
Promoted here, then continued under J&J.
Embedded Software Engineer IMay 2021 - May 2022
Joined full time after graduating.
Software Engineer Co-opJan 2020 - Aug 2020
Software Engineer Co-opJan 2019 - Aug 2019
Software Engineer Co-opJan 2018 - Aug 2018
Education
Northeastern University2016 - 2021
Bachelor of Science, Computer Science
Great Bay Community College2014 - 2016
via Seacoast School of Technology
Selected coursework
Computer Science: Algorithms and Data Structures, Computer Systems,
Programming Languages, Compilers, Object Oriented Design, Database Design, Discrete
Structures, Introduction to Computer Science Research. Networks and Distributed Systems (CS 3700). Mathematics: Linear Algebra, Calculus I. Other: Genetics and Molecular Biology, Organic Chemistry I and II.
Skills
chip familiarchip still learningchip unfortunately familiar
Daily
CC++PythonBashPowerShellGitVS Code
Git means the CLI, deliberately. A GUI hides which
commands it is running and when; I would rather see them.
Occasionally
C#
Mostly game modding, plus two tools from work. One is
hatchet, a CLI I wrote and released internally at Abiomed. It converts
binary log files into informationally complete JSON that can be converted
back, offers deliberately lossy exports to Excel or streamed JSON, and can
either interpolate the logged signal data or just survey a file to see what
it contains before committing to anything. The other was a Xamarin Forms
simulator tool that deployed to Windows and iOS.
Coursework, rarely now
JavaSQL
Previously
Elixir
Used while I was at Abiomed, before Johnson & Johnson
acquired it. Not something I have touched since.
Learning
RustF#HaskellBlenderGIMP
Rust and F# are things I want to get properly good at
rather than things I would claim today. Haskell was one course, but it is
where I first understood what composable functions actually buy you.
Editors, past and present
NeovimVimEclipseJetBrains
All of these have largely given way to VS Code, but I
have spent real time in each.
Embedded
QNXPOSIXI2CGNU MakeCMake
POSIX message queues and shared memory, plus some I2C.
I am happy to leave CMake to other people. It is GNU Make
with extra steps, worse documentation, and several more ways to get it wrong.
Security
AES-GCMTLSOpenSSL
Including a handshake I wrote from scratch in C using the
OpenSSL library, in order to talk to a device over USB.
Game development
GodotSlangGLSLBlender
The core shader is written in Slang, which transpiles
it to GLSL. A small Python script of mine then rewrites that GLSL into
gdshader, since the two syntaxes are close enough that it is not much of a
job. Writing in Slang means the same shader can also compile to C++ and run
on the CPU, which is how I debug and unit test it. GLSL I mostly read rather
than write, and Blender is still early days.
Building the tooling around models rather than training
them. OWUI plugins covers functions, tools and pipes. Day to day I use
DeepSeek V4.1 Flash: strong enough to trust with agentic work, and cheap
enough that I do not think about the bill. I have also got models running
locally on llama.cpp with Qwen, which worked, but not yet at a standard I
could rely on. I would like to come back to that.
Platforms
WindowsLinuxWSLiOSmacOSAndroid
I have deployed an app to iOS, but I would not call
myself an iOS developer. It was a Xamarin Forms simulator tool that also
targeted Windows, and the iOS side needed a Mac purely because Xcode
insists on Apple hardware. Building for iOS is considerably more awkward
than building for Android, which is most of the reason the mobile work
sits under learning rather than under things I do. I have used Android
too, out of curiosity more than necessity.
Vintage Story modding
A handful of small mods for
Vintage Story, written because something
in the game was bothering me. They are deliberately unambitious: each one fixes a
single irritation and does nothing else.
Download counts below are read from the mod
database, so they are current rather than whatever they said on the day I wrote
this.
Source for all
of these is in vintage-story-mods on
GitHub.
Learning shaders
I have been teaching myself Godot, and shaders in particular.
Everything you can see in these screenshots is shader work rather than texture
work, which is the part I am pleased with.
There are three shaders. The water surface has its own, which drives the waves.
The robot has its own. Both are ordinary Godot shaders, written in gdshader.
The third is the interesting one. A large core shader governs how almost
everything else appears, including the transition from above to below the water
and the caustics underneath it. It navigates a sparse octree and implements a ray
marching traversal over that structure, which is how it stays fast enough to be
worth doing at all.
That shader is written in Slang rather
than gdshader. Slang itself transpiles it to GLSL, and a small Python script of
mine then rewrites that GLSL into gdshader, which is a modest job since the two
syntaxes are similar. The reason for going the long way round is testing.
Slang will also compile the same shader to C++ and run it on the CPU, which means
I can step through the traversal, inspect the octree, and unit test the whole
thing, instead of inferring what went wrong from the picture on screen. I would
not want to debug a sparse octree traversal any other way.
The terrain itself is procedurally generated and streamed in chunks, loading and
unloading around the player as you move. I wrote that part in C++ after the
GDScript version proved too slow to keep up.
The grey cubes are a buoyancy test. They float, and rise and fall with the swell
of the waves rather than sitting at a fixed height.
From above. The waves are the water surface shader; the cubes are
riding them.The same water from underneath. Switching between the two views is
the core shader's job, as are the caustics below the surface.
Writing the traversal in Slang also meant I ran into a
genuine miscompilation in it. Reading an array element with an index, then changing
that index on the next line, made the compiler reorder the read to after the change
and return the wrong element. It showed up in my octree traversal stack, of all
places. I reported it with a minimal reproduction and it was confirmed and
triaged: slang
issue #13273.
Renaissance Faire costume
A jester costume for the New York Renaissance Faire, made from
scratch. Not software, but the most satisfying thing I have built with my hands.
My friend Ashley and I learned together while her mum, Lisa, taught us. We started
at the basics and worked up: threading and running a sewing machine, how to rip a
seam without ruining the fabric, how to use bopkins to thread elastic, and how to
read costume patterns, which are written in a dialect of their own. The trousers
came from a pattern and taught me why that dialect exists.
Some of it we simply winged, and those parts are the ones I am fondest of: the
hat, the collar, and the cross-shoulder bag.
Outside the gates at the New York Renaissance Faire.Closer up, where the panelling, the sleeves and the shoe covers
show properly.
Credit where it is due. Lisa taught us both, and made the vest.
Ashley made the shoe covers, and learned alongside me through all of it. I made
the trousers, the hat, the collar and the bag.
Theseus
The machine this page is served from. It started as a way to stop
paying for cloud storage, and has turned into the largest thing I have built:
a server that holds my photos, films, music, files and code, and runs a
language model on the side.
It is named Theseus because the original plan was to replace bits of it over
time until nothing original remained.
NVIDIA RTX 3090, 24GB
For running models locally. Capped at 280W from a 390W
default, which saves about 110W for no measurable loss of speed.
Integrated GPU
Intel UHD 770
Normally idle. Used for Quick Sync hardware transcoding,
so several people can stream at once without touching the CPU.
Memory
64GB DDR5
Fast storage
4TB NVMe SSD
Docker volumes and model files, where seek times
actually matter.
Bulk storage
4 x 12TB HDD in a btrfs RAID1 pool, 22TB usable
Described below.
Power
1000W 80+ Platinum PSU
Storage, and how it grows
The bulk storage is a btrfs pool called tank, running in RAID1. It
began as two 12TB drives, which gave about 11TB of usable, fully mirrored
space.
In September 2026 I added a second pair of 12TB drives and the pool grew to 22TB.
That operation is the reason I chose btrfs. RAID1 in btrfs mirrors at the block
level rather than tying one disk to another, so drives can be added while the
pool stays online: no restoring 11TB from a backup, no downtime, and redundancy
maintained the whole way through. With this much media, the alternative was
going to be painful.
A few things I learned along the way. Copy-on-write is switched off on the large
video files individually, since rewriting whole multi-gigabyte files on every
read is pure overhead. The filesystem mounts with noatime, so
reading a frame does not trigger a timestamp write. And a scrub runs once a
month, reading back every block and checking it against its checksum, which is
how bit rot gets caught before it reaches a film you actually wanted to watch.
What runs on it
Several dozen
containers, most of them behind Docker Compose. The ones worth naming:
Immich
Photo and video backup for our phones. The one that
finally got me off a cloud subscription.
Nextcloud
Files, calendar, contacts and documents, with
ONLYOFFICE behind it for editing in the browser.
Jellyfin
Films, television and music. Transcodes on the
integrated GPU, since not every client can play everything.
jfa-go
Creates time limited Jellyfin invites, so I can let
someone in without handing them an account.
Minecraft
A modded Prominence II server for friends. A
surprising amount of memory tuning for a game.
Open WebUI
The front end I use for hosted models and the one
running locally on the GPU.
GitLab
Git and CI on my own hardware, so nothing I write
depends on somebody else staying in business.
GameVault
A server for my games, with a desktop client, so it
behaves like a private store.
SnappyMail
Webmail, so I can read my email from anywhere without
installing a client.
Beszel
Graphs for CPU, memory, disk and network, plus SMART
health on the drives.
Uptime Kuma
Watches each service and tells me when one of them
stops answering.
Dockge
Compose stack manager, so a stack is a folder and a
file rather than a set of flags to remember.
🔍Bangs
A small redirector I wrote for browser search
shortcuts. One Python file.
All of it is
reached through a Cloudflare Tunnel with identity checks in front, so nothing is
exposed directly.
How one person manages all of this
A fair question, and the honest answer is that I do not manage it
alone. Theseus runs nearly fifty services and I could not keep up with them by
myself. A great deal of the work is done with AI assistance, and the way that is
organised is the actual engineering.
Every application or feature on the server has its own dedicated AI chat. When
something needs doing I go back to that same chat, which by then holds the full
development history of that one thing. It starts with complete context and does
not need re-briefing.
Everything is version controlled, so I can review any change at the command line
and see exactly what was touched and why. The amount of accumulated context is
what makes the assistants genuinely capable, to the point that I can ask for a new
service to be deployed and have it stood up and wired in without me intervening.
That is a deliberate strategy rather than something I stumbled into.
The
roster, roughly in order of seniority:
😎 MarkOversees the server as a whole. Sets the tone and the
standard operating procedures the rest work to.
🔗 LarryMaintains this page. Also covers the landing page
at glarkham.com.
🔖 GerryGitLab, and provisions credentials for new AI
chats so every commit is correctly signed and attributable.
📥 WestonOpen WebUI itself. Runs a separate development
instance so upgrades are tested before they touch production.
🎙️ BrendaThe inter-AI communication tool, an Open WebUI
plugin I have them talk to each other through.
⚡ DashOpen-terminal tooling, my own replacement for the
default integration, which was not up to much.
🐋 WaldoThe DeepSeek API pipe for Open WebUI.
🐞 BuggyThe Claude API pipe for Open WebUI.
🐳 IvanImmich, the photo and video library.
🪼 JenniferJellyfin, the media server.
🎮 SteveMinecraft, the modded server for friends.
👾 ApolloThe Godot and Slang learning from the previous
section. I do not get to claim all of that as unaided.
🐳 WillowA second open-terminal instance on Merlyn, my
Windows desktop. A separate machine from Theseus entirely.
There are
around twenty more beyond this list. Being able to hand a distinct, well-scoped
piece of infrastructure to a distinct assistant, with its own history and its own
accountability, is what makes a server this size tractable.