Help us shape the future of Go! Take the 2026 Go Developer Survey

node

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package node is the Agent Wire Protocol engine: it owns the identity key, the durable store, the listeners and every connection, and implements the handshake, resume, acks, blobs, grants and reconnection of SPEC.md.

Index

Constants

View Source
const (
	// AcceptAny admits any key with the default capabilities. It is what
	// the spec recommends for a coding agent on a sandbox.
	AcceptAny = "any"
	// AcceptAllowlist admits only allow-listed or trusted keys, keys we
	// have dialed ourselves, and keys that present an honored grant.
	AcceptAllowlist = "allowlist"
)

Admission policies (section 7.3).

View Source
const (
	CapExec      = "exec"
	CapFSRead    = "fs:read"
	CapFSWrite   = "fs:write"
	CapIntroduce = "introduce"
	CapAdmin     = "admin"
)

Capabilities with a meaning in this implementation (section 10.1).

View Source
const (
	MimeExecResult    = "application/vnd.awp.exec-result+json"
	MimeFSReadResult  = "application/vnd.awp.fs-read-result+json"
	MimeFSWriteResult = "application/vnd.awp.fs-write-result+json"
)

Result mime types for served requests (PROFILE.md).

View Source
const (
	PresenceStaleAfter = 150 * time.Second // no heartbeat for this long: stale

)

Presence gossip: an opt-in, signed summary of what each agent is doing, forwarded across the network so that a watcher on any connected host can see all of it (wire/presence.go, NOTES.md "Presence").

Variables

This section is empty.

Functions

func NewThreadID

func NewThreadID() string

NewThreadID returns a fresh thread id.

Types

type Config

type Config struct {
	// Home is the state directory (~/.awp by default in the CLI).
	Home string

	// Name and About are sent in hello.
	Name  string
	About string

	// Model is the model the agent runs on (claude-opus-5-5, gpt-5.5, ...),
	// shared in presence. The agent or its harness hooks report it, and it
	// can change while the node runs (SetModel). Remembered like the name.
	Model string

	// ShareWith lists the keys of hosts to mirror this node's conversations
	// to (wire/mirror.go). Nil keeps what was set before; empty stops.
	ShareWith []string

	// Harness is the agent harness this node runs in (internal/harness),
	// shared in presence. Remembered like the name.
	Harness string
	// DetectedHarness is the fallback when no harness was ever set: the one
	// the environment of whoever started the node points to. It is not
	// remembered, since the next start may come from another harness.
	DetectedHarness string

	// Listen lists addresses to accept connections on: "tailcat",
	// "tcp:host:port" or "unix:/path".
	Listen []string

	// Advertise is the address sent in hello.addr so the peer can dial us
	// back. Empty means the tailcat address if there is one, otherwise the
	// first listen address. "none" disables it.
	Advertise string

	PingInterval     time.Duration // idle time before a ping; default 30s
	HandshakeTimeout time.Duration // default 30s
	BlobLimit        int64         // largest blob accepted or sent; default 50 MiB
	OutboxTTL        time.Duration // outbox retention; default 7 days
	MaxBackoff       time.Duration // reconnect backoff cap; default 60s
	DialGrace        time.Duration // delay before dialing a hello-learned address; default 15s

	Policy Policy

	// Logf receives the daemon's log. Nil discards it.
	Logf func(format string, args ...any)
	// TailcatLogf receives tailcat's (verbose) diagnostics. Nil discards them.
	TailcatLogf func(format string, args ...any)
	// Trace logs every line sent and received.
	Trace bool
	// AllowPlaintext permits plain TCP to public addresses (see
	// transport.Transport.AllowPublicTCP).
	AllowPlaintext bool
	// Presence publishes this node's signed presence to its peers, who
	// gossip it on (presence.go). Receiving and forwarding other agents'
	// presence happens either way.
	Presence bool
}

Config configures a Node. Zero values get the defaults from the spec.

type Conn

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

Conn is one connection to a peer, from hello to close.

func (*Conn) Close

func (c *Conn) Close(reason string)

Close tears the connection down. It is safe to call more than once; the first reason sticks.

func (*Conn) RTT

func (c *Conn) RTT() time.Duration

RTT is the last measured round trip time, or zero.

type ConnInfo

type ConnInfo struct {
	Outbound bool          `json:"outbound"`
	Via      string        `json:"via"`
	Since    time.Time     `json:"since"`
	RTT      time.Duration `json:"rtt"` // last ping's round trip; zero until measured
}

