What Is the aqua exec Command? Purpose and Implementation in Aqua

The aqua exec command is an internal utility used by aqua-proxy to locate, lazily install if necessary, and execute tools managed by the Aqua package manager.

The aqua exec command serves as the execution bridge in the aquaproj/aqua ecosystem. While end users typically interact with Aqua through simple command calls like gh version, the actual process of finding the binary in Aqua's cache, verifying policies, and spawning the process is handled internally by this command.

Understanding the aqua exec Command Architecture

The aqua exec command operates as the runtime engine that translates user tool invocations into actual binary execution. When a user runs an executable that Aqua has downloaded, the aqua-proxy wrapper invokes aqua exec behind the scenes to handle the complex orchestration.

This command performs five critical architectural steps: parsing CLI arguments, initializing the execution controller, discovering the tool location, optionally installing missing binaries, and finally spawning the process with retry logic.

How the aqua exec command Works: Step-by-Step Execution Flow

The command follows a strict pipeline defined in the Aqua source code to ensure tools are discovered and executed correctly.

CLI Entry Point and Argument Parsing

In pkg/cli/exec/command.go (lines 73-95), the command definition parses the tool name and its arguments, builds a runtime Param structure, and initializes optional CPU profiling. The command.action function reads arguments, creates a config.Param, and calls the controller to begin execution.

Controller Initialization

The controller.InitializeExecCommandController function creates the execution controller with all required dependencies, including the policy reader, which resolver, and installer. This initialization occurs immediately after argument parsing in the CLI layer.

Tool Discovery via which Service

In pkg/controller/exec/exec.go (lines 41-48), the controller invokes c.which.Which to locate the requested binary within the local Aqua cache. This step determines whether the tool is already available or needs to be installed.

Lazy Installation and Policy Enforcement

If the binary is not present, lines 65-78 in pkg/controller/exec/exec.go trigger c.install to perform on-demand package installation. This process respects policy files and checksum validation before proceeding with execution.

Process Execution with Retry Logic

Finally, c.execCommandWithRetry (lines 54-66) handles the actual process spawning using the osexec wrapper, or a low-level execve(2) call when enabled. The controller implements retry logic if the process fails to start, ensuring robust execution.

Practical Examples of Using the aqua exec command

While primarily an internal mechanism, understanding how to interact with this command helps with debugging and advanced scripting.

Automatic Usage via aqua-proxy

When you run a tool managed by Aqua, such as gh version, the aqua-proxy wrapper automatically invokes the execution command behind the scenes:


# What happens internally when you type:

$ gh version

# aqua-proxy executes:

$ aqua exec -- gh version

This transparent handling ensures users can run tools without knowing their exact installation paths in the Aqua cache.

Manual Invocation for Debugging

Developers can call the command directly to troubleshoot tool resolution or verify which binary Aqua selects:


# Directly execute a specific tool through Aqua

$ aqua exec -- gh version

# This bypasses the proxy and shows any resolution errors directly

Programmatic Usage in Go

The controller can be initialized and invoked programmatically, as implemented in the CLI:

import (
    "context"
    "net/http"
    "github.com/aquaproj/aqua/v2/pkg/config"
    "github.com/aquaproj/aqua/v2/pkg/controller"
    "github.com/aquaproj/aqua/v2/pkg/runtime"
)

func runTool() error {
    ctx := context.Background()
    param := &config.Param{}
    
    // Initialize the execution controller
    ctrl, err := controller.InitializeExecCommandController(
        ctx,
        nil, // logger
        param,
        http.DefaultClient,
        runtime.New(),
    )
    if err != nil {
        return err
    }

    // Execute "gh version"
    return ctrl.Exec(ctx, nil, param, "gh", "version")
}

The Exec method implements the complete workflow from discovery to process spawning.

Key Source Files and Implementation Details

The execution logic spans several packages within the aquaproj/aqua repository:

These files collectively implement the bridge between Aqua's declarative package management and actual tool execution.

Summary

  • The aqua exec command is an internal utility that translates user tool invocations into actual binary execution within the Aqua ecosystem.
  • It operates as the execution engine behind aqua-proxy, handling tool discovery, lazy installation, and process spawning.
  • The command implements a five-stage pipeline: CLI parsing, controller initialization, tool discovery via which, optional lazy installation, and execution with retry logic.
  • Key implementation files include pkg/cli/exec/command.go for the CLI layer and pkg/controller/exec/exec.go for the core execution logic.
  • While primarily used internally, the command can be invoked manually for debugging or accessed programmatically via the Go controller interface.

Frequently Asked Questions

Is aqua exec meant to be run directly by users?

No, aqua exec is primarily an internal command used by aqua-proxy. End users typically run tools directly (e.g., gh version), and the proxy automatically invokes aqua exec behind the scenes to handle the complex orchestration of finding and executing the correct binary. However, advanced users can invoke it manually for debugging purposes.

How does aqua exec handle missing tools?

The command implements lazy installation through the controller's installation logic. When c.which.Which fails to locate a binary in the Aqua cache, the controller triggers c.install to download and install the package on-demand. This process respects policy files and performs checksum validation before making the binary available for execution.

What is the relationship between aqua exec and aqua-proxy?

aqua-proxy acts as a lightweight wrapper that intercepts tool calls and delegates the actual execution work to aqua exec. When you run a managed tool like gh, the proxy invokes aqua exec -- gh <args> to handle the complex logic of finding the correct version in the cache, installing if necessary, and spawning the process.

Where is the execution logic implemented in the source code?

The core execution logic resides in pkg/controller/exec/exec.go, specifically within the Exec method and helper functions like execCommandWithRetry. The CLI entry point and controller initialization are defined in pkg/cli/exec/command.go, while tool resolution happens in pkg/controller/which/which.go and installation logic in pkg/installpackage/installer.go.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →