From ded71b6b1e2a68c4e5b2cda2fd78c70346e36b67 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 09:45:04 -0500 Subject: [PATCH 01/24] feat(ai): add browsable /ai/skills directory and skill categories Adds a searchable, category-grouped /ai/skills page (reusing the existing file-browser plugin behind /examples and /gists) with a per-skill detail page for each SKILL.md, replacing the hand-maintained "Available Skills" list in the docs that had drifted to half the real count (25 vs 52). Adds `metadata.category` to every bundled SKILL.md, threads it through `pkg/ai/skills/marketplace`, and exposes it via a new `--format` flag (table/json/yaml/csv/tsv) on `atmos ai skill list`. Co-Authored-By: Claude Sonnet 5 --- agent-skills/skills/atmos-ai/SKILL.md | 1 + agent-skills/skills/atmos-ansible/SKILL.md | 1 + agent-skills/skills/atmos-asciicast/SKILL.md | 2 + agent-skills/skills/atmos-auth/SKILL.md | 1 + .../skills/atmos-aws-compliance/SKILL.md | 1 + agent-skills/skills/atmos-aws-ecr/SKILL.md | 1 + agent-skills/skills/atmos-aws-eks/SKILL.md | 1 + .../skills/atmos-aws-security/SKILL.md | 1 + agent-skills/skills/atmos-cache/SKILL.md | 1 + agent-skills/skills/atmos-cast/SKILL.md | 1 + agent-skills/skills/atmos-ci/SKILL.md | 1 + agent-skills/skills/atmos-components/SKILL.md | 1 + .../skills/atmos-compositions/SKILL.md | 1 + agent-skills/skills/atmos-config/SKILL.md | 1 + agent-skills/skills/atmos-container/SKILL.md | 1 + .../skills/atmos-custom-commands/SKILL.md | 1 + .../skills/atmos-design-patterns/SKILL.md | 1 + .../skills/atmos-devcontainer/SKILL.md | 1 + .../skills/atmos-diagnostics/SKILL.md | 1 + agent-skills/skills/atmos-emulator/SKILL.md | 1 + agent-skills/skills/atmos-git/SKILL.md | 1 + agent-skills/skills/atmos-helm/SKILL.md | 1 + agent-skills/skills/atmos-helmfile/SKILL.md | 1 + agent-skills/skills/atmos-hooks/SKILL.md | 1 + agent-skills/skills/atmos-imports/SKILL.md | 1 + agent-skills/skills/atmos-init/SKILL.md | 1 + .../skills/atmos-introspection/SKILL.md | 1 + agent-skills/skills/atmos-kubernetes/SKILL.md | 1 + agent-skills/skills/atmos-lint/SKILL.md | 1 + agent-skills/skills/atmos-migration/SKILL.md | 1 + .../skills/atmos-modernization/SKILL.md | 1 + agent-skills/skills/atmos-packer/SKILL.md | 1 + agent-skills/skills/atmos-pro/SKILL.md | 1 + agent-skills/skills/atmos-profiles/SKILL.md | 1 + .../skills/atmos-project-layout/SKILL.md | 1 + agent-skills/skills/atmos-sbom/SKILL.md | 1 + agent-skills/skills/atmos-scaffold/SKILL.md | 1 + agent-skills/skills/atmos-schemas/SKILL.md | 1 + agent-skills/skills/atmos-secrets/SKILL.md | 1 + agent-skills/skills/atmos-settings/SKILL.md | 1 + agent-skills/skills/atmos-stacks/SKILL.md | 1 + agent-skills/skills/atmos-steps/SKILL.md | 1 + agent-skills/skills/atmos-stores/SKILL.md | 1 + agent-skills/skills/atmos-templates/SKILL.md | 1 + .../atmos-terraform-state-migrations/SKILL.md | 1 + agent-skills/skills/atmos-terraform/SKILL.md | 1 + agent-skills/skills/atmos-toolchain/SKILL.md | 1 + agent-skills/skills/atmos-validation/SKILL.md | 1 + agent-skills/skills/atmos-vendoring/SKILL.md | 1 + agent-skills/skills/atmos-version/SKILL.md | 1 + agent-skills/skills/atmos-workflows/SKILL.md | 1 + .../skills/atmos-yaml-functions/SKILL.md | 1 + cmd/ai/skill/list.go | 40 ++++++- cmd/ai/skill/list_test.go | 64 +++++++++- .../markdown/atmos_ai_skill_list_usage.md | 6 + pkg/ai/skills/marketplace/catalog.go | 2 + website/docs/ai/agent-skills.mdx | 111 ++++-------------- website/docs/ai/ai.mdx | 6 +- website/docs/ai/skill-marketplace.mdx | 3 +- website/docusaurus.config.js | 27 +++++ website/plugins/file-browser/index.js | 46 +++++++- .../src/components/FileBrowser/IndexPage.tsx | 36 +++++- .../components/FileBrowser/styles.module.css | 27 +++++ website/src/components/FileBrowser/types.ts | 2 + 64 files changed, 318 insertions(+), 105 deletions(-) diff --git a/agent-skills/skills/atmos-ai/SKILL.md b/agent-skills/skills/atmos-ai/SKILL.md index 0f0439e0aa4..9df1ae395e7 100644 --- a/agent-skills/skills/atmos-ai/SKILL.md +++ b/agent-skills/skills/atmos-ai/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos AI and MCP integrations: connect external AI assistants to A metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ai --- # Atmos AI and MCP diff --git a/agent-skills/skills/atmos-ansible/SKILL.md b/agent-skills/skills/atmos-ansible/SKILL.md index 00f6ed82cec..0993a7c5faa 100644 --- a/agent-skills/skills/atmos-ansible/SKILL.md +++ b/agent-skills/skills/atmos-ansible/SKILL.md @@ -4,6 +4,7 @@ description: "Ansible orchestration: playbook execution, variable passing, inven metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Ansible Orchestration diff --git a/agent-skills/skills/atmos-asciicast/SKILL.md b/agent-skills/skills/atmos-asciicast/SKILL.md index 6be0881ba24..e486965b3b0 100644 --- a/agent-skills/skills/atmos-asciicast/SKILL.md +++ b/agent-skills/skills/atmos-asciicast/SKILL.md @@ -1,6 +1,8 @@ --- name: atmos-asciicast description: Create and review portable Atmos CLI asciicast demos for community-facing documentation, examples, and training materials. +metadata: + category: dev-tooling --- # Atmos Asciicast Skill diff --git a/agent-skills/skills/atmos-auth/SKILL.md b/agent-skills/skills/atmos-auth/SKILL.md index 1226b4e4aa5..da94ea8bfd0 100644 --- a/agent-skills/skills/atmos-auth/SKILL.md +++ b/agent-skills/skills/atmos-auth/SKILL.md @@ -4,6 +4,7 @@ description: "Authentication and identity management: providers (SSO/SAML/OIDC/G metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: security --- # Atmos Authentication and Identity Management diff --git a/agent-skills/skills/atmos-aws-compliance/SKILL.md b/agent-skills/skills/atmos-aws-compliance/SKILL.md index b6b62a7b700..ce2078fe94e 100644 --- a/agent-skills/skills/atmos-aws-compliance/SKILL.md +++ b/agent-skills/skills/atmos-aws-compliance/SKILL.md @@ -4,6 +4,7 @@ description: "AWS compliance commands in Atmos: atmos aws compliance report, Sec metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: security --- # Atmos AWS Compliance diff --git a/agent-skills/skills/atmos-aws-ecr/SKILL.md b/agent-skills/skills/atmos-aws-ecr/SKILL.md index b99c975bb64..53eab3b9209 100644 --- a/agent-skills/skills/atmos-aws-ecr/SKILL.md +++ b/agent-skills/skills/atmos-aws-ecr/SKILL.md @@ -4,6 +4,7 @@ description: "AWS ECR commands in Atmos: atmos aws ecr login, ECR auth integrati metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: aws --- # Atmos AWS ECR diff --git a/agent-skills/skills/atmos-aws-eks/SKILL.md b/agent-skills/skills/atmos-aws-eks/SKILL.md index bf0b6a381b0..594622bb3d3 100644 --- a/agent-skills/skills/atmos-aws-eks/SKILL.md +++ b/agent-skills/skills/atmos-aws-eks/SKILL.md @@ -4,6 +4,7 @@ description: "AWS EKS commands in Atmos: atmos aws eks update-kubeconfig, atmos metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: aws --- # Atmos AWS EKS diff --git a/agent-skills/skills/atmos-aws-security/SKILL.md b/agent-skills/skills/atmos-aws-security/SKILL.md index d031dcce9d2..6b944e4c606 100644 --- a/agent-skills/skills/atmos-aws-security/SKILL.md +++ b/agent-skills/skills/atmos-aws-security/SKILL.md @@ -4,6 +4,7 @@ description: "AWS security finding analysis: analyze findings, map to Atmos comp metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: security --- # Atmos AWS Security Finding Analysis diff --git a/agent-skills/skills/atmos-cache/SKILL.md b/agent-skills/skills/atmos-cache/SKILL.md index f3634880f3a..efd665fa6b7 100644 --- a/agent-skills/skills/atmos-cache/SKILL.md +++ b/agent-skills/skills/atmos-cache/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos caching: CI cache configuration and commands, GitHub Actions metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation --- # Atmos Cache diff --git a/agent-skills/skills/atmos-cast/SKILL.md b/agent-skills/skills/atmos-cast/SKILL.md index a9eacb65f31..a59bbb6b3ca 100644 --- a/agent-skills/skills/atmos-cast/SKILL.md +++ b/agent-skills/skills/atmos-cast/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos cast recording and rendering: atmos cast play/render, output metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: dev-tooling --- # Atmos Cast diff --git a/agent-skills/skills/atmos-ci/SKILL.md b/agent-skills/skills/atmos-ci/SKILL.md index 4493a256215..ebd963a0fc7 100644 --- a/agent-skills/skills/atmos-ci/SKILL.md +++ b/agent-skills/skills/atmos-ci/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos CI: Native CI with GitHub Actions containers, native outputs metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation references: - references/native-ci.md --- diff --git a/agent-skills/skills/atmos-components/SKILL.md b/agent-skills/skills/atmos-components/SKILL.md index 83d378a86fa..80ff84f7637 100644 --- a/agent-skills/skills/atmos-components/SKILL.md +++ b/agent-skills/skills/atmos-components/SKILL.md @@ -4,6 +4,7 @@ description: "Component architecture: Terraform root modules, remote source prov metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config --- # Atmos Component Architecture diff --git a/agent-skills/skills/atmos-compositions/SKILL.md b/agent-skills/skills/atmos-compositions/SKILL.md index 5f532e33b62..14cc846b671 100644 --- a/agent-skills/skills/atmos-compositions/SKILL.md +++ b/agent-skills/skills/atmos-compositions/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos compositions: named service groupings, compositions..s metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: templating-data --- # Atmos Compositions diff --git a/agent-skills/skills/atmos-config/SKILL.md b/agent-skills/skills/atmos-config/SKILL.md index 0e6c0d7ee63..55f770f56d8 100644 --- a/agent-skills/skills/atmos-config/SKILL.md +++ b/agent-skills/skills/atmos-config/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos root configuration: atmos.yaml discovery, precedence, deep m metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config references: - references/sections-reference.md --- diff --git a/agent-skills/skills/atmos-container/SKILL.md b/agent-skills/skills/atmos-container/SKILL.md index ae77e8e9ac4..fe0c69bfa98 100644 --- a/agent-skills/skills/atmos-container/SKILL.md +++ b/agent-skills/skills/atmos-container/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos container components: components.container, Docker Compose m metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Container Components diff --git a/agent-skills/skills/atmos-custom-commands/SKILL.md b/agent-skills/skills/atmos-custom-commands/SKILL.md index b55aaeb584c..3eacf535840 100644 --- a/agent-skills/skills/atmos-custom-commands/SKILL.md +++ b/agent-skills/skills/atmos-custom-commands/SKILL.md @@ -4,6 +4,7 @@ description: "Custom CLI commands: command definition in atmos.yaml, arguments, metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation references: - references/command-syntax.md --- diff --git a/agent-skills/skills/atmos-design-patterns/SKILL.md b/agent-skills/skills/atmos-design-patterns/SKILL.md index 3d7dde1bf8b..136f6a4f0a6 100644 --- a/agent-skills/skills/atmos-design-patterns/SKILL.md +++ b/agent-skills/skills/atmos-design-patterns/SKILL.md @@ -4,6 +4,7 @@ description: "Design patterns: stack organization, component catalogs, inheritan metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config --- # Atmos Design Patterns diff --git a/agent-skills/skills/atmos-devcontainer/SKILL.md b/agent-skills/skills/atmos-devcontainer/SKILL.md index 58357d2cf79..9ad7b404d28 100644 --- a/agent-skills/skills/atmos-devcontainer/SKILL.md +++ b/agent-skills/skills/atmos-devcontainer/SKILL.md @@ -4,6 +4,7 @@ description: "Devcontainer orchestration: start/stop/attach/shell/exec/rebuild, metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: dev-tooling references: - references/commands-reference.md --- diff --git a/agent-skills/skills/atmos-diagnostics/SKILL.md b/agent-skills/skills/atmos-diagnostics/SKILL.md index b1a7bab2491..aaa7d300474 100644 --- a/agent-skills/skills/atmos-diagnostics/SKILL.md +++ b/agent-skills/skills/atmos-diagnostics/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos diagnostics: machine-readable JSONL event streams, diagnosti metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: dev-tooling --- # Atmos Diagnostics diff --git a/agent-skills/skills/atmos-emulator/SKILL.md b/agent-skills/skills/atmos-emulator/SKILL.md index 9dbd3b20ea5..4d8bb1b2bca 100644 --- a/agent-skills/skills/atmos-emulator/SKILL.md +++ b/agent-skills/skills/atmos-emulator/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos emulator components: local AWS/GCP/Azure/Kubernetes/Vault/Op metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Emulators diff --git a/agent-skills/skills/atmos-git/SKILL.md b/agent-skills/skills/atmos-git/SKILL.md index 191c1b45675..e2df6b23ef9 100644 --- a/agent-skills/skills/atmos-git/SKILL.md +++ b/agent-skills/skills/atmos-git/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos Git and GitOps: git.repositories, clone/pull/status/diff/com metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation --- # Atmos Git diff --git a/agent-skills/skills/atmos-helm/SKILL.md b/agent-skills/skills/atmos-helm/SKILL.md index 3ecfbcf2fcd..d675565ff37 100644 --- a/agent-skills/skills/atmos-helm/SKILL.md +++ b/agent-skills/skills/atmos-helm/SKILL.md @@ -4,6 +4,7 @@ description: "Native Helm components (experimental): Helm Go SDK rendering/apply metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Native Helm Components diff --git a/agent-skills/skills/atmos-helmfile/SKILL.md b/agent-skills/skills/atmos-helmfile/SKILL.md index 21eaf8a3505..274666a0fc2 100644 --- a/agent-skills/skills/atmos-helmfile/SKILL.md +++ b/agent-skills/skills/atmos-helmfile/SKILL.md @@ -4,6 +4,7 @@ description: "Helmfile orchestration: sync/apply/destroy/diff, Kubernetes deploy metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Helmfile Orchestration diff --git a/agent-skills/skills/atmos-hooks/SKILL.md b/agent-skills/skills/atmos-hooks/SKILL.md index cbf29f7eeef..5759136c835 100644 --- a/agent-skills/skills/atmos-hooks/SKILL.md +++ b/agent-skills/skills/atmos-hooks/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos hooks: lifecycle events, hook kinds, command/store/git/secur metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation --- # Atmos Hooks diff --git a/agent-skills/skills/atmos-imports/SKILL.md b/agent-skills/skills/atmos-imports/SKILL.md index 4b248f8b0ea..ebafbbe5240 100644 --- a/agent-skills/skills/atmos-imports/SKILL.md +++ b/agent-skills/skills/atmos-imports/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos imports: local and remote stack imports, go-getter schemes, metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config --- # Atmos Imports diff --git a/agent-skills/skills/atmos-init/SKILL.md b/agent-skills/skills/atmos-init/SKILL.md index f92913f5636..526c685072d 100644 --- a/agent-skills/skills/atmos-init/SKILL.md +++ b/agent-skills/skills/atmos-init/SKILL.md @@ -4,6 +4,7 @@ description: "Bootstrapping new Atmos projects with atmos init: built-in templat metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: scaffolding --- # Atmos Init diff --git a/agent-skills/skills/atmos-introspection/SKILL.md b/agent-skills/skills/atmos-introspection/SKILL.md index ff0084803f3..b0bfd156ae6 100644 --- a/agent-skills/skills/atmos-introspection/SKILL.md +++ b/agent-skills/skills/atmos-introspection/SKILL.md @@ -4,6 +4,7 @@ description: "Introspection & Querying: describe/list commands, config filtering metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: dev-tooling references: - references/commands-reference.md --- diff --git a/agent-skills/skills/atmos-kubernetes/SKILL.md b/agent-skills/skills/atmos-kubernetes/SKILL.md index e9c56dd4b34..2faba1592b6 100644 --- a/agent-skills/skills/atmos-kubernetes/SKILL.md +++ b/agent-skills/skills/atmos-kubernetes/SKILL.md @@ -4,6 +4,7 @@ description: "Native Kubernetes components (experimental): render/plan/diff/appl metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Native Kubernetes Components diff --git a/agent-skills/skills/atmos-lint/SKILL.md b/agent-skills/skills/atmos-lint/SKILL.md index 5676028b29f..9d4e0b20687 100644 --- a/agent-skills/skills/atmos-lint/SKILL.md +++ b/agent-skills/skills/atmos-lint/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos Terraform linting with TFLint: standalone `atmos terraform l metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation --- # Atmos Linting diff --git a/agent-skills/skills/atmos-migration/SKILL.md b/agent-skills/skills/atmos-migration/SKILL.md index 89bf8dbd8d5..6c82ab8198d 100644 --- a/agent-skills/skills/atmos-migration/SKILL.md +++ b/agent-skills/skills/atmos-migration/SKILL.md @@ -4,6 +4,7 @@ description: "Migrating to Atmos from existing IaC: techniques, tactics, and des metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: state-versioning references: - references/from-native-terraform.md - references/from-terraform-workspaces.md diff --git a/agent-skills/skills/atmos-modernization/SKILL.md b/agent-skills/skills/atmos-modernization/SKILL.md index 2577a7641ae..8781881be10 100644 --- a/agent-skills/skills/atmos-modernization/SKILL.md +++ b/agent-skills/skills/atmos-modernization/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos Modernization: migrate deprecated or legacy Atmos patterns t metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: state-versioning --- # Atmos Modernization diff --git a/agent-skills/skills/atmos-packer/SKILL.md b/agent-skills/skills/atmos-packer/SKILL.md index a8a0a8a5d08..4061485f5ba 100644 --- a/agent-skills/skills/atmos-packer/SKILL.md +++ b/agent-skills/skills/atmos-packer/SKILL.md @@ -4,6 +4,7 @@ description: "Packer orchestration: init/build/validate/inspect/output, machine metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Packer Orchestration diff --git a/agent-skills/skills/atmos-pro/SKILL.md b/agent-skills/skills/atmos-pro/SKILL.md index 3e6d554f7ed..dcd1192cdac 100644 --- a/agent-skills/skills/atmos-pro/SKILL.md +++ b/agent-skills/skills/atmos-pro/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos Pro setup and workflows: settings.pro, GitHub OIDC, affected metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation --- # Atmos Pro diff --git a/agent-skills/skills/atmos-profiles/SKILL.md b/agent-skills/skills/atmos-profiles/SKILL.md index 0f38e676aaf..3060781ce95 100644 --- a/agent-skills/skills/atmos-profiles/SKILL.md +++ b/agent-skills/skills/atmos-profiles/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos profiles: profile directories, --profile and ATMOS_PROFILE a metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config --- # Atmos Profiles diff --git a/agent-skills/skills/atmos-project-layout/SKILL.md b/agent-skills/skills/atmos-project-layout/SKILL.md index 6e60ea1b9f9..f073d14b39c 100644 --- a/agent-skills/skills/atmos-project-layout/SKILL.md +++ b/agent-skills/skills/atmos-project-layout/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos project layout: base_path, relative path resolution, root st metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config --- # Atmos Project Layout diff --git a/agent-skills/skills/atmos-sbom/SKILL.md b/agent-skills/skills/atmos-sbom/SKILL.md index 44a749fa10c..b1eb5b18d83 100644 --- a/agent-skills/skills/atmos-sbom/SKILL.md +++ b/agent-skills/skills/atmos-sbom/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos SBOM provenance: CycloneDX and SPDX generation from vendor a metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: state-versioning references: - ../atmos-ci/references/native-ci.md - ../atmos-vendoring/references/component-updater.md diff --git a/agent-skills/skills/atmos-scaffold/SKILL.md b/agent-skills/skills/atmos-scaffold/SKILL.md index fe58104874c..5f05d06a4f6 100644 --- a/agent-skills/skills/atmos-scaffold/SKILL.md +++ b/agent-skills/skills/atmos-scaffold/SKILL.md @@ -4,6 +4,7 @@ description: "Scaffold templates: authoring scaffold.yaml, form fields (types, v metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: scaffolding references: - references/scaffold-yaml-schema.md - references/merge-strategy.md diff --git a/agent-skills/skills/atmos-schemas/SKILL.md b/agent-skills/skills/atmos-schemas/SKILL.md index dfda9319719..4dc08c82729 100644 --- a/agent-skills/skills/atmos-schemas/SKILL.md +++ b/agent-skills/skills/atmos-schemas/SKILL.md @@ -4,6 +4,7 @@ description: "JSON Schema for Atmos: stack-manifest and atmos.yaml config schema metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.1.0" + category: core-config --- # Atmos JSON Schema System diff --git a/agent-skills/skills/atmos-secrets/SKILL.md b/agent-skills/skills/atmos-secrets/SKILL.md index a86c6992682..2cd5a1325e1 100644 --- a/agent-skills/skills/atmos-secrets/SKILL.md +++ b/agent-skills/skills/atmos-secrets/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos Secrets: declarative secrets.vars, !secret, cloud/Vault/1Pas metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: security --- # Atmos Secrets diff --git a/agent-skills/skills/atmos-settings/SKILL.md b/agent-skills/skills/atmos-settings/SKILL.md index a0d39cc0d86..9dfcebb9313 100644 --- a/agent-skills/skills/atmos-settings/SKILL.md +++ b/agent-skills/skills/atmos-settings/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos global settings: settings, logs, errors, env, docs, metadata metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config --- # Atmos Settings diff --git a/agent-skills/skills/atmos-stacks/SKILL.md b/agent-skills/skills/atmos-stacks/SKILL.md index 230ad433816..39bddb3d5f0 100644 --- a/agent-skills/skills/atmos-stacks/SKILL.md +++ b/agent-skills/skills/atmos-stacks/SKILL.md @@ -4,6 +4,7 @@ description: "Stack configuration: local and remote imports, inheritance, deep m metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config --- # Atmos Stack Configuration diff --git a/agent-skills/skills/atmos-steps/SKILL.md b/agent-skills/skills/atmos-steps/SKILL.md index 2582ab3877f..97efb0e8c38 100644 --- a/agent-skills/skills/atmos-steps/SKILL.md +++ b/agent-skills/skills/atmos-steps/SKILL.md @@ -4,6 +4,7 @@ description: "Shared Atmos step DSL for workflows, custom commands, hooks, and c metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation --- # Atmos Steps diff --git a/agent-skills/skills/atmos-stores/SKILL.md b/agent-skills/skills/atmos-stores/SKILL.md index c480496ce73..cdc1f5dc6b8 100644 --- a/agent-skills/skills/atmos-stores/SKILL.md +++ b/agent-skills/skills/atmos-stores/SKILL.md @@ -4,6 +4,7 @@ description: "Store backends: AWS SSM, AWS Secrets Manager, Azure Key Vault, Goo metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: templating-data --- # Atmos External Stores diff --git a/agent-skills/skills/atmos-templates/SKILL.md b/agent-skills/skills/atmos-templates/SKILL.md index 21e65bed5b0..ea26b99b2ae 100644 --- a/agent-skills/skills/atmos-templates/SKILL.md +++ b/agent-skills/skills/atmos-templates/SKILL.md @@ -4,6 +4,7 @@ description: "Go templates: Sprig/Gomplate functions, atmos.Component, atmos.Gom metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: templating-data references: - references/go-templates.md --- diff --git a/agent-skills/skills/atmos-terraform-state-migrations/SKILL.md b/agent-skills/skills/atmos-terraform-state-migrations/SKILL.md index 60e5ecae76c..3363e3c60c6 100644 --- a/agent-skills/skills/atmos-terraform-state-migrations/SKILL.md +++ b/agent-skills/skills/atmos-terraform-state-migrations/SKILL.md @@ -4,6 +4,7 @@ description: "Terraform state migration workflow with tfmigrate in Atmos: writin metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: state-versioning references: - references/tfmigrate-migration-patterns.md --- diff --git a/agent-skills/skills/atmos-terraform/SKILL.md b/agent-skills/skills/atmos-terraform/SKILL.md index ccde8605b77..bc9fc12db6b 100644 --- a/agent-skills/skills/atmos-terraform/SKILL.md +++ b/agent-skills/skills/atmos-terraform/SKILL.md @@ -4,6 +4,7 @@ description: "Terraform and OpenTofu orchestration: plan/apply/deploy, workspace metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: orchestrators --- # Atmos Terraform and OpenTofu Orchestration diff --git a/agent-skills/skills/atmos-toolchain/SKILL.md b/agent-skills/skills/atmos-toolchain/SKILL.md index 171c390189d..b13abc9d61c 100644 --- a/agent-skills/skills/atmos-toolchain/SKILL.md +++ b/agent-skills/skills/atmos-toolchain/SKILL.md @@ -4,6 +4,7 @@ description: "Toolchain management: declarative dependencies, automatic installs metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: dev-tooling references: - references/commands-reference.md --- diff --git a/agent-skills/skills/atmos-validation/SKILL.md b/agent-skills/skills/atmos-validation/SKILL.md index a5d50a3f387..2cf6e14746b 100644 --- a/agent-skills/skills/atmos-validation/SKILL.md +++ b/agent-skills/skills/atmos-validation/SKILL.md @@ -4,6 +4,7 @@ description: "Validate Atmos projects, components, arbitrary JSON Schema inputs, metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.1.0" + category: security references: - references/json-schema.md - references/opa-policies.md diff --git a/agent-skills/skills/atmos-vendoring/SKILL.md b/agent-skills/skills/atmos-vendoring/SKILL.md index 26ebd32f839..493d24e08ff 100644 --- a/agent-skills/skills/atmos-vendoring/SKILL.md +++ b/agent-skills/skills/atmos-vendoring/SKILL.md @@ -4,6 +4,7 @@ description: "Component vendoring: vendor.yaml and component.yaml manifests, imm metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: state-versioning references: - references/component-updater.md --- diff --git a/agent-skills/skills/atmos-version/SKILL.md b/agent-skills/skills/atmos-version/SKILL.md index 5f6721370c8..644ac16bd67 100644 --- a/agent-skills/skills/atmos-version/SKILL.md +++ b/agent-skills/skills/atmos-version/SKILL.md @@ -4,6 +4,7 @@ description: "Atmos Version Tracker: version tracks, lock files, managed externa metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: state-versioning --- # Atmos Version Tracker diff --git a/agent-skills/skills/atmos-workflows/SKILL.md b/agent-skills/skills/atmos-workflows/SKILL.md index 091c8146b59..641ecf4f54a 100644 --- a/agent-skills/skills/atmos-workflows/SKILL.md +++ b/agent-skills/skills/atmos-workflows/SKILL.md @@ -4,6 +4,7 @@ description: "Workflow automation: native step types, multi-step workflows, para metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: ci-automation references: - references/workflow-syntax.md --- diff --git a/agent-skills/skills/atmos-yaml-functions/SKILL.md b/agent-skills/skills/atmos-yaml-functions/SKILL.md index 7a98a063481..869fd32fc98 100644 --- a/agent-skills/skills/atmos-yaml-functions/SKILL.md +++ b/agent-skills/skills/atmos-yaml-functions/SKILL.md @@ -4,6 +4,7 @@ description: "YAML functions: !terraform.state, !terraform.output, !store, !stor metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: templating-data references: - references/yaml-functions.md --- diff --git a/cmd/ai/skill/list.go b/cmd/ai/skill/list.go index 75a855df4f6..a4d9ca13b3e 100644 --- a/cmd/ai/skill/list.go +++ b/cmd/ai/skill/list.go @@ -31,6 +31,9 @@ const ( detailLabelWidth = 13 ) +// flagFormat is the name of the output-format flag. +const flagFormat = "format" + // listParser handles flag parsing with Viper precedence for the list command. var listParser *flags.StandardParser @@ -49,6 +52,7 @@ type listEntry struct { version string source string displaySource string + category string available bool // True when part of the bundled catalog. installed bool // True when installed locally. skill *marketplace.InstalledSkill // Non-nil when installed. @@ -73,6 +77,7 @@ var listCmd = &cobra.Command{ // Get flags from Viper (supports CLI > ENV > config > defaults). detailed := v.GetBool("detailed") installedOnly := v.GetBool("installed") + outputFormat := listformat.Format(v.GetString(flagFormat)) // Create installer (which manages registry). installer, err := marketplace.NewInstaller(version.Version) @@ -85,7 +90,7 @@ var listCmd = &cobra.Command{ return err } - return renderSkillList(entries, installedOnly, detailed) + return renderSkillList(entries, installedOnly, detailed, outputFormat) }, } @@ -96,6 +101,9 @@ func init() { flags.WithEnvVars("detailed", "ATMOS_AI_SKILL_DETAILED"), flags.WithBoolFlag("installed", "", false, "Show only installed skills"), flags.WithEnvVars("installed", "ATMOS_AI_SKILL_INSTALLED"), + flags.WithStringFlag(flagFormat, "f", "", "Output format: table, json, yaml, csv, tsv"), + flags.WithEnvVars(flagFormat, "ATMOS_AI_SKILL_FORMAT"), + flags.WithValidValues(flagFormat, "table", "json", "yaml", "csv", "tsv"), ) // Register flags on the command. @@ -137,6 +145,7 @@ func buildListEntries(installer *marketplace.Installer) ([]listEntry, error) { version: c.Version, source: c.Source, displaySource: sourceBuiltIn, + category: c.Category, available: true, } if s, ok := byName[c.Name]; ok { @@ -172,10 +181,13 @@ func buildListEntries(installer *marketplace.Installer) ([]listEntry, error) { return entries, nil } -// renderSkillList renders the merged skill view honoring the --installed and -// --detailed flags. Counts are computed from the full catalog before filtering -// so the header is accurate regardless of which rows are shown. -func renderSkillList(entries []listEntry, installedOnly, detailed bool) error { +// renderSkillList renders the merged skill view honoring the --installed, +// --detailed, and --format flags. Counts are computed from the full catalog +// before filtering so the header is accurate regardless of which rows are +// shown. Non-table formats (json/yaml/csv/tsv) skip the human-oriented +// header, legend, and install hint, and ignore --detailed, since the +// structured rows already carry every field. +func renderSkillList(entries []listEntry, installedOnly, detailed bool, outputFormat listformat.Format) error { available, installed := countEntries(entries) display := entries @@ -188,6 +200,10 @@ func renderSkillList(entries []listEntry, installedOnly, detailed bool) error { return writeSkillListOutput("No skills installed.\n\nBrowse available skills with:\n atmos ai skill list\n") } + if outputFormat != "" && outputFormat != listformat.FormatTable { + return renderSkillListStructured(display, outputFormat) + } + var rendered string var err error if detailed { @@ -234,6 +250,18 @@ func renderEntrySummaries(entries []listEntry) (string, error) { return r.RenderToString(skillListRows(entries)) } +// renderSkillListStructured renders skills as structured data (json/yaml/csv/tsv), +// skipping the human-oriented header, legend, and install hint used by the table view. +func renderSkillListStructured(entries []listEntry, outputFormat listformat.Format) error { + selector, err := column.NewSelector(skillListColumns(), column.BuildColumnFuncMap()) + if err != nil { + return fmt.Errorf("error creating skill list column selector: %w", err) + } + + r := renderer.New(nil, selector, nil, outputFormat, "") + return r.Render(skillListRows(entries)) +} + // countEntries returns the number of available (uninstalled catalog) and installed entries. // The available count includes only catalog entries that are not yet installed, // so the header legend matches the hollow-dot rows shown in the listing. @@ -255,6 +283,7 @@ func skillListColumns() []column.Config { {Name: "Name", Value: "{{ .name }}"}, {Name: "Source", Value: "{{ .source }}"}, {Name: "State", Value: "{{ .state }}"}, + {Name: "Category", Value: "{{ .category }}"}, } } @@ -270,6 +299,7 @@ func skillListRows(entries []listEntry) []map[string]any { "name": e.name, "source": e.displaySource, "state": entryState(&e), + "category": e.category, }) } return rows diff --git a/cmd/ai/skill/list_test.go b/cmd/ai/skill/list_test.go index 5dee3529c45..21602f6fcf3 100644 --- a/cmd/ai/skill/list_test.go +++ b/cmd/ai/skill/list_test.go @@ -134,6 +134,7 @@ func resetListFlags(t *testing.T) { t.Helper() require.NoError(t, listCmd.Flags().Set("detailed", "false")) require.NoError(t, listCmd.Flags().Set("installed", "false")) + require.NoError(t, listCmd.Flags().Set(flagFormat, "")) } func TestListCmd_BasicProperties(t *testing.T) { @@ -160,16 +161,25 @@ func TestListCmd_Flags(t *testing.T) { assert.Equal(t, "bool", flag.Value.Type()) assert.Equal(t, "false", flag.DefValue) }) + + t.Run("format flag", func(t *testing.T) { + flag := listCmd.Flags().Lookup(flagFormat) + require.NotNil(t, flag) + assert.Equal(t, "string", flag.Value.Type()) + assert.Equal(t, "", flag.DefValue) + assert.Equal(t, "f", flag.Shorthand) + }) } func TestSkillListColumns(t *testing.T) { columns := skillListColumns() - require.Len(t, columns, 4) + require.Len(t, columns, 5) assert.Equal(t, " ", columns[0].Name) assert.Equal(t, 1, columns[0].Width) assert.Equal(t, "Name", columns[1].Name) assert.Equal(t, "Source", columns[2].Name) assert.Equal(t, "State", columns[3].Name) + assert.Equal(t, "Category", columns[4].Name) } func TestListCmd_EnvVarBinding(t *testing.T) { @@ -186,6 +196,13 @@ func TestListCmd_EnvVarBinding(t *testing.T) { require.NoError(t, listParser.BindToViper(v)) assert.True(t, v.GetBool("installed")) }) + + t.Run("format env var", func(t *testing.T) { + t.Setenv("ATMOS_AI_SKILL_FORMAT", "json") + v := viper.New() + require.NoError(t, listParser.BindToViper(v)) + assert.Equal(t, "json", v.GetString(flagFormat)) + }) } func TestBuildListEntries(t *testing.T) { @@ -209,11 +226,13 @@ func TestBuildListEntries(t *testing.T) { assert.False(t, entries[0].installed) assert.Equal(t, sourceBuiltIn, entries[0].displaySource) assert.Equal(t, catalog[0].Source, entries[0].source) + assert.Equal(t, catalog[0].Category, entries[0].category) assert.Equal(t, catalog[len(catalog)-1].Name, entries[len(entries)-1].name) assert.True(t, entries[len(entries)-1].available) assert.False(t, entries[len(entries)-1].installed) assert.Equal(t, sourceBuiltIn, entries[len(entries)-1].displaySource) assert.Equal(t, catalog[len(catalog)-1].Source, entries[len(entries)-1].source) + assert.Equal(t, catalog[len(catalog)-1].Category, entries[len(entries)-1].category) }) t.Run("installed catalog skill is marked installed with its version", func(t *testing.T) { @@ -429,6 +448,49 @@ func TestListCmd_DefaultOutput(t *testing.T) { } } +func TestListCmd_FormatJSON(t *testing.T) { + catalog, err := marketplace.Catalog() + require.NoError(t, err) + + tempHome := withTempHome(t) + skillPath := filepath.Join(tempHome, ".atmos", "skills", "atmos-terraform") + writeRegistry(t, tempHome, map[string]map[string]interface{}{ + "atmos-terraform": installedEntry( + "atmos-terraform", + "github.com/cloudposse/atmos//agent-skills/skills/atmos-terraform", + "1.0.0", + skillPath, + ), + }) + resetListFlags(t) + require.NoError(t, listCmd.Flags().Set(flagFormat, "json")) + + stdout := setupSkillListOutput(t) + require.NoError(t, listCmd.RunE(listCmd, []string{})) + output := stdout.String() + + // The human-oriented header, legend, and install hint must not appear. + assert.NotContains(t, output, "Atmos skills (") + assert.NotContains(t, output, "Install a built-in skill by name:") + + var rows []map[string]string + require.NoError(t, json.Unmarshal([]byte(output), &rows), "output must be valid JSON") + require.Len(t, rows, len(catalog)) + + var found bool + for _, row := range rows { + assert.Contains(t, row, "Name") + assert.Contains(t, row, "Source") + assert.Contains(t, row, "State") + assert.Contains(t, row, "Category") + if row["Name"] == "atmos-terraform" { + found = true + assert.NotEmpty(t, row["Category"]) + } + } + assert.True(t, found, "atmos-terraform must be present in JSON output") +} + func TestListCmd_InstalledOnly(t *testing.T) { t.Run("with an installed skill shows only it", func(t *testing.T) { tempHome := withTempHome(t) diff --git a/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md b/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md index b273090efee..d7c39ea4a3a 100644 --- a/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md +++ b/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md @@ -15,3 +15,9 @@ $ atmos ai skill list --installed ``` $ atmos ai skill list --detailed ``` + +- List as JSON + +``` +$ atmos ai skill list --format=json +``` diff --git a/pkg/ai/skills/marketplace/catalog.go b/pkg/ai/skills/marketplace/catalog.go index ecd08fc755c..7bc77361c66 100644 --- a/pkg/ai/skills/marketplace/catalog.go +++ b/pkg/ai/skills/marketplace/catalog.go @@ -29,6 +29,7 @@ type AvailableSkill struct { Description string Version string Source string + Category string } // Catalog returns the official skills bundled into the binary, sorted by name. @@ -99,6 +100,7 @@ func LookupBundledSkill(name string) (AvailableSkill, bool) { Description: metadata.Description, Version: metadata.GetVersion(), Source: fmt.Sprintf(bundledSourceFmt, name), + Category: metadata.GetCategory(), }, true } diff --git a/website/docs/ai/agent-skills.mdx b/website/docs/ai/agent-skills.mdx index 2fea70b64de..95e5bc79e2a 100644 --- a/website/docs/ai/agent-skills.mdx +++ b/website/docs/ai/agent-skills.mdx @@ -7,15 +7,16 @@ slug: /ai/agent-skills --- import Intro from '@site/src/components/Intro' import KeyPoints from '@site/src/components/KeyPoints' +import Link from '@docusaurus/Link' -Atmos ships 25 agent skills that give AI coding assistants deep, accurate knowledge of Atmos conventions, stack -configuration, Terraform orchestration, authentication, validation, and more. The skills live in the `agent-skills/` -folder at the root of the Atmos repository and work across all major AI tools. +Atmos ships a growing set of agent skills that give AI coding assistants deep, accurate knowledge of Atmos +conventions, stack configuration, Terraform orchestration, authentication, validation, and more. The skills live in +the `agent-skills/` folder at the root of the Atmos repository and work across all major AI tools. -- 25 domain-specific skills covering every Atmos subsystem +- Domain-specific skills covering every Atmos subsystem -- browse them all at [/ai/skills](/ai/skills) - Works with Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more - Progressive disclosure: AI loads only the skill it needs, keeping context focused - Portable SKILL.md format with YAML frontmatter and tiered reference files @@ -40,95 +41,29 @@ that skill, and only pulls in reference files when deep detail is needed. ## Available Skills -Atmos includes 25 skills covering every major subsystem: +Atmos skills cover every major subsystem -- Terraform and Helmfile orchestration, stack configuration, auth, +secrets, validation, CI, emulators, and more -- and the list keeps growing with each release. Rather than a static +list here (which drifts out of date as skills are added), browse the full, always-current, searchable set at: -
-
`atmos-ansible`
-
Ansible playbook execution, variable passing, inventory management.
- -
`atmos-asciicast`
-
Terminal cast recording workflows, fixtures, validation, and website cast assets.
- -
`atmos-auth`
-
Multi-provider auth (SSO/SAML/OIDC), identities, keyring, login/exec/shell.
- -
`atmos-aws-security`
-
AWS security findings, component mapping, remediation, and compliance reports.
- -
`atmos-components`
-
Terraform root modules, abstract components, component inheritance, versioning.
- -
`atmos-config`
-
Project configuration: atmos.yaml structure, all sections, discovery, merging, profiles.
- -
`atmos-custom-commands`
-
User-defined CLI commands in atmos.yaml with arguments, flags, and steps.
- -
`atmos-design-patterns`
-
Stack organization, component catalogs, inheritance, version management patterns.
- -
`atmos-devcontainer`
-
Devcontainer management: start/stop/shell/exec, Docker/Podman, identity integration.
- -
`atmos-gitops`
-
GitHub Actions, Spacelift, Atlantis, `atmos describe affected`, PR-based workflows.
- -
`atmos-helmfile`
-
Helmfile sync/apply/destroy/diff, Kubernetes deployments, EKS integration.
- -
`atmos-hooks`
-
Lifecycle hooks for Terraform operations, stores, scanners, git, commands, and steps.
- -
`atmos-introspection`
-
describe/list commands for querying stacks, components, dependencies, and change impact.
- -
`atmos-packer`
-
Packer init/build/validate, machine image building, template management.
+

