CLEO

A configuration language for application-level configs

CLEO is specifically intended for configuration files that power your applications, focusing on clarity, nested structures, and environment-based values to keep your app setup flexible. This page highlights some key points, including examples, data types, command-line usage, integration with Go, and Q&As.

1. Overview

CLEO uses an indentation-based structure (multiples of 4 spaces) and # for comments. Lists start with *, environment variables are written as $VARIABLE_NAME, and references point to other keys or blocks via slash-based paths (e.g. /Server/Port). References must appear after the block or key they reference. Special keys can be any symbols up to the next space, but an empty key (i.e. "") is not allowed.

2. Basic Examples

Here are some examples of basic usage.

Blocks & Indentation

Nested values can be defined in indented blocks:

# Set the environment.
Environment "production"

# Define logging.
Logging
    Level "debug"

# A server block.
Server
    Host "localhost"
    Port 8080

Lists

Lists are indented under their key. For example, multiple output destinations under Logging:

Logging
    # Each '*' line is one list item.
    Outputs
        * "stdout"
        * "file"

References

Use references for reusing data from earlier definitions:

Server
    Host "localhost"
    Port 8080

# MainServer references Server, so it appears after.
MainServer /Server

3. Data Types

CLEO covers these core types: strings (inline/multiline), booleans, integers, floats, lists, blocks, environment variables, and references. Below are valid values, with examples.

String (inline and multiline)

Inline strings (e.g. "Hello") or multiline strings indented under a key:

# Inline string:
App
    Name "MyApp"

# Multiline string:
Description
    "This is a multi-line
    "description.

Strings can contain any characters except the closing quote. For multiline strings, each new line is another chunk of text appended with a newline in the final value.

Boolean

FeatureFlags
    Enabled true
    Experimental false

Valid values: true or false (unquoted).

Integer

Server
    Port 8080
    NegativePort -123
    ZeroPort 0

Valid integer values can be negative, zero, or positive.

Float

Limits
    Ratio 0.75
    NegativeFloat -3.14
    ZeroFloat 0.0

Valid float values require a decimal point (e.g. 3.14, -2.0).

List

Servers
    * "api-server"
    * "worker-server"
    * "db-server"

Each * line indicates one list item. All items can be any valid data type (strings, references, blocks, etc.).

Block

App
    Name "MyApp"
    Server
        Host "localhost"
        Port 8080

Blocks nest further keys or lists by indenting under the block’s name.

Dynamic (Environment) Value

Database
    Host $DB_HOST
    Password $DB_PASS

$SOMEVAR is replaced at parse time with the environment variable’s value.

Reference

A path of slash-separated tokens referencing previously declared blocks or keys:

App
    Title "Hello"

Paths
    # WebRoot references Title from App.
    WebRoot /App/Title

The file must define App (and Title) before Paths.

4. CLI Usage

Parse CLEO files and output JSON for tooling or inspection.

Installation

go install code.nicktrevino.com/cleo/cmd/cleo@latest

Then run cleo in your terminal.

Basic Command

cleo -config config.cleo

If config.cleo has:

Name "MyApp"
Database
    Host $DB_HOST
    Port 5432

The output JSON might look like:

{
  "Name": "MyApp",
  "Database": {
    "Host": "localhost",
    "Port": 5432
  }
}

Pipe this output to files or other tools as needed.

5. Integration with Go

Use CLEO’s official library to load configs directly into Go structures.

Example

Given config.cleo:

App
    Name "MyApplication"
    Server
        Host $HOST_ENV
        Port 8080

In your Go code:

package main

import (
    "fmt"
    "log"
    "code.nicktrevino.com/cleo"
)

type Config struct {
    App struct {
        Name   string
        Server struct {
            Host string
            Port int
        }
    }
}

func main() {
    configMap, err := cleo.ParseConfig("./config.cleo")
    if err != nil {
        log.Fatalf("Failed to parse CLEO: %v", err)
    }
    fmt.Println("Parsed Map:", configMap)

    var c Config
    if err := cleo.UnmarshalConfig("./config.cleo", &c); err != nil {
        log.Fatalf("Failed to unmarshal: %v", err)
    }
    fmt.Printf("Go Struct: %+v\n", c)
}

Here, HOST_ENV is substituted at runtime, and the entire config loads into Config.

6. Additional Examples

Check out these scenarios showing special keys and advanced references.

Special Keys ("[]key", "123key")

Unusual keys remain valid, but cannot be empty:

MyConfig
    # Bracket key
    []key "bracket key"

    # Numeric key
    123key "numeric key"

Advanced Environment References

Combining references with lists of blocks and environment variables:

App
    Databases
        *
            Host $PRIMARY_DB_HOST
            Port 5432
        *
            Host $SECONDARY_DB_HOST
            Port 5432

    # Reference to the first item in Databases
    MainDB /App/Databases/0

7. Comparison

CLEO is less ambiguous than YAML, supports references that TOML doesn’t, and leverages environment expansions lacking in JSON. Below are short side-by-side samples illustrating how each format handles nesting and placeholders.

CLEO Example

Name "MyApp"
Database
    Host $DB_HOST
    Credentials
        Username $DB_USER
        Password $DB_PASS

YAML Example

Name: "MyApp"
Database:
  Host: "${DB_HOST}"
  Credentials:
    Username: "${DB_USER}"
    Password: "${DB_PASS}"

TOML Example

Name = "MyApp"

[Database]
Host = "${DB_HOST}"

[Database.Credentials]
Username = "${DB_USER}"
Password = "${DB_PASS}"

JSON Example

{
  "Name": "MyApp",
  "Database": {
    "Host": "${DB_HOST}",
    "Credentials": {
      "Username": "${DB_USER}",
      "Password": "${DB_PASS}"
    }
  }
}

8. Q&As

1. Can I replace any typical JSON or YAML config with CLEO?

Absolutely. You’d define keys and blocks for your config, then parse it into JSON (or other structures) if your tooling requires.

2. What might be missing compared to other config formats?

3. What are the pros of using CLEO over JSON or YAML?

4. What are the cons?

5. Does CLEO mean anything?

CLEO is an acronym for: Concise, Lean, Ergonomic Options