Skip to content

Input Sources

A CLI gets its data from all over the place — flags you type, env vars, config files, piped input. Knowing where values come from (and which one wins) is how you build tools that work on someone's laptop and in a CI pipeline.

argv — The Argument Vector

When you type a command, your shell splits it into a list of strings and passes it to the program. This list is called argv (argument vector).

bash
mycli greet Alice --loud

The program receives:

json
["mycli", "greet", "Alice", "--loud"]

That's it. Just strings. The CLI framework's job is to parse these strings into something meaningful — commands, arguments, flags, values.

Why "vector"?

It's just a fancy word for "ordered list."

The name comes from C, where argv was literally an array of character pointers. You'll see it everywhere in CLI programming.

Environment Variables

Environment variables are key-value pairs that exist outside your command. They're set in your shell, your .bashrc, your CI config, your Docker setup — all over the place.

bash
export API_KEY=abc123
mycli upload photo.jpg  # can read API_KEY without you typing it

Why use env vars?

  • Secrets — you don't want passwords in your shell history
  • Configuration — same command, different behavior per environment
  • CI/CD — automated systems set env vars instead of typing flags

A well-designed CLI lets you do:

bash
# These are equivalent:
mycli upload --region eu photo.jpg
MYCLI_UPLOAD_REGION=eu mycli upload photo.jpg

Same result, different input source. The flag wins if both are present.

Config Files

For settings you use every time, typing flags gets old fast. Config files solve this:

For example, in ~/.config/mycli/config.json on Unix or %APPDATA%\\mycli\\config.json on Windows:

json
{
  "region": "eu",
  "format": "json"
}

Now mycli upload photo.jpg reads region from the config file automatically. No flag needed.

Common config file locations:

  • Project-local: ./.mycli.json, ./mycli.config.json
  • User-level: ~/.config/mycli/config.json (Linux/Mac) or %APPDATA%\\mycli\\config.json (Windows)
  • System-level: /etc/mycli/config.json

On Linux and Mac, the convention follows XDG. On Windows, the equivalent user config location is usually %APPDATA%. You don't need to memorize it; good CLIs handle the search automatically.

stdin — Standard Input

Programs can read data piped in from other programs:

bash
cat file.txt | grep "error"
echo '{"name":"Alice"}' | mycli process

The | (pipe) connects the output of one program to the input of the next. The receiving program reads from stdin (standard input) — a stream of bytes, like reading from a file that happens to be another program's output.

This is powerful because it lets you chain small tools together:

bash
curl -s https://api.example.com/data | jq '.items[]' | sort | head -5

Four programs, connected by pipes, each doing one thing well.

Interactive Prompts

Sometimes a CLI asks you questions:

bash
$ mycli init
? Project name: my-app
? Language: TypeScript
? Include tests? Yes

This is interactive input — the program waits for you to type something. It only works when there's a human at the keyboard. If the program is running in CI or piped input, there's no one to answer.

Good CLIs handle this gracefully:

  • In a terminal → prompt the user
  • In CI/piped → use defaults, env vars, or fail with a clear error

Resolution Order

When a value can come from multiple places, there's a natural priority.

The first source that has a value wins.

Flags:

text
1. Command-line flag     (highest — you typed it explicitly)
2. Environment variable  (set for this session/environment)
3. Config file           (persistent settings)
4. Interactive prompt    (ask the user)
5. Default value         (fallback)

Positional arguments that opt into extra sources:

Only positional arguments that call methods like .stdin() or .env() participate in this priority chain. Positional args without those opt-ins remain CLI-only and therefore stay required-or-optional based on their own declaration.

text
1. Command-line argument token
2. STDIN
3. Environment variable
4. Default value

What's Next?

Released under the MIT License.