Transports: local IPC vs TCP
The veriCue Runtime accepts automation clients over two transports, whether it was embedded or injected. They speak the identical protocol - same length-prefixed JSON framing, same commands, same handshake, same authentication and the same licensed session budget. The only difference is who can reach the server.
| Local IPC | TCP | |
|---|---|---|
| Endpoint | UNIX-domain socket | host + port |
| Platforms | Linux, macOS (Windows not supported yet) | Linux, macOS, Windows |
| Reachable from another host | No, by construction | Yes, on every interface |
| Access control | File permissions: owner only (0600) | Anyone who can reach the port |
| Start with | server.startLocal() | server.start(port) |
| Announced as | VERICUE_ENDPOINT=<path> | VERICUE_PORT=<n> |
| Use it for | Local runs, developer machines, single-host CI | Remote CI, containers, devices, cross-host |
Rule of thumb: if the client and the application under test run on the same Linux or macOS machine, use local IPC. Reach for TCP on Windows, and whenever something has to cross a machine or container boundary.
Default for injected runs
vericue-inject uses local IPC unless you pass --port. Nothing is exposed on the network unless you ask for it.
Local IPC
vericue::VeriCueServer server(&window);
if (server.startLocal())
qInfo() << "veriCue endpoint:" << server.localEndpoint();startLocal() with no argument picks a per-process endpoint inside a user-private runtime directory:
$XDG_RUNTIME_DIR/vericue/vericue-<pid>.sockIf XDG_RUNTIME_DIR is not set (bare login shells, minimal containers), the directory falls back to <tmp>/vericue-<uid>. You can also pass your own endpoint - a bare name is placed in that same runtime directory, an absolute path is used verbatim:
server.startLocal("my-app.sock"); // in the runtime directory
server.startLocal("/run/user/1000/my-app.sock"); // exact pathRead the resolved value back with server.localEndpoint().
Why it is safe by construction
- The socket is created with owner-only permissions, so no other user on the machine can open it - even in a shared runtime directory.
- A UNIX-domain socket has no network presence at all: no port, no interface, nothing for a remote host to connect to. Firewalling it is not something you can forget to do.
- Authentication (
setAuthToken()), the handshake gate and the licensed concurrent-session limit apply exactly as they do over TCP. Local IPC bypasses none of it.
Endpoint path length
UNIX-domain socket paths are limited by sockaddr_un::sun_path - 107 bytes on Linux. veriCue validates the path before binding and fails with an explicit message rather than an opaque bind error:
Local endpoint path is too long: 130 bytes, the platform limit is 107
(sizeof(sockaddr_un::sun_path) - 1). Use a shorter path - for example a
directory under $XDG_RUNTIME_DIR. Rejected path: /very/long/...Deep build directories are the usual cause. Keep endpoints in $XDG_RUNTIME_DIR.
Stale endpoints
If an application is killed hard, its socket file can survive. On the next start veriCue probes the endpoint: if a server is listening it refuses to start ("already in use"), and if nothing answers it removes the leftover and takes it over. A normal shutdown (stop(), or the server object being destroyed) removes the endpoint itself.
Windows
Local IPC is not supported on Windows yet. QLocalServer would map to a named pipe there, but veriCue neither builds nor tests that path, so the public API documents it as unsupported rather than advertising it - see the limitations. Use TCP on Windows.
TCP
vericue::VeriCueServer server(&window);
server.setAuthToken("s3cret");
server.start(4242); // 0 = let the OS pick, read back with serverPort()The port is reachable on every interface, so treat it as a remote-control surface: always set a token outside a single-developer machine, firewall it or tunnel it. See the security model.
Connecting
from vericue import VeriCueClient
async with VeriCueClient() as client:
await client.connect_local("/run/user/1000/vericue/vericue-4213.sock")
# ... or over TCP:
# await client.connect("127.0.0.1", 4242)auto *client = new vericue::VeriCueClient(this);
client->connectToLocalServer("/run/user/1000/vericue/vericue-4213.sock");
// ... or over TCP:
// client->connectToServer("127.0.0.1", 4242);await using var client = new VeriCueClient();
await client.ConnectLocalAsync("/run/user/1000/vericue/vericue-4213.sock");
// ... or over TCP:
// await client.ConnectAsync("127.0.0.1", 4242);python -m vericue --endpoint /run/user/1000/vericue/vericue-4213.sock list_objects
python -m vericue --port 4242 list_objectsAll of them perform the handshake automatically and accept the same optional authentication token.

