integromat/make-forman-schema · Archived

add-composite-type

Guidelines for adding a new Composite Type.

First seen Jun 18, 2026

Installation

$ npx skills add integromat/make-forman-schema --skill add-composite-type

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

License LICENSE
Default branch main
Open issues 0
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,725 B
  • docs SUMMARY.md 69 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Context

Composite Types in Forman are types which could be represented by a different structure, compound of multiple other, more primitive building blocks. For example, when having a field of type udtspec,

{
    "type": "udtspec",
    "name": "customType"
}

it's a wrapper around a more primitive structure, which looks like this:

{
    "type": "array",
    "name": "customType",
    "spec": [
        {
            "name": "name",
            "label": "Name",
            "placeholder": "Enter name",
            "type": "text",
            "required": true
        },
        {
            "name": "label",
            "label": "Label",
            "help": "Display name for better readability.",
            "type": "text",
            "advanced": true
        },
        {
            "name": "help",
            "label": "Description",
            "type": "text",
            "multiline": true,
            "required": false,
            "placeholder": "Enter description"
        },
        {
            "name": "type",
            "label": "Type",
            "type": "udttype",
            "required": true,
            "default": "text"
        }
    ]
}

Workflow

  • Composite Types are defined in src/composites
  • Each composite needs to be supported in:

- conversion from FormanSchema to JSON Schema - conversion from JSON Schema to FormanSchema - validation of FormanSchema

  • you need to know the composite structure (= the compound structure of the more primitive fields), associated with the composite type -- ask the operator to provide this.
  • based on the top-level type of the expanded structure (in case of udtspec it's array), add this to the type conversion map in both, validator and forman files
  • then add the handling of this composite type in the type-level switches
  • for that, you need to implement functions in the corresponding file in src/composites/${compositeType}.ts. Each composite must export four functions:

- ${compositeType}Expand — morphs the composite field into its expanded primitive structure. Accepts and mutates the field definition, setting spec, type, etc. Returns the mutated field. - ${compositeType}ExtractInner — extracts the inner structural fragment from the fully converted JSON Schema to store in $defs. This fragment must NOT contain field-specific title/description. (e.g. for udtspec: returns schema.items; for udttype: returns schema minus title/description) - ${compositeType}WrapRef — builds a per-usage wrapper that references the $defs fragment via $ref and carries field-specific title/description/default. (e.g. for udtspec: { type: 'array', title, description, items: { $ref } }; for udttype: { allOf: [{ $ref }], title, description, default } — uses allOf for draft-07 compliance where siblings of $ref are ignored) - ${compositeType}Collapse — reverse conversion from JSON Schema to Forman (see below)

  • then register the composite in the compositeHandlers config in src/forman.ts:

``typescript const compositeHandlers = { mytype: { expand: mytypeExpand, extractInner: mytypeExtractInner, wrapRef: mytypeWrapRef }, }; ``

  • in the high-level flow:

- when converting Forman to JSON Schema, the compositeHandlers block in toJSONSchemaInternal handles all composites uniformly: - x-composite marker is set via Object.defineProperty on both the inner fragment in $defs and on every wrapper — this is important for backward conversion - How $ref/$defs recursion prevention works: - The ConversionContext has a defs?: Record<string, JSONSchema7> property for collecting definitions - $defs stores only the inner structural fragment (no title/description). Title/description stay on each usage's wrapper. - On first encounter: register placeholder in context.defs[type], expand (with label/help stripped), convert, extract inner via extractInner, store in $defs, then return wrapper via wrapRef - On subsequent encounters: skip expansion, just return wrapper via wrapRef — each usage retains its own field-specific metadata - Only add to defs when the composite is actually used (lazy) — don't pre-populate $defs with unused definitions - The toJSONSchema wrapper in index.ts attaches collected context.defs as $defs on the root output, but only if non-empty - Validation: no recursion protection needed — validation walks the actual data values, which are always finite. Just expand the composite and validate recursively; termination is guaranteed by the data depth.

  • when validating Forman schema, morph the field, and then continue the validation recursively, as the morphed field is now in the structure of more primitive types
  • when converting JSON Schema to Forman, check if the field has x-composite property, and if it's equal to the composite type you're adding, then morph the field back to the composite structure and don't expand it further

- for this conversion, implement the function ${compositeType}Collapse, which will accept the expanded field definition, and will return the composite one, by basically doing the opposite of what ${compositeType}Expand does - notice that this one accepts JSONSchema Field and returns FormanSchema field

  • once done with these steps, make sure to cover the new composite type with tests, both for conversion and validation, following the structure of existing tests

- create the tests in the test/composites folder