boxxkite

package module
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

README

boxxkite (Go client)

Go Reference

A Go client for a hosted boxxkite control-plane — create sandboxes, run commands, edit files, over HTTP. Mirrors sdk-python's BoxxkiteClient (PyPI: boxxkite-client) and sdk-js's BoxxkiteClient (npm: boxxkite-client) method-for-method, adapted to Go idiom ((result, err) returns, a request-struct pattern instead of keyword arguments, context.Context on every call). Not a client for the boxxkite package itself (SandboxManager, embedded directly against a Kubernetes cluster) — use this to talk to someone else's running control-plane, hosted or self-hosted, over its API.

Install

go get github.com/EvAlssment/boxxkite/sdk-go

Quickstart

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/EvAlssment/boxxkite/sdk-go"
)

func main() {
	client, err := boxxkite.NewClient("https://your-control-plane.example.com", "bxk_live_...")
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()
	err = client.WithSandbox(ctx, boxxkite.CreateSandboxRequest{Label: boxxkite.Ptr("demo")}, func(sb *boxxkite.Session) error {
		result, err := sb.Exec(ctx, "python3 -c 'print(1 + 1)'", nil)
		if err != nil {
			return err
		}
		fmt.Println(result.Stdout) // "2\n"

		if _, err := sb.FileCreate(ctx, "notes.txt", "hello from boxxkite\n", nil); err != nil {
			return err
		}
		viewed, err := sb.View(ctx, "notes.txt", nil)
		if err != nil {
			return err
		}
		fmt.Println(viewed.Content)
		return nil
	})
	// sandbox is destroyed automatically here, even if the callback returned an error
	if err != nil {
		log.Fatal(err)
	}
}

WithSandbox is the create-on-enter, destroy-on-exit convenience mirroring sdk-python's with client.sandbox() as sb: context manager / sdk-js's withSandbox. Prefer Client.CreateSandbox / Client.DestroySandbox directly if you want the sandbox to outlive the call that created it.

