LocalBinding

A device-local forward of a workstation's ports and Unix sockets to your machine, and of your machine's services into a workstation.

A LocalBinding describes what this device forwards from a workstation: TCP ports and Unix sockets, statically or by auto-discovery. It also carries a service on this device into a workstation (reversePorts). It is the single interface for device-local forwarding, and it is never routed or synced: each device owns and writes its own.

apiVersion: core.ringleader.dev/v1
kind: LocalBinding

Most of the time you don’t author one directly: a workstation’s spec.defaultLocalBinding template makes the daemon seed a LocalBinding once, when the workstation first reaches Running (deletion is honored: it won’t re-create one you remove). If the workstation is shared with you instead of yours, the seed starts disabled, and rl binding enable turns it on. Author one explicitly when you want precise control.

Examples

Map a single port to a fixed host port, a one-line change. A per-port entry opts that port in on its own, so you don’t need forwardAll to forward just one:

spec:
  autoForward:
    ports: [{ port: 8080, localPort: 18080 }]   # workstation 8080 -> host 18080

Forward a workstation’s Docker socket to a fixed host path:

apiVersion: core.ringleader.dev/v1
kind: LocalBinding
metadata:
  name: docker
  namespace: dev
spec:
  enabled: true
  workstationSelector:
    matchName: my-box
  sockets:
    - remotePath: /var/run/docker.sock
      localPath: /tmp/ringleader-docker.sock

Auto-forward every listening port, with one exception and one override:

apiVersion: core.ringleader.dev/v1
kind: LocalBinding
metadata:
  name: runtime
  namespace: dev
spec:
  enabled: true
  workstationSelector:
    matchLabels:
      app: web
  autoForward:
    forwardAll: true
    ports:
      - port: 9999
        enabled: false        # exclude this discovered port
      - port: 80
        localPort: 8080       # override the host port
  urlForward:
    enabled: true
    open: false               # record opened URLs; don't auto-launch

Use a model server running on your Mac from inside a workstation. The workstation reaches it at its own 127.0.0.1:11434:

apiVersion: core.ringleader.dev/v1
kind: LocalBinding
metadata:
  name: ollama
  namespace: dev
spec:
  workstationSelector:
    matchName: my-box
  reversePorts:
    - localPort: 11434        # the service on this device

Spec fields

FieldTypeDescription
enabledboolMaster on/off switch (default true). The CLI enable/disable flips this. A seed for a workstation shared with you is created with false.
workstationSelector.matchNamestringTarget a single workstation by exact name.
workstationSelector.matchLabelsmapSelect potentially many workstations by labels.
autoForward.forwardAllboolForward every discovered listening port.
autoForward.portOffsetintBulk-shift the host port of every 1:1 auto-forward (workstation 8080 → host 18080 when 10000); 0/absent ⇒ 1:1. A per-port localPort override is absolute (not shifted).
autoForward.ports[][]objectPer-port overrides: {port, enabled, localPort} (localPort: 0 ⇒ ephemeral).
ports[][]objectStatic TCP forwards: {remotePort, localPort} (localPort: 0 ⇒ ephemeral).
sockets[][]objectStatic Unix-socket forwards: {remotePath, localPath}.
reversePorts[][]objectServices on this device carried into each selected workstation: {localPort, remotePort}. The workstation listens on its own 127.0.0.1:remotePort (default: localPort), and each connection reaches 127.0.0.1:localPort on this device.
urlForward.enabledboolEnable the browser/URL bridge (workstation → host).
urlForward.openboolAlso launch each forwarded URL in the host browser (default: record only).

Provide exactly one of workstationSelector.matchName or matchLabels.

reversePorts works on every provider the daemon connects to, cloud workstations included, for as long as the daemon holds its connection. It never reaches a workstation someone else shares with you, and a workstation’s defaultLocalBinding template cannot declare it: only this device’s owner decides which of its services a workstation may reach.

portOffset shifts only the 1:1 auto-forwards (a workstation port with no explicit localPort override); static ports[] and per-port localPort values are left absolute. If a shifted host port would fall outside the valid 1–65535 range, the offset is skipped for that one port (it forwards 1:1) rather than wrapping around, so a large offset never lands a high workstation port on 0 or a privileged low port.

Status fields

The daemon writes these per-device.

FieldTypeDescription
messagestringThe one human headline, e.g. 3 forwards active, 2 forwards active, 1 dropped, port forwarding is disabled for this binding, or no connected workstation matches matchName=web.
bindings[][]objectEndpoints actually forwarded right now: {kind, workstation, remotePort/localPort or remotePath/localPath, source, active}. kind is tcp, unix, or reverse; for reverse, localPort is on this device and remotePort in the workstation. source is static, auto, or seeded.
dropped[][]objectWanted forwards not forwarded, each with a human reason (e.g. host-port conflict, or a port the workstation would not listen on).
conditions[][]objectA Ready condition. Its reason is one of Disabled, DisabledSeed, Degraded, NotConnected, NoForwards, SharedWorkstation or Pending. DisabledSeed means the daemon created the binding disabled because the workstation is shared with you; its message gives the rl binding enable command that starts the forwarding. SharedWorkstation means the binding matched only workstations shared with you, and their owner has not set defaultLocalBinding.scope: accessors.

status.message is derived from the same computation as the Ready condition, so the headline and the condition can never disagree. Read the condition’s own message for the per-aspect detail.

Conflict handling

When two bindings name the same host port, the daemon resolves it deterministically (first-wins by workstation [namespace, name], then binding [namespace, name]) and records the loser in status.dropped with a reason. It is never silent. Inspect the live picture with rl binding show.