For LLMs — AI Skill Document
Preview feature: CLI AI Automation is currently a preview feature. If you encounter any issues, please report them at support.skipper18.com.
This page contains a machine-readable skill document that teaches AI assistants how to use the Skipper CLI. Copy the document below into your AI assistant's system prompt or instructions file, and it will be able to create projects, add entities, manage relationships, validate schemas, and export code on your behalf.
How to Use
Copy the skill document from the code block below and paste it into the instructions for your AI tool:
Claude Code: Add it to your project's
CLAUDE.mdfile or paste it into the project instructions.ChatGPT: Paste it into Custom Instructions or at the start of your conversation.
Cursor: Add it to your
.cursorrulesfile in the project root.Windsurf: Add it to your
.windsurfrulesfile in the project root.Generic / other tools: Add it to the system prompt or any instructions file your AI reads at startup.
Once the skill document is loaded, you can give natural-language instructions like "add a User entity with email and password fields" and the AI will know which Skipper CLI commands and patch operations to use.
Skipper CLI Skill Document
Last synced with docs/ai/skipper-skill.md on 2026-05-04.
Copy everything inside the code block below:
# Skipper CLI Skill
Skipper is an ORM design tool. The `-cli-*` flags let AI assistants and CI scripts drive it headlessly.
**Windows:** Use `SkipperCli.exe` (not `Skipper.exe`) for CLI operations.
**Linux/macOS:** Use `./Skipper` directly.
All CLI responses are JSON envelopes on stdout with fields: `status`, `command`, `data`, `warnings`, `meta`.
## Quick Start
```bash
# List all verbs (Windows: SkipperCli.exe, Linux/macOS: ./Skipper)
Skipper.exe -cli-help
# Detail for one verb
Skipper.exe -cli-help export
```
## Global Flags
| Flag | Effect |
|---|---|
| `-quiet` | Suppress stderr diagnostics |
| `-verbose` | Raise stderr to debug level (trace + progress) |
| `-include-timing` | Add `meta.timing_breakdown` to envelope |
## Envelope
Every verb emits a single JSON document on stdout. Schema: `docs/ai/skipper-envelope.schema.json`.
## Typical Workflow
1. `-cli-list-frameworks` — discover available ORM/MVC combinations
2. `-cli-create-project` or `-cli-import-project` or `-cli-import-database` — create/import a project
3. `-cli-apply-patch` — add modules, entities, fields, associations, indexes
4. `-cli-validate` — check for errors and warnings
5. `-cli-schema-summary` — inspect the result (JSON output, see `docs/ai/skipper-schema-shape.md`)
6. `-cli-export` — generate framework code (PHP classes, migrations, etc.)
7. `-cli-export-diagram` — render visual diagram (PNG/PDF, requires `Skipper.exe` GUI build)
For incremental changes, use `-cli-schema-summary` to read current state, then `-cli-apply-patch` or `-cli-apply-merge` to modify, then `-cli-validate` to verify.
## Verbs
### `-cli-help`
List available verbs or show detail for one.
```
Skipper.exe -cli-help [<verb-name>]
```
**Errors:** `UNKNOWN_VERB` (if verb-name not recognised).
---
### `-cli-export`
Full export: classes + migrations using the project's configured framework.
```
Skipper.exe -cli-export <project.skipper>
```
**Data shape:** `{ files_written: [{path, bytes}], framework: "...", output_dir: "..." }`
**Errors:** `PROJECT_LOAD_FAILED`, `EXPORT_FAILED`.
**Note:** Files are written relative to the project file location, into each module's `export_path`.
---
### `-cli-export-classes`
Export classes/models only.
```
Skipper.exe -cli-export-classes <project.skipper>
```
**Note:** Currently returns `NOT_IMPLEMENTED`. Use `-cli-export` for full export.
---
### `-cli-export-migrations`
Export migrations only.
```
Skipper.exe -cli-export-migrations <project.skipper>
```
**Note:** Currently returns `NOT_IMPLEMENTED`. Use `-cli-export` for full export.
---
### `-cli-export-diagram`
Render schema diagram as PNG or PDF. Available in `Skipper.exe` (GUI build), not in `SkipperCli.exe` (console build).
```
Skipper.exe -cli-export-diagram <project.skipper> -format <png|pdf> -output <path>
```
**Data shape:** `{ format: "...", output_path: "...", bytes: <int> }`
**Errors:** `INVALID_ARG_VALUE` (bad format), `NOT_IMPLEMENTED` (svg).
**Note:** On Linux, set `QT_QPA_PLATFORM=offscreen`.
---
### `-cli-validate`
Validate project consistency and migration freshness.
```
Skipper.exe -cli-validate <project.skipper>
```
**Data shape:** `{ issues: [{severity, code, object, message}], summary: {error_count, warning_count} }`
**Errors:** `PROJECT_LOAD_FAILED`, `VALIDATION_FAILED`.
---
### `-cli-schema-summary`
Dump entire project as JSON.
```
Skipper.exe -cli-schema-summary <project.skipper> [-with-visual]
```
**Data shape:** `{ project: {...} }` (see `docs/ai/skipper-schema-shape.md`)
---
### `-cli-compare`
Diff two `.skipper` files using the migration diff engine.
```
Skipper.exe -cli-compare <new.skipper> <old.skipper>
```
**Data shape:** `{ summary: {added, removed, modified, identical}, items: [{action, type, name, details?}], input_new: "...", input_old: "..." }`
---
### `-cli-apply-patch`
Apply a list of explicit operations (op-list, RFC 6902 spirit).
```
Skipper.exe -cli-apply-patch <project.skipper> -patch <ops.json> -output <out.skipper>
```
**Data shape (success):** `{ ops_executed: <int>, output_path: "..." }`
**Data shape (failure):** `{ ops_attempted: <int>, failed_op_index: <int> }`
**Errors:** `INVALID_OP`, `OBJECT_NOT_FOUND`, `MALFORMED_INPUT_FILE`.
**Error behavior:** On failure at op N, operations 0 through N-1 are already applied. The output file is **not** written on failure. To retry, fix the failing op and re-run with the original input file.
#### Patch Operations Reference (36 ops)
Each op is `{"op": "<name>", "args": {...}}`. Operations are executed in order. Both `{"ops": [...]}` and bare `[...]` array formats are accepted.
**Operations are sequential:** Objects created by earlier ops are immediately available to later ops in the same patch. You can `add_entity` and then `add_field` referencing that entity in a single patch file.
Example patch file:
```json
[
{"op": "add_entity", "args": {"module": "MainBundle", "name": "Customer"}},
{"op": "add_field", "args": {"entity": "Customer", "name": "email", "type": "string", "size": 255, "unique": true}},
{"op": "add_field", "args": {"entity": "Customer", "name": "name", "type": "string", "size": 100}}
]
```
**Name resolution:** Entity and module names accept short names (`Customer`, `MainBundle`) or full qualified names (`\Customer`, `\MainBundle`). Short names are matched against `LocalName`. Use short names for simplicity. **Caution:** If two entities share the same short name in different modules (e.g. `\App\Crm\Address` and `\App\EShop\Address`), the short name `Address` matches the first one found. Use the full qualified name to disambiguate.
**Namespace values:** Use forward slashes (`/App/Entity`) or backslashes (`\App\Entity`) — both are accepted. Forward slashes are auto-converted to backslashes. Invalid JSON escape sequences in backslash paths (e.g. `\App` instead of `\\App`) are auto-corrected.
**Entity template auto-creates PK:** `add_entity` automatically creates an `id` integer primary key field (auto-increment) from the framework template. Do **not** add a PK field manually — you will end up with duplicate `id` + `id2`. Only add non-PK fields after `add_entity`.
**Entity** (3):
- `add_entity` — `{module, name, [namespace], [description]}` — auto-creates `id` PK field from template; do not add PK manually
- `update_entity` — `{entity, [name], [namespace], [description]}` — use this to rename entities (not remove+add)
- `remove_entity` — `{entity}` — also removes associated fields, associations, indexes, and M:N relationships
**Field** (4):
- `add_field` — `{entity, name, [type], [size], [primary], [nullable], [unique], [auto_increment], [default]}` — fields are NOT NULL by default; pass `"nullable": true` explicitly for nullable fields. If a field with the same name already exists, the operation is silently skipped
- `update_field` — `{entity, field, [name], [type], [size], [primary], [nullable], [unique], [auto_increment], [default]}`
- `remove_field` — `{entity, field}`
- `reorder_field` — `{entity, field, sort_order}`
**Association** (3):
- `add_association` — `{from, to, [owner_alias], [inverse_alias]}`
- `update_association` — `{id, [owner_alias], [inverse_alias]}` — `id` is the numeric ID from `schema-summary`
- `remove_association` — `{id}` — `id` is the numeric ID from `schema-summary`
**Module** (3):
- `add_module` — `{name, [namespace], [description], [export_path], [export_format]}` — if `export_format` is omitted, uses the framework default
- `update_module` — `{module, [name], [namespace], [description], [export_path], [export_format]}` — use this to rename/reconfigure existing modules (not remove+add)
- `remove_module` — `{module}`
**Index** (3):
- `add_index` — `{entity, name, [unique], [fields: ["f1","f2"]]}`
- `update_index` — `{entity, index, [name], [unique]}`
- `remove_index` — `{entity, index}`
**ManyToMany** (3):
- `add_many_to_many` — `{owner, inverse, [mn_entity], [owner_alias], [inverse_alias]}` — automatically creates a join entity with composite PK foreign key fields
- `update_many_to_many` — `{id, [owner_alias], [inverse_alias]}`
- `remove_many_to_many` — `{id}`
**Embedded** (3):
- `add_embedded` — `{from, to, [owner_alias], [inverse_alias]}`
- `update_embedded` — `{id, [owner_alias], [inverse_alias]}`
- `remove_embedded` — `{id}`
**Inheritance** (3):
- `add_inheritance` — `{parent, child, [type], [discriminator_value]}` — valid types: `SINGLE_TABLE`, `JOINED`, `MAPPED_SUPERCLASS`
- `update_inheritance` — `{id, [discriminator_value]}`
- `remove_inheritance` — `{id}`
**Region** (3):
- `add_region` — `{module, [caption], [namespace], [description]}`
- `update_region` — `{id, [caption], [namespace], [description]}`
- `remove_region` — `{id}`
**Comment** (3):
- `add_comment` — `{module, [caption], [description]}`
- `update_comment` — `{id, [caption], [description]}`
- `remove_comment` — `{id}`
**ORM Attributes** (4):
- `set_orm_attribute` — `{object, [object_type], [entity], path, value}`
- `remove_orm_attribute` — `{object, [object_type], [entity], path}`
- `add_orm_attribute_item` — `{object, [object_type], [entity], path, [key], [values: {child: val, ...}]}`
- `remove_orm_attribute_item` — `{object, [object_type], [entity], path}`
**Visual Layout** (1):
- `reset_layout` — `{}` (no args) — resets visual positions on all entities/modules/regions/comments so auto-arranger runs on next GUI open
`object_type` defaults to `"entity"`. Supported types for ORM attribute write operations: `entity`, `field`, `module`, `association`. Schema-summary emits `orm_attributes` on all object types (including `index`, `many-to-many`, `embedded`, `region`) but write operations for those types are not yet implemented.
**ORM Attribute addressing for fields:** For `object_type: "field"`, use one of these formats to identify the field:
- **Dotted notation (recommended):** `"object": "Customer.email"` — `Entity.field` format
- **With entity parameter:** `"object": "email", "entity": "Customer"` — separate entity lookup
- **Field name only:** `"object": "email"` — searches all entities (fails if ambiguous)
**Attribute paths:** Use attribute names without framework prefix. Write `"table"` not `"orm:table"`. Use `/` to separate nested paths (e.g. `"options/charset"`). The `orm:` prefix is auto-stripped if present, but avoid it.
Examples:
```json
{"op": "set_orm_attribute", "args": {"object": "Product", "path": "table", "value": "app_products"}}
{"op": "set_orm_attribute", "args": {"object": "Product.price", "object_type": "field", "path": "precision", "value": "10"}}
{"op": "set_orm_attribute", "args": {"object": "price", "object_type": "field", "entity": "Product", "path": "scale", "value": "2"}}
{"op": "set_orm_attribute", "args": {"object": "Product", "path": "options/charset", "value": "utf8mb4"}}
{"op": "set_orm_attribute", "args": {"object": "Product", "path": "change-tracking-policy", "value": "DEFERRED_EXPLICIT"}}
{"op": "add_orm_attribute_item", "args": {"object": "Product", "path": "lifecycle-callbacks", "values": {"type": "prePersist", "method": "onPrePersist"}}}
```
**Referencing associations and M:N by ID:** `update_association`, `remove_association`, `update_many_to_many`, `remove_many_to_many` require a numeric `id` from `-cli-schema-summary` output. IDs are project-scoped auto-increment numbers. To modify objects created in the same patch, run `schema-summary` after the patch to discover their IDs, then apply a second patch.
**Referencing indexes by name:** `update_index` and `remove_index` use `{entity, index}` where `index` is the index **name** (string), not a numeric ID.
---
### `-cli-list-frameworks`
List available ORM and MVC frameworks.
```
Skipper.exe -cli-list-frameworks
```
**Data shape:** `{ orm_frameworks: [{name: "..."}], mvc_frameworks: [{name: "..."}] }`
---
### `-cli-apply-merge`
Apply a declarative sparse target state (RFC 7396 spirit).
```
Skipper.exe -cli-apply-merge <project.skipper> -merge <state.json> -output <out.skipper>
```
**Data shape (success):** `{ objects_changed: <int>, output_path: "..." }`
**Errors:** `INVALID_MERGE_INPUT`, `OBJECT_NOT_FOUND`, `MALFORMED_INPUT_FILE`.
**Input structure:** Must have a `project` root key mirroring `schema-summary` structure. Only include objects you want to change — unmentioned objects are left as-is. Merge updates existing fields by name and adds new ones. Warnings are emitted for newly added fields.
```json
{
"project": {
"modules": [
{
"name": "MainBundle",
"entities": [
{
"name": "Customer",
"fields": [
{"name": "email", "type": "string", "size": 320},
{"name": "middleName", "type": "string", "size": 100, "nullable": true}
]
}
]
}
]
}
}
```
---
### `-cli-create-migration`
Create a new migration revision.
```
Skipper.exe -cli-create-migration <project.skipper>
```
**Data shape:** `{ created: true }` (success) or `{ created: false, reason: "no_changes_pending" }` (no changes)
**Errors:** `MIGRATIONS_DISABLED`.
---
### `-cli-create-project`
Create an empty project with chosen ORM/MVC framework.
```
Skipper.exe -cli-create-project -output <path> -orm <name> -mvc <name> [-name <project-name>]
```
**Data shape:** `{ output_path: "...", orm: "...", mvc: "..." }`
**Errors:** `UNKNOWN_FRAMEWORK`, `IO_ERROR`, `VIEWER_LICENSE`.
---
### `-cli-import-project`
Scan a codebase directory and build a `.skipper` from discovered files.
```
Skipper.exe -cli-import-project <scan-dir> -output <path> -orm <name> -mvc <name> [-name <project-name>]
```
**Data shape:** `{ output_path: "...", orm: "...", mvc: "...", modules_created: <int>, entities_imported: <int> }`
**Errors:** `IO_ERROR`, `VIEWER_LICENSE`.
---
### `-cli-import-database`
Reverse-engineer a `.skipper` from a live database.
```
Skipper.exe -cli-import-database -output <path> -db-class <sqlite|mysql|postgres|sqlserver> -connection <conn> -orm <name> -mvc <name> [-name <project-name>] [-skip-initial-migrations]
```
**Errors:** `DB_CONNECTION_FAILED`, `DB_IMPORT_FAILED`, `UNKNOWN_FRAMEWORK`, `VIEWER_LICENSE`.
---
## Legacy / Compatibility
### `--export-model-to-image`
Legacy flag for diagram export. Still functional. Prefer `-cli-export-diagram` for new uses.Prompt Examples
Here are example prompts you can give your AI assistant once the skill document is loaded, along with what the AI should do for each.
1. "Add a User entity with email and password fields to my Doctrine2 project"
The AI should create a patch file with add_entity for User (which auto-creates the id PK field), then add_field for email (string, 255, unique) and password (string, 255). Do not add a PK field manually. Then apply it:
# The AI writes ops.json:
# [
# {"op":"add_entity","args":{"module":"Default","name":"User"}},
# {"op":"add_field","args":{"entity":"User","name":"email","type":"string","size":255,"unique":true}},
# {"op":"add_field","args":{"entity":"User","name":"password","type":"string","size":255}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper2. "Create a many-to-many relationship between Post and Tag"
The AI should use add_many_to_many with Post as owner and Tag as inverse, creating a join entity (PostTag):
# ops.json:
# [
# {"op":"add_many_to_many","args":{"owner":"Post","inverse":"Tag","mn_entity":"PostTag","owner_alias":"tags","inverse_alias":"posts"}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper3. "Set up SINGLE_TABLE inheritance for Vehicle with Car and Truck"
The AI should first ensure all three entities exist (using add_entity which auto-creates PK fields), then use add_inheritance twice to establish the parent-child relationships with discriminator values:
# ops.json:
# [
# {"op":"add_entity","args":{"module":"Default","name":"Vehicle"}},
# {"op":"add_entity","args":{"module":"Default","name":"Car"}},
# {"op":"add_entity","args":{"module":"Default","name":"Truck"}},
# {"op":"add_inheritance","args":{"parent":"Vehicle","child":"Car","type":"SINGLE_TABLE","discriminator_value":"car"}},
# {"op":"add_inheritance","args":{"parent":"Vehicle","child":"Truck","type":"SINGLE_TABLE","discriminator_value":"truck"}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper4. "Validate my project and fix any errors"
The AI should first run validation, read the issues from the JSON output, then create a patch to fix them (e.g., adding missing primary keys or removing orphaned references):
# Step 1: Validate
Skipper.exe -cli-validate project.skipper
# Step 2: Read the issues array from the JSON output
# Step 3: For each fixable issue, create the appropriate patch ops
# Step 4: Apply fixes
Skipper.exe -cli-apply-patch project.skipper -patch fixes.json -output project.skipper
# Step 5: Re-validate to confirm clean
Skipper.exe -cli-validate project.skipper5. "Export my project to PHP attribute annotations"
The AI should configure the export format via ORM attributes if needed, then run the export verb. The export format is controlled by the project's framework configuration:
# If the project's export format needs to change, set the module-level ORM attribute:
# [{"op":"set_orm_attribute","args":{"object":"Default","object_type":"module","path":"export-format","value":"php-attributes"}}]
# Skipper.exe -cli-apply-patch project.skipper -patch format.json -output project.skipper
# Then export:
Skipper.exe -cli-export project.skipper6. "Rename entity User to Account and update all references"
The AI should use update_entity to change the entity name. Skipper automatically updates all association and relationship references that point to the renamed entity:
# ops.json:
# [
# {"op":"update_entity","args":{"entity":"User","name":"Account"}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper7. "Add a unique index on the email field of the Customer entity"
The AI should use add_index with the unique flag and reference the target field:
# ops.json:
# [
# {"op":"add_index","args":{"entity":"Customer","name":"idx_customer_email","unique":true,"fields":["email"]}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper8. "Set the table name for entity Order to 'shop_orders'"
The AI should use set_orm_attribute to set the framework-specific table name attribute on the entity:
# ops.json:
# [
# {"op":"set_orm_attribute","args":{"object":"Order","object_type":"entity","path":"table","value":"shop_orders"}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper9. "Add a region called 'Domain Models' to the AppBundle module"
The AI should use add_region to create a visual grouping region inside the specified module:
# ops.json:
# [
# {"op":"add_region","args":{"module":"AppBundle","caption":"Domain Models"}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper10. "Remove the description field from the Product entity"
The AI should use remove_field specifying the entity and field name:
# ops.json:
# [
# {"op":"remove_field","args":{"entity":"Product","field":"description"}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper11. "Show me the full schema of my project as JSON"
The AI should use -cli-schema-summary to dump the entire project structure as JSON. No patch file is needed -- this is a read-only operation:
Skipper.exe -cli-schema-summary project.skipper -quiet12. "Compare my current project with the previous version and show what changed"
The AI should use -cli-compare to diff two .skipper files. If working with version control, it can extract the previous version from git first:
# Extract the previous version from version control
git show HEAD~1:project.skipper > /tmp/project-old.skipper
# Compare current vs. previous
Skipper.exe -cli-compare project.skipper /tmp/project-old.skipper -quiet13. "List available frameworks"
The AI should use -cli-list-frameworks to discover which ORM and MVC frameworks are available for project creation:
Skipper.exe -cli-list-frameworks -quiet14. "Set decimal precision on the price field of Product"
The AI should use set_orm_attribute with the dotted Entity.field notation to target the specific field's ORM attribute:
# ops.json:
# [
# {"op":"set_orm_attribute","args":{"object":"Product.price","object_type":"field","path":"precision","value":"10"}},
# {"op":"set_orm_attribute","args":{"object":"Product.price","object_type":"field","path":"scale","value":"2"}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper15. "Add a prePersist lifecycle callback to the Product entity"
The AI should use add_orm_attribute_item with the values parameter to add a lifecycle callback with its type and method:
# ops.json:
# [
# {"op":"add_orm_attribute_item","args":{"object":"Product","path":"lifecycle-callbacks","values":{"type":"prePersist","method":"onPrePersist"}}}
# ]
Skipper.exe -cli-apply-patch project.skipper -patch ops.json -output project.skipper16. "Merge a nullable middle name field into the Customer entity"
The AI should use -cli-apply-merge with a declarative state file that specifies the new field with nullable: true:
# state.json:
# {
# "project": {
# "modules": [{
# "name": "Default",
# "entities": [{
# "name": "Customer",
# "fields": [
# {"name": "middleName", "type": "string", "size": 100, "nullable": true}
# ]
# }]
# }]
# }
# }
Skipper.exe -cli-apply-merge project.skipper -merge state.json -output project.skipper