Every optional parameter uses a *Request/*Options struct with pointer-typed optional fields (nil == omit) rather than Go's nonexistent keyword arguments — use boxxkite.Ptr(v) to fill one in inline, e.g. boxxkite.CreateSandboxRequest{Size: boxxkite.Ptr("medium")}.

Also available: file/directory search (Ls/Glob/Grep), long-running background processes (StartProcess/GetProcessOutput/StopProcess), signed preview URLs for exposing a port (CreatePreviewURL/ RevokePreviewURL), an audit-log feed (GetLog/Watch), interactive human takeover over a raw WebSocket (Takeover), desktop (GUI) takeover over the same raw-WebSocket pattern (DesktopTakeover), and CRUD for images, volumes, webhooks, outbound-MCP connections, and secrets (CreateSecret/ ListSecrets/DeleteSecret). Full reference with examples for all of these: docs/API.md.

Webhooks

Register a subscription with CreateWebhook, then verify each delivery's X-Boxxkite-Webhook-Signature header (docs/WEBHOOKS-DESIGN.md §6) before trusting its body:

webhook, err := client.CreateWebhook(ctx, boxxkite.CreateWebhookRequest{
	URL:         "https://example.com/boxxkite-webhook",
	EventTypes:  []string{"sandbox.created", "sandbox.destroyed", "audit_log.entry"},
	Description: boxxkite.Ptr("webhooks example"),
})
if err != nil {
	log.Fatal(err)
}
fmt.Println("Signing secret (shown once, save it now):", webhook.Secret)

crypto/hmac.Equal is already constant-time (unlike Python's or Node's HMAC comparison, which need hmac.compare_digest/crypto.timingSafeEqual called out explicitly, Go's standard library gives you this for free) — a receiver verifying deliveries can lean on it directly:

func VerifySignature(secret, signatureHeader string, rawBody []byte, tolerance time.Duration) bool {
	var timestamp int64
	var signature string
	for _, part := range strings.Split(signatureHeader, ",") {
		key, value, ok := strings.Cut(part, "=")
		if !ok {
			continue
		}
		switch key {
		case "t":
			timestamp, _ = strconv.ParseInt(value, 10, 64)
		case "v1":
			signature = value
		}
	}

	if time.Since(time.Unix(timestamp, 0)).Abs() > tolerance {
		return false
	}

	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(strconv.FormatInt(timestamp, 10) + "."))
	mac.Write(rawBody)
	expected := hex.EncodeToString(mac.Sum(nil))

	return hmac.Equal([]byte(expected), []byte(signature))
}

Delete a subscription with client.DeleteWebhook(ctx, webhook.ID) when it's no longer needed. A runnable end-to-end version of this flow (create, list, verify a locally-signed payload, delete) lives in examples/webhooks.go:

BOXXKITE_BASE_URL=https://your-control-plane BOXXKITE_API_KEY=bxk_live_... \
    go run ./examples/webhooks.go

See docs/WEBHOOKS-DESIGN.md for the full event catalog, retry/backoff schedule, and delivery-idempotency contract.

Error handling

Every non-2xx response returns a *boxxkite.APIError (.StatusCode, .Code, .Message). A network-level failure (DNS, TLS, timeout, connection refused) returns a *boxxkite.ConnectionError instead. Both implement error; neither panics.

result, err := client.Exec(ctx, sandboxID, "echo hi", nil)
if err != nil {
	var apiErr *boxxkite.APIError
	if errors.As(err, &apiErr) && apiErr.Code == "concurrent_sandbox_limit_reached" {
		// back off, destroy an old session, etc.
	}
	return err
}

Retries

Automatic retry is off by default. Enable it with WithRetry, starting from DefaultRetryConfig() (2 retries, exponential backoff with full jitter, Retry-After honored):

client, err := boxxkite.NewClient(baseURL, apiKey, boxxkite.WithRetry(boxxkite.DefaultRetryConfig()))

Only idempotent verbs (GET/HEAD/PUT/DELETE/OPTIONS) are retried, and only on a connection failure or a transient status (429, 500, 502, 503, 504) — a non-idempotent POST (create-sandbox/secret/webhook) is never retried, so this can't double-create a resource. Backoff waits honor the request's context.Context: a cancelled/expired ctx cuts the wait short and returns immediately. Every field of RetryConfig is tunable if the defaults don't fit.

Streaming: Watch and Takeover

Watch returns a *LogWatcher you drive like bufio.Scanner:

watcher, err := client.Watch(ctx, sandboxID)
if err != nil {
	log.Fatal(err)
}
defer watcher.Close()
for watcher.Next() {
	entry := watcher.Entry()
	fmt.Println(entry.Operation, entry.StartedAt)
}
if err := watcher.Err(); err != nil {
	log.Fatal(err)
}

Takeover opens WS /v1/sandboxes/{id}/takeover and returns a *websocket.Conn (github.com/gorilla/websocket) for raw byte bridging — there is no message envelope, exactly as described in docs/API.md:

conn, err := client.Takeover(ctx, sandboxID)
if err != nil {
	log.Fatal(err)
}
defer conn.Close()
_ = conn.WriteMessage(websocket.BinaryMessage, []byte("ls -la\n"))
_, reply, err := conn.ReadMessage()

Unlike sdk-js's takeover() (constrained by the browser WebSocket API, which cannot set a custom header), this authenticates with a normal Authorization: Bearer <apiKey> header on the handshake — the same approach sdk-python's takeover() uses, since Go's websocket.Dialer, like Python's websockets library, can set arbitrary headers on a WebSocket upgrade request.

Design notes / library choices

  • WebSocket client: gorilla/websocket (BSD-2-Clause, 24k+ GitHub stars, not archived) — the de facto standard for Go WebSocket clients and servers, with straightforward support for setting a custom Authorization header on Dialer.DialContext, which Takeover needs. coder/websocket (formerly nhooyr.io/websocket) was also evaluated — a more modern, context-first API with more recent commits — but gorilla/websocket's wider adoption and this SDK's modest WebSocket surface (one raw byte-bridging connection, no advanced framing) didn't justify picking the less-established option.
  • SSE (Watch): hand-rolled with bufio.Scanner over the response body rather than a third-party SSE client library. sdk-python and sdk-js both hand-roll their own data:-line parser rather than pulling in a dependency for this too (see _iter_sse_events/parseSseEvents in their respective client.py/client.ts) — the actual parsing is ~20 lines and this SDK's needs (decode one JSON object per event, respect context.Context cancellation, no id:/event: framing) don't need more than that. r3labs/sse was evaluated as an existing option and would work, but wasn't adopted, to stay consistent with the other two SDKs' own approach here.
  • Request shape: every method with more than one or two optional parameters takes a *Request/*Options struct (pointer-typed optional fields) rather than Go's functional-options pattern (WithLabel(...)/WithSize(...)) — with ~15 methods each having 3-9 optional fields, functional options would mean dozens of tiny With* constructors for marginal benefit over a plain struct literal. This is used consistently across the whole client (CreateSandboxRequest, CreateImageRequest, ExecOptions, GrepOptions, etc.) — the functional-options pattern is reserved for Client construction itself (WithHTTPClient, WithTimeout, WithWebSocketDialer, WithRetry), where there are few, rarely-combined options and the pattern's real strength (extensible construction without breaking existing call sites) applies.

Explicitly out of scope for this pass

  • No LangChain-style tool-factory wrapper. sdk-python's langchain_tools.py / sdk-js's LangChain.js and Vercel AI SDK tool factories have no direct Go analog here, because there is no dominant Go agent-framework tool-spec convention to mirror yet (no Go equivalent of LangChain/LangGraph/Vercel AI SDK has emerged as a clear standard at the time of writing). If one does, a boxxkite/langchain-style subpackage wrapping Client's methods into that framework's tool interface would be the natural next step.
  • No payload_format/hec_token fields on CreateWebhookRequest. control-plane/src/control_plane/schemas.py's WebhookCreateRequest supports a Splunk HEC delivery format (GitHub issue #125), but neither sdk-python's nor sdk-js's create_webhook/createWebhook expose it yet — same "match the existing SDKs' method sets" rationale as above.
  • No separate async/concurrent client variant. Unlike sdk-python's AsyncBoxxkiteClient (a second class, because Python needs an explicit async/sync split), every method here already takes a context.Context and is safe to call from any goroutine — Go's goroutine-friendly blocking-call style doesn't need a parallel "async" API the way Python does.
  • No login/signup methods (POST /v1/auth/signup//login) — same scope as sdk-python/sdk-js: this client is constructed directly with an existing API key, not by authenticating a dashboard session itself. The opt-in dashboard-auth flows that are mirrored (RequestPasswordReset, ConfirmPasswordReset, VerifyEmail, ResendVerification, RefreshToken, Logout) match exactly what sdk-python's client.py exposes.

Development

go build ./...
go vet ./...
go test ./... -race -cover

Tests fake the control-plane with net/http/httptest (mirroring how sdk-python's tests use httpx.MockTransport and sdk-js's use a fake fetch) — no real deployment needed. WebSocket (Takeover) tests spin up a real gorilla/websocket upgrader against an httptest.Server.

Moving an in-progress local Claude Code/Codex CLI/opencode/Cursor session (full conversation history, not just a diff) into a fresh boxxkite sandbox is handled by boxxkite handoff <tool> (Python, part of the main boxxkite CLI, built on sdk-python, not this SDK) — see ../docs/handoff-adapters.md.

See the root README for what boxxkite is and the full self-hosting story, and docs/API.md for the complete REST API reference this client wraps.

Questions, bug reports, or need a usage-limit bump? Join the Discord.

Documentation

Overview

Package boxxkite is a Go client for a hosted boxxkite control-plane -- the same v1 HTTP API sdk-python's BoxxkiteClient and sdk-js's BoxxkiteClient wrap (see docs/API.md in the boxxkite repo). It is a thin request/response client: create sandboxes, run commands, edit files, stream the audit log, take over a sandbox's shell over a WebSocket -- all over HTTP against *someone else's* running control-plane. It is not a client for the boxxkite package itself (SandboxManager, embedded directly against a Kubernetes cluster).

Index

Examples

Constants

View Source
const DefaultTimeout = 30 * time.Second

DefaultTimeout is the default per-request timeout, matching sdk-python/sdk-js's 30-second default.

View Source
const ExecTimeoutHeadroom = 15 * time.Second

ExecTimeoutHeadroom is added on top of a caller-supplied exec/http-request timeout so the HTTP client's own deadline never fires before the control-plane's -- mirrors sdk-python's EXEC_TIMEOUT_HEADROOM / sdk-js's EXEC_TIMEOUT_HEADROOM_MS.

Variables

This section is empty.

Functions

func Ptr

func Ptr[T any](v T) *T

Ptr returns a pointer to v -- a small convenience for populating the pointer-typed optional fields on this package's *Request structs inline, e.g. boxxkite.CreateSandboxRequest{Size: boxxkite.Ptr("medium")}.

Types

type APIError

type APIError struct {
	StatusCode  int
	Code        string
	Message     string
	Retryable   bool
	Remediation string
	Details     any
	Taxonomy    string
}

APIError is returned when the control-plane responds with a non-2xx status and an `{"error": {code, message}}` envelope (or, failing that, a synthesized code/message from the bare HTTP status). Mirrors sdk-python's BoxxkiteApiError / sdk-js's BoxxkiteApiError.

func (*APIError) As added in v0.6.0

func (e *APIError) As(target any) bool

As exposes the typed taxonomy without changing the historical concrete return type of compatibility paths.

func (*APIError) Error

func (e *APIError) Error() string

type Account

type Account struct {
	ID        string `json:"id"`
	Email     string `json:"email"`
	CreatedAt string `json:"created_at"`
}

Account is the identity for the API key in use (GET /v1/account).

type AllowedCommandRule

type AllowedCommandRule struct {
	Command   string   `json:"command"`
	ArgsAllow []string `json:"args_allow,omitempty"`
	ArgsDeny  []string `json:"args_deny,omitempty"`
}

AllowedCommandRule is one account-level command allowlist rule -- either a bare command name (Command set, ArgsAllow/ArgsDeny both empty) or a command name plus argument allow/deny regex lists. The control-plane's own schema (AllowedCommandsRequest.rules: list[str | AllowedCommandRule] in control-plane/src/control_plane/schemas.py) accepts and returns rules in either shape -- UnmarshalJSON below decodes both into the same Go struct; MarshalJSON always emits the object form, which the control-plane accepts identically to the bare-string form for a rule with no argument constraints.

func (*AllowedCommandRule) UnmarshalJSON

func (r *AllowedCommandRule) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts either a bare JSON string (a plain command name, no argument constraints) or a JSON object ({"command", "args_allow"?, "args_deny"?}).

type AllowedCommandsResponse

type AllowedCommandsResponse struct {
	Rules []AllowedCommandRule `json:"rules"`
}

AllowedCommandsResponse is the body shape shared by GetAllowedCommands/SetAllowedCommands.

type CapabilityDeniedError added in v0.6.0

type CapabilityDeniedError struct{ APIError }

func (*CapabilityDeniedError) Error added in v0.6.0

func (e *CapabilityDeniedError) Error() string

func (*CapabilityDeniedError) Unwrap added in v0.6.0

func (e *CapabilityDeniedError) Unwrap() error

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a synchronous client for a hosted boxxkite control-plane. Safe for concurrent use by multiple goroutines (it holds no mutable state beyond a shared *http.Client).

func NewClient

func NewClient(baseURL, apiKey string, opts ...Option) (*Client, error)

NewClient constructs a Client for a hosted control-plane at baseURL, authenticating every request with apiKey (a boxxkite account API key, `bxk_live_...`, sent as `Authorization: Bearer <apiKey>`).

baseURL must be https://, or http://localhost (local dev only) -- an apiKey is a full-privilege, long-lived credential, so anything else would put it on the wire in cleartext. Mirrors sdk-python's _validate_base_url_scheme / sdk-js's validateBaseUrlScheme.

func (*Client) Account

func (c *Client) Account(ctx context.Context) (*Account, error)

Account returns the account identity for the API key in use.

func (*Client) ClearAllowedCommands

func (c *Client) ClearAllowedCommands(ctx context.Context) error

ClearAllowedCommands removes the per-account command allowlist (DELETE /v1/account/allowed-commands), back to the unrestricted default.

func (*Client) ConfirmPasswordReset

func (c *Client) ConfirmPasswordReset(ctx context.Context, token, newPassword string) (*MessageResponse, error)

ConfirmPasswordReset consumes a single-use token minted by RequestPasswordReset and sets a new password (POST /v1/auth/password-reset/confirm). Also revokes every outstanding refresh token for the account, if refresh tokens are enabled server-side.

func (*Client) CreateImage

func (c *Client) CreateImage(ctx context.Context, req CreateImageRequest) (*Image, error)

CreateImage queues a build of a custom sandbox image (POST /v1/images). Always asynchronous -- returns immediately with Status "queued"; poll GetImage for progress. 404s ("feature_disabled") if the deployment hasn't enabled the declarative builder (BOXXKITE_IMAGE_BUILDER_ENABLED).

func (*Client) CreateMCPConnection

func (c *Client) CreateMCPConnection(ctx context.Context, label, catalogID string) (*MCPConnection, error)

CreateMCPConnection grants this account access to one curated outbound-MCP catalog entry (POST /v1/mcp-connections). label is a unique (per-account) name for this connection -- pass it in CreateSandboxRequest.MCPConnectionNames to grant a session network egress to it. catalogID is one of "slack", "notion", "linear", "github" -- restricted to boxxkite's own reviewed allowlist, never a caller-supplied hostname.

Note: this only widens a granted session's per-pod NetworkPolicy egress allowlist to the connection's catalog hostname -- there is no MCP-proxy transport yet, so this does not yet let an agent speak MCP protocol to the destination.

func (*Client) CreatePreviewURL

func (c *Client) CreatePreviewURL(ctx context.Context, sessionID string, port int, ttlSeconds *int) (*PreviewURL, error)

CreatePreviewURL mints a signed, time-limited URL that proxies HTTP traffic to a port a background process opened inside this session (see StartProcessOptions.ExposePort) (POST /v1/sandboxes/{id}/preview/{port}). The returned URL carries its own authorization -- no API key is required to use it, only to mint it.

ttlSeconds bounds how long the minted URL stays valid (30-86400). Defaults to 900 (15 minutes) server-side when nil.

func (*Client) CreateSandbox

func (c *Client) CreateSandbox(ctx context.Context, req CreateSandboxRequest) (*Sandbox, error)

CreateSandbox creates a new sandbox session (POST /v1/sandboxes), or a batch of sandbox sessions when req.Count is greater than 1. Each session in a batch is created and limit-checked one at a time, so a later item can still fail the concurrent-sandbox or monthly-usage cap even if earlier items succeeded -- see CreateSandboxes for the batch form.

Example
mux := http.NewServeMux()
mux.HandleFunc("/v1/sandboxes", func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, `{"id":"sbx_123","status":"running","label":"demo","created_at":"2026-01-01T00:00:00Z"}`)
})
client, server := exampleServer(mux)
defer server.Close()

sandbox, err := client.CreateSandbox(context.Background(), CreateSandboxRequest{Label: Ptr("demo")})
if err != nil {
	fmt.Println("error:", err)
	return
}
fmt.Println(sandbox.Status)
Output:
running

func (*Client) CreateSandboxes

func (c *Client) CreateSandboxes(ctx context.Context, req CreateSandboxRequest) ([]Sandbox, error)

CreateSandboxes creates a batch of sandbox sessions in one call (POST /v1/sandboxes with req.Count > 1) and decodes the resulting array response. Use CreateSandbox instead for the common req.Count == 1 (or unset) case, which returns a single object rather than an array.

func (*Client) CreateSecret

func (c *Client) CreateSecret(ctx context.Context, req CreateSecretRequest) (*Secret, error)

CreateSecret registers a new org-scoped secret for the proxy-substitution secrets broker (POST /v1/secrets, docs/SECRETS-DESIGN.md). Returns the created secret's metadata -- never the raw value.

func (*Client) CreateVolume

func (c *Client) CreateVolume(ctx context.Context, req CreateVolumeRequest) (*Volume, error)

CreateVolume creates an independent, PVC-backed storage volume (POST /v1/volumes) that can later be mounted into one or more sandboxes via CreateSandboxRequest.VolumeMounts. Always asynchronous -- returns immediately with Status "queued"; poll GetVolume for progress. 404s ("feature_disabled") if the deployment hasn't enabled volumes (BOXXKITE_VOLUMES_ENABLED).

func (*Client) CreateWebhook

func (c *Client) CreateWebhook(ctx context.Context, req CreateWebhookRequest) (*Webhook, error)

CreateWebhook registers a webhook subscription (POST /v1/webhooks). Returns the subscription plus a Secret field -- the raw signing secret, shown exactly once.

func (*Client) DeleteImage

func (c *Client) DeleteImage(ctx context.Context, imageID string) error

DeleteImage deletes a custom sandbox image (DELETE /v1/images/{id}).

func (*Client) DeleteMCPConnection

func (c *Client) DeleteMCPConnection(ctx context.Context, connectionID string) error

DeleteMCPConnection deletes an outbound-MCP connection grant owned by this account (DELETE /v1/mcp-connections/{id}). 404s if already gone or never owned by this account.

func (*Client) DeleteSecret

func (c *Client) DeleteSecret(ctx context.Context, secretID string) error

DeleteSecret deletes a secret owned by this account (DELETE /v1/secrets/{id}). 404s if already gone or never owned by this account.

func (*Client) DeleteVolume

func (c *Client) DeleteVolume(ctx context.Context, volumeID string) error

DeleteVolume deletes a storage volume (DELETE /v1/volumes/{id}).

func (*Client) DeleteWebhook

func (c *Client) DeleteWebhook(ctx context.Context, subscriptionID string) error

DeleteWebhook deletes a webhook subscription owned by this account (DELETE /v1/webhooks/{id}). 404s if already gone or never owned by this account.

func (*Client) DesktopTakeover

func (c *Client) DesktopTakeover(ctx context.Context, sessionID string) (*websocket.Conn, error)

DesktopTakeover opens WS /v1/sandboxes/{id}/desktop -- interactive GUI/remote-desktop human takeover of a sandbox session (VNC over a raw duplex byte stream, proxied straight through to the sidecar's own WS /desktop), structurally identical to Takeover but bridging a full desktop instead of a shell (see docs/API.md and SECURITY.md's "New trust boundary: remote desktop takeover" section).

Like Takeover, this authenticates with a normal `Authorization: Bearer <apiKey>` header on the upgrade request. It reuses Takeover's can_initiate_takeover RBAC gate as-is -- requires an "admin"-role API key; a "member"-role key closes the connection with WS close code 4403. There is no dedicated can_initiate_desktop permission yet, and no read-only variant of this connection. A missing/invalid API key closes with 4401; an unowned or already-destroyed sessionID closes with 4404 -- both surface as an error from the first ReadMessage/WriteMessage call, since the close happens after the opening handshake completes. This route also closes with 4404 when the deployment has not set BOXXKITE_DESKTOP_ENABLED.

The caller must call Close on the returned *websocket.Conn once done.

func (*Client) DestroySandbox

func (c *Client) DestroySandbox(ctx context.Context, sessionID string) error

DestroySandbox tears down a sandbox session (DELETE /v1/sandboxes/{id}).

func (*Client) Exec

func (c *Client) Exec(ctx context.Context, sessionID, command string, opts *ExecOptions) (*ExecResult, error)

Exec runs a shell command inside the session's sandbox and returns its exit code, stdout, and stderr (POST /v1/sandboxes/{id}/exec). Commands run synchronously; there is no streaming of partial output.

Example
mux := http.NewServeMux()
mux.HandleFunc("/v1/sandboxes/sbx_123/exec", func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, `{"exit_code":0,"stdout":"2\n","stderr":""}`)
})
client, server := exampleServer(mux)
defer server.Close()

result, err := client.Exec(context.Background(), "sbx_123", "python3 -c 'print(1 + 1)'", nil)
if err != nil {
	fmt.Println("error:", err)
	return
}
fmt.Println(strings.TrimSpace(result.Stdout))
Output:
2

func (*Client) ExportMemories added in v0.7.0

func (c *Client) ExportMemories(ctx context.Context, scope string) (map[string]any, error)

ExportMemories exports live memories (and their relations) for this account, for backup or migration (GET /v1/memory/export).

func (*Client) FileCreate

func (c *Client) FileCreate(ctx context.Context, sessionID, path, content string, opts *FileOptions) (*FileCreateResult, error)

FileCreate creates or overwrites a file in the session's sandbox workspace (POST /v1/sandboxes/{id}/files).

func (*Client) ForgetMemory added in v0.7.0

func (c *Client) ForgetMemory(ctx context.Context, memoryID string) error

ForgetMemory permanently deletes one memory (DELETE /v1/memory/{id}). Not a soft-delete -- a forgotten memory cannot be recalled again.

func (*Client) GetAllowedCommands

func (c *Client) GetAllowedCommands(ctx context.Context) (*AllowedCommandsResponse, error)

GetAllowedCommands returns the current per-account command allowlist (GET /v1/account/allowed-commands). An empty Rules means unrestricted -- the default for every account. This allowlist is an opt-in guardrail, not a sandbox-escape boundary.

func (*Client) GetImage

func (c *Client) GetImage(ctx context.Context, imageID string) (*Image, error)

GetImage fetches one custom sandbox image's build status and details (GET /v1/images/{id}).

func (*Client) GetLog

func (c *Client) GetLog(ctx context.Context, sessionID string, opts *GetLogOptions) (*GetLogResult, error)

GetLog returns a page of audit-log entries for this session, oldest first (GET /v1/sandboxes/{id}/log).

func (*Client) GetMemory added in v0.7.0

func (c *Client) GetMemory(ctx context.Context, memoryID string) (*Memory, error)

GetMemory fetches one live memory owned by this account (GET /v1/memory/{id}).

func (*Client) GetProcessOutput

func (c *Client) GetProcessOutput(ctx context.Context, sessionID, processID string, sinceOffset int64) (*ProcessOutputResult, error)

GetProcessOutput polls a background process's output since a given byte offset (GET /v1/sandboxes/{id}/processes/{processId}/output). Polling-style, not streaming. sinceOffset (from a previous call's NextOffset, or 0 the first time) lets you fetch only the new output since your last check.

func (*Client) GetSandbox

func (c *Client) GetSandbox(ctx context.Context, sessionID string) (*Sandbox, error)

GetSandbox fetches one sandbox session by id (GET /v1/sandboxes/{id}). Unlike the exec/file routes, this resolves destroyed sessions too -- it is a lookup, not an operational route that requires a live pod.

func (*Client) GetVolume

func (c *Client) GetVolume(ctx context.Context, volumeID string) (*Volume, error)

GetVolume fetches one storage volume's status and details (GET /v1/volumes/{id}).

func (*Client) Glob

func (c *Client) Glob(ctx context.Context, sessionID, pattern string, path string) (*GlobResult, error)

Glob finds files matching a glob pattern (e.g. "**/*.py") under a directory in the session's sandbox workspace (POST /v1/sandboxes/{id}/files/glob). path defaults to "/".

