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.
      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.
    
#*$DB_HOST, etc.)/Database/Port) that come after the definition they referenceHere are some examples of basic usage.
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 are indented under their key. For example, multiple output destinations under Logging:
    
Logging
    # Each '*' line is one list item.
    Outputs
        * "stdout"
        * "file"
Use references for reusing data from earlier definitions:
Server
    Host "localhost"
    Port 8080
# MainServer references Server, so it appears after.
MainServer /Server
CLEO covers these core types: strings (inline/multiline), booleans, integers, floats, lists, blocks, environment variables, and references. Below are valid values, with examples.
      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.
FeatureFlags
    Enabled true
    Experimental false
      Valid values: true or false (unquoted).
    
Server
    Port 8080
    NegativePort -123
    ZeroPort 0Valid integer values can be negative, zero, or positive.
Limits
    Ratio 0.75
    NegativeFloat -3.14
    ZeroFloat 0.0
      Valid float values require a decimal point (e.g. 3.14, -2.0).
    
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.).
    
App
    Name "MyApp"
    Server
        Host "localhost"
        Port 8080
Blocks nest further keys or lists by indenting under the block’s name.
Database
    Host $DB_HOST
    Password $DB_PASS
      $SOMEVAR is replaced at parse time with the environment variable’s value.
    
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.
    
Parse CLEO files and output JSON for tooling or inspection.
go install code.nicktrevino.com/cleo/cmd/cleo@latestThen run cleo in your terminal.
cleo -config config.cleo
      If config.cleo has:
    
Name "MyApp"
Database
    Host $DB_HOST
    Port 5432The output JSON might look like:
{
  "Name": "MyApp",
  "Database": {
    "Host": "localhost",
    "Port": 5432
  }
}Pipe this output to files or other tools as needed.
Use CLEO’s official library to load configs directly into Go structures.
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.
    
Check out these scenarios showing special keys and advanced references.
Unusual keys remain valid, but cannot be empty:
MyConfig
    # Bracket key
    []key "bracket key"
    # Numeric key
    123key "numeric key"
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
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.
Name "MyApp"
Database
    Host $DB_HOST
    Credentials
        Username $DB_USER
        Password $DB_PASSName: "MyApp"
Database:
  Host: "${DB_HOST}"
  Credentials:
    Username: "${DB_USER}"
    Password: "${DB_PASS}"Name = "MyApp"
[Database]
Host = "${DB_HOST}"
[Database.Credentials]
Username = "${DB_USER}"
Password = "${DB_PASS}"{
  "Name": "MyApp",
  "Database": {
    "Host": "${DB_HOST}",
    "Credentials": {
      "Username": "${DB_USER}",
      "Password": "${DB_PASS}"
    }
  }
}Absolutely. You’d define keys and blocks for your config, then parse it into JSON (or other structures) if your tooling requires.
CLEO is an acronym for: Concise, Lean, Ergonomic Options