Global Flags & Completions
A global flag is a flag that applies across the whole command tree rather than to a single command. There are two kinds:
- Action flags run an effect and short-circuit the program — the command
handler never runs.
--helpand--versionwork this way. - Setting flags parse a value and make it available to every handler through
the Effect context.
--log-levelworks this way.
You never wire up the built-ins yourself: Command.run (and Command.runWith)
prepend GlobalFlag.Help, GlobalFlag.Version, GlobalFlag.Completions, and
GlobalFlag.LogLevel automatically. The moment you call Command.run, your CLI
already supports --help, --version, --completions, and --log-level.
import { NodeRuntime, NodeServices } from "@effect/platform-node"import { Console, Effect } from "effect"import { Command, Flag } from "effect/unstable/cli"
const greet = Command.make("greet", { name: Flag.string("name")}, (config) => Console.log(`Hello, ${config.name}!`))
// Command.run wires up --help / --version / --completions / --log-level for free.Command.run(greet, { version: "1.0.0" }).pipe( Effect.provide(NodeServices.layer), NodeRuntime.runMain)$ greet --version # => greet 1.0.0 (Version action, exits)$ greet --help # => prints help doc (Help action, exits)$ greet --name Alice # => Hello, Alice!$ greet --log-level debug --name Alice # => sets minimum log level, then runsAdding your own global flags
Section titled “Adding your own global flags”Use Command.withGlobalFlags to attach custom global flags to a command. They
apply to that command and all of its descendants, which makes them the right
tool for cross-cutting concerns like --region, --config, or --verbose.
A setting flag handlers can read
Section titled “A setting flag handlers can read”GlobalFlag.setting(id)({ flag }) returns a value that is both the global flag
definition and a Context.Service you yield* inside a handler to read the
parsed value. Attaching it with withGlobalFlags removes its service requirement
from the command’s R channel, so the program stays fully provided.
import { Console, Effect, Option } from "effect"import { Command, Flag, GlobalFlag } from "effect/unstable/cli"
// The returned `Region` is a global flag AND a Context.Service.const Region = GlobalFlag.setting("region")({ flag: Flag.string("region").pipe(Flag.withDefault("us-east-1"))})
const deploy = Command.make("deploy", {}, () => Effect.gen(function* () { // Read the parsed --region value from context. const region = yield* Region // => "us-east-1" (default) or the passed value yield* Console.log(`Deploying to ${region}`) })).pipe( // Attaching the flag discharges `Region` from the command's requirements. Command.withGlobalFlags([Region]))
// $ deploy => Deploying to us-east-1// $ deploy --region eu-west-1 => Deploying to eu-west-1If you use Flag.optional instead of Flag.withDefault, the service value is an
Option:
const Region = GlobalFlag.setting("region")({ flag: Flag.string("region").pipe(Flag.optional)})
const deploy = Command.make("deploy", {}, () => Effect.gen(function* () { const region = yield* Region // => Option.some("eu-west-1") when passed, Option.none() otherwise yield* Console.log(Option.getOrElse(region, () => "default region")) })).pipe(Command.withGlobalFlags([Region]))An action flag that short-circuits
Section titled “An action flag that short-circuits”GlobalFlag.action({ flag, run }) runs run(value, context) when the flag is
present and then exits — the handler is skipped. The second argument is a
HandlerContext carrying the resolved command, commandPath, and version.
import { Console, Effect } from "effect"import { Command, Flag, GlobalFlag } from "effect/unstable/cli"
const License = GlobalFlag.action({ flag: Flag.boolean("license").pipe( Flag.withDescription("Print license information") ), run: (_value, ctx) => Console.log(`${ctx.command.name} ${ctx.version} — MIT License`)})
const app = Command.make("tool", {}, () => Console.log("running")).pipe( Command.withGlobalFlags([License]))
// $ tool --license => tool 1.0.0 — MIT License (handler is NOT run)// $ tool => runningPrecedence and scope
Section titled “Precedence and scope”- Built-ins are processed in the order of
GlobalFlag.BuiltIns:Help,Version,Completions,LogLevel. The first present action runs and the program exits. withGlobalFlagsflags apply to the attached command and every descendant. A global flag passed outside the scope where it was declared is rejected with a help error.- Each call to
GlobalFlag.settingallocates a distinct context service. Define the setting once and reuse the exported value wherever a handler needs to read it.
Shell completions
Section titled “Shell completions”The built-in --completions <shell> action prints a shell completion script to
stdout. Effect derives the completion descriptor from your command tree
automatically, so no extra wiring is needed.
$ tool --completions bash # prints a bash completion script$ tool --completions zsh # prints a zsh completion script$ tool --completions fish # prints a fish completion script$ tool --completions sh # `sh` is normalized to `bash`Installing the script
Section titled “Installing the script”Either evaluate the output in your current shell session, or write it to your shell’s completion directory so it loads on every new shell.
# Try it in the current session:eval "$(tool --completions bash)"
# Install persistently (paths vary by OS / shell config):tool --completions bash > /etc/bash_completion.d/tooltool --completions zsh > "${fpath[1]}/_tool"tool --completions fish > ~/.config/fish/completions/tool.fishCompletion scripts complete subcommand names, flag names and aliases, finite
choice values, and file/directory paths — all derived from the same Param
definitions that drive parsing and help.
Attaching global flags: Command.withGlobalFlags
Section titled “Attaching global flags: Command.withGlobalFlags”Command.withGlobalFlags(flags) adds global flags to a command scope. For every
setting flag in the array, the matching Context.Service requirement is
removed from the command’s R channel (Exclude<R, ...Identifier>), so the
program is fully provided once attached. Available both data-first and
data-last (pipeable).
import { Console, Effect } from "effect"import { Command, Flag, GlobalFlag } from "effect/unstable/cli"
const Verbose = GlobalFlag.setting("verbose")({ flag: Flag.boolean("verbose").pipe(Flag.withDefault(false))})
// Data-last (pipe) form:const a = Command.make("deploy", {}, () => Effect.gen(function* () { if (yield* Verbose) yield* Console.log("verbose mode on") })).pipe(Command.withGlobalFlags([Verbose]))
// Data-first form:const b = Command.withGlobalFlags(a, [Verbose])See Subcommands for how flags attached to a parent command flow down to children.
GlobalFlag reference
Section titled “GlobalFlag reference”The GlobalFlag module (effect/unstable/cli) defines global flags and the
built-ins. Import it as a namespace:
import { GlobalFlag } from "effect/unstable/cli"GlobalFlag.action
Section titled “GlobalFlag.action”Creates an action global flag from { flag, run }. run(value, context) runs
when the flag is present and the program exits afterward; value is the parsed
flag value and context is a HandlerContext.
import { Console } from "effect"import { Flag, GlobalFlag } from "effect/unstable/cli"
const WhoAmI = GlobalFlag.action({ flag: Flag.boolean("whoami"), run: (_value, ctx) => Console.log(ctx.command.name)})// WhoAmI._tag => "Action"GlobalFlag.setting
Section titled “GlobalFlag.setting”GlobalFlag.setting(id)({ flag }) returns a value that is both a setting global
flag and a Context.Service for the parsed value. Reading it in a handler is
yield* <theSetting>.
import { Flag, GlobalFlag } from "effect/unstable/cli"
const Format = GlobalFlag.setting("format")({ flag: Flag.string("format").pipe(Flag.withDefault("text"))})// Format._tag => "Setting"// Format.id => "format"// In a handler: const fmt = yield* Format // => "text" or the passed valueGlobalFlag.HandlerContext
Section titled “GlobalFlag.HandlerContext”The context passed as the second argument to an action’s run. It exposes the
resolved command, the active command path, and the configured version.
import { GlobalFlag } from "effect/unstable/cli"
declare const ctx: GlobalFlag.HandlerContextctx.command // => the Command.Any that was matchedctx.commandPath // => ReadonlyArray<string>, e.g. ["tool", "deploy"]ctx.version // => "1.0.0" (the version passed to Command.run)GlobalFlag.Action / GlobalFlag.Setting
Section titled “GlobalFlag.Action / GlobalFlag.Setting”The two members of the GlobalFlag<A> discriminated union, distinguished by
_tag. Action<A> carries { _tag: "Action", flag, run }; Setting<Id, A>
extends Context.Service and carries { _tag: "Setting", id, flag }. You rarely
construct these directly — use action / setting.
import { GlobalFlag } from "effect/unstable/cli"
declare const f: GlobalFlag.GlobalFlag<unknown>f._tag // => "Action" | "Setting"GlobalFlag.Help
Section titled “GlobalFlag.Help”The built-in --help / -h action flag. Prints help documentation for the
active command path and exits.
import { GlobalFlag } from "effect/unstable/cli"
GlobalFlag.Help._tag // => "Action"// Triggered by: $ tool --help or $ tool -hGlobalFlag.Version
Section titled “GlobalFlag.Version”The built-in --version action flag. Prints <name> <version> using the version
passed to Command.run and exits.
import { GlobalFlag } from "effect/unstable/cli"
GlobalFlag.Version._tag // => "Action"// $ tool --version => tool 1.0.0GlobalFlag.Completions
Section titled “GlobalFlag.Completions”The built-in --completions <shell> action flag. Its value is an
Option<"bash" | "zsh" | "fish"> (the choice also accepts sh, normalized to
bash). When present, it derives a CommandDescriptor from the command and
prints the generated script.
import { GlobalFlag } from "effect/unstable/cli"
GlobalFlag.Completions._tag // => "Action"// $ tool --completions zsh => prints a zsh completion scriptGlobalFlag.LogLevel
Section titled “GlobalFlag.LogLevel”The built-in --log-level <level> setting flag (id "log-level"). Accepts
all, trace, debug, info, warn/warning, error, fatal, none. When
set, Command.run provides it as the minimum log level for the handler; you can
also read the parsed Option<LogLevel> directly.
import { Effect, Option } from "effect"import { Command, GlobalFlag } from "effect/unstable/cli"
const app = Command.make("tool", {}, () => Effect.gen(function* () { const level = yield* GlobalFlag.LogLevel // => Option.some("Debug") when run with --log-level debug, else Option.none() yield* Effect.logDebug("debug line will show when --log-level debug") return Option.getOrElse(level, () => "Info") }))See Logging for how log levels filter output.
GlobalFlag.BuiltIns
Section titled “GlobalFlag.BuiltIns”The array of built-in global flags in precedence order: [Help, Version, Completions, LogLevel]. Command.runWith prepends these when collecting and
parsing global flags.
import { GlobalFlag } from "effect/unstable/cli"
GlobalFlag.BuiltIns.map((f) => f._tag)// => ["Action", "Action", "Action", "Setting"]GlobalFlag.Setting.Identifier
Section titled “GlobalFlag.Setting.Identifier”Type-level helper for the service identifier used by setting flags:
`effect/unstable/cli/GlobalFlag/${Id}`. GlobalFlag.BuiltInSettingContext
is Setting.Identifier<"log-level">, the requirement that Command.run and
Command.make automatically discharge.
import type { GlobalFlag } from "effect/unstable/cli"
type RegionId = GlobalFlag.Setting.Identifier<"region">// => "effect/unstable/cli/GlobalFlag/region"Completions reference
Section titled “Completions reference”The Completions module (effect/unstable/cli) is the lower-level script
generation surface. The built-in --completions flag uses it for you; reach for
it directly only when you build descriptors yourself.
import { Completions } from "effect/unstable/cli"Completions.generate
Section titled “Completions.generate”Completions.generate(executableName, shell, descriptor) returns a completion
script as a string, dispatching by shell to the Bash, Zsh, or Fish generator.
It consumes an already-built CommandDescriptor — it does not inspect a
Command directly.
import { Completions } from "effect/unstable/cli"
const descriptor: Completions.CommandDescriptor = { name: "greet", description: "Greet someone", flags: [ { name: "name", aliases: ["n"], description: "Who to greet", type: { _tag: "String" } } ], arguments: [], subcommands: []}
const script = Completions.generate("greet", "bash", descriptor)// => a bash completion script string; printing/installing is up to youCompletions.Shell
Section titled “Completions.Shell”The supported shell names for script generation: "bash" | "zsh" | "fish".
import type { Completions } from "effect/unstable/cli"
const shell: Completions.Shell = "zsh" // "bash" | "zsh" | "fish"Completions.CommandDescriptor
Section titled “Completions.CommandDescriptor”A shell-agnostic tree describing a command: its name, optional description,
its flags, positional arguments, and nested subcommands. This is the shape
generate consumes. When using --completions, Effect derives it from your
command automatically.
import type { Completions } from "effect/unstable/cli"
const root: Completions.CommandDescriptor = { name: "tool", description: undefined, flags: [], arguments: [], subcommands: [ { name: "deploy", description: undefined, flags: [], arguments: [], subcommands: [] } ]}// root.subcommands[0].name => "deploy"Completions.FlagDescriptor
Section titled “Completions.FlagDescriptor”Describes one flag for completion: its name, aliases, optional description,
and value type (a FlagType). Filling in descriptions preserves help text in
the generated completions.
import type { Completions } from "effect/unstable/cli"
const flag: Completions.FlagDescriptor = { name: "format", aliases: ["f"], description: "Output format", type: { _tag: "Choice", values: ["json", "text"] }}Completions.FlagType
Section titled “Completions.FlagType”The value shape of a flag, a tagged union: Boolean, String, Integer,
Float, Date, Choice (with values), or Path (with pathType of
"file" | "directory" | "either"). Shells use this to complete choices and file
paths.
import type { Completions } from "effect/unstable/cli"
const boolean: Completions.FlagType = { _tag: "Boolean" }const choice: Completions.FlagType = { _tag: "Choice", values: ["a", "b"] }const path: Completions.FlagType = { _tag: "Path", pathType: "file" }Completions.ArgumentDescriptor
Section titled “Completions.ArgumentDescriptor”Describes a positional argument: its name, optional description, whether it is
required, whether it is variadic, and its value type (an ArgumentType).
import type { Completions } from "effect/unstable/cli"
const arg: Completions.ArgumentDescriptor = { name: "file", description: "File to process", required: true, variadic: false, type: { _tag: "Path", pathType: "file" }}Completions.ArgumentType
Section titled “Completions.ArgumentType”The value shape of a positional argument, a tagged union: String, Integer,
Float, Date, Choice (with values), or Path (with pathType). Same
shapes as FlagType minus Boolean.
import type { Completions } from "effect/unstable/cli"
const str: Completions.ArgumentType = { _tag: "String" }const dir: Completions.ArgumentType = { _tag: "Path", pathType: "directory" }