func (*Client) Grep

func (c *Client) Grep(ctx context.Context, sessionID, pattern string, opts *GrepOptions) (*GrepResult, error)

Grep searches file contents by regex pattern under a directory in the session's sandbox workspace, optionally restricted to files matching opts.Glob (POST /v1/sandboxes/{id}/files/grep).

func (*Client) HTTPRequest

func (c *Client) HTTPRequest(ctx context.Context, sessionID, method, targetURL string, opts *HTTPRequestOptions) (*HTTPRequestResult, error)

HTTPRequest issues the secrets-broker HTTP request (POST /v1/sandboxes/{id}/http-request, docs/SECRETS-DESIGN.md). opts.Headers/opts.Body may contain a literal `{{secret:name}}` reference for a secret granted to this session via CreateSandboxRequest.SecretNames; the sidecar substitutes the real value in-process -- this SDK never sees it.

func (*Client) ImportMemories added in v0.7.0

func (c *Client) ImportMemories(ctx context.Context, req ImportMemoriesRequest) (*MemoryIngestResponse, error)

ImportMemories imports memories (and optionally their relations) previously produced by ExportMemories (POST /v1/memory/import).

func (*Client) IngestMemory added in v0.7.0

func (c *Client) IngestMemory(ctx context.Context, req IngestMemoryRequest) (*MemoryIngestResponse, error)

