Isolate AI coding agents like Pi with kernel-level policies and a locally served vLLM model
| Symptom | Cause | Fix |
|---|---|---|
openshell status shows "Connection refused" | The openshell-gateway systemd user service is not running, or Docker socket is not accessible from the user service | Start it: systemctl --user start openshell-gateway. Check logs: journalctl --user -u openshell-gateway --no-pager -n 50. If the service cannot reach Docker, fix socket access with sudo setfacl -m u:$USER:rw /var/run/docker.sock, then restart the service |
| Gateway service fails to start after installation | Docker is not running | Start Docker: sudo systemctl start docker. Then restart the OpenShell gateway service: systemctl --user restart openshell-gateway |
openshell status shows gateway as unhealthy | Gateway service or container crashed / failed to initialize | Run systemctl --user restart openshell-gateway and inspect journalctl --user -u openshell-gateway --no-pager -n 50. Check Docker with docker ps -a and docker logs <container-id> |
openshell sandbox create --from pi-agent:local fails because the image isn't found | The image was built with a different container engine than the gateway's compute driver, or wasn't built at all | Confirm the build succeeded: docker images pi-agent:local. If the gateway uses Podman, build with podman build -t localhost/pi-agent:local -f Dockerfile.pi . and reference localhost/pi-agent:local. If the gateway runs on different hardware than this shell, push the image to a registry the gateway can pull from instead of using a local tag |
Sandbox is in Error phase after creation | Policy validation failed, a referenced provider profile is missing, or the container failed to start | Run openshell logs <sandbox-name> to see error details. Common causes: invalid policy or profile YAML, a provider profile that was never imported, or port conflicts |
Agent gets Error: Connection error. calling the local provider, even though the endpoint and model look right | The calling binary isn't in the attached profile's binaries list — a binary being allowed for one endpoint doesn't grant it access to others, and vice versa | Reproduce the request, then check openshell logs <sandbox-name> --tail for a line like DENIED /path/to/binary -> host:port [reason:transparent_tcp_policy_denied]. Add that exact binary path to the profile's binaries (export → edit → profile lint → profile update, per Step 11), then openshell sandbox provider attach <sandbox-name> <provider-name> --wait |
Agent gets repeated Error: Connection error. against the local vLLM endpoint, and openshell logs --tail shows NET:FAIL (not DENIED) for that destination | vLLM itself isn't responding — crashed, OOM, hung on a prior request, or was never started | From the host, confirm it's actually serving: curl -s http://0.0.0.0:8000/v1/models. Check the terminal/logs where vLLM is running for errors, and check nvidia-smi to see if the GPU is pegged or the process is gone. This is a host-side vLLM problem, not an OpenShell policy issue — a NET:FAIL means the connection never completed, unlike a DENIED line, which means policy blocked it |
| Agent's outbound connections are all denied for a destination you expect to be allowed | The attached provider's profile doesn't declare that host/port in endpoints, or doesn't declare the calling binary in binaries | Follow the profile update workflow in Step 11: export the profile, add the missing endpoints/binaries entry, lint, then openshell profile update <profile-id> -f <file>. For a one-off override scoped to a single sandbox instead of the shared profile, openshell policy get <sandbox-name> (without --full) and openshell policy set <sandbox-name> --policy <file> --wait work directly against that sandbox — see the next row for a common mistake with this path |
openshell policy set fails with unknown field 'Version' | openshell policy get --full prepends a metadata header (including a Version field) that policy set does not accept | Use openshell policy get <sandbox-name> without --full to export only the policy YAML. If you already have output with the metadata header, strip every line before the first --- (or before the first policy key) before passing it to policy set |
| "Permission denied" or Landlock errors inside the sandbox | Agent trying to access a path not in read_only or read_write filesystem policy | Pull the current policy and add the path to read_write (or read_only if read access is sufficient). Push the updated policy. Note: filesystem policy is static and requires sandbox recreation |
| vLLM OOM or very slow inference | Model too large for available memory or GPU contention | Free GPU memory (close other GPU workloads), choose a smaller model, or lower --gpu-memory-utilization / --max-model-len. Monitor with nvidia-smi |
openshell sandbox connect or sandbox exec refuses with "canonical main process already finished" / "sandbox is not ready (phase: Completed)" | The sandbox's main process (Pi) already exited — a Completed sandbox is retained for inspection (sandbox get, policy get, logs) but cannot accept a new attachment or exec'd process | There is no way to resume interactive work in a Completed sandbox — delete and recreate it (Step 8). To avoid this, detach instead of quitting next time: press Ctrl-P then Ctrl-Q rather than typing /quit, which keeps Pi running so sandbox connect has something to reattach to |
| Policy push returns exit code 1 (validation failed) | Malformed YAML or invalid policy/profile fields | Check the YAML syntax. Common issues: paths not starting with /, .. traversal in paths, root as run_as_user, endpoints missing required host/port fields, or a mapping entry landed outside its intended list because it was appended to the end of the file instead of inserted in place (see Step 11's sed insertion pattern) |
Gateway service won't become healthy, and journalctl shows it stuck rather than crashing outright | The gateway's internal bootstrap (compute driver, database, or container runtime) is taking longer than expected, or Docker doesn't have enough resources | Check journal logs: journalctl --user -u openshell-gateway --no-pager -n 50. Check whether the container is still progressing: docker ps --filter name=openshell. Ensure Docker has enough memory and disk. If it does not recover, systemctl --user stop openshell-gateway, docker rm -f <container>, then systemctl --user start openshell-gateway |
openshell status says "No gateway configured" | Gateway service never started or was disabled | Start the gateway: systemctl --user start openshell-gateway, then verify with openshell status (optionally systemctl --user enable openshell-gateway to auto-start on login). If the Docker container is unhealthy, run systemctl --user stop openshell-gateway, docker rm -f <container>, then systemctl --user start openshell-gateway |
| TLS / certificate errors when registering a remote gateway by raw LAN IP | The gateway's certificate may not validate against a bare IP address | Map a hostname to the hardware IP in /etc/hosts on the workstation you're connecting from, then register by that hostname instead of the raw IP: openshell gateway add https://<hostname>:17670 --name <name> (see Step 4) |
NOTE
Some hardware platforms use Unified Memory Architecture (UMA), which enables dynamic memory sharing between the GPU and CPU. With many applications still updating to take advantage of UMA, you may encounter memory issues even when within capacity. If that happens, manually flush the buffer cache with:
sudo sh -c 'sync; echo 3 > /proc/sys/vm/drop_caches'