Curated library of 16 public Ruby AI agent skills: 10 atomic skills (YARD docs, service objects, calculator pattern, API clients, DDD, bug triage, code review, skill routing), 5 process-discipline skills (TDD, refactoring, review, security, test planning), and 1 planning skill (TDD task generation). Zero agents — this is a foundational library consumed by framework-specific tiles like rails-agent-skills and hanakai-yaku.
95
96%
Does it follow best practices?
Impact
95%
1.05xAverage score across 16 eval scenarios
Passed
No known issues
| Aspect | Rule |
|---|---|
| Entry point | def self.call(...) → new(...).call |
| Validation | Validate inputs at top of call; return error hash if invalid |
| Error handling | rescue → log + error hash; never re-raise to caller |
| Transactions | Only wrap multi-step database operations that must be atomic |
call length | ≤20 lines; extract sub-services if longer |
| Scope | Return data only (no HTTP/UI concerns); single responsibility per service |
| SQL | Use query sanitization for any dynamic queries |
| Shared logic | Extract validators to class-only services (Pattern 3) |
| Response data | Serialize domain data; do not return raw persistence model objects (e.g. ActiveRecord, ROM) in response |
| Response shape | { success: true/false, response: { ... } } always |
TESTS GATE IMPLEMENTATION:
EVERY service object MUST have its test written and validated BEFORE implementation.
1. Write the spec/test for .call (with contexts for success, error, edge cases)
2. Run the spec/test — verify it fails because the service does not exist yet
3. ONLY THEN write the service implementation
The final artifact must include the test command and the failure message
before implementation. Use the observed failure when available; otherwise show
the exact expected failure class/message for the missing service.
See tdd-process for the full gate cycle.spec/services/<module_name>/<service_name>_spec.rb or test/services/). Cover success and error paths for .call. Run it to confirm it fails (see HARD-GATE).services/<module_name>/<service_name>.rb or lib/services/) with the correct module namespace.self.call and #call. The response must always be { success: true, response: { ... } } or { success: false, response: { error: { message: '...' } } }.StandardError (and domain exceptions). Log with the application logger (e.g., logger.error). Use UPPER_SNAKE_CASE constants for all user-facing error strings.@param, @return [Hash], and @raise tags to self.call and every other public method. Document self.call separately from #call.services/<module_name>/README.md explaining domain context. Required even for single-service modules..call Patterndef self.call(params)
new(params).call
end
def call
# ... processing ...
{ success: true, response: { data: result } }
rescue StandardError => e
logger.error("Processing Error: #{e.message}")
logger.error(e.backtrace.join("\n"))
{ success: false, response: { error: { message: ERROR_MESSAGE } } }
enddef call
results = @items.each_with_object({ successful: [], failed: [] }) do |item, acc|
# process...
rescue StandardError => e
logger.error("Unexpected item error: #{e.message}")
acc[:failed] << { sku: item[:sku], error: e.message }
end
{ success: true, response: results }
endWhen no instance state is needed, use ONLY class methods — no initialize, no instance variables. Suitable for validators, formatters, and argument-only helpers.
class Orders::QuantityValidator
def self.call(quantity:)
return { success: false, response: { error: { message: INVALID_QUANTITY } } } unless quantity.positive?
{ success: true, response: { valid: true } }
end
endcall)def call
user_result = UserCreationService.call(@params)
return user_result unless user_result[:success]
# ... continue ...
endEvery service-object task produces these artifacts:
services/<module_name>/<service_name>.rb (pragma on line 1, class wrapped in a module matching the directory name).@param, @return [Hash], and @raise on self.call and every other public method (self.call documented separately from #call).UPPER_SNAKE_CASE at the top of the class, never inline in a rescue.services/<module_name>/README.md, required even for single-service modules.spec/services/<module_name>/<service_name>_spec.rb (or equivalent test runner file), written and failing BEFORE implementation (see HARD-GATE). Tests must assert success: and response: top-level keys and the meaningful payload shape.initialize, no instance variables).For class-only services (Pattern 3), document public class methods in YARD; if the class returns a non-standard shape (e.g. nil / error string), document that explicitly in YARD and the README.
Load these files only when their specific content is needed:
| Skill | When to chain |
|---|---|
| write-yard-docs | Writing/reviewing inline docs |
| integrate-api-client | External API integrations |
| implement-calculator-pattern | Variant-based calculators |
| write-tests | General testing structure |
| refactor-process | Refactoring service objects |
docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
skills
code-quality
respond-to-review
ddd
define-domain-language
model-domain
review-domain-boundaries
docs
write-yard-docs
orchestration
skill-router
patterns
create-service-object
implement-calculator-pattern
planning
generate-tdd-tasks
process
testing
triage-bug