IngestMemory splits a bounded document or conversation into atomic memories (POST /v1/memory/ingest). Works with no model provider configured -- the default extractor is deterministic.

func (*Client) ListImages

func (c *Client) ListImages(ctx context.Context) ([]Image, error)

ListImages lists every custom sandbox image built for this account (GET /v1/images).

func (*Client) ListMCPConnections

func (c *Client) ListMCPConnections(ctx context.Context) ([]MCPConnection, error)

ListMCPConnections lists outbound-MCP connection grants for this account (GET /v1/mcp-connections).

func (*Client) ListMemories added in v0.7.0

func (c *Client) ListMemories(ctx context.Context, opts ListMemoriesOptions) ([]Memory, error)

ListMemories lists live memories for this account (GET /v1/memory).

func (*Client) ListProcesses

func (c *Client) ListProcesses(ctx context.Context, sessionID string) (*ProcessListResult, error)

ListProcesses returns every background process currently tracked for this session (GET /v1/sandboxes/{id}/processes).

func (*Client) ListSandboxes

func (c *Client) ListSandboxes(ctx context.Context, activeOnly bool) ([]Sandbox, error)

ListSandboxes lists sandbox sessions owned by the authenticated account (GET /v1/sandboxes). Pass activeOnly=true to restrict to currently-active sessions.

func (*Client) ListSecrets

func (c *Client) ListSecrets(ctx context.Context) ([]Secret, error)

ListSecrets lists secrets registered for this account (GET /v1/secrets). Raw values are never returned here.

func (*Client) ListVolumes

func (c *Client) ListVolumes(ctx context.Context) ([]Volume, error)

ListVolumes lists every storage volume created for this account (GET /v1/volumes).

func (*Client) ListWebhookDeliveries

func (c *Client) ListWebhookDeliveries(ctx context.Context, subscriptionID string, opts *ListWebhookDeliveriesOptions) ([]WebhookDelivery, error)

ListWebhookDeliveries returns recent delivery attempts (pending/delivered/failed) for this subscription, newest first (GET /v1/webhooks/{id}/deliveries).

func (*Client) ListWebhooks

func (c *Client) ListWebhooks(ctx context.Context) ([]Webhook, error)

ListWebhooks lists webhook subscriptions for this account (GET /v1/webhooks). The signing secret is never returned here.

func (*Client) Logout

func (c *Client) Logout(ctx context.Context, refreshToken string) error

Logout revokes one refresh token immediately (POST /v1/auth/logout), opt-in (BOXXKITE_REFRESH_TOKENS_ENABLED). Always succeeds (204) whether or not the token was valid -- never leaks which.

func (*Client) Ls

func (c *Client) Ls(ctx context.Context, sessionID string, path string) (*LsResult, error)

Ls lists the direct children of a directory in the session's sandbox workspace (POST /v1/sandboxes/{id}/files/ls). path defaults to "/".

func (*Client) MemoryProfile added in v0.7.0

func (c *Client) MemoryProfile(ctx context.Context, scope string, limit int) (*MemoryProfileResponse, error)

MemoryProfile builds a compact memory profile: stable, long-lived memories separated from recently-touched ones (GET /v1/memory/profile).

func (*Client) MemoryRelations added in v0.7.0

func (c *Client) MemoryRelations(ctx context.Context, memoryID string, limit int) (*MemoryRelationsResponse, error)

MemoryRelations lists other memories related to this one (GET /v1/memory/{id}/relations -- updates/extends/related/derives edges).

func (*Client) Recall added in v0.7.0

func (c *Client) Recall(ctx context.Context, query string, opts RecallOptions) (*MemorySearchResponse, error)

Recall ranks live account memories against a query using lexical evidence, phrase match, recency, and importance (GET /v1/memory/search).

func (*Client) RefreshToken

func (c *Client) RefreshToken(ctx context.Context, refreshToken string) (*TokenPair, error)

RefreshToken exchanges a still-valid refresh token for a brand new access_token + refresh_token pair (POST /v1/auth/refresh), opt-in (BOXXKITE_REFRESH_TOKENS_ENABLED). Revokes the presented token in the same request (rotation, not reuse) -- store the new RefreshToken from the response and discard the one presented here.

func (*Client) Remember added in v0.7.0

func (c *Client) Remember(ctx context.Context, req RememberRequest) (*Memory, error)

Remember stores one durable, account-scoped memory directly (POST /v1/memory). See the MemoryBase developer guide for the full model (opt-in, self-hosted retrieval by default, no third-party memory API).

func (*Client) RequestPasswordReset

func (c *Client) RequestPasswordReset(ctx context.Context, email string) (*MessageResponse, error)

RequestPasswordReset requests a password-reset email (POST /v1/auth/password-reset/request). Opt-in on the control-plane (BOXXKITE_PASSWORD_RESET_ENABLED); returns an *APIError with StatusCode 404 and Code "feature_disabled" if the deployment hasn't enabled it. Always returns the same message whether or not the email is registered, so this call can never be used to enumerate accounts.

func (*Client) ResendVerification

func (c *Client) ResendVerification(ctx context.Context, accessToken string) (*MessageResponse, error)

ResendVerification re-sends the verification email for the dashboard-JWT-authenticated account (POST /v1/auth/resend-verification). accessToken is a dashboard session token (the JWT returned by /v1/auth/login or /v1/auth/signup) -- a different, non-interchangeable credential type from this Client's own apiKey, so it overrides this call's Authorization header rather than using the Client's apiKey.

func (*Client) RevokePreviewURL

func (c *Client) RevokePreviewURL(ctx context.Context, sessionID string, port int, tokenID string) (*PreviewRevokeResult, error)

RevokePreviewURL invalidates one specific preview-URL token (its TokenID from CreatePreviewURL) before its TTL expires, without tearing down the sandbox session and without affecting any other preview token minted for the same session/port (POST /v1/sandboxes/{id}/preview/{port}/revoke). Idempotent: revoking an already-revoked, already-expired, or unrecognized tokenID still returns Revoked=true rather than erroring.

func (*Client) SendProcessInput

func (c *Client) SendProcessInput(ctx context.Context, sessionID, processID, data string) (*ProcessInputResult, error)

SendProcessInput writes to a tracked background process's stdin pipe (POST /v1/sandboxes/{id}/processes/{processId}/input).

func (*Client) SetAllowedCommands

func (c *Client) SetAllowedCommands(ctx context.Context, rules []AllowedCommandRule) (*AllowedCommandsResponse, error)

SetAllowedCommands replaces the per-account command allowlist wholesale (PUT /v1/account/allowed-commands). rules must be non-empty -- use ClearAllowedCommands to reset to unrestricted.

func (*Client) StartProcess

func (c *Client) StartProcess(ctx context.Context, sessionID, command string, opts *StartProcessOptions) (*ProcessStartResult, error)

StartProcess starts a background process that keeps running after this call returns (POST /v1/sandboxes/{id}/processes). Distinct from Exec, which is one-shot request/response bounded by its own timeout: poll the returned ProcessID's output with GetProcessOutput, feed it input with SendProcessInput, and stop it with StopProcess.

func (*Client) StopProcess

func (c *Client) StopProcess(ctx context.Context, sessionID, processID string) (*ProcessStopResult, error)

StopProcess stops a tracked background process (SIGTERM, then SIGKILL if it doesn't exit within a short grace period) (POST /v1/sandboxes/{id}/processes/{processId}/stop).

func (*Client) StrReplace

func (c *Client) StrReplace(ctx context.Context, sessionID, path, oldStr, newStr string, opts *StrReplaceOptions) (*StrReplaceResult, error)

StrReplace replaces oldStr with newStr in a file; oldStr must appear exactly once unless opts.ReplaceAll is set (POST /v1/sandboxes/{id}/files/str-replace).

func (*Client) StreamProcessOutput

func (c *Client) StreamProcessOutput(ctx context.Context, sessionID, processID string, sinceOffset int64) (*ProcessStream, error)

StreamProcessOutput opens the SSE output stream for a background process. The caller must call Close on the returned *ProcessStream once done.

func (*Client) Takeover

func (c *Client) Takeover(ctx context.Context, sessionID string) (*websocket.Conn, error)

Takeover opens WS /v1/sandboxes/{id}/takeover -- interactive human takeover of a sandbox session's shell: a raw duplex byte stream proxied straight through to the sandbox's PTY (see docs/API.md). There is no message envelope -- send and receive raw bytes on the returned connection exactly as you would over a local terminal (conn.WriteMessage(websocket.BinaryMessage, data) / conn.ReadMessage()).

Like sdk-python's takeover() (and unlike sdk-js's, which is constrained by the browser WebSocket API's inability to set a custom header), this authenticates with a normal `Authorization: Bearer <apiKey>` header on the upgrade request -- Go's websocket.Dialer, like Python's `websockets` library, can set arbitrary headers on the handshake. Requires an "admin"-role API key; a "member"-role key closes the connection with WS close code 4403 (see SECURITY.md's "Human takeover" section). A missing/invalid API key closes with 4401; an unowned or already-destroyed sessionID closes with 4404 -- both surface as an error from the first ReadMessage/WriteMessage call, since the close happens after the opening handshake completes.

The caller must call Close on the returned *websocket.Conn once done.

func (*Client) Usage

func (c *Client) Usage(ctx context.Context) (*Usage, error)

Usage returns current usage against fair-use limits.

