ivy-interactive/ivy-framework/ivy-create-crud

Claude Code and agent skill by ivy-interactive/ivy-framework

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Create a CRUD app with list, detail, create, and edit views for an Ivy project. Use when the user asks for CRUD views, master-detail views, data management screens, entity management, or wants to build views for database tables. Handles blades, dialogs, sheets, foreign key lookups, search, pagination, parent-child relationships, and async select inputs.

Install

npx vskill@latest install ivy-interactive/ivy-framework/ivy-create-crud

SKILL.md

ivy-create-crud

Create a CRUD app with list, detail, create, and edit views for an Ivy project.

Pre-flight: Read Learnings

If the file .ivy/learnings/ivy-create-crud.md exists in the project directory, read it first and apply any lessons learned from previous runs of this skill.

Reference Files

Read these before implementing:

Workflow

This skill guides you through creating complete CRUD applications:

  1. Plan - Analyze the data models and propose CRUD views for selected entities
  2. Review - Present the plan for user approval (accept / request changes / cancel)
  3. Implement - Generate all CRUD files following reference patterns, one entity at a time

Step 1: Plan the CRUD App

If the user has specified a database connection, read the connection context using ivy cli explain connections/{ConnectionName}. If not, ask the user which connection to use.

Ask the user which entities they want CRUD views for (suggest all top-level entities as options).

