github cloudposse/atmos v1.223.0-rc.11

pre-release5 hours ago
feat(mcp): server management commands, self/atmos-pro presets, and config UX fixes @osterman (#2720) ## what
  • Extracts the standalone atmos mcp install command (client-config installer for AI coding assistants) from the stalled osterman/pro-install-cmd branch, leaving all Atmos Pro-specific wiring behind.
  • Adds full MCP server-management commands: atmos mcp add, atmos mcp remove, and atmos mcp uninstall, rounding out the existing list/install/export/status/test set.
    • add/remove only edit mcp.servers in atmos.yaml (the source of truth); install/uninstall push/pull that declared config to/from AI client config files (Claude Code, Cursor, VS Code, Codex, Gemini).
    • Adds built-in self and atmos-pro presets so atmos mcp add (no arguments) works out of the box, resolving to Atmos's own MCP server or the Atmos Pro MCP server respectively.
    • Adding the self preset interactively offers to flip mcp.enabled: true in atmos.yaml if it isn't already, since that preset requires it to function.
    • atmos mcp list/status now nudge users to run atmos mcp add atmos-pro when Atmos Pro is configured but its MCP server hasn't been added yet.
    • atmos mcp install with nothing configured now interactively offers to add+install the self preset instead of just printing a static hint.
  • Adds a new top-level /mcp docs landing page (website/docs/mcp/mcp.mdx) covering both directions — Atmos as an MCP client and as an MCP server — cross-linked from /ai via tabs, matching the existing /pro and /ai landing pages.
  • Expands atmos mcp install/uninstall's supported-client list from 5 to 15: adds Claude Desktop, Windsurf, Cline, Cline CLI, Zed, OpenCode, Goose, GitHub Copilot CLI, Antigravity, and MCPorter, alongside the existing Claude Code, Cursor, VS Code, Codex, and Gemini. Includes a new YAML config writer (for Goose) and bespoke per-client entry renderers where a client's schema differs from the common mcpServers shape (Zed's context_servers, OpenCode's mcp).
  • Adds a ## Troubleshooting section to the atmos mcp install docs covering post-install behavior that varies by client (some need a restart, others need a manual settings toggle, some auto-reload).
  • Fixes #2628: atmos ai skill install previously always wrote to ~/.atmos/skills/, so VS Code / GitHub Copilot's .github/skills/ couldn't discover installed skills.
    • Adds --path/ATMOS_AI_SKILL_PATH to override the install directory.
    • Adds zero-flag multi-client skill distribution: atmos ai skill install <name> now auto-detects which AI clients (Claude Code, VS Code/Copilot, Gemini) are in use in the current project and copies the skill into each one's well-known skill directory, mirroring atmos mcp install's detect/--client/--all-clients/interactive-picker UX. atmos ai skill uninstall gained the same --client/--all-clients symmetry to clean up those copies.
    • atmos ai skill install/uninstall with no <source>/<name> now acts on every skill (every bundled skill for install, every installed skill for uninstall) instead of requiring one invocation per skill — mirrors atmos mcp install/uninstall's existing "no server names given = act on everything configured" convention rather than adding a separate --all flag.
  • Adds atmos config set/delete/format UX polish:
    • Infers the value's type (bool, int, float, string, yaml) from the Atmos config schema via reflection on yaml/mapstructure struct tags, so atmos config set mcp.enabled true writes a real boolean without needing --type=bool.
    • Echoes the value that was written/deleted/formatted, and shows paths relative to the current directory instead of absolute.
  • Fixes a CLI error-message bug: a leaf command (no subcommands) whose Args validator rejects the wrong number of arguments (e.g. atmos config unset mcp.enabled true against ExactArgs(1)) previously reported the misleading Unknown command mcp.enabled — implying an unrecognized subcommand — when the real problem was too many arguments. Now surfaces Cobra's own accurate validator message.
  • Fixes toolchain installs on macOS: verifier binaries downloaded during atmos toolchain install can carry the com.apple.quarantine/com.apple.provenance xattrs, causing Gatekeeper to block execution even though the binary was already checksum/signature-verified. Strips the xattrs and ad-hoc re-signs the binary on darwin, with a verifier_trust: disabled opt-out.
  • Adds a "Native AWS SigV4 Signing" design section to docs/prd/atmos-mcp-integrations.md (proposal only, not implemented in this PR) for natively signing requests to AWS-hosted MCP servers using Atmos Auth identities, without a third-party mcp-proxy-for-aws bridge.

why

  • atmos mcp install's client-installer code was implemented on a branch entangled with unrelated, stalled Atmos Pro onboarding work; splitting it out lets the MCP work ship independently.
  • Early testing surfaced a real gap: there was no way to get Atmos's own MCP server, or the Atmos Pro MCP server, into an AI client's config without hand-editing atmos.yaml and running client-specific commands manually — atmos mcp add self/atmos mcp add atmos-pro collapse that to one command.
  • atmos config set mcp.enabled true silently writing the string "true" instead of a boolean is a footgun users would hit immediately while following the new MCP add/enable flow; schema-based type inference removes the need to know or pass --type=bool.
  • The "Unknown command" error was actively misleading during testing of this same feature (atmos config unset mcp.enabled true), and the root cause turned out to be a small, generally-applicable flaw in how Cobra Args-validator failures were reported for leaf commands.
  • The toolchain trust fix was discovered by a concurrent session working in this same worktree; bundling it into this PR (with its own commit and blog post) avoids a second churn cycle through CI/review for an unrelated one-line-symptom, multi-file fix.
  • The VS Code/Copilot skill-discovery gap and the narrow 5-client MCP list were both instances of the same underlying problem: Atmos only supported a handful of AI clients by name instead of the broad set real users are on. Expanding both to the same ~15-client list (sourced from add-mcp.com/docs/agents, which also supplied the model for the new Troubleshooting guidance) closes that gap once instead of client-by-client over time, and mirroring MCP's already-proven detect/--client/--all-clients/picker UX for skills keeps the two subsystems consistent for users learning either one.

references

  • Supersedes the MCP-install portion of the stalled osterman/pro-install-cmd branch (Atmos Pro-specific --mcp install flag intentionally left behind there).
  • Closes #2628
feat: tags and labels standard for auth, components, and bulk selection @osterman (#2738) ## what
  • Adds tags to auth identities/providers, filterable via --tags on atmos auth list/login/logout (composes with --providers/--identities).
  • Adds metadata.tags (list, any-match) and metadata.labels (map, all-match) to components, filterable via atmos list components --tags/--labels.
  • Adds four new no-arg YAML functions — !tags, !labels, !labels.keys, !labels.values — that return the current component's own metadata.tags/metadata.labels, typed, for bridging into vars (e.g. vars.tags: !labels for terraform-null-label-style modules).
  • Adds --tags/--labels bulk-selection filtering to terraform, kubernetes, helm, and container commands, composing with (not replacing) --all/--affected, via a new shared pkg/tags package.
  • Updates the examples/demo-auth and examples/quick-start-advanced examples and their casts to demonstrate the new tags/labels filtering.

why

  • Implements the docs/prd/tags-and-labels-standard.md design (previously merged docs-only) so users can categorize and bulk-select components and identities without maintaining static name lists per stack/region/environment.
  • Tags (any-match) and labels (all-match, Kubernetes-selector semantics) give two matching semantics suited to different selection needs — "any of these categories" vs. "all of these key=value constraints" — consistent with existing conventions like atmos vendor pull --tags.

references

  • Implements docs/prd/tags-and-labels-standard.md.
  • Relates to #1323 (mcalhoun's open PR adding metadata.labels + a --selector flag to list/describe commands) — this PR is broader in scope (adds tags, auth tags, YAML functions, and --tags/--labels on terraform/kubernetes/helm/container) but shares the metadata.labels foundation.
feat(claude): add changelog and fix-log skills, convert roadmap agent @osterman (#2751) ## what
  • Adds a changelog skill consolidating blog-post authoring rules (template, tags/authors, problem-first framing, no backtick-opening prose, optional cast embeds, no Go-internals leakage) that were previously duplicated across CLAUDE.md, the pull-request skill, and the docs skill.
  • Adds a fix-log skill (with a validate-fix-doc.sh script) for durable fix records under docs/fixes/, using a merged format that keeps the old convention's title/date line but adopts a consistent five-section structure (Summary/Context/Changes/Validation/Follow-ups).
  • Converts .claude/agents/roadmap.md into .claude/skills/roadmap/SKILL.md, invoked via Skill instead of Agent.
  • Trims CLAUDE.md, pull-request/SKILL.md, and docs/SKILL.md to short pointers at the new changelog/roadmap skills instead of embedding or duplicating the rules.

why

  • Blog-post guidance had drifted into three places (CLAUDE.md, pull-request, docs), with docs independently restating rules and solely owning one rule (no backtick-opening prose) found nowhere else.
  • The roadmap agent's work is a narrow, deterministic data-editing procedure against a fixed schema — it doesn't need an isolated subagent context, matching this repo's agent-vs-skill philosophy.
  • Analyzing real website/blog/*.mdx posts turned up recurring style violations (feature-first framing, backtick-opening prose, Go-internals leakage) worth codifying with concrete before/after examples.

references

  • None
fix(ci): keep bot dependency PRs labeled and rebased automatically @osterman (#2752) ## what
  • Add a default no-release label to renovate.json, matching the label Dependabot PRs already get from dependabot.yml.
  • Add "rebaseWhen": "behind-base-branch" to renovate.json so Renovate keeps its own PRs current with main.
  • Add a Mergify rule in .github/mergify.yml that runs update on any open Dependabot/Renovate PR against main that's conflict-free but behind — Dependabot has no native "keep up to date" option, so this fills that gap.

why

Triaging the ~18 open Dependabot/Renovate PRs turned up two systemic problems instead of one-off bad PRs:

  • Every open Renovate PR (10 of them) was failing the required PR Semver Labels check because it carried zero semver label. The check-cleanup logic in .github/workflows/codeql.yml's pr-semver-labels job only special-cases dependabot[bot], and dependabot.yml is the only place a default label gets set — Renovate PRs never got one.
  • main's branch protection requires the PR branch to be up to date (strict: true), but neither bot proactively rebases a clean, non-conflicting PR just because main moved, so PRs accumulate as BEHIND until someone manually updates them.

This is purely CI/automation config — no user-facing behavior change, hence no-release.

references

  • Investigated as part of a broader Dependabot/Renovate PR triage (closed #1357 and #1846 as stale/superseded, left explanatory comments on #2732 and the other blocked PRs).
feat(workflows): add native archive step type for zip/tar packaging @osterman (#2730) ## what
  • Add a native type: archive step for workflows and custom commands that packs a directory or file into a zip, tar, or tgz archive using the Go standard library only (archive/zip, archive/tar, compress/gzip) — no external zip/tar binary required.
  • Support action: replace (always rebuild fresh) on every format, and action: update (incremental add/refresh) for zip and uncompressed tar; action: create/action: extract and tar.bz2/tar.xz writers are reserved in the schema for a later phase and return a typed "not yet implemented" error.
  • Support subpath nesting, include/exclude glob filtering (reusing the existing pkg/utils.PathMatch matcher), and format inference from the destination/source extension.
  • Reuse the existing kind: step hook bridge instead of adding a dedicated hook kind, so kind: step + type: archive works as a component lifecycle hook with zero hook-side code.
  • Add the docs/prd/archive-step.md PRD, step-type reference docs, a changelog blog post, and a roadmap milestone.

why

  • Packaging build artifacts (most commonly a Lambda function's handler.zip before terraform plan/apply) had no native Atmos primitive — the only option was shelling out to zip/tar via a kind: command hook or type: shell step, which breaks on Windows CI and gives no typed validation.
  • This surfaced while migrating a Terragrunt example that used a before_hook wrapping the zip binary; a data "archive_file" Terraform data source was tried first but doesn't reliably run before packaging is needed.
  • The step ships as a step type only (not a new hook kind) to follow the precedent set by emulator/http/container, which reach hooks purely through the kind: step bridge — this avoids duplicating schema and hook-engine code for a capability the step registry already provides.

references

  • PRD: docs/prd/archive-step.md

🚀 Enhancements

fix(hooks): user-defined hooks now fire under bulk dispatch @osterman (#2736) ## what
  • Component hooks: (the user-defined hooks.RunAll engine) now fire for atmos terraform apply/plan/deploy under --all, --affected, --components, and --query — previously they silently never ran in these bulk modes, only for single-component invocations.
  • Adds a schema.ComponentNodeHooks interface (Before/After) wired into the scheduler's TerraformDispatcher.Dispatch — the one choke point shared by every bulk dispatch path — via a new pkg/hooks.RunPerComponentHooks helper.
  • A before-hook failure now aborts that component's execution before Terraform ever runs; an after-hook failure fails that component even if Terraform itself succeeded. Both respect each hook's existing on_failure: fail|warn|ignore setting rather than introducing new failure semantics.
  • Helmfile gets the same ComponentNodeHooks wiring, which is actually its first user-defined hook support of any kind (it previously had none, single- or multi-component).
  • A second commit removes ~2,260 net lines of confirmed-dead legacy sequential executor code and its now-orphaned tests (terraform_executor.go, terraform_affected_graph.go, the associated _test.go files, and orphaned helpers in terraform_utils.go/terraform_affected.go) that predated the scheduler-based dispatch path and had no live (non-test) callers left.

why

  • A before.terraform.apply hook (e.g. zipping a Lambda handler before apply) worked correctly under atmos terraform apply <component> -s <stack> but silently never ran under atmos terraform deploy --all -s <stack> for the identical component/stack/hook config — the subsequent apply then failed because the hook's output never existed. This is exactly how CI normally invokes Atmos, so any hook-dependent component broke the moment it moved from manual single-component testing to a real pipeline run.
  • Root cause: bulk dispatch only ever wired a CI-reporting callback (hooks.RunCIHooks), never the user-defined hook engine (hooks.RunAll), and had no "before" seam of any kind — the code itself documented this as a known, unfixed limitation.
  • The dead-code removal is split into its own commit so the behavior change stays independently bisectable from the pure deletion; both were confirmed dead via call-graph analysis before removal (only test-file callers remained).

references

  • N/A
fix(version-tracker): default track update/lock/status/diff to a table @osterman (#2698) ## what
  • atmos version track update, lock, status, and diff now default to a human-readable, TTY-aware table (matching atmos version track list), instead of raw YAML.
  • --format=yaml / --format=json remain available as explicit opt-ins and continue to return the original full-fidelity struct (e.g. digests, ecosystem/datasource detail) unchanged.
  • --format=csv / --format=tsv are now also supported for these four verbs, reusing the same pkg/list/renderer pipeline already used by version track list and secret list.
  • lock's default table is scoped to the resolved track's entries (not the entire multi-track lock file); --format=yaml/json still dump the full versions.lock.yaml contents.
  • Updated website/docs/cli/commands/version/track/{update,status,lock,diff}.mdx and website/blog/2026-07-04-atmos-version-tracker.mdx (the source of a screenshot that surfaced this bug) to show the corrected default output.
  • Added test coverage in cmd/version/track/track_test.go for the new default-format dispatch and for full-fidelity yaml/json output.

why

  • atmos version track update (and its siblings) were printing raw YAML by default, which violates this project's UX convention that CLI output should be human-readable by default, with structured formats as an explicit opt-in.
  • atmos version track list already got this right; update/lock/status/diff shared a writeFormatted() helper that had no table option at all.

references

  • Base branch is osterman/atmos-yaml-schema-split (not main) because this is a follow-up fix stacked on the still-open #2664, which already contains the merged Atmos Version Tracker feature (#2688).

Don't miss a new atmos release

NewReleases is sending notifications on new releases.