ConnInfo describes a live connection.

type ExecRequest

type ExecRequest struct {
	Cmd     json.RawMessage   `json:"cmd"` // ["argv", ...] or "shell string"
	Cwd     string            `json:"cwd,omitempty"`
	Env     map[string]string `json:"env,omitempty"`
	Timeout float64           `json:"timeout,omitempty"` // seconds, default 600
	Stdin   string            `json:"stdin,omitempty"`
}

ExecRequest is the data of an application/vnd.awp.exec+json part.

type FSReadRequest

type FSReadRequest struct {
	Path   string `json:"path"`
	Offset int64  `json:"offset,omitempty"`
	Length int64  `json:"length,omitempty"`
}

FSReadRequest is the data of an application/vnd.awp.fs-read+json part.

type FSWriteRequest

type FSWriteRequest struct {
	Path     string `json:"path"`
	Content  string `json:"content"`
	Encoding string `json:"encoding,omitempty"` // "utf-8" (default) or "base64"
	Append   bool   `json:"append,omitempty"`
	Mkdir    bool   `json:"mkdir,omitempty"`
}

FSWriteRequest is the data of an application/vnd.awp.fs-write+json part.

type Node

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

Node is a running awp peer.

func Open

func Open(cfg Config) (*Node, error)

Open loads (or creates) the identity and store under cfg.Home. Call Start to begin listening and reconnecting.

func (*Node) Activity

func (n *Node) Activity() (last time.Time, waiting bool)

Activity reports when the agent last acted (zero if not since the daemon started) and whether it is waiting for a message now.

func (*Node) Addresses

func (n *Node) Addresses() []string

Addresses returns the addresses this node listens on, tailcat first.

func (*Node) Bye

func (n *Node) Bye(peer, reason string) error

Bye closes the connection to a peer gracefully (section 9.6) and parks it: no reconnection until something new is queued for it.

func (*Node) Caps

func (n *Node) Caps(peer string) []string

Caps returns the capabilities a peer holds on this node beyond the defaults.

func (*Node) Changed

func (n *Node) Changed() <-chan struct{}

Changed returns a channel that is closed at the next state change: a log record, an ack, a connection coming or going. Waiters re-check their condition and call Changed again.

func (*Node) Close

func (n *Node) Close() error

Close stops everything. Connections are dropped without bye: the state is on disk and peers will resume.

func (*Node) ConnInfo

func (n *Node) ConnInfo(key string) *ConnInfo

Conn returns information about key's active connection, if any.

func (*Node) Connect

func (n *Node) Connect(ctx context.Context, addr string) (string, error)

Connect dials an address given out of band (section 4.1) and returns the key of the peer that answered. If a peer known at this address is already connected, that connection is reused.

func (*Node) Connected

func (n *Node) Connected(key string) bool

Connected reports whether key has an active connection.

func (*Node) Dialing

func (n *Node) Dialing(key string) (bool, string)

Dialing reports whether a reconnect loop is running for key, and its last error.

func (*Node) Grant

func (n *Node) Grant(sub string, caps []string, ttl time.Duration) (*store.GrantRow, error)

Grant mints a grant for sub (section 10.3), records it, and sends it if the peer is connected; otherwise it goes out after the next resume.

func (*Node) Harness

func (n *Node) Harness() string

Harness returns the agent harness this node runs in, or "".

func (*Node) Home

func (n *Node) Home() string

Home returns the state directory.

func (*Node) Introduce

func (n *Node) Introduce(to, intro string, caps []string, ttl time.Duration, th string) (*SendResult, error)

Introduce hands peer `to` the identity and address of peer `intro`, with a grant `intro` will honor if it trusts us with introduce (section 10.4). The grant carries aud = intro so it confers nothing on anyone else.

func (*Node) Key

func (n *Node) Key() string

Key returns this peer's encoded public key.

func (*Node) LocalPresence

func (n *Node) LocalPresence() (*wire.Presence, error)

LocalPresence describes this node's current activity. It is what the node would publish, minus the signature, and is available whether or not sharing is on.

func (*Node) MakePrivate

func (n *Node) MakePrivate(peer, th string) error

MakePrivate keeps the thread th with peer out of conversation sharing, on both sides: this node stops mirroring it (and has its hosts forget it), and peer is asked to do the same.

