Skip to content

Build-time input-slot vocabulary: allowed_values, suggested_values, language, repeatable input groups, external-reference inputs #4331

@bokelley

Description

@bokelley

Context

This issue proposes additions to the build-time input-slot side of the creative protocol — distinct from the canonical output formats. The motivation is that as creative agents proliferate (Figma wrappers, Canva wrappers, AI generators, custom HTML renderers), they all need to advertise what inputs they accept in a way that an upstream orchestrator (or a buyer) can target generically.

This is largely a comment on #3305 (Creative Formats v2 RFC) — where build inputs collapse onto format declarations and validate_input becomes the dry-run primitive. A subset is small enough to land additively in 3.1 ahead of the full v2 redesign.

The framing throughout: canonical formats describe the output contract (PNG/HTML/MP4 the seller will accept and how it tracks); input-slot declarations describe the build-time contract (what the creative agent needs to fill in to produce that output). They live at different layers and shouldn't bleed.

Motivating example

A generic Figma-MCP wrapper exposes each Figma frame as a creative agent capability. Frame named meta_1080x1080, with named layers HEADLINE, SUBLINE, CTA, HERO_IMAGE, LOGO. The wrapper renders to a canonical image output, but its input-slot declaration needs to say:

  • HEADLINE: text, max 60 chars, language en (or nl-NL etc. per file)
  • CTA: text, must be one of ["Apply now", "View job", "Solliciteer direct"]
  • HERO_IMAGE: image, ≥1080×1080 — accepts a URL or a reference into a published asset library

The orchestrator (or a buyer) calls validate_input with proposed values, gets back valid: true/false plus per-slot errors, then calls the build primitive. Today there's no place in the protocol to express the picker, the language, or the catalog reference.

Proposed additions

1. allowed_values on text input slots — 3.1 candidate

Additive on text-asset-requirements.json. Closed enum of permitted strings. Validated by validate_input.

{
  "asset_type": "text",
  "asset_role": "cta",
  "max_length": 30,
  "allowed_values": ["Apply now", "View job", "Solliciteer direct"]
}

2. suggested_values on text input slots — v2 RFC

Open hint list. Discoverable by orchestrators that want to pick from a creative-agent-supplied template library; humans can override. Distinct from allowed_values (closed) so the validation semantics are clear.

{
  "asset_type": "text",
  "asset_role": "headline",
  "max_length": 60,
  "suggested_values": [
    "Werken als {{role}} bij {{brand}} {{location}}",
    "{{role}} gezocht in {{location}}"
  ]
}

(Whether suggested_values should support placeholders like {{role}} is a follow-on question — could just be plain strings the orchestrator template-fills before submitting.)

3. language on input slots — 3.1 candidate

The manifest-side text asset already carries language. Mirroring it on the input-slot requirements lets a creative agent declare per-slot locales (e.g., a Dutch-only Figma file declares language: "nl-NL" on every text slot), and validate_input can reject mismatched submissions early.

4. Repeatable input groups — v2 RFC

The output side already has item_type: "repeatable_group" (carousels, slideshows). The input side has no equivalent. The recruitment-SEA case wants "15 headline inputs + 4 description inputs"; today this has to be modeled as 15 individual slots, which doesn't compose. Proposing symmetry: an item_type: "repeatable_group" input that wraps a slot template plus min_count/max_count.

5. External-reference input slots — v2 RFC

An input slot that says: "I accept a URL, or a reference into this catalog/library." This is the clean answer to the per-location-photography pattern that today gets wedged into brand.json: photos live in a separately addressable asset library, and the hero_image input slot declares it accepts references into that library.

{
  "asset_type": "image",
  "asset_role": "hero_image",
  "min_width": 1080,
  "accepts_reference": {
    "schema": "https://example.com/photo-library.json",
    "selector": "$.locations[?(@.id == $location_id)].photography.exterior[*]"
  }
}

This intentionally does not put the catalog in brand.json — the v2 RFC's "brand.json with override capability" framing is preserved. The catalog is its own document that input slots can target.

Status of overlap with #3305

Suggested split

Happy to break (1) and (3) into a separate small PR if that helps land them sooner.

Notes

  • The example in (5) uses JSONPath in selector — that's a sketch, not a recommendation. The real design probably wants something simpler (or a more constrained pointer scheme); that's a discussion to have if the idea has legs.
  • asset_role: "cta" / "headline" / "hero_image" assume the canonical asset-group vocabulary from RFC #3305 implementation preview — v2 creative formats (full spec, not for merge) #3307 covers these. If it doesn't yet, the proposal still stands but the role names would shift.

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.creativeschemaJSON Schema source-of-truth: definitions, codegen artifacts, validation, hygiene

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions