CtrlK
BlogDocsLog inGet started
Tessl Logo

igmarin/hanakai-yaku

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

1.33x
Quality

94%

Does it follow best practices?

Impact

92%

1.33x

Average score across 35 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

SKILL.mdskills/dry-rb/create-validation-contract/

name:
create-validation-contract
license:
MIT
description:
Creates a dry-validation contract for type-safe input validation in Hanami actions and operations. Covers schema definition, custom predicates, error messages, and contract composition. Use when validating request params, operation input, or any structured data. Trigger words: validation, contract, dry-validation, params, schema, Dry::Validation::Contract, validate input, type-safe, custom predicate.
metadata:
{"version":"1.0.0","user-invocable":"true"}

Creating a Validation Contract

Define type-safe, composable validation rules with dry-validation contracts.

Quick Reference

  • Location: slices/<slice>/contracts/ or inline in the operation.
  • Structure: Dry::Validation::Contract with schema and rule blocks.
  • Usage: contract.call(params) returns a result with .success? and .errors.
  • Rule: Every operation that accepts user input uses a contract.

HARD-GATE

Write test → Run test → Verify it FAILS → Implement → Verify it PASSES
DO NOT use raw hashes as operation input. Validate through a contract first.
DO NOT put validation logic in actions. Contracts are the single source of validation.

Core Process

Pattern reference: See CONTRACT_PATTERNS.md for examples of custom predicates, nested schemas, composed contracts, and testing patterns.

  1. Define the contract — declare expected fields, types, and rules:
    module Users
      class CreateContract < Dry::Validation::Contract
        schema do
          required(:email).filled(:string)
          required(:name).filled(:string, min_size?: 2)
          optional(:role).filled(:string, included_in?: %w[admin member])
        end
    
        rule(:email) do
          key.failure("must be a valid email") unless value.match?(URI::MailTo::EMAIL_REGEXP)
        end
      end
    end
  2. Use in the operation — call the contract as the first step:
    def validate(input)
      result = CreateContract.new.call(input)
      result.success? ? Success(result.to_h) : Failure(result.errors.to_h)
    end
  3. Custom predicates and composed contracts — for reusable validation rules and shared fields (e.g., pagination params). If a CONTRACT_PATTERNS.md companion file is present in the bundle, consult it for executable examples of custom predicates, composed contracts, i18n error messages, and nested schemas.
  4. Test the contract — verify valid and invalid inputs independently from the operation:
    RSpec.describe Users::CreateContract do
      subject(:contract) { described_class.new }
    
      context "with valid input" do
        it "succeeds" do
          result = contract.call(email: "user@example.com", name: "Alice")
          expect(result).to be_success
          expect(result.to_h).to include(email: "user@example.com", name: "Alice")
        end
      end
    
      context "with invalid input" do
        it "fails with email error" do
          result = contract.call(email: "not-an-email", name: "Alice")
          expect(result).to be_failure
          expect(result.errors[:email]).to include("must be a valid email")
        end
    
        it "fails when name is too short" do
          result = contract.call(email: "user@example.com", name: "A")
          expect(result).to be_failure
          expect(result.errors[:name]).to be_present
        end
      end
    end

Output Style

  1. Contract class — complete schema and rule definitions.
  2. Operation integration — how the operation uses the contract.
  3. Spec — test valid inputs (Success) and invalid inputs (Failure with specific errors).
  4. English only unless user requests otherwise.

Integration

SkillWhen to chain
create-operationAfter defining the contract, use it as the first step of the operation
create-actionContracts validate action params before they reach the operation

skills

dry-rb

create-validation-contract

README.md

tile.json