# 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. `--help` and `--version` work this way.
- **Setting flags** parse a value and make it available to every handler through
  the Effect context. `--log-level` works 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`.

```ts
// app.ts
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
)
```

```sh
$ 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 runs
```
**Action flags exit; setting flags do not:** When an action flag is present, the first matching action runs and the program
returns immediately — your handler is skipped. A setting flag never
short-circuits; it only contributes a value the handler can read.

## 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

`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.

```ts
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-1
```

If you use `Flag.optional` instead of `Flag.withDefault`, the service value is an
`Option`:

```ts
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

`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`.

```ts
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             => running
```
**Mixing actions and settings:** You can attach a single array containing both kinds:
`Command.withGlobalFlags([VerboseAction, Region])`. If an action flag is present
it wins and exits before any handler or setting value is observed.

## 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.
- `withGlobalFlags` flags 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.setting` allocates a **distinct** context service.
  Define the setting once and reuse the exported value wherever a handler needs
  to read it.
**Caution:** Because `setting` creates a fresh service per call, calling it twice for the
"same" flag gives you two unrelated services. Export one `Region` constant and
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](https://effect.plants.sh/cli/subcommands/) for how flags attached to a parent command
flow down to children.

---

## GlobalFlag reference

The `GlobalFlag` module (`effect/unstable/cli`) defines global flags and the
built-ins. Import it as a namespace:

```ts
```

### `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`.

```ts
const WhoAmI = GlobalFlag.action({
  flag: Flag.boolean("whoami"),
  run: (_value, ctx) => Console.log(ctx.command.name)
})
// WhoAmI._tag => "Action"
```

### `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>`.

```ts
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 value
```

<Aside type="note">
The service id is namespaced as
`effect/unstable/cli/GlobalFlag/<id>` at the type level
(`GlobalFlag.Setting.Identifier<Id>`). `withGlobalFlags` uses this to remove the
setting from the command's requirements.

### `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.

```ts
declare const ctx: GlobalFlag.HandlerContext
ctx.command     // => the Command.Any that was matched
ctx.commandPath // => ReadonlyArray<string>, e.g. ["tool", "deploy"]
ctx.version     // => "1.0.0" (the version passed to Command.run)
```

### `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`.

```ts
declare const f: GlobalFlag.GlobalFlag<unknown>
f._tag // => "Action" | "Setting"
```

### `GlobalFlag.Help`

The built-in `--help` / `-h` action flag. Prints help documentation for the
active command path and exits.

```ts
GlobalFlag.Help._tag // => "Action"
// Triggered by: $ tool --help   or   $ tool -h
```

### `GlobalFlag.Version`

The built-in `--version` action flag. Prints `<name> <version>` using the version
passed to `Command.run` and exits.

```ts
GlobalFlag.Version._tag // => "Action"
// $ tool --version   => tool 1.0.0
```

### `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.

```ts
GlobalFlag.Completions._tag // => "Action"
// $ tool --completions zsh   => prints a zsh completion script
```

### `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.

```ts
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](https://effect.plants.sh/observability/logging/) for how log levels filter output.

### `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.

```ts
GlobalFlag.BuiltIns.map((f) => f._tag)
// => ["Action", "Action", "Action", "Setting"]
```

### `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.

```ts
type RegionId = GlobalFlag.Setting.Identifier<"region">
// => "effect/unstable/cli/GlobalFlag/region"
```

---

## 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.

```ts
```

### `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.

```ts
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 you
```

### `Completions.Shell`

The supported shell names for script generation: `"bash" | "zsh" | "fish"`.

```ts
const shell: Completions.Shell = "zsh" // "bash" | "zsh" | "fish"
```

### `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.

```ts
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`

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.

```ts
const flag: Completions.FlagDescriptor = {
  name: "format",
  aliases: ["f"],
  description: "Output format",
  type: { _tag: "Choice", values: ["json", "text"] }
}
```

### `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.

```ts
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`

Describes a positional argument: its `name`, optional `description`, whether it is
`required`, whether it is `variadic`, and its value `type` (an `ArgumentType`).

```ts
const arg: Completions.ArgumentDescriptor = {
  name: "file",
  description: "File to process",
  required: true,
  variadic: false,
  type: { _tag: "Path", pathType: "file" }
}
```

### `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`.

```ts
const str: Completions.ArgumentType = { _tag: "String" }
const dir: Completions.ArgumentType = { _tag: "Path", pathType: "directory" }
```
**Tip:** For most CLIs you never touch `Completions` directly: define your command with
`Command.make`, `Flag.*`, and `Argument.*`, and the built-in `--completions`
flag generates correct scripts from those definitions. Use
`Completions.generate` only when you assemble descriptors by hand.