sam-node
sam-node is the mesh member that runs beside an agent or a service.
sam-node join [control-plane-url] [flags] enroll and store a credential
sam-node run [flags] run the node
sam-node reset [--all] [--yes] forget the credential or everything
sam-node skill install|list|show manage the agent skill document
Files
The data directory is --data-dir if set, otherwise $SAM_DATA_DIR,
otherwise the user configuration directory of the operating system
(~/.config/sam-mesh on Linux, ~/Library/Application Support/sam-mesh on
macOS). It is created with mode 0700 and holds:
| File | Contents |
|---|---|
agent.db | The node’s key, credential, control plane URL and public key, router addresses, and OIDC refresh token. A running node holds a lock on this file. A second node started on the same directory refuses to start. |
sam.sock | The local API Unix socket, mode 0600, removed on exit. |
api-token | Generated by --daemonize when no token is configured. |
sam-node.pid, sam-node.log | Written by --daemonize. |
The configuration file is --config, by default sam-node.yaml in the
working directory. A missing file is treated as an empty one. See
node configuration.
Global flags
Accepted by every subcommand.
| Flag | Default | Meaning |
|---|---|---|
--control-plane | stored value | Control plane URL. join takes it as a positional argument. https:// is required unless the host is loopback. |
--insecure-control-plane | false | Accept a plaintext http:// URL to a non-loopback host. Whoever answers that URL becomes the node’s trust root. Intended for networks that are already trusted, such as a cluster. |
--config | sam-node.yaml | Node configuration file. |
--data-dir | see above | Data directory. |
--audience | sam-mesh-audience | OIDC audience to request. |
--oidc-issuer | from /info | Override the identity provider that the control plane advertises. |
--device-auth-url | discovered | Override the device authorization endpoint. |
--headless | false | Force the out-of-band login flow. |
--auth-mode | auto | Login flow: auto, device, oob or browser. auto uses the browser when one can be opened and the device flow otherwise. device fails if the provider has no device endpoint. |
join
Enrolls the node with the control plane and stores the credential. Without a
bootstrap token, join runs an interactive OIDC login.
| Flag | Default | Meaning |
|---|---|---|
--bootstrap-token-path | File containing a bootstrap token. | |
--bootstrap-token | The token as a value. Visible in process listings. The file form is preferred. | |
--offline-access | false | Request an OIDC refresh token, so that the node can re-enroll on its own when its credential expires. |
--allow-loopback | false | Advertise and dial loopback and link-local addresses. For several nodes on one host. |
--announce-private | true | Advertise RFC 1918 and ULA addresses. Turn off when peers are only reachable through a relay. |
--router-connect-timeout | 5s | Dial timeout per router. |
Labels declared in the configuration file are sent with the enrollment.
Running join for a node that already holds a credential for the same
control plane enrolls it again. For a different control plane, join
refuses until sam-node reset has been run.
run
Starts the node. If the data directory holds a credential, the node uses it.
Otherwise the node enrolls if it has a way to (--jwt-path,
--bootstrap-token-path, --client-id, or --join). If it has none, it
starts an unauthenticated local MCP server whose only tool explains how to
enroll.
Enrollment
| Flag | Default | Meaning |
|---|---|---|
--join | false | Run the interactive login on first start if there is no credential. Needs a terminal and --control-plane (or a stored control plane). Does nothing once the node is enrolled. |
--jwt-path | File containing an OIDC token to enroll with, for example a projected service account token. | |
--jwt | The token as a value. Logged as a warning. The file form is preferred. | |
--bootstrap-token-path, --bootstrap-token | As for join. | |
--client-id, --client-secret-path | OAuth client-credentials grant against --oidc-issuer. The secret can also come from SAM_CLIENT_SECRET. | |
--offline-access | false | With --join, as for join. |
--control-plane-public-key | stored value | Control plane Ed25519 public key, 32 bytes in hex. Only needed when the store lacks it. |
Local API
| Flag | Default | Meaning |
|---|---|---|
--bind-addr | 127.0.0.1:8080 | TCP address for the local API. An empty value disables TCP. |
--socket-path | <data-dir>/sam.sock | Unix socket for the same API. An empty value disables it. At least one listener is required. |
--api-token-path | File containing the bearer token for the TCP listener, or SAM_API_TOKEN. Required when TCP is enabled, unless mTLS is enabled. | |
--tls-cert, --tls-key | Serve the TCP listener over TLS. | |
--tls-ca | Require client certificates signed by this CA (mTLS). Callers with a verified certificate need no token. | |
--metrics-addr | off | Serve /metrics, /healthz and /readyz without authentication on this address, for scrapers. Do not expose it on shared networks. |
--daemonize | false | Start detached, wait for the API to answer, print the endpoint, token file and log path, and exit. Safe to run repeatedly. Generates api-token if no token is configured. Refuses to run on a node that has never enrolled. |
Mesh
| Flag | Default | Meaning |
|---|---|---|
--listen | /ip4/0.0.0.0/udp/5001/quic-v1, /ip4/0.0.0.0/tcp/5002 | libp2p listen addresses. Repeatable. |
--allow-loopback, --announce-private, --router-connect-timeout | As for join. | |
--enable-relay | false | Relay traffic for other peers. |
--mesh | public-mesh | Mesh federation name. Must match the routers’ name. |
--discovery-interval | 30s | DHT discovery polling interval. |
--dht-lookup-limit | 20 | Providers to query per DHT lookup. |
--discovery-concurrency | 10 | Concurrent catalog fetches during discovery. |
--dht-provider-addr-ttl, --dht-max-record-age | library defaults | DHT record lifetimes. |
--backend-probe-timeout | 2s | How long a service backend may take to answer before the node declines to advertise it. Raise it for subprocesses that start slowly. |
--control-plane-sync-interval | 15m | How often signing keys, the ban set, router addresses and the mesh policy are pulled from the control plane. Keep it well below the control plane’s --key-grace-period; raise it on large meshes. |
--key-grace-period | 24h | How long a rotated-out control plane key is still accepted for verifying peers. |
--monitor-bootstrap | 2m | Delay before the router-connection monitor starts. |
--monitor-interval | 1m | How often the monitor checks that a router is connected. |
--autorelay-min-interval, --autorelay-boot-delay, --autorelay-backoff | 30s, 0s, 3s | libp2p AutoRelay tuning. |
--log-level | info | debug, info, warn or error. |
reset
| Flag | Meaning |
|---|---|
| (none) | Delete the credential and control plane binding. The key and peer ID stay. |
--all | Delete every file the node keeps: agent.db, api-token, sam-node.pid, sam-node.log. The node gets a new peer ID. Asks for confirmation. |
--yes | Skip the confirmation, for scripts. |
Both variants refuse while a node has the store locked.
skill
Installs the SKILL.md document that teaches an agent harness how to use the
node.
| Command | Effect |
|---|---|
skill install | Write to ~/.claude/skills/sam-mesh/SKILL.md and ~/.gemini/config/skills/sam-mesh/SKILL.md. |
skill install --project | Write to ./.claude/skills/sam-mesh/ and ./.agents/skills/sam-mesh/ in the current directory. |
skill install --dir DIR | Write to DIR/sam-mesh/SKILL.md. |
skill list | Show each install location and whether the copy matches this binary. |
skill show | Print the document. |
Environment variables
| Variable | Equivalent |
|---|---|
SAM_API_TOKEN | --api-token-path contents |
SAM_CLIENT_SECRET | --client-secret-path contents |
SAM_DATA_DIR | --data-dir |
Exit behaviour
The node exits when its credential can no longer be refreshed. The causes are a ban, an expired session, or a signing key that was retired after its grace period while the node had no way to enroll again. The last lines of the log name the cause. A node that loses its routers keeps running and reconnects. A node whose control plane is unreachable keeps serving with its current credential until that credential expires.