Skip to content

Running an application: vericue run

vericue run starts your Qt application with the veriCue Runtime already inside it. One command, no code changes, no rebuild, no linking:

bash
vericue run ./your-qt-app
# VERICUE_ENDPOINT=/run/user/1000/vericue/vericue-4213.sock

That endpoint is a live veriCue server inside your application, exposing its object tree over the protocol with the full command surface - interaction, screenshots, model/view access, subscriptions, recording. Drive it with any client:

bash
vericue --endpoint /run/user/1000/vericue/vericue-4213.sock list_objects

This is the front door. It is deliberately the only thing you need to know: which mechanism gets the Runtime into the process, which probe matches your Qt, what has to be on LD_LIBRARY_PATH - all of that is the command's business, not yours.

Not serverless

veriCue Runtime code runs inside your application process. That is what makes full QObject / QWidget / QQuickItem introspection possible. vericue run changes how the Runtime gets there, not where it runs.

Install

vericue run ships with the Python client, which is where the vericue command lives:

bash
pip install vericue

The Runtime it loads into your application comes from the platform package - see Installation. Keep that package's bin/ and lib/ together; put bin/ on $PATH, or point VERICUE_HOME at the package root:

bash
export VERICUE_HOME=/opt/vericue
vericue run ./your-qt-app

If the package cannot be found, the command says so and lists every path it tried rather than failing somewhere inside your application.

Where it works today

Supported
Linux x64yes - dynamically linked Qt 5.15 / Qt 6 applications, Widgets and Qt Quick; local IPC by default, TCP on --port
Windows x64yes - dynamically linked Qt 5.15 / Qt 6 applications, Widgets and Qt Quick; TCP only. Uses a launch-time DLL load that endpoint security can block - read Windows launch path first
macOSno - the hardened runtime blocks loading code into another process; embed

The exact Linux compatibility envelope, and every case that is refused, is in Zero-source-change runs. On Windows the envelope and the security implications are in Windows launch path. vericue run uses each platform's preflight: there is one compatibility model per platform, and the command asks it before starting anything.

Windows uses TCP and a DLL-injection technique

On Windows the default transport is TCP (local IPC is not available), and the Runtime is loaded with CreateRemoteThread + LoadLibraryW, which antivirus and EDR products may block. This is a real constraint, not a footnote - see Windows launch path before relying on it in CI or on a managed fleet.

On an unsupported platform vericue run says so before starting anything and names the embedding fallback. Embedding is not a downgrade - it is the setup that works everywhere, can be compiled out of release builds, and is the recommended one for CI.

What Qt your application needs

The Runtime uses your application's Qt. veriCue does not put a second Qt into your process, and you should never copy veriCue's Qt libraries into your deployment to make injection work - two QtCore builds in one process abort on sight. (The Inspector is a different matter: it is a separate application, and its package carries its own Qt for its own process.)

That makes the Runtime's Qt modules a prerequisite your deployment has to satisfy:

ModuleNeededWhy
Qt Corealwayseverything
Qt Guialwaysscreenshots, the QPA boundary, input events
Qt Networkalwaysthe Runtime's TCP transport, and licence checks
Qt Widgetsonly if your application uses itthe Widgets backend is a separate plugin, loaded only when the module is already in your process
Qt Quickonly if your application uses itlikewise, a separate plugin - this is the module a QML application already has
Qt Qml / Qt QmlModels / Qt OpenGLonly if your application uses Qt QuickQt Quick is built on them, so an application that has Quick already has these. They are listed because the macOS build records them explicitly, and this table is checked against the shipped binaries rather than written from memory

Qt Network is required even if your application never uses it

This is the one that surprises people. The Runtime links Qt Network for its own transport, so a deployment trimmed down to Core and Gui - common for a kiosk or an embedded target - cannot host the injected Runtime until QtNetwork is present. It is not optional and there is no build of the Runtime without it.

The two toolkit backends are independent. A Widgets application does not need Qt Quick installed because veriCue is injected, and a QML application does not gain a QtWidgets dependency. Each backend is loaded only after the Runtime finds that module already mapped in the process, which is also why a pure QML application never pulls QtWidgets in.

Check before you run

bash
vericue run --check ./your-qt-app
vericue-inject: preflight OK
  target      ./your-qt-app (ELF64 x86-64)
  target Qt   6.7.1  [/opt/qt/6.7.1/lib/libQt6Core.so.6]
  toolkits    quick
  probe       /opt/vericue/lib/libvericue-inject.so
  probe build veriCue 0.4.0, Qt 6.7.1
  runtime     /opt/vericue/lib
  plugins     libvericue-widgets.so libvericue-quick.so
  transport   local IPC (auto, announced as VERICUE_ENDPOINT)
  docs        https://vericue.dev/docs/guides/injector

The report comes from the shared preflight, which is why it names the mechanism (vericue-inject on Linux). This is the first thing to attach to a support request.

Passing arguments to your application

Everything after -- belongs to your application and reaches it unchanged, including further -- and anything that looks like a veriCue option:

bash
vericue run ./your-qt-app -- --config prod.ini --verbose
bash
# --port here is your application's, not veriCue's
vericue run --port 4242 ./your-qt-app -- --port 8080

vericue inspect takes the tail the same way, because it starts your application too:

