AgentSkillsCN

nova-create-type

在NovaDB中创建新的对象类型——包括属性定义、表单,以及对象本身。当用户想要定义新的数据架构、为某一类型新增属性,或通过表单搭建完整的对象类型时,可使用此功能。

SKILL.md
--- frontmatter
name: nova-create-type
description: Creates new object types in NovaDB — attribute definitions, forms, and the type itself. Use when the user wants to define a new data schema, add attributes to a type, or set up a complete object type with forms.

You have access to the NovaDB MCP server tools. This skill guides you through creating object types, attribute definitions, and forms via the CMS API.

CMS API Value Format

The CMS API uses normalized value tuples, not flat key-value props:

json
{ "values": [{ "attribute": 1000, "language": 201, "variant": 0, "value": "Example" }] }
  • attribute — Numeric attribute definition ID
  • language — Language ID (0 for language-independent attributes; 201=en-US, 202=de-DE)
  • variant — Variant ID (0 for no variant)

Workflow: Create a Complete Object Type

1. Plan the Schema

Before creating anything, clarify with the user:

  • Type name (EN + DE) and apiIdentifier
  • List of attributes: name, data type, language-dependent?, multi-valued?, required?
  • Which attributes appear on the create form vs. detail form(s)
  • Any ObjRef attributes: which types can be referenced?

2. Create Attribute Definitions

Each attribute is an object of type typeAttribute (typeRef: 10).

Simple string attribute (language-dependent):

json
novadb_cms_create_objects(branch, objects=[{
  "meta": { "typeRef": 10, "apiIdentifier": "myAttrName" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "My Attribute (EN)" },
    { "attribute": 1000, "language": 202, "value": "Mein Attribut (DE)" },
    { "attribute": 1001, "value": "String" },
    { "attribute": 1017, "value": true },
    { "attribute": 1018, "value": true }
  ]
}])

ObjRef attribute (single reference):

json
{
  "meta": { "typeRef": 10, "apiIdentifier": "myAttrCategory" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "Category" },
    { "attribute": 1000, "language": 202, "value": "Kategorie" },
    { "attribute": 1001, "value": "ObjRef" },
    { "attribute": 1015, "value": [<targetTypeId>] },
    { "attribute": 1004, "value": false }
  ]
}

ObjRef attribute (multi reference):

json
{
  "meta": { "typeRef": 10, "apiIdentifier": "myAttrTags" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "Tags" },
    { "attribute": 1000, "language": 202, "value": "Schlagwort" },
    { "attribute": 1001, "value": "ObjRef" },
    { "attribute": 1015, "value": [<targetTypeId>] },
    { "attribute": 1004, "value": true }
  ]
}

Boolean attribute:

json
{
  "meta": { "typeRef": 10, "apiIdentifier": "myAttrActive" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "Active" },
    { "attribute": 1000, "language": 202, "value": "Aktiv" },
    { "attribute": 1001, "value": "Boolean" }
  ]
}

Rich text attribute (language-dependent):

json
{
  "meta": { "typeRef": 10, "apiIdentifier": "myAttrDescription" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "Description" },
    { "attribute": 1000, "language": 202, "value": "Beschreibung" },
    { "attribute": 1001, "value": "XmlRef.SimpleHtml" },
    { "attribute": 1017, "value": true }
  ]
}

Date attribute:

json
{
  "meta": { "typeRef": 10, "apiIdentifier": "myAttrDate" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "Date" },
    { "attribute": 1000, "language": 202, "value": "Datum" },
    { "attribute": 1001, "value": "DateTime.Date" }
  ]
}

Adding Validation Code to Attributes

After creating an attribute, you can add JavaScript validation via attribute 1008 (attributeValidationCode, data type TextRef.JavaScript). Use update_objects to set it:

json
novadb_cms_update_objects(branch, objects=[{
  "meta": { "id": <attrId>, "typeRef": 10 },
  "values": [
    { "attribute": 1008, "value": "if (value && !/^[^@]+@[^@]+\\.[^@]+$/.test(value)) {\n    \"Invalid email address\";\n}" }
  ]
}])

The validation script API:

  • value — Global variable containing the current attribute value
  • Return a string expression to reject the value (the string is the error message)
  • Return nothing (or falsy) to accept the value

Example patterns from existing NovaDB validations:

javascript
// Regex validation
if (value && !/^[A-Z]{2}$/.test(value)) {
    "The value must consist of exactly two capital letters.";
}

// Range validation
if (value && value < 0 || value > 999) {
    "The value must be in the range of 0-999.";
}

3. Create Forms

Forms control which attributes appear in the UI. See /nova-forms for full form details.

Create form (shown when creating new objects):

json
novadb_cms_create_objects(branch, objects=[{
  "meta": { "typeRef": 50, "apiIdentifier": "myTypeCreateForm" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "Create My Type" },
    { "attribute": 1000, "language": 202, "value": "My Type erstellen" },
    { "attribute": 5053, "value": <attrId1> },
    { "attribute": 5053, "value": <attrId2>, "sortReverse": 1 },
    { "attribute": 5056, "value": false }
  ]
}])

Detail form (shown as tab in edit view):

