atmos stack create
Create a new stack using the existing scaffold catalog and generation engine. Preview the rendered files and generation hooks before writing. Existing files are never overwritten.
Usage
atmos stack create --file=stacks/deploy/dev.yaml --name=dev
atmos stack create --file=stacks/deploy/dev.yaml \
--import=catalog/defaults \
--component=terraform:network \
--component=helmfile:services \
--dry-run
Choose either --file for a manifest or --target for a directory layout. These flags
are mutually exclusive. A --file must end in .yaml or .yml and match the project's
stack discovery paths. A relative --file resolves from the project base path, not the
current directory, and output files are rooted there too. Relative source paths in
scaffold.templates resolve from the configuration file that declares the source.
Named templates honor --config, configuration imports, and active profiles.
--name explicitly sets the stack name in the built-in scaffold. When omitted,
the generated manifest leaves naming to the project's conventions; provide the
variables required by your stacks.name_template, directly or through imports.
Repeat --import to add imports and --component=kind:name to add component
stubs. These stubs have metadata.enabled: false and empty vars. Configure them
and enable them when ready. The command does not generate component sources unless
your selected scaffold includes them. Component order does not imply dependencies.
If a write fails or creation is canceled, Atmos rolls back files created by that attempt so you can correct the cause and retry. It preserves preexisting files, hook-created files, and generated files changed after creation. If cleanup cannot finish, the error lists the remaining paths for manual recovery. A replaced stale generation record is restored when possible. Hook side effects are not rolled back. If generation succeeds but an after hook fails, the generated files and record remain.
Flags
--file- Path of the new stack manifest. Mutually exclusive with
--target. Must end in.yamlor.ymland fall under the project's stack discovery paths. Existing files are never overwritten. --target- Directory for generated stack files. Mutually exclusive with
--file. Relative paths resolve from the project base path. The directory must be understacks.base_path; template outputs are relative to it. Existing directories are allowed, but existing files are never overwritten. --template- Scaffold name or source: a name from
scaffold.templates, an embedded catalog template, or a direct local or remote source. Default:stack. --name- Explicit stack name. When omitted, the generated manifest follows the project's naming convention. Default: Empty.
--import- Stack import to add. Repeatable. Each occurrence is one value, so commas and braces such as
catalog/{a,b}are kept as written. Default: None. --component- Disabled component stub to add, in the form
kind:name. Repeatable. The kind must be a supported component kind, including custom kinds declared by custom commands, and the name cannot contain whitespace. Duplicates are rejected. Default: None. --set- Scaffold answer in the form
key=value. Repeatable. An entry without=is an error. The reserved inputsstack_file,stack_name,stack_imports, andstack_componentscannot be set. Default: None. --ref- Git revision to use for a scaffold fetched from a Git source. Using it with an embedded or local scaffold is an error. Default: The source's default revision.
--interactive,-i- Prompt for the destination and scaffold answers when connected to a terminal, including during
--dry-run. Without a terminal, Atmos uses defaults and errors on missing required inputs. Default:true. --defaults- Use scaffold defaults and
--setvalues without prompting.--interactive=falsehas the same effect. Default:false. --skip-hooks[=names]- Skip all scaffold hooks, or the comma-separated hook names. Environment variable:
ATMOS_SKIP_HOOKS. Default: No hooks skipped. --dry-run- Print the files and scaffold hooks without writing or running anything. Environment variable:
ATMOS_DRY_RUN. Default:false.
The template must consume the flags you pass. If --name, --import, or --component
is given and the rendered manifest does not contain the value (or no generated stack
document contains it in directory mode), creation fails and
names the flag, so no input is dropped silently. A custom template reads these flags
through stack_name, stack_imports, and stack_components.
Checks before writing
Before any hook runs or any file is written, Atmos processes the existing stack
manifests together with every generated stack file, using the same pipeline as
atmos describe stacks. Creation fails, and nothing is written, when the result has:
- A stack name that cannot be resolved. Pass
--name, or set the variables thatstacks.name_templateuses. - A missing import. Import paths are relative to
stacks.base_path; create the imported manifest or correct the--importvalue. - A component defined in more than one top-level manifest resolving to the same stack.
Disjoint component definitions may share a stack name. Choose distinct component
definitions or stack names, or edit the existing stack with
atmos stack config set. - An invalid generated stack file.
If the project's existing stacks already fail to process, the error says so and points
to atmos validate stacks, rather than blaming the new files.
Existing files are never overwritten. When the manifest exists, edit it with
atmos stack config set or delete it first and run the command again.
Use an existing scaffold
--template selects a name from the existing scaffold.templates configuration,
an embedded/catalog template, or a direct local or remote source. Without it,
creation uses the built-in stack scaffold.
scaffold:
templates:
application-stack:
description: Application stack with network and services
source: ./scaffolds/application-stack
atmos stack create --template application-stack \
--file stacks/deploy/dev.yaml --set environment=dev --dry-run
For --file, a stack-compatible scaffold declares its manifest output using spec.stack.manifest:
apiVersion: atmos/v1
kind: AtmosScaffoldConfig
metadata:
name: application-stack
spec:
stack:
manifest: '{{ .Config.stack_file }}'
fields:
- name: environment
type: input
required: true
files:
- path: stack.yaml
target: '{{ .Config.stack_file }}'
# atmos:template
vars:
stage: {{ .Config.environment | quote }}
components:
terraform:
network:
vars: {}
The generated manifest must match --file. Other outputs are relative to the project
base path; a scaffold can conditionally create component sources or documentation.
Custom templates decide how to use these reserved inputs:
stack_file- Project-relative manifest path from
--file. In directory mode, defaults tostack.yaml, relative to--target; templates do not have to use it. stack_name- Explicit
--name, or an empty string. stack_imports- List of requested imports.
stack_components- Component map containing disabled stubs, grouped by kind.
These inputs cannot be supplied through --set or declared as questionnaire fields.
Existing template defaults, questions, conditions, matrices, and per-file delimiters
work through the same engine as scaffold generate.
Use --set key=value for answers, --defaults or --interactive=false for automation,
and --ref to select a Git source revision. Required answers are validated before writing.
Create a directory layout
Use --target when the recipe produces several stack files. It supports both one
logical stack split across files and several distinct stacks:
atmos stack create --template application-stack \
--target stacks/deploy/dev \
--set environment=dev --set name=dev \
--component terraform:network --component helmfile:services \
--import catalog/defaults --dry-run
The template chooses which files receive the requested imports and component stubs.
Each supplied value must appear in a generated stack document. The --set name=dev
answer belongs to the template; --name dev supplies the reserved stack_name input.
Directory templates do not need spec.stack.manifest. If they declare it, its path
is relative to the target and must identify a generated, discoverable stack manifest.
The built-in stack template creates stack.yaml inside the target directory.
For example, a recipe can generate this layout:
stacks/deploy/dev/
├── _defaults.yaml
├── network.yaml
└── services.yaml
Configure discovery to include deploy/**/* and exclude **/_*. The excluded
_defaults.yaml is an import fragment, while the other two files are entrypoints:
apiVersion: atmos/v1
kind: AtmosScaffoldConfig
metadata:
name: application-stack
spec:
fields:
- name: environment
type: input
required: true
- name: name
type: input
required: true
files:
- path: _defaults.yaml
- path: network.yaml
- path: services.yaml
# atmos:template
name: {{ .Config.name | quote }}
vars:
environment: {{ .Config.environment | quote }}
# atmos:template
import:
- ./_defaults
{{ range .Config.stack_imports }} - {{ . | quote }}
{{ end }}components:
terraform:
{{ range $name, $_ := .Config.stack_components.terraform }} {{ $name | quote }}:
metadata:
enabled: false
vars: {}
{{ end }}
The services.yaml template follows the same pattern using the helmfile group
from stack_components. Both entrypoints import the shared name and variables;
their distinct components participate in one logical stack. To create separate
stacks, give their entrypoints distinct names or naming variables. Existing scaffold
matrices can repeat an entrypoint for several environments or regions.
Files do not merge merely because they share a directory. Atmos uses its existing imports, discovery, and stack naming rules. At least one generated stack file must match discovery; excluded fragments can be imported by entrypoints. All generated stack YAML is validated before hooks or writes. Output paths cannot escape the target.
Interactive inputs
When no destination is supplied in an interactive terminal, Atmos asks for a single
file or directory layout, then its destination. The single-file option is selected
initially. The scaffold questionnaire follows, with defaults and --set answers
prefilled for review. Required fields, conditions, and dynamic choices behave like
scaffold generate.
Interactive dry runs collect answers and then preview the files. Pass --defaults
or --interactive=false to suppress prompts. Without a terminal, provide a destination
and any required answers that have no defaults. Canceling a prompt writes nothing
and runs no hooks.
Preview, hooks, and generation records
A dry run prints a stream of file previews: a # <path> comment followed by each
file's content, with --- between files. The stream goes to stdout so it can be
piped, but it is not guaranteed to be valid YAML: files can contain Terraform
sources, documentation, or other content. It creates no output files or directories
and runs no hooks. Resolving a remote template can still download it.
The preview also lists each scaffold hook in the order it would run, with before
hooks ahead of after hooks, including its actions and conditions. A hook whose events
are not scaffold events is listed as ignored, along with the events it declares, and
a hook skipped by --skip-hooks is identified as skipped.
Scaffold hooks run around file creation using the normal before.scaffold.generate
and after.scaffold.generate events. Use --skip-hooks to skip all, or
--skip-hooks=name1,name2 for specific hooks. These are separate from component
hooks that run during deployment. Step-backed scaffold hooks receive the outcome of the
creation as ATMOS_HOOK_STATUS (success or failure), ATMOS_HOOK_EXIT_CODE, and
ATMOS_HOOK_ERROR. Hooks on before events always run with a success status.
Every destination is checked before hooks or writes. Files are created exclusively, so existing stack manifests, component sources, and project files are never overwritten. Creation writes the same rendered content shown in the preview. Filesystem or hook failures are reported; external hook effects are not rolled back automatically.
Each creation has an independent generation record under .atmos/stack-generations/.
File-mode records are keyed by the project-relative manifest path. Directory-mode
records use a separate key for the target directory and list its generated manifests.
Each record stores the template, answers, source revision when available, and generated
file hashes. Directory hooks use the target directory as their default working directory.
Creating another stack
does not replace project-level init/scaffold records. If you delete a created manifest
and run stack create for the same path again, the new run replaces that manifest's
generation record. A directory record can be replaced only after all outputs recorded
by the previous generation have been removed. Updating an existing stack from this record is not yet supported
by stack create.
init bootstraps a project; scaffold generate runs general
recipes; stack create requires and validates a stack output. Creation changes
configuration only. Use stack config to edit values
and stack deploy to deploy components.