func (*Client) VerifyEmail

func (c *Client) VerifyEmail(ctx context.Context, token string) (*MessageResponse, error)

VerifyEmail consumes a single-use email-verification token (POST /v1/auth/verify-email), opt-in (BOXXKITE_EMAIL_VERIFICATION_ENABLED).

func (*Client) View

func (c *Client) View(ctx context.Context, sessionID, path string, opts *ViewOptions) (*FileViewResult, error)

View reads a text file's contents (optionally a line range), or lists a directory's entries (POST /v1/sandboxes/{id}/files/view). Binary/image files are not supported.

func (*Client) Watch

func (c *Client) Watch(ctx context.Context, sessionID string) (*LogWatcher, error)

Watch opens the audit-log SSE stream for a session (GET /v1/sandboxes/{id}/watch). The caller must call Close on the returned *LogWatcher once done.

func (*Client) WithSandbox

func (c *Client) WithSandbox(ctx context.Context, req CreateSandboxRequest, fn func(*Session) error) error

WithSandbox is the create-on-enter, destroy-on-exit convenience -- mirroring sdk-python's `with client.sandbox() as sb:` context manager / sdk-js's withSandbox. It creates a sandbox from req, invokes fn with a *Session bound to it, and destroys the sandbox when fn returns (even if fn returns an error) -- teardown itself is best-effort, mirroring both sibling SDKs' "an already-gone session shouldn't raise on cleanup" behavior.

Example
mux := http.NewServeMux()
mux.HandleFunc("POST /v1/sandboxes", func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, `{"id":"sbx_123","status":"running","created_at":"2026-01-01T00:00:00Z"}`)
})
mux.HandleFunc("POST /v1/sandboxes/{id}/exec", func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, `{"exit_code":0,"stdout":"2\n","stderr":""}`)
})
mux.HandleFunc("POST /v1/sandboxes/{id}/files", func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, `{"path":"hello.txt","size":32,"created":true}`)
})
mux.HandleFunc("POST /v1/sandboxes/{id}/files/view", func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, `{"content":"hello from boxxkite-client (go)\n","lines":1,"is_directory":false}`)
})
mux.HandleFunc("DELETE /v1/sandboxes/{id}", func(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNoContent)
})
client, server := exampleServer(mux)
defer server.Close()

ctx := context.Background()
err := client.WithSandbox(ctx, CreateSandboxRequest{Label: Ptr("sdk-go-example")}, func(sb *Session) error {
	result, err := sb.Exec(ctx, "python3 -c 'print(1 + 1)'", nil)
	if err != nil {
		return err
	}
	fmt.Println(strings.TrimSpace(result.Stdout))

	if _, err := sb.FileCreate(ctx, "hello.txt", "hello from boxxkite-client (go)\n", nil); err != nil {
		return err
	}
	viewed, err := sb.View(ctx, "hello.txt", nil)
	if err != nil {
		return err
	}
	fmt.Println(strings.TrimSpace(viewed.Content))
	return nil
})
if err != nil {
	fmt.Println("error:", err)
	return
}
Output:
2
hello from boxxkite-client (go)

type ConnectionError

type ConnectionError struct {
	Message string
	Err     error
}

ConnectionError wraps a failure to reach the control-plane at all (DNS, TLS, timeout, connection refused) -- as opposed to a reachable server returning an error response (see APIError). Mirrors sdk-python's BoxxkiteConnectionError / sdk-js's BoxxkiteConnectionError.

func (*ConnectionError) Error

func (e *ConnectionError) Error() string

func (*ConnectionError) Unwrap

func (e *ConnectionError) Unwrap() error

type CreateImageRequest

type CreateImageRequest struct {
	// Label is an optional human-readable label for the image.
	Label *string `json:"label,omitempty"`
	// Base is one of "boxxkite-default", "boxxkite-minimal", "boxxkite-node",
	// "boxxkite-go". Defaults to "boxxkite-default" server-side when empty.
	// "boxxkite-node" drops Python entirely (no PythonPackages installable,
	// only AptPackages/NpmPackages); "boxxkite-go" drops both Python and
	// Node entirely (no PythonPackages or NpmPackages installable, only
	// AptPackages).
	Base string `json:"base,omitempty"`
	// PythonPackages are exact-version-pinned packages ("name==version",
	// no ranges) to install into the image.
	PythonPackages []string `json:"python_packages,omitempty"`
	// AptPackages are exact-version-pinned apt packages ("name==version",
	// no ranges) to install into the image.
	AptPackages []string `json:"apt_packages,omitempty"`
	// NpmPackages are exact-version-pinned npm packages ("name==version"
	// or "@scope/name==version", no ranges) to install into the image. Not
	// supported on Base="boxxkite-go".
	NpmPackages []string `json:"npm_packages,omitempty"`
}

CreateImageRequest is the request body for CreateImage (POST /v1/images). All fields are optional -- a zero-value CreateImageRequest{} builds an unmodified "boxxkite-default" image.

type CreateSandboxRequest

type CreateSandboxRequest struct {
	// Label is an optional human-readable label for the sandbox.
	Label *string `json:"label,omitempty"`
	// Size is one of "small", "medium", "large". Defaults to "small"
	// server-side when omitted.
	Size *string `json:"size,omitempty"`
	// StorageGB is the requested persistent storage in GB.
	StorageGB *float64 `json:"storage_gb,omitempty"`
	// LifetimeMinutes is the maximum lifetime of the sandbox in minutes
	// before automatic teardown.
	LifetimeMinutes *int `json:"lifetime_minutes,omitempty"`
	// Count is the number of sandboxes to create in this request.
	Count *int `json:"count,omitempty"`
	// SecretNames names this account's secrets (see docs/SECRETS-DESIGN.md)
	// this session should be granted access to via the sidecar's
	// secrets-broker HTTPRequest tool. A name that doesn't exist for this
	// account 404s before any sandbox is created.
	SecretNames []string `json:"secret_names,omitempty"`
	// ImageID is the id of a completed custom image built via CreateImage.
	// If set, the sandbox uses that digest-pinned image instead of the
	// operator's default. 404s if not owned by this account or not yet
	// status "completed".
	ImageID *string `json:"image_id,omitempty"`
	// MCPConnectionNames names this account's outbound-MCP connections
	// (see CreateMCPConnection) this session should be granted network
	// egress to. A name that doesn't exist for this account 404s before
	// any sandbox is created, same precedent as SecretNames.
	MCPConnectionNames []string `json:"mcp_connection_names,omitempty"`
	// VolumeMounts is an optional {volume_id: mount_path} mapping of
	// independent PVC-backed volumes (see CreateVolume) to mount into
	// this sandbox.
	VolumeMounts map[string]string `json:"volume_mounts,omitempty"`
	// GPUCount is opt-in and experimental (docs/GPU-SUPPORT-SCOPING.md) --
	// it requests this many GPUs as a Kubernetes extended-resource limit.
	// 422s (gpu_support_disabled) unless the deployment has
	// BOXXKITE_GPU_ENABLED set and a GPU-equipped node pool with a device
	// plugin provisioned; not verified against real GPU hardware in this
	// codebase.
	GPUCount *int `json:"gpu_count,omitempty"`
}

CreateSandboxRequest is the request body for CreateSandbox (POST /v1/sandboxes). All fields are optional -- a zero-value CreateSandboxRequest{} creates one default "small" sandbox. Use Ptr(...) to populate the pointer-typed fields, e.g. boxxkite.CreateSandboxRequest{Size: boxxkite.Ptr("medium")}.

type CreateSecretRequest

type CreateSecretRequest struct {
	// Name is the unique (per-account) name used to reference this secret
	// from CreateSandboxRequest.SecretNames and from an agent tool call as
	// {{secret:name}} in a POST /http-request body/header.
	Name string `json:"name"`
	// Value is the real credential value. Write-only -- accepted here and
	// never returned by this or any other route, including this response.
	Value string `json:"value"`
	// AllowedHosts are the destination hostnames this secret may be used
	// against via POST /http-request. Required, not optional -- an
	// unscoped secret usable against any destination defeats the point of
	// this feature. A host that resolves to a private/link-local/loopback/
	// metadata address is rejected at creation time (a best-effort
	// backstop; see docs/SECRETS-DESIGN.md §5 for why the real control is
	// the sidecar's request-time check).
	AllowedHosts []string `json:"allowed_hosts"`
	// TrustTier is only meaningful for wallet/private-key-style secrets
	// (docs/WALLET-SECRETS-DESIGN.md) -- omit for an ordinary API-key-style
	// secret. The only accepted value today is "testnet"; "mainnet" is
	// refused (422).
	TrustTier *string `json:"trust_tier,omitempty"`
}

CreateSecretRequest is the request body for CreateSecret (POST /v1/secrets).

type CreateVolumeRequest

type CreateVolumeRequest struct {
	// Label is an optional human-readable label for the volume.
	Label *string `json:"label,omitempty"`
	// SizeGB is the requested volume size in GB (max 1024).
	SizeGB float64 `json:"size_gb"`
}

CreateVolumeRequest is the request body for CreateVolume (POST /v1/volumes).

type CreateWebhookRequest

type CreateWebhookRequest struct {
	// URL is the HTTPS (or HTTP, for local testing) URL the control plane
	// will POST events to. Checked at registration time against the same
	// private/link-local/loopback/metadata-address denylist
	// CreateSandboxRequest's secrets use for allowed_hosts.
	URL string `json:"url"`
	// EventTypes are the event types this subscription should receive (at
	// least one required) -- "sandbox.created", "sandbox.destroyed", or
	// "audit_log.entry" (added per GitHub issue #125 for SIEM/audit-log
	// export). See docs/WEBHOOKS-DESIGN.md for the full event catalog.
	EventTypes []string `json:"event_types"`
	// Description is an optional caller-supplied label for this
	// subscription (e.g. "Slack notifier").
	Description *string `json:"description,omitempty"`
}

