ワンクリックで
pyro-maniac
Use this skill when defining or modifying PyroManiac DSL on Ash resources or PyroManiac page modules.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use this skill when defining or modifying PyroManiac DSL on Ash resources or PyroManiac page modules.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | pyro-maniac |
| description | Use this skill when defining or modifying PyroManiac DSL on Ash resources or PyroManiac page modules. |
PyroManiac is a declarative, framework-agnostic UI DSL for Ash Framework
resources. It compiles UI configuration at build time via Spark and exposes
it through PyroManiac.Info for renderers to consume. Rendering itself
lives in separate libraries (e.g. pyro_maniac_live_view); the core
package is render-agnostic by design.
Never import or reference Phoenix/LiveView/Hologram modules from PyroManiac DSL or extension code. Rendering and routing live in renderer libraries — keep the DSL clean.
Spark DSL entity keyword options cannot be passed inline when a do
block is present. The compiler rejects:
view :read, type: :data_table do
column :name
end
Always put the option inside the block:
view :read do
type :data_table
column :name
end
DSL validations belong in transformers, not verifiers. Validation
tests use assert_raise + inline defmodule, which only catches errors
raised during the transformer phase.
The pyro_maniac do default_label :field end block on the resource
is required. A verifier rejects any page whose resource lacks the
PyroManiac.Resource extension.
Page modules are data, not views. Do not define render/1, do not
import Phoenix.Component, do not reference any renderer module.
Resource:
defmodule MyApp.Brewery.Recipe do
use Ash.Resource,
domain: MyApp.Brewery,
extensions: [PyroManiac.Resource]
pyro_maniac do
default_label :name
end
attributes do
uuid_primary_key :id
attribute :name, :string, allow_nil?: false, public?: true
attribute :status, :atom,
constraints: [one_of: ~w[draft active retired]a],
allow_nil?: false,
public?: true,
default: :draft
end
actions do
defaults [:read, :destroy, create: :*, update: :*]
read :list do
prepare build(sort: [:name])
end
end
end
Page module:
defmodule MyAppWeb.RecipeLive do
use PyroManiac, resource: MyApp.Brewery.Recipe
page do
title "Recipes"
end
views do
view :read do
type :data_table
default_sort "name"
column :name
column :status
end
end
end
Navigation (optional, one module per app):
defmodule MyAppWeb.Navigation do
use PyroManiac.Navigation
nav do
group :brewery do
label "Brewery"
icon :beer
item :recipes do
path "/recipes"
page MyAppWeb.RecipeLive
end
end
end
end
page sectiontitle (required string), description, route, default_viewer
(:data_table | :grid | :calendar | :gantt | :kanban | :list,
default :data_table), track_presence? (default true).
Nested entities: tenant_from (singleton, modes :scope/:select/:combobox),
extra_action (custom toolbar/row buttons).
views sectionview :name do ... end — name is one or more action names. Each view
must declare type:. View types and their characteristic entities:
:data_table — interactive table; uses column entities:grid — card grid; uses field, section, relationship:calendar — keyed on date_field (+ optional end_date_field, granularity):gantt — start_field, end_field, optional progress_field/group_by:kanban — group_by, kanban_action, priority:list — optional parent_field for tree, indent_class:render — custom render fn, or component + props + loads:delegated — delegate_to another PyroManiac module (required for this type, forbidden elsewhere)Views are recursive (recursive_as: :views) — nest to drill into
relationships or mount sub-Viewers.
set maps parent record fields into a cross-resource view's read
action when the nested view has an explicit resource: but no
relationship:.
forms sectionSection schema: class, description, exclude, extra_form_types.
action :name do ... end — single-record forms. Schema: class,
description, label, name (required, atom or list), resource
(cross-resource), delegate_to (mutually exclusive with inline fields).
bulk_action :name do ... end — multi-record forms. Adds
set_all_fields? (default false).
Field entities (in action, bulk_action, field_group, or step):
field :name do ... end — type (default :default, extensible via
extra_form_types), label, description, options, prompt,
class, input_class, path, autofocus, form_only?, when
(1-arity predicate), autocomplete keys.field_group "Label" do ... end — recursive; class, path, when.step :name do ... end — wizard steps; label, path, render_fn,
review?, when.set :name, :source — only inside action; cross-resource form
parent → child mapping.searches section (top-level)search :name do ... end — preconfigured filter tabs. Schema:
interactive? (default true), label, operator (:and | :or).
field :name do ... end — operator (default :contains),
source (atom or [atom | [atom]] for OR-across-paths), value,
label.
PyroManiac.Resource (required for any page-backed resource)pyro_maniac do
default_label :name # attribute, calculation, or aggregate
end
A verifier checks that default_label exists on the resource.
PyroManiac.KanBan (optional, for kanban views)kan_ban do
lane :status # required atom — must be enum or `one_of`-constrained
priority :kanban_priority # required atom — integer; auto-created if missing
move_action :move_card # required atom — generated update action
read_action :kanban_read # required atom — generated read action
per_lane 20 # default 20
count? false # default false; `true` adds count queries per lane
end
The transformer auto-generates the priority attribute, move_action,
and read_action if not already present. Pair with a view :read do type :kanban; group_by :status; kanban_action :move_card; priority :kanban_priority to render the board.
use PyroManiac.Navigation declares the app's nav tree. Each item
must have exactly one of page, module, or href. Items with
page/module require path:. Renderers consume the compiled tree
via PyroManiac.Navigation.Info (nav_tree/1, route_manifest/1,
path_for_page/2, etc.) and provide their own routing — this library
does not ship a routes generator.
PyroManiac.Info is the stable runtime API renderers use:
resource/1, default_label/1, loads/1title/1, description/1, route/1, default_viewer/1, track_presence?/1tenant_from/1, page_extra_actions/1, view_extra_actions/1views/1, view_for/3, views_of_type/2, primary_view/2,
view_for_action/2form_actions/1, form_actions_for_resource/2, form_for/2-3,
form_for_action_type/2-3bulk_actions/1, bulk_action_for/2searches/1Companion Info modules: PyroManiac.Resource.Info,
PyroManiac.Navigation.Info, PyroManiac.KanBan.Info.
Do not read persisted Spark keys (:views_by_action_and_type,
:route_manifest, etc.) directly — those are internal.
do blocks (view :read, type: :data_table do ...) — fails to compile.render/1 or importing renderer modules in a page module.PyroManiac.Resource in the resource's extensions: list.default_label pointing at a relationship — renderers cannot stringify it.page/module/href on one nav item — validator rejects.set inside a bulk_action — only valid inside action.type: without listing it in
extra_form_types on the forms section.delegate_to with inline fields/groups/steps on action/
bulk_action — they're mutually exclusive.