22ad24db6c
CI / build (push) Successful in 1m17s
Workers could not run `mvn` or `java`. Every delegated task that asked for a build came back "mvn is not on PATH", and the worker was right. Root cause: HerdrPeerLauncher seeded the worker environment with an EMPTY map, so bridged passed only the vars it explicitly set (OPENCODE_CONFIG, GITEA_TOKEN, ANTHROPIC_*) and never PATH. herdr merges that map into its own process env, so a worker inherited whatever PATH the herdr SERVER was started with. On this host that server (pid 79870, PPID 1) had been up since Jul 4 with a PATH containing neither the JDK nor Maven. Confirmed on a live worker: its PATH was byte-identical to herdr's, and the only var bridged had contributed was OPENCODE_CONFIG. The failure was invisible and non-deterministic: the fleet's capabilities depended on how a long-lived daemon happened to be launched weeks earlier. There are three herdr processes on this box with three different PATHs; the one owning the socket is the one without a toolchain. bridged itself HAD Maven on PATH the whole time — it just never passed it on. It also quietly contradicted the project's own principle that "a worker is a full peer of the primary", and the implementer skill's instruction to build, commit and open a PR. Every delegation so far has depended on the primary running the build gate. Fix: baseEnv(cfg) seeds each worker with the daemon's own PATH, then applies the profile's new optional env: map. Adapter-specific vars are layered on top and therefore win — that ordering is load-bearing, not incidental: it stops an env: entry from overwriting ANTHROPIC_BASE_URL and slipping past SubscriptionGuard, which is checked against the profile's baseUrl alone. Pinned by a test. Because the default is now the daemon's PATH, both supervision units set PATH explicitly — launchd and systemd do not source a login shell, so under CB-504 the daemon (and every worker) would otherwise get a bare /usr/bin:/bin and this bug would silently return in production. 324 tests (was 321): daemon-PATH propagation, profile env: passthrough including an explicit PATH override, and the guard-bypass ordering. Verified live: daemon restarted, worker spawned, and asked to run the tools — "Apache Maven 3.9.16", "java version 25.0.2". Previously both were absent.
62 lines
2.5 KiB
Desktop File
62 lines
2.5 KiB
Desktop File
# CB-504 — systemd unit for bridged (Linux).
|
|
#
|
|
# The macOS launchd agent (deploy/dev.ltms.bridged.plist) is the supervision target for the
|
|
# current single-host deployment. This unit exists for the per-host gateways CB-308 introduces,
|
|
# which will run on Linux.
|
|
#
|
|
# Install (user service — bridged drives the user's herdr, not a system daemon):
|
|
# mkdir -p ~/.config/systemd/user
|
|
# cp deploy/bridged.service ~/.config/systemd/user/
|
|
# # edit ExecStart / WorkingDirectory / Environment below, then:
|
|
# systemctl --user daemon-reload
|
|
# systemctl --user enable --now bridged
|
|
# journalctl --user -u bridged -f
|
|
|
|
[Unit]
|
|
Description=bridged — claude-bridge message server
|
|
Documentation=https://git.ltms.dev/lms/claude-bridge/wiki
|
|
# Ordering only: herdr is a user process and its socket may appear after us. This is advisory —
|
|
# bridged retries the herdr socket rather than exiting, which is what actually makes a late
|
|
# socket survivable. Do NOT add Requires=: a herdr restart must not take bridged down with it.
|
|
After=herdr.service
|
|
Wants=herdr.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
WorkingDirectory=%h/src/claude-bridge/bridged
|
|
ExecStart=/usr/lib/jvm/temurin-25-jdk/bin/java -jar target/bridged.jar bridged.yaml
|
|
|
|
Environment=HERDR_SOCKET_PATH=%h/.config/herdr/herdr.sock
|
|
# PATH matters more than it looks (CB-511): bridged propagates its own PATH to every worker it
|
|
# spawns, so this line decides whether the fleet can run a build at all. systemd does not source a
|
|
# login shell, so without it the daemon — and every worker — gets a bare default with no JDK/Maven.
|
|
Environment=PATH=/usr/lib/jvm/temurin-25-jdk/bin:/usr/share/maven/bin:/usr/local/bin:/usr/bin:/bin
|
|
# Secrets are NOT set here — this file is committed. Put the API/worker tokens in a private
|
|
# drop-in that systemd reads with restrictive permissions:
|
|
# systemctl --user edit bridged → [Service] / Environment=BRIDGED_API_TOKEN=...
|
|
# or point EnvironmentFile at a 0600 file:
|
|
# EnvironmentFile=%h/.config/bridged/env
|
|
|
|
Restart=on-failure
|
|
RestartSec=10s
|
|
# A bad config (e.g. a non-loopback bind without token auth) makes bridged fail fast by design.
|
|
# Give up rather than restart-loop on a permanent error.
|
|
StartLimitBurst=5
|
|
StartLimitIntervalSec=120
|
|
|
|
# The daemon reads the repo, writes worktrees, and talks to a Unix socket — it needs no more.
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=strict
|
|
ProtectHome=read-write
|
|
ProtectKernelTunables=true
|
|
ProtectControlGroups=true
|
|
RestrictSUIDSGID=true
|
|
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
SyslogIdentifier=bridged
|
|
|
|
[Install]
|
|
WantedBy=default.target
|