kache 0.5.0

Zero-copy, content-addressed Rust build cache. No copies, no wasted disk — just hardlinks locally and S3 for sharing.
---
title: Lifecycle
description: Starting, stopping, installing as a service, and how the daemon handles binary updates.
---

# Lifecycle

## Starting and stopping

```sh
kache daemon start      # start in background, blocks until the socket is ready
kache daemon stop       # graceful shutdown
kache daemon            # show status: running/stopped, PID, version, uptime
kache daemon log        # stream the daemon log (follows like tail -f)
```

`kache daemon run` starts the daemon in the foreground. This is mostly useful for debugging — you see log output directly on stderr without needing `kache daemon log`.

## Installing as a system service

For the daemon to survive reboots and start automatically, install it as a system service.

<Tabs items={["macOS (launchd)", "Linux (systemd)"]}>
  <Tab value="macOS (launchd)">
    ```sh
    kache daemon install
    ```

    This creates a launchd plist at `~/Library/LaunchAgents/ninja.kunobi.kache.plist` and loads it. The daemon will start on login and restart if it crashes.

    To remove it:

    ```sh
    kache daemon uninstall
    ```
  </Tab>
  <Tab value="Linux (systemd)">
    ```sh
    kache daemon install
    ```

    This creates a systemd user unit and enables it. The daemon runs under your user session.

    ```sh
    systemctl --user status kache
    ```

    To remove it:

    ```sh
    kache daemon uninstall
    ```
  </Tab>
</Tabs>

## Automatic restart on binary update

When you update kache, the old daemon and the new wrapper would disagree on RPC protocol versions. kache handles this automatically.

Each process tracks a **build epoch** — the modification time of the kache binary. When the wrapper makes an RPC call and its epoch is newer than the daemon's, the daemon schedules a graceful shutdown and the wrapper attempts to restart it. The next RPC call hits the fresh daemon. You never need to manually restart the daemon after an update.

<Callout type="info">
The restart logic runs only in CLI and daemon code paths, never in the wrapper hot path. Restarting the daemon doesn't add latency to any in-progress rustc invocations.
</Callout>

## Offline behavior

If the daemon is down or unreachable when the wrapper makes an RPC call, the wrapper continues without it. This affects:

- **Remote checks**: skipped — the wrapper goes straight to compilation on a local miss
- **Upload jobs**: dropped — new artifacts won't be uploaded until the daemon is running again
- **Prefetch**: skipped for the current build session

The monitor shows `daemon: offline` when the daemon hasn't responded in the last refresh cycle. Common causes:

| Symptom | Likely cause |
|---|---|
| `daemon: offline` after reboot | Service not installed, or install is user-scoped and session hasn't started |
| `daemon: offline` after update | Epoch mismatch restart in progress — wait a second and refresh |
| `daemon: offline` continuously | Check `kache daemon log` for startup errors |

When the monitor shows `daemon: offline`, it falls back to reading the local store and event log directly, so the Build and Store tabs still show accurate data.