# `ReqManagedAgents.Environment.Spec`
[🔗](https://github.com/cash-mckeeman/req_managed_agents/blob/v0.12.0/req_managed_agents/lib/req_managed_agents/environment/spec.ex#L1)

Content-addressed identity of the runtime environment an agent is provisioned
into — the environment mirror of `ReqManagedAgents.Agent.Spec`. `config` is
provider-verbatim (opaque; the library never interprets it); `runtimes` is
typed — the library renders it, so `new/1` validates every runtime through
`ReqManagedAgents.Provisioner.Runtime.new/1` before it can reach the bootstrap
renderer.

`new/1` routes any top-level key that isn't `:name` or `:runtimes` into
`config` — a flat map like `%{runtimes: [...], networking: %{...}, type: "cloud"}`
is coerced with `config: %{networking: %{...}, type: "cloud"}`, so provider
fields at the top level are never silently dropped. An explicit `:config` key
wins on collision with a same-named stray key.

`digest/1` folds this identity into the provision content-address at both
hashing layers (the `Provisioner` cache key and the Bedrock harness name), so
two provisions of the same `Agent.Spec` into *different* environments no longer
collide. `name` is excluded from the digest (it is the base, not the identity),
exactly as in `Agent.Spec.digest/1`.

# `t`

```elixir
@type t() :: %ReqManagedAgents.Environment.Spec{
  config: map(),
  name: String.t() | nil,
  runtimes: [ReqManagedAgents.Provisioner.Runtime.t()]
}
```

# `digest`

```elixir
@spec digest(t()) :: String.t()
```

Deterministic content-address over the environment's identity fields
(`{runtimes, config}`, `name` excluded), using the same `Provisioner.hash/1`
helper as the rest of the provisioner. This is what makes an environment
content-addressable at both provisioning layers.

Returns the full hex hash — unlike `ReqManagedAgents.Agent.Spec.digest/1`,
which returns a lowercased 8-hex prefix. Callers that need the short form
(e.g. the `<base>_<digest8>` provider name) truncate and downcase it
themselves.

# `new`

```elixir
@spec new(t() | map() | nil) :: {:ok, t() | nil} | {:error, :invalid_environment_spec}
```

Coerce a map, an existing `%Spec{}`, or `nil` into a validated environment spec.

`nil` means "no environment" and is valid (`{:ok, nil}`). A map or struct has
each runtime validated/coerced via `Runtime.new/1`; any invalid runtime fails
the whole coercion with `{:error, :invalid_environment_spec}`, so no unvalidated
runtime can reach the bootstrap renderer. Both atom- and string-keyed maps are
accepted — more tolerant than `Agent.Spec.new/1`, which matches atom-keyed
maps only.

---

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