Atlas Knowledge Base
Dashboard
APSL Specification

APSL Specification


The Action Plan Scripting Language (APSL) is a markdown-based language for writing alarm response protocols. A script is authored in markdown, validated at compile time, and interpreted at runtime by the APSL Executor, which drives the operator UI over a WebSocket.

Design goals: readable markdown structure, an explicit safety model around dispatch, compile-time validation, and real-time backend-driven execution.

Safety rules

These are the non-negotiable guarantees the compiler and runtime enforce:


Rule

Enforcement

@auto dispatch is forbidden

Compiler error

@dispatch with a countdown (in <duration>) is forbidden

Compiler error

All dispatch requires operator confirmation

Structural (the two rules above)

@resolve must be terminal

Compiler warning if actions follow

Script should contain at least one @resolve

Compiler warning

All phase references must exist

Compiler error

Only @auto resolve closes immediately; bare @resolve needs operator confirmation

Runtime behavior

Document structure

An APSL script is YAML frontmatter, an optional @layout, then one or more phases. Frontmatter is required — a document without it falls back to a legacy syntax mode, so new scripts should always include it.

---
layer: standard # standard | dealer | installation | temporary (required)
version: 1.0.0 # required
dealer_id: acme-security # required when layer: dealer
expires: 2026-02-01T00:00:00Z # required when layer: temporary
params: # optional, exposed at runtime as instructions.params.*
max_contacts: 3
context: # optional test/dev context (production context comes from SBN)
account:
name: "Test Account"
---

@layout dispatch-video-focus

# Initial Assessment {#init}
...

Phases are markdown H1 headings (# followed by a space; ## and deeper are not phases). The {#id} is optional — when omitted the ID is kebab-cased from the title. A trailing @if <condition> gates the phase. Phase IDs must be unique, and content before the first heading becomes an implicit main section.

Actions

@auto action executes immediately; a bare @action pauses and creates an operator intervention. @dispatch may never be @auto.


Group

Actions

Setup

@ack, @take, @transfer <terminal>, @video <target>, @ai_detect, @ai_detect_quick, @ai_describe, @snapshot

Communication

@call, @sms, @email, @twv, @say, @hangup, @join

Dispatch (never @auto)

@dispatch <type> where type is police, fire, medical, guard, or cancel

Logging

@auto log "msg", @log, @comment "prompt"

Timing / resolution

@timer <duration>, @resolve <code>, @auto resolve <code>

When @log, @sms, or @email run without @auto, the operator is shown the pre-filled message to amend or cancel before it executes.

Text, display, and interpolation

Plain text (quoted or unquoted) is shown to the operator; bold marks critical warnings and italic is secondary emphasis. Fenced code blocks embed UI components — the block type is captured and the content is passed verbatim to the frontend (conventional types: data, map, contacts, timeline, video). Variables interpolate with {{path}}; an unresolved path renders as [no <root>].

Not implemented: the {{ value | filter }} pipe syntax is not wired up end-to-end — do not use filters in production scripts.

Choices and navigation

? "What do you see on video?"
- [Person detected](#dispatch)
- [Motion only](#verify) @if account.has_guard
- [False alarm](@resolve FA)

A choice target may be a phase (#id), a loop control (@continue / @break), or an inline action such as @resolve. Only @if is supported as a choice modifier. Direct navigation uses [](#id); conditional navigation uses @if / @else blocks around [](#id) links.

Control flow

  1. Conditionals: @if <cond>: / @else: (no @elif). Operators: ==, !=, <, <=, >, >=, in, contains, combined with and, or, not.
  2. Loops: @each x in list [where <cond>] [limit N]: with loop.index / loop.count / loop.first / loop.last available in the body.
  3. Wait: @wait <event> [or <event>] [timeout(<dur>)] — pauses for known events (ai_result, call_answered, guard_arrived, police_arrived, urn_received, timeout, etc.).

Input collection

@input "Enter verification code" -> code, required: true

@form dispatch_details:
- key: incident_type, format: select, label: "Incident Type"
- key: weapons_observed, format: boolean, label: "Weapons Observed?"

@set verified = false

@input and @form recognize type, format, required, maxLength, and placeholder. The format value is a free-form string passed to the frontend (conventional: string, number, select, textarea, phone, …). Format-specific properties such as mask:, options:, pattern: are not parsed and are silently dropped.

UI control

@layout <name> sets the panel arrangement and must appear once, at script start. @view / @hide appear in a section preamble (before the first instruction); @toggle / @configure may appear anywhere. Layout and panel names are free-form strings and are not validated against a known set.

Context namespaces

The runtime context combines incident data from SBN with variables injected during execution:


Namespace

Contents

incident.*

Alarm-queue data (installation ID, customer, address, alarm type/text, terminal, priority, zone)

installation.*

Site details (number, name, address, phones, email, lat/long, dealer)

panel.*

Alarm ID / panel info (type, transmitter, test mode, monitoring status)

account.*

id, name only

zone., signal., site.*

Zone, signal/SIA code, site

contact.N.*

1-indexed contact map (name, phones, type, codeword, passcard, language)

instructions.*

Layer metadata (layer, version, dealerID, expires, params)

person_detected, detections, ai.*

AI detection results injected at runtime

Resolution codes

The validator warns (does not error) on unrecognized codes; at runtime the operator-facing list is fetched per dealer.


Code

Meaning

Code

Meaning

FA

False Alarm

WOK

Welfare OK

FT

False Alarm – Technical

TRN

Transported

VA

Verified Alarm

REF

Refused Service

UV

Unable to Verify

ESC

Escalated

CAN

Cancelled



Validation

Validation runs at compile time. Errors block deployment (@auto dispatch, dispatch-with-countdown, unknown phase reference, missing/invalid layer or version, duplicate phase ID, misplaced @layout/@view/@hide, infinite loop). Warnings flag likely mistakes (unreachable phase, no @resolve in the script, code after @resolve, unknown resolution code). Unknown action, panel, and layout names are not validated.

See also

  1. APSL Executor — the runtime that interprets these scripts




Was this helpful?