> ## Documentation Index
> Fetch the complete documentation index at: https://docs.microsandbox.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent client

> Go SDK - Low-level agentd client reference

`AgentClient` is the low-level raw transport for talking to `agentd` through a running sandbox's relay socket. For most applications, use [`Sandbox`](/sdk/go/sandbox), [`Exec`](/sdk/go/execution), and filesystem helpers instead. Reach for this API when you are building protocol-level tools or higher-level SDK helpers.

All request and response bodies are raw CBOR bytes. The SDK handles framing and correlation ids, but it does not encode or decode the CBOR message body for you: decode it with a library such as `fxamacker/cbor`. The raw body is the full CBOR-encoded protocol `Message` body (`v`, `t`, `p`), not just the inner payload.

<p className="msb-label" id="typical-flow">Typical flow</p>

```go theme={null}
import (
    "context"

    "github.com/fxamacker/cbor/v2"
    m "github.com/superradcompany/microsandbox/sdk/go"
)

ctx := context.Background()

client, err := m.ConnectAgentSandbox(ctx, "dev")             // 1. connect
if err != nil {
    return err
}
defer client.Close()

body, err := cbor.Marshal(map[string]any{                    // 2. build a CBOR Message
    "v": 1,
    "t": "core.fs.request",
    "p": fsRequestBytes,
})
if err != nil {
    return err
}

frame, err := client.Request(ctx, m.FlagSessionStart, body)  // 3. request / response
if err != nil {
    return err
}
_ = frame.Body
```

## Constants

#### <span className="msb-hn">FlagTerminal</span>

```go theme={null}
const FlagTerminal uint8 = 0b0000_0001
```

Frame flag: this is the last message for the given correlation id. When a frame on an open stream carries this bit, no further frames will arrive for that id. Also available as `FLAG_TERMINAL`, the cross-SDK constant spelling.

#### <span className="msb-hn">FlagSessionStart</span>

```go theme={null}
const FlagSessionStart uint8 = 0b0000_0010
```

Frame flag: this is the first message of a new session. Set it on the opening frame of a request/response RPC or a streaming session. Also available as `FLAG_SESSION_START`.

#### <span className="msb-hn">FlagShutdown</span>

```go theme={null}
const FlagShutdown uint8 = 0b0000_0100
```

Frame flag: this message requests sandbox shutdown. Also available as `FLAG_SHUTDOWN`.

## Functions

#### <span className="msb-recv">m.</span><span className="msb-hn">ConnectAgentSandbox()</span>

```go theme={null}
func ConnectAgentSandbox(ctx context.Context, name string) (*AgentClient, error)
```

<Accordion title="Example">
  ```go theme={null}
  client, err := m.ConnectAgentSandbox(ctx, "dev")
  if err != nil {
      return err
  }
  defer client.Close()
  ```
</Accordion>

Connect to a running sandbox by name. Resolves the sandbox's relay socket path and performs the `core.ready` handshake. Sandbox names are limited to 128 UTF-8 bytes. Use `context.WithTimeout` to override the default 10s handshake timeout.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Bounds the handshake; defaults to a 10s timeout if none is set.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>name</code><span className="msb-type">string</span></div>
    <div className="msb-param-desc">Sandbox name, up to 128 UTF-8 bytes.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#agentclient">\*AgentClient</a></div>
    <div className="msb-param-desc">Connected client.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">m.</span><span className="msb-hn">ConnectAgentPath()</span>

```go theme={null}
func ConnectAgentPath(ctx context.Context, path string) (*AgentClient, error)
```

<Accordion title="Example">
  ```go theme={null}
  path, err := m.AgentSocketPath("dev")
  if err != nil {
      return err
  }

  client, err := m.ConnectAgentPath(ctx, path)
  if err != nil {
      return err
  }
  defer client.Close()
  ```
</Accordion>

