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 defining ROM Structs and Entities in Hanami 2.x.
Create the Entity file in the app or slice:
# app/entities/user.rb
# frozen_string_literal: true
module MyApp
module Entities
class User < Hanami::DB::Entity
attribute :id, Types::Integer
attribute :email, Types::String
attribute :first_name, Types::String
attribute :last_name, Types::String
attribute :role, Types::String.default("member")
attribute :created_at, Types::Time
end
end
endApply dry-types coercion and constraints: Specify attribute types using standard dry-types constraints. For a comprehensive list of type modifiers, constraints, and defaults, see TYPES.md.
attribute :email, Types::String.constrained(format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.\w+\z/)
attribute :role, Types::String.default("member")Entities are immutable:
Entities cannot be mutated in place. Use #copy to return a new instance with updated attributes:
updated_user = user.copy(first_name: "Alicia")Equality is value-based: Two entity instances with identical attributes are considered equivalent:
user1 == user2 # => true if attributes matchRegister the Entity namespace in Repositories: Wired repositories require mapping directives to output typed Entity classes rather than generic ROM structs:
class UserRepo < Hanami::DB::Repo[:users]
struct_namespace MyApp::Entities
auto_struct true
endSync Entities with migrations: Keep entity class attributes manually updated with database schema modifications. Verify using the Hanami console or spec suite:
bundle exec hanami console
# check MyApp::App[:user_repo].users.first.class.attributes| Mistake | Resolution |
|---|---|
Attempting in-place mutations (user.name = "new") | Entities are frozen. Always use user.copy(name: "new"). |
| Out of sync migrations | Stale attributes cause UnknownAttributeError. Sync entity attributes with database migrations. |
| Putting business logic inside Entities | Entities are pure data structs. Place logic in domain services or actions. |
Omitting struct_namespace configuration | Omitting this returns generic ROM::Struct objects instead of your custom Entity class. |
Missing .optional on nullable fields | Null database columns require Types::String.optional to prevent boot/coercion type errors. |
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