# `ReqManagedAgents.Provisioner.Agents`
[🔗](https://github.com/cash-mckeeman/req_managed_agents/blob/v0.13.0/req_managed_agents/lib/req_managed_agents/provisioner/agents.ex#L1)

Agents as content-addressed managed entities: keyed by spec digest, created
once, reused forever, superseded by NEW specs, destroyed only by explicit
prune — the exact lifecycle `Provisioner.Environments` gives environments.

The provider-side name is `<base>_<digest8>`, so a name collision can only
mean "this exact agent already exists", and recovery by name is version-correct
even with an empty store.

# `ensure_agent`

```elixir
@spec ensure_agent(term(), ReqManagedAgents.Agent.Spec.t() | map(), keyword()) ::
  {:ok, ReqManagedAgents.Agent.Handle.t()} | {:error, term()}
```

Build-if-absent for an agent. Returns `{:ok, %Handle{}}`.

Opts: `:name` (base, default the spec's `name`), `:store` (`{module, store_opts}`),
`:create_fun` / `:list_fun` (test seams; default to `ReqManagedAgents.Providers.ClaudeManagedAgents.Client`
calls on the given client).

Returns `{:error, {:agent_base_too_long, base}}` when the base is long enough
that composing `<base>_<digest>` would have to truncate it. Such a name cannot
be parsed back into its base and digest, which `prune_agents/3` requires, so
the agent would be unreclaimable.

# `prune_agents`

```elixir
@spec prune_agents(term(), String.t(), keyword()) ::
  {:ok, %{archived: [String.t()], kept: [String.t()]}}
  | {:error, :keep_required | {:partial, [String.t()], {String.t(), term()}}}
```

Explicit GC: archives `<base>_*` agent versions beyond the newest `keep:`
(REQUIRED), never touching tagged digests or already-archived versions.

# `resolve_agent`

```elixir
@spec resolve_agent(
  String.t(),
  keyword()
) ::
  {:ok, ReqManagedAgents.Agent.Handle.t()}
  | {:error, :unknown_tag}
  | {:error, {:untracked_digest, String.t()}}
```

Resolve `"base:tag"` to the tagged agent's handle. `{:error, :unknown_tag}`
when the tag is absent, `{:error, {:untracked_digest, d}}` when its digest has
no provision entry (re-`ensure_agent` to heal). Split is on the FIRST colon only.

# `tag_agent`

```elixir
@spec tag_agent(String.t(), String.t(), map() | String.t(), keyword()) :: :ok
```

Point `base:tag` at an agent digest (or a handle's digest). Movable; tagged digests survive prune.

---

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