Skip to content

Formal Specification ​

This page is the formal specification of the Instant Process language. Every node type the language supports is defined here as an EBNF production, accompanied by the constraints that EBNF cannot express on its own (uniqueness, defaulting, semantic restrictions).

Use this page when you need an unambiguous reference: tooling authors, reviewers writing parsers, and anyone integrating with the language. For a friendlier introduction, see the Documentation and the per-node pages.

Notation ​

The grammar uses the ISO/IEC 14977 EBNF metasymbols:

MetasymbolMeaning
=Defines a rule (left-hand side is the non-terminal being defined).
;Terminates a rule.
,Concatenation: items appear in sequence.
|Alternation: exactly one of the listed items.
[ x ]The item x is optional (zero or one occurrence).
{ x }The item x may repeat zero or more times.
( x )Grouping.
"x"A literal terminal (case-sensitive).
(* … *)A grammar comment; non-normative.

Whitespace (spaces, tabs) separates tokens but is otherwise insignificant. Each Node production occupies a single logical line; line breaks separate nodes. A # starts a comment that runs to the end of the line; comments are stripped before parsing and are ignored everywhere a token may appear.

Lexical productions ​

These productions define the basic tokens that node productions are built from.

text
Letter         = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
               | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
               | "U" | "V" | "W" | "X" | "Y" | "Z"
               | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j"
               | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t"
               | "u" | "v" | "w" | "x" | "y" | "z" ;

Digit          = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;

IdChar         = Letter | Digit | "_" | "-" ;

Identifier     = ( Letter | "_" ) , { IdChar } ;

DescriptionChar = ? any Unicode character except "'" ? ;

Description    = "'" , { DescriptionChar } , "'" ;

CommentChar    = ? any Unicode character except a line break ? ;

Comment        = "#" , { CommentChar } ;

HexDigit       = Digit | "a" | "b" | "c" | "d" | "e" | "f"
                       | "A" | "B" | "C" | "D" | "E" | "F" ;

ProcessId      = "'" , 8 * HexDigit , "-" , 4 * HexDigit , "-" , 4 * HexDigit , "-"
               , 4 * HexDigit , "-" , 12 * HexDigit , "'" ;

Constraints (not expressible in EBNF):

  • An Identifier must not contain whitespace and must not be enclosed in quotes, those forms are reserved for Description.
  • A Description must contain at least one character; an empty description ('') is invalid.
  • A Comment runs from the # to the end of the line and is discarded before parsing, so it may appear on its own line or after a complete node. It carries no meaning and never becomes part of the process.
  • A # inside a Description is an ordinary character, not the start of a comment.
  • Every node in a process must resolve to a unique identifier across the whole process. See Identifiers for how implicit and explicit identifiers share a namespace.
  • A ProcessId is the id of a process stored in the drive. It is written between single quotes and must be a well-formed id; the compiler does not check that a process with that id exists.

Node references ​

A NodeRef is how one node points at another, either by an explicit identifier token or by a description that doubles as an implicit identifier.

text
NodeRef = Identifier | Description ;

Constraints:

  • A NodeRef written as an Identifier matches a node whose explicit identifier is that token.
  • A NodeRef written as a Description matches a node whose implicit identifier (its description) is that string.
  • Every NodeRef must resolve to a node or a pool that exists in the same process. A NodeRef that names a pool is a connection that ends on that pool; see Pool.

Connections (NEXT, NEXT-MESSAGE, NEXT-ASSOCIATION and AND) ​

A node connects to other nodes with three clauses. The NextClause declares sequence flows, the MessageClause declares message flows and the AssociationClause declares associations. Every node type that carries outgoing connections uses the same clauses. They are defined once here and referenced from each node-type production.

Edge labels ​

A LinkDescription is an optional label attached to a single edge.

text
LinkDescription = Description ;

A single outgoing connection ​

A NextTarget is one outgoing edge: a target node and an optional edge label.

text
NextTarget = NodeRef , [ LinkDescription ] ;

The NEXT clause ​

A NextClause is either a bare NEXT (which falls through to the next node in the text), or NEXT followed by one or more NextTargets joined by AND. Every edge of a NextClause is a sequence flow.

text
NextClause = "NEXT" , [ NextTarget , { "AND" , NextTarget } ] ;

The NEXT-MESSAGE clause ​

A MessageClause has the shape of a NextClause with the keyword NEXT-MESSAGE in the place of NEXT. Every edge of a MessageClause is a message flow.

text
MessageClause = "NEXT-MESSAGE" , [ NextTarget , { "AND" , NextTarget } ] ;

The NEXT-ASSOCIATION clause ​

