Skip to content

Outputs

A playbook's outputs block names where a DONE run's findings are announced besides the store. What is announced: a stored open or confirmed finding never announced before (new), one last announced repeatWindowHours ago or more (repeat), and a finding the run resolved that had been announced (resolved). A run finds a candidate's row by its fingerprint (sha256(template | collection | candidate id)), else by the same playbook, collection and candidate id, so a row stored under another fingerprint continues and takes today's. A finding that comes back after a run resolved it reopens its own row (same id, its notes and verdicts kept) and is announced again as new, even inside the repeat window. Hidden and suppressed findings are never announced. No output failure changes the run.

A resolved finding says why it closed. Its entry in the session message, its MQTT message and the callback's finding dict carry reason — the resolve reason of section 8 ("When a finding closes": fire-passed, stretch-passed, not-screened, quiet, fell-back, within-band, not-checked, not-found); the key is absent when none was recorded. The email digest's Resolved list adds it in plain words after the subject, for example "(closed: no longer screened)". Every other key is unchanged.

Output Key What
Session message perspectiveMessage: { "type": "artekisFinding", "scope": "session" } at most one system.util.sendMessage per run to the playbook's own project, session scope, and only when the run has a finding that is new (reopened included), resolved, or escalated (its severity rose past the highest it has had; sent even inside the repeat window and not moving last_notified_at); a finding that merely continues (repeat) sends none, and is left to the email digest and MQTT. The views refresh on it, and Findings, FindingDetail and the Anomaly Watch queue also poll every 60 s, so a continuing finding's new last seen and count show without a message. It is opt-in per playbook (the Playbooks form's notification switch, on for a playbook created there); without it the views refresh only by polling. Never leaves the gateway
Email digest email: { "profile", "from", "to": [], "on": ["severity>=high"] } one HTML email per run through the named gateway email profile (from is required: a profile has no default sender; on filters by severity, nothing is sent when no finding passes). Severity badges, title, the subject as the plant names it (the context model's names, else its path), narrative, the "Do now" callout, the type-level reach line and each open finding's Cost with its kind (section 7.8: attributed, above normal, risk or not priced) render, findings worst first, then newest, in a standard HTML mail client
MQTT mqtt: { "connection", "topic", "qos": 1 } one JSON message per finding through the Artek MQTT suite (a priced new or repeated finding's message carries cost {kind, label, amount, currency, reason, figure, arithmetic, overlaps}, section 7.8; the callback's dict the same); the connection must be on policy.outputs.mqttConnections; without the suite the row records NO_SERVICE
Incident tags tags: true (default) the per-asset Incident tags (section 8.3)
Memory tags memoryTags: { "likely_cause": "[default]Line2/Out/Cause", … } maps likely_cause, confidence, action_now, finding_id, updated_at, open_findings, highest_severity to memory tags under a policy.outputs.memoryTagAllowlist prefix; checked when saved through playbooks.put (a Designer save of the file skips that check; the write-time check still applies) and before every write. Written on every DONE run that maps them: the two counts from the collection's store, the five finding fields from the most severe finding the run announces (an Incident run's follow its headline)
Callback callback: "package.module.function" a function in the playbook's own project under a policy.outputs.callbackAllowlist prefix, called once per announced finding with the finding dict, on its own pool, 30 s from being queued

Email and MQTT sends are egress rows with an outcome (SENT, PUBLISHED, QUEUED, REJECTED, NO_CONNECTION, NO_SERVICE, FAILED). Memory tags and callbacks never leave the gateway, so a success leaves no row; a failed write or callback does (REJECTED or FAILED), and the Status page's delivery failures list it.

The [Artekis] tag provider is created read-only when the module loads and rebuilt from the database at every start and whenever this gateway becomes the database owner. Its tree is a contract — bind to it, never write to it:

Path Written
[Artekis]Collections/<c>/Health/OpenFindings, HighestSeverity after every DONE run on the collection
[Artekis]Collections/<c>/Runs/<project>/<playbook>/LastRunAt, LastState, LastDurationMs at every run end; a cron playbook's go Bad_Stale (value kept) when its last DONE run is older than twice its interval
[Artekis]Collections/<c>/Assets/<asset>/Incident/… by Incident (section 8.3)
[Artekis]System/Provider/<name>/UsdToday, TokensToday, LastError after each run that called the provider and once a minute; reset at local midnight in the settings timezone
[Artekis]System/Owner, System/Scheduling on change

A collection or asset id holding . appears with : in these paths (system.artekis.outputs.tagPath builds the right one). On a gateway that does not own the Artekis database every tag reads Bad_Stale with its last value.