Skip to content

feat(deploy): add host-process systemd unit alongside the Docker one#3617

Merged
mabry1985 merged 2 commits into
mainfrom
feat/host-process-systemd-unit
May 22, 2026
Merged

feat(deploy): add host-process systemd unit alongside the Docker one#3617
mabry1985 merged 2 commits into
mainfrom
feat/host-process-systemd-unit

Conversation

@mabry1985
Copy link
Copy Markdown
Contributor

@mabry1985 mabry1985 commented May 22, 2026

Agents spawn host CLIs (gh, codex, opencode, infisical, claude) via child_process. In containers those tools either aren't installed or can't see the host's auth files (~/.codex/auth.json, ~/.config/gh/hosts.yml, etc.), so operator workflows that depend on host-local auth need a non-Docker deploy path.

This PR doesn't force a choice — it makes both modes first-class systemd units. Pick one per host.

Changes

  • Rename automaker.serviceautomaker-docker.service. Header rewritten to call out that this is the containerized variant and point at the host counterpart. Adds After=network-online.target + Wants=network-online.target so Docker doesn't race the network.
  • New automaker-host.service. Runs npm start (which executes start-automaker.mjs --production) under a dedicated deploy user.
    • NODE_ENV=production, AUTO_MODE=true, journald logging
    • Graceful SIGTERM with 30s drain (the server marks running features interrupted in their feature.json so they resume on next start)
    • Restart-on-failure with burst limit (StartLimitBurst=5 in 5min)
    • Filesystem hardening: ProtectSystem=full + explicit ReadWritePaths so the agent can still write worktrees + the deploy user's HOME for tool credentials
  • docs/self-hosting/deployment.md: systemd section rewritten to document the two-unit choice. Table comparing the two, install instructions for each, "pick exactly one per host" guidance.

Decision matrix (now in the docs)

Unit Runs When to use
automaker-docker.service docker compose up -d Containerized prod, full filesystem isolation, no host CLI access from agents
automaker-host.service npm start (= start-automaker.mjs --production) Bare-metal prod. Agents can shell out to host CLIs.

Out of scope

  • No changes to deploy-main.yml or any CI workflow. The deploy pipeline still produces a Docker image; switching the production deploy to install automaker-host.service instead of running compose is a separate change.
  • No changes to start-automaker.mjs. It already supports --production; the host unit just wires that into systemd.
  • No changes to docker-compose.yml or docker-compose.prod.yml. The compose-consolidation work is in refactor(docker): consolidate prod compose, drop Swarm-only prod.yml #3616 (which renames staging.yml → prod.yml + drops the Swarm version).

Test plan

  • Both .service files parse as valid INI (configparser.ConfigParser reads both, ExecStart keys resolve correctly).
  • Live: copy automaker-host.service to a staging-like host, systemctl enable --now, verify the server starts and npm start survives a reboot. Happens after merge.

Summary by CodeRabbit

  • New Features

    • Added containerized deployment option for self-hosting via Docker
    • Added direct host deployment option for self-hosting without containers
  • Documentation

    • Updated deployment guide with setup instructions for both containerized and host-based deployment options

Review Change Stack

Agents spawn host CLIs (gh, codex, opencode, infisical, claude) via
child_process. In containers those tools either aren't installed or
can't see the host's auth files (~/.codex/auth.json,
~/.config/gh/hosts.yml, etc), so operator workflows that depend on
host-local auth need a non-Docker deploy path.

## Changes

- Rename `automaker.service` -> `automaker-docker.service`. Header
  rewritten to call out that this is the containerized variant and
  point at the host counterpart. Adds `After=network-online.target`
  + `Wants=network-online.target` so docker doesn't race the network.
- New `automaker-host.service`: runs `npm start` (which executes
  `start-automaker.mjs --production`) under a dedicated deploy user.
  Sets NODE_ENV=production, AUTO_MODE=true, journald logging,
  graceful SIGTERM with 30s drain, restart-on-failure with burst limit.
  Filesystem hardening via ProtectSystem=full + ReadWritePaths so the
  agent can still write worktrees + the deploy user's HOME (for tool
  credentials).
- `docs/self-hosting/deployment.md`: systemd section rewritten to
  document the two-unit choice. Table comparing the two, install
  instructions for each, "pick exactly one per host" guidance.

Operators pick the variant that fits their deploy:
  sudo systemctl enable --now automaker-host.service     # bare-metal
  sudo systemctl enable --now automaker-docker.service   # containerized

## What's not in this PR

