Refresh Atmos agent skills for Native CI @osterman (#2493)
## what- Refresh the Atmos agent skills to use current stack naming, dependency, provisioning, auth, and toolchain guidance.
- Replace the old
atmos-gitopsskill withatmos-ci, centered on Native CI, containerized GitHub Actions, OIDC profiles, checks, comments, summaries, affected/all matrices, and direct Atmos commands. - Add an
atmos-aiskill focused on AI providers, MCP configuration/export, Atmos auth in agent workflows, and toolchain-aware MCP usage. - Remove Spacelift promotion from the skill bundle and keep deprecated wrapper actions,
name_pattern, andsettings.depends_ononly as migration warnings.
why
- Agents were recommending stale Atmos syntax and legacy CI patterns.
- Native CI,
dependencies.components,name_template, source provisioning with workdirs, backend provisioning, and Atmos-managed tool dependencies are the preferred guidance. - Terraform/OpenTofu setup actions and legacy Cloud Posse wrapper actions should be discouraged in favor of the Atmos container and toolchain-managed
dependencies.tools.
references
Summary by CodeRabbit
- Documentation
- Expanded and reorganized Atmos skill/reference guidance, adding first-class AI/MCP, Native CI, profiles, toolchain, containers/emulators, secrets, GitOps, AWS, and core configuration navigation.
- Added new/updated pages for
atmos-ai, Terraform/OpenTofu orchestration,atmos mcp export,atmos ai ask,atmos-profiles, migration (including Remote-State Bridge), and improved guidance forgenerate/overridesand validation.
- Bug Fixes
- Improved terminal color behavior to honor environment-based controls.
- Enhanced tool download retry/error reporting for clearer diagnostics.
- Tests
- Updated fixtures and strengthened marketplace/catalog and download retry assertions.
- Chores
- Refreshed plugin/marketplace metadata and licensing notice; reorganized documentation via links.
docs: provider-generation default_tags + missing YAML function pages @osterman (#2704)
## what- Add a "Setting Default Tags" section to the Provider Generation page (
components/terraform/providers.mdx), showing how to set the AWS provider'sdefault_tagsvia theproviderssection, populated with!git.repository,!git.sha, and!git.branch. - Add 5 missing YAML function doc pages so they appear in the docs sidebar:
!git.sha,!git.branch,!git.ref,!git.root, and!emulator. - Cross-link the new
!git.*pages from their existing siblings (git.name,git.host,git.owner,git.repository,git.url,repo-root) and from the YAML functions index page. - Fix a pre-existing template bug in
stacks/providers.mdx's dynamic provider example:{{ .stage }}is not a valid template variable and should be{{ .vars.stage }}.
why
- The Provider Generation page had no example showing how to set
default_tags, a common requirement for consistent resource tagging (repository, commit, branch, etc.) across an account. !git.sha,!git.branch,!git.ref,!git.root, and!emulatorare all implemented, working YAML functions, but had no doc page and were therefore invisible in the sidebar.- The
{{ .stage }}bug produced a non-functional example — Atmos's template context only exposes stage/tenant/environment/namespace nested under.vars, never as bare top-level keys.
references
Summary by CodeRabbit
- Documentation
- Added new docs for YAML functions covering Git metadata (
!git.sha,!git.ref,!git.branch,!git.root), repository paths, and emulator connection details (!emulator). - Expanded the YAML function index and “Related Functions” sections to improve discoverability of Git helpers.
- Added guidance for setting AWS provider
default_tagswith dynamic values and a CI-friendly fallback for detachedHEAD. - Updated the dynamic provider configuration example to use the correct current-stack variable format.
- Added new docs for YAML functions covering Git metadata (
perf(lint): isolate golangci-lint cache and lock per worktree @osterman (#2701)
## what- Point
TMPDIRandGOLANGCI_LINT_CACHEat repo-local dirs inscripts/run-custom-golangci-lint.shso each worktree gets its own golangci-lint lock and cache (GOCACHEstays shared for warm typecheck data); opt out withATMOS_LINT_SHARED_CACHE=1. - Skip rebuilding the
custom-gclbinary inatmos lint custom-gclwhen it is already up to date (staleness guard mirroringlint lintroller/lint gomodcheck). - Drop the redundant standalone
lint lintrollerpass fromatmos lint changed(it already runs as a plugin insidecustom-gcl).
why
- golangci-lint's single-instance lock is a fixed machine-global path (
os.TempDir()/golangci-lint.lock), not insideGOLANGCI_LINT_CACHE, so parallel worktree lints (e.g. rebase storms after a merge) serialized on one lock and a run orphaned by a tool timeout froze every other worktree; relocating the lock via a per-worktreeTMPDIRlets them run in parallel and contains an orphan to its own worktree. - Rebuilding
custom-gcl(clone + compile) on everylint changedwas the single biggest per-run cost during a rebase storm when the binary is identical across worktrees. - Verified empirically: an isolated-
TMPDIRlint ran at ~94% CPU in parallel with another holding the global lock, with its lock file under.golangci-tmp/.
references
- Contributor tooling only (dev lint flow + pre-commit hook); no user-visible change to the Atmos binary — labeled
no-release.
Summary by CodeRabbit
- Bug Fixes
- Improved linting behavior in parallel worktrees by isolating golangci-lint cache and lock files per worktree, reducing contention and unexpected failures.
- Updated the “changed” lint flow to skip an unnecessary full-repo lint pass, making runs leaner and faster.
- Made the custom Go-based lint helper rebuild only when the binary is missing or stale, avoiding redundant rebuilds and speeding up repeated lint runs.
[codex] Add native asciicast recording and demo embeds @osterman (#2672)
## what- Adds Atmos-native asciicast recording, playback, rendering, and cast/workdir step support.
- Adds reproducible cast demo commands, deterministic fixtures, committed website casts, and an asciicast authoring skill.
- Adds website cast playback plus README front matter/example embed support for showing casts on command and example pages.
why
- Makes command demos reproducible, source-controlled, reviewable as plain text, and reusable across docs.
- Lets examples opt into casts without duplicating command-page videos.
- Provides validated demo coverage for Terraform, vendor, describe/list, and AWS emulator workflows.
references
- None.
Summary by CodeRabbit
- New Features
- Added terminal recording via global
--cast(supports generated.castoutput and rendering to.gif/.mp4and more formats). - Introduced
atmos cast playandatmos cast render. - Added interactive cast simulation/session driving, plus
scriptandworkdirstep capabilities. - Added website cast playback through the new
CastPlayercomponent and an embedded cast demo gallery.
- Added terminal recording via global
- Bug Fixes
- Improved forced-color behavior and cast/help capturing consistency, without impacting normal CLI argument handling.
- Documentation
- Updated CLI docs, examples, and skills/guides to cover cast workflows and new step patterns.
🚀 Enhancements
fix(workflows): resolve step vars in inline shell/atmos/exec steps @sgtoj (#2711)
## WhatWorkflow step types handled inline (shell, atmos, exec) now resolve step-variable templates — {{ .steps.*.value }}, {{ .env.* }}, {{ .flags.* }}, plus Sprig/Gomplate functions — in both the step command and the step env: values, matching how custom command steps already behave.
workflows:
deploy:
steps:
- name: component
type: format
content: "vpc"
- type: atmos
command: terraform apply {{ .steps.component.value }} -auto-approve
env:
COMPONENT: "{{ .steps.component.value }}"Before this change, terraform apply {{ .steps.component.value }} -auto-approve was passed through verbatim (literal {{ .steps.component.value }}); now it resolves to terraform apply vpc -auto-approve.
Why
This is a bug, not a new feature. The documented contract (PRD goal “capture step outputs for use in subsequent steps via Go templates”, and its own examples using type: atmos / type: shell command steps) is that any step can consume prior steps' outputs. Handler-routed step types (toast, markdown, container, the interactive prompts, …) and custom command steps already resolved these templates; workflow shell/atmos/exec steps were the outlier — they executed the raw command and merged env: values without running either through the step-variable engine, so the templates were emitted literally. It went unnoticed because the shipped examples only surface step values through handler-routed display steps, never a raw shell/atmos command.
How
ExecuteWorkflowconfigures the workflow step executor with the same template engine as the custom command executor (cmd/cmd_utils.go): the full Atmos renderer (Sprig/Gomplate), multi-pass rendering, and flag protection — so templating behaves identically in workflows and custom commands.- Inline step commands and
env:values are resolved through that engine before execution. - New
Variables.ResolveWithapplies a per-call environment overlay without mutating the shared executor env, so a step's environment is visible as{{ .env.* }}without leaking across steps. prepareStepEnvironmentstays a pure merger (its existing tests are unchanged); env values are resolved ahead of it.
Commands and env: values without template markers are returned unchanged.
Testing
- Unit tests:
Variables.ResolveWith(overlay + non-mutation), command resolution (.steps+ env overlay, non-leak, Sprig parity, invalid-template error), andenv:resolution. - End-to-end (built binary): a workflow feeding a captured value into a
shellstep's command,env:, and a Sprig function all resolve correctly. go build ./...,pkg/runner/step+internal/execsuites, andatmos lint changedare clean.
References
docs/fixes/2026-07-07-workflow-step-variable-templating.md- Reference implementation mirrored:
cmd/cmd_utils.go(custom command step executor)
Summary by CodeRabbit
-
New Features
- Workflow steps can reference earlier step outputs in inline
shell,atmos, andexeccommands and inenv:values. - Expanded workflow documentation with “Referencing values from other steps” examples.
- Workflow steps can reference earlier step outputs in inline
-
Bug Fixes
- Fixed unresolved template expressions in certain inline workflow steps.
env:template resolution now uses a per-step overlay so values resolve correctly without impacting other steps.
fix: correct out-of-date atmos-manifest workflow schema (#2708) @sgtoj (#2710)
## what- Bring the published
atmos-manifestJSON Schema (served atatmos.toolsand mirrored to SchemaStore) back in sync with the workflow features shipped in1.222.0, so editors using# yaml-language-server: $schema=…stop drawing false-positive errors on valid workflows. workflow_manifest(the object under each named workflow): add the 7 missing workflow-definition fields —dependencies,working_directory,env,container,output,viewport,show(reusing the existingdependenciesdefinition via$ref).workflow_step: add the 75 missing step fields with descriptions, spanning every step-type family (options/default/interactive/tty/script, plushttp,cast,container,style,log,say,env,exit,emulator,junit,require,workdir,table, control/parallel). SetadditionalProperties: trueand makelevela plain string (see why).- Add three shared sub-definitions:
workflow_viewport,workflow_show,workflow_container(the latter also acceptsfalseto run on the host). - Add a reflection-based ratchet test (
schema_workflow_coverage_test.go) that fails the build if aWorkflowStep/WorkflowDefinitionfield is ever authored without a matching schema property — the same "you can't forget the schema" pattern already used for top-level/component sections. - Add regression tests (
schema_workflow_validation_test.go) reproducing the issue's exact snippets, covering one field from every step-type family, all workflow-level fields, and confirming typed fields (e.g.options,code) are still validated.
why
- The issue named three rejected fields (
dependencies,options,default), but the schema had drifted far more broadly: it modeled only 21 of ~96 authored step fields and 3 of 10 workflow-definition fields, both withadditionalProperties: false. Any workflow using a newer field produced misleading "Property X is not allowed" red squiggles on config that Atmos parses and runs correctly. - I validated the updated schema against all 60 real workflow files in the repo. That surfaced two ways the old strict schema over-tightened against shipped examples: an ignored/unknown key, and
level:values outside a log-level set. Workflow steps are a lenient, polymorphic union of ~30 step types and Atmos ignores unknown keys at runtime, soadditionalProperties: true(plus fully enumerated known fields for autocomplete + type checks) matches real behavior and eliminates the whole false-positive class — present and future — mirroring howproviders/templatesare modeled.levelis a plain string field, so it is no longer constrained by an enum. - The ratchet test makes this drift a build failure going forward, so the published schema can't silently fall behind the structs again.
- Scope is intentionally the published (website/SchemaStore) schema; the embedded schemas do not model workflow steps and
atmos validate stacksis unchanged.
references
- Closes #2708
- Follow-ups discovered while validating real workflows (out of scope here, worth separate issues):
examples/quick-start-advanced/stacks/workflows/{backend,validation}.yaml(and the mirrored doc) usecommand: true— an unquoted-YAML-boolean footgun where a string command belongs; the schema correctly flags it.- Dedicated schemas for custom-command files (
commands:) and profile files (auth:) — the issue's "ideally" ask; purely additive (no false-positives today) and a larger separate effort.
Summary by CodeRabbit
-
Bug Fixes
- Improved validation for workflow manifests so commonly used workflow and step settings are now recognized correctly.
- Fixed schema handling for interactive, command, file, container, output, and UI-related workflow options.
- Reduced false validation/editor warnings by allowing supported workflow step fields and preserving type checks for invalid values.
-
Tests
- Added coverage to guard against future workflow schema regressions.
fix(ci): exclude auth caches from ci.cache (defensive hardening) @osterman (#2705)
## whatci.cache(the CI build cache) now excludesaws-sso,azure-device-code,aws-webflow, andauth— the subdirectories under~/.cache/atmoswhere Atmos persists session credentials — unconditionally, with no opt-out, regardless ofci.cache.paths.- Applies in both Atmos's own cache backend (
pkg/ci/cache/archive.go) and theatmos ci cache pathsoutput used with the nativeactions/cacheGitHub Action (rendered as!-prefixed glob exclusions, working around a knownactions/toolkitglob-depth limitation). - Drift-guard tests in each owning auth package assert their subdir constants stay in sync with the exclusion list, so a rename can't silently reopen the gap.
- Docs (
website/docs/cli/configuration/ci/cache.mdx,docs/prd/native-ci/framework/ci-cache.md) and an internal fix note (docs/fixes/) are included.
why
ci.cache's default behavior (cache the entire XDG cache root whenci.cache.pathsis unset) meant Atmos's own auth session material (AWS SSO tokens/refresh token/client secret, Azure device-code tokens, Atmos's webflow refresh token) sat in the same directory tree that gets archived by default.- This is purely defensive hardening —
ci.cachewas never demonstrated to be exploitable or vulnerable in CI. A repo's GitHub Actions cache is already scoped to that repo, and everything involved is short-lived, rotating session material. This change just makes it structurally impossible for these directories to end up in a cache archive, rather than relying onci.cache.pathsconventions. - OIDC-based auth (GitHub/GCP/Azure) was confirmed unaffected either way — those flows never write credentials to disk.
references
docs/prd/native-ci/framework/ci-cache.md#default-excluded-auth-paths
Summary by CodeRabbit
- New Features
- CI cache outputs now include default excluded paths alongside included paths.
- GitHub, JSON, YAML, and env formats now show the exclusion list consistently.
- Bug Fixes
- Default auth-related cache directories are no longer archived by CI cache flows.
- Cache exclusion handling is now applied consistently across archive creation and cache path generation.
- Documentation
- Updated CI cache docs to explain the default exclusions and their effect on cache behavior.
fix(website): repair broken /blog announcement link @osterman (#2702)
## What- Fix the broken announcement-bar link:
/blog/native-ci-integration→/changelog/native-ci-integration. - Add a
createRedirectsrule toplugin-client-redirectsso any other stale/blog/<slug>URL (old bookmarks, indexed search results) forwards to its current/changelog/<slug>page, matching the existing bare/blog→/changelogredirect.
Why
The blog plugin's routeBasePath was changed from /blog to changelog a while back (#1707), but the announcement bar (website/src/data/announcements.js) still hardcoded the old /blog/... path, so it 404'd live on atmos.tools.
Neither existing safety net catches this class of bug:
.github/workflows/link-check.yml(lychee) is scoped to**.mdand explicitly excludeswebsite/**.- Docusaurus's
onBrokenLinks: 'throw'only analyzes links it discovers via rendered MDX/<Link>content — the announcement bar renders itscontentstring throughdangerouslySetInnerHTML, which is invisible to that check.
This PR fixes the one known broken instance and adds the redirect as a safety net for any other pre-#1707 /blog/* links floating around externally.
Test plan
-
cd website && npm run buildsucceeds. - Confirmed
build/blog/native-ci-integration/index.htmlcontains a meta-refresh to/changelog/native-ci-integration. - Confirmed 236
/blog/*redirect pages are generated (one per changelog post). - Live-verified
https://atmos.tools/changelog/native-ci-integrationreturns 200 (the corrected target).
🤖 Generated with Claude Code
Summary by CodeRabbit
-
New Features
- Added automatic redirects for old changelog URLs to their matching blog pages, helping visitors reach updated content without broken links.
-
Bug Fixes
- Updated an announcement link so it points to the correct changelog page.
fix: deep merge drops keys under unquoted-integer YAML map keys @osterman (#2700)
## what- Fixes
normalizeMapReflectinpkg/merge/merge.goso amap[interface{}]interface{}(the shape yaml.v3 produces for a YAML mapping with an unquoted non-string key, e.g.1:) is stringified intomap[string]anyinstead of being preserved as an opaque typed map. - Adds
pkg/merge/merge_yaml_integer_key_test.go, which reproduces the bug end-to-end via realyaml.v3unmarshaling and unit-tests the normalization contract directly. - Documents the root cause and fix in
docs/fixes/2026-07-07-deep-merge-yaml-integer-key.md.
why
- Since the native deep-merge rewrite (#2201), a nested map whose parent key is an unquoted integer in YAML (e.g.
eni.1:) was silently replaced instead of deep-merged whenever a stack overrides a subset of its keys, dropping catalog-only keys with no error. - Root cause: yaml.v3 only decodes a mapping into
map[string]interface{}when every key resolves to!!str; an unquoted integer key forcesmap[interface{}]interface{}for that mapping node.normalizeMapReflectlumped this together with genuinely-typed non-string-key Go maps (e.g.map[int]schema.Provider) and preserved both, sodeepMergeNative'smap[string]anyfast path saw a type mismatch and fell back to "src overrides dst" for the whole submap. - The previous partial regression fix (#2248) addressed list↔map type-mismatch guards but did not address this map-key normalization gap.
references
- Closes #2376
Summary by CodeRabbit
- Bug Fixes
- Fixed a deep-merge regression where YAML maps with unquoted integer keys could replace sub-maps instead of merging nested content.
- Improved normalization of maps with mixed interface/non-string keys, including correct behavior when stringified keys collide.
- Enhanced signature verification retry handling by classifying additional upstream cosign HTTP failures as retryable (with 404 non-retryable).
- Tests
- Expanded coverage for YAML integer-key normalization, interface-keyed normalization, and colliding stringified keys.
- Updated CLI golden snapshots and affected-area test expectations to use quoted numeric YAML keys.
- Documentation
- Added incident write-ups for the YAML regression and the cosign HTTP retry issue.