Getting Started¶
CMDx is a Ruby framework for building maintainable, observable business logic through composable command objects. It brings structure, consistency, and powerful developer tools to your business processes.
Common challenges:
- Inconsistent service object patterns across your codebase
- Black boxes make debugging a nightmare
- Fragile error handling erodes confidence
What you get:
- Consistent, standardized architecture
- Built-in flow control and error handling
- Composable, reusable workflows
- Comprehensive logging for observability
- Attribute validation with type coercions
- Sensible defaults and developer-friendly APIs
Installation¶
Add CMDx to your Gemfile:
Configuration¶
For Rails applications, run the following command to generate a global configuration file in config/initializers/cmdx.rb.
If not using Rails, manually copy the configuration file.
The CERO Pattern¶
CMDx embraces the Compose, Execute, React, Observe (CERO, pronounced "zero") pattern—a simple yet powerful approach to building reliable business logic.
Compose¶
Build reusable, single-responsibility tasks with typed attributes, validation, and callbacks. Tasks can be chained together in workflows to create complex business processes from simple building blocks.
Execute¶
Invoke tasks with a consistent API that always returns a result object. Execution automatically handles validation, type coercion, error handling, and logging. Arguments are validated and coerced before your task logic runs.
# Without args
result = AnalyzeMetrics.execute
# With args
result = AnalyzeMetrics.execute(model: "blackbox", "sensitivity" => 3)
React¶
Every execution returns a result object with a clear outcome. Check the result's state (success?, failed?, skipped?) and access returned values, error messages, and metadata to make informed decisions.
if result.success?
# Handle success
elsif result.skipped?
# Handle skipped
elsif result.failed?
# Handle failed
end
Observe¶
Every task execution generates structured logs with execution chains, runtime metrics, and contextual metadata. Logs can be automatically correlated using chain IDs, making it easy to trace complex workflows and debug issues.
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}
Task Generator¶
Generate new CMDx tasks quickly using the built-in generator:
This creates a new task file with the basic structure:
# app/tasks/moderate_blog_post.rb
class ModerateBlogPost < CMDx::Task
def work
# Your logic here...
end
end
Tip
Use present tense verbs + noun for task names, eg: ModerateBlogPost, ScheduleAppointment, ValidateDocument
Type safety¶
CMDx includes built-in RBS (Ruby Type Signature) inline annotations throughout the codebase, providing type information for static analysis and editor support.
- Type checking — Catch type errors before runtime using tools like Steep or TypeProf
- Better IDE support — Enhanced autocomplete, navigation, and inline documentation
- Self-documenting code — Clear method signatures and return types
- Refactoring confidence — Type-aware refactoring reduces bugs