# `BB.Process`
[🔗](https://github.com/beam-bots/bb/blob/main/lib/bb/process.ex#L5)

Helper functions for building child specs and looking up processes in the robot's registry.

# `key`

```elixir
@type key() :: term()
```

# `process_type`

```elixir
@type process_type() :: :actuator | :sensor | :controller
```

# `bridge_child_spec`

```elixir
@spec bridge_child_spec(module(), atom(), module() | {module(), Keyword.t()}, [atom()]) ::
  map()
```

Build a child_spec for a bridge process.

Bridges use GenServer directly (not a wrapper) as they implement the full
GenServer behaviour themselves.

# `call`

```elixir
@spec call(module(), key(), term(), timeout()) :: term()
```

Call a process looked up by name.

Uses a `:via` tuple so the registry handles lookup atomically.
Raises if the process doesn't exist or times out.

# `cast`

```elixir
@spec cast(module(), key(), term()) :: :ok
```

Cast a message to a process looked up by name.

Uses a `:via` tuple so the registry handles lookup atomically.
Returns `:ok` (GenServer.cast always returns :ok, even if process doesn't exist).

# `child_spec`

```elixir
@spec child_spec(
  module(),
  atom(),
  module() | {module(), Keyword.t()},
  [atom()],
  process_type(),
  Keyword.t()
) :: map()
```

Build a child_spec that registers the process in the robot's registry.

The resulting child spec uses the appropriate wrapper GenServer based on type:
- `:actuator` → `BB.Actuator.Server` (or `BB.Sim.Actuator` in simulation mode)
- `:sensor` → `BB.Sensor.Server`
- `:controller` → `BB.Controller.Server`

The user's callback module is passed via `__callback_module__` and the wrapper
server delegates GenServer callbacks to it.

The process is registered by its name (which must be globally unique across
the robot). The full path is passed to the process in its init args for
context, but is not used for registration.

## Options

- `:simulation` - when set (e.g., `:kinematic`), actuators use `BB.Sim.Actuator`
  instead of the real actuator module

# `registry_name`

```elixir
@spec registry_name(module()) :: atom()
```

Returns the registry name for a robot module.

# `send`

```elixir
@spec send(module(), key(), term()) :: :ok
```

Send a raw message to a process looked up by name.

Uses `Registry.dispatch/3` to handle lookup atomically.
Returns `:ok` regardless of whether the process exists.

# `via`

```elixir
@spec via(module(), key()) :: {:via, module(), {atom(), key()}}
```

Build a `:via` tuple for registry lookup by name.

Components register under their DSL name, which is an atom. Transient
processes that have no DSL name — command servers, for instance — register
under a tagged tuple such as `{:command, execution_id}`, so any term is
accepted.

# `via`

```elixir
@spec via(module(), key(), term()) :: {:via, module(), {atom(), key(), term()}}
```

Build a `:via` tuple that also stores `value` against the registry entry.

The value is returned by `Registry.select/2` alongside the key and pid, which
lets callers read a process's metadata without sending it a message.

# `whereis`

```elixir
@spec whereis(module(), key()) :: pid() | :undefined
```

Look up a process by name in the robot's registry.

Returns `pid` if found, `:undefined` otherwise.

---

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