# Linux (/docs/platforms/linux)



On Linux, Bowline runs as a user-level systemd service and works on headless
hosts through the CLI and TUI. Desktop notifications are a best-effort mirror
where a desktop is present, and they never block sync or approval. This page
covers installing the service, what it runs, restart and uninstall, headless
usage, when notifications fire, and what happens when no systemd user manager
exists.

## Install the user systemd service [#install-the-user-systemd-service]

The one-command installer puts `bowline` and `bowline-daemon` in `~/.local/bin`,
then runs `bowline daemon install`. The daemon command writes a user-level
systemd unit named `bowline.service`, reloads the user manager, and runs
`systemctl --user enable --now` to start it. The service is per-user, not
root-level, so it doesn't need elevated privileges or a system-wide package.

1. Install Bowline (see [Installation](/docs/getting-started/installation)).
2. Confirm with `bowline daemon status` and `bowline status`.
3. Run `bowline login` to authorize the machine.

If you install from a manual tarball, run `bowline daemon install` once after
the binaries are on your `PATH`.

## What the service runs [#what-the-service-runs]

The rendered `bowline.service` runs `bowline-daemon serve` with the active
workspace root, daemon state root, socket path, workspace id, device id,
persisted daemon environment, and `--notify-approvals`. The `--notify-approvals`
flag lets the daemon mirror pending Device Approval Requests to the desktop when
a notification service is available.

## Manage the service [#manage-the-service]

These commands cover the service lifecycle and the durable control surface. The
CLI and TUI are the source of truth on every Linux host.

| Command                     | What it does                                                                             |
| --------------------------- | ---------------------------------------------------------------------------------------- |
| `bowline daemon install`    | Writes `bowline.service`, reloads the user manager, and enables and starts the daemon    |
| `bowline daemon restart`    | Restarts the same service without changing sync state, workspace data, or project files  |
| `bowline daemon status`     | Reports the daemon's running state                                                       |
| `bowline daemon uninstall`  | Disables the service, removes only the generated unit file, and reloads the user manager |
| `bowline status`            | Durable workspace and project status (add `--json` for scriptable output)                |
| `bowline tui`               | Interactive status, approvals, and inspection                                            |
| `bowline approve [request]` | Approves a pending Device Approval Request                                               |

Run `bowline daemon restart` after you update the binary or the daemon
environment. `bowline daemon uninstall` removes only the generated unit; it
leaves your code under the workspace root untouched.

## Headless usage [#headless-usage]

Headless Linux is a first-class target. With no desktop present,
`bowline status`, `bowline tui`, and `bowline approve` are sufficient and remain
the approval source of truth. The complete trust path works over plain SSH.

1. Run `bowline status` to see pending Device Approval Requests and the short
   matching code.
2. Confirm the matching code, then run `bowline approve <request>` to grant
   trust.
3. Use `bowline tui` for an interactive view of status, conflicts, and
   approvals.

<Callout type="info">
  Nothing in the approval flow depends on a desktop or a notification server. On
  a headless host, the CLI and TUI are the full, durable trust surface.
</Callout>

## Best-effort desktop notifications [#best-effort-desktop-notifications]

Where a desktop is present, the daemon's `--notify-approvals` path mirrors
pending Device Approval Requests through the freedesktop notification interface
(`notify-rust`). Delivery is best effort: the daemon logs missing or broken
notification support and never blocks sync, status, the TUI, or approval.
Notifications repeat only the status-derived, non-secret approval text, and they
dedupe so a single pending request doesn't notify on every service-loop poll.

A notification shows the approval command; the approval still flows through
`bowline approve` and the existing trust model. Across platforms, native
notifications fire only for action-relevant states (Device Approval Requests, a
Blocking Degraded State, and a Review-Ready Agent Lease). They are a
convenience, never the only approval path.

## When no systemd user manager exists [#when-no-systemd-user-manager-exists]

Service commands report a structured unavailable state when there's no systemd
user manager, for example on a headless host with no active user session or
lingering enabled. This is a host service-manager condition, not a workspace
data condition. Your code and sync state are unaffected.

To run the background service, start a normal user session or enable lingering
for the user, then rerun `bowline daemon install`.

<Callout type="info">
  Even without the background service, the workspace stays usable. `bowline
    status`, `bowline tui`, and `bowline approve` work directly, so you can
  inspect and approve without systemd.
</Callout>

Bowline ships the portable user-level systemd unit as the install path. It
doesn't install `.deb` or `.rpm` packages, apt or yum repositories, a root-level
service, or a separate notification daemon. To gather a redacted support bundle,
run `bowline diagnostics collect` (add `--json` for scriptable output).

## Next steps [#next-steps]

* [macOS](/docs/platforms/macos): the daemon LaunchAgent and Menu Bar Status
  App.
* [Connect remote hosts](/docs/getting-started/connect-remote-hosts): bring a
  headless host into your workspace over SSH.
* [Device trust](/docs/concepts/device-trust): how Device Approval Requests
  work.
* [Status and health](/docs/concepts/status-and-health): what `bowline status`
  reports.
* [CLI commands](/docs/cli/commands): full reference for `bowline daemon`,
  `status`, and `approve`.