bash
vericue inspect ./your-qt-app -- --config prod.ini

Exit status and Ctrl-C

On Linux, vericue run does not sit between you and your application: it replaces itself with the application process. So there is nothing to explain:

  • the exit status you see is the application's own;
  • Ctrl-C reaches the application, because it is the foreground process;
  • an application killed by a signal is reported by your shell the usual way (128 + signo), because it really did die that way.
bash
vericue run ./your-qt-app -- --selftest; echo "exit $?"

On Windows there is no execve that replaces the running image, so vericue run starts vericue-inject.exe, which starts your application and supervises it. The outcome you rely on is the same - the exit code you see is the application's own, and Ctrl-C reaches the application because it shares the console - but there is a supervising process in the chain rather than a single replaced one.

A vericue run that refuses to start exits 1 and explains why on stderr, before your application has been started at all.

Transports

Local IPC is the default for same-host runs: a user-private UNIX socket with no network presence at all. The endpoint is announced on stdout as VERICUE_ENDPOINT=<path>.

The endpoint, without reading stdout

In CI you usually do not want to scrape the application's output. --announce writes the endpoint to a file of your choosing, before the application starts:

bash
vericue run --announce /tmp/ci/vericue.endpoint ./your-qt-app &
# /tmp/ci/vericue.endpoint contains: VERICUE_ENDPOINT=/tmp/ci/vericue.endpoint.sock

The file names where the endpoint will be, so wait for the socket itself before connecting:

bash
ENDPOINT=$(sed -n 's/^VERICUE_ENDPOINT=//p' /tmp/ci/vericue.endpoint)
for _ in $(seq 1 60); do [ -S "$ENDPOINT" ] && break; sleep 0.5; done
vericue --endpoint "$ENDPOINT" ping

Put the announce file in a directory only you can read. The socket beside it is always created owner-only, but a world-readable directory lets other users on the machine see that it exists - $XDG_RUNTIME_DIR is the obvious place, and the Runtime says so on stderr when the directory is more open than that.

--announce needs an endpoint that is knowable up front, so it pins one:

what you passedwhat is announced
nothingVERICUE_ENDPOINT=<announce file>.sock - the launcher pins that path
--endpoint PATHVERICUE_ENDPOINT=PATH
--port N (N > 0)VERICUE_PORT=N
--port 0refused: the port is chosen by the OS inside the application, so read the VERICUE_PORT=<n> line from stdout instead

TCP

TCP is an explicit opt-in, because it is reachable from other hosts:

bash
vericue run --port 4242 ./your-qt-app
vericue --port 4242 list_objects

--port 0 lets the OS pick a free port, announced on stdout as VERICUE_PORT=<n>. --port and --endpoint are mutually exclusive.

TCP is plaintext on all interfaces

It is unauthenticated unless you also pass --token. See Transports for the full comparison.

Authentication and licensing

Identical to an embedded Runtime, because it is the same Runtime configured the same way:

bash
vericue run --token s3cret --license /etc/vericue/license.json ./your-qt-app
FlagEmbedded equivalent
--token TsetAuthToken("T")
--license FILEsetLicenseFile("FILE")
--license-server HOST:PORTsetLicenseServer(...)

With none of them the run is a trial, exactly as for an embedded server that was never given a license. The licensed concurrent-session budget is one budget and is shared across transports; starting an application this way does not widen it. A licensing configuration you asked for and that cannot be applied refuses the run rather than quietly degrading to a trial - details in Authentication and licensing.

Options

OptionEffect
--endpoint PATHpin the local IPC endpoint
--port Nexpose TCP on port N instead of local IPC (0 picks a free port)
--token TOKENrequire this token in the client handshake
--license FILEload an RSA-signed license file
--license-server HOST:PORTcheck a session out of a floating license server
--announce FILEwrite the endpoint announcement to FILE before starting
--checkrun the compatibility checks, report, and exit
--no-preflightskip the compatibility checks (support will ask why)

Environment: VERICUE_HOME (platform package root), VERICUE_INJECT (absolute path to the launch helper, overriding the search).

A CI job

bash
set -euo pipefail

vericue run --check ./your-qt-app            # fail fast on a bad runner

QT_QPA_PLATFORM=offscreen vericue run \
    --token "$VERICUE_TOKEN" \
    --announce "$PWD/vericue.endpoint" \
    ./your-qt-app > app.log 2>&1 &
APP=$!

ENDPOINT=$(sed -n 's/^VERICUE_ENDPOINT=//p' "$PWD/vericue.endpoint")
for _ in $(seq 1 60); do [ -S "$ENDPOINT" ] && break; sleep 0.5; done
[ -S "$ENDPOINT" ] || { cat app.log; exit 1; }

VERICUE_ENDPOINT="$ENDPOINT" pytest tests/

See CI integration for the full picture.

Relationship to vericue-inject

On Linux, vericue run starts your application through vericue-inject, which owns the compatibility model: the preflight, the probe selection and every refusal message. vericue-inject remains a supported, documented interface - use it directly when you want the mechanism in front of you, or when you have no Python available on the machine that starts the application. Its guide is Zero-source-change runs.

The two are not alternatives with different capabilities. vericue run is the stable command; the mechanism behind it is free to differ per platform without your scripts changing.

Released under a commercial licence. Privacy · Terms