Skip to main content

Command System Overview

Overview​

Xec provides a powerful and extensible command system that supports both built-in commands and custom user-defined commands. This section covers the complete command reference for the Xec CLI.

The CLI entry point lives in apps/xec/src/main.ts. Built-in commands are the modules in apps/xec/src/commands/, each registering itself with the commander program. Dynamic commands are loaded by loadDynamicCommands() from apps/xec/src/utils/cli-command-manager.ts, and the BaseCommand class custom commands extend is defined in apps/xec/src/utils/command-base.ts.

Command Types​

Xec supports three types of commands:

1. Built-in Commands​

Core commands that are included with Xec:

  • config - Manage Xec configuration (aliases: conf, cfg)
  • copy - Copy files between targets (alias: cp)
  • docker - Manage Docker containers, images, networks, and Compose via the fluent API (alias: d)
  • forward - Forward ports between local and remote systems (alias: fwd)
  • in - Execute commands inside Docker containers or Kubernetes pods
  • inspect - Inspect configuration and targets
  • logs - View and stream logs from various sources
  • new - Create new Xec artifacts (scripts, configs, tasks)
  • on - Execute commands on SSH hosts
  • run - Run Xec scripts or tasks
  • secrets - Manage secrets and credentials
  • watch - Watch files for changes and execute commands

2. Dynamic Commands​

Commands loaded from .xec/commands/ directory that extend Xec's functionality.

3. Script and Task Execution​

Direct execution of JavaScript/TypeScript files as Xec scripts (xec ./script.ts), and execution of tasks defined in configuration by name (xec deploy).

Command Structure​

All Xec commands follow a consistent structure:

xec [global-options] <command> [command-options] [arguments]

Global Options​

Options that apply to all commands:

  • -v, --verbose - Enable verbose output
  • -q, --quiet - Suppress non-error output
  • --cwd <path> - Set current working directory
  • --no-color - Disable colored output (sets NO_COLOR)
  • -e, --eval <code> - Evaluate code directly
  • --repl - Start interactive REPL

Options such as --dry-run, --profile, or config-file selection are per-subcommand, not global — check xec <command> --help for what each command supports. The configuration file location is controlled by the XEC_CONFIG environment variable rather than a global flag.

Command Resolution​

When you run xec <something>, the CLI resolves it in the following order:

  1. -e/--eval and --repl - Handled first, before any command lookup
  2. Script files - If the first argument ends in .js, .ts, or .mjs, or is an existing file, it runs as a script
  3. Tasks - If the argument is not a registered command but matches a task in configuration, the task runs (task parameters are passed as --param=value or --param value)
  4. Direct command execution - Target-prefixed direct execution (e.g. running a command on a configured target)
  5. Built-in and dynamic commands - Resolved by commander, including aliases
  6. Unknown command - Prints an error with "did you mean" typo suggestions

Target Selection​

Many commands operate on targets (local, SSH, Docker, Kubernetes). The target selection pattern is:

xec <command> <target-pattern> [options]

Target patterns can be:

  • local - Local machine
  • hosts.<name> - SSH host
  • containers.<name> - Docker container
  • pods.<name> - Kubernetes pod
  • hosts.* - All SSH hosts (wildcard)
  • {hosts.web1,hosts.web2} - Multiple targets (brace expansion)

Configuration Integration​

Commands respect configuration from:

  1. .xec/config.yaml - Project configuration
  2. Command-specific defaults in configuration
  3. Environment variables (XEC_*)
  4. Command-line options (highest priority)

Error Handling​

Errors are handled by handleError() from @xec-sh/ops, which prints an actionable message and exits with a code based on the error type:

Exit Codes​

CodeError Type
0Success
1Generic / unhandled error
2ValidationError
3ConfigurationError
4ModuleError
5TaskError
6RecipeError
7NetworkError
8FileSystemError
9TimeoutError
10File not found (ENOENT)
11Permission denied (EACCES)
12Not a directory (ENOTDIR)
13Is a directory (EISDIR)

Error Features​

  • Clear error messages with context
  • Stack traces with --verbose flag
  • Suggestions for common issues
  • Colored output for error types

Command Development​

You can create custom commands by:

  1. Creating a .xec/commands/ directory
  2. Adding JavaScript/TypeScript files that extend BaseCommand (from apps/xec/src/utils/command-base.ts)
  3. Commands are automatically loaded via loadDynamicCommands()

Implementation Details:

  • Commands must extend the BaseCommand class
  • Must implement execute(args: any[]): Promise<void>
  • Command metadata (name, description, options, aliases, examples) is passed to the BaseCommand constructor
  • Throw specific error types for proper exit codes

See Creating Custom Commands for detailed guide.

Common Patterns​

Dry Run Mode​

Several commands support --dry-run to preview actions:

xec copy --dry-run source.txt hosts.* /tmp/

Parallel Execution​

Commands that operate on multiple targets execute in parallel:

xec on "hosts.*" "uptime" # Runs on all hosts in parallel

SSH connections are reused via the connection pool, and output streams are merged in real time.

Streaming Output​

Commands that produce continuous output support streaming:

xec logs containers.app --follow

Interactive Mode​

Some commands provide interactive prompts when options are missing:

xec new # Prompts for artifact type

Next Steps​