Skip to main content

Services

macOS LaunchAgents

import { darwin, defineConfig, launchAgent } from "@dovocode/workstation";

export default defineConfig(darwin({ resources: [
launchAgent("dev.example.worker", {
program: "/opt/homebrew/bin/example-worker",
args: ["serve", "--port", "7345"],
environment: { PATH: "/opt/homebrew/bin:/usr/bin:/bin" },
runAtLoad: true,
keepAlive: true,
stdoutPath: "~/Library/Logs/worker.log",
stderrPath: "~/Library/Logs/worker.error.log",
}),
] }));

Workstation writes ~/Library/LaunchAgents/<label>.plist, bootstraps it in the current user's gui/<uid> domain if unloaded, then requests a start. A GUI login session must exist for that domain. It does not manage system LaunchDaemons. Use unique labels, explicit executable paths, and an environment appropriate for a service rather than relying on interactive shell initialization.

Run-at-load defaults to true; keep-alive defaults to false. Removal unloads an owned agent and deletes its unchanged plist. A modified plist causes an error.

Linux systemd

import { defineConfig, linux, systemdService } from "@dovocode/workstation";

export default defineConfig(linux({ resources: [
systemdService("example-worker", {
description: "Example worker",
program: "/usr/local/bin/example-worker",
args: ["serve"],
environment: { PORT: "3000" },
restart: "on-failure",
}),
] }));

The default scope is user, writing under ~/.config/systemd/user/ and using systemctl --user. The .service suffix is added when missing. Set scope: "system" to write under /etc/systemd/system/ and use sudo. wantedBy defaults to default.target for user units and multi-user.target for system units. restart accepts no, on-failure, or always and defaults to on-failure.

Installation reloads the manager, enables the unit, and starts it. Owned removal disables/stops the unit, removes its unchanged file, and reloads the manager. An active user systemd manager is needed for user scope. systemdService does not enable lingering automatically; use the separate linger provision operation when needed. It does not create a login session.

Inspection limits

Service reconciliation compares declaration files and runtime activation. Systemd units must be active and enabled. LaunchAgents must be loaded; with keepAlive: true, they must also report running. A stopped/disabled managed service can therefore produce an update even when its file is unchanged.

This does not prove application readiness, network reachability, or successful account initialization. Use a separate read-only check for application health. Service installation failures are reported rather than treated as success.

Restart when configuration changes

Add dependsOn to connect a service to its package, custom executable, generated config, or health resource. Use resolved IDs, including absolute paths for files:

import { configure, defineConfig, files, linux, systemdService } from "@dovocode/workstation";

export default defineConfig(linux(configure(({ home }) => ({ resources: [
files.json("~/.config/worker/settings.json", { port: 7345 }),
systemdService("example-worker", {
program: "/usr/local/bin/example-worker",
args: ["--config", `${home}/.config/worker/settings.json`],
environment: { PATH: "/usr/local/bin:/usr/bin:/bin" },
dependsOn: [`file:${home}/.config/worker/settings.json`],
}),
] }))));

Install the real worker executable before applying this template. A changed settings file is applied before the dependent service restarts. The same dependsOn option is available on launchAgent. Unknown IDs and cycles fail; see the ID reference.

Generated service or existing-service activation?

Use systemdService or launchAgent when Workstation should generate and manage the unit/plist, including owned removal. Use provision with type: "service" when a package/vendor already supplies it and Workstation should check activation. Provision service declarations are retained on removal, including system launchd services. These are different lifecycle choices; do not manage the same service through both mechanisms.

For logs and user-session errors, see service troubleshooting.