# Runtime dependency and Docker image policy

LeanLsp v0.1.0 exposes a Docker-backed Lean runtime preview. Users can install
and inspect configuration without Docker, but starting the default runtime
requires Docker.

## External runtime requirement

Docker is required for the default runtime path:

- `LeanLsp.runtime_config/1` validates and normalizes options without starting
  Docker.
- `LeanLsp.start_runtime/1` starts `LeanLsp.Runtime.Docker` by default and needs
  a reachable Docker executable.
- The calling environment must have permission to run Docker containers.
- The selected image must be available locally or pullable by Docker.

A local Lean installation on the host is not required for this Docker-first
runtime path.

## Default image policy

The v0.1.0 preview default image is:

```text
leanprovercommunity/lean4:latest
```

The package keeps `latest` as the default for the initial preview so users get a
small, convenient Lean runtime without choosing an image up front. This is a
convenience default, not a reproducibility guarantee.

For reproducible workflows, pass a pinned tag or immutable digest explicitly with
the public `:docker_image` option:

```elixir
{:ok, runtime} =
  LeanLsp.start_runtime(
    docker_image: "leanprovercommunity/lean4:<pinned-tag-or-digest>"
  )
```

When calling `LeanLsp.Runtime.Docker.start_link/1` directly, use the runtime
`:image` option name:

```elixir
{:ok, runtime} =
  LeanLsp.Runtime.Docker.start_link(
    image: "leanprovercommunity/lean4:<pinned-tag-or-digest>"
  )
```

## Workspace and mount behaviour

`:container_workspace_root` configures the working directory inside the
container. It does not automatically mount a host directory.

Host filesystem access is opt-in through the runtime-specific `:mounts` option:

```elixir
{:ok, runtime} =
  LeanLsp.start_runtime(
    container_workspace_root: "/workspace",
    mounts: [{File.cwd!(), "/workspace", "ro"}]
  )
```

Docker bind mounts can expose host files to the container. Use read-only mounts
such as `"ro"` when the runtime only needs to read project files.

## Container lifecycle and cleanup

`LeanLsp.start_runtime/1` starts a long-lived Docker container. The returned
runtime handle is opaque and should be passed to `LeanLsp.Runtime.Docker.exec/3`
and `LeanLsp.Runtime.Docker.stop/1`.

Callers that start the runtime directly are responsible for stopping it:

```elixir
{:ok, runtime} = LeanLsp.start_runtime()

try do
  LeanLsp.Runtime.Docker.exec(runtime, ["lean", "--version"], [])
after
  LeanLsp.Runtime.Docker.stop(runtime)
end
```

The Docker implementation uses `docker stop` during cleanup and treats an
already-missing container as cleaned up. Supervised callers can use
`LeanLsp.Runtime.Docker.child_spec/1` and let the supervisor lifecycle stop the
runtime process.

## Expected Docker-related errors

When Docker is unavailable, the runtime cannot start and returns `{:error,
reason}`. The exact reason is implementation-specific during the v0.1.0 preview,
but common causes include:

- Docker is not installed.
- Docker is not running or is unreachable from the BEAM process.
- The current user does not have permission to run Docker.
- The selected image cannot be pulled or started.
- Invalid runtime options such as malformed mounts, environment variables, or
  timeouts.

Code should match on `{:ok, runtime}` / `{:error, reason}` rather than relying on
undocumented nested Docker error details.