Connect to an `agentd` relay socket by path. Use this when you already have the socket path, for example one returned by [`AgentSocketPath()`](#m-agentsocketpath). Use `context.WithTimeout` to override the default 10s handshake timeout.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Bounds the handshake; defaults to a 10s timeout if none is set.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>path</code><span className="msb-type">string</span></div>
    <div className="msb-param-desc">Filesystem path of the relay socket.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#agentclient">\*AgentClient</a></div>
    <div className="msb-param-desc">Connected client.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">m.</span><span className="msb-hn">AgentSocketPath()</span>

```go theme={null}
func AgentSocketPath(name string) (string, error)
```

<Accordion title="Example">
  ```go theme={null}
  path, err := m.AgentSocketPath("dev")
  if err != nil {
      return err
  }
  fmt.Println(path)
  ```
</Accordion>

Resolve a sandbox's `agentd` relay socket path **without connecting**. Returns the same path [`ConnectAgentSandbox()`](#m-connectagentsandbox) would dial internally (preferring the hashed path, falling back to the legacy name-derived path), so you can talk to `agentd` over a raw byte transport (for example a transparent relay that splices bytes between a WebSocket and the socket) instead of this frame client. The sandbox need not be running; the path is derived from the name and the configured home directory.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>name</code><span className="msb-type">string</span></div>
    <div className="msb-param-desc">Sandbox name, up to 128 UTF-8 bytes.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">string</span></div>
    <div className="msb-param-desc">Relay socket path.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

## AgentClient methods

#### <span className="msb-recv">c.</span><span className="msb-hn">Request()</span>

```go theme={null}
func (c *AgentClient) Request(ctx context.Context, flags uint8, body []byte) (*RawFrame, error)
```

<Accordion title="Example">
  ```go theme={null}
  frame, err := client.Request(ctx, m.FlagSessionStart, body)
  if err != nil {
      return err
  }

  var msg map[string]any
  if err := cbor.Unmarshal(frame.Body, &msg); err != nil {
      return err
  }
  ```
</Accordion>

Send one frame and await a single response frame. Use for request/response RPCs that produce exactly one terminal response (for example a `core.fs.request` to its `core.fs.response`).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the request.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>flags</code><span className="msb-type">uint8</span></div>
    <div className="msb-param-desc">Frame flag byte, e.g. <code>FlagSessionStart</code>.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>body</code><span className="msb-type">\[]byte</span></div>
    <div className="msb-param-desc">CBOR-encoded protocol message body.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#rawframe">\*RawFrame</a></div>
    <div className="msb-param-desc">The single response frame.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">Stream()</span>

```go theme={null}
func (c *AgentClient) Stream(ctx context.Context, flags uint8, body []byte) (*AgentStream, error)
```

<Accordion title="Example">
  ```go theme={null}
  stream, err := client.Stream(ctx, m.FlagSessionStart, body)
  if err != nil {
      return err
  }
  defer stream.Close(ctx)

  for {
      frame, err := stream.Next(ctx)
      if err != nil {
          return err
      }
      if frame == nil || frame.Flags&m.FlagTerminal != 0 {
          break
      }
  }
  ```
</Accordion>

Open a streaming session. The returned [`AgentStream`](#agentstream) carries the protocol correlation id (read it with [`ID()`](#s-id) and pass it to [`Send()`](#c-send) for follow-up frames), and yields frames one at a time via [`Next()`](#s-next).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels opening the stream.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>flags</code><span className="msb-type">uint8</span></div>
    <div className="msb-param-desc">Frame flag byte for the opening frame, e.g. <code>FlagSessionStart</code>.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>body</code><span className="msb-type">\[]byte</span></div>
    <div className="msb-param-desc">CBOR-encoded protocol message body.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#agentstream">\*AgentStream</a></div>
    <div className="msb-param-desc">Open stream of raw frames.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">Send()</span>

```go theme={null}
func (c *AgentClient) Send(ctx context.Context, id uint32, flags uint8, body []byte) error
```

<Accordion title="Example">
  ```go theme={null}
  if err := client.Send(ctx, stream.ID(), 0, stdinBytes); err != nil {
      return err
  }
  ```
</Accordion>

Send a follow-up frame on an existing correlation id (for example stdin, a signal, a resize, or data chunks on an open session). Use the id returned by [`AgentStream.ID()`](#s-id).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the send.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>id</code><span className="msb-type">uint32</span></div>
    <div className="msb-param-desc">Correlation id of an open session.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>flags</code><span className="msb-type">uint8</span></div>
    <div className="msb-param-desc">Frame flag byte.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>body</code><span className="msb-type">\[]byte</span></div>
    <div className="msb-param-desc">CBOR-encoded protocol message body.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">ReadyBytes()</span>

```go theme={null}
func (c *AgentClient) ReadyBytes() ([]byte, error)
```

<Accordion title="Example">
  ```go theme={null}
  ready, err := client.ReadyBytes()
  if err != nil {
      return err
  }

  var msg map[string]any
  if err := cbor.Unmarshal(ready, &msg); err != nil {
      return err
  }
  ```
</Accordion>

Return the cached handshake `core.ready` frame body as CBOR bytes. Captured during connect, so this reads from the cached handshake rather than producing protocol traffic.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">\[]byte</span></div>
    <div className="msb-param-desc">CBOR-encoded <code>core.ready</code> frame body.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">Close()</span>

```go theme={null}
func (c *AgentClient) Close() error
```

<Accordion title="Example">
  ```go theme={null}
  defer client.Close()
  ```
</Accordion>

Release the client handle. Idempotent: calling it more than once is safe.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">c.</span><span className="msb-hn">CloseCtx()</span>

```go theme={null}
func (c *AgentClient) CloseCtx(ctx context.Context) error
```

<Accordion title="Example">
  ```go theme={null}
  if err := client.CloseCtx(ctx); err != nil {
      return err
  }
  ```
</Accordion>

Release the client handle with a caller-controlled context. Like [`Close()`](#c-close), but lets you bound or cancel the teardown.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the close.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

## AgentStream methods

#### <span className="msb-recv">s.</span><span className="msb-hn">Next()</span>

```go theme={null}
func (s *AgentStream) Next(ctx context.Context) (*RawFrame, error)
```

<Accordion title="Example">
  ```go theme={null}
  for {
      frame, err := stream.Next(ctx)
      if err != nil {
          return err
      }
      if frame == nil {
          break
      }
  }
  ```
</Accordion>

Pull the next frame from the stream. Returns `nil, nil` at EOF, so loop until the frame is `nil` or carries [`FlagTerminal`](#flagterminal).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels waiting for the next frame.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#rawframe">\*RawFrame</a></div>
    <div className="msb-param-desc">Next frame, or <code>nil</code> at EOF.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

#### <span className="msb-recv">s.</span><span className="msb-hn">ID()</span>

```go theme={null}
func (s *AgentStream) ID() uint32
```

<Accordion title="Example">
  ```go theme={null}
  id := stream.ID()
  if err := client.Send(ctx, id, 0, stdinBytes); err != nil {
      return err
  }
  ```
</Accordion>

Return the protocol correlation id for this stream. Pass it to [`AgentClient.Send()`](#c-send) for follow-up frames in the session.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">uint32</span></div>
    <div className="msb-param-desc">Correlation id for this session.</div>
  </div>
</div>

#### <span className="msb-recv">s.</span><span className="msb-hn">Close()</span>

```go theme={null}
func (s *AgentStream) Close(ctx context.Context) error
```

<Accordion title="Example">
  ```go theme={null}
  defer stream.Close(ctx)
  ```
</Accordion>

Release the stream handle.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div>
    <div className="msb-param-desc">Cancels the close.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">error</span></div>
    <div className="msb-param-desc">Typed microsandbox error.</div>
  </div>
</div>

## Types

### AgentClient

<p className="msb-backref">Returned by <a href="#m-connectagentsandbox">ConnectAgentSandbox()</a> · <a href="#m-connectagentpath">ConnectAgentPath()</a></p>

Low-level client for talking to `agentd` through the sandbox relay socket. All bodies are raw CBOR bytes: encode and decode them in your code with a library like `fxamacker/cbor`, and build typed convenience methods on top of this client. Construct it with one of the package-level connect functions.

| Method                                    | Returns                                     | Description                                |
| ----------------------------------------- | ------------------------------------------- | ------------------------------------------ |
| [`Request(ctx, flags, body)`](#c-request) | `(`[`*RawFrame`](#rawframe)`, error)`       | Send one frame, await one response         |
| [`Stream(ctx, flags, body)`](#c-stream)   | `(`[`*AgentStream`](#agentstream)`, error)` | Open a streaming session                   |
| [`Send(ctx, id, flags, body)`](#c-send)   | `error`                                     | Send a follow-up frame on a correlation id |
| [`ReadyBytes()`](#c-readybytes)           | `([]byte, error)`                           | Cached `core.ready` handshake frame body   |
| [`Close()`](#c-close)                     | `error`                                     | Release the handle (idempotent)            |
| [`CloseCtx(ctx)`](#c-closectx)            | `error`                                     | Release the handle with a context          |

### AgentStream

<p className="msb-backref">Returned by <a href="#c-stream">Stream()</a></p>

An open raw agent streaming session. Drive it by calling [`Next()`](#s-next) until it returns `nil`, which happens after a frame carrying [`FlagTerminal`](#flagterminal) or when the underlying stream is exhausted.

| Method                   | Returns                               | Description                                                               |
| ------------------------ | ------------------------------------- | ------------------------------------------------------------------------- |
| [`Next(ctx)`](#s-next)   | `(`[`*RawFrame`](#rawframe)`, error)` | Pull the next frame; `nil` at EOF                                         |
| [`ID()`](#s-id)          | `uint32`                              | Protocol correlation id; pass to [`Send()`](#c-send) for follow-up frames |
| [`Close(ctx)`](#s-close) | `error`                               | Release the stream handle                                                 |

### RawFrame

<p className="msb-backref">Returned by <a href="#c-request">Request()</a> · yielded by <a href="#s-next">Next()</a></p>

A raw protocol frame. `Body` is the CBOR-encoded `Message` body (`v`, `t`, `p`) as it appeared on the wire; decode it with a CBOR library such as `fxamacker/cbor`.

| Field | Type     | Description                                           |
| ----- | -------- | ----------------------------------------------------- |
| ID    | `uint32` | Correlation id from the frame header                  |
| Flags | `uint8`  | Frame flags (`FlagTerminal`, `FlagSessionStart`, ...) |
| Body  | `[]byte` | Raw CBOR-encoded body bytes                           |