- No changes to deploy-main.yml or any CI workflow. Deploy plumbing
  decides which unit to install separately.
- No changes to start-automaker.mjs itself. It already supports
  --production; the host unit just wires it into systemd.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Warning

Rate limit exceeded

@mabry1985 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 17 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 206e113a-2efe-4d46-9306-74c416b41d4a

📥 Commits

Reviewing files that changed from the base of the PR and between 759feb5 and e394b73.

📒 Files selected for processing (1)
  • apps/server/package.json
📝 Walkthrough

Walkthrough

This PR refactors the systemd deployment model by replacing a single generic automaker.service unit with two specialized variants: automaker-docker.service for containerized Docker Compose deployment, and automaker-host.service for direct host execution with security hardening. Deployment documentation is updated to guide operators in choosing between them.

Changes

Systemd Deployment Unit Refactor

Layer / File(s) Summary
Docker Compose deployment unit
automaker-docker.service
Oneshot systemd unit that manages Docker Compose stack lifecycle with start/stop/reload commands, execution parameters, timeouts, restart-on-failure behavior, and service ordering after Docker and network readiness.
Host-based deployment unit with security hardening
automaker-host.service
Full systemd service running Node.js directly on host with production configuration (NODE_ENV, AUTO_MODE, networking, data directory), graceful shutdown semantics, journald logging, file descriptor and task limits, and filesystem hardening including ProtectSystem, restricted home directory access, and privilege restrictions.
Deployment documentation and operator guidance
docs/self-hosting/deployment.md
Updated systemd section replacing single-unit instructions with dual-unit choice guidance, documenting runtime behavior differences, providing unit-specific installation and configuration steps for both Docker and host deployments, and clarifying that only one unit should be enabled per host.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

A systemd dance in two new forms—
🐳 Docker's cozy containerized norms,
And direct on the host for agents to play,
With hardening and care to keep risks at bay!
Two units, one choice, a clearer new way. 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding a host-process systemd unit alongside the existing Docker one, which is the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/host-process-systemd-unit

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

Code Review — ? finding(s)

Async review running parallel to CodeRabbit. Findings are advisory; not all are merge blockers.

protoLabs Code Review Report

  • Generated: 2026-05-22T05:25:01Z
  • Git head: d1e2a9867a50a3575ddf00468ca0e2854607a9c0
  • Features mapped: 3
  • Findings: 0

No findings recorded.

