Skip to content

PIPN (Plainly Indented Procedural Notation) is a minimalist notation system for documenting workflows.

Notifications You must be signed in to change notification settings

michal-zagalak/PIPN

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

Plainly Indented Procedural Notation

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.

Table of Contents

Basic Syntax

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.

Symbols

Task (#)

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

Comment (^)

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

Condition (?)

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

Loop (*)

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

Mode (%)

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

Goto (>)

References another element in the procedure. Three types of references are available:

  1. Reference to a given symbol within the same process:
# do something 
# do something else
? if this is true
	> do something
  1. Reference to an external PIPN process file:
? if this is true
	> external_process.pipn

Role (@)

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

End (~)

Indicates process termination or loop iteration end:

  1. Process termination:
? if this is true
	~ end process
  1. Loop iteration termination:
* for each thing in a collection of things
	# do something
	? if this is true
		~ end iteration

Exception (!)

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

Timed Event (:)

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.

  1. Timeout - triggers once after specified duration:
: in 1 h
	# do something
  1. Recurring Timeout - triggers repeatedly at specified intervals:
: every 1 h
	# do something
  1. 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

Subprocess ($)

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

Pause (|)

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

Message (&)

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

Variable Assignment (=)

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

Best Practices

  1. Use ASCII 09 (TAB) for indentation
  2. Use lowercase letters for all steps
  3. Avoid punctuation marks
  4. Write tasks in imperative form
  5. Start conditions symbols with "if" followed by condition
  6. Start exception symbols with "in case" followed by the expected event
  7. Start timeouts symbols with "in", "every" or "on"
  8. Start subprocesses symbols with nouns
  9. Start loops symbols with "for each", followed by iterator and collection specification
  10. Start pause symbols with "wait for" followed by the expected event
  11. Use implicit no-action alternative:
? if this is true
	# do something
# do something else
  1. Use explicit condition negation instead of else:
? if this is true
	# do something
? if this is false
	# do something else
  1. Avoid nested conditions. Instead of:
? if this is true
	? if that is true
		# do something

Use:

? if this and that are true
	# do something
  1. For complex conditions, use parentheses for clarity:
? if (A or B) and (C or D)
	# do something
  1. 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
  1. 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.
  2. Use Git for version control of PIPN files.

License

PIPN is free to use, modify, and distribute. Please consider attaching link to this instruction in your documentation.

Keywords

  • 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

Contact

For questions and feedback, please contact: michal.zagalak@hotmail.com