Plainly Indented Procedural Notation (PIPN) is a simple, tab-based notation system for describing procedural workflows and business processes. It emphasizes readability and quick authoring while maintaining the expressive power needed for complex process descriptions.
PIPN uses tab-based indentation and special symbols to represent different elements of a process. Each line starts with a symbol that defines its role in the procedure. By default, activities described in the text run sequentially - each line is processed one after another until reaching the "end process" symbol.
Represents an action to be performed. Tasks are written in imperative form, preferably using lowercase letters and avoiding complex sentences.
# do something
# do something else
# do something else entirely
Tasks can be nested to show subtasks. Nested tasks should fully cover the scope of their parent task:
# do something
# do the first half of something
# do the second half of something
Provides additional information for the reader. Comments are indented relative to the step they annotate:
# do something
^ comment on this step
# do something else
^ comment on this step
Defines conditional execution. Tasks indented under a condition are only executed if the condition is met:
? if this is true
# do something
? if that is true
# do something else
Implements iteration over a collection. Indented tasks are executed for each element in the specified collection. By default, iterations are sequential, but you can explicitly specify the execution mode as either sequential or concurrent:
Default (sequential) iteration:
* for each thing in a collection of things
# do something
# do something else
Explicit sequential iteration:
* for each thing in a collection of things sequentially
# do something
# do something else
Concurrent iteration:
* for each thing in a collection of things concurrently
# do something
# do something else
Determines the execution order of the indented tasks. Two modes are available: "concurrent" and "sequential". When using "concurrent" mode, subsequent tasks wait for the completion of all tasks grouped under this symbol:
% concurrent
# do something
# do something else
% sequential
# do one thing
# do a second thing
References another element in the procedure. Three types of references are available:
- Reference to a given symbol within the same process:
# do something
# do something else
? if this is true
> do something
- Reference to an external PIPN process file:
? if this is true
> external_process.pipn
Specifies the person or system responsible for executing the indented tasks. Optional if all tasks are performed by the same entity:
@ this person
# do something
@ that system
# do something else
Indicates process termination or loop iteration end:
- Process termination:
? if this is true
~ end process
- Loop iteration termination:
* for each thing in a collection of things
# do something
? if this is true
~ end iteration
Represents an event disturbing the normal flow of the process. Exceptions not indented under any symbol are considered global and are monitored throughout the entire process. When an exception occurs, tasks indented below it are executed:
! in case this thing happens
# do something
# do something else
When an exception is indented under a task symbol, it is monitored only during the execution of that task:
# do something
! in case this thing happens
# do something else
If a task containing an exception includes other subtasks, these tasks are written at the same indentation level after the exception symbol:
# do something
! in case this thing happens
# do something else
# do the first half of something
# do the second half of something
To monitor an exception during the execution of a task group that cannot be assigned its own name, use the mode symbol:
% sequential
! in case this thing happens
# do something else entirely
# do something
# do something else
If task execution should be interrupted when an exception occurs, use the goto symbol:
# do something
! in case this thing happens
> do something else entirely
# do something else
Multiple exceptions can be monitored simultaneously:
# do something
! in case this thing happens
# do something else
! in case that thing happens
# do something else entirely
Represents time-based events that trigger specific actions when time conditions are met. Similar to exceptions, but specifically for time-related events. Timed events can take three forms: timeout, recurring timeout, or deadline.
- Timeout - triggers once after specified duration:
: in 1 h
# do something
- Recurring Timeout - triggers repeatedly at specified intervals:
: every 1 h
# do something
- Deadline - triggers when specified date/time is reached:
: on 2011-11-11
# do something
Timed events can be applied to tasks and task groups using the mode symbol:
% sequential
: in 1 h
# do something else entirely
# do something
# do something else
Multiple timed events can be monitored simultaneously:
# do something
: in 1 h
# handle timeout
: every 11 min
# handle recurring timeout
: on 2011-11-11
# handle deadline
# do something else
Defines reusable subprocess that can accept arguments and return values. Subprocess are defined by indenting their steps under the subprocess name and can be called from other parts of the process:
$ double-checking something (it) return (status)
# check it for the first time
# check it for the second time
~ return status
> double-check something (this thing)
? if status of this thing is valid
# do something
? if status of this thing is invalid
# do something else
Subprocesses maintain their own scope and can handle exceptions:
$ doing something (this, that) return (status)
! in case the thing happens
~ return failure
# do something with this
# do something with that
~ return success
Suspends process execution until a specified event occurs. Unlike exceptions which monitor for events while the process continues, the pause symbol halts the process until the condition is met:
# do something
| wait for this thing to happen
# do something else
Pause can be combined with timed events to create timeout scenarios:
# do something
| wait for this thing to happen
: in 1h
# do something else
# do something else entirely
Represents sending a message to another process participant. Messages are used for communication between roles and can contain additional content:
@ sender
# do something
& message recipient (content)
@ recipient
| wait for a message from sender
# do something else
Assigns values to variables that can be used throughout the process. Variables can store numeric values, text, or complex objects and can be used in conditions, loops, and other process elements. Basic assignment:
= name = "John"
# do something with name
Variables in calculations and loops:
= sum = 0
* for each amount in a ledger
= sum = sum + amount
? if sum > 1000
# do something
- Use ASCII 09 (TAB) for indentation
- Use lowercase letters for all steps
- Avoid punctuation marks
- Write tasks in imperative form
- Start conditions symbols with "if" followed by condition
- Start exception symbols with "in case" followed by the expected event
- Start timeouts symbols with "in", "every" or "on"
- Start subprocesses symbols with nouns
- Start loops symbols with "for each", followed by iterator and collection specification
- Start pause symbols with "wait for" followed by the expected event
- Use implicit no-action alternative:
? if this is true
# do something
# do something else
- Use explicit condition negation instead of else:
? if this is true
# do something
? if this is false
# do something else
- Avoid nested conditions. Instead of:
? if this is true
? if that is true
# do something
Use:
? if this and that are true
# do something
- For complex conditions, use parentheses for clarity:
? if (A or B) and (C or D)
# do something
- Use exceptions for rollback operations when a process needs to undo previous steps:
# do something
# do something else
! in case this thing happens
# undo something
! in case that thing happens
# undo something else
- While this notation doesn't require specialized software beyond a text editor, it works best with outliner-type editors such as Workflowy, Dynalist, or OneNote.
- Use Git for version control of PIPN files.
PIPN is free to use, modify, and distribute. Please consider attaching link to this instruction in your documentation.
- Process Modeling: workflow notation, process description, business process modeling
- Technical Features: indentation-based syntax, plain text format, tab-based structure
- Use Cases: procedure documentation, workflow automation, process specification
- Integration: BPMN alternative, UML activity alternative, Git-friendly
- Target Users: business analysts, developers, technical writers
- Key Benefits: human-readable, easy to learn, lightweight notation
For questions and feedback, please contact: michal.zagalak@hotmail.com