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--devorQPOINT_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, orQPOINT_DATA. Debug builds default tosynthetic, release builds tolocal. --world <name>orQPOINT_WORLDpicks 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.
- It looks for the dashboard's lock file:
<data dir>/dash/qdash.sock.lock, or beside the socket named byQCONTROL_DASH_SOCKET_PATH. - The second line of that file is the dashboard's URL. The first line is its pid.
- 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.dashboardabsent means on (crates/qconfig/src/file.rs). - The dashboard is the one embedded in the monitor. A static
qdash servehas 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.1or[::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.
| Platform | qcontrol (qconfig::data_dir_path) | The app (nozzle::data_dir) |
|---|---|---|
| macOS | ~/Library/Application Support/com.qpoint.qcontrol | the same, since Phase 2 (it was …/qcontrol) |
| Linux | ~/.local/share/qcontrol | the same; it also honours XDG_DATA_HOME |
| Windows | the 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)
| Rung | The check | What it says | If it fails here |
|---|---|---|---|
| Not found | no lock file in the data dir, or a stale one | no sensor on this machine | is the monitor running; is the data dir the one in the table above |
| Found | lock file present and its pid alive | installed and running | a dead pid means a stale lock: start the monitor |
| Answering | GET /api/stats returns 200 | connected; the events it has seen (the version is not served: c131 D17's /api/sensor) | a refused connection: the dashboard is off (ui.dashboard) |
| Streaming | the event stream opens | live | see Refused |
| Lost | it was connected and is retrying | reconnecting, with the attempt and the reason | the monitor restarted, or the app fell behind and was cut off |
| Refused | 403 or 503 | reachable but not serving | 403: 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).