@github-actions
Copy link
Copy Markdown
Contributor

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@automaker-host.service`:
- Around line 55-56: The StartLimitIntervalSec and StartLimitBurst directives
are currently placed under the [Service] section but must live in the [Unit]
section to apply start-rate limiting correctly; move the two lines
StartLimitIntervalSec=300 and StartLimitBurst=5 from the [Service] block into
the [Unit] block in the automaker-host.service unit file so systemd applies the
restart throttling semantics as intended.

In `@docs/self-hosting/deployment.md`:
- Around line 179-218: Reorder the "Install the host-process variant" and
"Install the Docker variant" sections so each begins with the runnable commands
(the cp, edit, systemctl, and journalctl lines) followed by the explanatory
narrative; specifically move the command blocks that reference
automaker-host.service and automaker-docker.service, and the notes about
WorkingDirectory and Environment=COMPOSE_FILE, to appear before the descriptive
paragraphs about when to use automaker-host.service vs automaker-docker.service
and the rationale about child_process/host CLIs; keep the same commands and
config hints (WorkingDirectory, User/Group, Environment=HOME,
Environment=COMPOSE_FILE) and preserve the example journalctl -u automaker-host
-f line.
- Around line 177-230: The systemd installation content (the two units
automaker-docker.service and automaker-host.service and their install
instructions) mixes a How-to into the multi-purpose deployment page; move that
block into a new dedicated How-to titled something like "Systemd service
install" (create a standalone page containing the service descriptions, the
install steps for automaker-host.service and automaker-docker.service, and the
enable/start commands), then replace the removed block in the original
deployment page with a short one-line cross-reference link to the new How-to;
ensure the new page follows Diataxis How-to structure and update any internal
TOC or links accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f63d46a8-bd40-4b18-9c62-f390f56b8861

📥 Commits

Reviewing files that changed from the base of the PR and between 7097da9 and 759feb5.

📒 Files selected for processing (4)
  • automaker-docker.service
  • automaker-host.service
  • automaker.service
  • docs/self-hosting/deployment.md
💤 Files with no reviewable changes (1)
  • automaker.service

Comment thread automaker-host.service
Comment on lines +55 to +56
StartLimitIntervalSec=300
StartLimitBurst=5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify unit directives are in valid sections
systemd-analyze verify automaker-host.service 2>&1 | rg -n "StartLimit|Unknown lvalue|warning|error" -C2 || true

Repository: protoLabsAI/protoMaker

Length of output: 48


🏁 Script executed:

systemd-analyze verify automaker-host.service 2>&1 | rg -n "StartLimit|Unknown lvalue|warning|error" -C2 || true

Repository: protoLabsAI/protoMaker

Length of output: 48


🏁 Script executed:

systemd-analyze verify automaker-host.service 2>&1 | rg -n "StartLimit|Unknown lvalue|warning|error" -C2 || true

Repository: protoLabsAI/protoMaker

Length of output: 48


Move StartLimitIntervalSec and StartLimitBurst to the [Unit] section in automaker-host.service

Start-rate limiting directives should be in [Unit]; keeping them under [Service] risks restart throttling not being applied as intended (no errors were reported by systemd-analyze verify, but that doesn’t guarantee the intended semantics).

Suggested fix
 [Unit]
  Description=Automaker AI Development Studio (host process)
  Documentation=https://github.com/protoLabsAI/protoMaker
  After=network-online.target
  Wants=network-online.target
+StartLimitIntervalSec=300
+StartLimitBurst=5
  
 [Service]
@@
  Restart=on-failure
  RestartSec=10
-StartLimitIntervalSec=300
-StartLimitBurst=5
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
StartLimitIntervalSec=300
StartLimitBurst=5
[Unit]
Description=Automaker AI Development Studio (host process)
Documentation=https://github.com/protoLabsAI/protoMaker
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Restart=on-failure
RestartSec=10
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@automaker-host.service` around lines 55 - 56, The StartLimitIntervalSec and
StartLimitBurst directives are currently placed under the [Service] section but
must live in the [Unit] section to apply start-rate limiting correctly; move the
two lines StartLimitIntervalSec=300 and StartLimitBurst=5 from the [Service]
block into the [Unit] block in the automaker-host.service unit file so systemd
applies the restart throttling semantics as intended.

Comment on lines +177 to +230
## systemd

For persistent server deployments, use systemd to manage Docker Compose.
Two systemd units ship in the repo. Pick exactly one per host:

### 1. Install Service File
| Unit | Runs | When to use |
| -------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `automaker-docker.service` | `docker compose up -d` | Containerized prod, full filesystem isolation, no host CLI access from agents |
| `automaker-host.service` | `npm start` (= `start-automaker.mjs --production`) | Bare-metal prod. Agents can shell out to host CLIs (`gh`, `codex`, `opencode`, `infisical`, `claude`). |

```bash
# Copy the service file
sudo cp automaker.service /etc/systemd/system/
The host-process variant exists because agents spawn external tools via `child_process`; in containers those tools either aren't installed or can't see the host's auth files. If your operator workflow depends on `gh auth login` or `codex login` happening on the host, use `automaker-host.service`.

# Edit for your environment
sudo nano /etc/systemd/system/automaker.service
```
### Install the host-process variant

### 2. Configure Service

Edit the service file:
```bash
# Copy the service file
sudo cp automaker-host.service /etc/systemd/system/

```ini
[Unit]
Description=protoLabs AI Development Studio
After=docker.service
Requires=docker.service
# Edit for your environment if defaults don't match
sudo nano /etc/systemd/system/automaker-host.service
# WorkingDirectory = clone path (default: /opt/protomaker)
# User / Group = deploy user (default: automaker)
# Environment=HOME = $HOME for that user (default: /home/automaker)

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/home/youruser/automaker
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
ExecReload=/usr/bin/docker compose restart
TimeoutStartSec=120
TimeoutStopSec=60
Restart=on-failure
RestartSec=10
sudo systemctl daemon-reload
sudo systemctl enable --now automaker-host.service
journalctl -u automaker-host -f
```

# Run as your user
User=youruser
Group=youruser
### Install the Docker variant

Environment=COMPOSE_PROJECT_NAME=automaker
```bash
# Copy the service file
sudo cp automaker-docker.service /etc/systemd/system/

[Install]
WantedBy=multi-user.target
# Edit for your environment
sudo nano /etc/systemd/system/automaker-docker.service
# WorkingDirectory = path containing the compose file
# User / Group = deploy user
```

### 3. Enable and Start
The shipped file uses the default `docker-compose.yml`. For a prod deploy, set `WorkingDirectory` to the directory containing `docker-compose.prod.yml` and add `Environment=COMPOSE_FILE=docker-compose.prod.yml` to the `[Service]` block.

### Enable and start

```bash
# Reload systemd
sudo systemctl daemon-reload

