# API reference This is the application-facing API guide for Reticulum-Go. It is not a dump of every exported symbol. It is organized the way you build programs: choose an integration path, follow a recipe, then look up types and methods. Wire behavior matches the [Python RNS API reference](https://reticulum.network/manual/reference.html). Package layout, concurrency rules, and embedder lifecycle are Go-specific and documented here because the Python manual does not cover them. For generated signatures, use `go doc` on the import path or browse the module on pkg.go.dev. For package file maps, see [Package map](package-map.md). ## How this differs from the Python reference | Python RNS manual | This document | |-------------------|---------------| | Class catalog (`RNS.Reticulum`, Identity, Destination, …) | Task-first recipes, then API tables | | One process model (`RNS.Reticulum(...)`) | Four integration paths with trade-offs | | Little concurrency guidance | Explicit callback and locking rules | | No C / WASM / control-plane docs in the same place | Links to Control API, librns, WASM | | Examples live elsewhere | Recipes point at `examples/` | ## Choose an integration path ```text Need Reticulum in my app | v Go process? / \ yes no | | v v pkg/node Same machine as daemon? in-process | -------+------- / | \ yes C/FFI browser | | | v v v Control API librns pkg/wasm HTTP/WS .so \ | / \ | / v v v destination + link ``` | Path | Package / surface | Use when | |------|-------------------|----------| | In-process Go | `pkg/node` | Default for Go services and tools | | Daemon + JSON | [Control API](control-api.md) | Python, Rust, scripts, multi-language hosts | | In-process C | [librns](librns.md) | Native hosts that cannot embed Go source | | In-process Odin | [librns](librns.md#odin-bindings) | `bindings/odin` over `librns.so` | | Out-of-process Dart / Flutter | [Control API](control-api.md#dart-and-flutter) | `bindings/dart` (rns_control) | | In-process Dart / Flutter FFI | [librns Dart FFI](librns.md#dart-ffi-bindings) | `bindings/dart` (`ffi.dart`), Linux / Android / Windows | | Out-of-process any language | [Control API](control-api.md) | HTTP and WebSocket | | Browser | `pkg/wasm` | WebSocket gateway clients | Most of this page describes the **`pkg/node` happy path**. Other paths expose the same concepts with different bindings. ## Mental model 1. **Config** loads interfaces and storage paths (`pkg/reticulumconfig`, `pkg/common`). 2. **Node** starts transport, interfaces, and optional shared instance (`pkg/node`). 3. **Identity** holds X25519 + Ed25519 keys (`pkg/identity`). 4. **Destination** is an app endpoint named `app.aspect…` (`pkg/destination`). 5. **Announce** publishes reachability. Peers learn paths. 6. **Path** is a cached route (`Transport.HasPath` / RequestPath). 7. **Link** is an encrypted session to a destination (`pkg/link`). 8. **Request / resource** move structured replies and large payloads (`Link.Request`, `pkg/resource`). Packet MTU remains **500 bytes** on the wire (`pkg/packet.MTU`), same as Python. ## Quick start recipe (Go) ```go package main import ( "log" "os" "os/signal" "syscall" "quad4/reticulum-go/pkg/destination" "quad4/reticulum-go/pkg/identity" "quad4/reticulum-go/pkg/node" "quad4/reticulum-go/pkg/reticulumconfig" ) const appName = "example_utilities" func main() { cfg, err := reticulumconfig.InitConfig() if err != nil { log.Fatal(err) } identity.InitKnownDestinationsPersistence(cfg.ConfigPath, cfg.InMemoryKnownDestinations) n, err := node.New(cfg) if err != nil { log.Fatal(err) } if err := n.Start(); err != nil { log.Fatal(err) } defer n.Stop() id, err := identity.New() if err != nil { log.Fatal(err) } dest, err := destination.New(id, destination.In|destination.Out, destination.Single, appName, n.Transport(), "minimal") if err != nil { log.Fatal(err) } if err := dest.Announce(false, nil, nil); err != nil { log.Fatal(err) } log.Printf("listening on %x", dest.GetHash()) ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) <-ch } ``` For a guide on complete runnable examples, see [Examples](examples.md). ## Recipe: inbound link and request handler ```go dest.AcceptsLinks(true) dest.SetLinkEstablishedCallback(func(v any) { l := v.(*link.Link) // import pkg/link _ = l.SetResourceStrategy(link.AcceptAll) l.SetPacketCallback(func(data []byte, _ *packet.Packet) { log.Printf("data: %q", data) }) }) _ = dest.RegisterRequestHandler("/echo", func(_ string, data []byte, _ []byte, _ []byte, _ *identity.Identity, _ int64) []byte { return data }, destination.AllowAll, nil) ``` ## Recipe: outbound link and request ```go remoteID, err := identity.Recall(peerDestHash) if err != nil { log.Fatal(err) } out, err := destination.FromHash(peerDestHash, remoteID, destination.Single, n.Transport()) if err != nil { log.Fatal(err) } if !n.Transport().HasPath(peerDestHash) { _ = n.Transport().RequestPath(peerDestHash, "", nil, false) ctx, cancel := context.WithTimeout(context.Background(), rnsutil.PathResponseWindow(n.Transport(), peerDestHash)) defer cancel() if err := rnsutil.WaitPath(ctx, n.Transport(), peerDestHash); err != nil { log.Fatal(err) } } l := link.NewLink(out, n.Transport(), nil, nil, nil) if err := l.Establish(); err != nil { log.Fatal(err) } receipt, err := l.Request("/echo", []byte("ping"), 15*time.Second) if err != nil { log.Fatal(err) } // poll receipt.Concluded() or set receipt.SetResponseCallback ``` ## Recipe: send a file resource ```go res, err := resource.New(fileBytes, true) if err != nil { log.Fatal(err) } _ = res.SetMetadata(map[string]any{"name": []byte("report.bin")}) if err := l.SendResource(res); err != nil { log.Fatal(err) } ``` On the receiver, set AcceptAll or AcceptApp and handle `link.IncomingResource` (or plain `[]byte` when no metadata). CLI equivalent: rgocp in [CLI utilities](utilities.md). ## Recipe: network sleep and wake ```go n.SetPauseMode(node.PauseModeDisable) _ = n.OnNetworkLost() // pause links, disable interfaces _ = n.OnNetworkAvailable() _ = n.RefreshPaths() // re-request watched destinations ``` Optional: `n.EnableLinkAutoReconnect(node.LinkReconnectOptions{MaxAttempts: 5, Backoff: time.Second})` and `n.RegisterLink(l)`. ## Core types ### Node (`pkg/node`) Orchestrates transport, interfaces, shared instance, and lifecycle. Prefer this over constructing `transport.Transport` by hand. | Symbol | Role | |--------|------| | `New(cfg) (*Node, error)` | Build without starting | | `Start() error` | Transport, path handler, shared instance, interfaces | | `Stop() error` | Tear down in reverse order | | `Transport() *transport.Transport` | Pass to destinations and links | | `Config() *common.ReticulumConfig` | Active config | | `Interfaces() []interfaces.Interface` | Configured interfaces | | `OnNetworkAvailable() error` | Resume after outage | | `OnNetworkLost() error` | Pause for sleep / NIC down | | `SetPauseMode(PauseMode)` | PauseModeDisable or PauseModeStop | | `WatchDestination(hash)` | Include hash in wake refreshes | | `RefreshPaths(dests...)` | Force path refresh | | `ReloadInterfaces(newCfg)` | Hot-reload interface blocks | | `EnableLinkAutoReconnect(opts)` | Re-establish registered links | | `RegisterLink(l)` | Track link for reconnect | | `StartInterfaceDiscovery()` | rnstransport discovery listen + InterfaceAnnouncer when discoverable | ### Identity (`pkg/identity`) | Symbol | Role | |--------|------| | `New() (*Identity, error)` | Generate software identity (preferred) | | `NewIdentity()` | Alternate generator | | FromFile / ToFile | Persist via identity_backend (file, Secret Service, or Linux kernel keyring + RSSI marker) | | FromBytes / FromPublicKey | Load from bytes | | `LoadIdentityFile(path, signer)` | Software or RHB1 hardware-bound (also resolves RSSI markers) | | `NewIdentityWithSigner(...)` | External Ed25519 signer (HSM) | | SetIdentityBackend / ApplyIdentityBackendFromConfig | Select file or secretservice | | Close / Wipe | Zero locked private key buffers | | `Hash() []byte` | 16-byte truncated hash | | `GetPublicKey() []byte` | 64-byte combined public key | | Sign / Verify | Ed25519 | | Encrypt / Decrypt | Identity tokens with optional ratchets | | RememberRatchet / GetRatchet / CurrentRatchetID | Announced peer ratchet public keys | | `Recall(destHash)` | Public identity from known destinations | | Remember / ValidateAnnounce | Announce storage | | LoadOrCreateTransportIdentity | Daemon transport identity | | RotateRatchet / GetRatchets / GetCurrentRatchetKey | Explicit identity-level keys only. Does not auto-generate. On-wire SINGLE ratchets use Destination.EnableRatchets | Constants: KeySize (bits), TruncatedHashLength (bits). Hex destination or identity hashes are **32 characters**. Private key material uses `pkg/securemem` (best-effort mlock, wipe on Close). See [Identity and destinations](identity-and-destinations.md). ### Destination (`pkg/destination`) | Constant | Meaning | |----------|---------| | In / Out | Direction bit flags (`In\|Out` for both) | | Single / Group / Plain | Destination types | | ProveNone / ProveAll / ProveApp | Proof strategy | | AllowNone / AllowAll / AllowList | Request handler ACL | | Symbol | Role | |--------|------| | `New(id, direction, type, app, transport, aspects...)` | Create and optionally auto-register (In) | | `FromHash(hash, id, type, transport)` | Outbound destination for a known peer | | `Hash(id, app, aspects...)` | Compute destination hash | | ParseName / ExpandAppName | Dotted name helpers | | `Announce(pathResponse, tag, iface)` | Publish reachability | | `AcceptsLinks(bool)` | Accept link requests | | Encrypt / Decrypt / Sign | Destination crypto | | CreateKeys / LoadPrivateKey / GetPrivateKey | GROUP Token PSK (64-byte AES-256 default) | | SetPacketCallback | Single-packet inbound data | | SetLinkEstablishedCallback | Inbound link ready (`func(any)`) | | RegisterRequestHandler / RegisterRequestHandlerAny | Link request paths | | EnableRatchets(path) | Enable SINGLE ratchets and persist private keys at path | | EnableRatchetsInMemory | Same, RAM only (no ratchet file) | | EnforceRatchets | Reject identity-key ciphertext (opt-in, same as Python) | | SetRetainedRatchets / SetRatchetInterval | Retention count and rotation interval | | RotateRatchets / CurrentRatchetPublic / LatestRatchetID / RatchetsEnabled | Local rotation and announce public key | ### Link (`pkg/link`) | Status | Value | Meaning on Link | |--------|-------|-------------------| | StatusPending | `0x00` | Not established | | StatusHandshake | `0x01` | Handshake | | StatusActive | `0x02` | Ready | | StatusStale | `0x03` | Stale | | StatusClosed | `0x04` | Closed | | StatusFailed | `0x05` | Failed | | Symbol | Role | |--------|------| | `NewLink(dest, transport, iface, onEst, onClose)` | Outbound link object | | `Establish() error` | Initiator handshake | | `EstablishmentTimeout()` | Handshake wait used by the link watchdog | | `Teardown()` | Close | | `Identify(id)` | Prove local identity to peer | | Send / SendPacket / SendPacketWithContext | Encrypted data | | `Request(path, data, timeout)` | Msgpack request (auto resource if large) | | `SendResource(res)` | Outbound resource transfer | | `GetChannel()` | Reliable channel over the link | | SetResourceStrategy | AcceptNone / AcceptAll / AcceptApp | | SetResourceConcludedCallback | `[]byte` or IncomingResource | | GetRTT / idle timers / PHY stats | Link health | #### RequestReceipt | Method | Role | |--------|------| | `Concluded()` | Finished (success or failure) | | `GetStatus()` | **StatusActive means response OK**, StatusFailed means timeout or error | | `GetResponse()` / `GetResponseValue()` | Bytes or decoded msgpack | | `GetMetadata()` | Resource response metadata | | `Progress()` | Bytes received / total for resource replies | | SetResponseCallback / SetFailedCallback | Async completion | Do not confuse `RequestReceipt.GetStatus()` with `Link.GetStatus()`. Both reuse status byte constants with different meanings. ### Resource (`pkg/resource`) | Symbol | Role | |--------|------| | `New(data, autoCompress)` | `[]byte` or seekable file | | `SetMetadata(map)` | Prepended msgpack metadata (Python-compatible) | | GetProgress / GetStatus / GetHash | Transfer state | | PrepareOutboundForLink | Called by `Link.SendResource` | Statuses: StatusPending, StatusActive, StatusComplete, StatusFailed, StatusCancelled. ### Transport (via `Node.Transport()`) | Method | Role | |--------|------| | `HasPath(hash)` | Cached route present | | `RequestPath(hash, iface, tag, recursive)` | Path request (throttled) | | HopsTo / NextHop / NextHopInterface | Route inspection | | `FirstHopTimeout(hash)` | Next-hop airtime plus 6s (Python `get_first_hop_timeout`) | | `PathResponseWindow(hash)` | Cold path wait from slowest online bitrate | | `SlowestOnlineBitrate()` | Lowest advertised bitrate of an online interface | | ExpirePath / PrepareFreshPathRequest | Drop or refresh cache | | RegisterInterface / GetInterfaces | Interface table | | RegisterDestination | Usually automatic for In destinations | | SendPacket / HandlePacket | Low-level inject (advanced) | | RegisterAnnounceHandler | Observe announces | Avoid `transport.Destination` and `transport.Link` placeholder types. Use `destination.Destination` and `link.Link`. ### Packet (`pkg/packet`) | Symbol | Role | |--------|------| | `MTU` | 500 | | NewPacket / Pack / Unpack | Wire encode/decode | | PacketReceipt | Delivery proofs for data packets | | Context constants | ContextRequest, ContextResource, link contexts, … | ### Config (`pkg/reticulumconfig`, `pkg/common`) | Function | Role | |----------|------| | `InitConfig()` | Load or create `~/.reticulum-go/config` | | `LoadConfig(path)` | Parse INI (unknown keys ignored) | | SaveConfig / DefaultConfig / CreateDefaultConfig | Persist defaults | Important ReticulumConfig fields: EnableTransport, ShareInstance, SharedInstanceType, ports, RPCKey, Interfaces, EnableControlAPI, InMemoryPathTable, InMemoryStorage, WatchInterfaces, DiscoverInterfaces, BackboneIO. Default config directory is **`~/.reticulum-go`**, not `~/.reticulum`. ## Python to Go map | Python | Go | |--------|-----| | `RNS.Reticulum(configdir=...)` | `reticulumconfig.LoadConfig` + `node.New` + Start | | `RNS.Identity()` | `identity.New()` | | `Identity.from_file` / to_file | FromFile / ToFile | | `Identity.recall(hash)` | `identity.Recall(hash)` | | `Destination(identity, IN, SINGLE, app, *aspects)` | `destination.New(id, destination.In, destination.Single, app, tr, aspects...)` | | `Destination(..., OUT, ...)` | `destination.Out` or FromHash for known peers | | `destination.announce()` | `dest.Announce(false, nil, nil)` | | `destination.set_link_established_callback` | SetLinkEstablishedCallback (`func(any)`) | | `destination.register_request_handler` | RegisterRequestHandler / RegisterRequestHandlerAny | | `RNS.Link(destination)` | `link.NewLink` + Establish | | `link.establishment_timeout` | `l.EstablishmentTimeout()` | | `link.identify(identity)` | `l.Identify(id)` | | `link.request(path, data=...)` | `l.Request(path, data, timeout)` | | `RNS.Resource(data, link, metadata=...)` | `resource.New` + SetMetadata + `l.SendResource` | | `RNS.Transport.has_path` / request_path | `tr.HasPath` / `tr.RequestPath` | | `RNS.Reticulum.get_first_hop_timeout` | `tr.FirstHopTimeout` (use `rnsutil.FirstHopTimeout` when attached to a shared instance) | | Shared instance master | First `share_instance = yes` process (daemon or Node) | | `~/.reticulum` | `~/.reticulum-go` | ## Concurrency and callbacks | Component | Rule | |-----------|------| | Transport / interfaces | Packet handlers run on interface or transport goroutines | | Destination / link callbacks | May fire concurrently. Return quickly. Do heavy work in your own goroutine | | `Link.Request` receipts | Timeout and response callbacks run in separate goroutines | | Same Link | Do not call Establish, Teardown, and Request concurrently without external locking | | `Node.ReloadInterfaces` / network hooks | Serialized by an internal mutex | | Identities / destinations | Internally mutex-protected. Still treat callbacks as re-entrant | Python RNS is largely single-threaded asyncio. Go is multi-threaded by default. Design for that. ## Errors and empty results | Situation | Typical signal | |-----------|----------------| | No path yet | HasPath false. Call RequestPath and wait | | Link not ready | Establish error or `GetStatus() != StatusActive` | | Request timeout | RequestReceipt status StatusFailed | | Recall before announce | `identity.Recall` error. Wait for announce or seed known destinations | | Shared instance auth failure | RPC dial / auth error. Align rpc_key or transport identity | | Hardware-bound identity without signer | ErrHardwareBoundSignerRequired | ## Other API surfaces | Surface | Document | |---------|----------| | Localhost JSON and WebSocket | [Control API](control-api.md) | | C ABI (`include/rns.h`) | [librns](librns.md) | | Odin bindings (`bindings/odin`) | [librns](librns.md#odin-bindings) | | Dart FFI and Control API (`bindings/dart`) | [librns](librns.md#dart-ffi-bindings), [Control API](control-api.md#dart-and-flutter) | | Browser JS bridge | [Embedding and WebAssembly](embedding-and-wasm.md) | | CLI tools | [CLI utilities](utilities.md) | | Crypto details | [Cryptography](cryptography.md) | | Interface types | [Interfaces](interfaces.md) | ## Related documents - [Examples](examples.md) - [Package map](package-map.md) - [Embedding and WebAssembly](embedding-and-wasm.md) - [Compatibility](compatibility.md) - [Python RNS API reference](https://reticulum.network/manual/reference.html) (wire and semantic authority)