Skip to main content

sandbox-comm

Trigger host actions from inside a micro-VM sandbox or Docker container by sending HTTP requests to a daemon running on the host.

The guest sends a JSON POST request to http://host.docker.internal:PORT/. The host daemon receives it and executes the requested action (desktop notification, shell command, etc.).

Why HTTP?

Unix domain sockets require both ends to be in the same kernel — they don't work across virtiofs/9p filesystem boundaries used by micro-VM sandboxes. vsock requires explicit hypervisor support. HTTP over TCP works universally: the sandbox proxy routes connections to host.docker.internal to the host's localhost, and the only requirement is opening the port in the sandbox network policy.

Installation

On the host:

pip install docker-sandbox-guest-to-host-communicator

On the guest (sandbox or container), either install the same package or copy docker_sandbox_guest_to_host_communicator/client.py — it has zero non-stdlib dependencies.

Quick start

  1. Open the port in the sandbox network policy (run on the host):

    sbx policy allow network -g "localhost:9999"
    
  2. Optionally create a config file (the SANDBOX_COMM_URL env var works too):

    mkdir -p ~/.config/sandbox-comm
    cat > ~/.config/sandbox-comm/config.toml <<EOF
    port = 9999
    allowed_commands = ["make", "git", "npm"]
    log_level = "INFO"
    EOF
    
  3. Start the host daemon:

    sandbox-comm-daemon
    # or: python -m docker_sandbox_guest_to_host_communicator.daemon
    
  4. From the guest:

    sandbox-comm ping
    sandbox-comm notify --title "Build" --body "Tests passed"
    sandbox-comm play
    sandbox-comm exec make test
    
    # To use a different URL either set SANDBOX_COMM_URL or use the --url argument 
    export SANDBOX_COMM_URL=http://host.docker.internal:9999
    sandbox-comm --url http://host.docker.internal:9999 ping
    

Actions

Action Args Description
ping — No-op, confirms the daemon is reachable
notify --title TEXT --body TEXT Show a desktop notification via notify-send
play — Play an audio file on the host (file configured on the daemon)
exec CMD [ARGS...] Run a command on the host (must be in allowed_commands)

notify and exec also accept JSON piped on stdin (Claude Code hook format):

echo '{"title":"Permission needed","message":"Claude needs Bash access"}' \
  | sandbox-comm notify

echo '{"session_id":"abc","cwd":"/tmp"}' \
  | sandbox-comm exec make test   # JSON fields become env vars: SESSION_ID, CWD, ...

play

The play action plays a pre-configured audio file on the host. The guest only triggers it — the file path is set on the daemon side via --sound-file or sound_file in the config:

# Start the daemon on the host with a sound file
sandbox-comm-daemon --sound-file /usr/share/sounds/freedesktop/stereo/complete.oga

# Trigger playback from the guest
sandbox-comm play

The daemon tries these players in order: paplay, aplay, mpg123, ffplay.

Docker usage

docker run -e SANDBOX_COMM_URL=http://host.docker.internal:9999 \
  my-image sandbox-comm notify --body "done"

Running as a systemd service

User service (recommended for desktop use)

cp systemd/sandbox-comm.service ~/.config/systemd/user/sandbox-comm.service

# Edit the port if needed (default: 9999)

systemctl --user daemon-reload
systemctl --user enable --now sandbox-comm
systemctl --user status sandbox-comm

# Logs
journalctl --user -u sandbox-comm -f

System service (headless / multi-user)

useradd -r -s /sbin/nologin sandbox-comm
cp systemd/sandbox-comm-system.service /etc/systemd/system/sandbox-comm.service

# Edit /etc/systemd/system/sandbox-comm.service to change the port if needed

systemctl daemon-reload
systemctl enable --now sandbox-comm
systemctl status sandbox-comm

# Logs
journalctl -u sandbox-comm -f

UFW

If UFW is running on the host, allow the port (scope it to the virtual interface for tighter control):

sudo ufw allow 9999/tcp comment "sandbox-comm"

Adding custom actions

Register a new action in daemon.py using the @action decorator:

from docker_sandbox_guest_to_host_communicator.daemon import action

@action("open_url")
async def _open_url(args: dict) -> None:
    import webbrowser
    webbrowser.open(args["url"])

Config reference

~/.config/sandbox-comm/config.toml (or /etc/sandbox-comm/config.toml):

port = 9999                          # daemon listens on this port (0.0.0.0:port)
host = "host.docker.internal"        # client connects here
allowed_commands = ["make", "git"]   # empty list = allow all exec commands
log_level = "INFO"                   # DEBUG, INFO, WARNING, ERROR
`sound_file = "/usr/share/sounds/freedesktop/stereo/complete.oga"  # played by 'play' action

The SANDBOX_COMM_URL environment variable overrides both host and port:

export SANDBOX_COMM_URL=http://host.docker.internal:9999

The client URL is resolved in this order, with earlier sources taking precedence:

  1. --url URL flag on the sandbox-comm command
  2. SANDBOX_COMM_URL environment variable
  3. host and port in the config file
  4. http://host.docker.internal:9999 (built-in default)

The daemon always listens on 0.0.0.0:PORT and accepts --port PORT and --sound-file PATH to override config values.

Metadata

Release files for docker-sandbox-guest-to-host-communicator 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for docker-sandbox-guest-to-host-communicator 1.0.0
File Size Uploaded Provenance
docker_sandbox_guest_to_host_communicator-1.0.0.tar.gz 34.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for docker-sandbox-guest-to-host-communicator 1.0.0
File Interpreter ABI Platform
docker_sandbox_guest_to_host_communicator-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 68.4 kB

Release files / docker_sandbox_guest_to_host_communicator-1.0.0.tar.gz

Download URL docker_sandbox_guest_to_host_communicator-1.0.0.tar.gz
Size 34.5 kB
Tags Source
SHA-256 checksum
How to use checksums
76f0a100daacacb0b0be04fb3881df2e72301b30818e6e3d5b1cd4c69c472283
BLAKE2b-256 checksum
How to use checksums
7e71adde2013e8730970a79172d062a07d7683ee45ac01f290600affa322f3f7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 16, 2026.

Transparency log

Release files / docker_sandbox_guest_to_host_communicator-1.0.0-py3-none-any.whl

Download URL docker_sandbox_guest_to_host_communicator-1.0.0-py3-none-any.whl
Size 33.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8cb770ad901f3cac6697ccc553a2f9d23830e8fc220bd9ffa8d66eacac49a825
BLAKE2b-256 checksum
How to use checksums
8ab4a571f9d710abb97fdb70c25aa65838af4134bfa5f1af3e0947db7e6bbbbc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 16, 2026.

Transparency log

Security for docker-sandbox-guest-to-host-communicator 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for docker_sandbox_guest_to_host_communicator-1.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 16, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page