An AssociationClause has the shape of a NextClause with the keyword NEXT-ASSOCIATION in the place of NEXT. Every edge of an AssociationClause is an association: a link between a node and information that belongs with it, outside the flow of the process.

text
AssociationClause = "NEXT-ASSOCIATION" , [ NextTarget , { "AND" , NextTarget } ] ;

The connections of a node ​

A node carries one, two or three connection clauses, in any order, with at most one clause of each kind. Each clause has its own AND chain.

text
ConnectionClause = NextClause | MessageClause | AssociationClause ;

Connections      = ConnectionClause , [ ConnectionClause ] , [ ConnectionClause ] ;
text
GATEWAY 'Approved?' NEXT 'Ship order' 'Yes' AND 'Archive' NEXT-MESSAGE 'Notify customer' 'No' NEXT-ASSOCIATION 'Approval policy'

In this line the edges to Ship order and Archive are sequence flows, the edge to Notify customer is a message flow and the edge to Approval policy is an association.

Constraints:

  • A LinkDescription only attaches to a NextTarget (after an explicit NodeRef). A bare NEXT 'Some label' is invalid because the label has no edge to attach to.
  • When a clause is written bare (NEXT, NEXT-MESSAGE or NEXT-ASSOCIATION with no NextTarget), the connection is created to the next node in the text that takes part in sequence flow. StartNode, LaneNode, PoolNode, and AttachmentNode are skipped as targets. If no following node exists in the process, the clause is invalid.
  • Each NextTarget in an AND chain may carry its own independent LinkDescription.
  • An AND belongs to the clause it follows. Every NextTarget is the kind of edge its clause keyword declares, until another clause keyword starts the next clause.
  • A node carries at most one NextClause, at most one MessageClause and at most one AssociationClause. A second NEXT, a second NEXT-MESSAGE or a second NEXT-ASSOCIATION on the same node is invalid.
  • A bare NEXT-MESSAGE makes the fall-through edge a message flow, and a bare NEXT-ASSOCIATION makes it an association. When several nodes fall through to the same node, each edge is the kind its own clause declares.
  • A sequence flow is drawn as a solid line with a filled arrowhead. A message flow is drawn as a dashed line with a small open circle at its source and an open arrowhead at its target. An association is drawn as a dotted line without an arrowhead.
  • A message flow and an association take part in layout, side assignment, gateway branch labels and reference resolution exactly as a sequence flow does. The message-flow and association stylesheet selectors colour them; see Stylesheets.

Where an edge attaches ​

Every edge attaches to one side of a node: left, top, right or bottom.

  • Outgoing edges claim their sides first, one edge per side.
  • Incoming edges take the sides no outgoing edge of that node uses, one edge per side: the left side while it is free, then the free side each edge approaches from.
  • Once every side is taken, further incoming edges share the left side and arrive side by side.
  • Edges leaving the same side of the same node share one line, as long as they are all sequence flows, all message flows or all associations. Every other edge runs on its own line, parallel to its neighbours.

Top-level ​

A process is a sequence of nodes, one per line.

text
Process = { Node } ;

Node    = StartNode
        | EndNode
        | ActivityNode
        | EventNode
        | GatewayNode
        | LaneNode
        | PoolNode
        | AttachmentNode
        | SubprocessNode ;

Node specifications ​

Each section below gives a single-line EBNF production for a node type, followed by the slot-by-slot constraints. The shared rule for every node carrying a description is:

The Identifier slot is optional. When omitted, the node's Description is used as its identifier (an implicit identifier). When present, the Identifier replaces the implicit identifier, and references must use the explicit token. Prefer the implicit identifier: add an explicit Identifier only when two nodes would otherwise resolve to the same identifier (for example duplicate descriptions, or multiple START nodes). See Identifiers.

Start ​

text
StartNode = "START" , [ Identifier ] , Description , Connections ;
  • Identifier (optional): explicit identifier token. If omitted, Description is used as the implicit identifier.
  • Description (required): human-readable label, in single quotes.
  • Connections (required): outgoing connection(s). A bare NEXT, NEXT-MESSAGE or NEXT-ASSOCIATION falls through to the following node. A START line without a connection is a compile error.

See Basic nodes.

End ​

text
EndKeyword = "END"
           | "END-TERMINATE" ;

EndNode = EndKeyword , [ Identifier ] , Description ;
  • EndKeyword (required): END is the plain end event. END-TERMINATE is the terminate end event, which ends the whole process at once.
  • Identifier (optional): explicit identifier token.
  • Description (required): human-readable label.
  • An End node must not have Connections; end nodes are terminal.

See Basic nodes.

Activity ​

