docs/guides/lifecycle_hooks.md

# Lifecycle hooks

Run code before or after `run/2`. Handy for setup, teardown, logging, and
sharing state across a command tree.

## `before_run`

Runs after all parsing and validation, just before `run/2`. Receives the
`args` map, must return an `args` map.

```elixir
command "migrate" do
  option :target, type: :string

  before_run fn args ->
    IO.puts("Connecting to database...")
    args
  end
end
```

Use it to inject derived state into `args`, open connections, or log start
events.

## `after_run`

Runs after `run/2` returns. Receives the return value, must return a value
(typically the same one).

```elixir
after_run fn result ->
  IO.puts("Done.")
  result
end
```

Useful for cleanup, timing, or unconditional logging.

## `persistent_before_run` (inherited)

Like `before_run`, but inherited by every descendant command. Declared on
the root; runs for every subcommand invocation, before each command's own
`before_run` hooks.

```elixir
command "my-tool" do
  persistent_before_run fn args ->
    Map.put(args, :start_time, System.monotonic_time(:millisecond))
  end

  subcommand MyTool.Server
  subcommand MyTool.Db
end
```

Every leaf-command handler under `my-tool` sees `args[:start_time]`.

## Multiple hooks

Each hook macro can be called more than once. Hooks run in declaration
order.

```elixir
before_run &add_tracing/1
before_run &add_logger/1
before_run &add_timing/1
```

## Ordering

For a subcommand invocation, the full ordering is:

1. Every ancestor's `persistent_before_run` hooks, root-first.
2. This command's `before_run` hooks, declaration order.
3. `run/2`.
4. This command's `after_run` hooks, declaration order.

There is no `persistent_after_run` -- parent cleanup typically belongs in
the root handler or in explicit supervision logic.

## See also

- [Subcommands](subcommands.md) for how persistent hooks flow through
  nested trees.