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
| Category | Step Types | Description |
|---|---|---|
| Command | atmos, shell, exec, container | Run Atmos, shell, process-replacement, or container operations |
| Interactive | input, confirm, choose, filter, file, write | Collect user input in a TTY |
| UI | toast, markdown, alert, title, clear, linebreak, stage, sleep, env, exit | Display status, control terminal output, or influence workflow control flow |
| Output | spin, table, pager, format, join, style, log | Format, 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.
interactiveAttach 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.ttyAllocate 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'soutputmode does not apply (the session writes directly to your terminal), and the step produces no capturable output for later steps. Combine withinteractive: truefor full terminal sessions —tty: truealone does not forward your keystrokes.
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 supervisorSecret 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 launcherNative 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_SHLVLis not incremented (the session replaces Atmos rather than nesting under it). Tools likeaws ssm start-sessionbehave exactly as when run directly.
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 }}