Skip to content

Host-Guest Socket Protocol

Wire Format

Length-prefixed JSON over a Unix stream socket:

┌─────────────────────────┬──────────────────────────────┐
│  4 bytes (big-endian)   │  N bytes (UTF-8 JSON)        │
│  payload length = N     │                              │
└─────────────────────────┴──────────────────────────────┘

Socket Location

Socket Path Created by
Host socket $XDG_RUNTIME_DIR/podbox/<name>.sock .socket Quadlet unit
Local guest socket /run/podbox/guest-<name>.sock podbox-guest --daemon

The host socket is created by systemd before the container starts and persists across restarts. The guest socket is used by interceptor processes to communicate with the local daemon.


Handshake

Guest sends:

{
  "type": "hello",
  "version": "0.1.0",
  "container": "myenv",
  "capabilities": ["notify", "xdg_open", "clipboard", "host_exec"]
}

Host responds:

{
  "type": "hello_ack",
  "accepted": ["notify", "xdg_open"],
  "rejected": ["clipboard", "host_exec"],
  "idle_timeout_secs": 0
}

The handshake establishes which capabilities the host allows and conveys the configured idle timeout (0 = disabled). The guest daemon only installs interceptor symlinks for accepted capabilities.


Message Types

Guest → Host

Type Fields
hello protocol_version, guest_version, container, capabilities
notify summary, body, urgency, actions (optional), app_name (optional)
xdg_open uri
clipboard_set text
clipboard_get
host_exec cmd, args
register_session — (pidfd via SCM_RIGHTS)
busy
idle_timeout

Host → Guest

Type Fields
hello_ack accepted, rejected, idle_timeout_secs
clipboard_data text
host_exec_stdout data
host_exec_stderr data
host_exec_done exit_code
notify_action_result notification_id, action_key
ping
check_idle
shutdown

Notify Actions

When present, actions is an array of objects with a key and label:

{
  "type": "notify",
  "summary": "Build complete",
  "body": "Exit code: 0",
  "actions": [
    { "key": "open", "label": "Open project" },
    { "key": "dismiss", "label": "Dismiss" }
  ]
}

The host sends notify_action_result with the notification_id and user-selected action_key back to the guest.

The actions and app_name fields use #[serde(default)] for backward compatibility with older guest binaries that do not send them.


Capabilities

Each capability corresponds to an interceptor symlink installed by the guest daemon:

Capability Interceptor Description
notify notify-send Desktop notification forwarding
xdg_open xdg-open URI opening via host
clipboard podbox-clipboard Clipboard sharing
host_exec host-exec Execute commands on host

Capabilities not accepted during handshake are silently skipped — no symlink is created and the guest does not attempt to use them.