npx agentspec-cli install 7b5eb4cb-7e62-4a0b-9498-67682c0c0952 --framework ClaudeCode→ .claude/skills/cmdx/SKILL.md
# CMDx Agent Skill
CMDx is a Ruby framework for composable command/service objects with built-in attribute validation, type coercion, error handling, and observability.
For full documentation, see the [docs/](docs/) directory or the [LLM reference](https://drexed.github.io/cmdx/llms-full.txt). Key doc pages are linked throughout this skill via progressive disclosure.
## Task Lifecycle (CERO)
Every task follows: **Compose → Execute → React → Observe**.
```
middlewares.call!(task) do
before_validation → define & validate attributes → fail! if errors
before_execution → result.executing! → task.work
verify returns
rescue Fault → result.throw!(fault.result)
rescue StandardError → retry or result.fail!
ensure
result.executed!
on_complete / on_interrupted # by state
on_executed # if execution ran
on_success / on_skipped / on_failed # by status
on_good / on_bad # by status group
log → rollback? → freeze → clear chain
end
```
## Minimal Task
```ruby
class Greet < CMDx::Task
required :name, type: :string, presence: true
def work
context.greeting = "Hello, #{name}!"
end
end
result = Greet.execute(name: "World")
result.success? #=> true
result.context.greeting #=> "Hello, World!"
```
## Full-Featured Task
```ruby
class ProcessPayment < CMDx::Task
settings(
retries: 3,
retry_on: [Gateway::TimeoutError],
retry_jitter: :exponential_backoff,
rollback_on: ["failed"],
tags: ["billing"]
)
register :middleware, CMDx::Middlewares::Timeout, seconds: 10
register :middleware, CMDx::Middlewares::Runtime
before_execution :find_order
on_success :send_receipt
on_failed :alert_support, if: -> { context.amount > 1000 }
required :order_id, type: :integer
required :amount, type: :big_decimal, numeric: { greater_than: 0 }
optional :currency, type: :string, default: "USD", inclusion: { in: %w[USD EUR GBP] }
optional :idempotency_key, type: :string, default: -> { SecureRandom.uuid }
returns :charge_id, :receipt_url
def work
charge = Gateway.charge!(amount: amount, currency: currency, key: idempotency_key)
context.charge_id = charge.id
context.receipt_url = charge.receipt_url
end
def rollback
Gateway.refund!(context.charge_id) if context.charge_id
end
private
def find_order
@order = Order.find(order_id)
fail!("Order already paid") if @order.paid?
end
def send_receipt
ReceiptMailer.send(@order, context.receipt_url).deliver_later
end
def alert_support
SupportNotifier.high_value_failure(@order, result.reason)
end
end
```
## Workflow Example
Workflows compose tasks into sequential or parallel execution groups.
```ruby
class OnboardCustomer < CMDx::Task
include CMDx::Workflow
task ValidateIdentity
task CreateAccount, breakpoints: %w[failed]
task SetupBilling, if: :billing_required?
tasks SendWelcomeEmail, SendWelcomeSms, strategy: :parallel
private
def billing_required?
context.plan != "free"
end
end
result = OnboardCustomer.execute(email: "user@example.com", plan: "pro")
```
Workflows share a single context across all tasks. A failing task halts execution when its status matches the group's breakpoints (default: `["failed"]`).
For advanced patterns, see [references/workflows.md](references/workflows.md) and [docs/workflows.md](docs/workflows.md).
## Attributes
Declared with `required`, `optional`, or `attribute`:
```ruby
class Example < CMDx::Task
required :email, type: :string, format: { with: URI::MailTo::EMAIL_REGEXP }
optional :role, type: :string, default: "member", inclusion: { in: %w[admin member guest] }
attribute :notes, required: false
def work
# Attributes accessible as methods: email, role, notes
# These return coerced/validated values (see pitfall #2)
end
end
```
### Pipeline
Each attribute flows through: **Source → Coerce → Transform → Validate**.
### Type coercion
Built-in types: `:array`, `:big_decimal`, `:boolean`, `:complex`, `:date`, `:datetime`, `:float`, `:hash`, `:integer`, `:rational`, `:string`, `:symbol`, `:time`.
```ruby
required :count, type: :integer # single type
required :value, types: [Integer, Float] # multiple types
```
### Validations
Built-in: `presence`, `absence`, `format`, `length`, `numeric`, `inclusion`, `exclusion`.
```ruby
required :age, type: :integer, numeric: { greater_than: 0, less_than: 150 }
required :code, type: :string, length: { is: 6 }, format: { with: /\A[A-Z0-9]+\z/ }
optional :tags, type: :array, length: { maximum: 10 }
```
### Naming
```ruby
attribute :template, prefix: true # method: context_template
attribute :format, prefix: "report_" # method: report_format
attribute :branch, suffix: true # method: branch_context
attribute :scheduled_at, as: :when # method: when
```
### Transforms
```ruby
attribute :email, transform: :strip
attribute :tags, transform: :compact_blank
attribute :score, type: :integer, transform: proc { |v| v.clamp(0, 100) }
```
For the complete attribute reference, see [references/attributes.md](references/attributes.md). Deep dives: [docs/attributes/definitions.md](docs/attributes/definitions.md), [docs/attributes/coercions.md](docs/attributes/coercions.md), [docs/attributes/validations.md](docs/attributes/validations.md).
## Interruptions
### skip! and fail!
```ruby
def work
skip!("Already processed") # halts
skip!("Duplicate", halt: false) # continues
fail!("Not found", code: 404) # halts
fail!("Validation failed", halt: false, errors: validation_errors) # continues
end
```
### throw!
Propagates another task's result upward:
```ruby
def work
inner_result = InnerTask.execute(context)
throw!(inner_result) if inner_result.failed?
end
```
### Faults
`execute` never raises — returns a `Result`. `execute!` raises `CMDx::FailFault` or `CMDx::SkipFault` when the status matches breakpoints.
```ruby
result = MyTask.execute(data: input)
result.success?
begin
result = MyTask.execute!(data: input)
rescue CMDx::FailFault => e
e.result # the failed Result
e.context # the context (delegated from result)
e.message # failure reason string (set from result.reason)
e.result.reason # same reason via result
end
```
#### Fault matching
`for?` and `matches?` are class methods that return matcher classes for use in `rescue`:
```ruby
rescue CMDx::FailFault.for?(PaymentTask, BillingTask) => e
# only catches FailFaults from PaymentTask or BillingTask
rescue CMDx::FailFault.matches? { |f| f.result.metadata[:critical] } => e
# only catches FailFaults where the block returns true
end
```
## Result
```ruby
result = MyTask.execute(input: data)
# State: initialized, executing, complete, interrupted
result.state #=> "complete"
result.complete? #=> true
result.interrupted? #=> false
# Status: success, skipped, failed
result.status #=> "success"
result.success? #=> true
result.good? #=> true (success OR skipped)
result.bad? #=> false (skipped OR failed)
# Data
result.context # shared Context object
result.reason # skip/fail reason string
result.cause # the Fault that caused interruption
result.metadata # hash of extra data (errors, runtime, etc.)
result.chain # Chain of results in execution
# Handlers
result.on(:success) { |r| redirect_to(dashboard_path) }
.on(:failed) { |r| render_error(r.reason) }
.on(:skipped) { |r| log_skip(r.reason) }
# Pattern matching
case result
in ["complete", "success"] then handle_success
in ["interrupted", "failed"] then handle_failure
end
```
## Callbacks
Registered as class methods. Accept method names, procs, or blocks. Support `if:`/`unless:` conditions.
```ruby
class Example < CMDx::Task
before_validation :normalize_input
before_execution :load_dependencies
on_success :notify_user, if: -> { context.notify? }
on_failed :log_failure
on_complete :cleanup
end
```
### Execution order
1. `before_validation` — before attribute validation
2. `before_execution` — after validation, before `work`
3. `on_complete` / `on_interrupted` — by state
4. `on_executed` — if execution ran
5. `on_success` / `on_skipped` / `on_failed` — by status
6. `on_good` / `on_bad` — by status group
## Middleware
Wraps the entire execution. Must yield.
```ruby
# Built-in
register :middleware, CMDx::Middlewares::Timeout, seconds: 5
register :middleware, CMDx::Middlewares::Runtime # result.metadata[:runtime]
register :middleware, CMDx::Middlewares::Correlate, id: proc { SecureRandom.uuid }
# Custom
class AuditMiddleware
def self.call(task, **options)
AuditLog.start(task.class.name)
yield(task)
ensure
AuditLog.finish(task.class.name, task.result.status)
end
end
register :middleware, AuditMiddleware
```
## Configuration
### Global
```ruby
CMDx.configure do |config|
config.task_breakpoints = "failed"
config.workflow_breakpoints = ["skipped", "failed"]
config.rollback_on = ["failed"]
config.freeze_results = true
config.backtrace = false
config.logger = Logger.new($stdout)
config.exception_handler = proc { |task, e| ErrorTracker.report(e) }
end
```
### Per-task
```ruby
class MyTask < CMDx::Task
settings(
retries: 3,
retry_on: [Net::TimeoutError],
retry_jitter: :exponential_backoff,
rollback_on: ["failed"],
task_breakpoints: ["failed"],
tags: ["critical"],
log_level: :info,
log_formatter: CMDx::LogFormatters::Json.new,
deprecate: :log
)
end
```
For all options, see [references/configuration.md](references/configuration.md) and [docs/configuration.md](docs/configuration.md).
## Returns (Output Contract)
```ruby
class CreateUser < CMDx::Task
returns :user, :token
def work
context.user = User.create!(params)
context.token = generate_token(context.user)
end
end
```
Missing returns cause the task to fail with validation errors.
## Context
A shared, hash-like object passed through tasks:
```ruby
context[:key] # read
context.key # read (method_missing)
context.key = value # write
context.store(:key, value) # write
context.merge!(hash) # bulk write
context.fetch(:key, default) # read with default
context.fetch_or_store(:key, v) # read or write
context.key?(:key) # existence check
context.dig(:a, :b, :c) # nested read
context.delete!(:key) # remove
```
## Retries
```ruby
settings retries: 3, retry_on: [Net::TimeoutError]
settings retries: 5, retry_jitter: :exponential_backoff
settings retries: 10, retry_jitter: ->(count) { [count * 0.5, 5.0].min }
```
Only retries when the rescued exception matches `retry_on`. Clears errors between attempts. See [docs/retries.md](docs/retries.md).
## Dry Run
```ruby
result = MyTask.execute(data: input, dry_run: true)
result.dry_run? #=> true
```
The `work` method still runs — implement dry-run guards inside `work` using `dry_run?` (delegated from task to chain).
## Common Pitfalls
### 1. Forgetting `def work`
Every task must define `work`. Without it, execution raises `CMDx::UndefinedMethodError`.
### 2. Using `context` vs attribute methods
```ruby
# Wrong: bypasses validation/coercion
def work
context.email
end
# Right: declare attributes, use generated methods
required :email, type: :string
def work
email
end
```
### 3. Not handling `throw!` in nested tasks
```ruby
# Wrong: inner failure is silently swallowed
def work
InnerTask.execute(context)
end
# Right: propagate or check the result
def work
inner = InnerTask.execute(context)
throw!(inner) unless inner.success?
end
```
### 4. Mutating context after freeze
Results are frozen by default (`freeze_results: true`). Attempting to modify context after execution raises an error. Set `freeze_results: false` if post-execution mutation is needed.
### 5. Middleware that doesn't yield
A middleware that omits `yield` silently swallows execution. The result will be marked as failed with `metadata[:source] == :swallowed_middleware`.
### 6. Breakpoints confusion
- `task_breakpoints`: controls when `execute!` raises (default: `["failed"]`)
- `workflow_breakpoints`: controls when a workflow halts (default: `["failed"]`)
- Group breakpoints: `tasks TaskA, TaskB, breakpoints: %w[skipped failed]`
- Empty breakpoints `[]` means never halt
### 7. Missing returns
Declared `returns` are verified after `work`. If the context doesn't contain the declared keys, the task fails with validation errors.
### 8. Attribute ordering
Attributes are order-dependent. If one attribute references another as a source or condition, declare the referenced attribute first:
```ruby
# Correct
required :credentials, source: :database_config
attribute :connection_string, source: :credentials
# Wrong: connection_string references credentials before it exists
attribute :connection_string, source: :credentials
required :credentials, source: :database_config
```
### 9. Exception vs Fault
`StandardError` exceptions are caught by `execute` and converted to failed results. `execute!` re-raises them. `CMDx::TimeoutError` inherits from `Interrupt`, not `StandardError` — it's always raised.
## References
- [Attribute details](references/attributes.md) — coercions, validations, naming, transforms, nesting
- [Workflow patterns](references/workflows.md) — composition, breakpoints, parallel, conditions
- [Interruptions & faults](references/interruptions.md) — skip!/fail!/throw!, propagation strategies, fault matching, errors
- [Result API](references/result.md) — states, statuses, handlers, pattern matching, chain analysis
- [Configuration options](references/configuration.md) — global and per-task settings
- [Testing guide](references/testing.md) — RSpec matchers, setup, patterns
### Deep-dive docs
- Basics: [setup](docs/basics/setup.md), [execution](docs/basics/execution.md), [context](docs/basics/context.md), [chain](docs/basics/chain.md)
- Interruptions: [halt](docs/interruptions/halt.md), [faults](docs/interruptions/faults.md), [exceptions](docs/interruptions/exceptions.md)
- Outcomes: [result](docs/outcomes/result.md), [states](docs/outcomes/states.md), [statuses](docs/outcomes/statuses.md)
- Features: [callbacks](docs/callbacks.md), [middlewares](docs/middlewares.md), [workflows](docs/workflows.md), [retries](docs/retries.md), [logging](docs/logging.md)
- [Testing](docs/testing.md) | [Tips & tricks](docs/tips_and_tricks.md) | [Comparison](docs/comparison.md)
Built on the Agent Skills standard
Copilot Instructions
You are an AI assistant that specializes in software development for the Ruby programming language.
by AgentHub Crawler
GitHub Copilot Instructions for win32-process
This document defines the authoritative operational workflow for AI assistants contributing to the win32-process Ruby gem repository. This gem provides enhanced Process API functionality for Microsoft Windows platforms. All AI actions must operate through explicit user confirmation gates and repository safeguards.
by AgentHub Crawler
Task Master Development Workflow
This guide outlines the typical process for using Task Master to manage software development projects.
by AgentHub Crawler
Sign in to leave a comment.
inner-light-studio Cline Rules
Art, Movement & Meditation Space - Jekyll + React hybrid site
by AgentHub Crawler