text
ActivityNode = "ACTIVITY" , [ Identifier ] , Description , [ Connections ] ;
  • Identifier (optional): explicit identifier token.
  • Description (required): human-readable label.
  • Connections (optional): outgoing connection(s).

See Basic nodes.

Event ​

text
EventKeyword = "EVENT"
             | "EVENT-MESSAGE"
             | "EVENT-TIMER"
             | "EVENT-CONDITIONAL"
             | "EVENT-ESCALATION"
             | "EVENT-LINK"
             | "EVENT-ERROR"
             | "EVENT-CANCEL"
             | "EVENT-COMPENSATION"
             | "EVENT-SIGNAL" ;

EventNode = EventKeyword , [ Identifier ] , Description , [ Connections ] ;
  • EventKeyword (required): selects the event subtype and the BPMN marker drawn inside the circle. The border and the catch or throw direction follow from the connections.
  • Identifier (optional): explicit identifier token.
  • Description (required): human-readable label.
  • Connections (optional): outgoing connection(s).

See Event nodes for the BPMN marker and meaning of each subtype.

Gateway ​

text
GatewayKeyword = "GATEWAY"
               | "GATEWAY-EVENT"
               | "GATEWAY-EXCLUSIVE"
               | "GATEWAY-PARALLEL"
               | "GATEWAY-INCLUSIVE"
               | "GATEWAY-COMPLEX" ;

GatewayNode = GatewayKeyword , [ Identifier ] , Description , [ Connections ] ;
  • GatewayKeyword (required): selects the gateway subtype; controls the marker inside the diamond.
  • Identifier (optional): explicit identifier token.
  • Description (required): human-readable label.
  • Connections (optional): outgoing connection(s). Gateways typically use AND to declare multiple branches, each with its own LinkDescription.

A gateway carries at most three distinct LinkDescription values across its outgoing connections, whatever their kind. A fourth distinct value is an error. Branches that repeat a LinkDescription leave the gateway in the same direction and do not count again. A gateway may have more than three outgoing connections.

A gateway's branches leave on the right, top and bottom sides, one branch per side (see Where an edge attaches). Branches past the three sides leave on the side that fits them best.

See Gateway nodes.

Pool ​

text
PoolClause      = ( "NEXT" | "NEXT-MESSAGE" | "NEXT-ASSOCIATION" ) , NextTarget , { "AND" , NextTarget } ;

PoolConnections = PoolClause , [ PoolClause ] , [ PoolClause ] ;

PoolNode        = "POOL" , ( Identifier | Description ) , [ PoolConnections ] ;
  • Identifier (required): the pool's name; doubles as the displayed pool label and as the pool's identifier. Written as a bare Identifier (e.g. POOL Customer) or as a quoted Description to allow spaces (e.g. POOL 'Web shop').
  • PoolConnections (optional): connections that start on the pool, at most one clause per keyword. Every clause names its targets; a bare clause on a PoolNode is invalid.
  • A process uses pools when its first node is a PoolNode. A PoolNode in any other process is invalid.
  • Every LaneNode and every other node after a PoolNode belongs to that pool until the next PoolNode. Declaring a pool again returns to it and resumes the lane that was last active in it.
  • A lane belongs to the pool it is declared in. The same lane name in two pools names two lanes.
  • A pool either declares lanes or holds its nodes directly. A LaneNode after a node that sits directly in the pool is invalid.
  • A pool without lanes and without nodes is valid.
  • A pool's identifier shares the namespace of the node identifiers. A pool and a node with the same identifier are invalid.
  • A NodeRef that names a pool is a connection that ends on the pool. A connection from one pool to another pool is valid.
  • A connection between a pool and a node inside that pool, a connection from a pool to itself, and a connection between a pool and an AttachmentNode are invalid.
  • A connection whose two ends are in different pools, or of which one end is a pool, is written as a message flow, with NEXT-MESSAGE. Written with NEXT it is reported as a warning and drawn as a sequence flow.
  • Pools are drawn stacked top to bottom in the order of their first declaration, separated by a gap. A pool carries its name in a header on the far left, with its lane headers to the right of that header. The lanes of a pool are stacked in the order of their first declaration in that pool.
  • A connection to or from a pool meets the border of the pool that faces its other end: the top border when the other end lies above the pool, the bottom border when it lies below. A message flow carries its open arrowhead, or its open circle, on that border.
  • The pool stylesheet selector colours pools; see Stylesheets.

See Links and lanes.

Lane ​

