Less is More: How an AI Agent Taught Me to Write Better systemd Services


YAGNI — You Ain’t Gonna Need It.

💬 Rambling

Welp, if you haven’t been living under a rock, AI now cost money yo… WTF is a token… well it’s a magical thing that makes Sam Altman ALOT of money… in theory?

That being said… There are a lot of things I’d rather do with my Saturday than sit and fuck around with Linux services.

I dunno, I think I have a pretty weird idea with what I consider fun. I should probably be cleaning or doing some chores, but I digress… AND… to be honest, I’m pretty far behind with working on my German. I really need to catch up. Das ist nicht gut.

I also spent a good chunk of yesterday trying to fix my Hermes install. That poor thing really got messed up. I mean it doesn’t know how to UN-fuck itself sometimes and you gotta go in and then use a different agent to go fix it, which is really annoying. Like literally I’ve used Crush and Goose to fix OpenCode before… and half the time Crush won’t make system level changes, becuase it’s too careful… normally good. Then I just break out Goose, which is HONKING MAD… 🪿🔪💻 That … thing… will do whatever bat shit instructions you tell it, more or less. IIRC only Ante or Pi might be more pants on head…?

I’m also using handy to write some of this because I think it’s easier for me to try to say what I’m thinking and ramble on versus trying to type it out.

… ANYWAY…

📏 What you came here for

I needed to run an LLM proxy stack on my home server: Bifrost (AI gateway), Headroom (caching proxy), and optionally copilot-api. I wanted proper systemd services — restart on failure, logging, the works.

So threw OpenCode at it. What followed was a masterclass in over-engineering, followed by a Ponytail beatdown.

🏅 Round 1: The “Enterprise” Edition (545 lines)

The AI’s first pass was impressive. Three services, dependency chains, readiness checks with curl loops, PATH detection, wrapper scripts, environment file generation, pre-install dependency caching… it looked like something a cloud provider would ship.

# (545 lines of... this)
wait_for_port() {
    local host="$1" port="$2" timeout="${3:-30}"
    for i in $(seq 1 "$timeout"); do
        if curl -sf "http://${host}:${port}" > /dev/null 2>&1; then
            return 0
        fi
        sleep 1
    done
    return 1
}

It was correct. It was thorough. It was also fucking overkill for three services on a laptop. Not even on my home server…

🫠 Round 2: The Middle Ground

I pushed back. The AI collapsed it to a single service running llm_proxy.sh with trap + wait so bash stayed alive. Cleaner, but still had a wrapper script.

#!/bin/bash
trap 'exit 0' SIGINT SIGTERM
...
wait

Better, but I asked myself: wait, why do I need a wrapper at all?

💯 Round 3: Three Lines of ExecStart

The final version (189 lines for the installer, and the service definitions themselves are practically nothing):

[Service]
Type=simple
ExecStart=bunx @maximhq/bifrost -port 11434 -host 0.0.0.0
Restart=on-failure

That’s it. No wrapper. No PATH detection. No readiness checks. No env file for the first pass. Each service is just:

Service Command
llm-proxy-bifrost bunx @maximhq/bifrost -port 11434 -host 0.0.0.0
llm-proxy-headroom uvx --from "headroom-ai[all]" headroom proxy ...
llm-proxy-copilot npx copilot-api@latest start (disabled by default)

Type=simple. Raw ExecStart. Restart=on-failure. DONE.

📖 The Headroom Standalone (the real lesson)

After all that, I realized I wanted Headroom minus Bifrost. So we made a standalone Headroom service with a swappable upstream via .env:

[Service]
Environment=HEADROOM_UPSTREAM_URL=http://127.0.0.1:11434
EnvironmentFile=-/opt/llm-proxy/.env
ExecStart=/bin/sh -c 'exec uvx --from "headroom-ai[all]" headroom proxy --no-telemetry --code-aware --openai-api-url "$HEADROOM_UPSTREAM_URL"'

The one shell wrapper I have, and it’s just to expand $HEADROOM_UPSTREAM_URL from the env file. Switching between local and OpenRouter:

echo 'HEADROOM_UPSTREAM_URL=https://openrouter.ai/api/v1' | sudo tee /opt/llm-proxy/.env
sudo systemctl restart llm-proxy-headroom

🧠 What I learned

Everything I cut had a reason:

  • Readiness checks? Restart=on-failure handles that. If the port isn’t up, the service errors and retries. systemd already has a loop.
  • Wrapper scripts? If your command fits in ExecStart, put it there. One fewer file to maintain.
  • PATH detection? Systemd has Environment=PATH=.... Explicit beats magic.
  • Hard dependencies? Wants= (soft) over Requires= (hard). If Headroom starts before Bifrost, it’ll fail once and restart fine.
  • Env file for the first version? Nope. Default baked into Environment=. Only add the file when you need to override.

The AI kept adding things “just in case.” I kept deleting them. What remained was what I actually needed.

⚖️ Verdict

Less code is better code. The best systemd service is the one you can read in one screen.

4/5 deletions 🪓

… 5/5 w/ rice 🥡

💾 TL;DR

/etc/systemd/system/headroom.service

[Unit]
Description=Headroom Caching Proxy
After=network-online.target

[Service]
Type=simple
User=USENAME_HERE
Environment=PATH=/home/USENAME_HERE/.bun/bin:/home/USENAME_HERE/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Environment=HOME=/home/USENAME_HERE
Environment=HEADROOM_OUTPUT_SHAPER=0
Environment=HEADROOM_UPSTREAM_URL=https://openrouter.ai/api/v1
EnvironmentFile=-/etc/headroom.env
ExecStart=/bin/sh -c 'exec uvx --from "headroom-ai[all]" headroom proxy --no-telemetry --no-code-aware --openai-api-url "$HEADROOM_UPSTREAM_URL"'
Restart=on-failure
RestartSec=5
StandardOutput=append:/var/log/headroom/headroom.log
StandardError=append:/var/log/headroom/headroom.log

[Install]
WantedBy=multi-user.target

Reply:
Mastodon Bluesky Email
Prev
How to setup ZSH LLM Autocomplete
How to setup ZSH LLM Autocomplete

Comments