Project

cmdx

0.0
A long-lived project that still receives updates
CMDx is a framework for building maintainable business processes.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme

CMDx Logo

Version Build License

🚀 CMDx — Business logic without the chaos

Stop wrestling with messy service objects. CMDx gives you a clean, consistent way to design business processes:

  • Start small with a single work method
  • Scale to complex tasks and multi-step workflows
  • Get built-in flow control, logging, validations, and more...

Build faster. Debug easier. Stay sane.

Compose, Execute, React, Observe pattern

CMDx encourages breaking business logic into composable tasks. Each task can be combined into larger workflows, executed with standardized flow control, and fully observed through logging, validations, and context.

  • Compose → Define small, contract-driven tasks with typed attributes, validations, and natural workflow composition.
  • Execute → Run tasks with clear outcomes, intentional halts, and pluggable behaviors via middlewares and callbacks.
  • React → Adapt to outcomes by chaining follow-up tasks, handling faults, or shaping future flows.
  • Observe → Capture immutable results, structured logs, and full execution chains for reliable tracing and insight.

Installation

Add this line to your application's Gemfile:

gem 'cmdx'

And then execute:

$ bundle

Or install it yourself as:

$ gem install cmdx

Quick Example

Here's how a quick 4 step process can open up a world of possibilities:

1. Compose

Minimum Viable Task

class SendAnalyzedEmail < CMDx::Task
  def work
    user = User.find(context.user_id)
    MetricsMailer.analyzed(user).deliver_now
  end
end

Fully Featured Task

class AnalyzeMetrics < CMDx::Task
  register :middleware, CMDx::Middlewares::Correlate, id: -> { Current.request_id }

  on_success :track_analysis_completion!

  required :dataset_id, type: :integer, numeric: { min: 1 }
  optional :analysis_type, default: "standard"

  def work
    if dataset.nil?
      fail!("Dataset not found", code: 404)
    elsif dataset.unprocessed?
      skip!("Dataset not ready for analysis")
    else
      context.result = PValueAnalyzer.execute(dataset:, analysis_type:)
      context.analyzed_at = Time.now

      SendAnalyzedEmail.execute(user_id: Current.account.manager_id)
    end
  end

  private

  def dataset
    @dataset ||= Dataset.find_by(id: dataset_id)
  end

  def track_analysis_completion!
    dataset.update!(analysis_result_id: context.result.id)
  end
end

2. Execute

result = AnalyzeMetrics.execute(
  dataset_id: 123,
  "analysis_type" => "advanced"
)

3. React

if result.success?
  puts "Metrics analyzed at #{result.context.analyzed_at}"
elsif result.skipped?
  puts "Skipping analyzation due to: #{result.reason}"
elsif result.failed?
  puts "Analyzation failed due to: #{result.reason} with code #{result.metadata[:code]}"
end

4. Observe

I, [2022-07-17T18:42:37.000000 #3784] INFO -- CMDx:
index=1 chain_id="018c2b95-23j4-2kj3-32kj-3n4jk3n4jknf" type="Task" class="SendAnalyzedEmail" state="complete" status="success" metadata={runtime: 347}

I, [2022-07-17T18:43:15.000000 #3784] INFO -- CMDx:
index=0 chain_id="018c2b95-b764-7615-a924-cc5b910ed1e5" type="Task" class="AnalyzeMetrics" state="complete" status="success" metadata={runtime: 187}

Table of contents

Ecosystem

For backwards compatibility of certain functionality:

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/drexed/cmdx. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the CMDx project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.