# `ExternalRuntimeTransport.Transport`
[🔗](https://github.com/nshkrdotcom/external_runtime_transport/blob/v0.1.0/lib/external_runtime_transport/transport.ex#L1)

Behaviour for the raw subprocess transport layer.

In addition to the long-lived subscriber-driven transport API, the transport
layer also owns synchronous non-PTY command execution through `run/2`.

Legacy subscribers receive bare transport tuples:

- `{:transport_message, line}`
- `{:transport_data, chunk}`
- `{:transport_error, %ExternalRuntimeTransport.Transport.Error{}}`
- `{:transport_stderr, chunk}`
- `{:transport_exit, %ExternalRuntimeTransport.ProcessExit{}}`

Tagged subscribers receive:

- `{event_tag, ref, {:message, line}}`
- `{event_tag, ref, {:data, chunk}}`
- `{event_tag, ref, {:error, %ExternalRuntimeTransport.Transport.Error{}}}`
- `{event_tag, ref, {:stderr, chunk}}`
- `{event_tag, ref, {:exit, %ExternalRuntimeTransport.ProcessExit{}}}`

When `:replay_stderr_on_subscribe?` is enabled at startup, newly attached
subscribers also receive the retained stderr tail immediately after
subscription. When `:buffer_events_until_subscribe?` is enabled, stdout,
stderr, and error events emitted before the first subscriber attaches are
replayed in order.

# `event_tag`

```elixir
@type event_tag() :: atom()
```

The tagged event atom prefix.

# `extracted_event`

```elixir
@type extracted_event() ::
  {:message, binary()}
  | {:data, binary()}
  | {:error, ExternalRuntimeTransport.Transport.Error.t()}
  | {:stderr, binary()}
  | {:exit, ExternalRuntimeTransport.ProcessExit.t()}
```

Normalized transport event payload extracted from a mailbox message.

# `message`

```elixir
@type message() ::
  {:transport_message, binary()}
  | {:transport_data, binary()}
  | {:transport_error, ExternalRuntimeTransport.Transport.Error.t()}
  | {:transport_stderr, binary()}
  | {:transport_exit, ExternalRuntimeTransport.ProcessExit.t()}
  | {event_tag(), reference(), {:message, binary()}}
  | {event_tag(), reference(), {:data, binary()}}
  | {event_tag(), reference(),
     {:error, ExternalRuntimeTransport.Transport.Error.t()}}
  | {event_tag(), reference(), {:stderr, binary()}}
  | {event_tag(), reference(),
     {:exit, ExternalRuntimeTransport.ProcessExit.t()}}
```

Transport events delivered to subscribers.

# `subscription_tag`

```elixir
@type subscription_tag() :: :legacy | reference()
```

Legacy subscribers use `:legacy`; tagged subscribers use a reference.

# `surface_kind`

```elixir
@type surface_kind() :: :local_subprocess | :ssh_exec | :guest_bridge
```

Generic execution-surface placement kind.

# `t`

```elixir
@type t() :: pid()
```

Opaque transport reference.

# `close`

```elixir
@callback close(t()) :: :ok
```

# `end_input`

```elixir
@callback end_input(t()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `force_close`

```elixir
@callback force_close(t()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `info`

```elixir
@callback info(t()) :: ExternalRuntimeTransport.Transport.Info.t()
```

# `interrupt`

```elixir
@callback interrupt(t()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `run`

```elixir
@callback run(
  ExternalRuntimeTransport.Command.t(),
  keyword()
) ::
  {:ok, ExternalRuntimeTransport.Transport.RunResult.t()}
  | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `send`

```elixir
@callback send(t(), iodata() | map() | list()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `start`

```elixir
@callback start(keyword()) ::
  {:ok, t()}
  | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `start_link`

```elixir
@callback start_link(keyword()) ::
  {:ok, t()}
  | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `status`

```elixir
@callback status(t()) :: :connected | :disconnected | :error
```

# `stderr`

```elixir
@callback stderr(t()) :: binary()
```

# `subscribe`

```elixir
@callback subscribe(t(), pid()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `subscribe`

```elixir
@callback subscribe(t(), pid(), subscription_tag()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

# `unsubscribe`

```elixir
@callback unsubscribe(t(), pid()) :: :ok
```

# `close`

```elixir
@spec close(t()) :: :ok
```

Stops the transport.

# `delivery_info`

```elixir
@spec delivery_info(t()) :: ExternalRuntimeTransport.Transport.Delivery.t()
```

Returns stable mailbox-delivery metadata for the current transport snapshot.

# `end_input`

```elixir
@spec end_input(t()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Closes stdin for EOF-driven CLIs.

Pipe-backed transports send `:eof`; PTY-backed transports send the terminal
EOF byte (`Ctrl-D`).

# `extract_event`

```elixir
@spec extract_event(term()) :: {:ok, extracted_event()} | :error
```

Extracts a normalized transport event from a legacy mailbox message.

Tagged subscribers should use `extract_event/2` so their code does not depend
on a specific outer event tag.

# `extract_event`

```elixir
@spec extract_event(term(), reference()) :: {:ok, extracted_event()} | :error
```

Extracts a normalized transport event for a tagged subscriber reference.

This is the stable core-owned way for adapters to consume tagged transport
delivery without hard-coding the configured outer event atom.

# `force_close`

```elixir
@spec force_close(t()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Forces the subprocess down immediately.

# `info`

```elixir
@spec info(t()) :: ExternalRuntimeTransport.Transport.Info.t()
```

Returns the current transport metadata snapshot.

# `interrupt`

```elixir
@spec interrupt(t()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Sends SIGINT to the subprocess.

# `run`

```elixir
@spec run(
  ExternalRuntimeTransport.Command.t(),
  keyword()
) ::
  {:ok, ExternalRuntimeTransport.Transport.RunResult.t()}
  | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Runs a one-shot non-PTY command and captures exact stdout, stderr, and exit
data.

# `send`

```elixir
@spec send(t(), iodata() | map() | list()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Sends data to the subprocess stdin.

# `start`

```elixir
@spec start(keyword()) ::
  {:ok, t()}
  | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Starts the default raw transport implementation.

# `start_link`

```elixir
@spec start_link(keyword()) ::
  {:ok, t()}
  | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Starts the default raw transport implementation and links it to the caller.

# `status`

```elixir
@spec status(t()) :: :connected | :disconnected | :error
```

Returns transport connectivity status.

# `stderr`

```elixir
@spec stderr(t()) :: binary()
```

Returns the stderr ring buffer tail.

# `subscribe`

```elixir
@spec subscribe(t(), pid()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Subscribes the caller in legacy mode.

# `subscribe`

```elixir
@spec subscribe(t(), pid(), subscription_tag()) ::
  :ok | {:error, {:transport, ExternalRuntimeTransport.Transport.Error.t()}}
```

Subscribes a process with an explicit tag mode.

# `unsubscribe`

```elixir
@spec unsubscribe(t(), pid()) :: :ok
```

Removes a subscriber.

---

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