← Qnative (provisional) · c3

guide/02-run-it.md

Run it on your machine

Standing: built through Phase 2 (2026-11-11): Dev › Source, the ladder and the doctor. The feed check is Phase 5's.

Today: build and run

cargo dev                                              # the alias for the line below
cargo run -p app --features dev                        # debug: developer pages on, synthetic data
cargo run -p app --features dev -- --data local        # this machine's sensor
cargo run --release -p app --features dev -- --dev     # release, developer pages allowed
cargo run -p app                                       # the lean build: no developer pages at all
  • Since Phase 0 the default build is lean: developer mode is compiled in only with --features dev. In that build it is allowed in debug, and in release with --dev or QPOINT_DEV=1; where it is allowed, the tray menu's Developer mode item turns it off and on, and the choice is remembered.
  • The data source is one switch for the whole process: --data synthetic|local|plane, or QPOINT_DATA. Debug builds default to synthetic, release builds to local.
  • --world <name> or QPOINT_WORLD picks a bundled synthetic world.
  • The footer of the window always names the source.

Today: how the app finds a sensor

With --data local the app reads one file and then speaks HTTP over loopback.

  1. It looks for the dashboard's lock file: <data dir>/dash/qdash.sock.lock, or beside the socket named by QCONTROL_DASH_SOCKET_PATH.
  2. The second line of that file is the dashboard's URL. The first line is its pid.
  3. It then GETs the same /api/* routes the dashboard's own UI uses. No credential.

What the sensor must be doing for this to work:

  • The monitor is running, with the dashboard on. ui.dashboard absent means on (crates/qconfig/src/file.rs).
  • The dashboard is the one embedded in the monitor. A static qdash serve has no live hub and answers the stream with 503.
  • The port is 7878 unless it was taken, in which case it is whatever the lock file says. Do not assume 7878.
  • The server refuses any request whose Host is not localhost, 127.0.0.1 or [::1] (crates/qdash/src/web.rs, require_local_host).

The data directory (fixed on macOS in Phase 2)

The app carries its own copy of qcontrol's data-directory rule, so that it compiles without qcontrol.

Platformqcontrol (qconfig::data_dir_path)The app (nozzle::data_dir)
macOS~/Library/Application Support/com.qpoint.qcontrolthe same, since Phase 2 (it was …/qcontrol)
Linux~/.local/share/qcontrolthe same; it also honours XDG_DATA_HOME
Windowsthe directories crate's data dir for com / qpoint / qcontrol%LOCALAPPDATA%\qcontrol: still different, not yet checked on a Windows machine

QCONTROL_DATA_DIR moves it, and QCONTROL_DASH_SOCKET_PATH moves the socket and its lock file.

  • A stale lock file is caught. When the monitor stopped without cleaning up, the lock file is still there, but its pid no longer runs. The ladder checks the pid before it tries the URL.
  • The elevated monitor is still open. If the monitor runs as root, can a user-level app read the lock file? That is a question for the sensor's engineer (Monitor, question 2).

Dev › Source (built in Phase 2)

Source is where the data comes from, for the whole app. It sits in the Dev group. "Sensor" under This machine is a different page: V1's view of qcontrol itself.

  • Synthetic: a world, a condition (healthy, sensor not running, slow answers, no live stream (503), a shape that does not match, the stream lags then is cut) and a stream (quiet, coding-session, mcp-heavy, file-storm, at the script's rate or 10, 100 or 1,000 a second). See Synthetic scenarios. Every condition goes through the real pipes, so each page draws it with its own honest state.
  • This machine: found through the lock file, with the ladder below.
  • An address: the near end of an SSH tunnel, with the same ladder from Answering up.
ssh -N -L 7878:127.0.0.1:<the sensor's port> you@the-box    # the port from the box's lock file

Then enter http://127.0.0.1:7878 on Source and press Attach. The footer says sensor at http://127.0.0.1:7878. The plane transport is no longer the way to do this (ruling 3).

A choice applies at once. The nozzle is swapped for the process through the one re-open path (host::reopen, c131 D16), and every page reads again. The choice is saved, and the next start applies it unless a flag or the environment says otherwise. The precedence is flag, then environment, then the saved choice, then the build's default. The lean build has no page and reads this machine's sensor.

The ladder (built: nozzle::ladder)

RungThe checkWhat it saysIf it fails here
Not foundno lock file in the data dir, or a stale oneno sensor on this machineis the monitor running; is the data dir the one in the table above
Foundlock file present and its pid aliveinstalled and runninga dead pid means a stale lock: start the monitor
AnsweringGET /api/stats returns 200connected; the events it has seen (the version is not served: c131 D17's /api/sensor)a refused connection: the dashboard is off (ui.dashboard)
Streamingthe event stream openslivesee Refused
Lostit was connected and is retryingreconnecting, with the attempt and the reasonthe monitor restarted, or the app fell behind and was cut off
Refused403 or 503reachable but not serving403: the Host is not local (use a tunnel, not an opened port). 503: a static qdash serve with no hub (start the monitor)

At an address the first two rungs do not apply, and the ladder starts at Answering.

The doctor (built: app --check-sensor)

The same checks from the command line, so a failing rung can be read without opening a window. It exits 0 only when the stream is live. These two are real runs on 2026-11-11:

$ app --check-sensor
sensor check: this machine (lock file ~/Library/Application Support/com.qpoint.qcontrol/dash/qdash.sock.lock)
  ok   lock file  …/qdash.sock.lock names http://127.0.0.1:7878
  FAIL running    the lock file names pid 54415, which is not running: a stale lock
reached: Not found. Start qcontrol's monitor on this machine, or attach to a sensor at an address.

$ app --check-sensor --sensor-url http://127.0.0.1:7882
sensor check: http://127.0.0.1:7882
  --   lock file  this machine only
  --   running    this machine only
  ok   answering  GET /api/stats 200: 50730 events seen; the version is not served yet (c131 D17's /api/sensor)
  FAIL streaming  the sensor has no live stream (503): live stream unavailable: static `qdash serve` has no live hub
reached: Refused. Reachable but not serving: a 403 means the Host was not local (use an SSH tunnel, not an opened port); a 503 means a static `qdash serve` (start the monitor instead).

Still to come: listing each feed the pages need as served, missing or mismatched, once the Monitor's routes exist (Phase 5).

Qpoint Brand Style Guide