arcp

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: May 22, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

README

ARCP Go SDK

License Go version

Go SDK for ARCP, the wire protocol an agent uses to talk to the runtime that hosts it. Ships a client, a server, transports for WebSocket / stdio / in-memory, OTel middleware, and the arcp CLI.

Install

go get github.com/agentruntimecontrolprotocol/go-sdk@latest

Packages

Import path Use when
.../go-sdk Envelope, errors, ids, feature constants, lease types.
.../go-sdk/client Building a client that talks to a runtime.
.../go-sdk/server Hosting agents.
.../go-sdk/transport Custom transports, or pairing MemoryTransport in tests.
.../go-sdk/messages Direct envelope construction (rare; clients and servers do it for you).
.../go-sdk/auth The Verifier interface for bearer-token authentication.
.../go-sdk/credentials Provisioner interface and in-memory lease-bound credential provider.
.../go-sdk/middleware/nethttp Attaching the WS upgrade to an existing *http.Server.
.../go-sdk/middleware/chi Mounting on a chi.Router.
.../go-sdk/middleware/otel W3C trace-context propagation per spec §11.
.../go-sdk/cmd/arcp arcp serve / arcp submit CLI.

Core concepts

  • Envelope (§5). Every wire message is arcp: "1.1" + id + type
    • payload, with optional session/job/event/trace ids. Unknown fields round-trip; v1.0 clients see future fields as opaque.
  • Session (§6). session.hellosession.welcome (or session.error); closes on session.bye or transport close.
  • Job (§7). job.submitjob.acceptedjob.event* → terminal job.resultjob.error.
  • Lease (§9). Capability namespace → glob patterns, immutable at submit. Optional expires_at and cost.budget add time and budget bounds; model.use gates runtime-mediated model calls.
  • Provisioned credentials (§9.8). Runtimes can issue short-lived, lease-bound credentials in job.accepted and revoke them on terminal job states.
  • Event (§8). One job.event envelope, payload.kind ∈ the ten reserved values plus x-vendor.*.
  • Subscribe (§7.6). Re-attach to a job from a different session. Subscribers observe; they cannot cancel.

Quickstart

package main

import (
    "context"
    "encoding/json"
    "log"

    "github.com/agentruntimecontrolprotocol/go-sdk/client"
    "github.com/agentruntimecontrolprotocol/go-sdk/server"
    "github.com/agentruntimecontrolprotocol/go-sdk/transport"
)

func main() {
    srv := server.New(server.Options{})
    srv.RegisterAgent("echo", func(ctx context.Context, input json.RawMessage, jc *server.JobContext) (any, error) {
        return map[string]json.RawMessage{"echo": input}, nil
    })

    a, b := transport.NewMemoryPair()
    ctx := context.Background()
    go srv.Accept(ctx, b)
    cli, err := client.Connect(ctx, a, client.Options{Token: "demo"})
    if err != nil {
        log.Fatal(err)
    }
    defer cli.Close(ctx)

    h, _ := cli.Submit(ctx, client.SubmitRequest{
        Agent: "echo",
        Input: map[string]string{"hi": "there"},
    })
    res, _ := h.Wait(ctx)
    log.Println("result:", string(res.Output))
}

Capabilities

Flag Section What it gates
heartbeat §6.4 session.ping/session.pong, watchdog
ack §6.5 session.ack, back-pressure status emission
list_jobs §6.6 session.list_jobs / session.jobs
subscribe §7.6 job.subscribe / job.subscribed / job.unsubscribe
agent_versions §7.5 name@version grammar; rich agents inventory
lease_expires_at §9.5 lease_constraints.expires_at
cost.budget §9.6 cost.budget lease capability and runtime counters
model.use §9.7 Model/profile lease capability
provisioned_credentials §9.8 Lease-bound credentials in job.accepted
progress §8.2.1 progress event kind
result_chunk §8.4 result_chunk event kind and streamed job.result

Examples

See examples/ for one runnable directory per scenario. Each has server/main.go, client/main.go, and a short README citing the spec section it exercises.

Conformance

The tests/conformance package emits a JSON summary against the spec sections via go test ./tests/conformance/.... See CONFORMANCE.md.

License

Apache-2.0.

Documentation

Overview

Package arcp implements the ARCP wire protocol: a transport-agnostic envelope for submitting, observing, and controlling long-running AI agent jobs.

The root package exposes the on-the-wire envelope, sentinel error values, identifier helpers, and protocol-version constants. Higher level code lives in the sibling packages:

The wire format is JSON; envelopes carry an [Envelope.Payload] as raw bytes so the read loop can hand off without parsing twice.

Index

Constants

View Source
const ProtocolVersion = "1.1"