CreateWebhookRequest is the request body for CreateWebhook (POST /v1/webhooks).

type DirEntry

type DirEntry struct {
	Path  string `json:"path"`
	IsDir bool   `json:"is_dir"`
	Size  int64  `json:"size"`
}

DirEntry is one entry returned by View (for a directory path), Ls, or Glob.

type EgressDeniedError added in v0.6.0

type EgressDeniedError struct{ APIError }

func (*EgressDeniedError) Error added in v0.6.0

func (e *EgressDeniedError) Error() string

func (*EgressDeniedError) Unwrap added in v0.6.0

func (e *EgressDeniedError) Unwrap() error

type ExecOptions

type ExecOptions struct {
	// Timeout bounds the command's runtime in seconds (1-100, server
	// default 30). A command that outlives it is killed and reported as
	// failed.
	Timeout *int
	// Description is an optional caller-supplied label for this exec call,
	// surfaced in the audit log (GetLog/Watch).
	Description *string
}

ExecOptions carries the optional parameters for Exec.

type ExecResult

type ExecResult struct {
	ExitCode int    `json:"exit_code"`
	Stdout   string `json:"stdout"`
	Stderr   string `json:"stderr"`
}

ExecResult is the response shape from Exec (POST /v1/sandboxes/{id}/exec).

type FileCreateResult

type FileCreateResult struct {
	Path    string `json:"path"`
	Size    int    `json:"size"`
	Created bool   `json:"created"`
}

FileCreateResult is the response shape from FileCreate.

type FileOptions

type FileOptions struct {
	Description *string
}

FileOptions carries the optional description field shared by every file operation below.

type FileViewResult

type FileViewResult struct {
	Content     string     `json:"content"`
	Lines       int        `json:"lines"`
	IsDirectory bool       `json:"is_directory"`
	Entries     []DirEntry `json:"entries"`
}

FileViewResult is the response shape from View. Entries is populated (Content/Lines left zero) when the target path is a directory.

type GetLogOptions

type GetLogOptions struct {
	Limit  *int
	Offset *int
}

GetLogOptions carries the optional pagination parameters for GetLog.

type GetLogResult

type GetLogResult struct {
	Entries []LogEntry `json:"entries"`
	Limit   int        `json:"limit"`
	Offset  int        `json:"offset"`
	Total   int        `json:"total"`
}

GetLogResult is the response shape from GetLog.

type GlobResult

type GlobResult struct {
	Matches []DirEntry `json:"matches"`
}

GlobResult is the response shape from Glob.

type GrepMatch

type GrepMatch struct {
	Path string `json:"path"`
	Line int    `json:"line"`
	Text string `json:"text"`
}

GrepMatch is one match returned by Grep.

type GrepOptions

type GrepOptions struct {
	// Path defaults to "/".
	Path string
	// Glob optionally restricts matches to files whose name matches this
	// glob pattern.
	Glob string
	// MaxMatches defaults to 500 and is capped at 5000 server-side.
	MaxMatches int
}

GrepOptions carries the optional parameters for Grep.

type GrepResult

type GrepResult struct {
	Matches   []GrepMatch `json:"matches"`
	Error     *string     `json:"error"`
	Truncated bool        `json:"truncated"`
}

GrepResult is the response shape from Grep.

type HTTPRequestOptions

type HTTPRequestOptions struct {
	Headers map[string]string
	Body    *string
	Timeout *int
}

HTTPRequestOptions carries the optional parameters for HTTPRequest.

type HTTPRequestResult

type HTTPRequestResult struct {
	StatusCode int               `json:"status_code"`
	Headers    map[string]string `json:"headers"`
	Body       string            `json:"body"`
	Truncated  bool              `json:"truncated"`
}

HTTPRequestResult is the response shape from HTTPRequest (POST /v1/sandboxes/{id}/http-request).

type Image

type Image struct {
	ID             string         `json:"id"`
	Label          *string        `json:"label"`
	Base           string         `json:"base"`
	PythonPackages []string       `json:"python_packages"`
	AptPackages    []string       `json:"apt_packages"`
	NpmPackages    []string       `json:"npm_packages"`
	Status         string         `json:"status"`
	Digest         *string        `json:"digest"`
	RegistryRef    *string        `json:"registry_ref"`
	ScanResult     map[string]any `json:"scan_result"`
	FailureReason  *string        `json:"failure_reason"`
	CreatedAt      string         `json:"created_at"`
	CompletedAt    *string        `json:"completed_at"`
}

Image is a custom sandbox image, as returned by CreateImage/GetImage/ ListImages.

type ImportMemoriesRequest added in v0.7.0

type ImportMemoriesRequest struct {
	Memories  []map[string]any `json:"memories"`
	Relations []map[string]any `json:"relations,omitempty"`
}

ImportMemoriesRequest is the request body for ImportMemories (POST /v1/memory/import).

type IngestMemoryRequest added in v0.7.0

type IngestMemoryRequest struct {
	Content         string         `json:"content"`
	Scope           string         `json:"scope,omitempty"`
	SourceSessionID *string        `json:"source_session_id,omitempty"`
	Metadata        map[string]any `json:"metadata,omitempty"`
}

IngestMemoryRequest is the request body for IngestMemory (POST /v1/memory/ingest).

type ListMemoriesOptions added in v0.7.0

type ListMemoriesOptions struct {
	Scope             string
	IncludeSuperseded bool
	Limit             int
	Offset            int
}

ListMemoriesOptions configures ListMemories.

type ListWebhookDeliveriesOptions

type ListWebhookDeliveriesOptions struct {
	// Limit is the maximum number of entries to return (server default
	// 20, max 100).
	Limit *int
	// Offset is the number of entries to skip, newest-first.
	Offset *int
}

ListWebhookDeliveriesOptions carries the optional pagination parameters for ListWebhookDeliveries.

type LogEntry

type LogEntry struct {
	ID              string          `json:"id"`
	SessionID       string          `json:"session_id"`
	Source          string          `json:"source"`
	Operation       string          `json:"operation"`
	Detail          json.RawMessage `json:"detail"`
	ExitCode        *int            `json:"exit_code"`
	OutputTruncated string          `json:"output_truncated"`
	StartedAt       string          `json:"started_at"`
	DurationMs      *int64          `json:"duration_ms"`
	RowHash         *string         `json:"row_hash"`
	PrevHash        *string         `json:"prev_hash"`
}

LogEntry is one row of a session's exec/file-operation audit trail, as returned by GetLog and streamed by Watch (docs/SANDBOX-OBSERVABILITY-DESIGN.md).

type LogWatcher

type LogWatcher struct {
	// contains filtered or unexported fields
}

LogWatcher streams new audit-log entries for a session as they're written (GET /v1/sandboxes/{id}/watch), one LogEntry per Server-Sent Event `data:` line. Use it like bufio.Scanner:

watcher, err := client.Watch(ctx, sessionID)
if err != nil { ... }
defer watcher.Close()
for watcher.Next() {
	entry := watcher.Entry()
	// ...
}
if err := watcher.Err(); err != nil { ... }

Next blocks until either a new entry arrives, the stream ends, or ctx is canceled. This is a live feed of exec/file operations as the control-plane logs them, not a live terminal -- see Takeover for that.

func (*LogWatcher) Close

func (w *LogWatcher) Close() error

Close closes the underlying HTTP response body, ending the stream.

func (*LogWatcher) Entry

func (w *LogWatcher) Entry() LogEntry

Entry returns the most recent entry produced by Next.

func (*LogWatcher) Err

func (w *LogWatcher) Err() error

Err returns the first error encountered while streaming, if any (nil if the stream simply ended).

func (*LogWatcher) Next

func (w *LogWatcher) Next() bool

Next advances to the next streamed LogEntry, blocking until one arrives. It returns false when the stream ends (server closed it, context canceled, or a decode error) -- check Err to distinguish a clean end from an error.

type LsResult

type LsResult struct {
	Entries []DirEntry `json:"entries"`
}

LsResult is the response shape from Ls.

type MCPConnection

type MCPConnection struct {
	ID         string  `json:"id"`
	Label      string  `json:"label"`
	CatalogID  string  `json:"catalog_id"`
	Host       string  `json:"host"`
	CreatedAt  string  `json:"created_at"`
	LastUsedAt *string `json:"last_used_at"`
}