json
novadb_cms_create_objects(branch, objects=[{
  "meta": { "typeRef": 50, "apiIdentifier": "myTypeDetailForm" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "General" },
    { "attribute": 1000, "language": 202, "value": "Allgemein" },
    { "attribute": 5053, "value": <attrId1> },
    { "attribute": 5053, "value": <attrId2>, "sortReverse": 1 },
    { "attribute": 5053, "value": <attrId3>, "sortReverse": 2 },
    { "attribute": 5056, "value": false }
  ]
}])

4. Create the Object Type

Object types are instances of root (typeRef: 0).

json
novadb_cms_create_objects(branch, objects=[{
  "meta": { "typeRef": 0, "apiIdentifier": "myCustomType" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "My Custom Type" },
    { "attribute": 1000, "language": 202, "value": "Mein Typ" },
    { "attribute": 5001, "value": <createFormId> },
    { "attribute": 5002, "value": [<detailFormId>] },
    { "attribute": 5005, "value": <displayNameAttrId> }
  ]
}])

5. (Optional) Create an Application Area

Application Areas group object types in the UI navigation. Create one with typeRef: 60.

json
novadb_cms_create_objects(branch, objects=[{
  "meta": { "typeRef": 60, "apiIdentifier": "myAppArea" },
  "values": [
    { "attribute": 1000, "language": 201, "value": "My Area" },
    { "attribute": 1000, "language": 202, "value": "Mein Bereich" },
    { "attribute": 6001, "value": [<typeId>] },
    { "attribute": 6003, "value": 100 }
  ]
}])

6. Verify

After creation, verify with the CMS API:

code
# Fetch the new type
novadb_cms_get_object(branch, id=<newTypeId>, inherited=true)
# Resolve form references (objectTypeCreateForm=5001, objectTypeDetailForms=5002)
novadb_cms_get_objects(branch, ids="<createFormId>,<detailFormId>")

Property Data Types Reference

Data TypeExample ValueNotes
String"Hello World"Plain text, may be language-dependent
TextRef"Long description..."Long/rich text
TextRef.JavaScript"function() { ... }"JavaScript code
TextRef.CSS"body { color: #000; }"CSS stylesheet code
XmlRef.SimpleHtml{"XML": "<div>...</div>"}Rich text (XHTML)
XmlRef.VisualDocument{"id": "...", "type": "group", ...}Visual component trees
Integer42Whole numbers
Decimal3.14Decimal numbers
Booleantrue / falseCheckbox values
DateTime.Date"2026-01-08"Date only
ObjRef2099001 or [2099001, 2099002]Reference(s) to other objects
BinRef.Icon(binary)Icon image upload
BinRef.Thumbnail(binary)Thumbnail image
String.DataType"ObjRef"Enumerated data type selector
String.InheritanceBehavior"None"Inheritance mode selector
String.UserName"john.doe"User name picker

Attribute Definition Properties (typeAttribute)

IDapiIdentifierData TypeNotes
1000attributeNameStringName (language-dependent, required)
1001attributeDataTypeString.DataTypeData type (required)
1004attributeAllowMultipleBooleanMulti-valued
1006attributePredefinedBooleanHas predefined values
1008attributeValidationCodeTextRef.JavaScriptJavaScript validation (value global, return string to reject)
1012attributeDescriptionTextRefDescription (language-dependent)
1013attributeInheritanceBehaviorString.InheritanceBehaviorNone / Inheriting / InheritingAll
1015attributeReferencedObjectTypesObjRef (multi)Allowed types for ObjRef
1017attributeLanguageDependentBooleanLocalized values
1018attributeRequiredBooleanValue required
1019attributeParentGroupObjRefParent attribute group
1020attributeVirtualBooleanComputed by JavaScript
1021attributeApiIdentifierStringAPI identifier (unique)
1032attributeUniqueValuesBooleanUnique constraint

Object Type Properties (root)

IDapiIdentifierData TypeNotes
5001objectTypeCreateFormObjRefCreate form
5002objectTypeDetailFormsObjRef (multi)Detail form tabs
5005objectTypeDisplayNameAttributeObjRefAttribute used for display name
5006objectTypeDisplayIconAttributeObjRefAttribute used for display icon
5008objectTypeThumbnailAttributeObjRefAttribute used for thumbnails
5009objectTypeBinaryProxyBooleanEnables binary file uploads

Application Area Properties (typeApplicationArea)

IDapiIdentifierData TypeNotes
6001applicationAreaObjectTypesObjRef (multi)Object types in this area
6003applicationAreaSortKeyIntegerSort order

Gotchas

  • apiIdentifier is immutable — Must be set in meta.apiIdentifier during create_objects. Cannot be changed later (HTTP 403). If wrong, delete and recreate.
  • attributeName (1000) is language-dependent — Always provide one value per language (201=en-US, 202=de-DE).
  • formContent (5053) uses individual entries, NOT arrays — Each attribute reference must be a separate value entry with "attribute": 5053 and a single "value". Use sortReverse (0, 1, 2, ...) to control field order. Passing an array like [id1, id2] causes HTTP 400.
  • objectTypeDetailForms (5002) is an array — When adding a form to a type that already has detail forms, first read the existing array, then append and update. Never overwrite with just the new form ID.
  • Use typeRef: 10 for attributes, typeRef: 50 for forms, typeRef: 0 for object types.
  • CMS uses numeric attribute IDs, not apiIdentifier strings. Always use the ID numbers from the tables above.