CtrlK
BlogDocsLog inGet started
Tessl Logo

igmarin/rails-agent-skills

Curated library of 39 AI agent skills for Ruby on Rails development. Organized by category: planning, testing, code-quality, ddd, engines, infrastructure, api, patterns, context, orchestration, and workflows. Includes 5 callable workflow skills (rails-tdd-loop, rails-review-flow, rails-setup-flow, rails-quality-flow, rails-engines-flow) for complete development cycles. Covers code review, architecture, security, testing (RSpec), engines, service objects, DDD patterns, and TDD automation.

95

1.20x
Quality

98%

Does it follow best practices?

Impact

95%

1.20x

Average score across 35 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

criteria.jsonevals/scenario-12/

{
  "context": "Tests whether the agent follows rails-graphql-best-practices: using dataloaders for association loads, applying field-level auth on sensitive fields, returning structured { result, errors } from mutations, disabling introspection in production, setting query depth/complexity limits, using dedicated resolver classes, connection types for paginated fields, and schema.execute in tests.",
  "type": "weighted_checklist",
  "checklist": [
    {
      "name": "Dataloader for association",
      "description": "ListResolver loads the buyer association through a dataloader (dataloader.with(...).load(...)) rather than calling object.buyer or object.buyer_id directly",
      "max_score": 10
    },
    {
      "name": "Field-level guard on sensitive field",
      "description": "The internal_notes field in Types::OrderType has its own field-level authorization guard (not just relying on type-level auth)",
      "max_score": 10
    },
    {
      "name": "No type-only auth for sensitive field",
      "description": "Types::OrderType does NOT rely solely on a class-level guard — internal_notes has a separate guard block or before_check",
      "max_score": 8
    },
    {
      "name": "Mutation returns errors array",
      "description": "Mutations::PlaceOrder defines a field :errors of array type (e.g. [String]) that is always present in the response",
      "max_score": 10
    },
    {
      "name": "Mutation no unhandled raise",
      "description": "Mutations::PlaceOrder does NOT raise unhandled exceptions to the caller — errors are caught and returned in the errors field",
      "max_score": 8
    },
    {
      "name": "Introspection disabled in production",
      "description": "AppSchema calls disable_introspection_entry_points (conditionally for production environment, or unconditionally)",
      "max_score": 10
    },
    {
      "name": "max_depth set",
      "description": "AppSchema sets max_depth with a numeric value",
      "max_score": 6
    },
    {
      "name": "max_complexity set",
      "description": "AppSchema sets max_complexity with a numeric value",
      "max_score": 6
    },
    {
      "name": "Dedicated resolver class",
      "description": "Orders list resolution is in a dedicated Resolvers::Orders::ListResolver class, not as an inline field block in QueryType",
      "max_score": 8
    },
    {
      "name": "Connection type for paginated list",
      "description": "The orders field (wherever it is defined) uses .connection_type (e.g. Types::OrderType.connection_type) rather than a plain array type",
      "max_score": 8
    },
    {
      "name": "schema.execute in specs",
      "description": "Both spec files use AppSchema.execute(...) to run queries/mutations — not controller dispatch or request specs via HTTP",
      "max_score": 8
    },
    {
      "name": "descriptions on fields",
      "description": "Types::OrderType includes description calls on at least 3 of its fields",
      "max_score": 8
    }
  ]
}

README.md

tile.json