# Enable on boot
sudo systemctl enable automaker

# Start now
sudo systemctl start automaker
# Pick exactly one:
sudo systemctl enable --now automaker-host.service
# OR
sudo systemctl enable --now automaker-docker.service

# Check status
sudo systemctl status automaker
# Check status (substitute the unit you enabled):
sudo systemctl status automaker-host
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

This addition continues mixing documentation types on one page.

The new systemd how-to content is added into an already multi-purpose page; please split this into a dedicated Diataxis page type (e.g., a focused How-to) and link it from here.

As per coding guidelines, "Documentation must follow the Diataxis framework; each page serves one of four types (Tutorial, How-to Guide, Reference, Explanation); never mix types on a single page".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/self-hosting/deployment.md` around lines 177 - 230, The systemd
installation content (the two units automaker-docker.service and
automaker-host.service and their install instructions) mixes a How-to into the
multi-purpose deployment page; move that block into a new dedicated How-to
titled something like "Systemd service install" (create a standalone page
containing the service descriptions, the install steps for
automaker-host.service and automaker-docker.service, and the enable/start
commands), then replace the removed block in the original deployment page with a
short one-line cross-reference link to the new How-to; ensure the new page
follows Diataxis How-to structure and update any internal TOC or links
accordingly.

Comment on lines +179 to +218
Two systemd units ship in the repo. Pick exactly one per host:

### 1. Install Service File
| Unit | Runs | When to use |
| -------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `automaker-docker.service` | `docker compose up -d` | Containerized prod, full filesystem isolation, no host CLI access from agents |
| `automaker-host.service` | `npm start` (= `start-automaker.mjs --production`) | Bare-metal prod. Agents can shell out to host CLIs (`gh`, `codex`, `opencode`, `infisical`, `claude`). |

```bash
# Copy the service file
sudo cp automaker.service /etc/systemd/system/
The host-process variant exists because agents spawn external tools via `child_process`; in containers those tools either aren't installed or can't see the host's auth files. If your operator workflow depends on `gh auth login` or `codex login` happening on the host, use `automaker-host.service`.

# Edit for your environment
sudo nano /etc/systemd/system/automaker.service
```
### Install the host-process variant

### 2. Configure Service

Edit the service file:
```bash
# Copy the service file
sudo cp automaker-host.service /etc/systemd/system/

```ini
[Unit]
Description=protoLabs AI Development Studio
After=docker.service
Requires=docker.service
# Edit for your environment if defaults don't match
sudo nano /etc/systemd/system/automaker-host.service
# WorkingDirectory = clone path (default: /opt/protomaker)
# User / Group = deploy user (default: automaker)
# Environment=HOME = $HOME for that user (default: /home/automaker)

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/home/youruser/automaker
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
ExecReload=/usr/bin/docker compose restart
TimeoutStartSec=120
TimeoutStopSec=60
Restart=on-failure
RestartSec=10
sudo systemctl daemon-reload
sudo systemctl enable --now automaker-host.service
journalctl -u automaker-host -f
```

# Run as your user
User=youruser
Group=youruser
### Install the Docker variant

Environment=COMPOSE_PROJECT_NAME=automaker
```bash
# Copy the service file
sudo cp automaker-docker.service /etc/systemd/system/

[Install]
WantedBy=multi-user.target
# Edit for your environment
sudo nano /etc/systemd/system/automaker-docker.service
# WorkingDirectory = path containing the compose file
# User / Group = deploy user
```

### 3. Enable and Start
The shipped file uses the default `docker-compose.yml`. For a prod deploy, set `WorkingDirectory` to the directory containing `docker-compose.prod.yml` and add `Environment=COMPOSE_FILE=docker-compose.prod.yml` to the `[Service]` block.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Put runnable commands before narrative in the new systemd section.

This section explains first and shows commands later; reverse that order to match the docs standard.