ProtocolVersion is the literal value carried in every envelope's "arcp" field.

View Source
const SDKVersion = "1.1.0"

SDKVersion is the version of this Go SDK.

Variables

View Source
var (
	ErrPermissionDenied         = &Error{Code: CodePermissionDenied, Message: "permission denied", Retryable: false}
	ErrLeaseSubsetViolation     = &Error{Code: CodeLeaseSubsetViolation, Message: "lease subset violation", Retryable: false}
	ErrJobNotFound              = &Error{Code: CodeJobNotFound, Message: "job not found", Retryable: false}
	ErrDuplicateKey             = &Error{Code: CodeDuplicateKey, Message: "duplicate idempotency key", Retryable: false}
	ErrAgentNotAvailable        = &Error{Code: CodeAgentNotAvailable, Message: "agent not available", Retryable: false}
	ErrAgentVersionNotAvailable = &Error{Code: CodeAgentVersionNotAvailable, Message: "agent version not available", Retryable: false}
	ErrCancelled                = &Error{Code: CodeCancelled, Message: "cancelled", Retryable: false}
	ErrTimeout                  = &Error{Code: CodeTimeout, Message: "timeout", Retryable: false}
	ErrResumeWindowExpired      = &Error{Code: CodeResumeWindowExpired, Message: "resume window expired", Retryable: false}
	ErrHeartbeatLost            = &Error{Code: CodeHeartbeatLost, Message: "heartbeat lost", Retryable: true}
	ErrLeaseExpired             = &Error{Code: CodeLeaseExpired, Message: "lease expired", Retryable: false}
	ErrBudgetExhausted          = &Error{Code: CodeBudgetExhausted, Message: "budget exhausted", Retryable: false}
	ErrInvalidRequest           = &Error{Code: CodeInvalidRequest, Message: "invalid request", Retryable: false}
	ErrUnauthenticated          = &Error{Code: CodeUnauthenticated, Message: "unauthenticated", Retryable: false}
	ErrInternalError            = &Error{Code: CodeInternalError, Message: "internal error", Retryable: true}
)

Sentinel error values. Each maps to one ErrorCode. Use errors.Is against these to test for a particular code.

View Source
var Features = []string{
	"heartbeat",
	"ack",
	"list_jobs",
	"subscribe",
	"agent_versions",
	"lease_expires_at",
	"cost.budget",
	"model.use",
	"provisioned_credentials",
	"progress",
	"result_chunk",
}

Features is the canonical list of negotiable feature flags advertised in session.hello and session.welcome capabilities.

Functions

func HasFeature

func HasFeature(features []string, name string) bool

HasFeature reports whether name appears in features.

func IntersectFeatures

func IntersectFeatures(a, b []string) []string

IntersectFeatures returns the set of feature flags present in both a and b, in the order they appear in a. Used at handshake to compute the effective negotiated feature set.

func IsRetryable

func IsRetryable(err error) bool

IsRetryable reports whether err is structurally marked retryable. Non-arcp errors are conservatively reported as retryable so generic transport-level failures do not become fatal.

func MarshalPayload

func MarshalPayload(payload any) (json.RawMessage, error)

MarshalPayload encodes any value to json.RawMessage. nil and already-raw values pass through.

func NewCallID

func NewCallID() string

NewCallID returns a ULID prefixed with "c_" for tool_call.call_id.

func NewEnvelopeID

func NewEnvelopeID() string

NewEnvelopeID returns a UUIDv7. UUIDv7 carries a millisecond timestamp prefix and is suitable for the envelope id field.

func NewJobID

func NewJobID() string

NewJobID returns a ULID prefixed with "job_".

func NewPayloadForType

func NewPayloadForType(typ string) any

NewPayloadForType returns a zero value of the registered type for typ suitable for json.Unmarshal. It returns nil if typ is not registered.

func NewPingNonce

func NewPingNonce() string

NewPingNonce returns a ULID prefixed with "p_". The nonce is matched on session.pong; ULIDs are short and time-ordered.

func NewResultID

func NewResultID() string

NewResultID returns a ULID prefixed with "res_".

func NewSessionID

func NewSessionID() string

NewSessionID returns a ULID prefixed with "sess_".

func NewTraceID

func NewTraceID() string

NewTraceID returns a 32-character lowercase hex string suitable for the envelope trace_id field (matches W3C trace-context).

func NewULID

func NewULID() string

NewULID returns a Crockford-base32 ULID with the current wall-clock timestamp. ULIDs sort lexicographically; we use them for session/job/result/nonce identifiers so log scans stay ordered.

func RegisterMessageType

func RegisterMessageType(m MessageType)