MCPConnection is an outbound-MCP connection grant, as returned by CreateMCPConnection/ListMCPConnections (GitHub issues #116/#117, docs/OUTBOUND-MCP-DESIGN.md).

type Memory added in v0.7.0

type Memory struct {
	ID              string         `json:"id"`
	Scope           string         `json:"scope"`
	Kind            string         `json:"kind"`
	Content         string         `json:"content"`
	Metadata        map[string]any `json:"metadata"`
	SourceSessionID *string        `json:"source_session_id"`
	CreatedAt       string         `json:"created_at"`
	UpdatedAt       string         `json:"updated_at"`
	ExpiresAt       *string        `json:"expires_at"`
	SourceContent   *string        `json:"source_content"`
	DocumentDate    *string        `json:"document_date"`
	EventDates      []string       `json:"event_dates"`
	Importance      float64        `json:"importance"`
	AccessCount     int            `json:"access_count"`
	LastAccessedAt  *string        `json:"last_accessed_at"`
	SupersededAt    *string        `json:"superseded_at"`
	SupersededByID  *string        `json:"superseded_by_id"`
}

Memory is one durable, account-scoped memory (MemoryBase -- POST/GET /v1/memory).

type MemoryIngestResponse added in v0.7.0

type MemoryIngestResponse struct {
	SourceSessionID *string  `json:"source_session_id"`
	Memories        []Memory `json:"memories"`
}

MemoryIngestResponse is the response from IngestMemory and ImportMemories.

type MemoryProfileResponse added in v0.7.0

type MemoryProfileResponse struct {
	Static  []Memory `json:"static"`
	Dynamic []Memory `json:"dynamic"`
}

MemoryProfileResponse is the response from MemoryProfile (GET /v1/memory/profile) -- stable, long-lived memories separated from recently-touched ones.

type MemoryRelation added in v0.7.0

type MemoryRelation struct {
	SourceMemoryID string  `json:"source_memory_id"`
	TargetMemoryID string  `json:"target_memory_id"`
	RelationType   string  `json:"relation_type"`
	Confidence     float64 `json:"confidence"`
	CreatedAt      string  `json:"created_at"`
}

MemoryRelation is one edge from MemoryRelations.

type MemoryRelationsResponse added in v0.7.0

type MemoryRelationsResponse struct {
	MemoryID  string           `json:"memory_id"`
	Relations []MemoryRelation `json:"relations"`
}

MemoryRelationsResponse is the response from MemoryRelations (GET /v1/memory/{id}/relations).

type MemorySearchHit added in v0.7.0

type MemorySearchHit struct {
	Memory
	Score float64 `json:"score"`
}

MemorySearchHit is a memory returned from Recall, with its retrieval score.

type MemorySearchResponse added in v0.7.0

type MemorySearchResponse struct {
	Query    string            `json:"query"`
	Memories []MemorySearchHit `json:"memories"`
}

MemorySearchResponse is the response from Recall (GET /v1/memory/search).

type MessageResponse

type MessageResponse struct {
	Message string `json:"message"`
}

MessageResponse is a generic ack body (e.g. password-reset request, which always returns the same message regardless of whether the email is registered).

type Option

type Option func(*Client)

Option configures a Client constructed via NewClient.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient overrides the *http.Client used for requests. Primarily useful for tests (point it at an httptest.Server) or for customizing transport-level behavior (proxies, custom TLS config).

func WithRetry

func WithRetry(cfg RetryConfig) Option

WithRetry enables automatic retry of transient failures. Retry is off by default -- pass this option (ideally starting from DefaultRetryConfig()) to turn it on. Only idempotent verbs are retried, and only on a connection failure or a retriable status (429 + transient 5xx); a non-idempotent POST is never retried, so this cannot double-create a resource. Zero-valued BackoffBase/BackoffMax/Statuses/ Methods fields are filled in from the defaults, so WithRetry(RetryConfig{MaxRetries: 3}) is valid -- but RespectRetryAfter stays false unless set, so prefer DefaultRetryConfig() as a base.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout overrides the default per-request timeout (DefaultTimeout).

func WithWebSocketDialer

func WithWebSocketDialer(d *websocket.Dialer) Option

WithWebSocketDialer overrides the *websocket.Dialer used by Takeover. Primarily useful for tests.

type PreviewRevokeResult

type PreviewRevokeResult struct {
	Revoked bool   `json:"revoked"`
	TokenID string `json:"token_id"`
}

PreviewRevokeResult is the response shape from RevokePreviewURL.

type PreviewURL

type PreviewURL struct {
	URL       string `json:"url"`
	ExpiresAt string `json:"expires_at"`
	TokenID   string `json:"token_id"`
}

PreviewURL is the response shape from CreatePreviewURL.

type ProcessInfo

type ProcessInfo struct {
	ProcessID   string  `json:"process_id"`
	Command     string  `json:"command"`
	Description *string `json:"description"`
	Status      string  `json:"status"`
	StartedAt   string  `json:"started_at"`
	ExitCode    *int    `json:"exit_code"`
}

ProcessInfo is one tracked background process, as returned by ListProcesses.

type ProcessInputResult

type ProcessInputResult struct {
	BytesWritten int `json:"bytes_written"`
}

ProcessInputResult is the response shape from SendProcessInput.

type ProcessListResult

type ProcessListResult struct {
	Processes []ProcessInfo `json:"processes"`
}

ProcessListResult is the response shape from ListProcesses.

type ProcessOutputResult

type ProcessOutputResult struct {
	Status      string `json:"status"`
	StdoutChunk string `json:"stdout_chunk"`
	NextOffset  int64  `json:"next_offset"`
	Truncated   bool   `json:"truncated"`
	ExitCode    *int   `json:"exit_code"`
}

ProcessOutputResult is the response shape from GetProcessOutput.

type ProcessStartResult

type ProcessStartResult struct {
	ProcessID string `json:"process_id"`
	Status    string `json:"status"`
	StartedAt string `json:"started_at"`
}

ProcessStartResult is the response shape from StartProcess.

type ProcessStopResult

type ProcessStopResult struct {
	Status   string `json:"status"`
	ExitCode *int   `json:"exit_code"`
}

ProcessStopResult is the response shape from StopProcess.

type ProcessStream

type ProcessStream struct {
	// contains filtered or unexported fields
}

ProcessStream streams a background process's stdout as Server-Sent Events (GET /v1/sandboxes/{id}/processes/{processId}/stream), the streaming counterpart to GetProcessOutput. Use it like bufio.Scanner:

stream, err := client.StreamProcessOutput(ctx, sessionID, processID, 0)
if err != nil { ... }
defer stream.Close()
for stream.Next() {
	ev := stream.Event()
	// ev.Type == "output" | "exit"
}
if err := stream.Err(); err != nil { ... }

func (*ProcessStream) Close

func (s *ProcessStream) Close() error

Close closes the underlying HTTP response body, ending the stream.

func (*ProcessStream) Err

func (s *ProcessStream) Err() error

Err returns the first error encountered while streaming, if any.

func (*ProcessStream) Event

func (s *ProcessStream) Event() ProcessStreamEvent

Event returns the most recent event produced by Next.

func (*ProcessStream) Next

func (s *ProcessStream) Next() bool

Next advances to the next streamed event, blocking until one arrives. It returns false when the stream ends -- check Err to distinguish a clean end from an error.

type ProcessStreamEvent

type ProcessStreamEvent struct {
	Type        string `json:"type"`
	StdoutChunk string `json:"stdout_chunk"`
	NextOffset  int64  `json:"next_offset"`
	Truncated   bool   `json:"truncated"`
	Status      string `json:"status"`
	ExitCode    *int   `json:"exit_code"`
}

ProcessStreamEvent is one event from StreamProcessOutput. Type is "output" (StdoutChunk/NextOffset/Truncated populated) for each new chunk, then "exit" (Status/ExitCode populated) once the process finishes.

type QuotaExceededError added in v0.6.0

type QuotaExceededError struct{ APIError }

Named errors allow callers to use errors.As for the most actionable sandbox failures while APIError remains the common compatibility shape.

func (*QuotaExceededError) Error added in v0.6.0

func (e *QuotaExceededError) Error() string

func (*QuotaExceededError) Unwrap added in v0.6.0

func (e *QuotaExceededError) Unwrap() error

Unwrap lets errors.As(err, &apiErr) reach the embedded APIError, which is what sdk-go's README promises ("Every non-2xx response returns a *boxxkite.APIError"). Without it the typed errors embed APIError by value with no link in the chain, so errors.As failed for exactly the codes callers branch on -- quota, egress, not-ready -- and they lost access to StatusCode and Code.

type ReadonlyFilesystemError added in v0.6.0

type ReadonlyFilesystemError struct{ APIError }

func (*ReadonlyFilesystemError) Error added in v0.6.0

func (e *ReadonlyFilesystemError) Error() string

func (*ReadonlyFilesystemError) Unwrap added in v0.6.0

func (e *ReadonlyFilesystemError) Unwrap() error

type RecallOptions added in v0.7.0

type RecallOptions struct {
	Scope string
	Limit int
}

RecallOptions configures Recall.

type RememberRequest added in v0.7.0

type RememberRequest struct {
	Content         string         `json:"content"`
	Scope           string         `json:"scope,omitempty"`
	Kind            string         `json:"kind,omitempty"`
	Metadata        map[string]any `json:"metadata,omitempty"`
	SourceSessionID *string        `json:"source_session_id,omitempty"`
	Importance      *float64       `json:"importance,omitempty"`
}

RememberRequest is the request body for Remember (POST /v1/memory).

type RetryConfig

type RetryConfig struct {
	// MaxRetries is the number of retries after the initial attempt (so a
	// total of MaxRetries+1 attempts). 0 disables retry.
	MaxRetries int
	// BackoffBase is the base of the exponential backoff (delay for the
	// first retry is drawn from [0, BackoffBase)).
	BackoffBase time.Duration
	// BackoffMax caps any single backoff (and any honored Retry-After).
	BackoffMax time.Duration
	// Statuses is the set of response status codes that trigger a retry.
	Statuses map[int]bool
	// Methods is the set of (idempotent) HTTP verbs eligible for retry.
	Methods map[string]bool
	// RespectRetryAfter honors a server-supplied Retry-After header (delta
	// seconds or HTTP-date) in preference to computed backoff.
	RespectRetryAfter bool
}

RetryConfig configures automatic retry of transient failures. Enable it via WithRetry; retry is off entirely when no RetryConfig is set.

func DefaultRetryConfig

func DefaultRetryConfig() RetryConfig

DefaultRetryConfig is the recommended starting point for WithRetry: 2 retries, exponential backoff with full jitter (500ms base, 30s cap), retry on 429/500/502/503/504 for idempotent verbs, Retry-After honored.

type Sandbox

type Sandbox struct {
	ID          string              `json:"id"`
	Status      string              `json:"status"`
	Label       *string             `json:"label"`
	CreatedAt   string              `json:"created_at"`
	DestroyedAt *string             `json:"destroyed_at"`
	ExpiresAt   *string             `json:"expires_at"`
	Connect     *SandboxConnectInfo `json:"connect,omitempty"`
	Usage       *Usage              `json:"usage,omitempty"`
}

Sandbox is one sandbox session (GET/POST /v1/sandboxes response shape).

type SandboxConnectInfo

type SandboxConnectInfo struct {
	PodName string `json:"pod_name"`
	Note    string `json:"note"`
}

SandboxConnectInfo is opaque connection metadata for operators with cluster access -- external callers operate on a session exclusively through the exec/files/* routes, never this directly.

type SandboxCrashedError added in v0.6.0

type SandboxCrashedError struct{ APIError }

func (*SandboxCrashedError) Error added in v0.6.0

func (e *SandboxCrashedError) Error() string

func (*SandboxCrashedError) Unwrap added in v0.6.0

func (e *SandboxCrashedError) Unwrap() error

type SandboxNotReadyError added in v0.6.0

type SandboxNotReadyError struct{ APIError }

func (*SandboxNotReadyError) Error added in v0.6.0

func (e *SandboxNotReadyError) Error() string

func (*SandboxNotReadyError) Unwrap added in v0.6.0

func (e *SandboxNotReadyError) Unwrap() error

type Secret

type Secret struct {
	ID           string   `json:"id"`
	Name         string   `json:"name"`
	AllowedHosts []string `json:"allowed_hosts"`
	TrustTier    *string  `json:"trust_tier"`
	CreatedAt    string   `json:"created_at"`
	LastUsedAt   *string  `json:"last_used_at"`
}

Secret is a secret's metadata, as returned by CreateSecret/ListSecrets. The raw value is never included here or anywhere else after creation.

type ServiceUnavailableError added in v0.6.0

type ServiceUnavailableError struct{ APIError }

func (*ServiceUnavailableError) Error added in v0.6.0

func (e *ServiceUnavailableError) Error() string

func (*ServiceUnavailableError) Unwrap added in v0.6.0

func (e *ServiceUnavailableError) Unwrap() error

type Session

type Session struct {
	ID string
	// contains filtered or unexported fields
}

Session is a thin, session-scoped view over Client -- every method forwards to the identically-named Client method with this Session's ID as the sessionID argument. Obtained via WithSandbox; mirrors sdk-python's SandboxSession / sdk-js's SandboxSession.

func (*Session) CreatePreviewURL

func (s *Session) CreatePreviewURL(ctx context.Context, port int, ttlSeconds *int) (*PreviewURL, error)

func (*Session) DesktopTakeover

func (s *Session) DesktopTakeover(ctx context.Context) (*websocket.Conn, error)

func (*Session) Exec

func (s *Session) Exec(ctx context.Context, command string, opts *ExecOptions) (*ExecResult, error)

func (*Session) FileCreate

func (s *Session) FileCreate(ctx context.Context, path, content string, opts *FileOptions) (*FileCreateResult, error)

func (*Session) GetLog

func (s *Session) GetLog(ctx context.Context, opts *GetLogOptions) (*GetLogResult, error)

func (*Session) GetProcessOutput

func (s *Session) GetProcessOutput(ctx context.Context, processID string, sinceOffset int64) (*ProcessOutputResult, error)

func (*Session) Glob

func (s *Session) Glob(ctx context.Context, pattern, path string) (*GlobResult, error)

func (*Session) Grep

func (s *Session) Grep(ctx context.Context, pattern string, opts *GrepOptions) (*GrepResult, error)

func (*Session) HTTPRequest

func (s *Session) HTTPRequest(ctx context.Context, method, targetURL string, opts *HTTPRequestOptions) (*HTTPRequestResult, error)

func (*Session) ListProcesses

func (s *Session) ListProcesses(ctx context.Context) (*ProcessListResult, error)

func (*Session) Ls

func (s *Session) Ls(ctx context.Context, path string) (*LsResult, error)

func (*Session) RevokePreviewURL

func (s *Session) RevokePreviewURL(ctx context.Context, port int, tokenID string) (*PreviewRevokeResult, error)

func (*Session) SendProcessInput

func (s *Session) SendProcessInput(ctx context.Context, processID, data string) (*ProcessInputResult, error)

func (*Session) StartProcess

func (s *Session) StartProcess(ctx context.Context, command string, opts *StartProcessOptions) (*ProcessStartResult, error)

func (*Session) StopProcess

func (s *Session) StopProcess(ctx context.Context, processID string) (*ProcessStopResult, error)

func (*Session) StrReplace

func (s *Session) StrReplace(ctx context.Context, path, oldStr, newStr string, opts *StrReplaceOptions) (*StrReplaceResult, error)

func (*Session) Takeover

func (s *Session) Takeover(ctx context.Context) (*websocket.Conn, error)

func (*Session) View

func (s *Session) View(ctx context.Context, path string, opts *ViewOptions) (*FileViewResult, error)

func (*Session) Watch

func (s *Session) Watch(ctx context.Context) (*LogWatcher, error)

type StartProcessOptions

type StartProcessOptions struct {
	Description *string
	// MaxRuntimeSeconds is a hard ceiling on how long the process may run
	// before being force-killed. Defaults to 3600.
	MaxRuntimeSeconds int
	// ExposePort, if set, makes this process's listening port reachable
	// via a preview URL (see CreatePreviewURL).
	ExposePort *int
}

StartProcessOptions carries the optional parameters for StartProcess.

type StrReplaceOptions

type StrReplaceOptions struct {
	ReplaceAll  bool
	Description *string
}

StrReplaceOptions carries the optional parameters for StrReplace.

type StrReplaceResult

type StrReplaceResult struct {
	Path        string `json:"path"`
	Replaced    bool   `json:"replaced"`
	Occurrences int    `json:"occurrences"`
}

StrReplaceResult is the response shape from StrReplace.

type TokenPair

type TokenPair struct {
	AccessToken  string  `json:"access_token"`
	TokenType    string  `json:"token_type"`
	ExpiresIn    int     `json:"expires_in"`
	RefreshToken *string `json:"refresh_token"`
	Account      Account `json:"account"`
}

TokenPair is the response shape from RefreshToken -- a brand new access_token + refresh_token pair, plus the account identity.

type Usage

type Usage struct {
	MonthlySandboxHoursUsed  float64 `json:"monthly_sandbox_hours_used"`
	MonthlySandboxHoursLimit float64 `json:"monthly_sandbox_hours_limit"`
	ConcurrentSandboxes      int     `json:"concurrent_sandboxes"`
	ConcurrentSandboxesLimit int     `json:"concurrent_sandboxes_limit"`
}

Usage is the current usage against fair-use limits (GET /v1/usage), also returned inline on CreateSandbox's response.

type ViewOptions

type ViewOptions struct {
	// ViewRange is an optional [start_line, end_line] pair, 1-indexed.
	ViewRange   []int
	Description *string
}

ViewOptions carries the optional parameters for View.

type Volume

type Volume struct {
	ID            string  `json:"id"`
	Label         *string `json:"label"`
	SizeGB        float64 `json:"size_gb"`
	Status        string  `json:"status"`
	PVCName       *string `json:"pvc_name"`
	FailureReason *string `json:"failure_reason"`
	CreatedAt     string  `json:"created_at"`
}

Volume is an independent, PVC-backed storage volume, as returned by CreateVolume/GetVolume/ListVolumes.

type Webhook

type Webhook struct {
	ID              string   `json:"id"`
	URL             string   `json:"url"`
	EventTypes      []string `json:"event_types"`
	Description     *string  `json:"description"`
	IsActive        bool     `json:"is_active"`
	CreatedAt       string   `json:"created_at"`
	LastTriggeredAt *string  `json:"last_triggered_at"`
	// Secret is the raw signing secret, shown exactly once on the
	// CreateWebhook response. Use it to verify the
	// X-Boxxkite-Webhook-Signature header on every delivery; it cannot be
	// retrieved again after this response.
	Secret string `json:"secret,omitempty"`
}

Webhook is a webhook subscription, as returned by CreateWebhook/ ListWebhooks. Secret is only ever populated on CreateWebhook's response -- it is never returned by any other route.

type WebhookDelivery

type WebhookDelivery struct {
	ID                 string  `json:"id"`
	EventType          string  `json:"event_type"`
	Status             string  `json:"status"`
	AttemptCount       int     `json:"attempt_count"`
	NextAttemptAt      string  `json:"next_attempt_at"`
	LastAttemptAt      *string `json:"last_attempt_at"`
	ResponseStatusCode *int    `json:"response_status_code"`
	FailureReason      *string `json:"failure_reason"`
	CreatedAt          string  `json:"created_at"`
	DeliveredAt        *string `json:"delivered_at"`
}

WebhookDelivery is one delivery attempt for a webhook subscription, as returned by ListWebhookDeliveries.

Directories

Path Synopsis
Runnable end-to-end example against a real hosted control-plane.
Runnable end-to-end example against a real hosted control-plane.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL