Docs »

KATA

A human-friendly format for modeling structured data

KATA (“Key Annotated Tree of Attributes”) is a human-friendly format for modeling structured data that is used throughout Cerb (since 9.6) to describe configurations, customizations, sheets, and automations.

KATA was inspired by YAML1 but avoids many of its pitfalls.

Pitfall YAML KATA
Data types YAML attempts to automatically detect data types, which requires the use of double quotes on keys and values to ensure they remain text. For example, no becomes FALSE and currency/versions (1.50) become decimal (1.5). KATA treats all keys and values as text without any type coercion. You never need to use quotes. You can optionally annotate a key to convert its value to a specific type.
Local objects YAML allows language-specific tags. In some implementations (PHP, Perl, Python, Ruby) these may be automatically enabled for classes and present a security issue. KATA never executes or refers to outside code.
Curly braces YAML allows objects to be defined on a single line using {key:value} syntax. This conflicts with our {{placeholder}} syntax, and requires double quoting, explicit types, or text blocks. KATA doesn’t interpret {}, so those characters can be used in values without quoting.
Text blocks YAML has a variety of symbols for blocks of text (|, |-, >). The default always preserves the first trailing linefeed and trims the rest. KATA implies blocks of text by key annotation (e.g. @text). The first trailing linefeed is always ignored and the rest are preserved.
Lists YAML requires - prefixes on list items and is sensitive to indentation. Lists are required for duplicate key names amongst siblings. Mistakes with lists of objects can lead to children being added to the wrong parent. KATA has @csv and @list key annotations for text-based lists. Sibling keys can be repeated with unique identifiers and never require list syntax.
Comments YAML ignores any text following an unquoted # character. KATA only treats indented lines that begin with # as a comment. You do not need to escape the character in values.

Syntax

Indentation

KATA uses indentation (spaces) to build a tree of key/value relationships.

Key names end with a colon (:), which may be followed by either a value, or a set of child keys at a deeper level of indentation.

By convention, the indentation for each level should be two spaces.


parent:
  child:
    name:

Root

The root of the tree is implicit, so there may be multiple keys at the top-level:


picklist:
date_range:
text:

Key names

Key names must be unique amongst their siblings, but can be repeated elsewhere.

Key names serve as declarative instructions to a feature using KATA for customization (e.g. dashboard filters, snippet prompts, form interactions, automations). In such cases, the possible keys are predefined by that feature.

A slash (/) may be appended to a key name to provide a unique identifier. This format should be read as type/name:.


options:
  picklist/status:
  picklist/color:
  picklist/group:

Values

A key may be followed by a text value rather than children. KATA will not automatically detect its type, which often removes the need for escaping.


object:
  color: red

Values may also contain subsequent colons (:), which do not require escaping:


widget:
  label: Status:

Whitespace

Sibling keys may be separated with blank lines for readability. The blank lines must contain the same indentation as the keys.


widget/chart:
  type: chart
  label: Chart
  data: ...

widget/gauge:
  type: gauge
  label: Gauge
  data: ...

Key annotations

KATA does not perform type coercion on key values. It will not unpredictably convert digits to numbers, nor words like true or no to booleans. All values are treated as text by default.

To manipulate values, a comma-separated list of annotations may be appended to a key name starting with a @ character. The annotations are processed in order.



picklist:
  options:
    color@csv: red, green, blue
    multiple@bool: no
    hidden@bool:
      {% if has_access %}
      no
      {% else %}
      yes
      {% endif %}


Text blocks

When using key annotations, a value may contain multiple lines of text. Most annotations imply a text block (e.g. @bool, @csv, @json, @list). The @text annotation may be used for arbitrary text without any special handling.



comment:
  content@text:
    This is a comment with
    multiple lines of content.
  author:
    name: Cerb


Comments

Lines that begin with # are treated as comments and are ignored.



picklist:
  # The options from a placeholder
  options:
    color@csv: {{colors}}


You do not need to escape the # character in values or text blocks.



# This is a comment
article:
  title: Using #commands <-- not a comment
  format: markdown
  content@text:
    # Heading <-- not a comment
    
    Some **bold** text.


References

You can break up a complex tree into manageable, reusable sections with references.

You define a reference by prefixing an ampersand (&) to a top-level key.

Any key can then use an @ref annotation to copy the contents and annotations of the reference.



picklist:
  options@ref: colors

&colors@list:
  red
  green
  blue


An @ref may target a child of a reference using dot-notation:



picklist:
  options@ref: options.colors

&options:
  colors@list:
    red
    green
    blue


And references themselves may contain @ref annotations:



picklist:
  options@ref: options.colors

&options:
  colors@ref: colors
  
&colors@list:
  red
  green
  blue


A reference’s annotations take the place of @ref, and any remaining annotations will affect the copied content.

For instance, this copies a reference as a @text block and then converts it to a @list:



picklist:
  options@ref,list: colors

&colors@text:
  red
  green
  blue


The result of all four examples above is:



picklist:
  options@list:
    red
    green
    blue


Dictionaries

Features that use KATA may enable scripting and provide a dictionary of placeholders for dynamic content.

Placeholders and scripting may be used in any value and do not require escaping.

Use the @raw annotation to prevent tags from being parsed.



chooser:
  label: {{label}}
  params:
    record_type: {{record_type}}


Annotation Reference

base64

@base64 converts a key’s value from base64-encoded2 text into binary. This is particularly useful for HMAC keys and images.



image@base64: QnVzdGVkISBUaGlzIGlzIG5vdCByZWFsbHkgYW4gaW1hZ2Uu


bit

@bit convert’s a key’s value into a 0 or 1.

The following values result in 0:

  • null/blank
  • 0
  • false
  • off
  • no
  • n


result@bit: off


Anything other value returns a 1.

bool

@bool convert’s a key’s value into a boolean true or false.

The following values result in false:

  • null/blank
  • 0
  • false
  • off
  • no
  • n

Anything other value returns true.



enabled@bool: yes


csv

@csv converts a comma-separated list into an array.



colors@csv: red,green,blue


int

@int parses the key’s value as a whole number.



number@int: 123


json

@json parses text as a JSON-encoded value.

This is particularly useful when combined with a placeholder based on an API response.



person@json:
  {
    "name": "Kina Halpue",
    "title": "Customer Support Manager"
  }

numbers@json: [1,2,3]


key

@key sets the value from a dictionary path.



http_status@key: response.http.status.code


list

@list converts text into an array with one line per item.



colors@list:
  red
  green
  blue


raw

@raw returns a key’s text without substituting {{placeholders}} or executing bot scripts using the dictionary.

This is useful for returning templates to other functionality (e.g. sheets).



template@raw:
  {{person}} is {{title}} at {{organization}}


ref

@ref copies the contents of a top-level &key: into the current key.

This can target a reference by name (key@ref: target) or by path (key@ref: target.nested.child.value).

The annotations of the target key replace the @ref, and any remaining annotations apply to the copied content.

See: References



event/start@ref: menu

&menu:
  options@list:
    Option 1
    Option 2
    Option 3


text

@text reads the key’s indented value as a text block. This continues until the indent returns to the same level as the key.

This is useful when a text block can’t be implied from any other attributes.



content@text:
  This is a _bunch_ of content
  on several lines
  that stops **here**
format: markdown


The first trailing linefeed is always removed so that multiple line scripts can return a single value.

End the text block with one or more indented blank lines to keep linefeeds:



content@text:
  This content ends
  with a blank line
  
format: markdown


Footnotes