# `Pixir.ACP.Protocol`
[🔗](https://github.com/Ranvier-Technologies/pixir/blob/main/lib/pixir/acp/protocol.ex#L1)

JSON-RPC 2.0 framing over `Jason`, newline-delimited (ndjson), for the ACP agent
transport (ADR 0009). Pure functions, no IO: one decoded ndjson line becomes a tagged
term; result/error/notification maps become a JSON string (the caller appends `"\n"`).

There is deliberately no JSON-RPC dependency — the wire shape is small and hand-built
over `Jason` (one JSON object per line). stdout carries only these encoded strings;
every diagnostic goes to stderr (ADR 0005 channel discipline).

# `decoded`

```elixir
@type decoded() ::
  {:request, id(), method(), params()}
  | {:notification, method(), params()}
  | {:response, id(), term()}
  | {:response_error, id(), term()}
  | {:error, rpc_error()}
  | {:ignore, id() | nil}
```

# `id`

```elixir
@type id() :: integer() | String.t()
```

# `method`

```elixir
@type method() :: String.t()
```

# `params`

```elixir
@type params() :: map()
```

# `rpc_error`

```elixir
@type rpc_error() :: {atom(), integer(), String.t()}
```

# `decode`

```elixir
@spec decode(binary()) :: decoded()
```

Decode one ndjson line into a tagged term:

  * `{:request, id, method, params}` — has both `"id"` and `"method"`.
  * `{:notification, method, params}` — has `"method"` and no `"id"`.
  * `{:error, {kind, code, message}}` — malformed JSON or a non-2.0 envelope.
  * `{:ignore, id}` — a valid envelope an agent never acts on (e.g. a response).

`params` defaults to `%{}` when absent.

# `error`

```elixir
@spec error(id() | nil, integer(), String.t(), map() | nil) :: String.t()
```

Encode an error response as a JSON string (no newline). `data` is omitted unless
non-nil. `id` may be `nil` (e.g. an unrecoverable parse error).

# `internal_error`

```elixir
@spec internal_error() :: integer()
```

JSON-RPC code for an internal-error fault.

# `invalid_params`

```elixir
@spec invalid_params() :: integer()
```

JSON-RPC code for an invalid-params fault.

# `method_not_found`

```elixir
@spec method_not_found() :: integer()
```

JSON-RPC code for a method-not-found fault.

# `notification`

```elixir
@spec notification(method(), params()) :: String.t()
```

Encode a notification (`method` + `params`, no `id`) as a JSON string (no newline).

# `request`

```elixir
@spec request(id(), method(), params()) :: String.t()
```

Encode an OUTBOUND request (agent→client) as a JSON string (no newline). Unlike
every other encoder here, this one originates a request expecting a response —
used for `session/request_permission` (A.2). The Server correlates the eventual
`{:response, id, _}` against the `id` written here.

# `result`

```elixir
@spec result(id(), map()) :: String.t()
```

Encode a successful response (`id` + `result`) as a JSON string (no newline).

---

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