func (*Node) Model

func (n *Node) Model() string

Model returns the model the agent runs on, or "".

func (*Node) Name

func (n *Node) Name() string

Name returns this peer's name.

func (*Node) ResolvePeer

func (n *Node) ResolvePeer(s string) (string, error)

ResolvePeer turns what a user typed into a key: a full key, an alias, a name, or a unique prefix of the key's base64 body.

func (*Node) ResolveThread

func (n *Node) ResolveThread(th string) (string, error)

ResolveThread finds which peer a thread id belongs to.

func (*Node) Revoke

func (n *Node) Revoke(hash string) (int64, error)

Revoke forgets a grant we issued. Grants are bearer statements, so a copy the peer holds stays valid elsewhere until it expires; locally it stops being honored at once.

func (*Node) Send

func (n *Node) Send(req SendRequest) (*SendResult, error)

Send queues a msg. It never fails because the peer is away: the message goes to the outbox on disk and is delivered on the next resume.

func (*Node) SetModel

func (n *Node) SetModel(m string) (bool, error)

SetModel records the model the agent now runs on, remembers it, and republishes presence if it changed. It reports whether it changed.

func (*Node) SetShareWith

func (n *Node) SetShareWith(keys []string) error

SetShareWith sets the hosts to share conversations with (none to stop), remembers them, and republishes presence. Peers learn of the change in presence at once, and in hello on their next connection.

func (*Node) SetState

func (n *Node) SetState(peer, th, state, note string) (*SendResult, error)

SetState sends our view of a thread's state (section 8.1).

func (*Node) ShareWith

func (n *Node) ShareWith() []string

ShareWith returns the keys of the hosts this node mirrors its conversations to.

func (*Node) SharesPresence

func (n *Node) SharesPresence() bool

SharesPresence reports whether this node publishes its own presence.

func (*Node) Start

func (n *Node) Start() error

Start opens the listeners and starts reconnecting to peers that have unfinished business. A tailcat listener starts in the background, since picking a DERP region takes a few seconds.

func (*Node) Store

func (n *Node) Store() *store.Store

Store exposes the store for read-only queries by the control server.

func (*Node) TailcatAddress

func (n *Node) TailcatAddress() (addr, errMsg string)

TailcatAddress returns the bare tailcat address, if listening on tailcat.

func (*Node) Touch

func (n *Node) Touch()

Touch records that the agent just acted.

func (*Node) Waiting

func (n *Node) Waiting() (done func())

Waiting marks the agent as blocked waiting for a message until the returned function is called.

type Policy

type Policy struct {
	Accept string   `json:"accept,omitempty"` // AcceptAny or AcceptAllowlist
	Allow  []string `json:"allow,omitempty"`  // keys admitted under the allowlist
	Trust  []string `json:"trust,omitempty"`  // issuers whose grants we honor as our own

	// Serve lists capabilities this daemon fulfils by itself when a peer
	// with the matching grant asks (exec, fs:read, fs:write). Requests for
	// capabilities not listed here are delivered to the agent instead,
	// marked allowed or denied.
	Serve []string `json:"serve,omitempty"`
	// Root confines fs:read and fs:write and is the default working
	// directory for exec. Empty means the daemon's working directory.
	Root string `json:"root,omitempty"`
}

Policy is the local trust configuration.

type Request

type Request struct {
	Part    int    `json:"part"`
	Mime    string `json:"mime"`
	Cap     string `json:"cap"`
	Allowed bool   `json:"allowed"`
	Served  bool   `json:"served,omitempty"`
}

Request is a capability request found in a received msg.

type SendRequest

type SendRequest struct {
	Peer    string      `json:"peer"`
	Th      string      `json:"th,omitempty"` // empty starts a new thread
	Subject string      `json:"subject,omitempty"`
	Re      string      `json:"re,omitempty"`
	Parts   []wire.Part `json:"parts,omitempty"`
	Files   []string    `json:"files,omitempty"` // attached as blobs
	// contains filtered or unexported fields
}

SendRequest describes a msg to send.

type SendResult

type SendResult struct {
	ID        string `json:"id"`
	Th        string `json:"th"`
	Peer      string `json:"peer"`
	NewThread bool   `json:"new_thread,omitempty"`
	Connected bool   `json:"connected"`
}

SendResult reports a queued message.

Jump to

Keyboard shortcuts

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