As per coding guidelines, "In documentation, show code snippets first, then explanation; use outcome-focused headings (e.g., 'Accept a payment' not 'PaymentIntent API'); write short sentences with active verbs and second person ('you')".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/self-hosting/deployment.md` around lines 179 - 218, Reorder the "Install
the host-process variant" and "Install the Docker variant" sections so each
begins with the runnable commands (the cp, edit, systemctl, and journalctl
lines) followed by the explanatory narrative; specifically move the command
blocks that reference automaker-host.service and automaker-docker.service, and
the notes about WorkingDirectory and Environment=COMPOSE_FILE, to appear before
the descriptive paragraphs about when to use automaker-host.service vs
automaker-docker.service and the rationale about child_process/host CLIs; keep
the same commands and config hints (WorkingDirectory, User/Group,
Environment=HOME, Environment=COMPOSE_FILE) and preserve the example journalctl
-u automaker-host -f line.

`apps/server/tsconfig.build.json` sets `rootDir: "../../"` so tsc preserves
the monorepo directory structure under `outDir`. The actual server entry
ends up at `dist/apps/server/src/index.js`, NOT `dist/index.js`. The
Dockerfile already uses the nested path (CMD line) — but
`apps/server/package.json`'s `main`, `start`, and `start:headless` all
pointed at the (non-existent) flat `dist/index.js`.

This had been broken for months. Nobody noticed because the Docker prod
path bypassed the start script. Surfaced during the host-process systemd
work: `npm start --production` built cleanly, then died at runtime trying
to load a months-old stale dist/services/discord-bot-service.js (the old
flat-layout artifact that predated the rootDir change). The "stale" file
was actually the only thing keeping the path resolvable for non-Docker
runs — clearing it exposes the structural mismatch.

## Changes

- `apps/server/package.json`:
  - `main`: `dist/index.js` → `dist/apps/server/src/index.js`
  - `start`: `node dist/index.js` → `node dist/apps/server/src/index.js`
  - `start:headless`: same path fix
  - `build` post-step (the .md copy script): substitutes `^src` with
    `dist/apps/server/src` so the runtime can find prompt files like
    `pm-prompt.md` (the second crash that surfaced during this debug).

## Validation

  rm -rf apps/server/dist
  cd apps/server && npm run build
  PORT=3018 node dist/apps/server/src/index.js
  # → server boots, /api/health returns 200, no missing-module crashes

This fix is a prerequisite for `automaker-host.service` to work
(this PR's main change). Folded in here rather than a separate PR
because the systemd unit is dead without it.
@mabry1985
Copy link
Copy Markdown
Contributor Author

Update: real-machine test surfaced a prerequisite fix (added in e394b73e1)

Tried npm start --production on this machine to validate the host-process path. It built clean, then died at runtime with Cannot find package 'discord.js' — pointing at apps/server/dist/services/discord-bot-service.js (the dist file). The error was misleading.

Root cause: apps/server/tsconfig.build.json sets rootDir: "../../", so tsc preserves the monorepo structure under outDir. The actual entry is at apps/server/dist/apps/server/src/index.js, NOT apps/server/dist/index.js. The Dockerfile's CMD already uses the nested path. But apps/server/package.json main, start, and start:headless all pointed at the flat path.

This has been broken for months. The Docker prod path bypassed the start script entirely (CMD ["node", "apps/server/dist/apps/server/src/index.js"] on line 222 of Dockerfile). Non-Docker users hit the wrong path → node tried to load a months-old stale flat-layout artifact that happened to have leftover import 'discord.js' from before the webhook-only migration.

Fix in e394b73e1:

  • apps/server/package.json: main + start + start:headlessdist/apps/server/src/index.js
  • apps/server/package.json build post-step: the .md copy script now substitutes ^src with dist/apps/server/src so runtime can find prompt files like pm-prompt.md (which surfaced as the second crash after the first fix)

Validation (this machine, port 3018 to avoid the dev server on 3008):

rm -rf apps/server/dist
cd apps/server && npm run build
PORT=3018 node dist/apps/server/src/index.js
# → server boots, /api/health returns 200

Without this fix, automaker-host.service (this PR's main change) would crash on start. The two changes are coupled.

@github-actions
Copy link
Copy Markdown
Contributor

Code Review — ? finding(s)

Async review running parallel to CodeRabbit. Findings are advisory; not all are merge blockers.

protoLabs Code Review Report

  • Generated: 2026-05-22T05:54:24Z
  • Git head: b138a40423a2fb44892ccf9f113046783a7dcce2
  • Features mapped: 3
  • Findings: 0

No findings recorded.

@github-actions
Copy link
Copy Markdown
Contributor

@mabry1985 mabry1985 merged commit 9618f39 into main May 22, 2026
7 checks passed
@mabry1985 mabry1985 deleted the feat/host-process-systemd-unit branch May 22, 2026 06:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant