# Startup scripts

pboss sets up an OS-level boot service so the daemon starts at boot — and, because the process list is saved automatically after every change, the daemon resurrects your processes after the reboot. **Processes survive reboots and restarts by default.**

## It is installed automatically

You normally never run these commands:

- A **package-manager install** (`bun add -g pboss`, `npm i -g pboss`) installs the boot service automatically and prints the one command to run on hosts where it could not (containers, minimal VMs).

<!-- 2026-09-29: hidden with the universal installer (JS/TS package-manager focus).
     Re-add when it returns:
     - The **one-line installer** (`curl -fsSL https://procboss.com/install.sh | bash`) installs
       the boot service as its final step — the daemon starts immediately and at every boot.
       Hosts without systemd (containers, minimal VMs) get a note instead of an error. -->

`pboss startup install` is for the cases the automation could not cover: you removed the service, or you are re-enabling it on a new systemd host.

## pboss startup install

Installs and starts the boot startup service — as your normal user, no root:

- **Linux:** writes and enables a **per-user systemd unit** (`~/.config/systemd/user/pboss.service`) and drives it with `systemctl --user` — no root, no sudo. After bring-up, pboss best-effort runs `loginctl enable-linger <user>` so the daemon starts at **boot** rather than at your first login; where linger is refused (older systemd / polkit), the install still succeeds and says so. The start is `--no-block` with a hard health deadline (unit state + socket ping), so `install` always returns — a failing daemon produces a diagnosis, never a hang.
- **macOS:** writes and loads a `launchd` LaunchAgent (`~/Library/LaunchAgents/com.pboss.daemon.plist`). No root needed or wanted — sudo is rejected with a re-run hint.
- **Windows:** registers a Scheduled Task (`PBOSS_Daemon`) starting the daemon at **this user's logon** via `Register-ScheduledTask`, at RunLevel **Limited** (a Highest task needs an elevated shell to register; the daemon needs only the user's token). Hosts that deny even per-user registration ("Access is denied") fall back to the **per-user Registry Run key** (`HKCU\Software\Microsoft\Windows\CurrentVersion\Run\PBOSS_Daemon`) — same logon trigger, zero Task Scheduler permissions; the install says which mechanism was used. Only when both fail does it exit nonzero with the elevated re-run hint. The daemon is also brought up immediately (`pboss upgrade` stops it before replacing the binary).

On Windows, both mechanisms start the daemon through a generated hidden launcher (`~\.pboss\daemon-launch.vbs` run by `wscript.exe`), so it comes up with **no console window** — right after install and at every logon — and its output is appended to `~\.pboss\daemon.out.log` / `daemon.err.log`. The launcher then runs the boot resurrect (`pboss resurrect --wait 15`, the Windows twin of the unit's `ExecStartPost`), so saved processes come back at logon; its log — `~\.pboss\resurrect.out.log` / `resurrect.err.log` — is where to look when something did not.

```bash
pboss startup install
```

Running it under `sudo` is rejected — root has no user systemd session, and a root daemon would split into `/root/.pboss`. Re-run it as yourself; the service runs as the invoking user and uses the same `~/.pboss` data as your daily `pboss` commands.

The generated file adapts to how pboss was installed. A **package install** re-executes the same runtime that is running pboss: under Bun, `ExecStart=/home/you/.bun/bin/bun run …/dist/cli.js __daemon`; under Node, `ExecStart=/usr/bin/node …/dist/cli.js __daemon`; under Deno, `ExecStart=/home/you/.deno/bin/deno run -A …/dist/cli.js __daemon`. The header comment states which mode and runtime were detected.

<!-- 2026-09-29: hidden with the universal installer. Re-add when it returns: a **compiled
     standalone install** (built with `build:bin` — the one-line installer installs the npm
     package instead) re-executes the pboss binary itself — `ExecStart=/usr/local/bin/pboss
     __daemon` — (Bun is embedded in the binary, not required on the system). -->

The service `PATH` includes the target user's `~/.bun/bin` whenever it exists (workers that shell out to `bun` by name must resolve it), and the daemon self-heals its `PATH` at startup — daemons started by older service definitions also find Bun after an upgrade. See [runtimes](/runtimes) for the full discovery chain.

Bare `pboss startup` does not install anything — it prints the available options (`install` / `uninstall` / `status` / `generate`).

## pboss startup status

A read-only report of boot persistence — nothing is started, installed, or changed:

```bash
pboss startup status
```

```text
Boot startup service (systemd, per-user)
  Service:    /home/ra/.config/systemd/user/pboss.service
  Installed:  yes
  Enabled:    yes — starts with your session (default.target)
  Active:     active
  Linger:     on — the daemon starts at BOOT, before login
  Daemon:     reachable (pid 1234) at /home/ra/.pboss/daemon.sock

Reboot persistence:
  Dump:       /home/ra/.pboss/dump.json
  On boot:    3 process(es) come back running, 1 stopped
```

When the service is missing, the report says so and prints the exact install command; saved processes are reported as waiting for the service. When there is nothing saved yet, it says so — starts are saved automatically, so the count appears the moment you run `pboss start`. The socket and dump are read from the home the daemon actually uses (an explicit `PBOSS_HOME` wins; otherwise the current user's `~/.pboss`).

The first `pboss start` on an empty machine states where persistence stands — one line, only on a TTY: `✓ Persistence on: this process is saved and will come back after reboot` when the boot service is active, or the one command that enables it when it is not.

## pboss startup uninstall (alias: remove)

Remove the installed startup service — per-user on every platform, no root:

```bash
pboss startup uninstall
```

On Windows, both persistence mechanisms are removed by the same command — the scheduled task AND the Registry Run key fallback, together with the hidden launcher script — and `schtasks /delete` reporting "cannot find" is surfaced honestly ("No PBOSS_Daemon scheduled task or Run key found — nothing to remove") instead of a fake success line.

## pboss startup generate

Print the service config for review (or to install by hand) without touching the system:

```bash
pboss startup generate
pboss startup generate win32   # generate for another OS
```

## Saving is automatic

The process list is saved to `~/.pboss/dump.json` **after every change** — start, stop, restart, reload, delete, scale — so the dump always mirrors the live list. A manual `pboss save` still exists (a deliberate re-save), but you never need to remember it: add a process and it is already persisted.

```bash
pboss start app.ts            # saved automatically
pboss delete app              # saved automatically (it won't resurrect)
```

The dump records one extra bit per process — whether it was stopped. That is what a reboot restores:

| Last state before reboot | After reboot |
|---|---|
| running (online, errored, launching) | resurrected **running** |
| stopped (user stop, or clean exit 0) | resurrected **stopped** — listed, ready to `pboss restart` |
| deleted | gone |

`pboss stop` therefore means "keep it configured, but it should not run" — it comes back after a reboot in the stopped state. `pboss delete` means "remove it entirely" — it never comes back. And `pboss kill` (stopping the daemon itself) deliberately does **not** touch the dump: the process list describes what *should* run, so the next boot (or `systemctl --user start pboss`) brings everything back as it was.

## pboss resurrect

Restore previously saved processes (this is what the boot service runs automatically — the unit's `ExecStartPost` on Linux, the hidden launcher on Windows):

```bash
pboss resurrect
```

If a saved process is already running (the daemon restarted while its children survived), resurrect keeps the running instance instead of spawning a duplicate.

## What a reboot looks like

1. systemd / launchd / Task Scheduler starts the pboss daemon (`pboss __daemon`).
2. On Linux (`ExecStartPost`) and Windows (hidden launcher), the service immediately runs `pboss resurrect` and restores the saved list — running processes running, stopped ones stopped. On macOS, run `pboss resurrect` once after logon.
3. If the daemon later crashes, systemd's `Restart=always` restarts it and the unit's post step resurrect runs again.

```bash
# the whole setup, once, at install time:
bun add -g pboss

# then just use pboss — everything is persisted from here on:
pboss start ecosystem.config.json
```