+ + Browse the Agent Skills Directory → + +

-
`atmos-schemas`
-
JSON Schema for stack manifests, IDE auto-completion, schema validation.
- -
`atmos-stacks`
-
Stack YAML manifests, imports, inheritance, deep merging, vars, settings, metadata.
- -
`atmos-stores`
-
Store backends (SSM, Azure Key Vault, GCP Secret Manager, Redis, Artifactory).
- -
`atmos-steps`
-
Shared step DSL for workflows, custom commands, hooks, and cast recordings.
- -
`atmos-templates`
-
Go templates, Sprig/Gomplate functions, `atmos.Component`, datasources.
- -
`atmos-terraform`
-
Terraform plan/apply/deploy/destroy, workspace management, backend config.
- -
`atmos-toolchain`
-
CLI tool version management via Aqua registries, .tool-versions, install/exec.
- -
`atmos-validation`
-
Aggregate, affected, and native-CI validation; OPA/Rego, JSON Schema, EditorConfig, and GitHub Actions.
- -
`atmos-vendoring`
-
Vendor manifests, pulling from Git/S3/HTTP/OCI/Terraform Registry.
- -
`atmos-workflows`
-
Multi-step workflows, Go template support, cross-component orchestration.
- -
`atmos-yaml-functions`
-
YAML functions: `!terraform.state`, `!store`, `!env`, `!exec`, `!include`, `!aws.*`.
-
+Each skill's page there is generated directly from its `SKILL.md`, grouped by category, and links back to its +source on GitHub. ## Folder Structure -All 25 skills live in a single flat directory, packaged as one Claude Code plugin: +All skills live in a single flat directory, packaged as one Claude Code plugin: ```text agent-skills/ # Single plugin AGENTS.md # Skill-activation router (loaded first) .claude-plugin/plugin.json # Plugin manifest skills/ - atmos-terraform/ # One directory per skill (25 total) + atmos-terraform/ # One directory per skill SKILL.md # Primary instruction file (<500 lines) references/ # Deep-dive reference files atmos-stacks/ @@ -137,13 +72,13 @@ agent-skills/ # Single plugin atmos-config/ SKILL.md references/ - ... # 22 more skills + ... # One directory per skill -- see /ai/skills for the full list .claude/skills/ # Symlinks for auto-discovery (Atmos contributors) atmos-terraform -> ../../agent-skills/skills/atmos-terraform atmos-config -> ../../agent-skills/skills/atmos-config atmos-stacks -> ../../agent-skills/skills/atmos-stacks - ... # 25 symlinks total + ... # One symlink per skill docs/ # Repo-local contributor skill, not part of agent-skills SKILL.md ``` @@ -166,6 +101,7 @@ description: "Stack configuration: imports, inheritance, deep merging, locals, v metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" + category: core-config references: - references/import-patterns.md - references/inheritance-deep-merge.md @@ -189,6 +125,9 @@ Instructions for the AI assistant...
`metadata.version`
SemVer version of the skill content.
+
`metadata.category`
+
Groups the skill in the [Agent Skills Directory](/ai/skills) (e.g. `orchestrators`, `security`, `ci-automation`).
+
`references`
Optional list of deeper reference files the AI should load when more detail is needed.
@@ -298,6 +237,8 @@ Skills are maintained in the Atmos repository under `agent-skills/`. To contribu 2. Keep the primary `SKILL.md` under 500 lines for optimal context usage 3. Place detailed reference material in `references/` subdirectories 4. Update `AGENTS.md` to include your skill in the routing table -5. Use YAML frontmatter with `name`, `description`, `metadata` (containing `copyright` and `version`), and optionally `references` fields +5. Use YAML frontmatter with `name`, `description`, `metadata` (containing `copyright`, `version`, and `category`), and optionally `references` fields + +New skills appear automatically in the [Agent Skills Directory](/ai/skills) -- no separate doc update needed. See the [Atmos Contributing Guide](/community) for general contribution guidelines. diff --git a/website/docs/ai/ai.mdx b/website/docs/ai/ai.mdx index 377fd609569..6a4e3419ee9 100644 --- a/website/docs/ai/ai.mdx +++ b/website/docs/ai/ai.mdx @@ -211,9 +211,9 @@ ATMOS_AI=true ATMOS_SKILL=atmos-terraform,atmos-stacks atmos terraform plan vpc ## Agent Skills -Atmos ships 25 agent skills that give AI coding assistants deep knowledge of Atmos conventions. -Skills follow the [Agent Skills](https://agentskills.io) open standard and work across Claude Code, -Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more. +Atmos ships a growing set of agent skills -- browsable at [/ai/skills](/ai/skills) -- that give AI coding +assistants deep knowledge of Atmos conventions. Skills follow the [Agent Skills](https://agentskills.io) open +standard and work across Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more.
[`atmos ai skill`](/cli/commands/ai/skill)
diff --git a/website/docs/ai/skill-marketplace.mdx b/website/docs/ai/skill-marketplace.mdx index fccdbe13f53..446bb0cb1dc 100644 --- a/website/docs/ai/skill-marketplace.mdx +++ b/website/docs/ai/skill-marketplace.mdx @@ -25,7 +25,7 @@ Install skills using various GitHub URL formats: ```bash -# Install all 25 official Atmos skills (recommended) +# Install all official Atmos skills (recommended) -- browse them at /ai/skills atmos ai skill install cloudposse/atmos # With specific version tag @@ -258,6 +258,7 @@ atmos ai skill install cloudposse/atmos ## Related Documentation +- [Agent Skills Directory](/ai/skills) - Browse every official Atmos skill - [AI Skills](/cli/configuration/ai/skills) - Skill system overview and configuration - [AI Configuration](/cli/configuration/ai) - Configure AI providers - [AI Chat Command](/cli/commands/ai/chat) - Interactive AI chat interface diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 9ba68344e6a..3984498694d 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -499,6 +499,33 @@ const config = { disclaimer: 'Gists are examples that demonstrate a concept, but are not actively maintained and may not work in your environment or current versions of Atmos without adaptations.', }, ], + [ + path.resolve(__dirname, 'plugins', 'file-browser'), + { + id: 'skills', + sourceDir: '../agent-skills/skills', + routeBasePath: '/ai/skills', + title: 'Agent Skills', + description: 'Browse every Atmos agent skill — domain-specific knowledge that gives AI coding assistants deep, accurate understanding of Atmos conventions.', + githubRepo: 'cloudposse/atmos', + githubBranch: 'main', + githubPath: 'agent-skills/skills', + // Skill chapters, in display order (from each SKILL.md's metadata.category). + tagOrder: [ + 'Core Configuration & Architecture', + 'Orchestration Engines', + 'Auth, Secrets & Compliance', + 'AWS Integrations', + 'CI/CD & Automation', + 'State, Versioning & Provenance', + 'Developer Tooling', + 'Templates & Data', + 'AI & MCP', + 'Scaffolding & Init', + ], + searchable: true, + }, + ], ], presets: [ diff --git a/website/plugins/file-browser/index.js b/website/plugins/file-browser/index.js index 80d65ef3d45..a1e16cfe660 100644 --- a/website/plugins/file-browser/index.js +++ b/website/plugins/file-browser/index.js @@ -10,6 +10,12 @@ const crypto = require('crypto'); const matter = require('gray-matter'); +// File names recognized as an item's primary content — the ones treated as +// its "readme" for description/title/tags extraction and index-page preview. +// SKILL.md is the Agent Skills open standard's fixed file name (skills don't +// ship a README.md), so it's recognized alongside the usual README variants. +const PRIMARY_CONTENT_FILENAMES = new Set(['readme.md', 'readme.mdx', 'skill.md']); + // Default patterns to exclude from scanning. const DEFAULT_EXCLUDE_PATTERNS = [ '**/node_modules/**', @@ -131,6 +137,23 @@ const TAGS_MAP = { scaffolding: ['Scaffold', 'Init'], }; +// Display labels for the `metadata.category` slug used by SKILL.md front matter +// (see agent-skills/skills/*/SKILL.md). Content with no top-level `tags:` front +// matter and a recognized category slug is tagged with this label instead of +// falling through to TAGS_MAP, which has no entries for skill directory names. +const CATEGORY_LABELS = { + 'core-config': 'Core Configuration & Architecture', + orchestrators: 'Orchestration Engines', + security: 'Auth, Secrets & Compliance', + aws: 'AWS Integrations', + 'ci-automation': 'CI/CD & Automation', + 'state-versioning': 'State, Versioning & Provenance', + 'dev-tooling': 'Developer Tooling', + 'templating-data': 'Templates & Data', + ai: 'AI & MCP', + scaffolding: 'Scaffolding & Init', +}; + // Cast recordings for examples whose README.md doubles as copied scaffold // template output (`atmos scaffold generate` copies the whole source // directory verbatim) — Docusaurus front matter in that README would leak @@ -434,8 +457,10 @@ function scanDirectory(dirPath, relativePath, options) { githubUrl: generateGitHubUrl(entryRelativePath, options), }; - // Track README files. - if (entry.name.toLowerCase() === 'readme.md' || entry.name.toLowerCase() === 'readme.mdx') { + // Track README files. SKILL.md is recognized alongside README.md/README.mdx + // as primary content — it's the file name mandated by the Agent Skills + // open standard (https://agentskills.io), which the skills gallery instance uses. + if (PRIMARY_CONTENT_FILENAMES.has(entry.name.toLowerCase())) { readme = fileNode; } @@ -560,12 +585,19 @@ function scanExamples(sourceDir, options) { const castMeta = readmeMetadata.data.cast; const cast = castMeta && typeof castMeta === 'object' ? castMeta : CAST_MAP[entry.name] || {}; - // Tags: README front matter wins so examples can self-categorize; fall back - // to the hand-maintained map. The first tag is the example's index section. + // Tags: README front matter wins so examples can self-categorize; next, a + // recognized SKILL.md `metadata.category` slug (see CATEGORY_LABELS); then + // fall back to the hand-maintained map. The first tag is the index section. const frontmatterTags = Array.isArray(readmeMetadata.data.tags) ? readmeMetadata.data.tags.filter((tag) => typeof tag === 'string') : []; - const tags = frontmatterTags.length > 0 ? frontmatterTags : TAGS_MAP[entry.name] || []; + const categorySlug = readmeMetadata.data.metadata && readmeMetadata.data.metadata.category; + const categoryLabel = typeof categorySlug === 'string' ? CATEGORY_LABELS[categorySlug] : undefined; + const tags = frontmatterTags.length > 0 + ? frontmatterTags + : categoryLabel + ? [categoryLabel] + : TAGS_MAP[entry.name] || []; // Check for atmos.yaml. const hasAtmosYaml = tree.children.some( @@ -688,6 +720,9 @@ module.exports = function fileBrowserPlugin(context, options) { excludePatterns = [], maxFileSize = 100 * 1024, // 100KB default. tagOrder = DEFAULT_TAG_ORDER, + // Shows a free-text search box on the index page. Defaults to false so the + // existing examples/gists instances render unchanged unless opted in. + searchable = false, } = options; const mergedExcludePatterns = [...DEFAULT_EXCLUDE_PATTERNS, ...excludePatterns]; @@ -725,6 +760,7 @@ module.exports = function fileBrowserPlugin(context, options) { githubBranch, githubPath, disclaimer, + searchable, }, }; }, diff --git a/website/src/components/FileBrowser/IndexPage.tsx b/website/src/components/FileBrowser/IndexPage.tsx index 2ea5753085b..4220a8db7c1 100644 --- a/website/src/components/FileBrowser/IndexPage.tsx +++ b/website/src/components/FileBrowser/IndexPage.tsx @@ -30,21 +30,32 @@ interface IndexPageProps { export default function IndexPage({ treeData, optionsData }: IndexPageProps): JSX.Element { const { examples, featured = [], tags } = treeData; - const { routeBasePath, title, description } = optionsData; + const { routeBasePath, title, description, searchable } = optionsData; const [activeTag, setActiveTag] = useState(null); + const [searchQuery, setSearchQuery] = useState(''); - const filteredExamples = activeTag + const tagFilteredExamples = activeTag ? examples.filter((ex) => ex.tags.includes(activeTag)) : examples; + const query = searchQuery.trim().toLowerCase(); + const filteredExamples = query + ? tagFilteredExamples.filter((ex) => { + const haystack = [ex.name, ex.title, ex.description, ...ex.tags].join(' ').toLowerCase(); + return haystack.includes(query); + }) + : tagFilteredExamples; + // Group the "All" view into visible sections by each example's primary // (first) tag, in the site's tag order; anything untagged lands in "More". + // When searching, sections are built from the search results so empty + // sections drop out instead of showing a heading with nothing under it. const sections = [ ...tags.map((tag) => ({ tag, - examples: examples.filter((ex) => (ex.tags[0] ?? 'More') === tag), + examples: filteredExamples.filter((ex) => (ex.tags[0] ?? 'More') === tag), })), - { tag: 'More', examples: examples.filter((ex) => ex.tags.length === 0) }, + { tag: 'More', examples: filteredExamples.filter((ex) => ex.tags.length === 0) }, ].filter((section) => section.examples.length > 0); // Render a single example card. All cards use the friendly English title @@ -107,7 +118,22 @@ export default function IndexPage({ treeData, optionsData }: IndexPageProps): JS

{description}

- {activeTag === null && featured.length > 0 && ( + {searchable && ( +
+ setSearchQuery(e.target.value)} + /> +
+ Showing {filteredExamples.length} of {examples.length} +
+
+ )} + + {activeTag === null && !query && featured.length > 0 && (

Featured

diff --git a/website/src/components/FileBrowser/styles.module.css b/website/src/components/FileBrowser/styles.module.css index 105aab74f8c..5d0e27e3759 100644 --- a/website/src/components/FileBrowser/styles.module.css +++ b/website/src/components/FileBrowser/styles.module.css @@ -74,6 +74,33 @@ color: var(--ifm-heading-color); } +/* Search (opt-in via the `searchable` plugin option) */ +.searchContainer { + margin: 0 0 1.5rem 0; +} + +.searchInput { + width: 100%; + padding: 0.75rem 1rem; + font-size: 1rem; + border: 2px solid var(--ifm-color-emphasis-300); + border-radius: 8px; + background: var(--ifm-background-surface-color); + color: var(--ifm-font-color-base); + transition: border-color 0.2s ease; +} + +.searchInput:focus { + outline: none; + border-color: var(--ifm-color-primary); +} + +.searchResults { + margin-top: 0.5rem; + font-size: 0.875rem; + color: var(--ifm-color-emphasis-600); +} + /* Filter Bar */ .filterBar { display: flex; diff --git a/website/src/components/FileBrowser/types.ts b/website/src/components/FileBrowser/types.ts index d5c6dfa5bc8..313832f2150 100644 --- a/website/src/components/FileBrowser/types.ts +++ b/website/src/components/FileBrowser/types.ts @@ -95,6 +95,8 @@ export interface FileBrowserOptions { githubBranch: string; githubPath: string; disclaimer?: string; + /** Shows a free-text search box on the index page when true. */ + searchable?: boolean; } /** From b39f49e8f498babd7f7e3c884bb00e873ec055b1 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 16:30:03 -0500 Subject: [PATCH 02/24] docs(ai): polish agent skills directory nav, homepage count, and changelog Adds the changelog post and roadmap entry for the browsable Agent Skills Directory shipped in the prior commit, plus follow-up polish: a SkillCount component that renders the live skill count at build time (used on the homepage AI section instead of a hardcoded number), file-browser plugin card icon/CTA options, sidebar nav restructuring under Atmos AI, and doc updates for the new `--format` flag. Also fixes pre-existing EditorConfig indentation violations (3-space markdown list continuations) in several SKILL.md files, surfaced by the affected-file validator once those files were touched by this branch's earlier commit. --- agent-skills/skills/atmos-ansible/SKILL.md | 22 +++---- agent-skills/skills/atmos-container/SKILL.md | 6 +- agent-skills/skills/atmos-helmfile/SKILL.md | 18 +++--- agent-skills/skills/atmos-packer/SKILL.md | 24 ++++---- agent-skills/skills/atmos-stacks/SKILL.md | 2 +- agent-skills/skills/atmos-templates/SKILL.md | 10 ++-- agent-skills/skills/atmos-terraform/SKILL.md | 28 ++++----- ...04-native-container-image-ci-summaries.mdx | 2 +- .../2026-08-05-agent-skills-directory.mdx | 48 ++++++++++++++++ website/docs/ai/agent-skills.mdx | 5 +- website/docs/ai/ai.mdx | 3 +- website/docs/cli/commands/ai/skill.mdx | 5 +- website/docs/cli/commands/ci/ci.mdx | 1 + website/docs/cli/configuration/ai/skills.mdx | 2 +- website/docs/cli/configuration/ci/index.mdx | 2 +- .../projects/setup-editor/ai-assistants.mdx | 1 + website/docs/projects/setup-editor/index.mdx | 3 +- website/docusaurus.config.js | 2 + website/plugins/file-browser/index.js | 6 ++ website/sidebars.js | 18 +++++- website/src/components/AISection/index.js | 57 +++++++++++-------- .../src/components/FileBrowser/FileTree.tsx | 38 +++++++------ .../src/components/FileBrowser/IndexPage.tsx | 20 +++++-- .../components/FileBrowser/styles.module.css | 11 +++- website/src/components/FileBrowser/types.ts | 4 ++ website/src/components/SkillCount/index.tsx | 18 ++++++ website/src/data/roadmap.js | 1 + 27 files changed, 245 insertions(+), 112 deletions(-) create mode 100644 website/blog/2026-08-05-agent-skills-directory.mdx create mode 100644 website/src/components/SkillCount/index.tsx diff --git a/agent-skills/skills/atmos-ansible/SKILL.md b/agent-skills/skills/atmos-ansible/SKILL.md index 0993a7c5faa..a9514a8f0bc 100644 --- a/agent-skills/skills/atmos-ansible/SKILL.md +++ b/agent-skills/skills/atmos-ansible/SKILL.md @@ -23,16 +23,16 @@ configuration from stack manifests and handles all of these concerns automatical When you run `atmos ansible playbook`, Atmos performs the following sequence: 1. **Resolves stack configuration** -- Reads and deep-merges all stack manifests to produce the fully resolved - configuration for the target component in the target stack. + configuration for the target component in the target stack. 2. **Generates a variables file** -- Writes a YAML file containing all `vars` defined for the component in the - stack, following the naming convention `-.ansible.vars.yaml`. + stack, following the naming convention `-.ansible.vars.yaml`. 3. **Resolves the playbook** -- Determines the playbook to run from `--playbook` flag or - `settings.ansible.playbook` in the stack manifest. + `settings.ansible.playbook` in the stack manifest. 4. **Resolves the inventory** -- Determines the inventory source from `--inventory` flag or - `settings.ansible.inventory` in the stack manifest. + `settings.ansible.inventory` in the stack manifest. 5. **Sets environment variables** -- Applies all `env` settings from the stack manifest. 6. **Executes `ansible-playbook`** -- Runs the playbook in the component directory, passing the generated - variables file via `--extra-vars @` and any additional native flags. + variables file via `--extra-vars @` and any additional native flags. 7. **Cleans up** -- Removes the generated variables file after execution completes. This means a single command like `atmos ansible playbook webserver -s prod` replaces what would normally require @@ -446,24 +446,24 @@ atmos ansible playbook webserver -s prod --dry-run > prompts. For fully automated pipelines, invoke `ansible-playbook` directly from a CI step. 1. **Use stack manifest settings for playbook configuration.** Define `settings.ansible.playbook` and - `settings.ansible.inventory` rather than passing flags every time. + `settings.ansible.inventory` rather than passing flags every time. 2. **Centralize defaults in catalog files.** Define common settings in catalog defaults and override only - what differs per environment. + what differs per environment. 3. **Use `dependencies.components` for ordering.** Define dependencies when playbooks need to run - after infrastructure is provisioned, such as after Terraform components. + after infrastructure is provisioned, such as after Terraform components. 4. **Keep playbooks focused.** Create small, task-specific playbooks rather than monolithic automation. 5. **Use `env` for Ansible configuration.** Configure Ansible behavior through environment variables - rather than `ansible.cfg` for consistency across environments. + rather than `ansible.cfg` for consistency across environments. 6. **Leverage inheritance.** Use abstract components and inheritance for shared playbook configurations - across environments. + across environments. 7. **Use `--dry-run` before production runs.** Preview the commands Atmos will execute before running - against production infrastructure. + against production infrastructure. ## Additional Resources diff --git a/agent-skills/skills/atmos-container/SKILL.md b/agent-skills/skills/atmos-container/SKILL.md index fe0c69bfa98..93eee7a74db 100644 --- a/agent-skills/skills/atmos-container/SKILL.md +++ b/agent-skills/skills/atmos-container/SKILL.md @@ -94,13 +94,13 @@ Migration process: 1. Inventory Compose services and split long-lived services into separate container components. 2. Move shared `.env` values into stack vars, component env, declared secrets, or `!secret` - references. + references. 3. Use `composition: ` so former Compose services validate and run as one system. 4. Replace `docker compose up/down/logs/exec/ps` with the matching `atmos container` commands. 5. Use workflow `container`, `wait`, `wait-all`, and explicit dependencies for startup order - instead of Compose-only `depends_on` assumptions. + instead of Compose-only `depends_on` assumptions. 6. Prefer first-class `components.container` for Atmos-managed services. Keep a native Compose - file only when the project must remain compatible with external Compose tooling. + file only when the project must remain compatible with external Compose tooling. ## Operational Guidance diff --git a/agent-skills/skills/atmos-helmfile/SKILL.md b/agent-skills/skills/atmos-helmfile/SKILL.md index 274666a0fc2..4222bcb3d9b 100644 --- a/agent-skills/skills/atmos-helmfile/SKILL.md +++ b/agent-skills/skills/atmos-helmfile/SKILL.md @@ -18,12 +18,12 @@ resolves the full configuration from stack manifests and handles all of these co When you run any `atmos helmfile` command, Atmos performs the following sequence: 1. **Resolves stack configuration** -- Reads and deep-merges all stack manifests to produce the fully resolved - configuration for the target component in the target stack. + configuration for the target component in the target stack. 2. **Generates variable file** -- Writes a varfile containing all `vars` defined for the component in the stack. 3. **Configures EKS authentication** -- If `use_eks: true`, runs `aws eks update-kubeconfig` to generate - kubeconfig from the EKS cluster and set up authentication. + kubeconfig from the EKS cluster and set up authentication. 4. **Executes the requested command** -- Runs `helmfile diff`, `apply`, `sync`, `destroy`, etc. with the - generated varfile and any additional flags. + generated varfile and any additional flags. This means a single command like `atmos helmfile apply nginx-ingress -s ue2-dev` replaces what would normally require multiple manual steps: configuring kubeconfig, writing variable files, and then running helmfile. @@ -455,24 +455,24 @@ components: ## Best Practices 1. **Use diff before apply.** Run `helmfile diff` first, review the output, then run `helmfile apply` - to ensure exactly the reviewed changes are applied. + to ensure exactly the reviewed changes are applied. 2. **Use deploy for combined operations.** The `deploy` command runs diff and apply in a single step. 3. **Store kubeconfig in `/dev/shm`.** When using EKS integration, use shared memory for security - since files are not persisted to disk. + since files are not persisted to disk. 4. **Use `cluster_name_template` instead of `cluster_name_pattern`.** The Go template syntax is - more powerful and the token replacement pattern is deprecated. + more powerful and the token replacement pattern is deprecated. 5. **Use source-based version pinning for multi-environment setups.** Override the `source.version` - per environment to control which version is deployed to each stack. + per environment to control which version is deployed to each stack. 6. **Use `atmos describe component`** to debug configuration resolution issues. It shows the fully - merged result of all stack manifest inheritance. + merged result of all stack manifest inheritance. 7. **Leverage component inheritance** to share common configuration across Helmfile components - and reduce duplication in stack manifests. + and reduce duplication in stack manifests. ## Additional Resources diff --git a/agent-skills/skills/atmos-packer/SKILL.md b/agent-skills/skills/atmos-packer/SKILL.md index 4061485f5ba..b4bce726129 100644 --- a/agent-skills/skills/atmos-packer/SKILL.md +++ b/agent-skills/skills/atmos-packer/SKILL.md @@ -18,16 +18,16 @@ Atmos resolves the full configuration from stack manifests and handles all of th When you run any `atmos packer` command, Atmos performs the following sequence: 1. **Resolves stack configuration** -- Reads and deep-merges all stack manifests to produce the fully resolved - configuration for the target component in the target stack. + configuration for the target component in the target stack. 2. **Generates variable file** -- Writes a variable file containing all `vars` defined for the component - in the stack, making them available to the Packer template. + in the stack, making them available to the Packer template. 3. **Auto-provisions source (if configured)** -- If the component has a `source` field and the target - directory does not exist, Atmos downloads the component via JIT vendoring before proceeding. + directory does not exist, Atmos downloads the component via JIT vendoring before proceeding. 4. **Resolves template path** -- Determines the Packer template to use from the `--template` flag, - `settings.packer.template` in the stack manifest, or defaults to `.` (all `*.pkr.hcl` files). + `settings.packer.template` in the stack manifest, or defaults to `.` (all `*.pkr.hcl` files). 5. **Sets environment variables** -- Applies any `env` values defined in the stack configuration. 6. **Executes the requested command** -- Runs `packer init`, `build`, `validate`, `inspect`, etc. with - the generated variable file and any additional flags. + the generated variable file and any additional flags. This means a single command like `atmos packer build ubuntu-base -s ue2-dev` replaces what would normally require manually writing variable files, configuring paths, and running packer directly. @@ -434,25 +434,25 @@ PACKER_LOG=1 atmos packer build ubuntu-base -s ue2-dev ## Best Practices 1. **Use directory mode for multi-file components.** Omit `--template` to let Packer load all - `*.pkr.hcl` files from the component directory. + `*.pkr.hcl` files from the component directory. 2. **Validate before building.** Run `atmos packer validate` before `atmos packer build` to catch - syntax and configuration errors early. + syntax and configuration errors early. 3. **Use stack inheritance for shared defaults.** Define base image configuration in catalog - manifests and override per environment. + manifests and override per environment. 4. **Configure manifests for build tracking.** Use Packer's manifest post-processor to track - build artifacts, then query them with `atmos packer output`. + build artifacts, then query them with `atmos packer output`. 5. **Use JIT vendoring for version control per environment.** The `source` field enables different - template versions for dev, staging, and production stacks. + template versions for dev, staging, and production stacks. 6. **Pin production versions.** Keep production stacks on stable, tested versions while allowing - development stacks to use newer template versions. + development stacks to use newer template versions. 7. **Use `atmos describe component`** to debug configuration resolution issues. It shows the fully - merged result of all stack manifest inheritance. + merged result of all stack manifest inheritance. ## Additional Resources diff --git a/agent-skills/skills/atmos-stacks/SKILL.md b/agent-skills/skills/atmos-stacks/SKILL.md index 39bddb3d5f0..06a5c703d7a 100644 --- a/agent-skills/skills/atmos-stacks/SKILL.md +++ b/agent-skills/skills/atmos-stacks/SKILL.md @@ -367,7 +367,7 @@ For the full current function inventory, load `atmos-yaml-functions`. 6. **Use `name` or `name_template` for stack naming**: If legacy `name_pattern` is present, migrate it. 7. **Use `atmos describe stacks` liberally**: Always verify the resolved configuration before applying changes. 8. **Treat remote imports as config only**: use component `source:` or `atmos vendor pull` when imported - config references component code that is not already local. + config references component code that is not already local. ## References diff --git a/agent-skills/skills/atmos-templates/SKILL.md b/agent-skills/skills/atmos-templates/SKILL.md index ea26b99b2ae..9996465be9f 100644 --- a/agent-skills/skills/atmos-templates/SKILL.md +++ b/agent-skills/skills/atmos-templates/SKILL.md @@ -226,21 +226,21 @@ are not supported in stack manifests (only in `atmos.yaml`). 1. **Prefer YAML functions over Go templates** -- Type-safe, cannot break YAML 2. **Prefer `!store` over `atmos.Component` for outputs** -- Avoids Terraform initialization 3. **Use `atmos.GomplateDatasource` instead of `datasource`** -- Built-in caching prevents - redundant API calls + redundant API calls 4. **Minimize `atmos.Component` usage** -- Each call may initialize Terraform 5. **All template functions cache results** per execution for repeated calls ## Common Pitfalls 1. **Go templates break YAML** -- Unquoted `{{ }}` can cause YAML parse errors. Always quote - template expressions. + template expressions. 2. **Type confusion** -- Go templates always return strings. Use `!template` with `toJson` for - complex types. + complex types. 3. **Indentation issues** -- Multi-line template output can break YAML indentation. 4. **Sprig/Gomplate conflicts** -- The `env` function exists in both libraries with different - syntax. Use `getenv` for Gomplate's version when both are enabled. + syntax. Use `getenv` for Gomplate's version when both are enabled. 5. **Performance degradation** -- Overuse of `atmos.Component` or `!terraform.output` across - many stacks can dramatically slow `atmos describe stacks` and `atmos describe affected`. + many stacks can dramatically slow `atmos describe stacks` and `atmos describe affected`. ## Additional Resources diff --git a/agent-skills/skills/atmos-terraform/SKILL.md b/agent-skills/skills/atmos-terraform/SKILL.md index bc9fc12db6b..56c24d9d27b 100644 --- a/agent-skills/skills/atmos-terraform/SKILL.md +++ b/agent-skills/skills/atmos-terraform/SKILL.md @@ -118,19 +118,19 @@ OpenTofu. When you run any `atmos terraform` command, Atmos performs the following sequence: 1. **Resolves stack configuration** -- Reads and deep-merges all stack manifests to produce the fully resolved - configuration for the target component in the target stack. + configuration for the target component in the target stack. 2. **Generates backend configuration** -- Writes a `backend.tf.json` file in the component directory with the - correct backend settings (S3 bucket, key, region, etc.) derived from the stack config. + correct backend settings (S3 bucket, key, region, etc.) derived from the stack config. 3. **Generates variable file** -- Writes a `terraform.tfvars.json` file containing all `vars` defined for the - component in the stack. + component in the stack. 4. **Provisions backend infrastructure** -- If `provision.backend.enabled: true`, creates the backend storage - (e.g., S3 bucket) before Terraform init. + (e.g., S3 bucket) before Terraform init. 5. **Runs `terraform init`** -- Initializes the working directory with the generated backend config. Cleans - `.terraform/environment` first and optionally adds `-reconfigure`. + `.terraform/environment` first and optionally adds `-reconfigure`. 6. **Selects or creates workspace** -- Calculates the Terraform workspace name from context variables and - selects it (or creates it if it does not exist). + selects it (or creates it if it does not exist). 7. **Executes the requested command** -- Runs `terraform plan`, `apply`, `destroy`, etc. with the generated - varfile and any additional flags. + varfile and any additional flags. This means a single command like `atmos terraform plan vpc -s plat-ue2-dev` replaces what would normally require multiple manual steps: configuring the backend, writing tfvars, running init, selecting the workspace, @@ -426,29 +426,29 @@ corresponding `ATMOS_COMPONENTS_TERRAFORM_*` environment variable override. See ## Best Practices 1. **Use the two-stage plan/apply workflow for production.** Run `plan` first, review the output, then - `apply --from-plan` to ensure exactly the reviewed changes are applied. + `apply --from-plan` to ensure exactly the reviewed changes are applied. 2. **Use `deploy` for automated pipelines.** It combines plan and apply with auto-approve, ideal for CI/CD. 3. **Always preview multi-component operations with `--dry-run`** before executing `--all` or `--affected`. 4. **Let Atmos manage backend configuration.** Set `auto_generate_backend_file: true` and define backend - settings in stack manifests rather than hardcoding in Terraform modules. + settings in stack manifests rather than hardcoding in Terraform modules. 5. **Use `atmos describe component`** to debug configuration resolution issues. It shows the fully merged - result of all stack manifest inheritance. + result of all stack manifest inheritance. 6. **Add generated files to .gitignore.** The `backend.tf.json` and `terraform.tfvars.json` files are - generated at runtime and should not be committed. + generated at runtime and should not be committed. 7. **Use `atmos terraform shell`** for interactive debugging. It sets up the full context so you can - run native terraform commands directly. + run native terraform commands directly. 8. **Enable backend provisioning** (`provision.backend.enabled: true`) to solve the Terraform bootstrap - problem and ensure backends exist before first use. + problem and ensure backends exist before first use. 9. **Use source provisioning with workdirs** when components are pulled via `source`, especially in CI - or any multi-stack workflow that can run concurrently. + or any multi-stack workflow that can run concurrently. ## Additional Resources diff --git a/website/blog/2026-07-04-native-container-image-ci-summaries.mdx b/website/blog/2026-07-04-native-container-image-ci-summaries.mdx index 056b902978c..d7b50b7a3fc 100644 --- a/website/blog/2026-07-04-native-container-image-ci-summaries.mdx +++ b/website/blog/2026-07-04-native-container-image-ci-summaries.mdx @@ -2,7 +2,7 @@ slug: native-container-image-ci-summaries title: "Native Container Image Summaries in CI" authors: [osterman] -tags: [feature, ci] +tags: [feature] date: 2026-07-04T12:00:00.000Z --- diff --git a/website/blog/2026-08-05-agent-skills-directory.mdx b/website/blog/2026-08-05-agent-skills-directory.mdx new file mode 100644 index 00000000000..068e048cbe3 --- /dev/null +++ b/website/blog/2026-08-05-agent-skills-directory.mdx @@ -0,0 +1,48 @@ +--- +slug: agent-skills-directory +title: "Browse Every Atmos Agent Skill, Always Up to Date" +authors: [osterman] +tags: [feature, dx] +--- + +A hand-maintained list is only accurate on the day someone writes it. Add a new item to the underlying +system and forget to update the doc -- which happens constantly once a catalog is large enough to have +real momentum -- and the list quietly falls behind. Readers trust it anyway, because nothing on the page +signals that it's stale. + + + +## The Problem + +Atmos's own [agent skills](/ai/agent-skills) documentation had exactly this problem. The page hand-listed +each skill in a static table, and as new skills shipped, the list wasn't updated to match -- it drifted to +roughly half the real count, with a couple of stale entries pointing at skills that no longer existed. There +was also no way to search or filter -- just one long page to scroll and skim. + +## The Fix + +The [Agent Skills Directory](/ai/skills) replaces that static list with a page generated directly from the +skills themselves. Every skill gets its own detail page rendering its full instructions, skills are grouped +into categories, and a search box filters by name, description, or category. Add a skill, and it appears in +the directory automatically -- there's no separate doc to remember to update. + +`atmos ai skill list` also gained a `--format` flag and now shows each skill's category, so the same +categorization is available from the CLI, not just the website. + +## How to Use It + +Browse and search the directory at [atmos.tools/ai/skills](/ai/skills), or from the CLI: + +```shell +# Table view, now with a Category column +atmos ai skill list + +# Machine-readable output for scripting +atmos ai skill list --format=json +atmos ai skill list --format=yaml +``` + +## Get Involved + +See the [Agent Skills](/ai/agent-skills) guide for how skills are structured and how to contribute one. Skill +ideas and contributions are welcome in the [Atmos community](https://github.com/cloudposse/atmos). diff --git a/website/docs/ai/agent-skills.mdx b/website/docs/ai/agent-skills.mdx index 95e5bc79e2a..24d14dba31a 100644 --- a/website/docs/ai/agent-skills.mdx +++ b/website/docs/ai/agent-skills.mdx @@ -8,15 +8,16 @@ slug: /ai/agent-skills import Intro from '@site/src/components/Intro' import KeyPoints from '@site/src/components/KeyPoints' import Link from '@docusaurus/Link' +import SkillCount from '@site/src/components/SkillCount' -Atmos ships a growing set of agent skills that give AI coding assistants deep, accurate knowledge of Atmos +Atmos ships agent skills that give AI coding assistants deep, accurate knowledge of Atmos conventions, stack configuration, Terraform orchestration, authentication, validation, and more. The skills live in the `agent-skills/` folder at the root of the Atmos repository and work across all major AI tools. -- Domain-specific skills covering every Atmos subsystem -- browse them all at [/ai/skills](/ai/skills) +- domain-specific skills covering every Atmos subsystem -- browse them all at [/ai/skills](/ai/skills) - Works with Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more - Progressive disclosure: AI loads only the skill it needs, keeping context focused - Portable SKILL.md format with YAML frontmatter and tiered reference files diff --git a/website/docs/ai/ai.mdx b/website/docs/ai/ai.mdx index 6a4e3419ee9..91a01607c2b 100644 --- a/website/docs/ai/ai.mdx +++ b/website/docs/ai/ai.mdx @@ -11,6 +11,7 @@ import Intro from '@site/src/components/Intro' import ActionCard from '@site/src/components/ActionCard' import PrimaryCTA from '@site/src/components/PrimaryCTA' import Experimental from '@site/src/components/Experimental' +import SkillCount from '@site/src/components/SkillCount' Atmos is designed for AI agents to operate your infrastructure directly. It can call MCP servers and be called as one, reason about your infrastructure on its own, and share the same skills and context with whatever AI tool your team already uses. @@ -211,7 +212,7 @@ ATMOS_AI=true ATMOS_SKILL=atmos-terraform,atmos-stacks atmos terraform plan vpc ## Agent Skills -Atmos ships a growing set of agent skills -- browsable at [/ai/skills](/ai/skills) -- that give AI coding +Atmos ships agent skills -- browsable at [/ai/skills](/ai/skills) -- that give AI coding assistants deep knowledge of Atmos conventions. Skills follow the [Agent Skills](https://agentskills.io) open standard and work across Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more. diff --git a/website/docs/cli/commands/ai/skill.mdx b/website/docs/cli/commands/ai/skill.mdx index 1fa11152ded..00e7f97d1da 100644 --- a/website/docs/cli/commands/ai/skill.mdx +++ b/website/docs/cli/commands/ai/skill.mdx @@ -17,8 +17,9 @@ Use this command to manage community and custom AI skills. Install skills from G -**See also:** [AI Skills Configuration](/cli/configuration/ai/skills) for configuring skills in `atmos.yaml` | -[Skill Marketplace](/ai/skill-marketplace) for browsing available skills +**See also:** [Agent Skills Directory](/ai/skills) to browse every skill | +[AI Skills Configuration](/cli/configuration/ai/skills) for configuring skills in `atmos.yaml` | +[Skill Marketplace](/ai/skill-marketplace) for installing community skills diff --git a/website/docs/cli/commands/ci/ci.mdx b/website/docs/cli/commands/ci/ci.mdx index 9275c3824d7..02d52d27787 100644 --- a/website/docs/cli/commands/ci/ci.mdx +++ b/website/docs/cli/commands/ci/ci.mdx @@ -31,6 +31,7 @@ The `atmos ci` command group provides tools for working with CI/CD systems. Use ## Related +- [Native CI Overview](/ci) - Feature overview and quick start - [CI Configuration](/cli/configuration/ci) - Configure CI integration in `atmos.yaml` - [Profiles](/cli/configuration/profiles) - Configure CI-specific profiles - [Auth](/stacks/auth) - Configure OIDC authentication for CI diff --git a/website/docs/cli/configuration/ai/skills.mdx b/website/docs/cli/configuration/ai/skills.mdx index d02a5a7f198..3a3b0cb767f 100644 --- a/website/docs/cli/configuration/ai/skills.mdx +++ b/website/docs/cli/configuration/ai/skills.mdx @@ -18,7 +18,7 @@ and behavior for different tasks. Skills follow the [Agent Skills open standard] ## Configuration -Set the default skill and optionally define custom skills in `atmos.yaml`. Marketplace skills (installed via `atmos ai skill install`) are available automatically. +Set the default skill and optionally define custom skills in `atmos.yaml`. Marketplace skills (installed via `atmos ai skill install`) are available automatically -- browse the full set in the [Agent Skills Directory](/ai/skills). ```yaml diff --git a/website/docs/cli/configuration/ci/index.mdx b/website/docs/cli/configuration/ci/index.mdx index cced0069f21..dcecc4d3ae4 100644 --- a/website/docs/cli/configuration/ci/index.mdx +++ b/website/docs/cli/configuration/ci/index.mdx @@ -164,7 +164,7 @@ GitHub Actions workflow linting is available through [`atmos ci validate`](/cli/ ## Related - [Native CI Overview](/ci) - Feature overview and quick start -- [Native CI Overview](/ci) - Feature overview +- [CI Commands](/cli/commands/ci) - CI command reference - [Planfile Storage](/ci/planfile-storage) - Store and verify planfiles - [`atmos terraform plan --ci`](/cli/commands/terraform/plan) - Plan with CI integration - [`atmos terraform deploy --ci`](/cli/commands/terraform/deploy) - Deploy with plan verification diff --git a/website/docs/projects/setup-editor/ai-assistants.mdx b/website/docs/projects/setup-editor/ai-assistants.mdx index bcb4fed8c02..54bd5455d67 100644 --- a/website/docs/projects/setup-editor/ai-assistants.mdx +++ b/website/docs/projects/setup-editor/ai-assistants.mdx @@ -21,6 +21,7 @@ stack configuration, Terraform orchestration, and more. Each tool has its own in - Cursor, Windsurf, GitHub Copilot: reference `AGENTS.md` from the Atmos repo - Gemini CLI, OpenAI Codex: symlink or copy the `agent-skills/` directory - Skills activate automatically -- no special syntax needed +- Browse every skill in the [Agent Skills Directory](/ai/skills) ## Install Atmos Skills diff --git a/website/docs/projects/setup-editor/index.mdx b/website/docs/projects/setup-editor/index.mdx index ceb15135fa2..9e655728281 100644 --- a/website/docs/projects/setup-editor/index.mdx +++ b/website/docs/projects/setup-editor/index.mdx @@ -243,4 +243,5 @@ To work effectively with Atmos, we recommend configuring your VS Code editor for ## AI Coding Assistants For configuring AI coding assistants (Claude Code, Cursor, Windsurf, GitHub Copilot, Gemini CLI, OpenAI Codex) -to use Atmos agent skills, see [Configure AI Assistants](/projects/setup-editor/ai-assistants). +to use Atmos agent skills, see [Configure AI Assistants](/projects/setup-editor/ai-assistants). Browse every +available skill in the [Agent Skills Directory](/ai/skills). diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 3984498694d..0f445ba2f3c 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -524,6 +524,8 @@ const config = { 'Scaffolding & Init', ], searchable: true, + cardIcon: 'graduation-cap', + cardCtaLabel: 'Learn', }, ], ], diff --git a/website/plugins/file-browser/index.js b/website/plugins/file-browser/index.js index a1e16cfe660..9cb484876c8 100644 --- a/website/plugins/file-browser/index.js +++ b/website/plugins/file-browser/index.js @@ -723,6 +723,10 @@ module.exports = function fileBrowserPlugin(context, options) { // Shows a free-text search box on the index page. Defaults to false so the // existing examples/gists instances render unchanged unless opted in. searchable = false, + // Card icon and CTA label, see ICON_MAP in IndexPage.tsx. Default to the + // folder icon and "Open" so examples/gists render unchanged. + cardIcon = 'folder', + cardCtaLabel = 'Open', } = options; const mergedExcludePatterns = [...DEFAULT_EXCLUDE_PATTERNS, ...excludePatterns]; @@ -761,6 +765,8 @@ module.exports = function fileBrowserPlugin(context, options) { githubPath, disclaimer, searchable, + cardIcon, + cardCtaLabel, }, }; }, diff --git a/website/sidebars.js b/website/sidebars.js index 07780f0fbe9..8f16d22162b 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -203,7 +203,22 @@ module.exports = { {type: 'doc', id: 'cli/environment-variables', label: 'Environment Variables'}, {type: 'doc', id: 'cli/versioning', label: 'Versioning'}, {type: 'doc', id: 'projects/layout', label: 'Folder Structure'}, - {type: 'doc', id: 'ai/ai', label: 'Atmos AI'}, + { + type: 'category', + label: 'Atmos AI', + link: {type: 'doc', id: 'ai/ai'}, + items: [ + { + type: 'category', + label: 'Skills', + link: {type: 'doc', id: 'ai/agent-skills'}, + items: [ + {type: 'doc', id: 'ai/skill-marketplace', label: 'Skill Marketplace'}, + {type: 'link', label: 'Browse the Skills Directory', href: '/ai/skills'}, + ] + }, + ] + }, {type: 'doc', id: 'mcp/mcp', label: 'MCP'}, {type: 'doc', id: 'pro/pro', label: 'Atmos Pro'}, { @@ -546,7 +561,6 @@ module.exports = { collapsible: false, collapsed: false, items: [ - {type: 'doc', id: 'ci/ci', label: 'Native CI'}, { type: 'autogenerated', dirName: 'integrations/github-actions', diff --git a/website/src/components/AISection/index.js b/website/src/components/AISection/index.js index 25ff57f11da..c435fea33c9 100644 --- a/website/src/components/AISection/index.js +++ b/website/src/components/AISection/index.js @@ -1,6 +1,7 @@ import React from 'react'; import { motion } from 'framer-motion'; import Link from '@docusaurus/Link'; +import useGlobalData from '@docusaurus/useGlobalData'; import { RiStackLine, RiGraduationCapLine, RiPlugLine } from 'react-icons/ri'; import './styles.css'; @@ -19,31 +20,41 @@ function AIBadge() { // Each card links to the doc section that proves its claim. const MotionLink = motion(Link); -const capabilities = [ - { - icon: RiStackLine, - title: 'Declared, not scripted', - desc: 'The tools, workflows, dependencies, and validation — everything you used to script together — is declared and wired end to end. Agents drive one complete system, not a pile of glue scripts.', - link: '/stacks', - delay: 0, - }, - { - icon: RiGraduationCapLine, - title: 'Agent Skills', - desc: '22 portable skills in the open Agent Skills format hand agents exactly what they need about your stacks, components, and workflows — working across Claude Code, Cursor, Gemini, and Copilot. Publish your own.', - link: '/ai/agent-skills', - delay: 0.1, - }, - { - icon: RiPlugLine, - title: 'MCP Server', - desc: 'Atmos exposes itself over the Model Context Protocol, so any MCP client — Claude Code, Cursor, VS Code — can query and drive your infrastructure as native tools. No custom integration.', - link: '/ai/mcp-server', - delay: 0.2, - }, -]; +// Live skill count, computed at build time by the file-browser "skills" plugin +// instance behind /ai/skills — never needs manual updates. +function useSkillCount() { + const globalData = useGlobalData(); + return globalData['file-browser']?.['skills']?.examples?.length; +} function AISection() { + const skillCount = useSkillCount(); + const skillCountLabel = skillCount ? `${skillCount} portable skills` : 'Portable skills'; + + const capabilities = [ + { + icon: RiStackLine, + title: 'Declared, not scripted', + desc: 'The tools, workflows, dependencies, and validation — everything you used to script together — is declared and wired end to end. Agents drive one complete system, not a pile of glue scripts.', + link: '/stacks', + delay: 0, + }, + { + icon: RiGraduationCapLine, + title: 'Agent Skills', + desc: `${skillCountLabel} in the open Agent Skills format hand agents exactly what they need about your stacks, components, and workflows — working across Claude Code, Cursor, Gemini, and Copilot. Publish your own.`, + link: '/ai/skills', + delay: 0.1, + }, + { + icon: RiPlugLine, + title: 'MCP Server', + desc: 'Atmos exposes itself over the Model Context Protocol, so any MCP client — Claude Code, Cursor, VS Code — can query and drive your infrastructure as native tools. No custom integration.', + link: '/ai/mcp-server', + delay: 0.2, + }, + ]; + return (
diff --git a/website/src/components/FileBrowser/FileTree.tsx b/website/src/components/FileBrowser/FileTree.tsx index a2e8b6ae578..e172fe722c1 100644 --- a/website/src/components/FileBrowser/FileTree.tsx +++ b/website/src/components/FileBrowser/FileTree.tsx @@ -20,25 +20,27 @@ export default function FileTree({ }: FileTreeProps): JSX.Element { return ( ); } diff --git a/website/src/components/FileBrowser/IndexPage.tsx b/website/src/components/FileBrowser/IndexPage.tsx index 4220a8db7c1..9402387c849 100644 --- a/website/src/components/FileBrowser/IndexPage.tsx +++ b/website/src/components/FileBrowser/IndexPage.tsx @@ -7,11 +7,21 @@ import Link from '@docusaurus/Link'; import Markdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faFolder } from '@fortawesome/free-solid-svg-icons'; +import { faFolder, faGraduationCap } from '@fortawesome/free-solid-svg-icons'; import CastPlayer from '@site/src/components/CastPlayer'; import type { ExamplesTree, FileBrowserOptions } from './types'; import styles from './styles.module.css'; +/** + * Card icons selectable via the `cardIcon` plugin option (see FileBrowserOptions). + * 'folder' (examples/gists) is the default; add new entries here as new + * file-browser instances need a different visual identity. + */ +const ICON_MAP = { + folder: faFolder, + 'graduation-cap': faGraduationCap, +}; + /** * Markdown components for card descriptions. * Links are rendered as plain text to avoid nested tags. @@ -30,7 +40,9 @@ interface IndexPageProps { export default function IndexPage({ treeData, optionsData }: IndexPageProps): JSX.Element { const { examples, featured = [], tags } = treeData; - const { routeBasePath, title, description, searchable } = optionsData; + const { routeBasePath, title, description, searchable, cardIcon, cardCtaLabel } = optionsData; + const cardIconDefinition = ICON_MAP[cardIcon] || faFolder; + const cardCta = cardCtaLabel || 'Open'; const [activeTag, setActiveTag] = useState(null); const [searchQuery, setSearchQuery] = useState(''); @@ -68,7 +80,7 @@ export default function IndexPage({ treeData, optionsData }: IndexPageProps): JS
- +

{displayName}

@@ -104,7 +116,7 @@ export default function IndexPage({ treeData, optionsData }: IndexPageProps): JS ))}
- Open + {cardCta}
diff --git a/website/src/components/FileBrowser/styles.module.css b/website/src/components/FileBrowser/styles.module.css index 5d0e27e3759..0c077e76266 100644 --- a/website/src/components/FileBrowser/styles.module.css +++ b/website/src/components/FileBrowser/styles.module.css @@ -342,10 +342,19 @@ } /* Sidebar / File Tree */ +/* `.sidebar` only handles sticky positioning. The scrollable, rounded-corner + panel styling lives on the nested `.sidebarInner` instead of combining + position: sticky + overflow-y: auto + border-radius on one element -- + that combination makes Chromium/WebKit render the element translucently + while scrolling (the underlying content bleeds through mid-scroll). */ .sidebar { position: sticky; top: 80px; max-height: calc(100vh - 100px); +} + +.sidebarInner { + height: 100%; overflow-y: auto; background: var(--ifm-background-surface-color); border: 1px solid rgba(0, 0, 0, 0.08); @@ -353,7 +362,7 @@ padding: 1rem; } -:global(html[data-theme='dark']) .sidebar { +:global(html[data-theme='dark']) .sidebarInner { border-color: rgba(255, 255, 255, 0.08); } diff --git a/website/src/components/FileBrowser/types.ts b/website/src/components/FileBrowser/types.ts index 313832f2150..61b08ceb41f 100644 --- a/website/src/components/FileBrowser/types.ts +++ b/website/src/components/FileBrowser/types.ts @@ -97,6 +97,10 @@ export interface FileBrowserOptions { disclaimer?: string; /** Shows a free-text search box on the index page when true. */ searchable?: boolean; + /** Card icon name (see ICON_MAP in IndexPage.tsx). Defaults to 'folder'. */ + cardIcon?: string; + /** Card call-to-action label. Defaults to 'Open'. */ + cardCtaLabel?: string; } /** diff --git a/website/src/components/SkillCount/index.tsx b/website/src/components/SkillCount/index.tsx new file mode 100644 index 00000000000..e957435368a --- /dev/null +++ b/website/src/components/SkillCount/index.tsx @@ -0,0 +1,18 @@ +/** + * SkillCount - Renders the live count of bundled Atmos agent skills inline in + * prose, computed at build time from the same file-browser "skills" plugin + * instance that powers /ai/skills. Never needs manual updates. + */ +import useGlobalData from '@docusaurus/useGlobalData'; + +interface GlobalDataFileBrowser { + examples: { name: string }[]; +} + +export default function SkillCount(): JSX.Element { + const globalData = useGlobalData(); + const skillsData = globalData['file-browser']?.['skills'] as GlobalDataFileBrowser | undefined; + const count = skillsData?.examples.length; + + return <>{count ?? 'dozens of'}; +} diff --git a/website/src/data/roadmap.js b/website/src/data/roadmap.js index 7912fca7779..6d81d522dc7 100644 --- a/website/src/data/roadmap.js +++ b/website/src/data/roadmap.js @@ -250,6 +250,7 @@ export const roadmapConfig = { { label: 'AI Agent Skills (19 domain skills)', status: 'shipped', quarter: 'q1-2026', changelog: 'ai-agent-skills', docs: '/ai/agent-skills', description: 'Atmos ships 19 domain-specific agent skills covering stacks, components, vendoring, terraform, helmfile, packer, ansible, workflows, custom-commands, auth, stores, schemas, gitops, validation, templates, design-patterns, toolchain, introspection, and devcontainers. Compatible with Claude Code, OpenAI Codex, Gemini CLI, Cursor, Windsurf, GitHub Copilot, and more.', benefits: 'AI coding assistants get deep knowledge of Atmos conventions and patterns. Contributors and users get AI assistance that understands Atmos stack configuration, orchestration, and best practices.' }, { label: 'YAML key delimiter for dot notation', status: 'shipped', quarter: 'q1-2026', pr: 2139, changelog: 'yaml-key-delimiter', docs: '/reference/yaml#dot-notation-for-nested-keys', description: 'Configurable key delimiter expands dotted YAML keys into nested maps in stack files. Quoted keys stay literal. Supports custom delimiters.', benefits: 'Write concise dot notation like metadata.component: vpc-base instead of deeply nested YAML. Opt-in and backwards compatible.', experimental: true }, { label: 'Official AI skills bundled in the binary for offline install', status: 'shipped', quarter: 'q2-2026', pr: 2665, changelog: 'offline-ai-skill-catalog', docs: '/cli/commands/ai/skill', description: 'The official Atmos agent skills are embedded in the binary, so `atmos ai skill install ` works fully offline (no network or Git clone). `atmos ai skill list` shows a merged available-vs-installed view with status markers, plus `--installed` and `--detailed` flags.', codeExample: 'atmos ai skill install atmos-terraform', benefits: 'Install official skills anywhere — locked-down CI runners and air-gapped environments included. The catalog always matches the running binary.' }, + { label: 'Browsable, searchable Agent Skills Directory', status: 'shipped', quarter: 'q3-2026', changelog: 'agent-skills-directory', docs: '/ai/skills', description: 'A generated directory at /ai/skills replaces the hand-maintained skill list, with a detail page per skill, category grouping, and a search box. `atmos ai skill list` gained a `--format` flag (table/json/yaml/csv/tsv) and a Category column.', codeExample: 'atmos ai skill list --format=json', benefits: 'The skill list can never drift out of date again — new skills appear automatically. Skills are discoverable by category and free-text search instead of one long page.' }, { label: 'Reproducible demo cast workflows', status: 'shipped', quarter: 'q2-2026', changelog: 'atmos-demo-workflows', description: 'Atmos can generate, validate, and publish website asciicast demos from declarative cast workflows. The cast workflow stages fixtures, records CLI scenarios, writes website assets, and verifies the resulting cast output.', benefits: 'Documentation demos become repeatable build artifacts instead of hand-recorded terminal sessions. Contributors can update demos through the same Atmos workflow model used for infrastructure automation.' }, { label: '`terraform.workspace.prefix_separator` setting for backend key prefixes', status: 'shipped', quarter: 'q2-2026', pr: 2313, changelog: 'workspace-prefix-separator', description: 'New `prefix_separator` setting in `atmos.yaml` under `components.terraform.workspace` controls the character used when Atmos builds workspace key prefixes for S3 (`workspace_key_prefix`), GCS (`prefix`), and Azure (`key`) backends. Set `prefix_separator: "/"` to preserve the component directory hierarchy in state bucket paths instead of flattening with hyphens.', benefits: 'Large component libraries can keep state buckets organized to match their directory structure. Teams that use nested component paths (e.g., vpc/subnets) get a matching state path without manual backend configuration.' }, { label: 'Git repository metadata YAML functions (`!git.repository`, `!git.owner`, `!git.name`, `!git.host`, `!git.url`)', status: 'shipped', quarter: 'q2-2026', pr: 2558, changelog: 'git-repository-yaml-functions', docs: '/functions/yaml/git.repository', description: 'New YAML functions expose Git repository metadata derived from the `origin` remote, working across GitHub, GitLab, Bitbucket, and Azure DevOps. `!git.repository` returns the `/` slug (matching GitHub\'s `GITHUB_REPOSITORY`), with `!git.owner`, `!git.name`, `!git.host`, and `!git.url` for the individual parts. All support a fallback value.', benefits: 'Tag resources or build paths with the repository slug without shelling out through `!exec` and `sed`. Portable across Git hosts and CI environments.' }, From 042c5877ad32f4667f605d4b2a8365941b339f90 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 16:57:02 -0500 Subject: [PATCH 03/24] feat(ai): add copy-as-markdown button to skill pages Adds a "Copy as Markdown" button to a skill's root page that concatenates its SKILL.md and every nested reference file into one clipboard-ready Markdown document, so the full context can be grabbed without installing the skill. Ships as an opt-in `enableCopyMarkdown` file-browser plugin option (enabled for the /ai/skills instance only; /examples and /gists render unchanged). --- website/docusaurus.config.js | 1 + website/plugins/file-browser/index.js | 6 +++ .../FileBrowser/CopyMarkdownButton.tsx | 47 +++++++++++++++++++ .../components/FileBrowser/DirectoryPage.tsx | 13 ++++- .../components/FileBrowser/styles.module.css | 46 ++++++++++++++++++ website/src/components/FileBrowser/types.ts | 2 + website/src/components/FileBrowser/utils.ts | 35 ++++++++++++++ 7 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 website/src/components/FileBrowser/CopyMarkdownButton.tsx diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 0f445ba2f3c..132edb91d8a 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -526,6 +526,7 @@ const config = { searchable: true, cardIcon: 'graduation-cap', cardCtaLabel: 'Learn', + enableCopyMarkdown: true, }, ], ], diff --git a/website/plugins/file-browser/index.js b/website/plugins/file-browser/index.js index 9cb484876c8..f83dc4e922d 100644 --- a/website/plugins/file-browser/index.js +++ b/website/plugins/file-browser/index.js @@ -727,6 +727,11 @@ module.exports = function fileBrowserPlugin(context, options) { // folder icon and "Open" so examples/gists render unchanged. cardIcon = 'folder', cardCtaLabel = 'Open', + // Shows a "Copy as Markdown" button on each item's root page, which + // concatenates the item's readme and every nested file into one + // clipboard-ready document. Defaults to false so existing instances + // render unchanged unless opted in. + enableCopyMarkdown = false, } = options; const mergedExcludePatterns = [...DEFAULT_EXCLUDE_PATTERNS, ...excludePatterns]; @@ -767,6 +772,7 @@ module.exports = function fileBrowserPlugin(context, options) { searchable, cardIcon, cardCtaLabel, + enableCopyMarkdown, }, }; }, diff --git a/website/src/components/FileBrowser/CopyMarkdownButton.tsx b/website/src/components/FileBrowser/CopyMarkdownButton.tsx new file mode 100644 index 00000000000..a676451c31a --- /dev/null +++ b/website/src/components/FileBrowser/CopyMarkdownButton.tsx @@ -0,0 +1,47 @@ +/** + * CopyMarkdownButton - Copies a directory's full content, nested files + * included, to the clipboard as one Markdown document. Lets someone grab a + * skill's complete context without installing it. + */ +import React, { useState } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCopy, faCheck } from '@fortawesome/free-solid-svg-icons'; +import { collectMarkdownContext } from './utils'; +import type { DirectoryNode } from './types'; +import styles from './styles.module.css'; + +interface CopyMarkdownButtonProps { + directory: DirectoryNode; + title?: string; + description?: string; + label?: string; +} + +export default function CopyMarkdownButton({ + directory, + title, + description, + label = 'Copy as Markdown', +}: CopyMarkdownButtonProps): JSX.Element { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + const heading = title ? `# ${title}\n\n${description ? `${description}\n\n` : ''}` : ''; + const markdown = heading + collectMarkdownContext(directory); + + try { + await navigator.clipboard.writeText(markdown); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch { + // Clipboard API unavailable (e.g. insecure context) - button just won't confirm. + } + }; + + return ( + + ); +} diff --git a/website/src/components/FileBrowser/DirectoryPage.tsx b/website/src/components/FileBrowser/DirectoryPage.tsx index 4169c179389..d095d550b02 100644 --- a/website/src/components/FileBrowser/DirectoryPage.tsx +++ b/website/src/components/FileBrowser/DirectoryPage.tsx @@ -8,6 +8,7 @@ import FileTree from './FileTree'; import DirectoryListing from './DirectoryListing'; import FileViewer from './FileViewer'; import RelatedDocs from './RelatedDocs'; +import CopyMarkdownButton from './CopyMarkdownButton'; import { findExampleByName, getExampleNameFromPath } from './utils'; import GistDisclaimer from '@site/src/components/GistDisclaimer'; import CastPlayer from '@site/src/components/CastPlayer'; @@ -48,6 +49,7 @@ export default function DirectoryPage({ : `${dirData.name} - ${exampleName}`; const isExampleRoot = dirData.path === exampleName; const showCast = isExampleRoot && !!example.cast?.file; + const showCopyMarkdown = isExampleRoot && !!optionsData.enableCopyMarkdown; return ( @@ -58,7 +60,16 @@ export default function DirectoryPage({ currentPath={dirData.path} />
- +
+ + {showCopyMarkdown && ( + + )} +
{optionsData.disclaimer && ( diff --git a/website/src/components/FileBrowser/styles.module.css b/website/src/components/FileBrowser/styles.module.css index 0c077e76266..b36a5e4549a 100644 --- a/website/src/components/FileBrowser/styles.module.css +++ b/website/src/components/FileBrowser/styles.module.css @@ -692,6 +692,52 @@ opacity: 0.7; } +/* Page Toolbar (breadcrumb + page-level actions) */ +.pageToolbar { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 0.75rem; + margin-bottom: 1rem; +} + +/* .breadcrumb already carries its own margin-bottom; avoid doubling it when wrapped. */ +.pageToolbar .breadcrumb { + margin-bottom: 0; +} + +/* Copy Markdown Button */ +.copyMarkdownButton { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: rgba(0, 0, 0, 0.05); + border: none; + border-radius: 6px; + color: var(--ifm-color-emphasis-700); + font-size: 0.85rem; + cursor: pointer; + transition: all 0.2s ease; +} + +.copyMarkdownButton:hover { + background: rgba(0, 0, 0, 0.1); +} + +:global(html[data-theme='dark']) .copyMarkdownButton { + background: rgba(255, 255, 255, 0.08); +} + +:global(html[data-theme='dark']) .copyMarkdownButton:hover { + background: rgba(255, 255, 255, 0.12); +} + +.copyMarkdownIcon { + font-size: 1rem; +} + /* README Section */ .readmeSection { width: 100%; diff --git a/website/src/components/FileBrowser/types.ts b/website/src/components/FileBrowser/types.ts index 61b08ceb41f..3fe24ce135e 100644 --- a/website/src/components/FileBrowser/types.ts +++ b/website/src/components/FileBrowser/types.ts @@ -101,6 +101,8 @@ export interface FileBrowserOptions { cardIcon?: string; /** Card call-to-action label. Defaults to 'Open'. */ cardCtaLabel?: string; + /** Shows a "Copy as Markdown" button on each item's root page when true. */ + enableCopyMarkdown?: boolean; } /** diff --git a/website/src/components/FileBrowser/utils.ts b/website/src/components/FileBrowser/utils.ts index 4f1af2d3878..2d8b622aac9 100644 --- a/website/src/components/FileBrowser/utils.ts +++ b/website/src/components/FileBrowser/utils.ts @@ -204,6 +204,41 @@ export function getParentPath(path: string): string { return parts.join('/'); } +/** + * Recursively concatenates every readable file under a directory into one + * Markdown document — the whole skill, references included, as a single + * block of context that can be copied without installing anything. The + * node's own `readme` (e.g. SKILL.md) leads, since it's the entry point; + * everything else follows in tree order. Binary files and files skipped at + * scan time (over the plugin's `maxFileSize`, `content === null`) are + * omitted rather than left as empty sections. + */ +export function collectMarkdownContext(root: DirectoryNode): string { + const sections: string[] = []; + const readmePath = root.readme?.path; + + const addFile = (node: FileNode) => { + if (node.content == null || isBinaryFile(node)) return; + const body = isMarkdownFile(node) + ? node.content.trim() + : `\`\`\`${node.language}\n${node.content.trim()}\n\`\`\``; + sections.push(`## ${node.path}\n\n${body}`); + }; + + const visit = (node: TreeNode) => { + if (node.type === 'directory') { + node.children.forEach(visit); + } else if (node.path !== readmePath) { + addFile(node); + } + }; + + if (root.readme) addFile(root.readme); + visit(root); + + return sections.join('\n\n---\n\n'); +} + /** * Counts total files in a tree. */ From 3472c0759de709df5aefd5bd90af32341a41eadc Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 19:12:12 -0500 Subject: [PATCH 04/24] fix: address CodeRabbit review feedback on skills directory browser PR Fixes six issues flagged on PR #2881: - cmd/ai/skill/list.go: dispatch structured --format output (json/yaml/csv/tsv) before the "No skills installed" empty-message check, so --installed with zero results stays machine-readable instead of returning prose. - cmd/ai/skill/list.go: validate the Viper-resolved --format value (covers ATMOS_AI_SKILL_FORMAT env/config, not just the CLI flag) before it reaches the renderer. - pkg/ai/skills/marketplace/catalog_test.go: add the missing Category field to the AvailableSkill compile-time sentinel so a future field rename or drop is caught at compile time. - cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md: fix MD040/MD014 lint on the new --format=json example (shell fence, no unshown $ prompt). - agent-skills/skills/atmos-templates/SKILL.md: add missing trailing period. - website/src/components/FileBrowser/styles.module.css: move the viewport max-height constraint from .sidebar onto .sidebarInner so a long file tree scrolls inside the sidebar instead of growing it (shared by /examples, /gists, and /ai/skills). Co-Authored-By: Claude Sonnet 5 --- agent-skills/skills/atmos-templates/SKILL.md | 2 +- cmd/ai/skill/list.go | 32 +++++++++--- cmd/ai/skill/list_test.go | 50 +++++++++++++++++-- .../markdown/atmos_ai_skill_list_usage.md | 4 +- pkg/ai/skills/marketplace/catalog_test.go | 2 +- .../components/FileBrowser/styles.module.css | 12 +++-- 6 files changed, 85 insertions(+), 17 deletions(-) diff --git a/agent-skills/skills/atmos-templates/SKILL.md b/agent-skills/skills/atmos-templates/SKILL.md index 9996465be9f..cd27e044033 100644 --- a/agent-skills/skills/atmos-templates/SKILL.md +++ b/agent-skills/skills/atmos-templates/SKILL.md @@ -228,7 +228,7 @@ are not supported in stack manifests (only in `atmos.yaml`). 3. **Use `atmos.GomplateDatasource` instead of `datasource`** -- Built-in caching prevents redundant API calls 4. **Minimize `atmos.Component` usage** -- Each call may initialize Terraform -5. **All template functions cache results** per execution for repeated calls +5. **All template functions cache results** per execution for repeated calls. ## Common Pitfalls diff --git a/cmd/ai/skill/list.go b/cmd/ai/skill/list.go index a4d9ca13b3e..e3d3e3689cd 100644 --- a/cmd/ai/skill/list.go +++ b/cmd/ai/skill/list.go @@ -3,6 +3,7 @@ package skill import ( _ "embed" "fmt" + "slices" "sort" "strings" "time" @@ -12,6 +13,7 @@ import ( ai "github.com/cloudposse/atmos/cmd/ai" + errUtils "github.com/cloudposse/atmos/errors" "github.com/cloudposse/atmos/pkg/ai/skills/marketplace" "github.com/cloudposse/atmos/pkg/flags" "github.com/cloudposse/atmos/pkg/list/column" @@ -34,6 +36,13 @@ const ( // flagFormat is the name of the output-format flag. const flagFormat = "format" +// validSkillListFormats lists the supported --format values. It is shared between +// flag registration (CLI validation via flags.WithValidValues) and the explicit +// check in RunE below, which is needed because a value sourced from Viper's +// lower-precedence layers (ATMOS_AI_SKILL_FORMAT env var or config file) never +// passes through the flag parser's "explicitly changed" validation path. +var validSkillListFormats = []string{"table", "json", "yaml", "csv", "tsv"} + // listParser handles flag parsing with Viper precedence for the list command. var listParser *flags.StandardParser @@ -77,7 +86,15 @@ var listCmd = &cobra.Command{ // Get flags from Viper (supports CLI > ENV > config > defaults). detailed := v.GetBool("detailed") installedOnly := v.GetBool("installed") - outputFormat := listformat.Format(v.GetString(flagFormat)) + + // Validate explicitly: the flag parser only validates values that came + // directly from the CLI flag, so an invalid ATMOS_AI_SKILL_FORMAT env var + // or config-file value must be checked here before it reaches the renderer. + formatValue := v.GetString(flagFormat) + if formatValue != "" && !slices.Contains(validSkillListFormats, formatValue) { + return fmt.Errorf("%w: %q (supported: %v)", errUtils.ErrInvalidFlagValue, formatValue, validSkillListFormats) + } + outputFormat := listformat.Format(formatValue) // Create installer (which manages registry). installer, err := marketplace.NewInstaller(version.Version) @@ -103,7 +120,7 @@ func init() { flags.WithEnvVars("installed", "ATMOS_AI_SKILL_INSTALLED"), flags.WithStringFlag(flagFormat, "f", "", "Output format: table, json, yaml, csv, tsv"), flags.WithEnvVars(flagFormat, "ATMOS_AI_SKILL_FORMAT"), - flags.WithValidValues(flagFormat, "table", "json", "yaml", "csv", "tsv"), + flags.WithValidValues(flagFormat, validSkillListFormats...), ) // Register flags on the command. @@ -195,15 +212,18 @@ func renderSkillList(entries []listEntry, installedOnly, detailed bool, outputFo display = filterInstalled(entries) } + // Dispatch structured formats before the empty-message check so json/yaml/csv/tsv + // stay machine-readable (e.g. an empty array) even when --installed matches + // nothing, instead of falling through to the human-readable prose message below. + if outputFormat != "" && outputFormat != listformat.FormatTable { + return renderSkillListStructured(display, outputFormat) + } + if len(display) == 0 { // Only reachable with --installed (the catalog is never empty). return writeSkillListOutput("No skills installed.\n\nBrowse available skills with:\n atmos ai skill list\n") } - if outputFormat != "" && outputFormat != listformat.FormatTable { - return renderSkillListStructured(display, outputFormat) - } - var rendered string var err error if detailed { diff --git a/cmd/ai/skill/list_test.go b/cmd/ai/skill/list_test.go index 21602f6fcf3..891779c41e9 100644 --- a/cmd/ai/skill/list_test.go +++ b/cmd/ai/skill/list_test.go @@ -13,9 +13,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + errUtils "github.com/cloudposse/atmos/errors" "github.com/cloudposse/atmos/pkg/ai/skills/marketplace" "github.com/cloudposse/atmos/pkg/config/homedir" "github.com/cloudposse/atmos/pkg/data" + "github.com/cloudposse/atmos/pkg/flags" iolib "github.com/cloudposse/atmos/pkg/io" ) @@ -129,12 +131,14 @@ func installedEntryWithMetadata(name, source, version, path string, enabled, isB return entry } -// resetListFlags restores the list command's flags to defaults between subtests. +// resetListFlags restores the list command's flags to defaults between subtests, +// clearing pflag's "Changed" state too. Without clearing Changed, a flag stays +// "explicitly changed" forever once any earlier subtest calls Set() on it (pflag +// has no unset), which would make Viper always prefer the stale CLI value over +// an env var in later subtests that test env-var precedence. func resetListFlags(t *testing.T) { t.Helper() - require.NoError(t, listCmd.Flags().Set("detailed", "false")) - require.NoError(t, listCmd.Flags().Set("installed", "false")) - require.NoError(t, listCmd.Flags().Set(flagFormat, "")) + flags.ResetCommandFlags(listCmd) } func TestListCmd_BasicProperties(t *testing.T) { @@ -205,6 +209,27 @@ func TestListCmd_EnvVarBinding(t *testing.T) { }) } +// TestListCmd_FormatEnvVarInvalid verifies that a value sourced from +// ATMOS_AI_SKILL_FORMAT (rather than the --format flag itself) is still +// validated: the flag parser only validates values that came directly from +// an explicitly-changed CLI flag, so RunE must check the Viper-resolved +// value before it reaches the renderer. +func TestListCmd_FormatEnvVarInvalid(t *testing.T) { + withTempHome(t) + resetListFlags(t) + t.Setenv("ATMOS_AI_SKILL_FORMAT", "invalid") + + // Set up output plumbing in case validation regresses and the command falls + // through to rendering; without this a regression would panic instead of + // failing the assertions below with a clear message. + setupSkillListOutput(t) + + err := listCmd.RunE(listCmd, []string{}) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrInvalidFlagValue) + assert.Contains(t, err.Error(), "invalid") +} + func TestBuildListEntries(t *testing.T) { catalog, err := marketplace.Catalog() require.NoError(t, err) @@ -527,6 +552,23 @@ func TestListCmd_InstalledOnly(t *testing.T) { assert.Contains(t, output, "No skills installed") assert.Contains(t, output, "atmos ai skill list") }) + + t.Run("with nothing installed and format=json returns an empty array, not prose", func(t *testing.T) { + withTempHome(t) + resetListFlags(t) + require.NoError(t, listCmd.Flags().Set("installed", "true")) + require.NoError(t, listCmd.Flags().Set(flagFormat, "json")) + + stdout := setupSkillListOutput(t) + require.NoError(t, listCmd.RunE(listCmd, []string{})) + output := stdout.String() + + assert.NotContains(t, output, "No skills installed") + + var rows []map[string]string + require.NoError(t, json.Unmarshal([]byte(output), &rows), "output must be valid JSON") + assert.Empty(t, rows) + }) } func TestListCmd_DetailedOutput(t *testing.T) { diff --git a/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md b/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md index d7c39ea4a3a..8a2a2ecd82f 100644 --- a/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md +++ b/cmd/ai/skill/markdown/atmos_ai_skill_list_usage.md @@ -18,6 +18,6 @@ $ atmos ai skill list --detailed - List as JSON -``` -$ atmos ai skill list --format=json +```shell +atmos ai skill list --format=json ``` diff --git a/pkg/ai/skills/marketplace/catalog_test.go b/pkg/ai/skills/marketplace/catalog_test.go index e9fddbba354..adc64dca7a3 100644 --- a/pkg/ai/skills/marketplace/catalog_test.go +++ b/pkg/ai/skills/marketplace/catalog_test.go @@ -35,7 +35,7 @@ func newBundledTestInstaller(t *testing.T) *Installer { // Compile-time sentinel: fails the build if any AvailableSkill field is renamed, // so the catalog tests below cannot silently reference stale fields. -var _ = AvailableSkill{Name: "", DisplayName: "", Description: "", Version: "", Source: ""} +var _ = AvailableSkill{Name: "", DisplayName: "", Description: "", Version: "", Source: "", Category: ""} func TestCatalog(t *testing.T) { catalog, err := Catalog() diff --git a/website/src/components/FileBrowser/styles.module.css b/website/src/components/FileBrowser/styles.module.css index b36a5e4549a..f74e8a22d21 100644 --- a/website/src/components/FileBrowser/styles.module.css +++ b/website/src/components/FileBrowser/styles.module.css @@ -346,15 +346,18 @@ panel styling lives on the nested `.sidebarInner` instead of combining position: sticky + overflow-y: auto + border-radius on one element -- that combination makes Chromium/WebKit render the element translucently - while scrolling (the underlying content bleeds through mid-scroll). */ + while scrolling (the underlying content bleeds through mid-scroll). + The viewport-based `max-height` also lives on `.sidebarInner` (not `.sidebar`) + so it is a definite constraint for this element itself: `.sidebar` has no + `height`, so a `height: 100%` child would resolve against it as `auto` and + let a long file tree grow the sidebar instead of scrolling inside it. */ .sidebar { position: sticky; top: 80px; - max-height: calc(100vh - 100px); } .sidebarInner { - height: 100%; + max-height: calc(100vh - 100px); overflow-y: auto; background: var(--ifm-background-surface-color); border: 1px solid rgba(0, 0, 0, 0.08); @@ -370,6 +373,9 @@ .sidebar { position: relative; top: 0; + } + + .sidebarInner { max-height: none; } } From d120a86b0ba9b87fcf61ecd3445444063a422c67 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 19:14:01 -0500 Subject: [PATCH 05/24] docs(ai): use natural link text for the Agent Skills Directory Two spots linked to /ai/skills using the raw path as the visible link text ("browsable at /ai/skills") instead of natural language, which read poorly next to the "Agent Skills Directory" phrasing used everywhere else this page is linked. Match the established convention. --- website/docs/ai/agent-skills.mdx | 2 +- website/docs/ai/ai.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/ai/agent-skills.mdx b/website/docs/ai/agent-skills.mdx index 24d14dba31a..89be6617c06 100644 --- a/website/docs/ai/agent-skills.mdx +++ b/website/docs/ai/agent-skills.mdx @@ -17,7 +17,7 @@ the `agent-skills/` folder at the root of the Atmos repository and work across a -- domain-specific skills covering every Atmos subsystem -- browse them all at [/ai/skills](/ai/skills) +- domain-specific skills covering every Atmos subsystem -- browse them all in the [Agent Skills Directory](/ai/skills) - Works with Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more - Progressive disclosure: AI loads only the skill it needs, keeping context focused - Portable SKILL.md format with YAML frontmatter and tiered reference files diff --git a/website/docs/ai/ai.mdx b/website/docs/ai/ai.mdx index 91a01607c2b..897f886e05f 100644 --- a/website/docs/ai/ai.mdx +++ b/website/docs/ai/ai.mdx @@ -212,7 +212,7 @@ ATMOS_AI=true ATMOS_SKILL=atmos-terraform,atmos-stacks atmos terraform plan vpc ## Agent Skills -Atmos ships agent skills -- browsable at [/ai/skills](/ai/skills) -- that give AI coding +Atmos ships agent skills -- browsable in the [Agent Skills Directory](/ai/skills) -- that give AI coding assistants deep knowledge of Atmos conventions. Skills follow the [Agent Skills](https://agentskills.io) open standard and work across Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more. From ff048891dc1ed0171a426b6b65725b289ec5833f Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 20:25:53 -0500 Subject: [PATCH 06/24] feat(ai): per-page skill markdown, code-styled titles, fix AWS compliance category - file-browser plugin: new enablePerPageMarkdown option writes a raw .md per item at build time (SKILL.md + nested reference files concatenated), extending the sitewide "append .md for raw Markdown" convention to skill pages, which docusaurus-plugin-llms-txt can't see since they're custom routes, not docs/blog content. - new titleAsCode option renders each item's title as a code-formatted `/name` on the index cards and sidebar header, signaling how a skill is invoked. Enabled for the skills instance only. - atmos-aws-compliance: recategorize from "security" to "aws" so it groups with the other AWS integrations instead of Auth/Secrets. --- .../skills/atmos-aws-compliance/SKILL.md | 2 +- website/docusaurus.config.js | 2 + website/plugins/file-browser/index.js | 84 +++++++++++++++++++ .../components/FileBrowser/DirectoryPage.tsx | 1 + .../src/components/FileBrowser/FilePage.tsx | 1 + .../src/components/FileBrowser/FileTree.tsx | 4 +- .../src/components/FileBrowser/IndexPage.tsx | 6 +- website/src/components/FileBrowser/types.ts | 2 + 8 files changed, 98 insertions(+), 4 deletions(-) diff --git a/agent-skills/skills/atmos-aws-compliance/SKILL.md b/agent-skills/skills/atmos-aws-compliance/SKILL.md index ce2078fe94e..4dc5581de3c 100644 --- a/agent-skills/skills/atmos-aws-compliance/SKILL.md +++ b/agent-skills/skills/atmos-aws-compliance/SKILL.md @@ -4,7 +4,7 @@ description: "AWS compliance commands in Atmos: atmos aws compliance report, Sec metadata: copyright: Copyright Cloud Posse, LLC 2026 version: "1.0.0" - category: security + category: aws --- # Atmos AWS Compliance diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 132edb91d8a..e7b9a6382d2 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -527,6 +527,8 @@ const config = { cardIcon: 'graduation-cap', cardCtaLabel: 'Learn', enableCopyMarkdown: true, + enablePerPageMarkdown: true, + titleAsCode: true, }, ], ], diff --git a/website/plugins/file-browser/index.js b/website/plugins/file-browser/index.js index f83dc4e922d..b8ae97e0ef0 100644 --- a/website/plugins/file-browser/index.js +++ b/website/plugins/file-browser/index.js @@ -706,6 +706,74 @@ function collectDirectories(node, basePath) { return dirs; } +// Binary extensions skipped when concatenating Markdown context — mirrors +// isBinaryFile() in website/src/components/FileBrowser/utils.ts. +const BINARY_EXTENSIONS = new Set([ + 'png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'ico', 'pdf', 'zip', 'tar', + 'gz', 'exe', 'dll', 'so', 'dylib', 'bin', 'dat', +]); + +/** + * Recursively concatenates every readable file under a directory into one + * Markdown document — the whole item, nested reference files included, as a + * single block of context. Mirrors collectMarkdownContext() in + * website/src/components/FileBrowser/utils.ts (used by the client-side "Copy + * as Markdown" button); this build-time twin backs the per-page `.md` files + * written by generatePerPageMarkdown() below. Keep both in sync. + * @param {object} root - Directory node (an example's `root`). + * @returns {string} - Concatenated Markdown. + */ +function collectMarkdownContext(root) { + const sections = []; + const readmePath = root.readme ? root.readme.path : undefined; + + const addFile = (node) => { + if (node.content == null || BINARY_EXTENSIONS.has((node.extension || '').toLowerCase())) return; + const ext = (node.extension || '').toLowerCase(); + const body = ext === 'md' || ext === 'mdx' + ? node.content.trim() + : `\`\`\`${node.language}\n${node.content.trim()}\n\`\`\``; + sections.push(`## ${node.path}\n\n${body}`); + }; + + const visit = (node) => { + if (node.type === 'directory') { + node.children.forEach(visit); + } else if (node.path !== readmePath) { + addFile(node); + } + }; + + if (root.readme) addFile(root.readme); + visit(root); + + return sections.join('\n\n---\n\n'); +} + +/** + * Writes a raw `.md` file for each example, mirroring the sitewide + * "append `.md` to any URL for raw Markdown" convention that + * docusaurus-plugin-llms-txt provides for regular docs/blog pages — those + * pages are invisible to that plugin since file-browser routes aren't + * docs/blog content, so this instance has to generate its own. + * @param {object} tree - The scanned examples tree (see scanExamples()). + * @param {string} outDir - Docusaurus build output directory. + * @param {string} routeBasePath - This instance's route base path. + * @param {string} id - Plugin instance id, for logging. + */ +async function generatePerPageMarkdown(tree, outDir, routeBasePath, id) { + let written = 0; + for (const example of tree.examples) { + const heading = `# ${example.title || example.name}\n\n${example.description ? `${example.description}\n\n` : ''}`; + const body = heading + collectMarkdownContext(example.root); + const outPath = path.join(outDir, routeBasePath, `${example.name}.md`); + await fs.promises.mkdir(path.dirname(outPath), { recursive: true }); + await fs.promises.writeFile(outPath, body, 'utf-8'); + written += 1; + } + console.log(`[file-browser:${id}] Wrote ${written} per-page .md files`); +} + module.exports = function fileBrowserPlugin(context, options) { const { id = 'default', @@ -732,6 +800,15 @@ module.exports = function fileBrowserPlugin(context, options) { // clipboard-ready document. Defaults to false so existing instances // render unchanged unless opted in. enableCopyMarkdown = false, + // Writes a raw `.md` file for each item's root page at build time (e.g. + // /ai/skills/atmos-terraform.md), so it's fetchable the same way any + // docs/blog page is via docusaurus-plugin-llms-txt's `.md` + // convention. Defaults to false so existing instances are unaffected. + enablePerPageMarkdown = false, + // Renders each item's title as a code-formatted `/name` (e.g. `/atmos-terraform`) + // instead of plain text, signaling how it's invoked. Defaults to false — + // examples/gists have friendly English titles this wouldn't suit. + titleAsCode = false, } = options; const mergedExcludePatterns = [...DEFAULT_EXCLUDE_PATTERNS, ...excludePatterns]; @@ -773,6 +850,7 @@ module.exports = function fileBrowserPlugin(context, options) { cardIcon, cardCtaLabel, enableCopyMarkdown, + titleAsCode, }, }; }, @@ -864,5 +942,11 @@ module.exports = function fileBrowserPlugin(context, options) { // Watch the source directory for changes during development. return [absoluteSourceDir]; }, + + async postBuild({ content, outDir }) { + if (!enablePerPageMarkdown) return; + const { tree, options: pluginOptions } = content; + await generatePerPageMarkdown(tree, outDir, pluginOptions.routeBasePath, id); + }, }; }; diff --git a/website/src/components/FileBrowser/DirectoryPage.tsx b/website/src/components/FileBrowser/DirectoryPage.tsx index d095d550b02..2eca176ecc3 100644 --- a/website/src/components/FileBrowser/DirectoryPage.tsx +++ b/website/src/components/FileBrowser/DirectoryPage.tsx @@ -58,6 +58,7 @@ export default function DirectoryPage({ example={example} routeBasePath={routeBasePath} currentPath={dirData.path} + titleAsCode={optionsData.titleAsCode} />
diff --git a/website/src/components/FileBrowser/FilePage.tsx b/website/src/components/FileBrowser/FilePage.tsx index 676b66d97af..71157d5a3b0 100644 --- a/website/src/components/FileBrowser/FilePage.tsx +++ b/website/src/components/FileBrowser/FilePage.tsx @@ -49,6 +49,7 @@ export default function FilePage({ example={example} routeBasePath={routeBasePath} currentPath={fileData.path} + titleAsCode={optionsData.titleAsCode} />
diff --git a/website/src/components/FileBrowser/FileTree.tsx b/website/src/components/FileBrowser/FileTree.tsx index e172fe722c1..bf7c2d71f8e 100644 --- a/website/src/components/FileBrowser/FileTree.tsx +++ b/website/src/components/FileBrowser/FileTree.tsx @@ -11,12 +11,14 @@ interface FileTreeProps { example: ExampleProject; routeBasePath: string; currentPath: string; + titleAsCode?: boolean; } export default function FileTree({ example, routeBasePath, currentPath, + titleAsCode, }: FileTreeProps): JSX.Element { return (
    diff --git a/website/src/components/FileBrowser/IndexPage.tsx b/website/src/components/FileBrowser/IndexPage.tsx index 9402387c849..90af25a81b6 100644 --- a/website/src/components/FileBrowser/IndexPage.tsx +++ b/website/src/components/FileBrowser/IndexPage.tsx @@ -40,7 +40,7 @@ interface IndexPageProps { export default function IndexPage({ treeData, optionsData }: IndexPageProps): JSX.Element { const { examples, featured = [], tags } = treeData; - const { routeBasePath, title, description, searchable, cardIcon, cardCtaLabel } = optionsData; + const { routeBasePath, title, description, searchable, cardIcon, cardCtaLabel, titleAsCode } = optionsData; const cardIconDefinition = ICON_MAP[cardIcon] || faFolder; const cardCta = cardCtaLabel || 'Open'; const [activeTag, setActiveTag] = useState(null); @@ -82,7 +82,9 @@ export default function IndexPage({ treeData, optionsData }: IndexPageProps): JS
    -

    {displayName}

    +

    + {titleAsCode ? /{example.name} : displayName} +

    {example.cast?.file && ( diff --git a/website/src/components/FileBrowser/types.ts b/website/src/components/FileBrowser/types.ts index 3fe24ce135e..0130e078fab 100644 --- a/website/src/components/FileBrowser/types.ts +++ b/website/src/components/FileBrowser/types.ts @@ -103,6 +103,8 @@ export interface FileBrowserOptions { cardCtaLabel?: string; /** Shows a "Copy as Markdown" button on each item's root page when true. */ enableCopyMarkdown?: boolean; + /** Renders each item's title as a code-formatted `/name`, signaling how it's invoked. */ + titleAsCode?: boolean; } /** From 331e2e3ef5e59d92f1080a1b775d964bc69ec90a Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 20:48:24 -0500 Subject: [PATCH 07/24] feat(ai): hover copy button on skill cards, drop code-title background - IndexPage cards get a "Copy as Markdown" icon button in the corner, revealed on hover/focus, so a skill's full context (including nested reference files) can be copied straight from the grid without opening it. Gated by enableCopyMarkdown, so /examples and /gists are unaffected. CopyMarkdownButton gained an iconOnly mode. - Code-formatted titles (titleAsCode) now drop Infima's default inline-code background chip/border, keeping just the monospace font. --- .../FileBrowser/CopyMarkdownButton.tsx | 27 +++++++- .../src/components/FileBrowser/IndexPage.tsx | 12 +++- .../components/FileBrowser/styles.module.css | 67 +++++++++++++++++++ 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/website/src/components/FileBrowser/CopyMarkdownButton.tsx b/website/src/components/FileBrowser/CopyMarkdownButton.tsx index a676451c31a..cbc894153bd 100644 --- a/website/src/components/FileBrowser/CopyMarkdownButton.tsx +++ b/website/src/components/FileBrowser/CopyMarkdownButton.tsx @@ -15,6 +15,9 @@ interface CopyMarkdownButtonProps { title?: string; description?: string; label?: string; + /** Renders as an icon-only control (no visible label) for tight spaces like a card corner. */ + iconOnly?: boolean; + className?: string; } export default function CopyMarkdownButton({ @@ -22,10 +25,17 @@ export default function CopyMarkdownButton({ title, description, label = 'Copy as Markdown', + iconOnly = false, + className, }: CopyMarkdownButtonProps): JSX.Element { const [copied, setCopied] = useState(false); - const handleCopy = async () => { + const handleCopy = async (event: React.MouseEvent) => { + // Cards this button sits on may be clickable themselves - never let the + // click fall through to a parent link/card navigation. + event.preventDefault(); + event.stopPropagation(); + const heading = title ? `# ${title}\n\n${description ? `${description}\n\n` : ''}` : ''; const markdown = heading + collectMarkdownContext(directory); @@ -38,10 +48,21 @@ export default function CopyMarkdownButton({ } }; + const buttonClassName = [ + iconOnly ? styles.copyMarkdownIconButton : styles.copyMarkdownButton, + className, + ].filter(Boolean).join(' '); + return ( - ); } diff --git a/website/src/components/FileBrowser/IndexPage.tsx b/website/src/components/FileBrowser/IndexPage.tsx index 90af25a81b6..23584d15bb2 100644 --- a/website/src/components/FileBrowser/IndexPage.tsx +++ b/website/src/components/FileBrowser/IndexPage.tsx @@ -9,6 +9,7 @@ import remarkGfm from 'remark-gfm'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faFolder, faGraduationCap } from '@fortawesome/free-solid-svg-icons'; import CastPlayer from '@site/src/components/CastPlayer'; +import CopyMarkdownButton from './CopyMarkdownButton'; import type { ExamplesTree, FileBrowserOptions } from './types'; import styles from './styles.module.css'; @@ -40,7 +41,7 @@ interface IndexPageProps { export default function IndexPage({ treeData, optionsData }: IndexPageProps): JSX.Element { const { examples, featured = [], tags } = treeData; - const { routeBasePath, title, description, searchable, cardIcon, cardCtaLabel, titleAsCode } = optionsData; + const { routeBasePath, title, description, searchable, cardIcon, cardCtaLabel, titleAsCode, enableCopyMarkdown } = optionsData; const cardIconDefinition = ICON_MAP[cardIcon] || faFolder; const cardCta = cardCtaLabel || 'Open'; const [activeTag, setActiveTag] = useState(null); @@ -77,6 +78,15 @@ export default function IndexPage({ treeData, optionsData }: IndexPageProps): JS key={example.name} className={styles.exampleCard} > + {enableCopyMarkdown && ( + + )}
    diff --git a/website/src/components/FileBrowser/styles.module.css b/website/src/components/FileBrowser/styles.module.css index f74e8a22d21..772a142fd50 100644 --- a/website/src/components/FileBrowser/styles.module.css +++ b/website/src/components/FileBrowser/styles.module.css @@ -169,6 +169,7 @@ /* Example Card */ .exampleCard { + position: relative; min-width: 0; max-width: 100%; overflow: hidden; @@ -184,6 +185,25 @@ transition: all 0.2s ease; } +/* "Copy as Markdown" icon button in a card's corner (enableCopyMarkdown + option) - hidden until the card is hovered/focused, so it doesn't compete + with the title at rest. Sits outside the card's s so a click never + triggers navigation (see CopyMarkdownButton's stopPropagation). */ +.exampleCardCopyButton { + position: absolute; + top: 1rem; + right: 1rem; + z-index: 1; + opacity: 0; + transition: opacity 0.15s ease; +} + +.exampleCard:hover .exampleCardCopyButton, +.exampleCard:focus-within .exampleCardCopyButton, +.exampleCardCopyButton:focus-visible { + opacity: 1; +} + .exampleCard:hover { border-color: rgba(30, 91, 184, 0.3); box-shadow: 0 4px 16px rgba(30, 91, 184, 0.1); @@ -244,6 +264,16 @@ color: var(--ifm-heading-color); } +/* Skill titles rendered as `/name` (titleAsCode option) keep the monospace + font but drop Infima's default inline-code background chip/border. */ +.exampleCardTitle code { + background: none; + border: none; + padding: 0; + color: inherit; + font-size: inherit; +} + .exampleCardDescription { min-width: 0; font-size: 0.9rem; @@ -398,6 +428,16 @@ text-decoration: none; } +/* Skill titles rendered as `/name` (titleAsCode option) keep the monospace + font but drop Infima's default inline-code background chip/border. */ +.sidebarExampleLink code { + background: none; + border: none; + padding: 0; + color: inherit; + font-size: inherit; +} + .sidebarExampleLink:hover { color: var(--ifm-color-primary); text-decoration: none; @@ -744,6 +784,33 @@ font-size: 1rem; } +/* Icon-only variant (CopyMarkdownButton's iconOnly prop) - a compact circular + button for tight spaces like a card corner. */ +.copyMarkdownIconButton { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0; + background: var(--ifm-background-surface-color); + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 50%; + color: var(--ifm-color-emphasis-700); + cursor: pointer; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); + transition: all 0.15s ease; +} + +.copyMarkdownIconButton:hover { + background: var(--ifm-color-emphasis-100); + color: var(--ifm-color-primary); +} + +:global(html[data-theme='dark']) .copyMarkdownIconButton { + border-color: rgba(255, 255, 255, 0.12); +} + /* README Section */ .readmeSection { width: 100%; From 853002addcb8e076e2a944e9e389bf91a08b9547 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 20:53:45 -0500 Subject: [PATCH 08/24] fix(ai): match card copy-button style to the site's pill buttons The icon-only copy button used a solid circular background with a border and drop shadow, inconsistent with the translucent rounded- rect pill language used everywhere else (.copyMarkdownButton, .githubButton, .filterButton). Same rgba background/hover, 6px radius, no shadow. --- .../components/FileBrowser/styles.module.css | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/website/src/components/FileBrowser/styles.module.css b/website/src/components/FileBrowser/styles.module.css index 772a142fd50..74318438c5e 100644 --- a/website/src/components/FileBrowser/styles.module.css +++ b/website/src/components/FileBrowser/styles.module.css @@ -784,8 +784,9 @@ font-size: 1rem; } -/* Icon-only variant (CopyMarkdownButton's iconOnly prop) - a compact circular - button for tight spaces like a card corner. */ +/* Icon-only variant (CopyMarkdownButton's iconOnly prop) - a compact button + for tight spaces like a card corner. Same translucent pill language as + .copyMarkdownButton/.githubButton/.filterButton, just square and unlabeled. */ .copyMarkdownIconButton { display: inline-flex; align-items: center; @@ -793,22 +794,24 @@ width: 2rem; height: 2rem; padding: 0; - background: var(--ifm-background-surface-color); - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 50%; + background: rgba(0, 0, 0, 0.05); + border: none; + border-radius: 6px; color: var(--ifm-color-emphasis-700); cursor: pointer; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); - transition: all 0.15s ease; + transition: all 0.2s ease; } .copyMarkdownIconButton:hover { - background: var(--ifm-color-emphasis-100); - color: var(--ifm-color-primary); + background: rgba(0, 0, 0, 0.1); } :global(html[data-theme='dark']) .copyMarkdownIconButton { - border-color: rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.08); +} + +:global(html[data-theme='dark']) .copyMarkdownIconButton:hover { + background: rgba(255, 255, 255, 0.12); } /* README Section */ From e51d96e6b4b8251dbac2526cca8589b8a160f0e7 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 21:26:20 -0500 Subject: [PATCH 09/24] docs(ci): note that atmos CLI replaces the old github-action-* Actions --- website/docs/ci/ci.mdx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/website/docs/ci/ci.mdx b/website/docs/ci/ci.mdx index 1c6340d0f73..1b00e6750a8 100644 --- a/website/docs/ci/ci.mdx +++ b/website/docs/ci/ci.mdx @@ -22,6 +22,19 @@ repositories, and commit results back to your source of truth. Kubernetes compon native job summaries, with a deliberately smaller v1 surface. +:::note Replaces the old `cloudposse/github-action-*` Actions +You do not need the separate [`cloudposse/github-action-atmos-terraform-*` Actions](/deprecated/github-actions) +anymore. The `atmos` CLI now does this work: + +- It writes job summaries. +- It posts status checks. +- It sets output variables. +- It manages planfiles. + +Do not use the old Actions in new workflows. Existing workflows that use them still work. New +workflows need only `actions/checkout` and an `atmos` command, as shown below. +::: + ## Quick Start From 8f9992c34e0ae137242fc41e9624c534a42706c4 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 21:43:09 -0500 Subject: [PATCH 10/24] fix: JSON empty-array bug in list renderer, backtick-fence collision - pkg/list/renderer: formatJSON built its result with a nil slice var, so json.MarshalIndent emitted "null" instead of "[]" for zero rows. Every --format=json list command was affected, not just skills. Strengthened the regression test (cmd/ai/skill/list_test.go) to require a non-nil slice, which is what caught this. - file-browser plugin + client utils: collectMarkdownContext wrapped non-Markdown file content in a fixed ``` fence. A nested file whose own content contains a ``` run would close the fence early and corrupt the generated/copied Markdown. Both twins now pick a fence longer than any backtick run already in the content. --- cmd/ai/skill/list_test.go | 1 + pkg/list/renderer/renderer.go | 5 ++++- website/plugins/file-browser/index.js | 20 +++++++++++++++++--- website/src/components/FileBrowser/utils.ts | 17 ++++++++++++++--- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/cmd/ai/skill/list_test.go b/cmd/ai/skill/list_test.go index 891779c41e9..d5aedeff415 100644 --- a/cmd/ai/skill/list_test.go +++ b/cmd/ai/skill/list_test.go @@ -567,6 +567,7 @@ func TestListCmd_InstalledOnly(t *testing.T) { var rows []map[string]string require.NoError(t, json.Unmarshal([]byte(output), &rows), "output must be valid JSON") + require.NotNil(t, rows, "output must be a JSON array, not null") assert.Empty(t, rows) }) } diff --git a/pkg/list/renderer/renderer.go b/pkg/list/renderer/renderer.go index 567fe8429c3..7e7ae39ef4f 100644 --- a/pkg/list/renderer/renderer.go +++ b/pkg/list/renderer/renderer.go @@ -347,8 +347,11 @@ func columnIndex(headers []string, name string) int { } // formatJSON formats headers and rows as JSON array of objects. +// Uses make (not a nil var) so json.MarshalIndent emits "[]" instead of +// "null" when rows is empty - callers rely on the output staying a valid, +// parseable JSON array regardless of row count. func formatJSON(headers []string, rows [][]string) (string, error) { - var result []map[string]string + result := make([]map[string]string, 0, len(rows)) for _, row := range rows { obj := make(map[string]string) for i, header := range headers { diff --git a/website/plugins/file-browser/index.js b/website/plugins/file-browser/index.js index b8ae97e0ef0..0f8326c228d 100644 --- a/website/plugins/file-browser/index.js +++ b/website/plugins/file-browser/index.js @@ -713,6 +713,21 @@ const BINARY_EXTENSIONS = new Set([ 'gz', 'exe', 'dll', 'so', 'dylib', 'bin', 'dat', ]); +/** + * Wraps content in a fenced code block using a fence longer than any + * backtick run already in the content, so a nested file containing its own + * ``` doesn't close the wrapping fence early and corrupt the document. + * Mirrors codeFence() in website/src/components/FileBrowser/utils.ts. + * @param {string} content - File content (already trimmed by caller). + * @param {string} language - Syntax-highlighting language hint. + * @returns {string} - Fenced code block. + */ +function codeFence(content, language) { + const longestRun = Math.max(0, ...(content.match(/`+/g) || []).map((run) => run.length)); + const fence = '`'.repeat(Math.max(3, longestRun + 1)); + return `${fence}${language}\n${content}\n${fence}`; +} + /** * Recursively concatenates every readable file under a directory into one * Markdown document — the whole item, nested reference files included, as a @@ -730,9 +745,8 @@ function collectMarkdownContext(root) { const addFile = (node) => { if (node.content == null || BINARY_EXTENSIONS.has((node.extension || '').toLowerCase())) return; const ext = (node.extension || '').toLowerCase(); - const body = ext === 'md' || ext === 'mdx' - ? node.content.trim() - : `\`\`\`${node.language}\n${node.content.trim()}\n\`\`\``; + const trimmed = node.content.trim(); + const body = ext === 'md' || ext === 'mdx' ? trimmed : codeFence(trimmed, node.language); sections.push(`## ${node.path}\n\n${body}`); }; diff --git a/website/src/components/FileBrowser/utils.ts b/website/src/components/FileBrowser/utils.ts index 2d8b622aac9..e80d28ec1fc 100644 --- a/website/src/components/FileBrowser/utils.ts +++ b/website/src/components/FileBrowser/utils.ts @@ -204,6 +204,18 @@ export function getParentPath(path: string): string { return parts.join('/'); } +/** + * Wraps content in a fenced code block using a fence longer than any + * backtick run already in the content, so a nested file containing its own + * ``` doesn't close the wrapping fence early and corrupt the document. + * Mirrors codeFence() in website/plugins/file-browser/index.js. + */ +function codeFence(content: string, language: string): string { + const longestRun = Math.max(0, ...(content.match(/`+/g) ?? []).map((run) => run.length)); + const fence = '`'.repeat(Math.max(3, longestRun + 1)); + return `${fence}${language}\n${content}\n${fence}`; +} + /** * Recursively concatenates every readable file under a directory into one * Markdown document — the whole skill, references included, as a single @@ -219,9 +231,8 @@ export function collectMarkdownContext(root: DirectoryNode): string { const addFile = (node: FileNode) => { if (node.content == null || isBinaryFile(node)) return; - const body = isMarkdownFile(node) - ? node.content.trim() - : `\`\`\`${node.language}\n${node.content.trim()}\n\`\`\``; + const trimmed = node.content.trim(); + const body = isMarkdownFile(node) ? trimmed : codeFence(trimmed, node.language); sections.push(`## ${node.path}\n\n${body}`); }; From 3ea5b0f4a99c248b40bcc370e1085ef5215b499b Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Wed, 5 Aug 2026 21:53:37 -0500 Subject: [PATCH 11/24] fix(ai): disable pointer-events on hidden card copy button opacity: 0 doesn't remove an element from hit testing. The invisible button sat in front of the card link (top-right), so an early click or touch there hit the button instead of navigating - its handler stops propagation, silently swallowing the click. --- website/src/components/FileBrowser/styles.module.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/src/components/FileBrowser/styles.module.css b/website/src/components/FileBrowser/styles.module.css index 74318438c5e..7e61a72e3de 100644 --- a/website/src/components/FileBrowser/styles.module.css +++ b/website/src/components/FileBrowser/styles.module.css @@ -195,6 +195,7 @@ right: 1rem; z-index: 1; opacity: 0; + pointer-events: none; transition: opacity 0.15s ease; } @@ -202,6 +203,7 @@ .exampleCard:focus-within .exampleCardCopyButton, .exampleCardCopyButton:focus-visible { opacity: 1; + pointer-events: auto; } .exampleCard:hover { From 6b8b814cb233f46b5a592ecb8fee3e084431318c Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 6 Aug 2026 08:47:47 -0500 Subject: [PATCH 12/24] ci: give windows acceptance-test job timeout real headroom A run hit the 75-minute job-level ceiling to the exact second while every individual step, including the full go test suite, had already completed successfully per the logs - the "Acceptance tests" step itself finished in 54.6m, under its own 60m budget, but the job-level timeout left almost no slack once summed with setup/toolchain steps. Same CI-to-CI variance already documented on the step-level timeout below; widen the job-level ceiling to match. --- .github/workflows/test.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5dd0e2228d8..700b71f280d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -180,7 +180,14 @@ jobs: - { os: "ubuntu-latest", target: linux } - { os: "windows-latest", target: windows } - { os: "macos-15", target: macos } - timeout-minutes: 75 + # windows-latest's steps individually stay within their own budgets (the + # "Acceptance tests" step has a 60m budget below) but their sum leaves the + # job-level timeout almost no slack - a run that hit exactly 75.0 minutes + # was force-cancelled by this ceiling with every step, including the full + # go test suite, already completed successfully in the logs. Same + # variance documented on the "Acceptance tests" step's own timeout below; + # give the job-level ceiling real headroom too. + timeout-minutes: 90 runs-on: ${{ matrix.flavor.os }} steps: - name: Check out code into the Go module directory From e127f8a8a4ba7f18c1b37545baa7fbd0126dbe54 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 6 Aug 2026 15:25:06 -0500 Subject: [PATCH 13/24] docs(website): reorganize Atmos AI sidebar and consolidate agent skills docs Nest MCP under the Atmos AI category alongside a flat "Agent Skills" link (previously a top-level sibling behind a nested "Skills" category), and consolidate the redundant agent-skills.mdx and skill-marketplace.mdx pages into the atmos ai skill CLI command reference, updating all cross-references and adding redirects for the removed URLs. Also fixes a duplicate "scaffold" sidebar entry: scaffold.mdx now lives inside the scaffold/ folder as usage.mdx with a _category_.json, matching every other multi-subcommand command (auth, pro, validate, ai, toolchain). Co-Authored-By: Claude Sonnet 5 --- ...-20-introducing-atmos-init-and-scaffold.md | 2 +- website/blog/2026-03-03-ai-agent-skills.mdx | 2 +- ...026-05-19-mcp-for-ai-coding-assistants.mdx | 4 +- .../2026-06-30-offline-ai-skill-catalog.mdx | 4 +- .../2026-08-05-agent-skills-directory.mdx | 4 +- website/docs/ai/agent-skills.mdx | 245 ---------------- website/docs/ai/ai.mdx | 8 - website/docs/ai/skill-marketplace.mdx | 266 ------------------ website/docs/cli/commands/ai/skill.mdx | 247 +++++++++++++++- website/docs/cli/commands/init.mdx | 4 +- .../cli/commands/scaffold/_category_.json | 10 + website/docs/cli/commands/scaffold/list.mdx | 2 +- .../{scaffold.mdx => scaffold/usage.mdx} | 1 - .../docs/cli/commands/scaffold/validate.mdx | 2 +- website/docs/cli/configuration/ai/skills.mdx | 5 +- .../projects/setup-editor/ai-assistants.mdx | 2 +- website/docusaurus.config.js | 6 + website/plugins/file-browser/index.js | 8 + website/sidebars.js | 12 +- website/src/components/CommandBox/index.css | 110 ++++++++ website/src/components/CommandBox/index.tsx | 46 +++ .../components/FileBrowser/DirectoryPage.tsx | 9 + website/src/components/FileBrowser/types.ts | 4 + .../components/landing/Extensibility/index.js | 2 +- website/src/data/roadmap.js | 2 +- 25 files changed, 457 insertions(+), 550 deletions(-) delete mode 100644 website/docs/ai/agent-skills.mdx delete mode 100644 website/docs/ai/skill-marketplace.mdx create mode 100644 website/docs/cli/commands/scaffold/_category_.json rename website/docs/cli/commands/{scaffold.mdx => scaffold/usage.mdx} (99%) create mode 100644 website/src/components/CommandBox/index.css create mode 100644 website/src/components/CommandBox/index.tsx diff --git a/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md b/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md index ab3e34887e5..7b5c568094e 100644 --- a/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md +++ b/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md @@ -294,7 +294,7 @@ We'd love to hear your feedback! Join the discussion in our [GitHub Discussions] ## Documentation - [atmos init command reference](/cli/commands/init) -- [atmos scaffold command reference](/cli/commands/scaffold) +- [atmos scaffold command reference](/cli/commands/scaffold/usage) - [Creating Custom Scaffold Templates](/cli/commands/scaffold/generate) - [PRD: Init Command](https://github.com/cloudposse/atmos/blob/main/docs/prd/atmos-init.md) - [PRD: Scaffold Command](https://github.com/cloudposse/atmos/blob/main/docs/prd/atmos-scaffold.md) diff --git a/website/blog/2026-03-03-ai-agent-skills.mdx b/website/blog/2026-03-03-ai-agent-skills.mdx index 3e918572aa7..13583c52e65 100644 --- a/website/blog/2026-03-03-ai-agent-skills.mdx +++ b/website/blog/2026-03-03-ai-agent-skills.mdx @@ -129,7 +129,7 @@ atmos vendor pull --component agent-skills This downloads the `agent-skills/` directory with the correct structure intact. To update skills later, run the same command again. -See the [AI Agent Skills documentation](/ai/agent-skills) for the full skill reference and [Configure AI Assistants](/projects/setup-editor/ai-assistants) for tool-specific setup instructions. +See the [AI Agent Skills documentation](/cli/commands/ai/skill) for the full skill reference and [Configure AI Assistants](/projects/setup-editor/ai-assistants) for tool-specific setup instructions. ## How Skills Are Activated diff --git a/website/blog/2026-05-19-mcp-for-ai-coding-assistants.mdx b/website/blog/2026-05-19-mcp-for-ai-coding-assistants.mdx index 35c14d7709a..1209cd6b7c8 100644 --- a/website/blog/2026-05-19-mcp-for-ai-coding-assistants.mdx +++ b/website/blog/2026-05-19-mcp-for-ai-coding-assistants.mdx @@ -211,7 +211,7 @@ So the AI can answer cross-layer questions in one prompt: ## Pair with Atmos Agent Skills MCP gives the AI **tools** — to inspect stacks, query AWS, check Atmos -Pro. [Atmos Agent Skills](/ai/agent-skills) give it +Pro. [Atmos Agent Skills](/cli/commands/ai/skill) give it **knowledge** — domain-specific skills (stacks, components, validation, YAML functions, vendoring, toolchain, GitOps, auth, …) that activate based on what you ask. @@ -441,7 +441,7 @@ toolchain aliases and `atmos toolchain install` work. - [Atmos MCP Server](/ai/mcp-server) — the Atmos-AI-tools-as-MCP-server mode, exposed to your AI coding assistant via the `atmos` entry in `mcp.servers`. -- [Atmos Agent Skills](/ai/agent-skills) — 21 +- [Atmos Agent Skills](/cli/commands/ai/skill) — 21 domain-specific skills that complement MCP tools by giving AI assistants deep Atmos knowledge (stacks, components, validation, YAML functions, vendoring, GitOps, design patterns, …). diff --git a/website/blog/2026-06-30-offline-ai-skill-catalog.mdx b/website/blog/2026-06-30-offline-ai-skill-catalog.mdx index 830a1214e0e..1a86cef41e9 100644 --- a/website/blog/2026-06-30-offline-ai-skill-catalog.mdx +++ b/website/blog/2026-06-30-offline-ai-skill-catalog.mdx @@ -6,7 +6,7 @@ authors: [osterman] tags: [enhancement, dx] --- -The official Atmos [agent skills](/ai/agent-skills) are now embedded directly in the Atmos binary. `atmos ai skill install ` works **fully offline** — no network call, no Git clone — and `atmos ai skill list` shows a single merged view of every skill available to you alongside what's already installed. +The official Atmos [agent skills](/cli/commands/ai/skill) are now embedded directly in the Atmos binary. `atmos ai skill install ` works **fully offline** — no network call, no Git clone — and `atmos ai skill list` shows a single merged view of every skill available to you alongside what's already installed. @@ -49,4 +49,4 @@ atmos terraform plan vpc -s plat-ue2-prod --ai --skill atmos-terraform ## Get Involved -See the [`atmos ai skill`](/cli/commands/ai/skill) command reference and the [Agent Skills](/ai/agent-skills) guide. Skill ideas and contributions are welcome in the [Atmos community](https://github.com/cloudposse/atmos). +See the [`atmos ai skill`](/cli/commands/ai/skill) command reference. Skill ideas and contributions are welcome in the [Atmos community](https://github.com/cloudposse/atmos). diff --git a/website/blog/2026-08-05-agent-skills-directory.mdx b/website/blog/2026-08-05-agent-skills-directory.mdx index 068e048cbe3..6e88f122c4d 100644 --- a/website/blog/2026-08-05-agent-skills-directory.mdx +++ b/website/blog/2026-08-05-agent-skills-directory.mdx @@ -14,7 +14,7 @@ signals that it's stale. ## The Problem -Atmos's own [agent skills](/ai/agent-skills) documentation had exactly this problem. The page hand-listed +Atmos's own [agent skills](/cli/commands/ai/skill) documentation had exactly this problem. The page hand-listed each skill in a static table, and as new skills shipped, the list wasn't updated to match -- it drifted to roughly half the real count, with a couple of stale entries pointing at skills that no longer existed. There was also no way to search or filter -- just one long page to scroll and skim. @@ -44,5 +44,5 @@ atmos ai skill list --format=yaml ## Get Involved -See the [Agent Skills](/ai/agent-skills) guide for how skills are structured and how to contribute one. Skill +See the [Agent Skills](/cli/commands/ai/skill) guide for how skills are structured and how to contribute one. Skill ideas and contributions are welcome in the [Atmos community](https://github.com/cloudposse/atmos). diff --git a/website/docs/ai/agent-skills.mdx b/website/docs/ai/agent-skills.mdx deleted file mode 100644 index 89be6617c06..00000000000 --- a/website/docs/ai/agent-skills.mdx +++ /dev/null @@ -1,245 +0,0 @@ ---- -title: AI Agent Skills -sidebar_label: AI Agent Skills -description: Give AI coding assistants deep knowledge of Atmos through portable agent skills that work across Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more. -id: agent-skills -slug: /ai/agent-skills ---- -import Intro from '@site/src/components/Intro' -import KeyPoints from '@site/src/components/KeyPoints' -import Link from '@docusaurus/Link' -import SkillCount from '@site/src/components/SkillCount' - - -Atmos ships agent skills that give AI coding assistants deep, accurate knowledge of Atmos -conventions, stack configuration, Terraform orchestration, authentication, validation, and more. The skills live in -the `agent-skills/` folder at the root of the Atmos repository and work across all major AI tools. - - - -- domain-specific skills covering every Atmos subsystem -- browse them all in the [Agent Skills Directory](/ai/skills) -- Works with Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more -- Progressive disclosure: AI loads only the skill it needs, keeping context focused -- Portable SKILL.md format with YAML frontmatter and tiered reference files - - -## What Are Agent Skills? - -Agent skills are structured knowledge files that teach AI coding assistants how to work with specific tools and -frameworks. Each skill is a self-contained package with: - -- **SKILL.md** -- The primary instruction file (under 500 lines) with YAML frontmatter metadata -- **references/** -- Deeper reference files that the AI loads only when the task requires them - -Skills use a three-tier progressive disclosure pattern: - -1. **Router** (`AGENTS.md`) -- A lightweight index that maps user tasks to the right skill -2. **Skill** (`SKILL.md`) -- Domain-specific instructions, patterns, and examples -3. **References** (`references/*.md`) -- Detailed specifications, schemas, and command references - -This design keeps AI context windows focused. The AI loads the router first, identifies which skill applies, loads -that skill, and only pulls in reference files when deep detail is needed. - -## Available Skills - -Atmos skills cover every major subsystem -- Terraform and Helmfile orchestration, stack configuration, auth, -secrets, validation, CI, emulators, and more -- and the list keeps growing with each release. Rather than a static -list here (which drifts out of date as skills are added), browse the full, always-current, searchable set at: - -

    - - Browse the Agent Skills Directory → - -

    - -Each skill's page there is generated directly from its `SKILL.md`, grouped by category, and links back to its -source on GitHub. - -## Folder Structure - -All skills live in a single flat directory, packaged as one Claude Code plugin: - -```text -agent-skills/ # Single plugin - AGENTS.md # Skill-activation router (loaded first) - .claude-plugin/plugin.json # Plugin manifest - skills/ - atmos-terraform/ # One directory per skill - SKILL.md # Primary instruction file (<500 lines) - references/ # Deep-dive reference files - atmos-stacks/ - SKILL.md - references/ - atmos-config/ - SKILL.md - references/ - ... # One directory per skill -- see /ai/skills for the full list - -.claude/skills/ # Symlinks for auto-discovery (Atmos contributors) - atmos-terraform -> ../../agent-skills/skills/atmos-terraform - atmos-config -> ../../agent-skills/skills/atmos-config - atmos-stacks -> ../../agent-skills/skills/atmos-stacks - ... # One symlink per skill - docs/ # Repo-local contributor skill, not part of agent-skills - SKILL.md -``` - -`agent-skills/` is the single source of truth for consumer-facing Atmos skills. `.claude/skills/` contains symlinks -so Claude Code auto-discovers those skills when working directly in the Atmos repo. It can also contain repo-local -contributor skills, such as `docs`, that are intentionally not included in the public agent skill package. - -Each skill folder follows the same pattern: one `SKILL.md` file and a `references/` directory with one or more -deep-dive reference files. - -## SKILL.md Format - -Every skill file uses YAML frontmatter followed by markdown instructions: - -```yaml ---- -name: atmos-stacks -description: "Stack configuration: imports, inheritance, deep merging, locals, vars, settings, metadata, overrides, atmos.yaml setup" -metadata: - copyright: Copyright Cloud Posse, LLC 2026 - version: "1.0.0" - category: core-config -references: - - references/import-patterns.md - - references/inheritance-deep-merge.md ---- - -# Atmos Stacks - -Instructions for the AI assistant... -``` - -
    -
    `name`
    -
    Unique identifier for the skill (must match the directory name).
    - -
    `description`
    -
    Human-readable summary of what the skill teaches.
    - -
    `metadata.copyright`
    -
    Copyright notice.
    - -
    `metadata.version`
    -
    SemVer version of the skill content.
    - -
    `metadata.category`
    -
    Groups the skill in the [Agent Skills Directory](/ai/skills) (e.g. `orchestrators`, `security`, `ci-automation`).
    - -
    `references`
    -
    Optional list of deeper reference files the AI should load when more detail is needed.
    -
    - -## AGENTS.md Router - -The `AGENTS.md` file at the root of `agent-skills/` is a lightweight router that maps tasks to skills. AI tools -load this file first and use it to decide which skill to activate. - -The router includes: -- **Core Concepts** -- Brief definitions of stacks, components, vendoring, auth, stores, workflows -- **Key Commands** -- Quick reference for the most common Atmos CLI commands -- **Skill Index** -- A table mapping task descriptions to skill names and file paths -- **Common Patterns** -- Naming conventions, inheritance patterns, and cross-stack references - -## How Skills Are Activated - -You do **not** invoke skills manually. Your AI tool activates the right skill automatically based on your question: - -1. **At session start**, the AI loads lightweight metadata (name and description) from each installed skill -2. **When you ask a question** about Atmos, the AI matches your question to the most relevant skill's description -3. **The full skill content** loads on demand, giving the AI accurate, up-to-date guidance -4. **Reference files** load only when the AI needs deeper detail (e.g., full command reference, schema examples) - -For example, if you ask *"How do I configure stack imports?"*, the AI automatically activates the `atmos-stacks` -skill and uses its content to answer correctly -- no special syntax or commands needed. - -:::tip -For Claude Code plugin installations, activation uses the `description` field in each SKILL.md's frontmatter. -For file-based installations (Codex, Gemini, Windsurf, Copilot), the `AGENTS.md` router maps your task to -the right skill via its skill index table. Both mechanisms are automatic. -::: - -## Open Standards - -Atmos skills build on two open standards that are broadly adopted across AI coding tools: - -- **[AGENTS.md](https://agents.md/)** -- A Markdown file convention for project-level AI instructions. Created by OpenAI - with Google, Cursor, and others. Governed by the [Linux Foundation's Agentic AI Foundation (AAIF)](https://www.linuxfoundation.org/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation). - Adopted by 60,000+ GitHub repositories. -- **[Agent Skills](https://agentskills.io/specification)** (`SKILL.md`) -- A directory-based format for packaging AI - capabilities with instructions, references, and assets. Created by Anthropic as an open standard. Adopted by Microsoft, - OpenAI, Cursor, and GitHub. - -Every major AI tool has its own configuration directory (`.claude/`, `.cursor/`, `.gemini/`, `.github/`, etc.). -Cross-tool interoperability happens at the **file format level** (`AGENTS.md` and `SKILL.md`), not through a shared -directory path. This is why Atmos places skills in a tool-agnostic `agent-skills/` directory and uses symlinks for -tool-specific discovery. - -## Uninstalling Skills - -To remove Atmos skills from Claude Code: - -```bash -# Remove the plugin -/plugin uninstall atmos@cloudposse - -# Remove the marketplace (optional) -/plugin marketplace remove cloudposse -``` - -## Using Skills with AI Tools - -For step-by-step instructions on configuring each AI tool, see -[Configure AI Assistants](/projects/setup-editor/ai-assistants). That page covers installation and setup for -Claude Code, Cursor, Windsurf, GitHub Copilot, Gemini CLI, OpenAI Codex, and more. - -## How Skills Improve AI Assistance - -Without skills, AI assistants rely on general training data that may be outdated or incomplete. With skills: - -- **Accurate configuration** -- The AI knows the exact YAML schema, merge behavior, and naming conventions -- **Correct commands** -- The AI generates valid `atmos terraform`, `atmos helmfile`, and other CLI commands -- **Best practices** -- The AI follows Atmos design patterns for stack organization and component reuse -- **Current features** -- Skills are updated with each Atmos release, covering features like YAML functions (`!store`, `!aws.*`), - store integrations, and multi-provider auth - -### Example: Without Skills vs. With Skills - -**Without skills**, an AI might generate incorrect stack configuration: - -```yaml -# Wrong: AI guesses at the format -terraform: - vpc: - region: us-east-1 - cidr: "10.0.0.0/16" -``` - -**With the `atmos-stacks` skill loaded**, the AI generates correct configuration: - -```yaml -# Correct: AI knows the Atmos schema -components: - terraform: - vpc: - vars: - region: us-east-1 - cidr_block: "10.0.0.0/16" -``` - -## Contributing Skills - -Skills are maintained in the Atmos repository under `agent-skills/`. To contribute: - -1. Follow the existing folder structure: `agent-skills/skills//SKILL.md` -2. Keep the primary `SKILL.md` under 500 lines for optimal context usage -3. Place detailed reference material in `references/` subdirectories -4. Update `AGENTS.md` to include your skill in the routing table -5. Use YAML frontmatter with `name`, `description`, `metadata` (containing `copyright`, `version`, and `category`), and optionally `references` fields - -New skills appear automatically in the [Agent Skills Directory](/ai/skills) -- no separate doc update needed. - -See the [Atmos Contributing Guide](/community) for general contribution guidelines. diff --git a/website/docs/ai/ai.mdx b/website/docs/ai/ai.mdx index 897f886e05f..63d980164d9 100644 --- a/website/docs/ai/ai.mdx +++ b/website/docs/ai/ai.mdx @@ -221,14 +221,6 @@ standard and work across Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf
    Install, list, and uninstall community AI skills from GitHub.
-### [Agent Skills Overview](/ai/agent-skills) - -How skills work, available skills, and the SKILL.md format. - -### [Skill Marketplace](/ai/skill-marketplace) - -Install and share community skills from GitHub. - ### [Skills Configuration](/cli/configuration/ai/skills) Configure skills in `atmos.yaml`. diff --git a/website/docs/ai/skill-marketplace.mdx b/website/docs/ai/skill-marketplace.mdx deleted file mode 100644 index 446bb0cb1dc..00000000000 --- a/website/docs/ai/skill-marketplace.mdx +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: AI Skill Marketplace -sidebar_label: Skill Marketplace -description: Install and share community AI skills from GitHub -id: skill-marketplace ---- -import Terminal from '@site/src/components/Terminal' -import File from '@site/src/components/File' -import Intro from '@site/src/components/Intro' -import Experimental from '@site/src/components/Experimental' - - -The Atmos AI Skill Marketplace enables you to install, share, and use community-created AI skills from GitHub repositories. Installed skills are stored in `~/.atmos/skills/` and appear in the TUI skill selector (Ctrl+A). - - - - -:::info Not Claude's Marketplace -The Atmos Skill Marketplace is **not related to Anthropic's Claude marketplace**. This is Atmos's own system for installing and sharing specialized AI skills from GitHub repositories. Skills follow the [Agent Skills open standard](https://agentskills.io) governed by the Linux Foundation's Agentic AI Foundation (AAIF). -::: - -## Installing Skills - -Install skills using various GitHub URL formats: - - -```bash -# Install all official Atmos skills (recommended) -- browse them at /ai/skills -atmos ai skill install cloudposse/atmos - -# With specific version tag -atmos ai skill install cloudposse/atmos@v1.200.0 - -# With branch name -atmos ai skill install cloudposse/atmos@main - -# Full GitHub URL -atmos ai skill install https://github.com/cloudposse/atmos.git - -# Force reinstall -atmos ai skill install cloudposse/atmos --force - -# Skip confirmation prompt -atmos ai skill install cloudposse/atmos --yes -``` - - -:::warning Security Consideration -Only use `--yes` with skills from trusted sources. Always review skill metadata before installing, especially the `tools.allowed` section. -::: - -When you install a skill, Atmos downloads the repository, validates the SKILL.md file, checks version compatibility, prompts for confirmation, and registers it in the local skill registry. - -## Managing Installed Skills - -### List Available and Installed Skills - -`atmos ai skill list` shows the full catalog of official skills (embedded in the binary, so it works offline) alongside anything you've installed. A filled dot (`●`) marks an installed skill; a hollow dot (`○`) marks one that's available to install. Add `--installed` to show only what's installed. - - -```bash -atmos ai skill list -``` - - -### Uninstall a Skill - - -```bash -# Interactive confirmation -atmos ai skill uninstall atmos-terraform - -# Force uninstall (no confirmation) -atmos ai skill uninstall atmos-terraform --force -``` - - -### Enable/Disable Skills - -*(Coming soon)* Temporarily disable skills without uninstalling: - - -```bash -atmos ai skill disable atmos-terraform -atmos ai skill enable atmos-terraform -``` - - -## Creating Marketplace Skills - -### SKILL.md Format - -Skills follow the [Agent Skills open standard](https://agentskills.io) format -- a single SKILL.md file with YAML frontmatter and a Markdown body containing the system prompt. - -``` -your-skill-repo/ -├── SKILL.md # Skill definition (required) -├── README.md # Documentation (recommended) -├── examples/ # Usage examples (optional) -└── LICENSE # License file (recommended) -``` - -### SKILL.md Structure - -The frontmatter declares metadata and tool access. The Markdown body is the AI system prompt. - - -```markdown ---- -name: terraform-expert -display_name: "Terraform Expert" -version: 1.0.0 -author: Cloud Posse -description: > - Specialized AI skill for Terraform component development, - debugging, and best practices. -category: refactor - -atmos: - min_version: 1.50.0 - max_version: "" - -tools: - allowed: - - atmos_describe_component - - read_component_file - - read_file - - edit_file - - execute_bash - restricted: - - edit_file - - execute_bash - -capabilities: - - terraform-development - - component-architecture - -dependencies: - - terraform - -repository: https://github.com/yourorg/atmos-skill-terraform ---- - -# Skill: Terraform Expert - -## Role - -You are a specialized AI skill for Terraform component development... - -## Instructions - -[Detailed instructions for the AI skill go here] - -## Restrictions - -- Always confirm before executing destructive commands -- Never commit secrets or credentials to code -``` - - -
-
`name`
-
Unique skill identifier in kebab-case.
- -
`display_name`
-
User-facing display name.
- -
`version`
-
Semantic version (e.g., `1.2.3`).
- -
`author`
-
Author name or organization.
- -
`description`
-
Brief description of skill purpose.
- -
`category`
-
One of: `general`, `analysis`, `refactor`, `security`, `validation`, `optimization`.
- -
`atmos.min_version`
-
Minimum compatible Atmos version.
- -
`tools.allowed`
-
Tools the skill can use. Tools in `restricted` require user confirmation each time.
- -
`repository`
-
GitHub repository URL.
-
- -### Publishing Your Skill - -Create a GitHub repository with a valid SKILL.md, tag a release, and share it: - - -```bash -mkdir atmos-skill-terraform && cd atmos-skill-terraform -git init - -# Create SKILL.md with frontmatter and prompt (see format above) - -git add . && git commit -m "Initial skill release" -git remote add origin git@github.com:yourorg/atmos-skill-terraform.git -git push -u origin main -git tag v1.0.0 && git push origin v1.0.0 -``` - - -Share your skill in [Atmos Discussions](https://github.com/cloudposse/atmos/discussions) and add the `atmos-skill` topic to your repository. - -:::tip Naming Convention -- **Repository**: prefix with `atmos-skill-`, use kebab-case (e.g., `atmos-skill-cost-optimizer`) -- **Skill name**: no prefix, kebab-case (e.g., `cost-optimizer`) -- **Display name**: title case (e.g., "Cost Optimizer") -::: - -## Tool Access and Security - -Skills declare which tools they need. Review the `tools.allowed` section before installing any skill. - -:::danger Review Before Installing -**Always review skill source code on GitHub before installing skills that request:** -- File write access (`edit_file`, `write_stack_file`, `write_component_file`) -- Command execution (`execute_bash_command`, `execute_atmos_command`) -::: - -Use the `restricted` field to require user confirmation for sensitive operations. A tool listed in both `allowed` and `restricted` means the skill can use it, but the user must approve each invocation. - -## Troubleshooting - -### Skill Not Found After Installation - -Skill may be disabled or the registry is corrupted. Check with `atmos ai skill list` and inspect `~/.atmos/skills/registry.json`. - -### Version Compatibility Error - -``` -Error: skill requires Atmos >= 1.50.0, but current version is 1.48.0 -``` - -Upgrade Atmos (`brew upgrade atmos`) or install an older skill version (`atmos ai skill install user/skill@v0.9.0`). - -### Invalid Metadata Error - -The skill's SKILL.md has malformed frontmatter. Report the issue to the skill author or try a different version tag. - -### Registry Corruption - - -```bash -# Backup and reset registry -cp ~/.atmos/skills/registry.json ~/.atmos/skills/registry.json.backup -rm ~/.atmos/skills/registry.json - -# Reinstall skills -atmos ai skill install cloudposse/atmos -``` - - -## Related Documentation - -- [Agent Skills Directory](/ai/skills) - Browse every official Atmos skill -- [AI Skills](/cli/configuration/ai/skills) - Skill system overview and configuration -- [AI Configuration](/cli/configuration/ai) - Configure AI providers -- [AI Chat Command](/cli/commands/ai/chat) - Interactive AI chat interface -- [Tool Execution](/cli/configuration/ai/tools) - How AI skills use tools -- [Community Discussions](https://github.com/cloudposse/atmos/discussions) - Discover and share skills diff --git a/website/docs/cli/commands/ai/skill.mdx b/website/docs/cli/commands/ai/skill.mdx index 00e7f97d1da..98a4d4d7976 100644 --- a/website/docs/cli/commands/ai/skill.mdx +++ b/website/docs/cli/commands/ai/skill.mdx @@ -7,9 +7,11 @@ description: Manage AI skills including install, list, and uninstall operations --- import CastPlayer from '@site/src/components/CastPlayer' import Terminal from '@site/src/components/Terminal' +import File from '@site/src/components/File' import DocCardList from '@theme/DocCardList' import Intro from '@site/src/components/Intro' import Experimental from '@site/src/components/Experimental' +import SkillCount from '@site/src/components/SkillCount' Use this command to manage community and custom AI skills. Install skills from GitHub repositories, list installed skills, and remove skills you no longer need. @@ -18,8 +20,7 @@ Use this command to manage community and custom AI skills. Install skills from G **See also:** [Agent Skills Directory](/ai/skills) to browse every skill | -[AI Skills Configuration](/cli/configuration/ai/skills) for configuring skills in `atmos.yaml` | -[Skill Marketplace](/ai/skill-marketplace) for installing community skills +[AI Skills Configuration](/cli/configuration/ai/skills) for configuring skills in `atmos.yaml` @@ -44,6 +45,81 @@ atmos terraform plan vpc -s ue1-prod --ai --skill atmos-terraform See [Global Flags](/cli/global-flags) for details. ::: +## What Are Agent Skills? + +Atmos ships official agent skills that give AI coding assistants deep, accurate knowledge of Atmos +conventions, stack configuration, Terraform orchestration, authentication, validation, and more -- browse them all in +the [Agent Skills Directory](/ai/skills). They live in the `agent-skills/` folder at the root of the Atmos repository +and work across Claude Code, Gemini CLI, OpenAI Codex, Cursor, Windsurf, GitHub Copilot, and more. + +Each official skill is a self-contained package with: +- **SKILL.md** -- The primary instruction file (under 500 lines) with YAML frontmatter metadata +- **references/** -- Deeper reference files that the AI loads only when the task requires them + +Skills use a three-tier progressive disclosure pattern so AI context windows stay focused: + +1. **Router** (`AGENTS.md`) -- A lightweight index that maps user tasks to the right skill +2. **Skill** (`SKILL.md`) -- Domain-specific instructions, patterns, and examples +3. **References** (`references/*.md`) -- Detailed specifications, schemas, and command references + +The AI loads the router first, identifies which skill applies, loads that skill, and only pulls in reference files +when deep detail is needed. You do **not** invoke skills manually -- your AI tool activates the right skill +automatically based on your question. For step-by-step client setup, see +[Configure AI Assistants](/projects/setup-editor/ai-assistants). + +### Official SKILL.md Format + + +```yaml +--- +name: atmos-stacks +description: "Stack configuration: imports, inheritance, deep merging, locals, vars, settings, metadata, overrides, atmos.yaml setup" +metadata: + copyright: Copyright Cloud Posse, LLC 2026 + version: "1.0.0" + category: core-config +references: + - references/import-patterns.md + - references/inheritance-deep-merge.md +--- + +# Atmos Stacks + +Instructions for the AI assistant... +``` + + +
+
`name`
+
Unique identifier for the skill (must match the directory name).
+ +
`description`
+
Human-readable summary of what the skill teaches.
+ +
`metadata.category`
+
Groups the skill in the [Agent Skills Directory](/ai/skills) (e.g. `orchestrators`, `security`, `ci-automation`).
+ +
`references`
+
Optional list of deeper reference files the AI should load when more detail is needed.
+
+ +Skills build on two open standards: [AGENTS.md](https://agents.md/) for project-level AI instructions, and +[Agent Skills](https://agentskills.io/specification) (`SKILL.md`) for packaging AI capabilities with instructions, +references, and assets. + +### Contributing an Official Skill + +Official skills are maintained in the Atmos repository under `agent-skills/`. To contribute one: + +1. Follow the existing folder structure: `agent-skills/skills//SKILL.md` +2. Keep the primary `SKILL.md` under 500 lines for optimal context usage +3. Place detailed reference material in `references/` subdirectories +4. Update `AGENTS.md` to include your skill in the routing table +5. Use YAML frontmatter with `name`, `description`, `metadata` (containing `copyright`, `version`, and `category`), and optionally `references` fields + +New skills appear automatically in the [Agent Skills Directory](/ai/skills) -- no separate doc update needed. See the +[Atmos Contributing Guide](/community) for general contribution guidelines. + ## Usage ```shell @@ -211,6 +287,172 @@ atmos ai skill uninstall skill-name --all-clients atmos ai skill uninstall skill-name --scope user ``` +## Creating and Publishing Your Own Skill + +Skills installed via `atmos ai skill install ` follow the same [Agent Skills open standard](https://agentskills.io) format -- a single SKILL.md file with YAML frontmatter and a Markdown body containing the system prompt. + +``` +your-skill-repo/ +├── SKILL.md # Skill definition (required) +├── README.md # Documentation (recommended) +├── examples/ # Usage examples (optional) +└── LICENSE # License file (recommended) +``` + +The frontmatter declares metadata and tool access. The Markdown body is the AI system prompt. + + +```markdown +--- +name: terraform-expert +display_name: "Terraform Expert" +version: 1.0.0 +author: Cloud Posse +description: > + Specialized AI skill for Terraform component development, + debugging, and best practices. +category: refactor + +atmos: + min_version: 1.50.0 + max_version: "" + +tools: + allowed: + - atmos_describe_component + - read_component_file + - read_file + - edit_file + - execute_bash + restricted: + - edit_file + - execute_bash + +capabilities: + - terraform-development + - component-architecture + +dependencies: + - terraform + +repository: https://github.com/yourorg/atmos-skill-terraform +--- + +# Skill: Terraform Expert + +## Role + +You are a specialized AI skill for Terraform component development... + +## Instructions + +[Detailed instructions for the AI skill go here] + +## Restrictions + +- Always confirm before executing destructive commands +- Never commit secrets or credentials to code +``` + + +
+
`name`
+
Unique skill identifier in kebab-case.
+ +
`display_name`
+
User-facing display name.
+ +
`version`
+
Semantic version (e.g., `1.2.3`).
+ +
`author`
+
Author name or organization.
+ +
`description`
+
Brief description of skill purpose.
+ +
`category`
+
One of: `general`, `analysis`, `refactor`, `security`, `validation`, `optimization`.
+ +
`atmos.min_version`
+
Minimum compatible Atmos version.
+ +
`tools.allowed`
+
Tools the skill can use. Tools in `restricted` require user confirmation each time.
+ +
`repository`
+
GitHub repository URL.
+
+ +### Publishing Your Skill + +Create a GitHub repository with a valid SKILL.md, tag a release, and share it: + + +```bash +mkdir atmos-skill-terraform && cd atmos-skill-terraform +git init + +# Create SKILL.md with frontmatter and prompt (see format above) + +git add . && git commit -m "Initial skill release" +git remote add origin git@github.com:yourorg/atmos-skill-terraform.git +git push -u origin main +git tag v1.0.0 && git push origin v1.0.0 +``` + + +Share your skill in [Atmos Discussions](https://github.com/cloudposse/atmos/discussions) and add the `atmos-skill` topic to your repository. + +:::tip Naming Convention +- **Repository**: prefix with `atmos-skill-`, use kebab-case (e.g., `atmos-skill-cost-optimizer`) +- **Skill name**: no prefix, kebab-case (e.g., `cost-optimizer`) +- **Display name**: title case (e.g., "Cost Optimizer") +::: + +## Tool Access and Security + +Skills declare which tools they need. Review the `tools.allowed` section before installing any skill. + +:::danger Review Before Installing +**Always review skill source code on GitHub before installing skills that request:** +- File write access (`edit_file`, `write_stack_file`, `write_component_file`) +- Command execution (`execute_bash_command`, `execute_atmos_command`) +::: + +Use the `restricted` field to require user confirmation for sensitive operations. A tool listed in both `allowed` and `restricted` means the skill can use it, but the user must approve each invocation. + +## Troubleshooting + +### Skill Not Found After Installation + +Skill may be disabled or the registry is corrupted. Check with `atmos ai skill list` and inspect `~/.atmos/skills/registry.json`. + +### Version Compatibility Error + +``` +Error: skill requires Atmos >= 1.50.0, but current version is 1.48.0 +``` + +Upgrade Atmos (`brew upgrade atmos`) or install an older skill version (`atmos ai skill install user/skill@v0.9.0`). + +### Invalid Metadata Error + +The skill's SKILL.md has malformed frontmatter. Report the issue to the skill author or try a different version tag. + +### Registry Corruption + + +```bash +# Backup and reset registry +cp ~/.atmos/skills/registry.json ~/.atmos/skills/registry.json.backup +rm ~/.atmos/skills/registry.json + +# Reinstall skills +atmos ai skill install cloudposse/atmos +``` + + ## Related Commands diff --git a/website/docs/cli/commands/init.mdx b/website/docs/cli/commands/init.mdx index ac95a375e2d..3606e07bc81 100644 --- a/website/docs/cli/commands/init.mdx +++ b/website/docs/cli/commands/init.mdx @@ -83,7 +83,7 @@ spec: ``` Conditions use `when:` predicates or CEL over earlier `answers`. Generation hooks can use only -`kind: step` and ordered `kind: steps`; see [scaffold templates](/cli/commands/scaffold) for the +`kind: step` and ordered `kind: steps`; see [scaffold templates](/cli/commands/scaffold/usage) for the complete authoring model, including `--skip-hooks` and answer templating. ## Updating an Initialized Project @@ -133,6 +133,6 @@ atmos init --update --merge-strategy=theirs ## Related Commands -- [Scaffold templates](/cli/commands/scaffold) +- [Scaffold templates](/cli/commands/scaffold/usage) - [`atmos scaffold generate`](/cli/commands/scaffold/generate) - [`atmos scaffold validate`](/cli/commands/scaffold/validate) diff --git a/website/docs/cli/commands/scaffold/_category_.json b/website/docs/cli/commands/scaffold/_category_.json new file mode 100644 index 00000000000..90d66310122 --- /dev/null +++ b/website/docs/cli/commands/scaffold/_category_.json @@ -0,0 +1,10 @@ +{ + "label": "scaffold", + "className": "command", + "collapsible": true, + "collapsed": true, + "link": { + "type": "doc", + "id": "usage" + } +} diff --git a/website/docs/cli/commands/scaffold/list.mdx b/website/docs/cli/commands/scaffold/list.mdx index c954a7af19b..283566f7f6f 100644 --- a/website/docs/cli/commands/scaffold/list.mdx +++ b/website/docs/cli/commands/scaffold/list.mdx @@ -290,6 +290,6 @@ $ git commit -m "Add VPC component from scaffold" ## Learn More -- [Configuring Scaffold Templates](/cli/commands/scaffold) +- [Configuring Scaffold Templates](/cli/commands/scaffold/usage) - [atmos.yaml Configuration Reference](/cli/configuration) - [Creating Custom Templates](/cli/commands/scaffold/generate) diff --git a/website/docs/cli/commands/scaffold.mdx b/website/docs/cli/commands/scaffold/usage.mdx similarity index 99% rename from website/docs/cli/commands/scaffold.mdx rename to website/docs/cli/commands/scaffold/usage.mdx index fc02ac04217..6ffa859aeb8 100644 --- a/website/docs/cli/commands/scaffold.mdx +++ b/website/docs/cli/commands/scaffold/usage.mdx @@ -2,7 +2,6 @@ title: atmos scaffold sidebar_label: scaffold sidebar_class_name: command -id: scaffold description: Generate, validate, and update template-driven boilerplate with versioned Atmos scaffold manifests. --- diff --git a/website/docs/cli/commands/scaffold/validate.mdx b/website/docs/cli/commands/scaffold/validate.mdx index 725e9ecb86e..4cb2aed139b 100644 --- a/website/docs/cli/commands/scaffold/validate.mdx +++ b/website/docs/cli/commands/scaffold/validate.mdx @@ -141,5 +141,5 @@ atmos scaffold generate ./scaffolds/terraform-component ./test-output \ ## Related Commands - [`atmos scaffold generate`](/cli/commands/scaffold/generate) -- [Scaffold templates](/cli/commands/scaffold) +- [Scaffold templates](/cli/commands/scaffold/usage) - [Workflow step types](/workflows/steps/type) diff --git a/website/docs/cli/configuration/ai/skills.mdx b/website/docs/cli/configuration/ai/skills.mdx index 3a3b0cb767f..da60a01d814 100644 --- a/website/docs/cli/configuration/ai/skills.mdx +++ b/website/docs/cli/configuration/ai/skills.mdx @@ -8,6 +8,7 @@ import File from '@site/src/components/File' import Terminal from '@site/src/components/Terminal' import Intro from '@site/src/components/Intro' import Experimental from '@site/src/components/Experimental' +import SkillCount from '@site/src/components/SkillCount' The `ai.skills` section defines custom AI skills with specialized system prompts, tool permissions, @@ -381,7 +382,7 @@ Atmos includes 25 marketplace skills covering all aspects of infrastructure orch ## Custom Skill Examples :::tip Use Existing Skills First -Atmos ships with 25 [marketplace skills](/ai/skill-marketplace) covering Terraform, stacks, components, validation, auth, templates, and more. Check the marketplace before creating custom skills - most common use cases are already covered. Reserve custom skills for organization-specific needs that marketplace skills don't address. +Atmos ships with [official skills](/cli/commands/ai/skill) covering Terraform, stacks, components, validation, auth, templates, and more. Check the catalog before creating custom skills - most common use cases are already covered. Reserve custom skills for organization-specific needs that official skills don't address. ::: Custom skills complement marketplace skills for organization-specific needs. @@ -491,4 +492,4 @@ ai: - [AI Configuration](/cli/configuration/ai) - Configure AI providers and settings - [Claude Code Integration](/ai/claude-code-integration) - Use Atmos with Claude Code - [Tools Configuration](/cli/configuration/ai/tools) - Tool execution and permissions -- [Skill Marketplace](/ai/skill-marketplace) - Install and share community skills +- [`atmos ai skill`](/cli/commands/ai/skill) - Install and share community skills diff --git a/website/docs/projects/setup-editor/ai-assistants.mdx b/website/docs/projects/setup-editor/ai-assistants.mdx index 54bd5455d67..3ba526f8696 100644 --- a/website/docs/projects/setup-editor/ai-assistants.mdx +++ b/website/docs/projects/setup-editor/ai-assistants.mdx @@ -322,5 +322,5 @@ the right skill via its skill index table. Both mechanisms are automatic. ## Related -- [AI Agent Skills](/ai/agent-skills) -- Full list of available skills, folder structure, and SKILL.md format +- [`atmos ai skill`](/cli/commands/ai/skill) -- Browse, install, and manage agent skills; SKILL.md format - [Setup Editor (IDE)](/projects/setup-editor) -- Configure VS Code and DevContainers for Atmos diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index e7b9a6382d2..130757cb4b3 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -346,6 +346,10 @@ const config = { {from: '/cli/commands/auth', to: '/cli/commands/auth/usage'}, {from: '/cli/commands/ai', to: '/cli/commands/ai/usage'}, {from: '/cli/commands/toolchain', to: '/cli/commands/toolchain/usage'}, + {from: '/cli/commands/scaffold', to: '/cli/commands/scaffold/usage'}, + // Agent Skills docs consolidated onto the CLI command reference + {from: '/ai/agent-skills', to: '/cli/commands/ai/skill'}, + {from: '/ai/skill-marketplace', to: '/cli/commands/ai/skill'}, // Terraform source command reorganization {from: '/cli/commands/terraform/terraform-source', to: '/cli/commands/terraform/source'}, {from: '/cli/commands/terraform/terraform-source-pull', to: '/cli/commands/terraform/source/pull'}, @@ -529,6 +533,8 @@ const config = { enableCopyMarkdown: true, enablePerPageMarkdown: true, titleAsCode: true, + installCommandLabel: 'Use this skill', + installCommandTemplate: 'atmos ai skill install {name}', }, ], ], diff --git a/website/plugins/file-browser/index.js b/website/plugins/file-browser/index.js index 0f8326c228d..cda5b778ed2 100644 --- a/website/plugins/file-browser/index.js +++ b/website/plugins/file-browser/index.js @@ -823,6 +823,12 @@ module.exports = function fileBrowserPlugin(context, options) { // instead of plain text, signaling how it's invoked. Defaults to false — // examples/gists have friendly English titles this wouldn't suit. titleAsCode = false, + // Label and command template for a per-item install command box, rendered at + // the top of each item's root page (e.g. "Use this skill" / "atmos ai skill + // install {name}"). `{name}` is replaced with the item's directory name. + // Default to '' so existing instances render unchanged unless opted in. + installCommandLabel = '', + installCommandTemplate = '', } = options; const mergedExcludePatterns = [...DEFAULT_EXCLUDE_PATTERNS, ...excludePatterns]; @@ -865,6 +871,8 @@ module.exports = function fileBrowserPlugin(context, options) { cardCtaLabel, enableCopyMarkdown, titleAsCode, + installCommandLabel, + installCommandTemplate, }, }; }, diff --git a/website/sidebars.js b/website/sidebars.js index 8f16d22162b..80f3c81fc0f 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -208,18 +208,10 @@ module.exports = { label: 'Atmos AI', link: {type: 'doc', id: 'ai/ai'}, items: [ - { - type: 'category', - label: 'Skills', - link: {type: 'doc', id: 'ai/agent-skills'}, - items: [ - {type: 'doc', id: 'ai/skill-marketplace', label: 'Skill Marketplace'}, - {type: 'link', label: 'Browse the Skills Directory', href: '/ai/skills'}, - ] - }, + {type: 'link', label: 'Agent Skills', href: '/ai/skills'}, + {type: 'doc', id: 'mcp/mcp', label: 'MCP'}, ] }, - {type: 'doc', id: 'mcp/mcp', label: 'MCP'}, {type: 'doc', id: 'pro/pro', label: 'Atmos Pro'}, { type: 'category', diff --git a/website/src/components/CommandBox/index.css b/website/src/components/CommandBox/index.css new file mode 100644 index 00000000000..2d5dc122c10 --- /dev/null +++ b/website/src/components/CommandBox/index.css @@ -0,0 +1,110 @@ +.command-box { + margin: 1.5rem 0; +} + +.command-box__content { + display: flex; + align-items: center; + gap: 0; + max-width: 100%; + background: #1a1d23; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + padding: 0; + overflow: hidden; +} + +html[data-theme='light'] .command-box__content { + background: #2d3748; + border-color: rgba(0, 0, 0, 0.15); +} + +.command-box__label-wrapper { + display: flex; + align-items: center; + padding: 0.9rem 1.25rem; + border-right: 1px solid rgba(255, 255, 255, 0.1); +} + +html[data-theme='light'] .command-box__label-wrapper { + border-right-color: rgba(0, 0, 0, 0.15); +} + +.command-box__label { + font-size: 0.95rem; + color: rgba(255, 255, 255, 0.7); + font-weight: 400; + white-space: nowrap; +} + +html[data-theme='light'] .command-box__label { + color: rgba(255, 255, 255, 0.8); +} + +.command-box__command { + display: flex; + align-items: center; + flex: 1; + min-width: 0; + padding: 1.1rem 1.5rem; +} + +.command-box__code { + font-family: 'Monaco', 'Menlo', 'Courier New', monospace; + font-size: 0.9rem; + color: #fff; + flex: 1; + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + min-width: 0; +} + +.command-box__copy { + background: transparent; + border: none; + border-left: 1px solid rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.4); + cursor: pointer; + padding: 0.9rem 1.25rem; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + flex-shrink: 0; +} + +html[data-theme='light'] .command-box__copy { + border-left-color: rgba(0, 0, 0, 0.15); + color: rgba(255, 255, 255, 0.5); +} + +.command-box__copy:hover { + color: #fff; + background: rgba(255, 255, 255, 0.05); +} + +@media screen and (max-width: 768px) { + .command-box__content { + flex-direction: column; + align-items: stretch; + } + + .command-box__label-wrapper { + border-right: none; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + } + + html[data-theme='light'] .command-box__label-wrapper { + border-bottom-color: rgba(0, 0, 0, 0.15); + } + + .command-box__command { + width: 100%; + } + + .command-box__code { + font-size: 0.85rem; + } +} diff --git a/website/src/components/CommandBox/index.tsx b/website/src/components/CommandBox/index.tsx new file mode 100644 index 00000000000..5e6e2e95fa9 --- /dev/null +++ b/website/src/components/CommandBox/index.tsx @@ -0,0 +1,46 @@ +import React, { useState } from 'react'; +import './index.css'; + +interface CommandBoxProps { + label: string; + command: string; +} + +export default function CommandBox({ label, command }: CommandBoxProps) { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + await navigator.clipboard.writeText(command); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( +
+
+
+ {label} +
+
+ {command} +
+ +
+
+ ); +} diff --git a/website/src/components/FileBrowser/DirectoryPage.tsx b/website/src/components/FileBrowser/DirectoryPage.tsx index 2eca176ecc3..d8922aaf438 100644 --- a/website/src/components/FileBrowser/DirectoryPage.tsx +++ b/website/src/components/FileBrowser/DirectoryPage.tsx @@ -12,6 +12,7 @@ import CopyMarkdownButton from './CopyMarkdownButton'; import { findExampleByName, getExampleNameFromPath } from './utils'; import GistDisclaimer from '@site/src/components/GistDisclaimer'; import CastPlayer from '@site/src/components/CastPlayer'; +import CommandBox from '@site/src/components/CommandBox'; import type { ExamplesTree, FileBrowserOptions, DirectoryNode } from './types'; import styles from './styles.module.css'; @@ -50,6 +51,7 @@ export default function DirectoryPage({ const isExampleRoot = dirData.path === exampleName; const showCast = isExampleRoot && !!example.cast?.file; const showCopyMarkdown = isExampleRoot && !!optionsData.enableCopyMarkdown; + const showInstallCommand = isExampleRoot && !!optionsData.installCommandTemplate; return ( @@ -76,6 +78,13 @@ export default function DirectoryPage({ )} + {showInstallCommand && ( + + )} + {showCast && (
` works fully offline (no network or Git clone). `atmos ai skill list` shows a merged available-vs-installed view with status markers, plus `--installed` and `--detailed` flags.', codeExample: 'atmos ai skill install atmos-terraform', benefits: 'Install official skills anywhere — locked-down CI runners and air-gapped environments included. The catalog always matches the running binary.' }, { label: 'Browsable, searchable Agent Skills Directory', status: 'shipped', quarter: 'q3-2026', changelog: 'agent-skills-directory', docs: '/ai/skills', description: 'A generated directory at /ai/skills replaces the hand-maintained skill list, with a detail page per skill, category grouping, and a search box. `atmos ai skill list` gained a `--format` flag (table/json/yaml/csv/tsv) and a Category column.', codeExample: 'atmos ai skill list --format=json', benefits: 'The skill list can never drift out of date again — new skills appear automatically. Skills are discoverable by category and free-text search instead of one long page.' }, From a95d69a47494ccb7eb5917da12f9af9fbe05053b Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 6 Aug 2026 16:29:05 -0500 Subject: [PATCH 14/24] fix(website): correct EditorConfig indentation in scaffold blog post CI's EditorConfig validation requires left-padding in multiples of 2; these list items under a numbered entry used 3 spaces. Co-Authored-By: Claude Sonnet 5 --- .../blog/2025-10-20-introducing-atmos-init-and-scaffold.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md b/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md index 7b5c568094e..03c308a9a63 100644 --- a/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md +++ b/website/blog/2025-10-20-introducing-atmos-init-and-scaffold.md @@ -255,9 +255,9 @@ These commands represent significant architectural improvements: 1. **Command Registry Pattern**: Both commands use the new command registry pattern, making them independently testable and maintainable 2. **Shared Core Packages**: - - `pkg/init/ui` - Interactive UI components and prompts - - `pkg/scaffold/templating` - Template processing engine - - `pkg/init/config` - Scaffold configuration parsing + - `pkg/init/ui` - Interactive UI components and prompts + - `pkg/scaffold/templating` - Template processing engine + - `pkg/init/config` - Scaffold configuration parsing 3. **Embedded Templates**: Built-in templates are embedded in the Atmos binary, ensuring version compatibility and eliminating external dependencies From e4726a808b019a4e96e7e4b6bb786659d744231f Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 6 Aug 2026 16:29:24 -0500 Subject: [PATCH 15/24] fix(website): collapse multi-line PrimaryCTA/SecondaryCTA to single line MDX wraps a JSX component's text in a

when it sits on its own line inside a block-level context, which overrides the button's centered white/bold styling with muted paragraph styling. Single-line usage (the pattern already used on working pages like auth/usage.mdx) keeps the label as plain inline text. Co-Authored-By: Claude Sonnet 5 --- website/docs/cli/commands/helm/usage.mdx | 4 +--- website/docs/cli/commands/kubernetes/kubernetes-apply.mdx | 8 ++------ .../docs/cli/commands/kubernetes/kubernetes-delete.mdx | 4 +--- .../docs/cli/commands/kubernetes/kubernetes-deploy.mdx | 8 ++------ website/docs/cli/commands/kubernetes/kubernetes-diff.mdx | 4 +--- website/docs/cli/commands/kubernetes/kubernetes-plan.mdx | 4 +--- .../docs/cli/commands/kubernetes/kubernetes-render.mdx | 4 +--- .../docs/cli/commands/kubernetes/kubernetes-validate.mdx | 4 +--- website/docs/cli/commands/kubernetes/usage.mdx | 8 ++------ website/docs/learn/why-atmos.mdx | 4 +--- website/docs/quick-start/introduction.mdx | 8 ++------ 11 files changed, 15 insertions(+), 45 deletions(-) diff --git a/website/docs/cli/commands/helm/usage.mdx b/website/docs/cli/commands/helm/usage.mdx index fb6aecc26cd..a9baa537945 100644 --- a/website/docs/cli/commands/helm/usage.mdx +++ b/website/docs/cli/commands/helm/usage.mdx @@ -25,9 +25,7 @@ import Experimental from "@site/src/components/Experimental"; stack should deploy with `chart`, `version`, `repositories`, `values`, `values_files`, `namespace`, `env`, hooks, and dependencies.

- - Stack Configuration - + Stack Configuration
diff --git a/website/docs/cli/commands/kubernetes/kubernetes-apply.mdx b/website/docs/cli/commands/kubernetes/kubernetes-apply.mdx index 41fa22294ed..e103aadd522 100644 --- a/website/docs/cli/commands/kubernetes/kubernetes-apply.mdx +++ b/website/docs/cli/commands/kubernetes/kubernetes-apply.mdx @@ -24,12 +24,8 @@ import CastPlayer from '@site/src/components/CastPlayer' credentials or hooks should run from the Kubernetes component stack configuration.
- - Stack Configuration - - - atmos.yaml Configuration - + Stack Configuration + atmos.yaml Configuration
diff --git a/website/docs/cli/commands/kubernetes/kubernetes-delete.mdx b/website/docs/cli/commands/kubernetes/kubernetes-delete.mdx index eac9903ab74..1a7a90056b1 100644 --- a/website/docs/cli/commands/kubernetes/kubernetes-delete.mdx +++ b/website/docs/cli/commands/kubernetes/kubernetes-delete.mdx @@ -23,9 +23,7 @@ import CastPlayer from '@site/src/components/CastPlayer' Keep the desired objects in stack configuration, then use `delete` when a component should be removed from an environment.
- - Stack Configuration - + Stack Configuration
diff --git a/website/docs/cli/commands/kubernetes/kubernetes-deploy.mdx b/website/docs/cli/commands/kubernetes/kubernetes-deploy.mdx index d60b1d51bff..b2732983dcb 100644 --- a/website/docs/cli/commands/kubernetes/kubernetes-deploy.mdx +++ b/website/docs/cli/commands/kubernetes/kubernetes-deploy.mdx @@ -24,12 +24,8 @@ import CastPlayer from '@site/src/components/CastPlayer' `deploy` uses the same stack and `atmos.yaml` settings as `apply`, including manifest paths, variables, credentials, hooks, and dependency ordering.
- - Stack Configuration - - - atmos.yaml Configuration - + Stack Configuration + atmos.yaml Configuration
diff --git a/website/docs/cli/commands/kubernetes/kubernetes-diff.mdx b/website/docs/cli/commands/kubernetes/kubernetes-diff.mdx index 08fcbb968f0..95e48b24280 100644 --- a/website/docs/cli/commands/kubernetes/kubernetes-diff.mdx +++ b/website/docs/cli/commands/kubernetes/kubernetes-diff.mdx @@ -23,9 +23,7 @@ import CastPlayer from '@site/src/components/CastPlayer' `diff` uses the same stack inputs as deployment: `provider`, `paths`, `manifests`, `vars`, `env`, Auth, hooks, and dependencies.
- - Stack Configuration - + Stack Configuration
diff --git a/website/docs/cli/commands/kubernetes/kubernetes-plan.mdx b/website/docs/cli/commands/kubernetes/kubernetes-plan.mdx index 316e57a5c63..358ce1356fa 100644 --- a/website/docs/cli/commands/kubernetes/kubernetes-plan.mdx +++ b/website/docs/cli/commands/kubernetes/kubernetes-plan.mdx @@ -19,9 +19,7 @@ import PrimaryCTA from "@site/src/components/PrimaryCTA"; `plan` uses the same Kubernetes component stack configuration as `diff`: manifest inputs, rendered values, Auth, hooks, and dependencies.
- - Stack Configuration - + Stack Configuration
diff --git a/website/docs/cli/commands/kubernetes/kubernetes-render.mdx b/website/docs/cli/commands/kubernetes/kubernetes-render.mdx index 12e82e5f4b2..9d8e0c3f749 100644 --- a/website/docs/cli/commands/kubernetes/kubernetes-render.mdx +++ b/website/docs/cli/commands/kubernetes/kubernetes-render.mdx @@ -24,9 +24,7 @@ import CastPlayer from '@site/src/components/CastPlayer' Put manifest files, Kustomize paths, inline objects, variables, environment, and default output paths in the Kubernetes component stack configuration.
- - Stack Configuration - + Stack Configuration
diff --git a/website/docs/cli/commands/kubernetes/kubernetes-validate.mdx b/website/docs/cli/commands/kubernetes/kubernetes-validate.mdx index 5267da637b7..95eb5fa3ef0 100644 --- a/website/docs/cli/commands/kubernetes/kubernetes-validate.mdx +++ b/website/docs/cli/commands/kubernetes/kubernetes-validate.mdx @@ -26,9 +26,7 @@ import CastPlayer from '@site/src/components/CastPlayer' `provider`, `paths`, `manifests`, `vars`, `env`, Auth, hooks, and dependencies.
- - Stack Configuration - + Stack Configuration
diff --git a/website/docs/cli/commands/kubernetes/usage.mdx b/website/docs/cli/commands/kubernetes/usage.mdx index df95edc3d0a..359874d3f6b 100644 --- a/website/docs/cli/commands/kubernetes/usage.mdx +++ b/website/docs/cli/commands/kubernetes/usage.mdx @@ -22,12 +22,8 @@ import PrimaryCTA from "@site/src/components/PrimaryCTA"; stack should deploy with `provider`, `paths`, `manifests`, `vars`, `env`, hooks, and dependencies.
- - atmos.yaml Configuration - - - Stack Configuration - + atmos.yaml Configuration + Stack Configuration
diff --git a/website/docs/learn/why-atmos.mdx b/website/docs/learn/why-atmos.mdx index dc9f8660d2c..aa362f3e316 100644 --- a/website/docs/learn/why-atmos.mdx +++ b/website/docs/learn/why-atmos.mdx @@ -67,9 +67,7 @@ Most Terraform teams progress through 10+ stages of maturity—from ClickOps to **Atmos helps you skip these growing pains** by providing battle-tested solutions for every stage. - - See the Terraform Maturity Journey - +See the Terraform Maturity Journey ## Next Steps diff --git a/website/docs/quick-start/introduction.mdx b/website/docs/quick-start/introduction.mdx index db62fd59646..69e8b764217 100644 --- a/website/docs/quick-start/introduction.mdx +++ b/website/docs/quick-start/introduction.mdx @@ -26,13 +26,9 @@ In many cases, with enterprise-grade infrastructures (multi-org, multi-tenant, m In this Quick Start guide, we describe how to provision infrastructure managed by Terraform into different AWS environments. Atmos manages the configurations for the environments. - - Try our Simple Tutorial - +Try our Simple Tutorial - - Try our Advanced Tutorial - +Try our Advanced Tutorial ## Explore an Example Project From 571652468e44658cb0b5e4164e616728e9b4837d Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 6 Aug 2026 16:55:17 -0500 Subject: [PATCH 16/24] docs(ci): clarify actions/checkout + atmos is only a baseline setup The intro note and workflow overview implied actions/checkout plus an atmos command was universally sufficient. Status checks, check runs, PR comments, OIDC, SBOM uploads, and github/artifacts planfile storage need additional permissions or the github-runtime action, already documented in the Permissions section below - cross-reference it instead of overclaiming. Co-Authored-By: Claude Sonnet 5 --- website/docs/ci/ci.mdx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/website/docs/ci/ci.mdx b/website/docs/ci/ci.mdx index 1b00e6750a8..3b08e906c66 100644 --- a/website/docs/ci/ci.mdx +++ b/website/docs/ci/ci.mdx @@ -31,8 +31,11 @@ anymore. The `atmos` CLI now does this work: - It sets output variables. - It manages planfiles. -Do not use the old Actions in new workflows. Existing workflows that use them still work. New -workflows need only `actions/checkout` and an `atmos` command, as shown below. +Do not use the old Actions in new workflows. Existing workflows that use them still work. `actions/checkout` +plus an `atmos` command is the minimum for a basic workflow (job summaries, output variables) — it is not +universally sufficient. Status checks, check runs, PR comments, and OIDC need matching permissions, and SBOM +uploads and `github/artifacts` planfile storage also need the `github-runtime` action. See +[Permissions](#permissions) below. ::: @@ -80,7 +83,7 @@ ci: ## GitHub Actions Workflows -Running Atmos in GitHub Actions reduces to two steps: **check out the repository, then run an `atmos` command.** Atmos detects the CI environment automatically and produces job summaries, output variables, status checks, and stored planfiles without any wrapper actions. +Running Atmos in GitHub Actions reduces to two steps for the basics: **check out the repository, then run an `atmos` command.** Atmos detects the CI environment automatically and produces job summaries and output variables with no extra setup. Status checks, check runs, and PR comments need matching [permissions](#permissions); SBOM uploads and planfile storage in `github/artifacts` also need the `github-runtime` action. Terraform commands use the full native CI feature set. Kubernetes commands currently emit human-readable job summaries only; they do not write `$GITHUB_OUTPUT` values, commit statuses, From a524be1ee9aa4f8baa1239554815a95a55797acc Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 6 Aug 2026 16:55:26 -0500 Subject: [PATCH 17/24] fix(ai): keep copy confirmation visible for its full duration Repeated clicks scheduled overlapping setTimeout calls to reset the "Copied!" state; an earlier click's timeout could fire and hide the confirmation before the latest click's 2s window elapsed. Track the timeout in a ref, clear it before scheduling a new one, and clean it up on unmount. Co-Authored-By: Claude Sonnet 5 --- website/src/components/FileBrowser/CopyMarkdownButton.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/website/src/components/FileBrowser/CopyMarkdownButton.tsx b/website/src/components/FileBrowser/CopyMarkdownButton.tsx index cbc894153bd..60528cdb78f 100644 --- a/website/src/components/FileBrowser/CopyMarkdownButton.tsx +++ b/website/src/components/FileBrowser/CopyMarkdownButton.tsx @@ -3,7 +3,7 @@ * included, to the clipboard as one Markdown document. Lets someone grab a * skill's complete context without installing it. */ -import React, { useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCopy, faCheck } from '@fortawesome/free-solid-svg-icons'; import { collectMarkdownContext } from './utils'; @@ -29,6 +29,9 @@ export default function CopyMarkdownButton({ className, }: CopyMarkdownButtonProps): JSX.Element { const [copied, setCopied] = useState(false); + const resetTimeoutRef = useRef>(); + + useEffect(() => () => clearTimeout(resetTimeoutRef.current), []); const handleCopy = async (event: React.MouseEvent) => { // Cards this button sits on may be clickable themselves - never let the @@ -42,7 +45,8 @@ export default function CopyMarkdownButton({ try { await navigator.clipboard.writeText(markdown); setCopied(true); - setTimeout(() => setCopied(false), 2000); + clearTimeout(resetTimeoutRef.current); + resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000); } catch { // Clipboard API unavailable (e.g. insecure context) - button just won't confirm. } From 18824b9f0d65cd8a26cc2a71aa99852044cd0b01 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 6 Aug 2026 19:31:51 -0500 Subject: [PATCH 18/24] docs(blog): fix inaccurate claim and rewrite agent-skills-directory post The post claimed atmos ai skill list was a hand-maintained doc that drifted out of sync with the real catalog. It never was -- the listing is generated at runtime from the embedded skill catalog. The actual gap was the missing full-content browse/search/copy/fetch experience, which is what the post now leads with. Also rewritten in short, active, single-idea sentences (ASD-STE100 style). Co-Authored-By: Claude Sonnet 5 --- .../2026-08-05-agent-skills-directory.mdx | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/website/blog/2026-08-05-agent-skills-directory.mdx b/website/blog/2026-08-05-agent-skills-directory.mdx index 6e88f122c4d..a4be0e65871 100644 --- a/website/blog/2026-08-05-agent-skills-directory.mdx +++ b/website/blog/2026-08-05-agent-skills-directory.mdx @@ -1,39 +1,51 @@ --- slug: agent-skills-directory -title: "Browse Every Atmos Agent Skill, Always Up to Date" +title: "Browse, Search, and Copy Any Atmos Agent Skill Before You Install It" authors: [osterman] tags: [feature, dx] --- -A hand-maintained list is only accurate on the day someone writes it. Add a new item to the underlying -system and forget to update the doc -- which happens constantly once a catalog is large enough to have -real momentum -- and the list quietly falls behind. Readers trust it anyway, because nothing on the page -signals that it's stale. +Before you install a skill, you want to read what it does. Atmos agent skills did not let you do that. You +had to install a skill first to read its full instructions. Or you had to find its file in the Atmos +repository on GitHub. An AI agent had the same problem. No page listed every skill with its full content. No +single URL let an agent fetch a skill's content on its own. ## The Problem -Atmos's own [agent skills](/cli/commands/ai/skill) documentation had exactly this problem. The page hand-listed -each skill in a static table, and as new skills shipped, the list wasn't updated to match -- it drifted to -roughly half the real count, with a couple of stale entries pointing at skills that no longer existed. There -was also no way to search or filter -- just one long page to scroll and skim. +The [`atmos ai skill list`](/cli/commands/ai/skill) command already listed every official skill, showing +each skill's name, source, and install status. Add `--detailed`, and it also showed a one-line description. +But no view showed a skill's full instructions -- the actual content that teaches the AI its domain +knowledge. + +To read that content, you had two options. Install the skill first. Or open the Atmos repository on GitHub +and find the right `SKILL.md` file. Neither option let you compare skills quickly. Neither option gave an AI +agent a direct way to fetch and read a skill's content on its own. ## The Fix -The [Agent Skills Directory](/ai/skills) replaces that static list with a page generated directly from the -skills themselves. Every skill gets its own detail page rendering its full instructions, skills are grouped -into categories, and a search box filters by name, description, or category. Add a skill, and it appears in -the directory automatically -- there's no separate doc to remember to update. +The [Agent Skills Directory](/ai/skills) lists every skill with its full content. Open the directory. Search +by name, description, or category. Click a skill to read its complete instructions -- no install step +required. Add a new skill to the Atmos repository, and it appears in the directory automatically. + +Each skill's page also has a raw Markdown version. Add `.md` to the page's URL. This is the same convention +the rest of the Atmos docs site uses. An AI agent can fetch this URL directly and read the skill's content. -`atmos ai skill list` also gained a `--format` flag and now shows each skill's category, so the same -categorization is available from the CLI, not just the website. +Each skill's page also has a "Copy as Markdown" button. Use it to copy the skill's full content. Paste it +into a chat session, or review it, before you install anything. + +The `atmos ai skill list` command also gained a `--format` flag and a Category column, so the same +categorization shown in the directory is available from the CLI. ## How to Use It -Browse and search the directory at [atmos.tools/ai/skills](/ai/skills), or from the CLI: +Browse and search the directory at [atmos.tools/ai/skills](/ai/skills). Or fetch a skill's content directly: ```shell +# Raw Markdown for one skill - readable by a human, fetchable by an agent +curl https://atmos.tools/ai/skills/.md + # Table view, now with a Category column atmos ai skill list @@ -44,5 +56,6 @@ atmos ai skill list --format=yaml ## Get Involved -See the [Agent Skills](/cli/commands/ai/skill) guide for how skills are structured and how to contribute one. Skill -ideas and contributions are welcome in the [Atmos community](https://github.com/cloudposse/atmos). +See the [Agent Skills](/cli/commands/ai/skill) guide to learn how skills are structured. It also explains +how to contribute one. Share skill ideas and contributions in the +[Atmos community](https://github.com/cloudposse/atmos). From 229be5da26bcd6696cd14581ed74a8fca8500b94 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Fri, 7 Aug 2026 08:26:42 -0500 Subject: [PATCH 19/24] ci: give the acceptance-test job real timeout headroom on Linux timeout-minutes: 90 matched Linux's timed-step sum exactly (25m registry cache + 60m coverage tests + 5m coverage upload), leaving zero slack for checkout, Go/Atmos setup, and toolchain installs before the job gets force-cancelled. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/test.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 700b71f280d..3eb6191f5b5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -180,14 +180,16 @@ jobs: - { os: "ubuntu-latest", target: linux } - { os: "windows-latest", target: windows } - { os: "macos-15", target: macos } - # windows-latest's steps individually stay within their own budgets (the - # "Acceptance tests" step has a 60m budget below) but their sum leaves the - # job-level timeout almost no slack - a run that hit exactly 75.0 minutes - # was force-cancelled by this ceiling with every step, including the full - # go test suite, already completed successfully in the logs. Same - # variance documented on the "Acceptance tests" step's own timeout below; - # give the job-level ceiling real headroom too. - timeout-minutes: 90 + # Linux is the tightest target: its timed steps alone (registry cache test 25m + + # coverage-enabled acceptance tests 60m + coverage upload 5m) already sum to 90m, + # before checkout, Go/Atmos setup, and toolchain installs. windows-latest and + # macos-15 sum to 85m (registry cache test 25m + acceptance tests 60m) for the + # same reason - a run that hit exactly 75.0 minutes was force-cancelled by the + # previous ceiling with every step, including the full go test suite, already + # completed successfully in the logs. Same variance documented on the + # "Acceptance tests" step's own timeout below; give the job-level ceiling real + # headroom above the step-budget sum, not just equal to it. + timeout-minutes: 120 runs-on: ${{ matrix.flavor.os }} steps: - name: Check out code into the Go module directory From a1e541190a9a002df0bd886c363d4521ec4ae3f2 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Fri, 7 Aug 2026 08:27:04 -0500 Subject: [PATCH 20/24] docs(blog): use a shell-safe curl example in the skills directory post The unquoted placeholder is parsed as shell redirection syntax, so a reader who copies the command as written fails before curl runs. Co-Authored-By: Claude Sonnet 5 --- website/blog/2026-08-05-agent-skills-directory.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/blog/2026-08-05-agent-skills-directory.mdx b/website/blog/2026-08-05-agent-skills-directory.mdx index a4be0e65871..ee4ae695fa2 100644 --- a/website/blog/2026-08-05-agent-skills-directory.mdx +++ b/website/blog/2026-08-05-agent-skills-directory.mdx @@ -44,7 +44,8 @@ Browse and search the directory at [atmos.tools/ai/skills](/ai/skills). Or fetch ```shell # Raw Markdown for one skill - readable by a human, fetchable by an agent -curl https://atmos.tools/ai/skills/.md +skill_name=atmos-ai +curl "https://atmos.tools/ai/skills/${skill_name}.md" # Table view, now with a Category column atmos ai skill list From 2686bc0225f839bb4e6485e132fbc48074ee7307 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Fri, 7 Aug 2026 08:27:33 -0500 Subject: [PATCH 21/24] fix(website): remove invalid font-family quotes in CommandBox Stylelint's font-family-name-quotes rule rejects quotes on single- word font names like Monaco and Menlo; Courier New keeps its quotes since it contains a space. Co-Authored-By: Claude Sonnet 5 --- website/src/components/CommandBox/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/components/CommandBox/index.css b/website/src/components/CommandBox/index.css index 2d5dc122c10..2c251549d4d 100644 --- a/website/src/components/CommandBox/index.css +++ b/website/src/components/CommandBox/index.css @@ -50,7 +50,7 @@ html[data-theme='light'] .command-box__label { } .command-box__code { - font-family: 'Monaco', 'Menlo', 'Courier New', monospace; + font-family: Monaco, Menlo, 'Courier New', monospace; font-size: 0.9rem; color: #fff; flex: 1; From 10c842b6ce0eebaea4bb5efa7e4401d6bfd5d840 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Fri, 7 Aug 2026 08:27:54 -0500 Subject: [PATCH 22/24] fix(website): handle clipboard write failures in CommandBox navigator.clipboard.writeText can reject when the browser denies clipboard access, and the rejection was left unhandled. Catch it and surface a "Copy failed" state instead of letting the click silently do nothing. Co-Authored-By: Claude Sonnet 5 --- website/src/components/CommandBox/index.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/website/src/components/CommandBox/index.tsx b/website/src/components/CommandBox/index.tsx index 5e6e2e95fa9..42960afb9e9 100644 --- a/website/src/components/CommandBox/index.tsx +++ b/website/src/components/CommandBox/index.tsx @@ -8,11 +8,17 @@ interface CommandBoxProps { export default function CommandBox({ label, command }: CommandBoxProps) { const [copied, setCopied] = useState(false); + const [failed, setFailed] = useState(false); const handleCopy = async () => { - await navigator.clipboard.writeText(command); - setCopied(true); - setTimeout(() => setCopied(false), 2000); + try { + await navigator.clipboard.writeText(command); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch { + setFailed(true); + setTimeout(() => setFailed(false), 2000); + } }; return ( @@ -27,7 +33,7 @@ export default function CommandBox({ label, command }: CommandBoxProps) {