atmos ai skill install atmos-stepsAtmos Steps
Atmos steps are the shared execution DSL used by workflows, custom commands,
hooks (kind: step), and cast recordings. When a task involves steps:, step
type, working_directory, env, output, retries, or hook with: payloads,
use this skill together with the surface-specific skill (atmos-workflows,
atmos-custom-commands, or atmos-hooks).
Core Model
A step is a typed action with native fields. Do not treat steps as a place to write shell scripts by default. Prefer the Atmos field that expresses the operation directly:
- Use
working_directoryinstead ofcdfor real execution. Atype: simulatechild of amode: stepscast may displaycd <directory>to narrate a directory transition, but it never changes the working directory of later real steps. - Use
envmaps instead of inlineFOO=bar commandorexport. - Use
output: noneinstead of redirecting to/dev/null. - Use
type: scriptinstead of heredoc shell snippets likepython3 - <<'PY'. - Use
type: workdirwithsourceandresetinstead ofmkdir,rm -rf, andcp. - Use
type: atmosfor Atmos commands instead of shelling out toatmos ...when the surface supports typed steps. - Use Atmos Terraform/OpenTofu
rcconfiguration instead of hand-managing temporary.terraformrcor.tofurcfiles.
Shell is still valid for real shell work, but it should be a conscious fallback when no native step type or field expresses the intent.
Where Steps Run
Step fields are shared, but defaults differ by surface:
- Workflows default command steps to
type: atmos. - Custom command string steps historically behave like shell commands; use structured step objects when you need typed behavior.
- Hooks use an envelope plus
with:. Forkind: step, the hook'stypeselects the step type, whilewith:contains the step-specific fields. - Cast steps can run nested steps and record their terminal output.
Always load the surface-specific skill for invocation rules, path anchoring, and template context.
Common Fields
Most typed steps can use these fields when the step type supports them:
steps:- name: validatetype: scriptinterpreter: python3working_directory: !repo-root .env:ATMOS_LOGS_LEVEL: warnoutput: noneretry:max_attempts: 3delay: 2sscript: |print("ok")
Important shared fields:
name: Stable step id for logs, dependencies, outputs, and resume behavior.type: Registered step handler; the canonical catalog below is the source for authored YAML.command: Command text for command-running steps.scriptandinterpreter: Inline script body and runtime fortype: script.working_directory: Directory for the subprocess or script.env: Map of environment variables layered onto the step.output: Output mode:raw,log,viewport, ornone.retry: Retry policy around the whole step.identity: Atmos identity used when the step runs.when: Declarative condition for whether the step runs.needs: Dependency names for concurrent control steps.timeout: Duration limit for supported steps.ttyandinteractive: Terminal handoff for commands that need it.
Step Types
Use the docs at website/docs/workflows/workflows/workflow/steps/type.mdx and
the type-specific files under website/docs/workflows/workflows/workflow/steps/type/
as the canonical reference. Current canonical step types include:
- Command and integration:
atmos,shell,script,exec,container,emulator,http,archive,require,workdir,cast,store. - Orchestration:
parallel,matrix,wait,wait-all,cancel. - Interactive:
input,confirm,choose,filter,file,write. - UI and output:
toast,markdown,spin,table,pager,format,join,style,log,junit,hint,alert,say,title,clear,linebreak,stage,sleep,env,exit.
Use webhook only as the http alias and assert only as the require alias;
document and configure the canonical names unless compatibility requires an alias.
If code and docs disagree, inspect the registered step handlers under
pkg/runner/step/ and schema constants in pkg/schema/task.go.
Environment
Prefer map syntax:
env:PATH: '{{ env "PWD" }}/../../.context/bin:{{ env "PATH" }}'ATMOS_LOGS_LEVEL: warn
For custom commands, command-level env supports the same map style. Use
template expressions such as {{ env "PATH" }} or .Env where supported. Use
valueCommand only when the value genuinely must come from a command's stdout;
do not move shell string building into valueCommand.
Working Directory
Use working_directory at the narrowest useful scope:
steps:- name: docstype: shellworking_directory: !repo-root .command: npm run docs:build
Do not use --chdir or cd for real workflow, custom-command, or step execution when
working_directory can express the same thing. In a mode: steps cast, a display-only
type: simulate cd <directory> is the exception: use it to keep the recorded story coherent,
and still configure working_directory on every real step. Relative paths must be checked
against the surface's base path rules.
Working-directory resolution is not one rule — it differs by surface, and getting this wrong
silently anchors relative fields (source, destination, path, files, context, ...) to the
wrong directory instead of erroring:
| Surface | Relative working_directory resolves against |
|---|---|
Custom command's own working_directory: (command- or step-level) | Atmos base_path — always, whether or not the value starts with ./ |
A workflow's own working_directory: (the workflow-level default), or a type: shell/exec/atmos step's working_directory: | Atmos base_path — always, whether or not the value starts with ./ |
An extended/registered step type (archive, file, junit, workdir, container, ...) with its own step-level working_directory: | The current working directory — always, whether or not the value starts with ./ |
kind: step/kind: steps hook | The component's own working directory for a bare value or when unset; the current working directory for a dot-prefixed value (., .., ./x, ../x) — see atmos-hooks for the full Dot/Bare rule |
A workflow-level working_directory: default still reaches extended step types that leave their
own working_directory: unset — it falls back to the same base_path-anchored resolution the
workflow-level default already gets for shell/exec/atmos steps.
After working_directory is resolved, relative handler fields such as source, destination,
path, files, and context resolve against that directory. For container builds, Dockerfile
resolves relative to the resolved context, not directly to working_directory.
Output
Use output modes instead of pipe redirection:
steps:- name: preparetype: atmoscommand: terraform generate varfile vpc -s devoutput: none
output: none is for quiet setup. raw preserves command output, log routes
through Atmos logging, and viewport is for richer terminal display.
Script Steps
Use type: script for inline scripts:
steps:- name: validate-casttype: scriptinterpreter: python3script: |from pathlib import Pathtext = Path("website/static/casts/examples/sops-secrets.cast").read_text()if "All proofs passed" not in text:raise SystemExit("cast validation failed")
Do not put command on a script step. The schema requires interpreter and
script.
Workdir Steps
Use type: workdir for repeatable scratch directories:
steps:- name: stage-fixturestype: workdirpath: .context/casts/demosource: demo/casts/fixturesreset: true
This replaces shell sequences that create, delete, and copy directories.
Hooks
For hooks, the hook envelope controls lifecycle behavior and with: is the
step payload. A scaffold template may use this bridge too, but only with
kind: step or kind: steps and its two generation events:
hooks:notify:kind: steptype: httpevents: [after.terraform.apply]on_failure: warnretry:max_attempts: 3with:url: https://example.com/hookmethod: POST
Use atmos-hooks for hook events, outcome conditions, on_failure, and
preflight behavior.
Verification
When changing step YAML, verify the user-facing command from the directory where
users actually run Atmos. Prefer working_directory fields in YAML and command
tool workdir settings in tests over shell cd or --chdir.