Skip to main content

steps

The steps field is the work a custom command performs. Custom commands run steps through the same engine as workflows and support the same step types — from plain shell and Atmos commands to interactive prompts, spinners, tables, and container operations.

Simple and structured steps

In its simplest form, steps is a list of shell command strings:

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

For anything beyond a plain shell command, use the structured form — an object per step with a type and the fields for that type. The two forms can be mixed in the same list:

commands:
- name: deploy
description: Deploy with a confirmation prompt
steps:
- type: confirm
name: proceed
prompt: "Deploy to production?"
default: false
- "echo Deploying..."
- type: atmos
command: terraform apply vpc -s plat-ue2-prod

A structured step is the same object documented for workflows. See the step reference for the common step fields (name, type, command, output, and more).

Step types

Custom commands and workflows share one step-type registry, so every step type works the same in both. The full reference lives with the workflow docs — see the step type reference for each type's fields, examples, and behavior.

Atmos supports 25+ step types for workflows and custom command steps. Step type values live in the type field on a step object; type-specific fields stay on that same step object.

Step Types Overview

CategoryStep TypesDescription
Commandatmos, shell, exec, containerRun Atmos, shell, process-replacement, or container operations
Interactiveinput, confirm, choose, filter, file, writeCollect user input in a TTY
UItoast, markdown, alert, title, clear, linebreak, stage, sleep, env, exitDisplay status, control terminal output, or influence workflow control flow
Outputspin, table, pager, format, join, style, logFormat, render, log, or capture output

Status Messages

Use type: toast for themed status messages. success, info, warn, and error are level values, not step types:

steps:
- name: done
type: toast
level: success
content: Deployment complete.

Interactive Steps

Interactive step types require a TTY. In CI, avoid prompts by using non-interactive command steps, defaults, or values supplied through environment variables.

Full Reference

See the step type reference for the complete list, examples, required fields, and type-specific behavior.

Interactive and TTY Steps

Some commands need to take over the terminal — SSM sessions, SSH, database consoles, vim, top. By default, shell steps run with Atmos managing output (masking, capture), which mangles full-screen terminal applications and means Ctrl-C interrupts Atmos itself instead of the command.

Steps support docker-style tty and interactive fields to hand the terminal to the command:

commands:
- name: ssh
description: Open an SSM session to an instance
arguments:
- name: instance_id
description: EC2 instance ID
required: true
steps:
- type: shell
tty: true
interactive: true
command: "aws ssm start-session --target {{ .Arguments.instance_id }}"

With this configuration, atmos ssh i-1234567890 behaves like docker run -it: the session gets a real TTY, keystrokes (including Ctrl-C) go to the session instead of Atmos, and the session's exit code becomes the Atmos exit code.

interactive

Attach host stdin to the step and let the step handle Ctrl-C (like docker -i). While the step runs, Atmos suspends its own interrupt handling so pressing Ctrl-C interrupts the step's process, not Atmos. Output is still masked and captured normally.

tty

Allocate a pseudo-terminal for the step (like docker -t). The command sees a real TTY on stdin/stdout, so full-screen and cursor-addressing programs render correctly. Secret masking is still applied to session output. The step's output mode does not apply (the session writes directly to your terminal), and the step produces no capturable output for later steps. Combine with interactive: true for full terminal sessions — tty: true alone does not forward your keystrokes.

Platform support

Pseudo-terminals are supported on macOS and Linux. On Windows, tty: true falls back to attaching the real console streams directly; the session still works, but secret masking is unavailable in that mode (Atmos prints a warning when masking is enabled).

The same fields work in workflow shell steps.

Replacing the Atmos Process (type: exec)

For commands that should fully take over — where Atmos is purely a launcher — use a step of type: exec. The command replaces the Atmos process entirely (shell exec semantics): on macOS and Linux it's a true execve of the system shell, so the command inherits your terminal, environment, and working directory natively, job control (Ctrl-Z) works exactly as if you'd run the command yourself, and its exit code becomes the Atmos exit code with no intermediary.

commands:
- name: ssh
description: Open an SSM session to an instance
arguments:
- name: instance_id
description: EC2 instance ID
required: true
steps:
- type: exec
command: "aws ssm start-session --target {{ .Arguments.instance_id }}"

Choose between the two models:

tty: true + interactive: true — Atmos as supervisor

Secret masking applied to session output, multiple steps before and after the session, retries and timeouts available. The session runs under a pseudo-terminal proxied by Atmos.

type: exec — Atmos as launcher

Native terminal behavior with zero proxy overhead. Because the process is replaced: the exec step must be the last step (validated — later steps could never run), no secret masking applies to its output, no steps run after it, and supervisor-only fields (tty, interactive, retry, timeout, output) are rejected. ATMOS_SHLVL is not incremented (the session replaces Atmos rather than nesting under it). Tools like aws ssm start-session behave exactly as when run directly.

Platform support

On Windows, which has no execve, type: exec is emulated: the command runs with the real console streams attached, Atmos waits while the command owns Ctrl-C, and the command's exit code is propagated as the Atmos exit code.

Extended Step Types

Beyond shell, atmos, and exec, custom commands support the full set of extended step types — the same ones workflows use — enabling interactive CLI wizards directly in your custom commands. Use these step types to collect user input, display formatted output, and control execution flow.

Example: Interactive Deployment Command

commands:
- name: deploy-wizard
description: Interactive deployment wizard
steps:
# Collect environment selection
- name: env
type: choose
prompt: "Select target environment"
options:
- dev
- staging
- prod
default: dev

# Show warning for production
- name: prod_warning
type: toast
level: warn
content: "You are about to deploy to PRODUCTION!"

# Confirm deployment
- name: confirm
type: confirm
prompt: "Deploy to {{ .steps.env.value }}?"
default: false

# Run the deployment
- name: deploy
type: atmos
command: terraform apply vpc -s {{ .steps.env.value }}

# Show success message
- name: done
type: toast
level: success
content: "Deployment to {{ .steps.env.value }} completed!"

Example: Multi-Component Deploy with Selection

commands:
- name: deploy-components
description: Select and deploy multiple components
steps:
# Multi-select components
- name: components
type: filter
prompt: "Select components to deploy"
multiple: true
options:
- vpc
- eks
- rds
- s3
- lambda

# Show selected components
- name: summary
type: markdown
content: |
## Deployment Summary

You selected **{{ len .steps.components.values }}** components:
{{ range .steps.components.values }}
- {{ . }}
{{ end }}

# Confirm and deploy
- name: confirm
type: confirm
prompt: "Proceed with deployment?"

# Deploy each component
- type: shell
command: |
{{ range .steps.components.values }}
echo "Deploying {{ . }}..."
{{ end }}

Example: Input Collection

commands:
- name: create-ticket
description: Create a deployment ticket
steps:
- name: title
type: input
prompt: "Ticket title"
placeholder: "Brief description of the change"

- name: description
type: write
prompt: "Detailed description"

- name: priority
type: choose
prompt: "Priority level"
options: [low, medium, high, critical]
default: medium

- type: toast
level: success
content: |
Ticket created:
Title: {{ .steps.title.value }}
Priority: {{ .steps.priority.value }}