Nine public commands, and vigil --help names every one of them:
| Command | What it does |
|---|---|
vigil run |
Starts the camera runtime, the local store, the health and review servers, and the owner channel every command below is answered on |
vigil events |
Lists this deployment's recent landed detection events, newest first |
vigil why |
Walks one detection back through its camera, site, detector Decision, baseline Intention and evidence |
vigil stats |
Prints this deployment's own persisted snapshot of pipeline counters and health |
vigil settings |
Reads and changes what this deployment is configured to run at, and reports what it is running at now |
vigil enroll |
Names the subject in a detection, so later sightings match that name |
vigil forget |
Removes this site's recognition references for a named subject |
vigil doctor acceleration |
Reports the decode and detection acceleration this host actually offers |
vigil fabric ticket |
Prints this node's fabric enrollment ticket, on explicit invocation only |
A tenth command is dispatched and deliberately kept off that list: vigil detector-probe belongs
to the detection-probe machinery rather than to an operator, and is described under
Detector probe. This page documents each public command and the answers it
gives.
vigil run [OPTIONS]Starts the camera runtime, local store, health server, review server, the owner channel the CLI reaches this process on, and configured Home Assistant and recognition tasks.
If another process is reading this deployment's store when the runtime starts, the runtime waits for it rather than failing. It says on its startup output that it is waiting and what it is waiting for, and it starts normally the moment the reader finishes. There is no timeout on that wait and no setting that shortens it: a reader that is genuinely working is not a fault, and a runtime that gave up on one would leave a healthy node down for a condition that was about to clear.
Common options:
| Option | Meaning | Default |
|---|---|---|
--config PATH |
Read a TOML configuration file | none |
--data-dir PATH |
Runtime data root | ./vigil-data |
--store-path PATH |
Context Graph store | <data-dir>/store.contextgraph |
--health-port PORT |
Health HTTP port | 8099 |
--review-port PORT |
Review HTTP port | 8098 |
--site-name NAME |
Site/context name | site-1 |
--camera-name NAME |
Single-camera name | camera-1 |
--rtsp-url URL |
Detection stream | none |
--live-rtsp-url URL |
Separate Home Assistant live stream | detection URL |
--usb-device IDENTITY |
Legacy single-camera USB source | none |
--csi-module IDENTITY |
Legacy single-camera CSI source | none |
--mjpeg-url URL |
Legacy single-camera MJPEG source | none |
--rtsp-username USER |
RTSP username outside the URL | none |
--rtsp-password PASSWORD |
RTSP password outside the URL | none |
--detector-model-id ID |
Model identity written to provenance | yolox-tiny-burn-cpu |
--detector-model-path PATH |
Detector weights path | artifact/config dependent |
--detector-confidence-threshold FLOAT |
Keep detections at or above this value | 0.5 |
--detector-sample-frames N |
Frames sampled per segment | 5 |
--detector-stationary-interval-secs N |
Sampling interval for stationary scenes | 30 |
--recognition-weights-dir PATH |
Enable recognition with local weights | disabled |
--hardware-decoding BOOL |
Request hardware-decode probing | true |
--accelerated-detection BOOL |
Request accelerated-detector probing | true |
--fabric-ticket TICKET |
Join an existing configured fabric | none |
--fabric-hub BOOL |
Start the node as a fabric join point | false |
--fabric-allow-frame-offload BOOL |
Permit this node's detector work to move | true |
--fabric-worker-lease-ms MS |
Fabric worker lease setting | 300000 |
--fabric-fallback-horizon-ms MS |
Remote-result wait setting | 5000 |
Developer-preview fabric warning: default builds omit fabric entirely. In a fabric-enabled build, remote or rescued detector jobs can currently return empty detection content, and the two tuning fields are not both production-wired. Do not treat these flags as an operational distributed-compute surface.
The confidence threshold must be between 0.0 and 1.0; sampled frames must be between 1 and 64; booleans accept true or false. Multi-camera lists and MQTT are configured through TOML or add-on options rather than repeated CLI flags. Recognition class coverage (recognition_covered_classes) is configured through TOML or add-on options; it is not an environment variable. Service identity is not a TOML or add-on field at all — an ordinary vigil settings set service_identity is refused, and moving it is its own deliberate operation, vigil settings identity change <identifier> --confirm (see Configuration).
VIGIL_DATA_DIR=/var/lib/vigil vigil eventsLists up to 100 recent landed detection events, newest first. It does not list motion-only segments or correction observations.
/var/lib/vigil must match the running daemon's data_dir. Review commands do not read its
--config TOML; without VIGIL_DATA_DIR or an exact VIGIL_STORE_PATH, they use
./vigil-data and can silently read a different store.
With its local store selected explicitly, vigil events reads landed events and orders them newest
observed first.
An empty result is an empty answer, not a refusal and not a manufactured row. On a deployment
nothing has run in, vigil events prints nothing at all and exits 0 — there are no events, and
that is what was asked. vigil why --latest is the opposite case on the same deployment: it could
not serve the request, because there is no event to walk, so it refuses on standard error with exit
status 2.
Where a running owner serves that empty answer instead, the whole of it is the
served-by=af_unix line with nothing beneath it.
VIGIL_DATA_DIR=/var/lib/vigil vigil why <detection-id>
VIGIL_DATA_DIR=/var/lib/vigil vigil why --latestvigil why --latest selects the newest observed detection and walks its camera, site, detector
Decision, baseline Intention, and evidence. An unknown UUID returns a clean not-found error.
A malformed detection ID is refused as a malformed ID and never reported as a missing event: the answer names what was typed and the form a detection ID takes, so an operator who mistyped one is not sent looking for a recording nobody ever named.
Omitting the why argument currently behaves as --latest. The mapped tests do not exercise that
CLI form directly.
VIGIL_DATA_DIR=/var/lib/vigil vigil statsvigil stats prints the runtime's local persisted snapshot of pipeline counters and health.
Those figures come from this deployment's own snapshot file, <data-dir>/runtime-stats.json, and
vigil stats opens no store to read them. The answer opens with a stats-provenance= line whenever
the figures are not a reading of a running node. stats-provenance=not-started says nothing has run
in this data directory yet and names the directory it looked in, so an all-zeros answer from a
mistyped VIGIL_DATA_DIR is not read as a quiet node; stats-provenance=stopped-run says these are
the last figures this deployment's own run wrote before it ended, carried under a line saying they
are a record and not a reading. A live run's figures carry no such line, and that absence is what
says they are current. A snapshot whose writer cannot be established at all — truncated, unreadable,
or carrying no ownership stamp — is refused rather than served as either.
If a fabric is configured, shared fabric status and join instructions are intended to appear on this surface as well; the local-counter witness does not exercise a fabric-configured CLI invocation.
VIGIL_DATA_DIR=/var/lib/vigil vigil settings
VIGIL_DATA_DIR=/var/lib/vigil vigil settings list
VIGIL_DATA_DIR=/var/lib/vigil vigil settings find <TEXT>
VIGIL_DATA_DIR=/var/lib/vigil vigil settings set <SETTING> <VALUE>
VIGIL_DATA_DIR=/var/lib/vigil vigil settings reset <SETTING>
VIGIL_DATA_DIR=/var/lib/vigil vigil settings identity
VIGIL_DATA_DIR=/var/lib/vigil vigil settings identity change <IDENTIFIER> --confirmEvery one of these asks the process that owns this deployment's store, through Context Graph's
authenticated owner channel, and reads the store file directly only when no runtime is holding it.
Both routes render the same report; an answer the running owner served opens with a
served-by=af_unix line, and an answer read from an idle store file carries no such line. Neither
route brings anything into existence: asking a deployment that has never started what it would run
at leaves its data directory exactly as it was, with no store on disk afterwards.
vigil settings and vigil settings list are the same listing. It is six kinds of line —
served-by, identity, setting, held, domain and secret — and every field each kind
carries, with its value set, is in
the settings listing's field glossary, beside
the table that says which surface may author each field.
vigil settings find <TEXT> searches the same listing and answers with every line containing
that text — setting lines, the domain switch= control lines and the explanations alike, because
the search is over the whole rendered answer and that breadth is deliberate. A search that matches
nothing succeeded and found nothing: the answer is empty and the exit status is 0. A search with
no text names nothing to look for, so it is a usage error.
vigil settings set <SETTING> <VALUE> records the value at this deployment through the
vigil-settings surface and then prints the listing back; a bare true or false is a switch, a
bare number is a number, a comma-separated value is a list, and anything else is text.
vigil settings reset <SETTING> withdraws this deployment's own record for that setting, states
what the withdrawal leaves in force, and prints the listing beneath it. A change made against the
running node takes effect on that node before the answer is rendered where the setting is one the
process can take on live; where only a start brings it into force, the line says so with
applies=next-restart.
vigil settings identity prints this node's service identifier and how it was arrived at, and it is
read-only. The identifier is not an ordinary setting: vigil settings set service_identity is
refused, naming the orphaned-history consequence, and so is a reset of it. Moving it is its own
deliberate operation. vigil settings identity change <IDENTIFIER> without --confirm states the
consequence and changes nothing, so the consequence is read before the identity moves; with
--confirm the change is recorded and takes effect at the next start.
What each of these shapes answers when another process is reading the store, when nothing has ever run in this directory, when another runtime owns the store, and when the store cannot be read at all — and which stream and exit status each of those answers arrives on — is stated once, in When a read command cannot open the store.
VIGIL_DATA_DIR=/var/lib/vigil vigil enroll <detection-id> <name>The underlying enrollment operation creates a named site-local recognition reference from a detection and writes its linked correction. The detection must carry the stored recognition probe; when it does not, enrollment fails without a stranded correction row.
The vigil enroll command is dispatched to this operation, but the current deterministic witnesses
invoke the operation directly rather than through the CLI.
VIGIL_DATA_DIR=/var/lib/vigil vigil forget <name>The underlying forget operation removes site-local recognition references for the named subject; later sightings then stop matching that subject.
The vigil forget command is dispatched to this operation, but the current deterministic witness
invokes the operation directly rather than through the CLI.
vigil doctor acceleration [--service-user USER] [RUN_OPTIONS]The acceleration report renders decode and detection receipts in a fixed order with configured,
status, attempted-backend, active-backend, and failure-code fields. Without sudo, it reports the
current process's usable software and CPU fallback state.
The command is intended to be read-only, include an operator action for each fallback, and use the same relevant probes as feature-enabled runtime startup. The current mapped tests call the report logic directly and do not bind all three CLI-level assertions.
vigil fabric ticket [--data-dir PATH]Prints this node's fabric enrollment ticket to stdout, on explicit invocation only. The ticket is a
credential, held to a two-tier contract. On every displayed or served surface — logs, vigil stats, vigil doctor, the /health HTTP body — it is deliberately absent, with exactly two
sanctioned retrieval paths: vigil run's own startup log, which still prints it as a sanctioned
operator-facing instruction, and this command, which falls back to the ticket the running node
cached the last time it bound (since a live rebind opens the same on-disk fabric ledger the
running node's own Database::open already holds, which fails fast with a typed writer-held
refusal before this command ever reaches its own endpoint bind step). Separately, it is expected to
sit in exactly two private, tight-permissioned (owner-read/write only) persisted stores: the
fabric/own-ticket cache this command falls back to, and the fabric ledger
(fabric/fabric-ledger.db), whose
peer-directory table is the fleet's own coordination mechanism — reading either already requires
filesystem access to this node's data directory.
vigil detector-probe is an internal subprocess command used by the detection-probe machinery. It is not an operator workflow and its wire arguments are intentionally omitted here.
Four different things stop a read command opening this deployment's store, and they are four different answers because they send you to four different places. Every one of them is decided on the typed condition the layers below report, never on the wording of a message, and none of them writes to your store.
Somebody is reading it. Another process — a second command, or this node's own reader — holds
the store while it hydrates. Nothing you only ASK notices: vigil settings, vigil settings list,
vigil settings find <text>, vigil settings identity, vigil why and vigil events all read
through a door that coexists with other readers, so they are served their ordinary answer and name
nobody. vigil enroll and vigil forget are the two that wait, because they change what this node
recognizes and that needs the store to itself. They say so on a busy line naming the store and
how many readers hold it, followed by a reader line per reader carrying that reader's process id
and process name, so you can go and look at the one that is in the way. The store is healthy,
nothing needs repairing, and the condition clears on its own: run the same command again once they
finish and it lands. It is not the unreadable answer — nothing tells you the store cannot be read,
and nothing calls this node unmanaged.
Nothing has ever run here. There is no store because no runtime has started in this directory.
Nothing is broken and nothing needs repairing, so no answer sends you to repair anything: vigil events answers with no events, vigil why refuses because there is no event to walk, vigil stats and the read-only settings shapes answer what this node would run at, and vigil enroll
and vigil forget refuse because there is nothing here yet to correct. Whichever you ask, asking
leaves the directory exactly as it was — no command in this family brings a deployment into
existence, so a command pointed at the wrong path does not turn that path into a deployment.
Another runtime owns it. A writer holds the store, and it keeps holding it until that runtime lets go. That is one condition however it is reached: the same refusal whether the writer is this process or another one, spelled by type rather than by matching text.
It cannot be read at all. A corrupt file or an unreadable volume is a storage problem. Here the answer names the store and says this deployment's settings and this node's identity are not available through this command, and where they are. What it deliberately does not do is print a settings listing, a domain roster or an identity: this process never read your store, so every one of those would be a value it made up — the artifact's own defaults standing where your deployment's belong, with nothing on the line to say so.
vigil stats is the exception to all four conditions, because it never opens the store: its figures
come from <data-dir>/runtime-stats.json, so it answers normally at exit 0 — under its own
stats-provenance= line — however badly the store is faring. The condition it has of its own is a
snapshot whose writer cannot be established, which it refuses.
How each answer is delivered does not change with which of the conditions produced it, for every
condition a command actually meets. vigil why and vigil events could not serve your request, so
they refuse: the answer is on standard error and the exit status is 2. The vigil settings,
vigil settings list and vigil settings find <text> listings were served — the explanation is the
answer — so they arrive on standard output. vigil settings identity is a failed request whichever
way it fails: an operator asked this node what it is called and no answer exists to give them, so it
leaves on standard error with exit status 2 rather than letting a script read a missing identity
as a successful lookup. A settings change refuses too, on the same terms, because a change nothing
recorded is not a change. The reader condition is the one no question ever meets: everything you
only ask reads through a door that coexists with other readers, so a store somebody is reading
answers with your settings, your node's identity and your review history exactly as an idle store
does.
One refusal sits outside those four, because the store is not what is in the way. A running owner
serves a bounded number of these requests at a time — four, on the shipped limits — and a request
that arrives while that many are already in flight is refused rather than queued. The answer is
the process holding the store at <path> is already serving as many requests as it admits, on
standard error with exit status 2, and that holds for every command in the family: it is a live
owner speaking for itself, so no command may go behind it and read the store instead. It is neither
the busy answer nor the unreadable one — nothing needs repairing, and the same command answers
normally once the requests in flight have landed — and it is the one condition under which a
read-only settings shape does not deliver its answer on standard output.
| Option | Meaning |
|---|---|
--version |
Print the Vigil package version |
--help, -h |
Print the current built-in help |
The current binary has no status, health, config check, config validate, correct, state-at, why-flagged, scan onvif, scan rtsp, or support-bundle command. Health is an HTTP endpoint, corrections use Home Assistant/MQTT or the review HTTP API, and configuration validation happens while vigil run loads its inputs. These names remain unavailable until implemented and tested.