For each selected entity, determine:

  • Singular name and plural name
  • Lucide icon (PascalCase, e.g. ShoppingBag, Users, FileText)
  • Whether it is a top-level entity (gets its own App with list/details/create/edit) or a child entity (shown as a relationship blade on a parent's details view)
  • Child entities are those that primarily exist as children of another entity via a required foreign key (e.g., OrderLines belong to Orders)

Detect one-to-many relationships from navigation properties and foreign keys:

  • A parent entity's details blade should show a related card linking to child blades
  • Child entities get: RelationshipBlade (table view), RelationshipCreateDialog, RelationshipEditSheet
Plan Format
# Plan
## Create App: [PluralName]
**Namespace**: `{ProjectNamespace}.Apps`
**Connection**: `[ConnectionName]`
**Entity**: `[SingularName]`
**Icon**: `[LucideIcon]`
**Group**: `Apps`
**Layout**: `Blades`
**Files**: `Apps\[PluralName]App.cs`
Opens [Singular]ListBlade.
### Create View: [Singular]ListBlade
**Files**: `Apps\[PluralName]\[Singular]ListBlade.cs`
**Namespace**: `{ProjectNamespace}.Apps.[PluralName]`
List view with search. Shows [key fields]. Click opens [Singular]DetailsBlade. Create button opens [Singular]CreateDialog.
### Create View: [Singular]DetailsBlade
**Files**: `Apps\[PluralName]\[Singular]DetailsBlade.cs`
**Namespace**: `{ProjectNamespace}.Apps.[PluralName]`
Detail view showing [interesting fields]. Edit button opens [Singular]EditSheet. Delete button with confirmation.
[If has children: Related card with links to child blades with count badges.]
### Create View: [Singular]CreateDialog
**Files**: `Apps\[PluralName]\[Singular]CreateDialog.cs`
**Namespace**: `{ProjectNamespace}.Apps.[PluralName]`
Create dialog with required fields. [List the fields.]
### Create View: [Singular]EditSheet
**Files**: `Apps\[PluralName]\[Singular]EditSheet.cs`
**Namespace**: `{ProjectNamespace}.Apps.[PluralName]`
Edit sheet with all editable fields. Removes Id, CreatedAt, UpdatedAt. [List notable field customizations.]
### Create Relationship View: [ParentSingular][ChildPlural]Blade
**Files**: `Apps\[PluralName]\[ParentSingular][ChildPlural]Blade.cs`
**Namespace**: `{ProjectNamespace}.Apps.[PluralName]`
Table view of [ChildPlural] for a given [ParentSingular]. Shows [key columns]. Add button opens [ParentSingular][ChildPlural]CreateDialog.
### Create Relationship View: [ParentSingular][ChildPlural]CreateDialog
**Files**: `Apps\[PluralName]\[ParentSingular][ChildPlural]CreateDialog.cs`
**Namespace**: `{ProjectNamespace}.Apps.[PluralName]`
Create dialog for adding a [ChildSingular] to a [ParentSingular]. Parent ID passed via constructor.
### Create Relationship View: [ParentSingular][ChildPlural]EditSheet
**Files**: `Apps\[PluralName]\[ParentSingular][ChildPlural]EditSheet.cs`
**Namespace**: `{ProjectNamespace}.Apps.[PluralName]`
Edit sheet for a [ChildSingular]. Takes child entity ID as parameter.

Repeat the ## Create App block for each top-level entity selected.

Chrome Decision
  • If the plan has only one `## Create App` block (single entity) and no multi-app navigation needs, add a ### Update Program.cs section that replaces server.UseAppShell(...) with server.UseDefaultApp(typeof(TheAppClass));.
  • If the plan has multiple `## Create App` blocks or the user explicitly wants sidebar navigation, add a ### Update Program.cs section that ensures server.UseAppShell(new AppShellSettings().DefaultApp<FirstAppClass>().UseTabs(preventDuplicates: true)); is present.

Present the plan to the user and ask them to Accept, Request Changes, or Cancel.

Step 2: Handle Changes

If the user requests changes, apply them to the plan and present the updated plan again.

Step 3: Implement

Once approved, implement each entity's views in order.

Namespace Conventions
  • App files ([PluralName]App.cs): namespace {ProjectNamespace}.Apps;
  • View files (all blades, dialogs, sheets): namespace {ProjectNamespace}.Apps.[PluralName];
Required Using Directives

Every generated .cs file must include explicit using statements. Do NOT rely on global usings.

Connection usings (when using a database connection):

  • using {ProjectNamespace}.Connections.{ConnectionName}; -- for context factory
  • using {ProjectNamespace}.Connections.{ConnectionName}.Models; -- for entity classes (only if project uses a Models subfolder)
  • using Microsoft.EntityFrameworkCore; -- for ToListAsync, FirstOrDefaultAsync, Include, etc.

Common Ivy usings by view type:

View TypeRequired Namespaces
All viewsIvy, Ivy.Core.Hooks, Ivy.Hooks, Ivy.Shared, Ivy.Views
App entry point+ Ivy.Apps
Blades+ Ivy.Views.Blades
Details views+ Ivy.Views.Builders
Forms (dialogs, sheets)+ Ivy.Views.Forms, System.ComponentModel.DataAnnotations
Tables+ Ivy.Views.Tables
Alerts/Callouts+ Ivy.Views.Alerts
Async select inputs+ Ivy.Widgets.Inputs

Include only the namespaces your file actually uses.

Data Access Pattern

Always use the context factory pattern:

csharp
var factory = UseService<{ConnectionName}ContextFactory>();
await using var db = factory.CreateDbContext();
Program.cs Chrome Configuration

Check if the approved plan includes a ### Update Program.cs section. If it does:

  • If it specifies UseDefaultApp: Open Program.cs and replace the server.UseAppShell(...) line with server.UseDefaultApp(typeof(AppClassName));. Remove the UseAppShell line entirely.
  • If it specifies UseAppShell: Ensure server.UseAppShell(new AppShellSettings().DefaultApp<AppClassName>().UseTabs(preventDuplicates: true)); is present in Program.cs.
  • Follow the approved plan exactly.
Per-View-Type Instructions
App ([PluralName]App.cs)
csharp
using {ProjectNamespace}.Apps.[PluralName];
namespace {ProjectNamespace}.Apps;
[App(icon: Icons.[Icon], group: ["[Group]"])]
public class [PluralName]App : ViewBase
{
public override object? Build()
{
return UseBlades(() => new [Singular]ListBlade(), "Search");
}
}
ListBlade ([Singular]ListBlade.cs)
  • Define a private record [Singular]ListRecord(int Id, ...) with the key display fields. For FK properties (e.g., `CustomerId`, `PartnerId`), do NOT include the raw ID. Instead, include a resolved name field (e.g., `string? CustomerName`) and project it via the navigation property in the `.Select()`.
  • Use UseRefreshToken() for create/edit refresh flow.
  • UseEffect on refreshToken to pop, revalidate, and push to DetailsBlade.
  • onItemClicked pushes [Singular]DetailsBlade(id).
  • Create button: Icons.Plus.ToButton(...).Ghost().Tooltip("Create [Singular]").ToTrigger(isOpen => new [Singular]CreateDialog(isOpen, refreshToken)).
  • Two UseQuery methods: Use[Singular]ListRecords (filtered list) and Use[Singular]ListRecord (single item for FuncView).
  • List query: filter with .Where(), order by .OrderByDescending(e => e.CreatedAt), .Take(50), tags: [typeof([Entity][])].
  • Single item query: RevalidateOnMount = false, initialValue: record, tags: [(typeof([Entity]), record.Id)].
  • Search input + create button in a horizontal header layout.
  • If entity has FK properties, ALWAYS .Include() the navigation property and project the human-readable name into the record -- NEVER expose raw FK IDs as display columns. Explicitly type as IQueryable<Entity> to avoid IIncludableQueryable type issues.
DetailsBlade ([Singular]DetailsBlade.cs)
  • Constructor: (int [entityCamelCase]Id).
  • Query the entity with .Include() for navigation properties.
  • Show loading skeleton: if (query.Loading) return Skeleton.Card();
  • Show not found callout if null.
  • Delete button with .WithConfirm(), pops and revalidates typeof([Entity][]).
  • Edit button with .ToTrigger(isOpen => new [Singular]EditSheet(isOpen, [entityCamelCase]Id)).
  • Details card using anonymous type .ToDetails().RemoveEmpty().Builder(e => e.Id, e => e.CopyToClipboard()).
  • Only include "interesting" fields. Exclude CreatedAt, UpdatedAt.
  • If entity has one-to-many children: add a related card with ListItem entries that push child blades with count badges.
CreateDialog ([Singular]CreateDialog.cs)
  • Constructor: (IState<bool> isOpen, RefreshToken refreshToken).
  • Define a private record [Singular]CreateRequest with [Required] attributes on required nullable fields (string, int?, Guid?, etc.). Do NOT add [Required] on non-nullable value types (int, decimal, DateTime, bool, etc.).
  • CRITICAL: CreateRequest MUST NEVER include these auto-managed fields:
  • Id -- auto-generated by the database
  • CreatedAt -- set in OnSubmit: CreatedAt = DateTime.UtcNow
  • UpdatedAt -- set in OnSubmit: UpdatedAt = DateTime.UtcNow
  • Any other auto-increment or computed fields
  • Use the SAME types as in the target entity to avoid type mismatches.
  • UseState(() => new [Singular]CreateRequest()).
  • .ToForm().OnSubmit(OnSubmit).ToDialog(isOpen, title: "Create [Singular]", submitTitle: "Create").
  • Use .Builder(e => e.ForeignKeyId, e => e.ToAsyncSelectInput(...)) for foreign key fields.
  • OnSubmit creates entity, sets CreatedAt/UpdatedAt if they exist, saves, returns ID via refreshToken.Refresh(id).

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/ivy-interactive/ivy-framework/ivy-create-crud/badge)](https://verified-skill.com/skills/ivy-interactive/ivy-framework/ivy-create-crud)

Something wrong with this skill or its page? Tell us.