text
LaneNode = "LANE" , ( Identifier | Description ) ;
  • Identifier (required): the lane's name; doubles as the displayed lane label. Written as a bare Identifier (a single term with no spaces, e.g. LANE Customer) or as a quoted Description to allow spaces (e.g. LANE 'Sales Team').
  • A Lane node carries no separate Description and no Connections. Subsequent nodes belong to this lane until another LaneNode is encountered.
  • A later node belongs to an earlier lane only when that lane is declared again.
  • In a process that uses pools, a lane belongs to the pool it is declared in.

See Links and lanes.

Attachment ​

text
AttachmentKeyword = "DATA" | "DATABASE" | "TEXT" ;

AttachmentNode = AttachmentKeyword , [ Identifier ] , Description , [ Connections ] ;
  • AttachmentKeyword (required): DATA for a generic data artifact (page shape), DATABASE for a persistent store (cylinder shape), TEXT for a text annotation (the text inside an open bracket).
  • Identifier (optional): explicit identifier token.
  • Description (required): human-readable label. For a text annotation it is the annotation text.
  • Connections (optional): the node(s) the attachment is associated with. A bare NEXT, NEXT-MESSAGE or NEXT-ASSOCIATION falls through to the following node.
  • Attachments are not part of the sequence flow. Their Connections place the attachment next to the nodes they name.
  • An attachment and every node its Connections name belong to the same lane. A NextTarget naming a node in another lane is invalid.
  • Every connection of a text annotation is an association, written with NEXT or NEXT-ASSOCIATION. A MessageClause on a text annotation is invalid.

See Attachments.

Subprocess ​

text
ProcessClause  = "PROCESS" , ProcessId ;

SubprocessNode = "SUBPROCESS" , [ Identifier ] , Description , ProcessClause , [ Connections ] ;
  • Identifier (optional): explicit identifier token.
  • Description (required): human-readable label. It is the label drawn on the canvas; the referenced process's own name never appears there.
  • ProcessClause (required): names the process this node stands for. A missing clause, or a ProcessId that is not well-formed, is a compile error on that line.
  • Connections (optional): outgoing connection(s).
  • A subprocess node takes part in the sequence flow exactly as an ActivityNode does: incoming edges, AND chains, implicit NEXT, NEXT-MESSAGE and NEXT-ASSOCIATION fall-through, edge labels, and lane membership.
  • The compiler resolves nothing: it carries the ProcessId through as data. A reference to a process that does not exist still compiles.

See Subprocesses.

Semantic constraints summary ​

Constraints that EBNF cannot express, collected here for tooling authors:

  1. Identifier uniqueness: every node in a process must resolve to a unique identifier. Implicit and explicit identifiers share the same namespace.
  2. Implicit identifier defaulting: when a node omits its Identifier, the value of its Description is used as the identifier. This is a semantic rule, not a syntactic rewrite.
  3. NodeRef resolution: every NodeRef must point to a node declared somewhere in the same process.
  4. Empty NEXT fallback: a NEXT, NEXT-MESSAGE or NEXT-ASSOCIATION with no NodeRef connects to the next node declared in the source text that takes part in sequence flow; StartNode, LaneNode, PoolNode, and AttachmentNode are skipped as targets. Several nodes may each carry a bare clause before that target; every one of them connects to it. If no such node exists, the clause is invalid.
  5. LinkDescription placement: a LinkDescription may only follow a present NodeRef. A bare quoted string after NEXT, NEXT-MESSAGE, NEXT-ASSOCIATION or AND is not a valid link description.
  6. Terminal nodes: EndNode and LaneNode must not carry Connections.
  7. Subprocess reference: a SubprocessNode must carry a ProcessClause, and its ProcessId must be well-formed. The referenced process is resolved outside the compiler; a reference to a process that does not exist, or that the reader cannot open, is not a compile error. A subprocess node whose ProcessId is the process being edited is reported as a quality finding.
  8. Connection kinds: every edge of a NextClause is a sequence flow, every edge of a MessageClause is a message flow and every edge of an AssociationClause is an association. A node carries at most one of each clause. NEXT-MESSAGE and NEXT-ASSOCIATION are reserved words and are never an Identifier. Every edge of a text annotation is an association, and a text annotation carries no MessageClause.
  9. Pool scoping: a process uses pools when its first node is a PoolNode. POOL is a reserved word and is never an Identifier. TEXT is a reserved word and is never an Identifier. A pool's identifier is unique among the node identifiers.
  10. Pool connections: a NodeRef may name a pool. A connection never joins a pool to itself, to a node inside it, or to an AttachmentNode. A sequence flow whose ends are in different pools is reported as a warning.
  11. Minimal explicit identifiers: an explicit Identifier is only required to disambiguate nodes that would otherwise share an identifier (duplicate descriptions, or multiple START nodes). When a node's description is already unique, omit the explicit token and let the description serve as the identifier.