# Main Entry Point for the Aqua CLI: A Deep Dive into cmd/aqua/main.go

> Discover the main entry point for the aqua CLI in cmd/aqua/main.go. Understand how the application bootstraps and delegates execution to pkg/cli/runner.go for seamless operation.

- Repository: [aquaproj/aqua](https://github.com/aquaproj/aqua)
- Tags: deep-dive
- Published: 2026-02-25

---

**The main entry point for the aqua CLI is the `main` function in [`cmd/aqua/main.go`](https://github.com/aquaproj/aqua/blob/main/cmd/aqua/main.go), which bootstraps the application by calling `urfave.Main` and delegates execution to `cli.Run` in [`pkg/cli/runner.go`](https://github.com/aquaproj/aqua/blob/main/pkg/cli/runner.go).**

Understanding how the [aquaproj/aqua](https://github.com/aquaproj/aqua) CLI initializes is essential for contributors and advanced users who want to trace command execution or debug startup behavior. The repository follows a clean separation between the binary entry point and the core application logic, leveraging a wrapper around the popular `urfave/cli` library.

## Where the Aqua CLI Starts: cmd/aqua/main.go

The compiled binary begins execution in **[`cmd/aqua/main.go`](https://github.com/aquaproj/aqua/blob/main/cmd/aqua/main.go)**. This file contains the standard Go `main` function responsible for the initial bootstrap.

The implementation is concise and delegates immediately to a helper:

```go
func main() {
    urfave.Main("aqua", version, cli.Run)
}

```

Here, `urfave.Main` performs three critical tasks:
1.  Sets up global flags and the help system
2.  Creates the command tree structure
3.  Invokes **`cli.Run`** as the core execution handler

This design keeps the entry point minimal while allowing complex initialization logic to reside in the `pkg/cli` package.

## The Runner: pkg/cli/runner.go

The actual command handling logic lives in **[`pkg/cli/runner.go`](https://github.com/aquaproj/aqua/blob/main/pkg/cli/runner.go)**. This file defines the `Run` function that `urfave.Main` invokes after parsing arguments.

The function signature accepts context, a structured logger, and environment configuration:

```go
func Run(ctx context.Context, logger *slogutil.Logger, env *urfave.Env) error {
    // …initialises the CLI app, registers sub‑commands, and runs the app
}

```

Inside `Run`, the application:
- Initializes the CLI application instance
- Registers all subcommands (such as `install`, `update`, `exec`, and `generate`)
- Starts the command execution loop based on user input

This architecture separates the concerns of binary initialization from command routing and business logic.

## Bootstrapping Sequence

The complete startup flow from binary execution to command handling follows this sequence:

1.  **[`cmd/aqua/main.go`](https://github.com/aquaproj/aqua/blob/main/cmd/aqua/main.go)** → `main()` function executes
2.  Calls `urfave.Main("aqua", version, cli.Run)` to initialize the CLI framework
3.  `urfave.Main` creates a `urfave.App` instance and invokes **[`pkg/cli/runner.go`](https://github.com/aquaproj/aqua/blob/main/pkg/cli/runner.go)** → `Run`
4.  `Run` registers all subcommands and starts the CLI loop to process the specific command (e.g., `aqua install`)

## Practical Examples

Every command you run triggers this entry point sequence. Here are examples that exercise the bootstrap code:

```bash

# Show version information - triggers main.go and cli.Run

aqua --version

# Install a tool - routes through the full bootstrap to the install command

aqua install gh

# Display help output generated by the urfave framework initialized in main.go

aqua --help

```

These commands demonstrate how the binary entry point in [`cmd/aqua/main.go`](https://github.com/aquaproj/aqua/blob/main/cmd/aqua/main.go) ultimately delegates to the specific command implementations located in `pkg/cli/commands/`.

## Summary

-   The **main entry point** for the aqua CLI is the `main` function in **[`cmd/aqua/main.go`](https://github.com/aquaproj/aqua/blob/main/cmd/aqua/main.go)**.
-   This file delegates initialization to `urfave.Main`, which sets up the CLI framework and invokes **`cli.Run`**.
-   The **`Run` function in [`pkg/cli/runner.go`](https://github.com/aquaproj/aqua/blob/main/pkg/cli/runner.go)** contains the core logic for registering subcommands and executing the application.
-   Individual command implementations (install, update, exec, etc.) reside in **`pkg/cli/commands/`** and are orchestrated by the runner.

## Frequently Asked Questions

### What file contains the main function for aqua?

The `main` function is located in **[`cmd/aqua/main.go`](https://github.com/aquaproj/aqua/blob/main/cmd/aqua/main.go)**. This is the standard Go entry point that executes when you run the `aqua` binary, and it immediately delegates to the `urfave.Main` helper to bootstrap the CLI.

### How does aqua delegate command handling after the entry point?

After [`main.go`](https://github.com/aquaproj/aqua/blob/main/main.go) calls `urfave.Main`, the framework invokes **`cli.Run`** from **[`pkg/cli/runner.go`](https://github.com/aquaproj/aqua/blob/main/pkg/cli/runner.go)**. The `Run` function initializes the CLI application, registers all available subcommands (such as install, update, and exec), and then executes the specific command requested by the user.

### What library does aqua use for CLI framework?

Aqua uses a wrapper around **urfave/cli** (also known as `cli` package). The `urfave.Main` function in [`cmd/aqua/main.go`](https://github.com/aquaproj/aqua/blob/main/cmd/aqua/main.go) abstracts the urfave/cli setup, handling global flags, help generation, and command routing before delegating to the custom `Run` logic in the `pkg/cli` package.

### Where are individual subcommands defined in aqua?

Individual subcommand implementations are located in the **`pkg/cli/commands/`** directory. These command definitions are imported and registered within the **`Run` function in [`pkg/cli/runner.go`](https://github.com/aquaproj/aqua/blob/main/pkg/cli/runner.go)**, which orchestrates their execution based on the arguments passed through the entry point.