CMLabs · Psyclone AIOS

13. PsySpec XML Reference

Every PsySpec element and attribute, with an honest status badge for each: what ships, what is parsed but inert, and what is still roadmap.

How to read this chapter

This is the lookup chapter, extracted from the current parser code. Each element carries a badge:

  • Shipped — parsed and functionally wired.
  • Stub — parsed into internal structures but not (or only partially) acted on.
  • Roadmap — documented/reserved syntax; no real parsing or behaviour yet.

Status summary

ElementStatusNotes
<psyspec>ShippedRoot tag; new SSL policy attributes
<include>ShippedXML file inclusion
<variable>Shipped%var% substitution + new cmdline override
<node>ShippedMulti-node topology; per-node <library>
<library>ShippedDLL/.so registration
<space>ShippedOnly type="external" handled at top level
<interface>ShippedAuth/encryption children stubbed; new SSL attrs
<service>StubPartial: custom services have a NULL receiver
<psyprobe>ShippedPort / location / alias / post
<module>ShippedPer-module verbose/debug/logfile now wired
<whiteboard>Shippedroot= persistence is parsed-only
<catalog>ShippedFile/Data/Replay + CCM/TimeSeries families
<stream>StubComponent created, backing function empty
<feed>RoadmapLog-only branch, never becomes a component
<supervisor>RoadmapLog-only branch
<monitoring> / <performance>Roadmap“Not yet implemented” log
<group>RoadmapLog-only branch
<trigger>ShippedFilters, interval, context triggers
<filter>Shipped7 comparison types + maxage
<triggergroup>ShippedDeclarative multi-trigger join (all/N-of-M, time windows, snapshot, etc.)
<triggers>StubRecognised, silently does nothing
<retrieve>ShippedWhiteboard/catalog retrieval spec
<query>ShippedIncl. remote host/port queries
<retrieves> / <posts> / <signals>StubEmpty branches
<crank>ShippedFunction / script / inline / external
<post>Shipped
<signal>ShippedMinimal: name + type only
<context> (in module)ShippedGroups triggers under a named context
<parameter>ShippedTyped values incl. ranges/lists/random
<setup> / <key> / <customview>Shipped
<recording> / <playback>StubParameters stored, not acted on
<executable>StubCmdline stored, never launched
<alias> (in psyprobe)Shipped
<authentication> (in interface)StubParser body empty
<phase>RoadmapNo parsing code at all
system= trigger attributeRoadmapUse context= instead

<psyspec> (root) Shipped

The root element of every spec. Besides port= (main system port, see System Guide), it now carries the global SSL client-verification policy:

AttributeMeaningDefault
allowselfsignedNew. yes/true/1 loosens verification (accepts self-signed certificates) for all SSL client connections. Per-interface value overrides either way.secure — verify peer
cafileNew. Path to a CA PEM file used for SSL verification instead of the OS trust store.OS trust store
capathNew. Directory of CA certificates, same mechanism as cafile.OS trust store
Note. Top-level verbose/debug/logfile on the root element are Roadmap — only per-component logging attributes are wired. System-wide levels are set on the command line.

Children: <include>, <variable>, <node>, <library>, <space>, <interface>, <service>, <psyprobe>, <whiteboard>, <catalog>, <module>, <stream>, plus the roadmap tags listed above.

<include> Shipped

<include file="system.xml" /> splices the referenced file's contents into the spec (like a C include) and reparses; errors in the expanded spec report line/column. file is required. Includes and variables are processed before anything else.

<variable> Shipped

<variable name="SystemID" value="2" /> defines a literal %SystemID% text substitution applied over the whole spec before XML parsing — usable in names, cranks, triggers, anywhere, as long as the result stays valid XML. Both name and value are required.

Tip. New: a name=value argument on the Psyclone command line overrides the spec default — Psyclone spec=robot.xml SystemID=3. Reserved parameters (spec=, port=, html=, verbose=, debug=, per-topic variants) are respected and not treated as variables.

<node> Shipped

AttributeMeaningDefault
nameNode name; Main (or no/local address) reconfigures the local node
addr / addressIP or hostname (addr preferred, address accepted)local
typeNode type string (adhoc/java types not implemented Roadmap)
portPort; for the local node a differing port adds Main/PsyProbe/Console interfaces on it0
timeoutConnect timeout (ms)0