RegisterMessageType associates the concrete struct behind m with its wire-type string. Each wire-type string may only be registered once; duplicate registration panics. Call from init() in messages/*.go.

func RegisteredTypes

func RegisteredTypes() []string

RegisteredTypes returns the names of every registered MessageType, useful for diagnostics.

Types

type BudgetAmount

type BudgetAmount struct {
	Currency Currency
	Value    float64
}

BudgetAmount is one entry in a cost.budget pattern list, of the form "USD:5.00".

func ParseBudgetAmount

func ParseBudgetAmount(s string) (BudgetAmount, error)

ParseBudgetAmount parses a cost.budget pattern entry per the spec grammar: amount ::= currency ":" decimal. Negative values are rejected.

func (BudgetAmount) String

func (b BudgetAmount) String() string

String returns the canonical "CUR:value" representation.

type Capability

type Capability string

Capability is the lease namespace identifier. The constants below enumerate spec-reserved namespaces; vendors may add their own string-valued capabilities.

const (
	CapFSRead        Capability = "fs.read"
	CapFSWrite       Capability = "fs.write"
	CapNetFetch      Capability = "net.fetch"
	CapToolCall      Capability = "tool.call"
	CapAgentDelegate Capability = "agent.delegate"
	CapModelUse      Capability = "model.use"
	CapCostBudget    Capability = "cost.budget"
)

Reserved capability namespaces.

type Currency

type Currency string

Currency is an ISO 4217 currency code, or the protocol-reserved "credits" string, or a runtime-defined identifier.

type Envelope

type Envelope struct {
	// ARCP is the protocol version literal. Always "1.1" on the wire.
	ARCP string `json:"arcp"`
	// ID is a unique message identifier (UUIDv7 recommended).
	ID string `json:"id"`
	// Type is the wire-type token, for example "job.submit".
	Type string `json:"type"`
	// SessionID identifies the owning session; empty on session.hello.
	SessionID string `json:"session_id,omitempty"`
	// JobID is set on job-scoped envelopes (job.*).
	JobID string `json:"job_id,omitempty"`
	// TraceID is a 32-hex-char W3C trace identifier when present.
	TraceID string `json:"trace_id,omitempty"`
	// EventSeq is the session-scoped monotonic sequence for
	// job.event / job.result / job.error. Zero on every other type.
	EventSeq uint64 `json:"event_seq,omitempty"`
	// Payload is the typed payload, kept raw so the dispatch loop can
	// hand it off to a registered MessageType without parsing twice.
	Payload json.RawMessage `json:"payload,omitempty"`
	// Extensions carries x-vendor.* namespaced opaque fields per the
	// spec extensions namespace.
	Extensions map[string]json.RawMessage `json:"extensions,omitempty"`
}

Envelope is the wire-level frame for every ARCP message. Field names map exactly onto the JSON object documented in the spec.

func NewEnvelope

func NewEnvelope(typ string, payload any) (Envelope, error)

NewEnvelope returns an Envelope with arcp/id pre-populated.

func (*Envelope) DecodePayload

func (e *Envelope) DecodePayload(v any) error

DecodePayload unmarshals e.Payload into v.

func (*Envelope) Validate

func (e *Envelope) Validate() error

Validate reports a structured *Error if the envelope is missing fields the protocol mandates.

type Error

type Error struct {
	Code      ErrorCode      `json:"code"`
	Message   string         `json:"message"`
	Retryable bool           `json:"retryable"`
	Details   map[string]any `json:"details,omitempty"`
	// contains filtered or unexported fields
}

Error is the structured ARCP error. It carries a code, a human message, a retry hint, optional structured details, and an optional wrapped cause.

func Newf

func Newf(code ErrorCode, format string, args ...any) *Error

Newf constructs an *Error with code and a formatted message.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

func (*Error) Is

func (e *Error) Is(target error) bool

Is matches by Code so wrapped errors satisfy errors.Is against sentinel values.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the wrapped cause, if any.

func (*Error) WithCause

func (e *Error) WithCause(cause error) *Error

WithCause returns a copy of e wrapping cause.

func (*Error) WithDetails

func (e *Error) WithDetails(details map[string]any) *Error

WithDetails returns a copy of e with details merged into Details.

func (*Error) WithMessage

func (e *Error) WithMessage(msg string) *Error

WithMessage returns a copy of e with msg as the human message.

type ErrorCode

type ErrorCode string

ErrorCode is the canonical string code for the protocol's error taxonomy. The fifteen codes below cover every spec-mandated rejection point.

const (
	CodePermissionDenied         ErrorCode = "PERMISSION_DENIED"
	CodeLeaseSubsetViolation     ErrorCode = "LEASE_SUBSET_VIOLATION"
	CodeJobNotFound              ErrorCode = "JOB_NOT_FOUND"
	CodeDuplicateKey             ErrorCode = "DUPLICATE_KEY"
	CodeAgentNotAvailable        ErrorCode = "AGENT_NOT_AVAILABLE"
	CodeAgentVersionNotAvailable ErrorCode = "AGENT_VERSION_NOT_AVAILABLE"
	CodeCancelled                ErrorCode = "CANCELLED"
	CodeTimeout                  ErrorCode = "TIMEOUT"
	CodeResumeWindowExpired      ErrorCode = "RESUME_WINDOW_EXPIRED"
	CodeHeartbeatLost            ErrorCode = "HEARTBEAT_LOST"
	CodeLeaseExpired             ErrorCode = "LEASE_EXPIRED"
	CodeBudgetExhausted          ErrorCode = "BUDGET_EXHAUSTED"
	CodeInvalidRequest           ErrorCode = "INVALID_REQUEST"
	CodeUnauthenticated          ErrorCode = "UNAUTHENTICATED"
	CodeInternalError            ErrorCode = "INTERNAL_ERROR"
)

The full set of canonical error codes.

func Code

func Code(err error) ErrorCode

Code walks the error chain and returns the first matched ErrorCode. If no *Error is found, Code returns CodeInternalError.

type Lease

type Lease map[Capability][]string

Lease maps capability namespaces to pattern lists. The lease is immutable for a job's lifetime; budget counters are runtime state derived from the lease, not part of it.

func (Lease) Clone

func (l Lease) Clone() Lease

Clone returns a deep copy of l.

func (Lease) MarshalJSON

func (l Lease) MarshalJSON() ([]byte, error)

MarshalJSON encodes l as a JSON object with string-typed keys.

func (*Lease) UnmarshalJSON

func (l *Lease) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a JSON object into l.

type MessageType

type MessageType interface {
	ARCPType() string
}

MessageType is implemented by every typed payload struct registered against the envelope dispatch table.

Directories

Path Synopsis
Package auth defines the Verifier interface used by the server to validate bearer tokens at the session.hello handshake.
Package auth defines the Verifier interface used by the server to validate bearer tokens at the session.hello handshake.
Package client implements the ARCP client surface: dial, submit, observe, cancel, subscribe.
Package client implements the ARCP client surface: dial, submit, observe, cancel, subscribe.
Package credentials defines the provisioner surface used by runtimes to mint lease-bound credentials for accepted jobs.
Package credentials defines the provisioner surface used by runtimes to mint lease-bound credentials for accepted jobs.
examples
cancel/client command
cancel/server command
internal/demo
Package demo provides shared helpers for the examples — addr resolution and a tiny "log fatal on error" idiom.
Package demo provides shared helpers for the examples — addr resolution and a tiny "log fatal on error" idiom.
progress/client command
progress/server command
stdio/agent command
stdio/client command
tracing/client command
tracing/server command
internal
clock
Package clock defines the small Clock interface used by the runtime for testable time.
Package clock defines the small Clock interface used by the runtime for testable time.
eventlog
Package eventlog persists session-scoped envelopes for resume and subscription replay.
Package eventlog persists session-scoped envelopes for resume and subscription replay.
glob
Package glob implements the lease pattern matcher.
Package glob implements the lease pattern matcher.
idstore
Package idstore implements the (principal, idempotency_key) → job_id dedupe map.
Package idstore implements the (principal, idempotency_key) → job_id dedupe map.
lease
Package lease implements the lease enforcement primitives: glob match, target canonicalization, expires_at and budget checks.
Package lease implements the lease enforcement primitives: glob match, target canonicalization, expires_at and budget checks.
Package messages defines the typed payload structs for every ARCP wire type.
Package messages defines the typed payload structs for every ARCP wire type.
middleware
chi
Package chi mounts an ARCP server on a chi.Router.
Package chi mounts an ARCP server on a chi.Router.
nethttp
Package nethttp exposes a net/http handler that upgrades incoming requests to WebSocket and hands the resulting connection to a server.Server.
Package nethttp exposes a net/http handler that upgrades incoming requests to WebSocket and hands the resulting connection to a server.Server.
otel
Package otel wires ARCP transports to OpenTelemetry trace context.
Package otel wires ARCP transports to OpenTelemetry trace context.
recipes
Package server hosts ARCP agents.
Package server hosts ARCP agents.
Package transport defines the Transport interface and ships three concrete implementations: an in-memory pair (for tests and same- process embedders), a WebSocket transport, and an NDJSON-over-stdio transport.
Package transport defines the Transport interface and ships three concrete implementations: an in-memory pair (for tests and same- process embedders), a WebSocket transport, and an NDJSON-over-stdio transport.

Jump to

Keyboard shortcuts

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