I Am a Cross-Cutting Concern — Scott Lawson

10 min read Original article ↗

I have 76 Go projects, 61 PCB designs, 51 PlatformIO firmware projects, hundreds of technical notes, my resumes, my tax documents, and a ray tracer. They all live in one git repo.

The repo is called slam. It stands for Scott Lawson's Awesome Monorepo, a name I'm not going to defend. I chose it because I knew I'd type it thousands of times and wanted something short. Today it's just slam.

Collage showing the breadth of the slam monorepo: KiCad PCB designs, a pile of fabricated circuit boards, the Battleaxe multiplayer game, a parts database CLI, and a pick-and-place machine with illuminated LED ring
One repo holds PCB designs, multiplayer games, robot controllers, firmware, and more.

What unites all of these seemingly unrelated projects is the same thing: me. In software, a cross-cutting concern is something that touches every part of a system even though it isn't the main purpose of any one part. Logging, authentication, error handling are things that cut across everything. In my monorepo, I'm the cross-cutting concern. I'm not the purpose of any individual project, but I'm the thing that touches all of them. That turned out to be enough to put them in one repo.

I Was Losing My Code

Before slam, my projects lived in dozens of small private git repos scattered across different computers and operating systems. Many of them were small one-off projects like a PlatformIO project to test a microcontroller, or an LED animation, or a small tool or script that I wrote. None of them individually felt important enough to maintain properly.

But I was losing my projects slowly to the sands of time. I would forget that some projects existed, or I'd remember writing code for an ESP32 a year ago but forget where I put it, or which computer it was on. Some of the projects, especially the one-off ones, were badly named, and I'd forget which one of thirty different folders had the code that used a particular sensor. My notes and technical references were scattered in bits and pieces all over the place. When I would write a new note, I didn't feel like I was contributing to larger system or process.

The other problem was that most of these projects weren't "enough" to justify their own repo. They were early stage, small, and often one-off. But they weren't nothing either. For microcontrollers especially, I found myself constantly wanting to copy chunks of PlatformIO configuration from one project into another. I needed a home for things that were too small to stand alone but too useful to lose.

In 2022, I created slam and started pulling everything in.

One Place for Everything

The top-level structure is simple, has short names, and clear boundaries.

slam/
├── code/    # Software projects (Go, C++, Python)
├── pcb/     # KiCad PCB designs with firmware
├── hack/    # Experimental projects and prototypes
├── edge/    # Infrastructure config, Cloudflare tunnels, machine provisioning
├── note/    # Technical notes and reference material
├── post/    # Blog post drafts
├── rule/    # Conventions and patterns
├── bbb/     # Business administration
└── me/      # Personal documentation and resumes

I didn't design this structure upfront. It's a fluid and living system that has emerged over time. I've revised it, moved projects, and noticed what belonged together. The most important thing was that I had a starting point that I could iterate on. It didn't matter that I hadn't gotten it perfect from the beginning.

The Garage

The distinction between code/ and hack/ was one of the first decisions I made, and it turned out to be one of the most important.

Some projects have a clear structure from the beginning. A blog, a raytracer, a multiplayer game. You can sketch out an architecture and build it up. But a lot of what I do is exploratory. Things like testing a new microcontroller, experimenting with a new LED animation, or trying out a new sensor for the first time. These projects don't have a well-defined future and they don't fit neatly into existing patterns.

hack/ is where I put experimental things that don't have well defined home. I think of it as a garage. Ideas live there while they figure out what they are, and some of them eventually graduate to code/. Others stay experimental forever and I use them as snippet references or just delete them. Either outcome is fine. I got this idea partially from Go's /x/ packages and partially from Google's monorepo, which separates //experimental from production code. I like this distinction between stable and unstable code.

But the garage turned out to be more than just an organizational tool. It's the place where things that seem unrelated can sit next to each other long enough for me to notice patterns. Hundreds of small PlatformIO projects for different microcontrollers, each one a snippet: how to control WS2812 LED strips, read a sensor, communicate over I2C, drive a servo. Before slam, these were scattered across computers and I was slowly losing them. Once they were all in hack/, I started spotting recurring boards and configurations. I created note/ to hold technical references about the hardware I worked with. The archive grew into something I could draw from for every new project.

None of this would have happened if the snippets had stayed in separate repos on separate machines. I had to see the pattern pile up in one place before I could notice it.

Connections I Didn't Plan For

The monorepo started as a giant bucket that I could put everything that I worked on. Originally, I just wanted to make sure I wouldn't keep losing things that I worked on. But over three years, connections emerged that I never planned for. This is the part I didn't expect and the part I find most interesting.