Child: <library name library path> — libraries loaded only on that node.

<library> Shipped

<library name="MyExamples" library="Examples" path="../libs" />. name is how cranks refer to it (MyExamples::Ping); library is the file name, resolved as Examples.dll (Windows) / libExamples.so (UNIX) — debug builds first try the ...Debug variants; path is an optional directory; node restricts to a node.

<space> Shipped

<space name="GUISpace" type="external" />. At the top level only type="external" is handled (creates a process-map entry waiting for an external program to connect). Regular spaces are created implicitly by the space= attribute on components (default Root). node restricts to a node. See Distributed Systems.

<interface> Shipped

<interface name="MyWebInterface" node="Node0" port="1234" protocol="HTTP"
           service="MyWebService" timeout="3000" default="yes" />
AttributeMeaningDefault
nameInterface name (required; parse fails without)
serviceTarget service name (required)
nodeNode the interface lives onany/local
portTCP/UDP port (required)
protocolMessage | HTTP | Telnet | RAW (anything else = parse failure)unset
ipUDP selects UDP; otherwise TCPTCP
timeoutTimeout msunset
defaultyes = default interface on a shared portno
allowselfsignedNew. Per-interface SSL verification override; wins over the global setting either wayinherit global
cafile / capathNew. Per-interface CA file/directory overrideinherit global

Child <authentication>: Stub — parsed by an empty function body; interface encryption attributes are likewise stubbed.

<service> Stub (partial)

Attributes: name, rootdir, subdir, timeout, node. The service is registered and a component is created for its subscription, so <trigger>/<post>/<crank> children parse — but custom services register a NULL receiver, so inbound requests are discarded. Built-in PsyProbe/Console services work. See Services & Interfaces.

<psyprobe> Shipped

AttributeMeaningDefault
defaultportAny value other than no removes PsyProbe from the main portshares main port
portAdds a dedicated PsyProbe HTTP interface on this port
locationWeb root directory for PsyProbebuilt-in

Children: <alias name location default> (URL alias to a local directory with optional default file) and <post> (same attributes as a module post plus XML content, registered as a clickable manual post in PsyProbe).

Components: <module> / <whiteboard> / <catalog> / <stream>

All component tags share one parser; the tag name selects the type. <module type="external"> declares an external process component (connects via a space). <module count=N> tag-instancing is Roadmap. Common attributes:

AttributeMeaningDefault
nameComponent name (required)
tagAppends _tag to the name; * uses the component's own name as tagnone
nodeNode assignment; modules also accept * = every nodeconfig node
spaceProcess space; Python-crank modules auto-get their own spaceRoot
selftriggerallow | warn | anything-else = nonewarn
logfileNew — now wired. Per-module log filenode log
verbose / debugNew — now wired. Per-module verbosity/debug levels (0–9)node levels
migrationyes flags the component movable; runtime migration itself is parsed-only Stubno
priorityuint8 stored; scheduling effect parsed-only Stub0

Extra attributes for whiteboard/catalog/stream/service:

AttributeMeaningDefault
function / typeBacking crank Lib::Func; bare names get the PsySystem:: prefix. Defaults: whiteboard→PsySystem::Whiteboard, stream→PsySystem::Stream; a catalog/service with neither is an error. Catalog type= selects the family: File/Data/Replay/RequestStore and the CCM & TimeSeries families are Shipped; the Media and Google catalog types are Stub — do not rely on them.see left
rootStorage root directory (whiteboard root= persistence is parsed-only Stub)
subdir / extSubdirectory / file extension
operationDefault operation
key + keytypeAdds an index key (repeatable via <key> children)time index
timeout / intervalms0
maxcount / maxsizeMax entries / max bytes0
rotateyes/no rotation (replay looping)no

Component children

ChildStatusMeaning
<recording root filesize overwrite>StubStores recording parameters; not acted on per-module
<playback root interval>StubStores playback parameters; not acted on
<executable consoleoutput autorestart>cmdline</executable>StubCommand line stored but never launched (roadmap: auto-start external processes)
<customview name template>ShippedRegisters a PsyProbe custom view; also accepts an inline XML/text body instead of a template= file
<setup>ShippedFree-form XML/text blob, read via getParameterString("componentsetup"); file= variant supported
<key name type>ShippedExtra index keys
<parameter>ShippedSee below
<context name>ShippedSee below

