Flow

Network Policies

Membership caps, port whitelists, and network metadata for enterprise networks.

Overview

Network policies let owners and admins enforce constraints on enterprise networks. Policies control how many agents can join, which ports are accessible, and what metadata is attached to the network.

Policies use merge-on-update semantics: you only send the fields you want to change, and unmentioned fields keep their current values. This makes partial updates safe - setting max_members does not reset allowed_ports.

MaxMembers

Caps the total number of agents that can be members of the network at any given time. The owner counts toward the cap.

BehaviorWhat happens
Join attempt at capacityRejected with “membership limit reached”
Invite accept at capacityRejected - the invite remains pending but the agent cannot join until a slot opens
Value of 0No limit (default)
Reducing below current countRejected - the registry refuses to set max_members below the current member count (“cannot set max_members to N: network already has M members”). Remove members first, then lower the cap.
# Set a membership cap of 50 agents
pilotctl network policy <network_id> --max-members 50

AllowedPorts

Restricts which Pilot ports are accessible within the network. When set, only connections to listed ports are permitted between network members. Connections to unlisted ports are silently dropped.

BehaviorWhat happens
Empty list (default)All ports allowed
Non-empty listOnly listed ports are accessible
Maximum entries100 ports per policy
# Allow only HTTP, HTTPS, and data exchange ports
pilotctl network policy <network_id> --allowed-ports 80,443,1001

To reset the port whitelist (allow all ports again), set an empty list directly via the registry RPC set_network_policy with "allowed_ports": [].

Port policies are enforced at the connection acceptance layer. The daemon checks the destination port against the network’s allowed ports list before accepting the connection.

Description

A free-text metadata field for the network. Use it for human-readable context: purpose, team name, environment, or compliance notes.

ConstraintValue
Maximum length256 characters
DefaultEmpty string
pilotctl network policy <network_id> --description "Production fleet - US East region"

Setting policies

Set a policy

pilotctl network policy <network_id> --max-members 50 --allowed-ports 80,443

Protocol command: set_network_policy. Requires owner or admin role (or admin token).

{
  "type": "set_network_policy",
  "network_id": 1,
  "max_members": 50,
  "allowed_ports": [80, 443],
  "description": "Production fleet",
  "admin_token": "your-admin-token"
}

The message is dispatched on type, and policy fields (max_members, allowed_ports, description) sit flat at the top level - not nested under a policy object. The pilotctl network policy CLI builds this message for you.

Merge-on-update: only include the fields you want to change. Omitted fields are preserved.

Get a policy

pilotctl network policy <network_id>

Protocol command: get_network_policy. Returns the current policy for the network.

# Example response
{
  "max_members": 50,
  "allowed_ports": [80, 443],
  "description": "Production fleet"
}

Audit trail

Every policy change emits a network.policy_changed audit event. It records the network ID, the old and new max_members values, and the old and new allowed_ports counts (the number of whitelisted ports, not the port values). Description changes are not recorded in the event.

Programmable (expr) policies

Beyond the static caps above, an enterprise network can carry a programmable expression policy - a versioned document of rules (using the expr-lang expression language) that the managed-network policy runner evaluates on membership events to gate joins and to prune or fill trust links. This is a separate slot from the static set_network_policy record and is managed with its own RPCs.

Set an expr policy

Protocol command: set_expr_policy. Requires owner/admin role (or admin token). The expr_policy field is required and may be a JSON string or object; it must declare "version": 1 and at least one rule. Sending an empty string or "null" clears the policy.

{
  "type": "set_expr_policy",
  "network_id": 1,
  "expr_policy": {
    "version": 1,
    "rules": [ /* ... */ ]
  },
  "admin_token": "your-admin-token"
}

The reply is {"type": "set_expr_policy_ok", "network_id": 1} (with "cleared": true when the policy was removed). Setting or clearing an expr policy emits a network.expr_policy_set / network.expr_policy_cleared audit event.

Get an expr policy

Protocol command: get_expr_policy. Returns {"type": "get_expr_policy_ok", "network_id": N, "expr_policy": {...}}; the expr_policy field is omitted when the network has no programmable policy.

Go SDK

The registry client exposes SetExprPolicy(networkID uint16, policyJSON json.RawMessage, adminToken string) and GetExprPolicy(networkID uint16). Blueprints can provision the same document declaratively via the expr_policy field - see Blueprints.

Member tags

Member tags are admin-assigned labels attached to a specific node within a network (distinct from the node's own capability tags). They are the inputs programmable (expr) policies match against - e.g. keeping only nodes tagged gpu, or evicting nodes without a required tag.

Set member tags

Protocol command: set_member_tags. Requires an admin token. Takes network_id, target_node_id, and a tags array (max 10, lowercase alphanumeric with hyphens; an empty array clears them).

{
  "type": "set_member_tags",
  "network_id": 1,
  "target_node_id": 42,
  "tags": ["gpu", "us-east"],
  "admin_token": "your-admin-token"
}

Returns {"type": "set_member_tags_ok", "network_id": N, "target_node_id": M, "tags": [...]} and emits a member_tags.changed audit event.

Get member tags

Protocol command: get_member_tags. Pass network_id with a target_node_id for one node's tags, or target_node_id: 0 to return the tags of every member.

The Go SDK exposes MemberTagsGet(networkID uint16, nodeID uint32) and MemberTagsSet(networkID uint16, nodeID uint32, tags []string) for the same operations.

Persistence

Policies are stored as part of the network record in the registry. They persist across registry restarts via the atomic JSON snapshot system. When the registry loads from a snapshot, all network policies are restored exactly as they were.

Policy state is also included in HA replication snapshots, so standby registries (started via rendezvous -standby <primary:port> -repl-token <token>) have the same policies as the primary.

See also: RBAC & Access Control - who can set policies (owners and admins). Blueprints - set policies declaratively during network provisioning.