The PsySpec is the XML file that defines a whole system architecture: which libraries to load, which modules exist, how they are triggered and where they post, plus whiteboards, catalogs, variables, parameters, nodes and spaces. It is read at startup:
./Psyclone spec=mysystem.xml [port=10000]
This page walks through the elements bottom-up, using the shipped examples — each snippet here comes from a runnable file in Examples/ (see Examples Index).
Skeleton
<psySpec>
<library name="Examples" library="Examples" />
<variable name="PingCycles" value="10" />
<whiteboard name="WB1" />
<catalog name="MyFiles" type="FileCatalog" root="./" />
<module name="Ping">
<trigger name="Ready" type="Psyclone.Ready" />
<crank name="Ping" function="Examples::Ping" />
<post name="Ball" type="ball.2" />
</module>
</psySpec>
Libraries
<library name="Examples" library="Examples" />
Loads a crank library. name= is the logical name used elsewhere in the spec; library= is the file stem — the platform file name and extension are resolved automatically (Examples.dll, libExamples.so; an optional path= sets the directory), so one PsySpec runs everywhere. Module <crank function="Library::Function"> entries refer to it by its name=.
Variables
<variable name="PingCycles" value="10" />
...
<parameter name="Cycles" type="Integer" value="%PingCycles%" />
Variables are simple spec-wide substitutions, referenced as Name% anywhere in the file — handy for tuning a whole test from one place (Examples/single.xml drives three sub-tests this way).
Modules
The full shape of a module entry:
<module name="Ping" node="Main">
<parameter name="Cycles" type="Integer" value="%PingCycles%" />
<context name="Test.PingPong">
<trigger name="Start" context="Test.PingPong" />
<trigger name="Ball" type="ball.1" />
<crank name="Ping" function="Examples::Ping" />
<post name="Ball" type="ball.2" />
<post name="Done" context="Test.Signals" />
</context>
</module>
- name must be unique in the system.
- node / space optionally place the module on a specific node or in a separate OS process (see Distributed Systems).
- <parameter> declares named, typed values the crank reads with cmlabs::PsyAPI::getParameter() — and that other components and PsyProbe can inspect and adjust at runtime (cmlabs::PsyAPI::tweakParameter()).
- <context> wraps the wiring that is only live while that context is active. It may be omitted entirely (the module is then always active), and a module may have several <context> blocks with different wiring in each — see Core Concepts.
- <trigger> subscribes to a message type (type=), a context change (context=), or a timer (interval= in ms). Extras: maxage= (ignore stale messages, ms), after=/delay= (delayed wake-up), wildcard types (type="Psyclone.*.MySpace.Connect").
- <crank> binds the code. If omitted, a built-in default crank simply posts the module's outputs upon triggering — enough for pure "wiring" modules like the Startup bootstrapper:
<module name="Startup">
<trigger name="Ready" type="Psyclone.Ready" />
<post name="Done" context="Test.PingPong" />
</module>
- <post> declares an output: a message type (type=) or a context change (context=). Options seen in the examples: to="WB1" (address a whiteboard directly), ttl="100000" (time-to-live), guaranteed="yes|no" (delivery guarantee; no allows faster unguaranteed transport between nodes, see Examples/multinode.xml), maxage=, and contentkey=/content= to inline a payload entry (Examples/messagerecord.xml).
- <signal> declares named signals for cmlabs::PsyAPI::emitSignal() / cmlabs::PsyAPI::waitForSignal():
<signal name="Output" type="My.Signal.1" />
<signal name="Input" type="My.Signal.2" />
- <retrieve> / <query> declare named whiteboard retrieves and catalog queries executed from crank code (see Whiteboards & Catalogs).
- <setup> passes an arbitrary setup string/XML to the component.
Whiteboards
<whiteboard name="WB1" key="count" keytype="integer" />
<whiteboard name="WB2" key="count" keytype="integer">
<trigger name="Ball" type="ball.4" />
</whiteboard>
A whiteboard stores messages for later retrieval. It receives messages either by being addressed (<post to="WB1" .../>) or by subscribing itself with <trigger> entries, in which case posters don't need to know it exists. key=/keytype= add a custom index over a user data entry so messages can be retrieved by value ranges, not just by time. Details and retrieval API: Whiteboards & Catalogs.
Catalogs
<catalog name="MyFiles" type="FileCatalog" root="./">
<parameter name="ReadOnly" type="String" value="no" />
</catalog>
<catalog name="MyData" type="DataCatalog" interval="2000" root="./mydata.dat" />
<catalog name="Replay1" type="ReplayCatalog" root="./replay1" maxsize="1024000" maxcount="20">
<trigger name="Ball" type="ball" />
</catalog>
The built-in catalog types (FileCatalog, DataCatalog, ReplayCatalog) are covered in Whiteboards & Catalogs. Note that catalogs, like whiteboards and modules, accept node= and space= placement attributes.
Nodes and spaces
<node name="Node1" address="localhost" port="11000" />
<space name="MySpace" type="external" />
<node> declares another Psyclone node that is part of this system; components can then be placed on it with node="Node1". <space> declares a separate OS process on the local node; components placed there with space="MySpace" get crash isolation from the main process. Both are covered in Distributed Systems.
A complete tour in one file
Examples/single.xml is the best single file to study: it chains three test phases (ping-pong → signals → catalogs) purely through context switches, uses variables, parameters, whiteboards with custom indexes, two catalog types, named retrieves and queries, and a shutdown module — all on one node. Examples/multinode.xml is the same architecture spread over two nodes.
Tips
- Give every trigger and post a meaningful name — crank code branches on trigger names, and posts are made by name; the names are your code↔spec interface.
- Use dot-delimited, namespaced message types of increasing specificity (MyProject.Input.Audio.Raw), which keeps PsyProbe's wildcard filters and trigger wildcards useful.
- Drive system phases with contexts (<post context="..."/>) rather than sentinel message types; you get the gating for free.
- End automated runs with a module that posts Psyclone.Shutdown (Examples/shutdown.xml is the minimal version).