Skip to main content

Unified Task Runner for Custom Commands

· 2 min read
Erik Osterman
Founder @ Cloud Posse

Custom commands now support structured task syntax with per-step configuration including timeouts, retry logic, working directories, and authentication identities.

What Changed

We've introduced a new pkg/runner package that provides a unified task execution layer for custom commands. This enables structured syntax alongside the existing simple string syntax:

Simple syntax (still works):

commands:
- name: hello
steps:
- "echo Hello world!"
- "echo Goodbye!"

New structured syntax:

commands:
- name: deploy
steps:
- name: validate
command: terraform validate
timeout: 30s
- name: apply
command: terraform apply -auto-approve
timeout: 10m
working_directory: /app/infra

Mixed syntax:

commands:
- name: build
steps:
- "echo Starting build..."
- name: compile
command: make build
timeout: 5m
- "echo Build complete!"

With retry for flaky operations:

commands:
- name: sync
steps:
- name: upload
command: aws s3 sync ./dist s3://mybucket
retry:
max_attempts: 3
initial_delay: 1s
max_delay: 30s

Using atmos commands with identity:

commands:
- name: deploy-all
steps:
- name: deploy-vpc
command: terraform apply vpc
type: atmos
stack: prod-us-east-1
identity: production-deployer
timeout: 15m

Why This Matters

This change lays the groundwork for unifying custom commands and workflows under a shared execution model. The new Task type supports:

  • Timeouts - Prevent runaway commands with per-step time limits
  • Working directories - Execute steps in specific directories
  • Task types - shell (default) for shell commands, atmos for atmos CLI commands with stack support
  • Retry configuration - Built-in retry support with configurable attempts and backoff delays
  • Identity - Per-step authentication identity for multi-account deployments
  • Stack - Specify which stack to use for atmos type commands

For Contributors

The new pkg/runner package provides:

  • Task and Tasks types with flexible YAML unmarshaling
  • CommandRunner interface for testable command execution
  • Run() and RunAll() functions with context-based timeout enforcement
  • Full mapstructure decode hook support for Viper integration

This is an internal architectural improvement with full backward compatibility for existing custom command configurations.

For more details, see the Custom Commands documentation.