Curated library of atomic AI agent skills for Hanami, dry-rb, and ROM Ruby development. Covers actions, slices, repositories, relations, changesets, providers, DI, operations, TDD, CLI, views, routing, and validation. Shared Ruby process skills have moved to ruby-core-skills. Uses Markdown + Front-matter architecture.
92
94%
Does it follow best practices?
Impact
92%
1.33xAverage score across 35 eval scenarios
Passed
No known issues
Use this skill when creating View Parts for decorator-style logic in Hanami 2.x.
Core principle: Parts wrap data with presentation methods. They keep Views and templates free of complex formatting logic.
| Scenario | Approach |
|---|---|
| Create a Part | Class inherits from Hanami::View::Part |
| Expose as a Part | expose :user, as: :user_part |
| Define Part methods | Add methods to the Part class for presentation logic |
| Access wrapped data | value method returns the raw underlying object |
| Delegate to wrapped data | delegate :name, :email, to: :value |
| Use in template | <%= user_part.display_name %> |
| Format data | def formatted_date; value.created_at.strftime("%B %d, %Y"); end |
| Generate HTML | Keep HTML generation out of Parts. Use helpers or template logic. |
Create the Part class:
# app/views/parts/user.rb
# frozen_string_literal: true
module MyApp
module Views
module Parts
class User < Hanami::View::Part
delegate :name, :email, to: :value
def display_name
"#{value.first_name} #{value.last_name}"
end
def member_since
value.created_at.strftime("%B %Y")
end
def admin?
value.role == "admin"
end
end
end
end
endExpose data as a Part in the View:
class Show < MyApp::View
expose :user, as: :user_part
endUse Part methods in templates:
<h1><%= user_part.display_name %></h1>
<p>Member since <%= user_part.member_since %></p>
<% if user_part.admin? %>
<span class="badge">Admin</span>
<% end %>Keep Parts focused on presentation. No database queries, no business rules:
# GOOD: formatting and simple predicates
def display_name
"#{value.first_name} #{value.last_name}"
end
# BAD: business logic
def can_delete?(resource)
value.role == "admin" && resource.owner_id == value.id
endDelegate common methods to the wrapped value:
delegate :id, :name, :email, :created_at, to: :valueAccess the raw value with the value method when needed:
def raw_attributes
value.to_h
endDo not generate HTML in Parts. Parts return strings or booleans. Templates handle HTML:
# GOOD
def status_label
value.active? ? "Active" : "Inactive"
end
# BAD
def status_badge
"<span class='badge'>#{status_label}</span>"
end| Related Skill | When to chain |
|---|---|
| create-view | Parts are used within Views. Master View structure first. |
| create-action | Actions pass data to Views, which wrap them in Parts. |
| define-entity | Parts often wrap Entity objects returned by Repositories. |
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
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
scenario-27
scenario-28
scenario-29
scenario-30
scenario-31
scenario-32
scenario-33
scenario-34
scenario-35
skills
actions
build-json-api
create-action
handle-errors
validate-params
context
load-context
db
create-changeset
create-repository
define-relation
write-migration
dry-monads
handle-result-pattern
dry-rb
create-operation
create-validation-contract
providers
configure-providers
implement-di
review-security
routing
define-routes
slices
configure-slice
create-slice
extract-slice
review-slice-boundaries
test-slice