1 Kumori DSL Syntax Guide

Kumori DSL is a modular, strongly-typed language for describing reusable, deployable artifacts. Its syntax is inspired by CUE and Go, with a focus on clarity, composability, and explicitness.

This guide covers the core syntax of the language.

1.1 Notation

The syntax is specified using a variant of Extended Backus-Naur Form (EBNF).

  • | indicates an alternative.
  • ( ... ) groups expressions.
  • [ ... ] denotes an optional part (0 or 1 occurrence).
  • { ... } denotes repetition (0 or more occurrences).

1.2 Comments

Comments begin with // and extend to the end of the line. Multiline comments begin with /* and end with */. They are ignored by the compiler.

// This is a single-line comment.
component MyComponent {
    /* a
    multiline
    comment */
}

1.3 File Structure

A Kumori file (.kumori) consists of an optional package declaration, zero or more import statements, and a body containing artifact or library definitions.

<kumori-file> = [<package>] [<imports>] <body>

1.3.1 Package Declaration

Every file belongs to a package. The package is declared at the top of the file. If omitted, the package name is inferred from the directory name.

<package> = 'package' NAME

Example:

package myapp

1.3.2 Imports

Imports allow you to use definitions from other packages. You can import a package using its default name, assign an alias, or import its contents directly into the current scope using a dot (.).

<imports>     = 'import' ( <import-spec> | '(' { <import-spec> } ')' )
<import-spec> = [ <alias> ] <package-path>
<alias>       = NAME | '.'

Examples:

// Import a single package
import "kumori"

// Import multiple packages with aliases
import (
    "strconv"         // Use default name 'strconv'
    p "pkg/utils"     // Import with alias 'p'
    . "pkg/common"    // Import contents into current scope
)

1.4 Top-Level Definitions

The body of a .kumori file can contain either:

  1. One or more artifact definitions.
  2. A single library block for defining types.
<body> = { <artifact> } | <library>

1.4.1 Scoped vs. Unscoped Definitions

Definitions can be scoped (enclosed in braces {...}) or unscoped (without braces). A file can contain multiple scoped definitions but only one unscoped definition. This is a syntactic convenience for files that define a single entity.

Scoped (Multiple Definitions):

// components.kumori

component ComponentA {
    // ...
}

component ComponentB {
    // ...
}

Unscoped (Single Definition):

// main-component.kumori
component MainComponent
// ... body of the component starts here at the top level

1.5 Artifacts

Artifacts are the core building blocks of a Kumori application. There are four types: component, service, builtin, and deployment.

<artifact> = <component> | <service> | <builtin> | <deployment>

<component>     = 'component'  NAME '{' <artifact-body> '}'
<service>       = 'service'    NAME '{' <artifact-body> '}'
<builtin>       = 'builtin'    NAME '{' <artifact-body> '}'
<deployment>    = 'deployment'      '{' <artifact-body> '}'

<artifact-body>   = <typed-entry> | <variables>

<typed-entry>     = (STRING | NAME) ['?'] [ [':'] <type-identifier> ] [ ['='] <expression> ]
<type-identifier> = <identifier>

<variables> = 'var' '(' <variable> ')'
<variable>  = NAME '=' <expression>

<identifier> = NAME { '.' NAME }
<expression> = /* OMITTED FOR BREVITY */

Example Artifact:

component MyWebApp {
    // A variable block
    var (
        ListenPort = 8080
    )

    // A field 'config' of an anonymous struct type
    config {
        Port: number = var.ListenPort
        EnableTLS: bool = false
    }

    // A field 'code'
    code {
        // ...
    }
}

1.6 Libraries and Type Definitions

Custom types are defined within a library block. This is the only place where new types, aliases, or function signatures can be declared.

<library>      = 'library' '{' { <library-stmt> } '}'
<library-stmt> = <type-def> | <alias> | <fn-def>

<type-def>     = 'type' NAME <type>
<alias>        = 'alias' NAME <type>
<fn-def>       = 'func' NAME <signature>

1.6.1 Type Expressions

A type can be a reference to another type, a union, a list, or a struct.

<type>          = <union> | <list> | <struct> | <identifier> | <literal>
<union>         = <type> '|' <type>
<list>          = '[]' <type>
<struct>        = 'struct' ( <struct-open> | <struct-closed> )
<struct-open>   = 'open' '[' <type> ']'
<struct-closed> = '{' { <struct-field> } '}'
<struct-field>  = (NAME | STRING) [ '?' ] ':' <type>

1.6.2 Function Signatures

A function declaration specifies input parameters and the return type.

<signature>      = <parameters> <result>
<result>         = <identifier>
<parameters>     = '(' [ <parameter-list> ] ')'
<parameter-list> = <parameter-decl> { ',' <parameter-decl> }
<parameter-decl> = NAME <type>

Example Library:

library {
    // A named struct type
    type Config struct {
        Port: number
        Response?: string // Optional field
    }

    // A type alias for a list of strings
    alias StringList []string

    // A type alias for a union (enum)
    alias Status "active" | "inactive" | "pending"

    // A function signature (implementation is built-in)
    func Concat(parts []string) string
}

For more details, see the Type System documentation.


1.7 Expressions

Expressions compute values and are used in field assignments, variable declarations, and function calls.

<expression>   = <unary-expr> | <expression> <binary-op> <expression>
<unary-expr>   = <primary-expr> | <unary-op> <unary-expr>

<binary-op>    = '||' | '&&' | '==' | '!=' | '<' | '<=' | '>' | '>=' | '+' | '-' | '*' | '/' | '%'
<unary-op>     = '+' | '-' | '!'

<primary-expr> = <literal> | <identifier> | <list-literal> | <struct-literal> | <fn-call> | '(' <expression> ')'

<literal>      = NUMBER | STRING | BOOL | SIZED
<list-literal> = '[' [ <expression> { ',' <expression> } ] ']'
<struct-literal> = '{' [ <field-init> { ',' <field-init> } ] '}'
<field-init>   = (NAME | STRING) ':' <expression>
<fn-call>      = <identifier> '(' [ <expression> { ',' <expression> } ] ')'

1.7.1 Examples

Arithmetic and Logic:

var (
    Port = 8000 + 100
    IsEnabled = isProduction && featureFlag
)

Struct and List Literals:

config {
    Limits: { cpu: "400m", memory: "1G" }
    Ports:  [ 8080, 8081, 8082 ]
}

Function Calls:

var (
    Greeting = strconv.Concat(["Hello, ", config.User])
)

For more details, see the Concepts Overview and the Type System Guide.