Claude Code Plugins

Community-maintained marketplace

Feedback

Core Ash framework concepts - understanding, structure, data layers, and code generation

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name ash-basics
description Core Ash framework concepts - understanding, structure, data layers, and code generation

Ash Framework Basics

Understanding Ash

Ash is an opinionated, composable framework for building applications in Elixir. It provides a declarative approach to modeling your domain with resources at the center. Read documentation before attempting to use its features. Do not assume that you have prior knowledge of the framework or its conventions.

Code Structure & Organization

  • Organize code around domains and resources
  • Each resource should be focused and well-named
  • Create domain-specific actions rather than generic CRUD operations
  • Put business logic inside actions rather than in external modules
  • Use resources to model your domain entities

Data Layers

Data layers determine how resources are stored and retrieved. Examples of data layers:

  • Postgres: For storing resources in PostgreSQL (via AshPostgres)
  • ETS: For in-memory storage (Ash.DataLayer.Ets)
  • Mnesia: For distributed storage (Ash.DataLayer.Mnesia)
  • Embedded: For resources embedded in other resources (data_layer: :embedded) (typically JSON under the hood)
  • Ash.DataLayer.Simple: For resources that aren't persisted at all. Leave off the data layer, as this is the default.

Specify a data layer when defining a resource:

defmodule MyApp.Post do
  use Ash.Resource,
    domain: MyApp.Blog,
    data_layer: AshPostgres.DataLayer

  postgres do
    table "posts"
    repo MyApp.Repo
  end

  # ... attributes, relationships, etc.
end

For embedded resources:

defmodule MyApp.Address do
  use Ash.Resource,
    data_layer: :embedded

  attributes do
    attribute :street, :string
    attribute :city, :string
    attribute :state, :string
    attribute :zip, :string
  end
end

Each data layer has its own configuration options and capabilities. Refer to the rules & documentation of the specific data layer package for more details.

Generating Code

Use mix ash.gen.* tasks as a basis for code generation when possible. Check the task docs with mix help <task>. Be sure to use --yes to bypass confirmation prompts. Use --yes --dry-run to preview the changes.

Migrations and Schema Changes

After creating or modifying Ash code, run mix ash.codegen <short_name_describing_changes> to ensure any required additional changes are made (like migrations are generated). The name of the migration should be lower_snake_case. In a longer running dev session it's usually better to use mix ash.codegen --dev as you go and at the end run the final codegen with a sensible name describing all the changes made in the session.

UUID Primary Keys (UUID v7)

This project is configured to use UUID v7 for all primary keys by default. UUID v7 provides time-ordered, incremental UUIDs that offer better database index performance compared to random UUID v4.

Configuration

The repo is configured in lib/clientt_crm_app/repo.ex with:

@impl true
def uuid_v7_primary_key? do
  true
end

This ensures all resources using uuid_primary_key :id will automatically generate UUIDs using the uuid_generate_v7() PostgreSQL function.

UUID v7 Function

The uuid_generate_v7() function is installed via database migrations and is compatible with PostgreSQL 13+. It's fully backwards compatible with PostgreSQL 17.

Benefits of UUID v7

  • Time-ordered: UUIDs are sortable by creation time
  • Better index performance: Sequential IDs reduce B-tree fragmentation
  • Distributed-friendly: Can generate IDs across multiple servers without collisions
  • Compatible: Standard UUID type, works with all PostgreSQL tooling

Usage in Resources

When defining resources, use uuid_primary_key :id as normal:

defmodule MyApp.MyDomain.MyResource do
  use Ash.Resource,
    domain: MyApp.MyDomain,
    data_layer: AshPostgres.DataLayer

  postgres do
    table "my_table"
    repo MyApp.Repo
  end

  attributes do
    uuid_primary_key :id  # Automatically uses UUID v7
    # ... other attributes
  end
end

The migration generator will automatically use uuid_generate_v7() for the default value.