I wrote a fast UART driver for controlling serial instruments with low latency. I built it for a microscope project. A year later, I needed the same driver for a robot controller. Because both projects lived in the same Go workspace, I could import the package directly. It was easier to reference this code because I don't have to publish, mirror, or spin off a new repo. A microscope and a robot have nothing obvious in common. But they share me, and I needed low-latency serial communication for both. In separate repos, that connection might never have happened.

I started with one web server I cared about deploying: a multiplayer game. I put it on Heroku. Then I built a Vietnamese dictionary. Then a monitoring tool. Then a robot dashboard. Then a blog. Each one was its own Go project in slam. After the fifth or sixth server, I noticed the deployment pattern repeating and built a CLI tool that could operate on any project in the monorepo. The incremental cost of adding another service dropped to nearly zero. I now self-host over a dozen services through Cloudflare tunnels.

The slam CLI showing commands for deploying, running, monitoring, transferring files, and configuring machines and Cloudflare tunnels
The slam CLI tool can deploy, run, monitor, transfer files, and configure cloudflare tunnels. I use this tool for everything in the monorepo.

That CLI tool only made sense because I had accumulated enough projects in one place to justify building it. The pattern wasn't clear when I only had two servers, but became obvious when I had six. Having everything in one place made things more visible to me, so I could spot the patterns more easily. Ultimately, I was the thing that connected them all.

Having everything in one repo also turns out to have advantages when coding with AI tools. Now, I can say "help me create a new instrument driver, and look at how I wrote the UART driver in code/photon/driver/uart for reference", or "help me create a new web service that uses the same page structure and pattern that I used in code/bietviet". If I had split everything into separate repos, it would be harder for the tools to build relevant context. I'd need to make sure each other repo was checked out on whatever machine I'm using. With slam, I always have everything and the context the tools need is easy to retrieve.

It's Contagious

I shared some screenshots of slam in a friends and family group chat. The directory structure, the CLI tool, how the projects fit together. Two people in the group were inspired enough to create their own personal monorepos.

One person created a repo called "claw" with a CLI tool that has a Trello-style task manager built right in. Another person created "LAIR" (Lab Automation Infrastructure Runner), focused on DevOps workflows like Docker, SSH, and Git automation. A third created "MapleForge" with commands tailored to their own projects. Each person picked a name that means something to them, organized things their own way, and built tools that solve their specific problems.

The LAIR CLI tool showing commands for configuration, Docker management, SSH, Git operations, and project scaffolding
LAIR: Lab Automation Infrastructure Runner. DevOps-focused, built around a completely different workflow than slam.
The MapleForge CLI tool showing ASCII art maple leaf logo and commands for package management
MapleForge. Different person, different domain, same idea.
The claw CLI tool showing a Trello-style task management command with personal task boards and lists
claw, another monorepo created by a friend. This one features a personal Trello built right into the CLI.

All of the CLI tools mentioned above were created with the help of Claude Code. The barrier to building a personalized command-line tool for your monorepo has dropped dramatically. What used to take weeks of scaffolding can be done in an afternoon. The hard part is not the tooling or infrastructure work, it's deciding to put everything in one place and trusting that it will grow into something useful.

The Freedom and the Risk

A personal monorepo is a fundamentally different thing than a company monorepo. At a company, you have communication costs, coordinated releases, shared ownership, and the need for systems like Bazel to build everything uniformly. None of that applies when it's just you.

When you are the only user, decisions have zero communication cost. Breaking changes can be made instantly. You don't need permission, review, or consensus. You are this amazing little dictator who can do whatever you want because it is your space. Don't set up Bazel. Don't design a perfect directory structure upfront. Do things that don't scale. Just get started and evolve it over time.

The biggest weakness is security. I keep sensitive information in slam. Resumes, tax documents, some API keys and secrets. The repo is private, I'm the only user, and I only access it on machines I control. But I won't pretend this is ideal. It's a huge airtight hatch: if someone gets inside, they get everything. I'm still looking for a better way to handle this, ideally something self-hosted. I'd love to hear suggestions.

The Cross-Cutting Concern

If you're late in your career and you've already built a workflow that works, keep doing what you're doing. You've solved your problems and a monorepo won't magically add value.

But if you're a recent graduate, or someone who hasn't worked out all the patterns yet, or you're intrinsically motivated and build things for fun across different domains, consider giving it a try. A raytracer and a circuit board have nothing obvious in common, and neither do a robot controller and a Vietnamese dictionary. But they share me, and having them in one place created connections and tools that I never would have discovered otherwise.

Most people organize projects by what they are. I kept losing mine, so I organized by who made them instead. Four years in, I can't imagine going back.