# `Nous.Teams.Coordinator`
[🔗](https://github.com/nyo16/nous/blob/v0.17.1/lib/nous/teams/coordinator.ex#L1)

Team lifecycle GenServer that manages agent processes within a team.

The Coordinator is responsible for spawning, stopping, and monitoring agent
processes. It registers agents in the `Nous.AgentRegistry` with team-scoped
keys and sets up PubSub subscriptions.

## Architecture

Each team has exactly one Coordinator, started as part of `Nous.Teams.Supervisor`.
The Coordinator uses the team's DynamicSupervisor to start `AgentServer` processes.

    Teams.Supervisor
    ├── Coordinator (this module)
    ├── SharedState
    ├── RateLimiter (optional)
    └── DynamicSupervisor (for agents)
        ├── AgentServer ("alice")
        └── AgentServer ("bob")

## Quick Start

    {:ok, pid} = Coordinator.start_link(
      team_id: "team_1",
      team_name: "Research Team",
      pubsub: MyApp.PubSub,
      agent_supervisor: agent_sup_pid,
      shared_state: shared_state_pid
    )

    {:ok, agent_pid} = Coordinator.spawn_agent(pid, "alice", %{
      model: "openai:gpt-4",
      instructions: "You are a researcher"
    })

    agents = Coordinator.list_agents(pid)
    Coordinator.stop_agent(pid, "alice")
    Coordinator.dissolve(pid)

# `agent_info`

```elixir
@type agent_info() :: %{name: String.t(), pid: pid(), status: :running | :stopped}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `dissolve`

```elixir
@spec dissolve(pid()) :: :ok
```

Dissolve the team by stopping all agents and cleaning up.

## Examples

    :ok = Coordinator.dissolve(coordinator)

# `list_agents`

```elixir
@spec list_agents(pid()) :: [agent_info()]
```

List all agents in the team.

Returns a list of maps with `:name`, `:pid`, and `:status` keys.

## Examples

    agents = Coordinator.list_agents(coordinator)
    # [%{name: "alice", pid: #PID<0.123.0>, status: :running}]

# `spawn_agent`

```elixir
@spec spawn_agent(pid(), String.t(), map(), keyword()) ::
  {:ok, pid()} | {:error, term()}
```

Spawn a new agent within the team.

The agent is started under the team's DynamicSupervisor, registered in
`Nous.AgentRegistry` with a `{:team, team_id, name}` key, and subscribed
to team PubSub topics.

## Options

- `:role` — a `Nous.Teams.Role` struct to apply
- `:plugins` — list of plugin modules for the agent

## Examples

    {:ok, pid} = Coordinator.spawn_agent(coordinator, "alice", %{
      model: "openai:gpt-4",
      instructions: "Research specialist"
    })

# `start_link`

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

Start a Coordinator for a team.

## Options

- `:team_id` (required) — unique identifier for the team
- `:team_name` — human-readable team name (default: team_id)
- `:pubsub` — PubSub module for messaging
- `:agent_supervisor` — pid of the team's DynamicSupervisor for agents
- `:shared_state` — pid of the team's SharedState process
- `:rate_limiter` — pid of the team's RateLimiter process (optional)
- `:name` — optional GenServer name

# `stop_agent`

```elixir
@spec stop_agent(pid(), String.t()) :: :ok | {:error, :not_found}
```

Stop an agent by name.

## Examples

    :ok = Coordinator.stop_agent(coordinator, "alice")

# `team_status`

```elixir
@spec team_status(pid()) :: map()
```

Get the team's current status.

Returns a map with `:team_id`, `:team_name`, `:agent_count`, and `:agents` keys.

## Examples

    status = Coordinator.team_status(coordinator)
    # %{team_id: "team_1", team_name: "Research", agent_count: 2, agents: [...]}

---

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