Triggers
A trigger is something that can cause a reaction to run. Domain events and the clock are built in; everything else is declared, so the set of things an application can react to is open without the language having to grow a keyword per source.
Two kinds of trigger, one of them declared. This page is about application triggers - the declared signal, with a payload shape, that a
reaction ... whenconsumes. What starts something in the UI is an interaction trigger: the anonymouson click/on enterclause of a behavior, which is never declared. See Interactions. The two meet in two places:on <ApplicationTrigger>lets an interaction observe a declared trigger, andraise <ApplicationTrigger>lets one fire it. A trigger declared with the name of a built-in interaction kind is an error, sinceon <Name>would then mean the interaction.
Syntax
Section titled “Syntax”trigger <Name> [description "<text>"] [file <path>] [<name> [<Type>]]*The optional file line names the repository relative file this declaration is realized by, so a document can be navigated back to the code it describes. It is additive - it never stands in for any part of the declaration. See File references.
A trigger body reserves file, so a trigger value by that name is written @file.
A trigger is declared at the top level of a document, beside concept, type and policy, because what
can happen to an application is not the property of one slice.
What a trigger declares
Section titled “What a trigger declares”A trigger declares two things: that the name exists, and what an occurrence of it hands the reaction.
trigger GitHubIssueCreated description "GitHub reported a new issue on a watched repository" repository Repository issue IssueIt deliberately declares nothing about what makes one occur. That belongs to whatever produces it — an integration, a runtime signal, a person — and keeping it out of the document is what lets the set be open at all. The compiler’s whole job here is to know the name and the shape, so a reaction naming it resolves and a reaction taking a value it does not carry is reported.
The type on a value is optional:
trigger DirectoryChanged entry changedAt DateTimeA trigger is often declared before the shape of what it carries has settled, and a bare name is already a useful statement — the reaction is handed something by that name. Add the type when there is one to state.
Using one
Section titled “Using one”A reaction names a trigger with when, exactly as it names an event:
trigger BuildFinished repository outcome
module Delivery feature Builds slice Automation NotifyOnFailure reaction NotifyOnFailure when BuildFinished repository outcome where outcome == "failed"That sameness is the point. A reaction should not have to know whether what set it off came from the event store, a clock, an integration or a custom runtime provider — see Trigger → reaction → effects.
How a name resolves
Section titled “How a name resolves”when <Name> is resolved against three sets, in the order they sit closest to the document:
| Order | Set | Declared by |
|---|---|---|
| 1 | events the document declares or imports | event <Name> / import <Qualified.Name> |
| 2 | triggers the document declares | trigger <Name> |
| 3 | triggers registered with the compiler, plus the built-in host signals | a consumer, or the language |
If an event and a declared trigger share a name, the event wins. Both reaction value validation and
executable binding use the event’s shape, including values used by produces ... for <value>; the shadowed
trigger’s shape does not contribute. An imported event also wins, but its unknown shape cannot be checked
against the declared trigger’s values. Rename and reference queries follow that same precedence: renaming
an event updates its reaction’s when reference, while editing a shadowed trigger’s name leaves it alone.
Editor hover and go-to-definition select the event too; an external import has no local definition to open.
A registration wins over a built-in of the same name, so a host that raises a richer Startup can say what
it carries rather than being overruled by the empty one the language ships.
Only when all three miss is the name reported as unknown — as a warning, like every other unresolved reference in the language.
Built-in triggers
Section titled “Built-in triggers”| Trigger | Occurs |
|---|---|
Startup | when the application starts |
Shutdown | when the application stops |
These need no declaration because every application has them and there is no event to declare for them.
The clock is built in too, but with its own syntax rather than a name — see
what sets a reaction off. Clock triggers (every and at) take no values, so value lines beneath them are errors. A reads line under any reaction trigger takes no indented children either; such lines are rejected, not treated as values.
Registering a trigger
Section titled “Registering a trigger”A trigger an integration provides has no declaration in the document that reacts to it — the integration is what knows it exists. A consumer tells the compiler about it through the same registry that carries the inline sub-languages:
var compiler = new ScreenplayCompiler( new ScreenplayLanguageRegistry(triggers: ["GitPushed", "PullRequestMerged"]));That form says only that the compiler recognizes the name. A registration can also say what an occurrence hands the reaction, and then a reaction taking anything else is reported exactly as it is for a declared trigger:
var compiler = new ScreenplayCompiler( new ScreenplayLanguageRegistry(triggers: [ new TriggerDefinition("GitPushed", ["repository", "branch", "sha"]), new TriggerDefinition("PullRequestMerged", ["repository", "number"]) ]));Stating no values and stating none are different claims. A TriggerDefinition with no Values says the
registration does not describe the shape, so what a reaction takes is left alone. One with an empty list says
an occurrence carries nothing, so taking something from it is reported. The built-in Startup and Shutdown
are registered the second way.
What a registration never says is what makes an occurrence happen. That boundary is the same one the inline languages draw, and it is what keeps the set open.
A trigger the document itself needs to describe — its values, or what it means — is better written as a
trigger declaration, where a reader can see it.