Agent skill

Curd

by JaguarJack in JaguarJack/catch-admin

Generates complete CRUD module from database table definition.

Apache-2.0Auto-check passedDocuments & Office

Install Curd

skills CLI
$ npx skills add JaguarJack/catch-admin --skill curd -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install JaguarJack/catch-admin curd --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/JaguarJack/catch-admin.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/curd .claude/skills/curd && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
curd
GitHub stars
935
Token cost
~3.3k tokens
SKILL.md length
305 words
Files
1
Skills in repo
10
Repo updated
First seen
Licence
Apache-2.0

At a glance

Generates complete CRUD module from database table definition.

  • Works in 9 steps: Parse Table Definition → 01-parse-table → Generate Migration → 02-migration → Generate Model → 03-model → …
  • User says create CRUD
  • SKILL.md covers Sub-Skills (9 个子 Skills), Input: Table Definition, Output: Complete Module… and Pre-checks (执行前), plus 7 more sections
  • Calls php

What it does

Curd is an agent skill from JaguarJack/catch-admin. Generates complete CRUD module from database table definition. Orchestrates 9 sub-skills. Use when user says "create CRUD", "generate module from table", or provides a table structure.

Its SKILL.md is about 3.3k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Documents & Office. It works with PHP, Vue.js and Laravel. The repository describes itself as: CatchAdmin 是一个功能强大、易于扩展的现代化 PHP 后台管理系统。它采用前后端分离架构,CatchAdmin 集成了 Token 鉴权、权限管理、动态路由、动态表格、分页封装、资源权限、上传下载、代码生成器支持一键导出导入,数据回收站,附件管理的等等一系列实用的开发功能的模块化框架。官网地址:. The licence is Apache-2.0.

When your agent uses it

  • User says create CRUD
  • Generate module from table
  • Provides a table structure

Example prompts

  • “create CRUD”
  • “generate module from table”
  • “Use the curd skill to generate complete CRUD module from database table definition”
  • “/curd”

Workflow steps

9 steps, taken from the step headings in SKILL.md.

  1. Parse Table Definition → 01-parse-table
  2. Generate Migration → 02-migration
  3. Generate Model → 03-model
  4. Generate Controller → 04-controller
  5. Generate Request → 05-request
  6. Generate Routes → 06-routes
  7. Generate Export → 07-export
  8. Generate Import → 08-import
  9. Generate Vue Pages → 09-vue-pages

What it can do on your machine

Read from SKILL.md and the folder at commit e83d5aa. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • php

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Curd loads about 3.3k tokens when it runs. Until then it costs about 47 tokens; SKILL.md has 305 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~47
When it runs · the whole SKILL.md, loaded when a task matches
~3.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from JaguarJack/catch-admin at commit e83d5aa, republished under its Apache-2.0 licence (© JaguarJack). 305 words, ~3,333 tokens.

