Illustrated portrait of Grahm Larkham

Grahm Larkham

Embedded Software Engineer
Greater Boston, Massachusetts

Here to help 😊

About

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.

Contents

Experience

Johnson & Johnson MedTech 2022 - Present
Danvers, Massachusetts · On-site · formerly Abiomed
Principal Embedded Software Engineer Mar 2026 - Present
Senior Embedded Software Engineer Jun 2024 - Mar 2026
Embedded Software Engineer II Dec 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.
Abiomed 2018 - 2022
Danvers, Massachusetts · On-site
Embedded Software Engineer II Jun 2022 - Dec 2022
Promoted here, then continued under J&J.
Embedded Software Engineer I May 2021 - May 2022
Joined full time after graduating.
Software Engineer Co-op Jan 2020 - Aug 2020
Software Engineer Co-op Jan 2019 - Aug 2019
Software Engineer Co-op Jan 2018 - Aug 2018

Education

Northeastern University 2016 - 2021
Bachelor of Science, Computer Science
Great Bay Community College 2014 - 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 familiar chip still learning chip 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.
Infrastructure
DockerSelf-hostingSSH
AI
DeepSeek APIAnthropic APIChatGPT APIOpen WebUIOWUI pluginsopen-terminalllama.cppQwen models
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.

A game scene with a rippling blue water surface seen from above, a small round robot character in an orange helmet, grey cubes floating on the water, green ground below and a pink sky
From above. The waves are the water surface shader; the cubes are riding them.
The same water surface seen from underneath, looking up through the water at a purple and mauve sky, with the robot and cubes floating and light patterns across the underside of the surface
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.

Grahm dressed as a jester in an orange and brown costume with a jester's hat, standing with one arm raised in front of the wooden gates of the New York Renaissance Faire
Outside the gates at the New York Renaissance Faire.
A closer view of the same jester costume, showing the orange and brown panelled tunic, the laced sleeves, the hat with bells, and the decorated shoe covers
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.

Hardware

CPU
Intel Core i7-14700K 20 cores: 8 performance, 12 efficient.
GPU
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:

😎 Mark Oversees the server as a whole. Sets the tone and the standard operating procedures the rest work to.
🔗 Larry Maintains this page. Also covers the landing page at glarkham.com.
🔖 Gerry GitLab, and provisions credentials for new AI chats so every commit is correctly signed and attributable.
📥 Weston Open WebUI itself. Runs a separate development instance so upgrades are tested before they touch production.
🎙️ Brenda The inter-AI communication tool, an Open WebUI plugin I have them talk to each other through.
⚡ Dash Open-terminal tooling, my own replacement for the default integration, which was not up to much.
🐋 Waldo The DeepSeek API pipe for Open WebUI.
🐞 Buggy The Claude API pipe for Open WebUI.
🐳 Ivan Immich, the photo and video library.
🪼 Jennifer Jellyfin, the media server.
🎮 Steve Minecraft, the modded server for friends.
👾 Apollo The Godot and Slang learning from the previous section. I do not get to claim all of that as unaided.
🐳 Willow A 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.

Pets

Pip, a fluffy black cat, lying on a shelf beside a pothos plant
Pip · supervisor
Georgie, a fluffy grey and white cat, perched on the back of a chair
Georgie · perched
no longer with us
Gambit, an orange tabby kitten, lying on a wooden stair tread
Gambit
Juju, a cream and dark-pointed cat, sitting on a sofa back
Juju
Rico, a small tan shaggy dog, lying on a wooden floor
Rico