# `Planck.Headless.SidecarManager`
[🔗](https://github.com/alexdesousa/planck/blob/v0.1.0/lib/planck/headless/sidecar_manager.ex#L1)

Manages the optional sidecar OTP application.

At startup `SidecarManager` checks whether a sidecar directory is configured
(`Config.sidecar!/0`). When it exists on disk, it:

1. Runs `mix deps.get` and `mix compile` synchronously (fast-fail on error).
2. Spawns the sidecar as a long-lived OS process via erlexec using:
   `elixir --sname planck_sidecar --cookie <cookie> -S mix run --no-halt`
   The following env var is injected so the sidecar can connect back:
   - `PLANCK_HEADLESS_NODE` — `Node.self()` stringified
3. Monitors node connections. When the sidecar's Erlang node connects
   (name must begin with `"planck_sidecar"`), `SidecarManager` fetches the
   tool list via RPC and stores it in `ResourceStore`.
4. On node-down or OS-process exit, clears tools from `ResourceStore`.

## Progress events

Subscribe with `subscribe/0` to receive messages on the `"planck:sidecar"`
PubSub topic. Events are one of:

- `{:building, sidecar_dir}` — running `mix deps.get` / `mix compile`
- `{:starting, sidecar_dir}` — OS process spawned, waiting for node
- `{:connected, node}` — sidecar node is up and tools are loaded
- `{:disconnected, node}` — sidecar node went down, tools cleared
- `{:exited, reason}` — OS process exited unexpectedly
- `{:error, step, reason}` — build/startup step failed

# `state`

```elixir
@type state() :: %{
  sidecar_dir: Path.t() | nil,
  sidecar_node: atom() | nil,
  os_pid: pos_integer() | nil,
  status: status()
}
```

# `status`

```elixir
@type status() :: :idle | :building | :starting | :connected | :failed
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `node`

```elixir
@spec node() :: atom() | nil
```

Return the connected sidecar node name, or `nil` if not connected.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Start the SidecarManager under its supervisor.

# `status`

```elixir
@spec status() :: status()
```

Return the current lifecycle status.

# `subscribe`

```elixir
@spec subscribe() :: :ok | {:error, term()}
```

Subscribe the calling process to sidecar lifecycle events on `planck:sidecar`.

# `unsubscribe`

```elixir
@spec unsubscribe() :: :ok
```

Unsubscribe the calling process from sidecar lifecycle events.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