Download SKILL.mdSave it as .claude/skills/curd/SKILL.md (or your agent's skills folder).
name
curd
description
Generates complete CRUD module from database table definition. Orchestrates 9 sub-skills. Use when user says "create CRUD", "generate module from table", or provides a table structure.
globs
modules/**/*.php, web/src/views/**/*.vue

CatchAdmin CRUD Generator

一键生成完整 CRUD 模块 - 从数据表定义到前后端完整实现。

Sub-Skills (9 个子 Skills)

StepSkill生成文件
101-parse-table- (解析输入)
202-migrationdatabase/migrations/*.php
303-modelModels/{Model}.php
404-controllerHttp/Controllers/{Model}Controller.php
505-requestHttp/Requests/{Model}Request.php
606-routesroutes/route.php
707-exportExport/{Model}.php
808-importImport/{Model}.php
909-vue-pagesindex.vue + create.vue

Input: Table Definition

Table: products
Fields:
- id (primary key)
- name (string, 100, required)
- category_id (foreign key -> categories)
- description (text, nullable)
- price (decimal 10,2, required)
- stock (integer, default 0)
- status (tinyint, default 1)

Output: Complete Module Structure

modules/{Module}/
├── Http/
│   ├── Controllers/{Model}Controller.php
│   └── Requests/{Model}Request.php
├── Models/{Model}.php
├── Export/{Model}.php
├── Import/{Model}.php
├── database/migrations/*.php
└── routes/route.php

web/src/views/{module}/
├── index.vue
└── create.vue

Pre-checks (执行前)

  • 模块存在性:若 modules/{Module} 不存在,先询问是否创建新模块。
  • 文件冲突:目标文件已存在时,先询问覆盖或增量修改。
  • 路由/权限前缀:检查 modules/{Module}/routes/route.php 是否已有相同资源前缀。
  • 依赖/配置:新增依赖或改动 config/ 前必须先询问。

Output Contract (输出契约)

  • 必须生成 9 步完整产物(迁移/模型/控制器/请求/路由/导入导出/前端页)。
  • 所有路径、类名、命名空间与 {Module}/{Model}/{table} 一致。
  • 前端 catch-table 的 api 与后端路由前缀保持一致。

Consistency Validation (生成后校验)

  • 迁移包含 CatchAdmin 标准字段:creator_id/created_at/updated_at/deleted_at + 索引。
  • Model/Request 与迁移字段一致(类型/必填/默认值)。
  • Route API 前缀与前端 api/permission 前缀一致。

Fallback Rules (失败兜底)

  • 输入缺失关键字段(如 table/fields)时必须先澄清,停止生成。
  • 复杂关系或非标准业务逻辑需用户确认后再生成。

Workflow

Step 1: Parse Table Definition → 01-parse-table

Extract from user input:

  • Table name (snake_case plural)
  • Model name (PascalCase singular)
  • Module name (PascalCase)
  • Fields with types, constraints, and relationships
Step 2: Generate Migration → 02-migration
php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('{table}', function (Blueprint $table) {
            $table->id();
            
            // Generated from field definitions
            $table->string('name', 100);
            $table->unsignedBigInteger('category_id')->default(0)->index();
            $table->text('description')->nullable();
            $table->decimal('price', 10, 2);
            $table->unsignedInteger('stock')->default(0);
            $table->string('image', 255)->nullable();
            $table->tinyInteger('status')->default(1);
            $table->unsignedInteger('sort')->default(0);
            
            // CatchAdmin standard fields
            $table->unsignedInteger('creator_id')->default(0);
            $table->unsignedInteger('created_at')->default(0);
            $table->unsignedInteger('updated_at')->default(0);
            $table->unsignedInteger('deleted_at')->default(0);
            
            $table->index(['status', 'deleted_at']);
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('{table}');
    }
};
Step 3: Generate Model → 03-model
php
<?php

namespace Modules\{Module}\Models;

use Catch\Base\CatchModel as Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class {Model} extends Model
{
    protected $table = '{table}';

    protected $fillable = [
        'id', 'name', 'category_id', 'description', 'price', 'stock',
        'image', 'status', 'sort', 'creator_id', 'created_at', 'updated_at', 'deleted_at',
    ];

    public array $searchable = [
        'name' => 'like',
        'category_id' => '=',
        'status' => '=',
    ];

    protected array $fields = [
        'id', 'name', 'category_id', 'price', 'stock', 'status', 'created_at'
    ];

    protected array $form = [
        'name', 'category_id', 'description', 'price', 'stock', 'image', 'status', 'sort'
    ];

    // Relationships (auto-detected from foreign keys)
    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class, 'category_id');
    }
}
Step 4: Generate Controller → 04-controller
php
<?php

namespace Modules\{Module}\Http\Controllers;

use Catch\Base\CatchController as Controller;
use Modules\{Module}\Http\Requests\{Model}Request;
use Modules\{Module}\Models\{Model};
use Modules\{Module}\Import\{Model} as {Model}Import;
use Illuminate\Http\Request;

class {Model}Controller extends Controller
{
    public function __construct(
        protected readonly {Model} $model
    ) {}

    public function index()
    {
        return $this->model->getList();
    }

    public function store({Model}Request $request)
    {
        return $this->model->storeBy($request->all());
    }

    public function show($id): mixed
    {
        return $this->model->firstBy($id);
    }

    public function update($id, {Model}Request $request): mixed
    {
        return $this->model->updateBy($id, $request->all());
    }

    public function destroy($id)
    {
        return $this->model->deleteBy($id);
    }

    public function enable($id)
    {
        return $this->model->toggleBy($id);
    }

    public function export(): mixed
    {
        return {Model}::query()
            ->select('id', 'name', 'price', 'stock', 'created_at')
            ->get()
            ->download(['ID', 'Name', 'Price', 'Stock', 'Created At']);
    }

    public function import(Request $request, {Model}Import $import)
    {
        return $import->import($request->file('file'));
    }
}
Step 5: Generate Request → 05-request
php
<?php

namespace Modules\{Module}\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class {Model}Request extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            // Auto-generated from field definitions
            'name' => 'required|string|max:100',
            'category_id' => 'required|integer|exists:categories,id',
            'description' => 'nullable|string',
            'price' => 'required|numeric|min:0',
            'stock' => 'sometimes|integer|min:0',
            'image' => 'nullable|string|max:255',
            'status' => 'sometimes|integer|in:1,2',
            'sort' => 'sometimes|integer|min:0',
        ];
    }
}
Step 6: Generate Routes → 06-routes
php
<?php

use Illuminate\Support\Facades\Route;
use Modules\{Module}\Http\Controllers\{Model}Controller;

Route::apiResource('{resources}', {Model}Controller::class);
Route::put('{resources}/enable/{id}', [{Model}Controller::class, 'enable']);
Route::get('{resource}/export', [{Model}Controller::class, 'export']);
Route::post('{resource}/import', [{Model}Controller::class, 'import']);
Step 7: Generate Export → 07-export
php
<?php

namespace Modules\{Module}\Export;

use Catch\Support\Excel\Export;

class {Model} extends Export
{
    protected array $header = ['ID', 'Name', 'Price', 'Stock', 'Created At'];

    public function array(): array
    {
        return \Modules\{Module}\Models\{Model}::query()
            ->select('id', 'name', 'price', 'stock', 'created_at')
            ->get()
            ->toArray();
    }
}
Step 8: Generate Import → 08-import
php
<?php

namespace Modules\{Module}\Import;

use Catch\Support\Excel\Import;
use Illuminate\Support\Collection;
use Modules\{Module}\Models\{Model};

class {Model}Import extends Import
{
    public function collection(Collection $rows): void
    {
        $rows->skip(1)->each(function ($row) {
            {Model}::create([
                'name' => $row[0],
                'price' => $row[1],
                'stock' => $row[2],
            ]);
        });
    }
}
Step 9: Generate Vue Pages → 09-vue-pages

index.vue:

vue
<template>
  <div>
    <catch-table
      :columns="columns"
      api="{module}/{resources}"
      :exports="true"
      :trash="true"
      permission="{module}.{model}"
      exportUrl="/{module}/export"
      importUrl="/{module}/import"
      :search-form="searchForm"
    >
      <template #dialog="row">
        <Create :primary="row?.id" api="{module}/{resources}" />
      </template>
    </catch-table>
  </div>
</template>

<script lang="ts" setup>
import Create from './create.vue'

const columns = [
  { type: 'selection' },
  { label: 'ID', prop: 'id', width: 80 },
  { label: 'Name', prop: 'name' },
  { label: 'Category', prop: 'category.name' },
  { label: 'Price', prop: 'price', width: 100 },
  { label: 'Stock', prop: 'stock', width: 80 },
  { label: 'Status', prop: 'status', switch: true, width: 80 },
  { label: 'Created At', prop: 'created_at', width: 180 },
  { type: 'operate', label: 'Actions', width: 150, update: true, destroy: true }
]

const searchForm = [
  { type: 'input', label: 'Name', name: 'name' },
  { type: 'select', label: 'Category', name: 'category_id', api: 'categories' },
  { type: 'select', label: 'Status', name: 'status', api: 'status' }
]
</script>

create.vue:

vue
<template>
  <el-form :model="formData" label-width="100px" ref="form" v-loading="loading">
    <el-form-item label="Name" prop="name" :rules="[{ required: true, message: 'Required' }]">
      <el-input v-model="formData.name" maxlength="100" />
    </el-form-item>
    <el-form-item label="Category" prop="category_id" :rules="[{ required: true, message: 'Required' }]">
      <el-select v-model="formData.category_id" class="w-full">
        <el-option v-for="item in categories" :key="item.id" :label="item.name" :value="item.id" />
      </el-select>
    </el-form-item>
    <el-form-item label="Price" prop="price" :rules="[{ required: true, message: 'Required' }]">
      <el-input-number v-model="formData.price" :precision="2" :min="0" class="w-full" />
    </el-form-item>
    <el-form-item label="Stock" prop="stock">
      <el-input-number v-model="formData.stock" :min="0" class="w-full" />
    </el-form-item>
    <el-form-item label="Description" prop="description">
      <el-input v-model="formData.description" type="textarea" :rows="3" />
    </el-form-item>
    <el-form-item label="Status" prop="status">
      <el-radio-group v-model="formData.status">
        <el-radio :value="1">Active</el-radio>
        <el-radio :value="2">Inactive</el-radio>
      </el-radio-group>
    </el-form-item>
    <div class="flex justify-end">
      <el-button type="primary" @click="submitForm(form)">Submit</el-button>
    </div>
  </el-form>
</template>

<script lang="ts" setup>
import { inject, onMounted, ref } from 'vue'
import { useCreate } from '@/composables/curd/useCreate'
import { useShow } from '@/composables/curd/useShow'
import http from '@/support/http'

const props = defineProps<{ primary?: string | number; api: string }>()
const { formData, form, loading, submitForm, close } = useCreate(props.api, props.primary)
if (props.primary) useShow(props.api, props.primary, formData)

const closeDialog = inject('closeDialog')
const categories = ref([])

onMounted(async () => {
  close(() => closeDialog?.())
  const res = await http.get('categories')
  categories.value = res.data.data
})
</script>

Field Type Mapping

Input TypeMigrationModelValidationVue Component
string(n)string('x', n)fillable`stringmax:n`
texttext('x')fillablestringel-input type="textarea"
integerunsignedInteger('x')fillable`integermin:0`
decimal(m,n)decimal('x', m, n)fillablenumericel-input-number :precision="n"
booleantinyInteger('x')fillable`integerin:1,2`
foreign_keyunsignedBigInteger('x')belongsToexists:table,idel-select
datedate('x')fillabledateel-date-picker
datetimedateTime('x')fillabledateel-date-picker type="datetime"
jsonjson('x')$casts['x'] = 'array'arrayCustom

Execution Checklist

When generating a complete CRUD:

  • Step 1: Parse table definition
  • Step 2: Create migration file
  • Step 3: Create model
  • Step 4: Create controller
  • Step 5: Create request validation
  • Step 6: Create routes
  • Step 7: Create export class
  • Step 8: Create import class
  • Step 9: Create Vue pages
  • Run php artisan migrate

Boundaries

  • ✅ Always: Generate all files, follow CatchAdmin conventions
  • ⚠️ Ask first: Complex relationships, custom business logic
  • 🚫 Never: Skip validation, ignore foreign key constraints

© JaguarJack, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/curd of JaguarJack/catch-admin.

Open the folder on GitHubat commit e83d5aa

Compare with similar skills

Curd next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Curd compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Curd this skillJaguarJack/catch-admin935—~3.3kAutomated safety check: PassApache-2.0
Livewire Developmentcoollabsio/coolify63k—~964Automated safety check: PassMIT
Livewire Developmentyungifez/skuul4091 repos~1.9kAutomated safety check: PassMIT
Configure Nightwatchtrypostit/trypost685—~2.7kAutomated safety check: PassMIT
Passport Developmenttrypostit/trypost685—~1.9kAutomated safety check: PassMIT
Spa Auth Developmentgdarko/laravel-vue-starter145—~668Automated safety check: NotesMIT

Similar skills

  • Livewire Development

    coollabsio/coolify

    A skill your agent uses for any task or question involving Livewire.

    63k GitHub stars~964 tokensUpdated today
    Backend & APIsAuto-check passed
  • Livewire Development

    yungifez/skuul

    A skill your agent uses for any task or question involving Livewire.

    409 GitHub starsUsed in 1 repo~1.9k tokens
    Backend & APIsAuto-check passed
  • Configure Nightwatch

    trypostit/trypost

    Configures Laravel Nightwatch data collection, sampling rates, filtering rules, and redaction policies.

    685 GitHub stars~2.7k tokensUpdated today
    Backend & APIsAuto-check passed
  • Passport Development

    trypostit/trypost

    Develops OAuth2 API authentication with Laravel Passport. An agent skill from trypostit/trypost.

    685 GitHub stars~1.9k tokensUpdated today
    Backend & APIsAuto-check passed
  • Spa Auth Development

    gdarko/laravel-vue-starter

    Activate when working on SPA authentication flow, Sanctum cookie-based auth, Vue Router guards, auth store, login/register/password reset pages, or CORS/session configuration.

    145 GitHub stars~668 tokensUpdated 6 mo ago
    Backend & APIsAuto-check: notes
  • Spatie Guidelines

    freekmurze/dotfiles

    Spatie's PHP, Laravel, JavaScript and Vue coding guidelines and conventions.

    1k GitHub stars~2.7k tokensUpdated yesterday
    Backend & APIsAuto-check passed

More from JaguarJack/catch-admin

All 10 skills in this repo
  • Controller

    JaguarJack/catch-admin

    Generate CRUD controller for CatchAdmin module. An agent skill from JaguarJack/catch-admin.

    935 GitHub stars~523 tokensUpdated 23 days ago
    Auto-check passed
  • Migration

    JaguarJack/catch-admin

    Generate database migration file for CatchAdmin module. An agent skill from JaguarJack/catch-admin.

    935 GitHub stars~474 tokensUpdated 23 days ago
    Auto-check passed
  • Model

    JaguarJack/catch-admin

    Generate Eloquent model for CatchAdmin module with full CatchModel features.

    935 GitHub stars~1.7k tokensUpdated 23 days ago
    Auto-check passed
  • Parse Table

    JaguarJack/catch-admin

    Parse table definition to extract module name, model name, table name, and field definitions.

    935 GitHub stars~520 tokensUpdated 23 days ago
    Auto-check passed
  • Vue Pages

    JaguarJack/catch-admin

    Generate Vue frontend pages using catch-table for CatchAdmin module with full component features.

    935 GitHub stars~2.6k tokensUpdated 23 days ago
    Auto-check passed
  • Export

    JaguarJack/catch-admin

    Generate Excel export class for CatchAdmin module. An agent skill from JaguarJack/catch-admin.

    935 GitHub stars~321 tokensUpdated 23 days ago
    Auto-check passed

Questions about Curd

What does Curd do?

Generates complete CRUD module from database table definition. Curd is an agent skill from JaguarJack/catch-admin. Generates complete CRUD module from database table definition.

When should I use Curd?

Curd fits situations like: user says create CRUD; generate module from table; provides a table structure.

How do I install Curd in Claude Code?

Run `npx skills add JaguarJack/catch-admin --skill curd -a claude-code`. Or copy the skill folder (.claude/skills/curd in JaguarJack/catch-admin) into .claude/skills/curd in your project. Claude Code loads it when a task matches its description.

How do I install Curd in Codex?

Run `npx skills add JaguarJack/catch-admin --skill curd -a codex`. Or copy the skill folder (.claude/skills/curd in JaguarJack/catch-admin) into .agents/skills/curd in your project. Codex loads it when a task matches its description.

Can I use Curd in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add JaguarJack/catch-admin --skill curd -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/curd, .gemini/skills/curd, .github/skills/curd and .opencode/skills/curd in your project.

What does Curd need to run?

Going by SKILL.md and its folder, Curd needs the command-line tools its instructions call (php).

Does Curd access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Curd safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Curd use?

Curd is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Curd use?

About 3.3k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Curd?

Skills that share tags, products or a category with Curd: Livewire Development (coollabsio/coolify, 63k stars), Livewire Development (yungifez/skuul, 409 stars), Configure Nightwatch (trypostit/trypost, 685 stars) and Passport Development (trypostit/trypost, 685 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Curd?

JaguarJack (a GitHub user) maintains it in JaguarJack/catch-admin, which has 935 GitHub stars. The repository holds 10 skills in this directory. The repository was last updated on September 16, 2026.

Source: JaguarJack/catch-admin on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.