Authoring Templates
Template authoring follows a similar process to Typescript expansion rule authoring.
To create a new sequence template for an activity type (or to edit existing ones) navigate to the Sequence Templates page of Aerie.

To create a new template, select New Template
, and provide your template with:
- a name
- a sequencing language, currently restricted to:
STOL
,SeqN
, orText
- (this setting enables editor syntax highlighting for supported languages, but arbitrary languages may be used with the "Text" setting)
- a parcel ID (to get the set of allowed commands from the dictionary)
- a model ID (to enable access to the activity types)
- and the activity type that this template is for
To edit an existing template, mouse over it in the table and select the edit button.

This editor has autocomplete functionality, whitespace formatting, and error visibility for supported languages. There is also a panel that describes the available commands, one describing the template, and the ability to switch to editing a different sequence template.

Finally, you can save your result, and you are now ready to expand using this template.
Using the Handlebars template language
Sequence templates are written in the Handlebars template language. This language allows users to embed variables from some input (more on the input shortly) into a body of text. For example, if I had the following:
Input
{ input: "bananas" }
Template
I like to eat {{ input }}.
and compiled these together using Handlebars, I would get as a result:
Result
I like to eat bananas.
This is useful for expanding activities because, as discussed in the Introduction, it allows us directly write sequence templates with expressions, which more closely resemble the final expanded sequences than rules did. To reuse our earlier example, the template:
C BOOT_COPY_NOR_IMAGE "ZONE_0" "ZONE_1"
A2024-123T00:00:00 AVS_PCE_MEMORY_POKE {{ attributes.arguments.quantity }} "string"
C EP_XFC_LV_CLOSE "XFC_A"
C DP_PRIORITIZE "STRING" {{ attributes.arguments.quantity }}
compiles to this very similar looking result:
Result
C BOOT_COPY_NOR_IMAGE "ZONE_0" "ZONE_1"
A2024-123T00:00:00 AVS_PCE_MEMORY_POKE 5 "string"
C EP_XFC_LV_CLOSE "XFC_A"
C DP_PRIORITIZE "STRING" 5
Template input data
During expansion, Aerie goes through your plan looking for activities which have a template associated with them, and compiles the template with the following input data structure from the activity, which may be used in the template:
{
id: number; // ID of the activity instance
simulationDatasetId: number; // ID of the associated simulation dataset
simulationDataset: {
simulation: {
planId: number // ID of the associated plan
}
};
attributes: {
arguments: { ... }; // arguments provided to the activity
directiveId: number; // ID of the associated activity directive
computed: { ... }; // activity's computed attributes
};
duration: Temporal.Duration; // duration of the activity
startOffset: Temporal.Duration; // start offset of the activity from its parent, or the beginning of the plan
startTime: Temporal.Instant; // start time of the activity
endTime: Temporal.Instant; // end time of the activity
activityTypeName: string; // name of the associated activity type
}
So, to access the activity type name, followed by the end time, and then a computed argument by the name of quantity
, one could write:
CMD {{ activityTypeName }} endsAt={{ endTime }} quantity={{ attributes.arguments.quantity }}
The actual compilation of templates is discussed in Expanding Templates.
Template Helpers
We also introduce with Handlebars formatting the notion of helpers. Helper functions (discussed in the Handlebars documentation here), allow a user to invoke a function with arguments and produce a result in the template. Aerie defines 4 helpers for use in templates. User-defined helpers are not yet supported, so only these 4 are available at the moment.
add-time
This helper allows a user to compute a new time string (that is either STOL or SeqN compatible) from an existing one, and a duration to be added to that time. For example:
Input
{
...,
startTime: "2024-001T00:00:00",
attributes: {
...,
arguments: {
...,
growingDuration: "01:00:00"
}
}
}
Template
A{{ add-time startTime attributes.arguments.growingDuration }}
compiles to:
Result
A2024-001T01:00:00
subtract-time
This helper allows a user to compute a new time string (that is either STOL or SeqN compatible) from an existing one, and a duration to be subtracted from that time. For example:
Input
{
...,
startTime: "2024-001T00:00:00",
attributes: {
...,
arguments: {
...,
growingDuration: "01:00:00"
}
}
}
Template
A{{ subtract-time startTime attributes.arguments.growingDuration }}
which compiles to:
Result
A2023-365T23:00:00
format-as-date
This helper allows a user to format a date-like string input in the date format defined in the target sequencing language. For example, if I want STOL-like dates (which use /
instead of a T
, and include the time zone abbreviation) but my input is:
Input
{
...,
startTime: "2025-001T00:00:00.00
}
then I can write my template as:
Template
CMD AT={{ format-as-date startTime }}
which provides me with:
Result
CMD AT=2025-001/00:00:00Z
If the sequencing language is Text
, it is preferred that users include the Zulu time abbreviation in their input data. Currently, if it is left out, and the date is formatted as a YYYY-MM-DD string, the date is automatically converted to the current time zone, which produces some inconsistency in output.
flatten
This helper allows a user to format arrays correctly according to the target sequencing language. SeqN array formatting looks a little different than conventional array formatting in Handlebars, which we illustrate below:
Input
{
...,
attributes: {
...,
arguments: {
...,
array: [1, 2, 3, 3.5, "string"]
}
}
}
Template
Unflattened: {{ firstArraySet }}; Flattened: {{ flatten firstArraySet }}
compiles to:
Result
Unflattened: 1,2,3.5,string; Flattened: [1 2 3.5 string]
Putting this all together in AERIE, we might have the following:

Other Notes
There are some quirks to our application of the Handlebars language to sequence templates. Some of the least intuitive parts are listed below, please refer to the official Handlebars documentation for language details before filing an issue for any quirks you may notice.
Missing inputs/helpers
If you refer to an input variable or helper that is not present in the input object or the helpers library, it is considered invalid and will produce an empty string in the compiled output, for example:
Template
ECHO "{{ badInputVariable }}"
compiles to
Result
ECHO ""
HTML/XML-like String Escaping
HTML string escaping (should any inputs coming from a simulated activity have XML-like strings) is automatic in Handlebars. That is, if we have:
Input
{
name: "<name>"
}
Template
I am {{ name }}.
it will compile to:
Result
I am <name>.
This can be avoided by using triple brackets:
Input
{
name: "<name>"
}
Template
I am {{{ name }}}.
will compile to:
Result
I am <name>.
Helper functions will still be correctly applied to expressions in triple brackets.
Arrays and Objects
Arrays and objects also have particular behavior. There currently exists no well-defined behavior for objects, so the default behavior of resolving to the string [Object object]
for any given object is used. For arrays, if the flatten
helper isn't used, the array is serialized as a list of comma-separated elements WITHOUT brackets. That is:
Input
{
array: [1, 2, 3],
object: {
arbitrary: {
property1: "a",
property2: "b",
},
important: "item"
}
}
Template
Array: {{ array }}
Object: {{ object }}
will compile to:
Result
Array: 1,2,3
Object: [Object object]