CLI Applications

Build command-line tools that read input, write output, and interact with users.

What We're Building

A simple CLI that greets the user:

$ wippy run -x app:cli
Hello from CLI!

Project Structure

cli-app/
├── wippy.lock
└── src/
    ├── _index.yaml
    └── cli.lua

Step 1: Create Project

mkdir cli-app && cd cli-app
mkdir src

Step 2: Entry Definitions

Create src/_index.yaml:

version: "1.0"
namespace: app

entries:
  # Terminal host connects processes to stdin/stdout
  - name: terminal
    kind: terminal.host
    lifecycle:
      auto_start: true

  # CLI process
  - name: cli
    kind: process.lua
    source: file://cli.lua
    method: main
    modules:
      - io
The terminal.host bridges your Lua process to the terminal. Without it, io.print() has nowhere to write.

Step 3: CLI Code

Create src/cli.lua:

local io = require("io")

local function main()
    io.print("Hello from CLI!")
    return 0
end

return { main = main }

Step 4: Run It

wippy init
wippy run -x app:cli

Output:

Hello from CLI!
The -x flag auto-detects your terminal.host and runs in silent mode for clean output.

Reading User Input

local io = require("io")

local function main()
    io.write("Enter your name: ")
    local name = io.readline()

    if name and #name > 0 then
        io.print("Hello, " .. name .. "!")
    else
        io.print("Hello, stranger!")
    end

    return 0
end

return { main = main }

Colored Output

Use ANSI escape codes for colors:

local io = require("io")

local reset = "\027"
local function red(s) return "\027" .. s .. reset end
local function green(s) return "\027" .. s .. reset end
local function yellow(s) return "\027" .. s .. reset end
local function cyan(s) return "\027" .. s .. reset end
local function bold(s) return "\027" .. s .. reset end

local function main()
    io.print(bold(cyan("Welcome!")))
    io.write(yellow("Enter a number: "))

    local input = io.readline()
    local n = tonumber(input)

    if n then
        io.print("Squared: " .. green(tostring(n * n)))
        return 0
    else
        io.print(red("Error: ") .. "not a number")
        return 1
    end
end

return { main = main }

System Information

Access runtime stats with the system module:

# Add to entry definition
modules:
  - io
  - system
local io = require("io")
local system = require("system")

local function main()
    io.print("Host: " .. system.process.hostname())
    io.print("CPUs: " .. system.runtime.cpu_count())
    io.print("Goroutines: " .. system.runtime.goroutines())

    local mem = system.memory.stats()
    io.print("Memory: " .. string.format("%.1f MB", mem.heap_alloc / 1024 / 1024))

    return 0
end

return { main = main }

Exit Codes

Return from main() to set the exit code:

local function main()
    if error_occurred then
        return 1  -- Error
    end
    return 0      -- Success
end

I/O Reference

Function Description
io.print(...) Write to stdout with newline
io.write(...) Write to stdout without newline
io.eprint(...) Write to stderr with newline
io.readline() Read line from stdin
io.flush() Flush output buffer

CLI Flags

Flag Description
wippy run -x app:cli Run CLI process (auto-detects terminal.host)
wippy run -x app:cli --host app:term Explicit terminal host
wippy run -x app:cli -v With verbose logging

Next Steps