<parameter> Shipped

<parameter name=".." type="String|Integer|Float" value=".." interval=".." /> (type defaults to String). Rich value syntax:

FormExampleMeaning
Plain valuevalue="10"Fixed initial value
Rangevalue="[0:110]"Bounded range, initial = lowest
Stepped rangevalue="[0:110:2]"Step 2; step can also come from interval="2"
Range + initialvalue="[0:110]=55"Initial value 55
Random initialvalue="[0:110]=*"Random initial within the range
Listsvalue="[-2.5;1.5;1.8]", value="['a';'b';'c']"Enumerated numeric or string choices

All parameters are queryable, settable and tweakable at runtime (getParameterString/Int, setParameter, tweakParameter, resetParameter) — see Modules.

<context> (in a component) Shipped

<context name="SoB.Alive.Awake">...</context> groups child trigger/post/retrieve/query/crank/signal elements under a named context instead of the default Psyclone.Ready. See Contexts.

<trigger> Shipped

Subscribes the component to messages; a match dispatches its cranks. Valid if it has a name plus at least one of type, from, to; duplicate names are an error.

AttributeMeaningDefault
nameTrigger name (required, unique)
typeMessage type to match (wildcards allowed: input.audio.*)
from / toOnly messages from this component / addressed to this componentany
intervalms — makes it a timer trigger (needs one real message first to start)0
delay / afterms delay before firing (after is an alias)0
contextFire on context change to this context (forces type CTRL_CONTEXT_CHANGE)
maxagems — becomes a MAXAGE filter
tagMatch tag; * = component's own nameany

Trigger priority/history and the system= attribute are Roadmap — use context= to react to context changes.

<filter> (child of trigger) Shipped

<filter type="haskey" key="SomeKey" />                      <!-- entry exists (any type) -->
<filter type="equals" key="camera" value="front-left" />    <!-- string ==, exact, case-sensitive -->
<filter type="notequals" key="state" value="disabled" />    <!-- string != -->
<filter type="equalsnumeric" key="mode" value="3" />        <!-- float == -->
<filter type="notequalsnumeric" key="channel" value="0" />  <!-- float != -->
<filter type="greaterthan" key="temp" value="80" />         <!-- float > (≥ at the epsilon boundary) -->
<filter type="lessthan" key="pressure" value="2.5" />       <!-- float < (≤ at the epsilon boundary) -->

type is one of equals (exact, case-sensitive, no wildcards), notequals, equalsnumeric, notequalsnumeric, greaterthan, lessthan (all take key+value; numeric values are parsed as float64 with an epsilon compare, so exactly-equal values also pass greaterthan/lessthan) and haskey (key only, matches any entry type). The eighth filter operation, maxage, is written as a trigger attribute (milliseconds) rather than a <filter> child. Unrecognised types are silently ignored.

<retrieve> Shipped

On-demand fetch from a whiteboard/catalog when the owning trigger fires (see Whiteboards).

AttributeMeaningDefault
nameRequired, unique
sourceComponent to retrieve from (required)
type / from / toType / original sender / addressee filtersany
maxcountMax messages (0 = all)0
maxageAge window, stored ×1000 (exact wall-clock unit under review — see Whiteboards)
tagTag filter; * = own nameany
key / keytypeIndex key; keytype string|integer|float|time (invalid drops the spec)time
start / endRange bounds, interpreted per keytypeopen

<query> Shipped

Free-form query to a catalog/component; catalogs dispatch on the Query/Operation fields. Attributes: name (required, unique), source (required), type (string), subdir, ext, binary (yes), maxcount, maxage (stored ×1000; unit under review), key, value, operation, and for remote queries host (DNS-resolved at parse time) + port.

<crank> Shipped

The processing function attached to triggers. Four forms:

<crank name="c1" function="lib::function" />            <!-- C/C++ library crank -->
<crank name="c2" language="python" script="file.py" />  <!-- external script file -->
<crank name="c3" language="python">inline code</crank>  <!-- inline script -->
<crank name="c4" />                                     <!-- external crank slot -->

