Activity
An activity is a collection of connected tasks with one start event and one (or many) end events.
Installation
To use activities you need one gem, only.
gem "trailblazer-activity"
Overview
Since TRB 2.1, we use BPMN lingo and concepts for describing workflows and processes.
An activity is a workflow that contains one or several tasks. It is the main concept to organize control flow in Trailblazer.
The following diagram illustrates an exemplary workflow where a user writes and publishes a blog post.

After writing and spell-checking, the author has the chance to publish the post or, in case of typos, go back, correct, and go through the same flow, again. Note that there's only a handful of defined transistions, or connections. An author, for example, is not allowed to jump from "correct" into "publish" without going through the check.
The activity gem allows you to define this activity and takes care of implementing the control flow, running the activity and making sure no invalid paths are taken.
Your job is solely to implement the tasks and deciders put into this activity - Trailblazer makes sure it is executed it in the right order, and so on.
To eventually run this activity, three things have to be done.
- The activity needs be defined. Easiest is to use the Activity.from_hash builder.
- It's the programmer's job (that's you!) to implement the actual tasks (the "boxes"). Use tasks for that.
- After defining and implementing, you can run the activity with any data by
calling it.
Operation vs. Activity
An Activity allows to define and maintain a graph, that at runtime will be used as a "circuit". Or, in other words, it defines the boxes, circles, arrows and signals between them, and makes sure when running the activity, the circuit with your rules will be executed.
Please note that an Operation simply provides a neat DSL for creating an Activity with a railway-oriented wiring (left and right track). An operation always maintains an activity internally.
class Create < Trailblazer::Operation
step :exists?, pass_fast: true
step :policy
step :validate
fail :log_err
step :persist
fail :log_db_err
step :notify
end
Check the operation above. The DSL to create the activity with its graph is very different to Activity, but the outcome is a simple activity instance.

When calling an operation, several transformations on the arguments are applied, and those are passed to the Activity#call invocation. After the activity finished, its output is transformed into a Result object.
Activity
To understand how an activity works and what it performs in your application logic, it's easiest to see how activities are defined, and used.
Activity: From_Hash
Instead of using an operation, you can manually define activities by using the Activity.from_hash builder.
activity = Activity.from_hash do |start, _end|
{
start => { Trailblazer::Circuit::Right => Blog::Write },
Blog::Write => { Trailblazer::Circuit::Right => Blog::SpellCheck },
Blog::SpellCheck => { Trailblazer::Circuit::Right => Blog::Publish,
Trailblazer::Circuit::Left => Blog::Correct },
Blog::Correct => { Trailblazer::Circuit::Right => Blog::SpellCheck },
Blog::Publish => { Trailblazer::Circuit::Right => _end }
}
end
The block yields a generic start and end event instance. You then connect every task in that hash (hash keys) to another task or event via the emitted signal.
Activity: Call
To run the activity, you want to call it.
= {}
last_signal, , , _ = activity.( nil, , {} )
- The
startevent iscalled and per default returns the generic signalTrailblazer::Circuit::Right. - This emitted (or returned) signal is connected to the next task
Blog::Write, which is nowcalled. Blog::Writeemits anotherRightsignal that leads toBlog::SpellCheckbeingcalled.Blog::SpellCheckdefines two outgoing signals and hence can decide what next task to call by emitting eitherRightif the spell check was ok, orLeftif the post contains typos.- ...and so on.

Visualizing an activity as a graph makes it very straight-forward to understanding the mechanics of the flow.
Note how signals translate to edges (or connections) in the graph, and tasks become vertices (or nodes).
The return values are the last_signal, which is usually the end event (they return themselves as a signal), the last options that usually contains all kinds of data from running the activity, and additional args.
More
The full documentation for this gem and many more interesting things can be found on the Trailblazer website.