# The tools, area by area

> What every tool an agent can call does, grouped by the capability toggle that advertises it, and the help tools that need none.

Tool names are stable snake_case identifiers. Errors are structured and actionable: a
failed call returns what went wrong plus a hint naming the tool or step that fixes it,
so an agent self-corrects instead of guessing. The server instructs every agent to read
the help with `help_search` and `help_read` before answering a question about how the app
works and, when the Backups (manage) area is on, to create a configuration backup before
making configuration changes. Which of these lists an agent actually sees is
[what each area opens](agent-areas), plus the help tools, which need no area.

## Help {#help}

The two help tools read this documentation, as the installation carries it: the same
articles the [help panel](app-window#contextual-help) opens, written for the version installed on the station. They
come with the endpoint whenever the master switch is on, whatever the area toggles say,
because the text is the public documentation and shows nothing of the station. Both keep
working while the runtime is stopped.

| Tool | What it does |
| --- | --- |
| `help_search` | Finds articles by the words of a question and returns each one's slug, title, summary and the sections the words touch, best match first (10 by default, up to 50). Case and accents are ignored. Without a query it lists every article. |
| `help_read` | Reads one whole article by its slug as plain text: the title, the summary, the list of sections and the body, with each section on a heading line and tables one row per line, plus the slugs of the articles it links to. |

Both read the station's interface language by default, so the pages, buttons and fields an
answer names are the ones on screen. Either takes a `culture` naming another language the
installed help carries; a language it does not carry is refused with the list of the ones
it does, and no other language answers in its place. An installation whose help is missing
or cannot be read answers each call with the reason instead of articles.

## Connector: read {#connector--read}

| Tool | What it does |
| --- | --- |
| `connector_browse` | Lists the tree the Connector page draws, with live health: every driver added to the station, one with nothing under it included, and a driver holding a device, a serial line or a broker is always added; Modbus RTU as driver, serial line, device, tag; MQTT as driver, broker (with its session state), device, tag; every other driver as driver, device, tag with each device's folder beside it. Generic serial and TCP lists its serial lines like Modbus RTU and its network devices like any other driver, with each device's transport. SCPI instruments lists its serial lines and its other devices the same way. A File device carries its folder, its file name, how it reads (one file or an inbox folder) and its format. A Database device carries its database type (`databaseKind`). Each device carries `error`, the one sentence its page shows, in the station's language: a sentence that points to its serial line or broker when the error belongs to that one, else the device's own error (it does not connect, the connection is refused, the driver warns), else the summary of its tags whose reads are refused, each tag's reason being the `readFailure` of `tag_read`. It is `null` when the device holds none; the sentence `tag_read` gives for a tag whose device is not connected leads here. Reveals the tag aliases (`Driver.Folders….Device.Tag`) that `tag_read`, `tag_write` and Logic expressions use. Aliases are null while the Connector is stopped. |
| `tag_read` | Reads one tag's live values by alias: `valueRaw`, the device's own value before any stage, `value`, the engineering value after every stage of the conversion pipeline, Decimals included (a Double the device reports as 2.718281828459 reads 2.72 with Decimals at 2), quality, both timestamps and `substitution`, which says whether the value is a configured stand-in rather than what the device reported: `None` (a measurement, or no value at all), `NaNReplaced` (the reading was NaN and the declared number took its place), `LastGoodHeld` (the read failed and the last reading that landed is held, with that reading's raw value and timestamps) or `ReadFailureReplaced` (the read failed and the declared number is presented). A stand-in counts as a value, so the quality stays good unless a limit fault is raised, but it is never a measurement. `communicating` says whether the device is still answering: false when the latest read failed or nothing has been read yet. A reading that stood past the tag's poll interval, plus a short margin, without a new one counts as a failed read: the value, the quality and `substitution` answer as they do for one (no value and bad quality by default, the held reading or the declared number where the tag says so), `communicating` is false, and the timestamps date the last reading that landed. A value outside the tag's limits is not a connection fault: the quality goes bad while `communicating` stays true. `readFailure` says why a read did not land, in the one sentence the tag's panel shows, in the station's language: the reason the device or the driver gave when the tag's own read was refused, or a sentence that points to the tag's device when that device is not connected. It is `null` while the tag reads, and when a read that did not land has no reason on record yet. |
| `modbus_server_status` | Reports the station's own [Modbus server](connector-modbus-server): whether it is on (`enabled`), its `port`, its `status` (Off, Listening, PortInUse, Failed with the system's words in `failure`, or RuntimeStopped), the clients connected now (at most `maximumClients` at once), and every row of the register map: its `registerClass`, the 0-based `register` and `lastRegister`, its type and layout, its `access` (ReadOnly or ReadAndWrite), its source (a tag or a variable, by address and id) and what a client reads there now, `value` and `good`, or the `gap` (NoSource, SourceRemoved, NoGoodValue, NotRepresentable) for which a client is answered with exception 04. It keeps working while the runtime is stopped. |
| `station_broker_status` | Reports the station's own [MQTT broker](connector-mqtt-broker), the one devices publish to, never one of the brokers the station reads: whether it is on (`enabled`), its `port`, its `status` (Off, Listening, PortInUse, Failed with the system's words in `failure`, or RuntimeStopped), its `authentication` (Anonymous or UsernamePassword, with `username` and `hasPassword`, never the password), the devices connected now (at most `maximumClients` at once) and `thisStationEntry`, the MQTT driver's broker This station through which the station reads it. It keeps working while the runtime is stopped. |
| `mqtt_publish_list` | Lists what the station publishes to each MQTT broker it reads, the [Publish card](driver-mqtt#the-publish-card) of each: the broker's `publishTopicPrefix` and whether it publishes, and each row with its source (by address, `removed` when the source was deleted), its `topic` and its message (`value` or `alarm`), with both messages described in `payloads`. It keeps working while the runtime is stopped. A row whose `access` is `ReadAndWrite` takes values on its `writeTopic` (its topic followed by `/set`), written to its source and journaled as `MQTT <broker name>`; `payloads.write` says what that topic takes. Each broker says its `publishFormat`; a broker in Sparkplug B adds `sparkplug` (its group, the station's edge node id and its devices), each of its rows says the device and metric it is published as, and `payloads.sparkplug` says how Sparkplug B goes out ([Publishing in Sparkplug B](driver-mqtt#publishing-in-sparkplug-b)). |
| `remote_access_devices` | Reports who opens the station's screens over the network: the browsers connected from another computer or tablet right now (address, browser and system, page, user, since, and the configured device each one is) and the configured devices with how each one opens (start screen, lock, who it signs in as, the minutes after which it goes back, view-only, and why it opens otherwise when its fixed user or its start screen changed). It never carries a key or its hash. It keeps working while the runtime is stopped. |
| `server_status` | Reports the embedded [OPC UA server](connector-opcua-server)'s health: whether it is turned on (`enabled`), whether it is running, its uptime, endpoint URL and connected client sessions, and the size of the configured address space; `available` says whether the Connector runtime reads, which it does while the server is off or stopped, and `serverError` why the server's last start failed. `list` is what the server serves, and all it serves: one row per tag, Logic variable, alarm or device command, each with its `access` and the `node` a client is configured with; while it is empty, `servesNothing` is true. |

## Connector: configure {#connector--configure}

| Tool | What it does |
| --- | --- |
| `driver_capabilities` | Lists every driver the app can serve with the connection fields a device needs, the tag addressing model (free-text address and/or typed fields), discovery support and parameters, timing ranges and the supported value types, with `defaultPort`, the port a device that names none is dialed on. `added` says whether the driver is added to the station, which is what draws it in the Connector tree; creating a device, a serial line or a broker with `device_upsert`, `serial_line_upsert` or `mqtt_broker_upsert` adds its driver. AVEVA PI and HTTP dial the port of the transport the device speaks, so they also give `defaultPortByTransport`: 443 over HTTPS, their default, and 80 in the clear. Generic serial and TCP adds `genericSerialTcp`: its transports, how bytes are typed, how messages end, the checksums, the tag modes, filters and extractions, how values are read and written, and two worked examples. Omron adds `omron`: its two protocols with the device fields, address forms and data types each takes, the FINS transports and ranges, writes and discovery. SCPI instruments adds `scpi`: its transports, whether this computer has VISA (`visa.installed`), the terminators, the write confirmations, the setup commands, how queries and write commands are written and answers read, discovery, and two worked examples. NI-DAQmx adds `niDaqmx`: for each measurement, an example channel, the unit, its fields and the data types and accesses it allows. A driver whose devices need something the product cannot ship adds `prerequisite` (Fluke NetDAQ: the Visual C++ 2005 runtime; OPC DA: the OPC Core Components, OpcEnum and the OPC DA proxy and stub; NI-DAQmx: National Instruments' NI-DAQmx; SCPI: a 64-bit VISA, NI-VISA or the Keysight IO Libraries Suite, for its VISA devices only, with both pages; Database: a 64-bit ODBC driver or data source for an ODBC device, judged per device (`perDevice` true), so `installed` stays null and the device's own error says what is missing): whether this computer has it (`installed`, for a driver added to the station), the official download page, the file, how to install it, the known stumble and what happens next. SNMP adds `snmp`: its versions and the credentials each takes, the SNMPv3 security levels and protocols, the types by kind of value, every standard object the driver knows by name with its OID, how reads and writes behave, discovery, and two worked examples. File adds `file`: the simple path, the folder and the confinement to it, the file name forms, one file or an inbox folder, the formats with their address grammar, what a tag reads and its types, the text settings, how reads and writes behave, discovery, and three worked examples. Database adds `database`: each database with its fields and its own port, the encryption, the two ways a tag reads and the two ways it writes, the rule that a value enters a statement only as `@value` or `@now`, the timeouts, the advice on the database user, discovery, and four worked examples. The map an agent reads before `device_upsert` or `tag_upsert`. |
| `serial_line_list` | Lists every persisted serial line, disabled and empty ones included, with its stable id and its driver; a Modbus RTU line also with its mode and the configured, automatic and effective timing values. |
| `serial_line_upsert` | Creates a serial line or updates one by stable id. `driver` names the driver it belongs to, `ModbusRtu` (the default), `GenericSerialTcp`, `Scpi` or `Omron`, fixed at creation; a line of the generic, the SCPI or the Omron driver refuses `mode`, `responseTimeoutMs` and `minimumTransactionIntervalMs`. Name and enabled state change at any time; the minimum transaction interval also changes while enabled; serial port, baud rate, serial format, transmission mode and response timeout only change while the persisted line is disabled. |
| `serial_line_delete` | Deletes a line by stable id. A line that still contains devices is refused unless the call explicitly authorizes deleting every child device and tag. |
| `mqtt_broker_list` | Lists every persisted MQTT broker, disabled and empty ones included, with its stable id, where it answers, its transport, username, client id, keep-alive, topic prefix, publication format (`publishFormat`) and Sparkplug B group (`sparkplugGroupId`) and device count. It says whether a password is stored and never returns it. |
| `mqtt_broker_upsert` | Creates an MQTT broker or updates one by stable id: name, enabled state, host (a whole `mqtt://` or `mqtts://` address is read apart), port, TLS, username, password, client id, keep-alive the prefix its Publish card suggests topics under (`publishTopicPrefix`, an empty string back to the default), how that card goes out (`publishFormat`, `Json` or `SparkplugB`) and the Sparkplug B group of the station's edge node (`sparkplugGroupId`, an empty string back to `GanterLab`, a group holding `/`, `+` or `#` refused). Only supplied parameters change; a broker is enabled only with a host, and a client id another broker uses is refused. A saved change of the connection reconnects the session every device under the broker shares. |
| `mqtt_broker_delete` | Deletes a broker by stable id. A broker that still contains devices is refused unless the call explicitly authorizes deleting every child device and tag. |
| `mqtt_publish_upsert` | Creates a row of a broker's [Publish card](driver-mqtt#the-publish-card) (`brokerId` and `source`: a tag, `Connector.` and its alias, a variable, `Variables.` and its path, or an alarm, `Alarms.` and its path) or edits one by `id`. `topic` is optional: omitted, the row takes the one suggested from the source's name under the broker's prefix, and an empty string takes it again. A broker publishes a source once and a topic once; a topic holds no + or # and does not start with $. A row never moves to another broker. `access` is `ReadOnly`, the default, or `ReadAndWrite`, which only a tag with write access on a driver that writes, or a memory variable, takes: the station then writes what is published on the row's topic followed by `/set` ([Writing back](driver-mqtt#writing-back)). No row's topic may be another row's topic followed by `/set`. On a broker in Sparkplug B the row is published as a metric instead (`row.sparkplug`), and `ReadAndWrite` takes the values Sparkplug B commands send to it. |
| `mqtt_publish_delete` | Deletes a row of a Publish card by `id`. The station stops publishing it; the tag, variable or alarm is not touched. |
| `device_upsert` | Creates or updates a device by driver + name (the driver is immutable after creation). Only supplied parameters change; connection fields are per driver; moving a device into a folder rewrites every reference to its old tag addresses. A device of the generic serial and TCP driver takes `transport` and the fields of its Messages and Checksum cards, and `serialLineId` only for a line of its own driver; a device on a line refuses a host, a port and a folder. An Omron device takes `omronProtocol` (`Fins` or `NjNx`) and, over FINS, the `fins*` fields of its FINS card; a device read by tag name refuses a port. A SCPI device takes `transport` (`Tcp`, `Visa`, or `SerialLine` with `serialLineId` of a line of its own driver), `visaResource`, `terminator`, `responseTimeoutMs`, `writeCheck` and `setupCommands`. An NI-DAQmx device takes `daqmxDevice`, the name NI MAX gives it. An SNMP device takes `snmpVersion`, `snmpCommunity` (SNMPv1, SNMPv2c), `username`, `password`, `snmpSecurityLevel`, `snmpAuthProtocol`, `snmpPrivacyProtocol` and `snmpPrivacyPassword` (SNMPv3), `responseTimeoutMs` and `snmpRetries`; it returns whether each secret is set, never the secret. A File device takes `fileFolder`, `fileName`, `fileMode` (`SingleFile` or `Inbox`), `fileFormat`, `fileEncoding`, `fileSeparator`, `fileDecimal`, `fileHeaderRow` and `fileWrites`, with `fileHeaderText` and `fileLineEnd` once writing is on; it returns `file.fileStatus`, the file the running driver reads and what it read off it. A Database device takes `databaseKind`, and for a server `host`, `port` and `databaseName` (on SQL Server also `databaseInstance`, `databaseWindowsSignIn` and `databaseEncryption`), `databaseFile` for SQLite or `databaseOdbc` for ODBC, with `username` and `password`; it returns `database`, the address and whether the device still waits for its user, never the password. A port outside 0 to 65535 is refused; 0 stands for the port the driver dials. The change is reconciled into the running server immediately. |
| `device_delete` | Deletes a device and all its tags; reconciled into the running server immediately. |
| `tag_upsert` | Creates or updates a tag on a device. Addressing is driver-specific (free-text address and/or typed fields; for Generic serial and TCP the read mode, request, filter, extraction and write fields; for SCPI instruments the query as `address`, `valueField` and `writeTemplate`; for NI-DAQmx the physical channel as `address` and the `daqmx*` fields of its measurement; for SNMP the OID as `address`, by number or by standard name; for File the column or the path as `address`, `fileSource`, `fileRow` and its fields, `fileWriteMode` and `fileLineTemplate`, a free-text value taking the generic driver's `value*` fields, and a new tag born read only; for Database the value column as `address`, `databaseSource`, `databaseTable`, `databaseRow` and its fields or `databaseQuery`, and once the tag writes `databaseWriteMode` and `databaseCommand`, a new tag born read only as well); the response echoes the assembled wire address and the alias for `tag_read`. Includes the invalid-reading stages: the NaN action for numeric tags, and the read-failure presentation for every tag the station reads, where only `Replace` is limited to numeric and Boolean tags. A `Replace` already stored that the tag's new type cannot take is saved as the default instead: the NaN action becomes `PassThrough` once the type is not numeric, and the read-failure presentation becomes `ShowError` once the type is String, DateTime, Guid or ByteString. |
| `tag_delete` | Deletes a tag; reconciled immediately. |
| `server_start` | Turns the embedded OPC UA server on and starts it, as Enable does on its row: it serves its list, and stays on across restarts until `server_stop`. A no-op when already running; when the Connector itself is not running, it is started first, materializing the current configuration. |
| `server_stop` | Turns the server off and stops it gracefully, as Disable does: OPC UA clients are dropped and nothing is published until `server_start` turns it on again. The Connector goes on reading, and tag reads, the Logic and the recordings go on. |
| `server_restart` | Stop then start of the server alone, while it is on; the Connector reads throughout. A server that is off is refused, since `server_start` is what turns it on. Device and tag changes are applied with `connector_refresh`. |
| `server_list_upsert` | Creates a row of the OPC UA server's [list](connector-opcua-served-nodes), or updates one by `id`. `source` names a tag (`Connector.` and its alias), a variable (`Variables.` and its path), an alarm (`Alarms.` and its path) or a device command (the device's address, a dot, the command's name and `()`); a source is listed once. `access` is ReadOnly, the default of every new row, or ReadAndWrite, which only a tag with write access or a memory variable takes; a client's write then goes through the Logic write funnel and is journaled with the client's session. The answer carries the row with its `node`. |
| `server_list_delete` | Deletes a row of the list by `id`. A client no longer finds its node; the source it served is not touched. |
| `modbus_server_configure` | Turns the Modbus server on or off (`enabled`) or moves it to another `port`, 1 to 65535, as its page does. A port the web server, agent access or the OPC UA server is set to, and a port another program holds, are refused; Windows Firewall is never changed. Turned on, it lets any machine that reaches the port read what the map serves. Answers with the whole server, as `modbus_server_status` does. |
| `station_broker_configure` | Turns the station's own MQTT broker on or off (`enabled`), moves it to another `port` and changes its `authentication`, `username` and `password`, as its page does, in that order: port, authentication, then on or off. A port the web server, agent access, the OPC UA server or the Modbus server is set to, and a port another program holds, are refused; Windows Firewall is never changed. Turned on, it adds the broker This station to the MQTT driver. Answers with the whole broker, as `station_broker_status` does. |
| `modbus_map_upsert` | Creates a row of the Modbus server's register map, or updates one by `id`. `source` names a tag by its address (`Connector.` and its alias, as `connector_browse` lists it) a variable (`Variables.` and its path) or an alarm (`Alarms.` and its path, always ReadOnly, serving the state `alarmValue` names: Active, Acked or State); `registerClass` (HoldingRegister by default), `register` (0-based), `type` (Float by default, Boolean in a coil or a discrete input), `length` for a String, `mostSignificantByte` and `mostSignificantWord` take the fields and the rules of a Modbus tag. `access` is ReadOnly, the default of every new row, or ReadAndWrite, which only a holding register or a coil takes, from a source that takes writes (a tag with write access, a memory variable). A new row needs its `register` and its `source`; a row the map refuses is answered with the reason and a hint. |
| `modbus_map_delete` | Deletes a row of the register map by `id`. A client reading its registers is answered with exception 02 from then on; the tag or the variable it served is not touched. |
| `remote_access_device_update` | Changes a configured device's name, start screen (a dashboard by id or name, or empty to clear it, which also unlocks it), lock, idle minutes (0 for never) and view-only setting, as its row on the Remote access page does. Who the device signs in as is not changed here: that takes a person with Manage local users. A device is configured and forgotten on the station's screen, never by a tool. Answers with the device as `remote_access_devices` lists it. |

## Connector: operate {#connector--operate}

| Tool | What it does |
| --- | --- |
| `connector_refresh` | Incrementally reconciles the running server with the configured devices (adds, removes, recreates) without a full restart; the lighter way to apply changes. |
| `device_discover` | Runs a driver's device-discovery scan and returns candidates with their tags, persisting nothing. Only drivers whose protocol supports a real scan take part; candidates that already exist are marked as such. An SNMP scan walks either `target` with `snmpCommunity`, or `snmpDevice`, a configured device, which is how an SNMPv3 agent is scanned. A File scan reads either `fileDevice`, a configured device, or `fileFolder`, `fileName`, `fileMode` and `fileFormat` typed for the scan. A Database scan reads `databaseDevice`, a configured device, and optionally `databaseTables`, a table name or a pattern with `*`. A `target` the driver's Scan scope card would refuse, or none where the scan needs one, is refused with what it has to be. A Database, File or SNMP scan stopped at its bound of values, tables or objects says so in `cut`, with what to pass to see the rest; a whole list has no `cut`. |

## Logic: read {#logic--read}

| Tool | What it does |
| --- | --- |
| `logic_browse` | Browses the rooted Logic address space, the same dot tree every expression reads: System, Server, Connector, Variables, Alarms, Process and Assets. Operator folders are real address levels; child points include their live value and quality, and a Connector tag point also carries `substitution` and `communicating`, as `logic_read` reports them. |
| `logic_read` | Reads one point by its dot address (for example `Variables.Setpoint`) and returns the live value and quality. A Connector tag point also carries `substitution` and `communicating`, as `tag_read` reports them, which is what tells a stand-in, or a reading from a device that stopped answering, from a live measurement; other points carry neither. A reading that went silent reads there as a failed read. |

## Logic: configure {#logic--configure}

Upserts are partial (omitted parameters keep their value) and every merged draft passes
the same validation the [Logic](logic) editors apply; an invalid draft is rejected and
nothing is half-applied.

| Tool | What it does |
| --- | --- |
| `variable_upsert` | Creates or updates a variable: Expression (a single read-only JavaScript expression over the address space) or Memory (a writable, optionally retentive value). The name is the key and, sanitized, the address; the folder parameter files it, rewriting every reference to the old address. |
| `variable_delete` | Deletes a variable by path, its retained value included. Channels bound to it lose their source. |
| `action_upsert` | Creates or updates an action: a JavaScript statement block with exactly two write verbs, memory-variable assignment and the engineering tag write. Statically validated, never executed at save time. |
| `action_delete` | Deletes an action by name. Triggers bound to it idle. |
| `trigger_upsert` | Creates or updates an interval trigger: every `intervalMs` (minimum 100) the bound action fires on the actions lane; a tick during a pending run is skipped. The action binding is loose and by name. |
| `trigger_delete` | Deletes a trigger; the bound action is untouched. |
| `alarm_upsert` | Creates or updates an alarm: a Boolean condition expression, priority (Critical/High/Medium/Low), on/off delays, whether acknowledgement is required, and the annunciation style. Saving a changed condition or timing resets the running state machine. |
| `alarm_delete` | Deletes an alarm by path; an active annunciation is cleared first. |
| `logic_folder_upsert` | Creates, renames or re-files an organizing folder of one section (Variables, Alarms, Actions, Triggers; at most three levels). For Variables and Alarms the folder path is part of the address, so renames and moves rewrite every expression, script, condition and dashboard binding beneath. |
| `logic_folder_delete` | Deletes a folder. Nothing it held is destroyed: items and subfolders re-file one level up and references are rewritten; a name collision at the destination refuses the delete. |

## Logic: operate {#logic--operate}

All of these ride the same Logic write funnel the pages ride and journal with origin **MCP**. A write leaves the Logic for the device's own delivery queue, and the tool call is what waits for the answer, so what comes back is what became of the value and not merely that it was sent.

| Tool | What it does |
| --- | --- |
| `variable_write` | Writes a value into a Memory variable (coerced to its output type, retained when retentive). Expression variables are computed and refuse writes. |
| `tag_write` | Writes an engineering value to a writable tag: reversed through the tag's conversion pipeline, coerced to the device type, written to the equipment. The answer carries what the tag presents once the write is through: the value, the quality, `substitution` and `communicating`, as `tag_read` reports them, so a device that took the write but has stopped answering reads is told apart from one that still answers. Read-only tags and read-only drivers are refused with the reason. |
| `action_run` | Runs one action on the actions lane and returns its outcome and duration. A disabled action fails without running. |
| `alarm_ack` | Acknowledges one alarm, the operator response; a no-op when nothing is pending. |
| `alarm_ack_all` | Acknowledges every alarm awaiting one, as one logic-queue item with each transition journaled. |

## Logs: read {#logs--read}

| Tool | What it does |
| --- | --- |
| `logs_read` | Reads the program-wide live log feed (the same one on the [Events](events) Console), filtered by minimum severity (Debug/Information/Warning/Error, default Information), area (App/Server/Connector/Logic/Process/Dashboard/Agent/Licensing), component and a contextual substring; returns the newest matches (default 100, at most 500). Agent actions journal under the Agent area. |
| `event_history_read` | Reads the persistent operational-event timeline, which survives restarts: alarm transitions, occurrence transitions and interlock transitions. Filter by kind (Alarm/Occurrence/Interlock), an inclusive UTC period and a level (alarm priority, occurrence severity or interlock transition); newest first, default 100, at most 500. Strictly read-only: nothing can clear or delete journal entries. |

## Process: read {#process--read}

| Tool | What it does |
| --- | --- |
| `process_models` | Lists the [Process](process) models in full: channels, shared groups, units with resolved wiring and running state, procedures, panels, recipes, evaluations, occurrences, plus the global report-template library. The map an agent reads before starting anything. |
| `process_runs` | Lists runs, most recent first: id, name, state, verdict, what ran, who started it (Station/User/Automation/Agent), timing and cycle progress. Can be restricted to active runs, searched by a part of the name or of any metadata value (a serial number, a lot), and capped (default 50). |
| `process_run` | Reads one run's complete frozen record by id: snapshot, metadata, judged criteria with sample counts, occurrence episodes and events, as-executed recipe writes, comments, and the frozen report and label artifacts with their print attempts. Optionally computes datalog row count and time range. |
| `process_samples` | Reads the samples a run recorded, while it records or after it ended. A stretch of up to 500 samples comes as recorded: one point per sample, with a value per channel. A longer one comes summarized: its duration is divided into 500 equal slices, and each slice carries every channel's minimum, maximum and mean, so a peak survives in the maximum. The answer says which of the two it is and, summarized, how long each slice lasts and how many samples it joins. `fromUtc` and `toUtc` narrow the stretch, and one narrow enough comes back as recorded; `channels` reads only the channels it names. |
| `unit_status` | Reports a unit's live status: whether it is running (with the active run) and the current engineering value behind each channel, read without recording. |

## Process: configure {#process--configure}

| Tool | What it does |
| --- | --- |
| `process_view_configure` | Configures exactly one panel of a model: the icon drawn beside it and whether it stands on the View page. Nothing else of the Process aggregate is writable over MCP; the rest is edited on the Process page. |

## Process: operate {#process--operate}

Runs started, ended or commented by an agent record **Agent** as the actor, never the
operator who happens to be signed in at the bench.

| Tool | What it does |
| --- | --- |
| `process_snapshot` | Captures one datalog row on a unit outside a procedure. Every call creates a new, already-completed Instant run in [Histories](histories) with no evaluation (verdict None). |
| `process_evaluate` | Captures one datalog row and judges it with an evaluation; creates a completed Instant run and returns its verdict. |
| `process_recipe_apply` | Applies an Instant recipe once to a unit through the Process write funnel and source locks. Commands equipment; creates no run (the writes are journaled). Temporal recipes are refused. |
| `process_start` | Starts a procedure run on a unit, with a JSON object for the metadata fields the procedure prompts. Every value passed is recorded or nothing starts: a field the procedure does not prompt, a value for a sequential field (the app composes it at start) or a field named twice refuses the start, as do missing or invalid required metadata, a unit already running or a shared-channel lock conflict. Returns the new run id. |
| `process_stop` | Stops a running run: finalization block, frozen history snapshot, computed verdict. |
| `process_hold` | Holds a run's temporal profile at the last setpoint; the datalog keeps recording. |
| `process_resume` | Resumes a held run's temporal profile. |
| `process_abort` | Aborts a run from Running or Held: finalization runs, the snapshot is written, the state becomes Aborted and the verdict NOK. |
| `process_comment` | Adds a timestamped comment into a run's file: a timeline note while active, a post-run note after. |
| `process_report` | Generates (or regenerates) the PDF report of a finished run and returns its file path. A named template from the global library overrides the procedure's configured one; with neither, the all-sections default layout applies. Refused while the run is active. |
| `process_run_delete` | Permanently deletes a recorded run: its history-index pointer and per-run database file. Refused while active; configuration is untouched. |

## Dashboard: configure {#dashboard--configure}

The role names these tools read and report are English on every station: `Not signed in`,
`Viewer`, `Operator`, `Maintainer` and `Developer`, whatever words the operator reads on
the screen. `Admin` is not listable: it always sees every dashboard. A role the
administrator renamed is named by what he typed.

| Tool | What it does |
| --- | --- |
| `dashboard_list` | Lists dashboards (or, naming a model, that model's screens): grid size, folder, icon, startup flag, role visibility and every component with its position, layer and properties JSON, plus every persisted connection network. Also returns the component-kind catalog with each kind's default size and default property bag. |
| `dashboard_upsert` | Creates or updates a dashboard by name: grid size (a shrink that would orphan a component is rejected), folder and icon in the View page's Visualization column, startup flag, status-bar visibility in full screen, and per-role visibility. Naming a model addresses that model's screens instead. Open dashboard pages reflect the change live. |
| `dashboard_delete` | Deletes a dashboard and its components by name; naming a model deletes that model's screen instead. |
| `component_upsert` | Adds a component by kind (placed at the first free cell with the kind's default size unless told otherwise) or updates one by id. Placement must lie inside the grid; overlapping is allowed with the z layer deciding rendering order; the properties JSON is the kind's typed bag. Naming a model addresses that model's screens instead, so a screen created there can be laid out here. |
| `component_delete` | Removes a component by id; naming a model addresses that model's screens instead. |
| `connection_upsert` | Connects two Symbol terminals with a typed connection network, resolving type, role and direction from the symbol catalog exactly as the canvas editor does. Ends that resolve to different types fail unless an undefined connection is explicitly allowed; an anchor already carrying a connection is rejected. Naming a model addresses that model's screens instead. |
| `connection_delete` | Removes one connection network by id and expected revision, so a stale delete is rejected instead of clobbering a newer edit; naming a model addresses that model's screens instead. |

## UI: automate {#ui--automate}

These tools drive the real application window; they exist so an agent can verify the
operator-facing UI, not a simulation of it. Interactions are dispatched to the live
shell, so the intended conduct is to follow each gesture with `ui_screenshot` and
observe the effect, and ambiguous matches come back as candidate lists instead of a
guessed click.

| Tool | What it does |
| --- | --- |
| `ui_state` | Reports the shell's state: active page, available pages, theme, window size and visibility, and the loopback address this instance serves its UI on. The orientation call before anything else. |
| `ui_navigate` | Activates a page of the shell by its stable name, which is English on every station: `View`, `Process`, `Logic`, `Connector`, `Users`, `Validation`, `Events`, `Agent`, `Settings`, `Account`. The label the navigation rail draws in the station's own language is accepted too. |
| `ui_screenshot` | Captures the window as shown on screen into a PNG file and returns its absolute path; restores the window first when hidden to the tray. Can capture one named screen region (a unique, visible `data-doc-region` area) instead of the whole window, and a missing, hidden or ambiguous region fails with the visible regions listed rather than silently falling back to a full capture. |
| `ui_scroll` | Scrolls the active page's main scroll region to top or bottom or by viewport pages, returning the offsets so a long page can be swept. |
| `ui_set_theme` | Applies the station's theme (System, Light or Dark): the one the station's window draws in and every browser that has not chosen its own follows; a browser that has chosen its own keeps it. This persists exactly like a choice made with the theme keys in the station's window, so a well-behaved agent restores the original value when done. |
| `ui_resize` | Resizes the restored window in device-independent units, clamped to the window minimum; useful to audit compact layouts. |
| `ui_click` | Clicks the visible button, hyperlink, checkbox or toggle whose text matches; checkboxes and toggles are found by their field label and the result reports the landed state. Ambiguity returns the candidates instead of picking one. |
| `ui_set_text` | Writes a value into a text box identified by its field label, committing the binding like typing would. |
| `ui_select` | Selects an item by visible text: a slash-separated path walks a tree, expanding along the way; a single segment also matches list, tab, combo-box items and grid rows on the current page. |

## Backups: manage {#backups--manage}

| Tool | What it does |
| --- | --- |
| `backup_create` | Creates an online snapshot of the configuration database into the backups folder, with an optional note. Recorded runs live outside the configuration and are never touched by backup or restore. |
| `backup_list` | Lists the configuration backups (file name, creation time, size, note) plus any restore already scheduled. |

There is deliberately **no backup delete tool**: retention is operator-only, on the
[Backups](settings-backups) page.

## Backups: restore {#backups--restore}

| Tool | What it does |
| --- | --- |
| `backup_restore` | Schedules a backup to replace the current configuration at the **next** application start. Nothing changes in the running app and the tool never restarts it; the configuration being replaced is snapshot automatically first, and the operator can cancel the pending restore from Settings until the restart. Refused while a recording is active. |

## Settings: manage {#settings--manage}

| Tool | What it does |
| --- | --- |
| `settings_read` | Reads the station's display and lifecycle preferences: date/time/number formats, decimal places, theme, close-to-tray and crash-report flags. |
| `localization_set` | Updates the display preferences (partial: omitted parameters stay). Display only: storage, driver I/O and recordings always use the invariant format. |
| `asset_list` | Lists the user assets (images, icons, colors) with ids, values and paths. |
| `asset_import` | Imports a PNG/JPG from a local file path into the app-owned asset library and returns the new asset id. The bytes are copied, so the source file may move afterwards. |
| `symbol_validate` | Validates inline symbol content (raw SVG or a v2 package) without persisting anything: a dry run of the exact import, returning errors, sanitizer warnings and a summary of what was recognized. The tool description carries the complete [portable symbol contract](ganter-symbols). |
| `symbol_import` | Imports inline symbol content as a new user-symbol asset and returns its id and `user:<guid>` reference. Always creates a new asset; a colliding name is auto-suffixed. |

## Reports: draft {#reports--draft}

| Tool | What it does |
| --- | --- |
| `report_draft` | Opens the [report form](account-feedback#a-report-drafted-by-an-agent) in the station's window, already filled in with what the agent wrote: `kind` (`DriverRequest`, `Bug` or `Suggestion`), `summary` (one line of at most 120 characters, refused rather than cut) and `details` (optional). Like the title bar's report button, it captures the window first and offers the capture with the report, ticked. It answers at once that the form is open and that nothing was sent. |

The tool never sends. The person at the station reads the report, corrects it if they want, and
presses Send; the outcome shows in the station's status bar and is not reported back to the agent.
While this area is on, the server asks every agent to offer a report when the person needs a driver
Ganter Lab does not have, when a call fails in a way that looks like a defect of the program, or when
the person asks for an improvement, and the descriptions of `driver_capabilities`, `device_upsert`
and `device_discover` say the same.

It refuses with a `reason`, and then opens nothing and captures nothing:

| `reason` | When |
| --- | --- |
| `not_permitted` | The role signed in at the station does not hold Send reports to Ganter. |
| `no_station_window` | The station has no window of its own to open the form in: a host that serves its pages to browsers only. |
| `no_credential` | The session cannot send: the demo profile, signed in or out, or a sign-in to the station's Ganter account that holds no credential. |
| `form_busy` | The report form is open at the station, or a report is being captured or sent. |
| `draft_in_progress` | The form holds a report a person is writing. An earlier draft of the agent's that nobody changed is replaced instead. |

A station not signed in to a Ganter account is not refused: the form opens, and says the report
goes without an account, so Ganter cannot reply to it.

Like every tool that changes something, it answers `Runtime stopped` while the runtime is stopped.