A function without lib:: is an internal (built-in) crank. Duplicate crank names across components are rejected. Modules with no crank get the built-in passthrough (Internal::Simple) default crank. Java cranks are Roadmap.

<post> Shipped

Message posted when the owning trigger fires. Valid if it has a name and (type or context).

AttributeMeaningDefault
nameRequired, unique
typeType of the posted message
contextPost a context change to this context
toAddress to a specific component (also still delivered to subscribers)broadcast
ttlSeconds (stored ×1000 ms); 0 = no expiry0
guaranteedno marks the message non-guaranteedguaranteed
tag* = own namenone

Message content comes from child XML elements; the older contentkey/content attribute form is no longer parsed. time="trigger" is Roadmap.

<signal> Shipped (minimal)

<signal name="Output" type="My.Signal.1" /> — both attributes required; no others are parsed. See Messaging & Signals.

<triggergroup> declarative join Shipped

Joins several triggers into one crank activation: member messages sharing the same tag are buffered on the node until the group completes, then delivered together as one set (wakeups ≈ joins, not one per member). Untagged messages group under the literal empty-string tag "" and never mix with real tags. This is the primitive for multi-modal fusion (audio + text + vision joined before a decision crank runs).

<module name="Simple" node="Node0">
  <triggergroup name="ts" count="2" maxage="2000">
    <trigger name="t1" type="bla1" />
    <trigger name="t2" type="bla2" />
    <trigger name="t3" type="bla3" optional="true" maxage="200" />
  </triggergroup>
  <crank name="c1" function="lib::function" />
  <post name="p1" type="bla4" to="WB/Stream/Cat" />
</module>
AttributeMeaningDefault
nameRequired, unique within the module. A duplicate group name discards the extra group with a level-1 warning; a group missing name or maxage is skipped with a warning.
maxagems — required, no default. A partial set living longer than this is evicted.
countFire when any N members are present ("all" = every named member). For N-of-M, any N complete the set; members arriving after the set closes are discarded.all
minFire at N members, then re-fire as more of the same tag-set arrive (growing set).
withinms — all required members present and their post times (send time) within the window.
timems — as within but on content times (created time). time="0" = identical content time.
modesnapshot — fire on the primary trigger (first child, or primary="true"), attaching the latest value of each other member: no wait, no tag match.
slideSliding-window correlation (with within=): re-emit a fresh joined set each time a member updates while the window still holds.off
debouncems — coalesce fast member streams: fire at most once per N ms with the latest set.
dupOn a duplicate member before completion: latest (latest-wins) or keep (queue all).latest
orderstrict — only fire if members arrived in declared order (pipeline-stage joins).off
timeout / ontimeoutOn timeout="<ms>" (or maxage) expiry with an incomplete set: ontimeout="fire" partial-fires (with a level-1 warning) or "discard" drops the set.fire

Child <trigger> elements accept all their normal attributes (they still route individually) plus:

AttributeMeaning
optional="true"Member is not required for completion; included in the delivered map if present.
maxage (per member)A member older than its own freshness bound does not count toward completion.
primary="true"Marks the primary trigger for mode="snapshot" (defaults to the first child).

SDK. A completed (or partial-fired) set arrives as one grouped activation. The crank calls waitForNewMessageGroup(ms, groupName), which returns a std::map<std::string, DataMessage*> keyed by trigger name — optional/absent members are simply not in the map (check with .count("t3")). getCurrentTriggerName() returns the group name. Messages are owned by the API for the activation and freed on the next waitForNewMessageGroup()/waitForNewMessage() call. Existing single-message cranks are untouched.

Stub grouping elements Stub

<triggers>, <retrieves>, <posts> and <signals> are recognised by the parser but their handling bodies are empty — they silently do nothing.

Roadmap-only elements Roadmap

<feed>, <supervisor>, <monitoring>, <performance> and <group> are logged and ignored; <phase> has no parsing code at all. None of these produce components or behaviour in the current build — do not rely on them.

Cross-cutting rules

  • Config-node scoping: elements without node= run on the config node; with node= only on the named node.
  • Expansion order: variables and includes are processed before all other parsing; the spec is reparsed after each expansion.
  • Code escaping: inside the spec, message content and setup blobs must remain valid XML.
Psyclone AIOS · CMLabs