Skip to content

feat: support dotenv files in !include - #1930

Merged
Andriy Knysh (aknysh) merged 9 commits into
mainfrom
feature/dev-2990-add-support-for-env-files
Jun 14, 2026
Merged

Andriy Knysh (aknysh) merged 9 commits into
mainfrom
feature/dev-2990-add-support-for-env-files

Conversation

@osterman

@osterman Erik Osterman (Cloud Posse) (osterman) commented Jan 4, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds explicit dotenv file support to the existing !include YAML function. Dotenv files now resolve to maps, so they can be used directly in CLI and stack env sections and with YAML merge keys.

env:
  <<: !include .env
  AWS_REGION: us-east-2

Dotenv files can also be layered with YAML merge sequences. This uses YAML's << merge-key syntax, the same YAML mechanism commonly used with anchors and aliases:

env:
  <<:
    - !include .env.local
    - !include .env
  AWS_REGION: us-east-2

YAML merge sequence precedence is earlier item wins, and inline keys under env override all merged values.

What Changed

  • Parse .env, .env.*, and exact *.env filenames as dotenv files when used with !include
  • Support env: !include .env and env: { <<: !include .env } / block merge forms in stack config
  • Support dotenv !include in atmos.yaml env, including merge sequences for layered dotenv files
  • Preserve !include.raw behavior for raw file contents
  • Keep .envrc and foo.env.local unsupported/raw; Atmos does not auto-load or execute dotenv files
  • Preserve YAML custom tags during schema validation so env: !include .env satisfies stack manifest schema rules
  • Update the stack manifest JSON schema description for env to document the !include string form
  • Document dotenv includes in both CLI env and stack env docs, including YAML merge-key behavior, include path resolution, and layered files
  • Add a short blog post for explicit dotenv inclusion
  • Add a roadmap milestone entry for the shipped dotenv !include support
  • Add coverage-focused tests for dotenv merge-key retry handling, include path helpers, case-preservation helpers, and YAML custom-tag conversion
  • Harden the LocalStack demo provider config to use the local edge endpoint directly, path-style S3, and skip AWS account-ID discovery so Terraform does not hang before reaching LocalStack in CI

Tests

  • cd examples/demo-localstack && ATMOS_IDENTITY=false go run ../.. describe component demo -s dev --format json --logs-level Off | jq '.providers.aws'
  • cd examples/demo-localstack && ATMOS_IDENTITY=false go run ../.. validate stacks --logs-level Off
  • go test ./pkg/config ./pkg/validator ./pkg/filetype
  • go test ./internal/exec -run 'TestGenerateProviderOverrides|TestGenerateProviderOverridesForAliases|TestProcessStackConfigProviderSection'
  • go test ./pkg/config ./pkg/validator -coverprofile=.context/dotenv-include-coverage.out
  • go test ./pkg/utils -run 'TestInclude(Dotenv|ExtensionBased|RawFunction|WithNoExtension)'
  • node -e "import('./website/src/data/roadmap.js').then(() => console.log('roadmap import ok'))"
  • git diff --check
  • Real stack manifest schema regression: env: !include .env validates against tests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
  • Commit hooks passed: go-fumpt, Go build, go mod tidy, golangci-lint, whitespace/EOF/large-file checks

Closes DEV-2990

@github-actions github-actions Bot added the size/l Large size PR label Jan 4, 2026
@github-actions

github-actions Bot commented Jan 4, 2026 •

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Jan 4, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds structured env configuration and .env file support: new pkg/env loader, early .env injection during config load, EnvConfig schema (vars + files), and propagates case-sensitive env merging and per-directory .env merging into shell/terraform execution paths.

Changes

Cohort / File(s) Summary
Env file utilities
pkg/env/file.go, pkg/env/file_test.go
New package to discover, load, parse, and merge .env files (glob patterns, parent traversal, deterministic ordering) plus merge helpers and comprehensive tests.
Configuration schema
pkg/schema/schema.go, pkg/schema/schema_test.go
Replaced AtmosConfiguration.Env with EnvConfig (Vars + Files), added EnvFilesConfig, and GetCaseSensitiveEnvVars() accessor to return case-preserving vars.
Config loading
pkg/config/load.go
Added early .env file loading (loadEnvFilesEarly) and parseEnvConfig to support structured (vars+files) and legacy flat env forms; injects loaded vars into process env before profile detection.
Shell execution / exec helpers
internal/exec/shell_utils.go, internal/exec/shell_utils_test.go, internal/exec/stack_processor_process_stacks.go, internal/exec/workflow_utils.go, internal/exec/workflow_adapters.go
Threaded atmosConfig into ExecuteShell, switched env merges to GetCaseSensitiveEnvVars(), and integrated per-directory .env loading/merging into shell and Terraform execution flows; tests updated to pass nil where appropriate.
CLI wiring
cmd/cmd_utils.go, cmd/auth_exec.go
Updated calls to new ExecuteShell signature to pass atmosConfig (or nil).
Terraform env check
internal/exec/terraform.go
Replaced direct atmosConfig.Env access with GetCaseSensitiveEnvVars() for TF_PLUGIN_CACHE_DIR lookup.
Dependency
go.mod
Promoted github.com/joho/godotenv v1.5.1 to a direct dependency.
Examples & docs
examples/dotenv/*, website/blog/2025-01-15-dotenv-file-support.mdx, website/docs/cli/configuration/env.mdx, website/plugins/file-browser/index.js, website/src/data/roadmap.js
Added dotenv example files and README, example atmos.yaml, docs and blog post describing .env support, and UI/file-browser mappings.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User
    participant ConfigLoader as Config Loader
    participant EnvLoader as Env File Loader
    participant ShellExec as Shell Executor
    participant OS as OS Process

    User->>ConfigLoader: Load atmos.yaml
    ConfigLoader->>EnvLoader: loadEnvFilesEarly(env.files)
    EnvLoader->>OS: Inject global .env vars into process env
    ConfigLoader->>ConfigLoader: parseEnvConfig -> AtmosConfiguration.Env (EnvConfig)

    User->>ShellExec: Run command (workflow/component)
    ShellExec->>EnvLoader: LoadFromDirectory(component dir, patterns, parents)
    EnvLoader->>ShellExec: Return merged component .env vars + file list
    ShellExec->>ShellExec: Merge OS env + global env (GetCaseSensitiveEnvVars) + component env
    ShellExec->>OS: Execute command with final environment
    OS-->>User: Command output
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • aknysh
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 73.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title 'feat: support dotenv files in !include' does not accurately reflect the main change, which is comprehensive .env file loading support across Atmos—not specifically about !include syntax. Revise the title to better reflect the primary change, such as 'feat: add .env file loading support' or 'feat: support loading environment variables from .env files'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/dev-2990-add-support-for-env-files

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (7)
pkg/env/file.go (2)

104-108: Consider removing redundant perf tracking.

MapToSlice delegates to ConvertMapToSlice, which already has its own perf.Track. This creates double tracking overhead for the same operation.

🔎 Proposed fix
 func MapToSlice(m map[string]string) []string {
-	defer perf.Track(nil, "env.MapToSlice")()
-
 	return ConvertMapToSlice(m)
 }

120-126: Silent skip of invalid glob patterns may hide configuration issues.

When a pattern has invalid syntax (e.g., [invalid), it's silently skipped. Users won't know their pattern is malformed. Consider logging a warning.

🔎 Proposed enhancement
 for _, pattern := range patterns {
 	fullPattern := filepath.Join(dir, pattern)
 	matches, err := filepath.Glob(fullPattern)
 	if err != nil {
-		// Invalid pattern - skip it but don't fail.
+		// Invalid pattern syntax - log warning but don't fail.
+		log.Debug("Invalid glob pattern", "pattern", pattern, "error", err)
 		continue
 	}

This would require importing the log package.

pkg/schema/schema_test.go (1)

145-186: GetCaseSensitiveMap tests align with new EnvConfig semantics

The new subtests exercise EnvConfig.Vars both with and without CaseMaps and cover the nil Vars case; this matches the updated GetCaseSensitiveMap / GetCaseSensitiveEnvVars behavior and preserves previous expectations for the "env" path.

If you want to harden coverage further, consider adding a small subtest that calls GetCaseSensitiveMap("env.vars") explicitly to lock in the structured-path behavior, but the current suite is already functionally solid.

cmd/cmd_utils.go (1)

551-612: Custom‑command env is wired correctly, but we now double‑merge global env

Using atmosConfig.GetCaseSensitiveEnvVars() when seeding env and switching ExecuteShell to &atmosConfig keeps custom commands aligned with the new env handling (including case preservation and .env behavior).

Right now env already includes os.Environ() + global env, and ExecuteShell repeats that merge internally before applying envVars, so the same keys get processed twice. It’s harmless but a bit redundant. Longer‑term, it may be cleaner to treat env here as “overrides only” (commandConfig/env + auth) and let ExecuteShell own the system/global/.env merge.

pkg/schema/schema.go (1)

53-72: EnvConfig / EnvFilesConfig and case‑sensitive env access look coherent

The new EnvFilesConfig + EnvConfig structs, the switch to AtmosConfiguration.Env EnvConfig, and the updated GetCaseSensitiveMap/GetCaseSensitiveEnvVars all line up cleanly:

  • Dual form is supported (flat env vs structured env.vars/env.files) without fighting mapstructure.
  • Case preservation for env vars is centralized via GetCaseSensitiveEnvVars() and the extended caseSensitivePaths ("env", "env.vars"), which matches how workflows, shell exec, and auth shells are now consuming env.
  • Returning the raw Vars map when CaseMaps is nil preserves previous behavior.

Only minor thought: if you ever care about distinguishing “unset” vs “empty map” when CaseMaps is present, you might add an early if source == nil { return nil } before calling ApplyCase, but as it stands this is fully workable.

Also applies to: 113-114, 243-270, 1322-1323

pkg/config/load.go (1)

21-29: Early .env support and dual‑form env parsing are wired correctly

Nice job threading the new env behavior through config loading:

  • parseEnvConfig cleanly supports both legacy flat env and structured env.vars/env.files without reintroducing the old mapstructure collision with Command.Env.
  • loadEnvFilesEarly runs after setEnv(v) but before profile resolution, uses env.files.enabled/env.files.paths, and injects only missing vars into os.Environ, so ATMOS_* in .env can influence profile selection and other config without clobbering explicit env.
  • UI feedback via ui.Success("Loaded …") is consistent with the later working‑dir .env loading path.
  • Extending caseSensitivePaths with "env" and "env.vars" completes the link so GetCaseSensitiveEnvVars() can rely on casemap for both flat and structured forms.

One behavioral nuance to keep in mind (likely acceptable): early .env loading will honor env.files.* from the base config, not from profiles, since profiles are applied later. If you ever need profile‑specific .env behavior at bootstrap time, that would require a follow‑up design, but this implementation is internally consistent.

Also applies to: 218-237, 280-284, 1237-1317, 1321-1325

internal/exec/shell_utils.go (1)

18-26: Consider merging command env with MergeEnvSlices to avoid duplicate keys

The new layering in ExecuteShellCommand—system env → global env → working‑dir .env → command env—is the right shape, and using GetCaseSensitiveEnvVars() keeps it aligned with the dual‑form env config.

Right now the final step is:

cmdEnv = append(cmdEnv, env...)

Since env is already a full environment slice (from prepareStepEnvironment), this can introduce duplicate KEY=value entries and leaves which value “wins” up to the OS/env implementation. To make precedence explicit and avoid duplicates, you could merge the slices instead:

cmdEnv = envpkg.MergeEnvSlices(cmdEnv, env)

That keeps “command/env manager output” as the clear highest‑priority layer while still honoring global + .env values.

Also applies to: 51-76

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between def7a4b and 268f81f.

📒 Files selected for processing (13)
  • cmd/auth_exec.go
  • cmd/cmd_utils.go
  • go.mod
  • internal/exec/shell_utils.go
  • internal/exec/shell_utils_test.go
  • internal/exec/stack_processor_process_stacks.go
  • internal/exec/workflow_adapters.go
  • internal/exec/workflow_utils.go
  • pkg/config/load.go
  • pkg/env/file.go
  • pkg/env/file_test.go
  • pkg/schema/schema.go
  • pkg/schema/schema_test.go
🧰 Additional context used
📓 Path-based instructions (5)
cmd/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands, implementing each command in a separate file under cmd/ directory
Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions
Provide meaningful feedback to users and include progress indicators for long-running operations in CLI commands

Files:

  • cmd/auth_exec.go
  • cmd/cmd_utils.go
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
All code must pass golangci-lint checks
Follow Go's error handling idioms: use meaningful error messages, wrap errors with context using fmt.Errorf("context: %w", err), and consider using custom error types for domain-specific errors
Follow standard Go coding style: use gofmt and goimports to format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables
Document all exported functions, types, and methods following Go's documentation conventions
Document complex logic with inline comments in Go code
Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging

**/*.go: All comments must end with periods (enforced by godot linter) in Go code
Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (cfg, log, u, errUtils)
All errors MUST be wrapped using static errors defined in errors/errors.go - use errors.Join for combining errors, fmt.Errorf with %w for context, and errors.Is() for error checking
Never manually create mocks - use go.uber.org/mock/mockgen with //go:generate directives in Go code
Keep files small and focused - under 600 lines with one cmd/impl per file, co-locate tests, never use //revive:disable:file-length-limit
Use colors from pkg/ui/theme/colors.go for all UI theming in Go code
Code must be compatible with Linux, macOS, and Windows - use SDKs over binaries, use filepath.Join() instead of h...

Files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/env/file_test.go
  • pkg/schema/schema.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
**/{pkg,internal,cmd}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Add defer perf.Track(atmosConfig, "pkg.FuncName")() plus blank line to all public functions, using nil if no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions

Files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/env/file_test.go
  • pkg/schema/schema.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages
Use table-driven tests for testing multiple scenarios in Go
Include integration tests for command flows and test CLI end-to-end when possible with test fixtures

Prefer unit tests with mocks over integration tests - use interfaces and dependency injection for testability, generate mocks with go.uber.org/mock/mockgen, use table-driven tests, target >80% coverage

Files:

  • pkg/schema/schema_test.go
  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
{go.mod,go.sum}

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies

Files:

  • go.mod
🧠 Learnings (64)
📓 Common learnings
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-01-19T22:30:27.600Z
Learning: The Atmos YAML function `!env` is used to retrieve environment variables and assign them to sections in stack manifests. It supports both simple types (string, number, boolean) and complex types (JSON-encoded lists, maps, objects).
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.
📚 Learning: 2025-12-13T06:10:25.156Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: internal/exec/workflow_utils.go:0-0
Timestamp: 2025-12-13T06:10:25.156Z
Learning: Atmos workflows: In internal/exec/workflow_utils.go ExecuteWorkflow, non-identity steps intentionally use baseWorkflowEnv, which is constructed from the parent environment with PATH modifications for the toolchain. Avoid appending os.Environ() again; prefer documenting this behavior and testing that standard environment variables are preserved.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/env/file_test.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • go.mod
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • internal/exec/workflow_utils.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/schema/schema.go
  • cmd/cmd_utils.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
📚 Learning: 2025-11-08T19:56:18.660Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/schema/schema.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*.go : Use `viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")` for environment variables - ATMOS_ prefix required in Go code

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/schema/schema.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • go.mod
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1202
File: pkg/utils/yaml_func_exec.go:104-104
Timestamp: 2025-04-23T15:02:50.246Z
Learning: In the Atmos codebase, direct calls to `os.Getenv` should be avoided. Instead, use `viper.BindEnv` for environment variable access. This provides a consistent approach to configuration management across the codebase.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/schema/schema.go
  • cmd/cmd_utils.go
  • go.mod
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2025-11-11T03:47:59.576Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.

Applied to files:

  • cmd/auth_exec.go
  • pkg/schema/schema_test.go
  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
📚 Learning: 2025-11-11T03:47:45.878Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
📚 Learning: 2025-09-29T15:47:10.908Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/terraform_cli_args_utils.go:64-73
Timestamp: 2025-09-29T15:47:10.908Z
Learning: In the Atmos codebase, viper.BindEnv is required for CLI commands in the cmd/ package, but internal utilities can use os.Getenv directly when parsing environment variables for business logic purposes. The requirement to use viper is specific to the CLI interface layer, not all environment variable access throughout the codebase.

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • internal/exec/shell_utils.go
  • internal/exec/workflow_utils.go
📚 Learning: 2025-09-07T18:07:00.549Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1452
File: cmd/auth_login.go:43-44
Timestamp: 2025-09-07T18:07:00.549Z
Learning: In the atmos project, the identity flag is defined as a persistent flag on the auth root command (cmd/auth.go), making it available to all auth subcommands without needing to be redefined in each individual subcommand.

Applied to files:

  • cmd/auth_exec.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • cmd/auth_exec.go
  • pkg/schema/schema.go
  • cmd/cmd_utils.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2025-12-13T04:37:25.223Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/root.go:0-0
Timestamp: 2025-12-13T04:37:25.223Z
Learning: In Atmos cmd/root.go Execute(), after cfg.InitCliConfig, we must call both toolchainCmd.SetAtmosConfig(&atmosConfig) and toolchain.SetAtmosConfig(&atmosConfig) so the CLI wrapper and the toolchain package receive configuration; missing either can cause nil-pointer panics in toolchain path resolution.

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
📚 Learning: 2025-08-15T14:43:41.030Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.

Applied to files:

  • cmd/auth_exec.go
  • pkg/schema/schema_test.go
  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
📚 Learning: 2025-12-13T04:37:40.435Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/toolchain/get.go:23-40
Timestamp: 2025-12-13T04:37:40.435Z
Learning: In Go CLI command files using Cobra, constrain the subcommand to accept at most one positional argument (MaximumNArgs(1)) so it supports both listing all items (zero args) and fetching a specific item (one arg). Define and parse flags with a standard parser (e.g., flags.NewStandardParser()) and avoid binding flags to Viper (no viper.BindEnv/BindPFlag). This promotes explicit argument handling and predictable flag behavior across command files.

Applied to files:

  • cmd/auth_exec.go
  • cmd/cmd_utils.go
📚 Learning: 2025-12-21T04:10:29.030Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1891
File: internal/exec/describe_affected.go:468-468
Timestamp: 2025-12-21T04:10:29.030Z
Learning: In Go, package-level declarations (constants, variables, types, and functions) are visible to all files in the same package without imports. During reviews in cloudposse/atmos (and similar Go codebases), before suggesting to declare a new identifier, first check if it already exists in another file of the same package. If it exists, you can avoid adding a new declaration; if not, proceed with a proper package-level declaration. 

Applied to files:

  • cmd/auth_exec.go
  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/env/file_test.go
  • pkg/schema/schema.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
📚 Learning: 2024-11-13T21:37:07.852Z
Learnt from: Cerebrovinny
Repo: cloudposse/atmos PR: 764
File: internal/exec/describe_stacks.go:289-295
Timestamp: 2024-11-13T21:37:07.852Z
Learning: In the `internal/exec/describe_stacks.go` file of the `atmos` project written in Go, avoid extracting the stack name handling logic into a helper function within the `ExecuteDescribeStacks` method, even if the logic appears duplicated.

Applied to files:

  • internal/exec/stack_processor_process_stacks.go
📚 Learning: 2025-12-13T03:21:35.786Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1813
File: cmd/terraform/shell.go:28-73
Timestamp: 2025-12-13T03:21:35.786Z
Learning: In Atmos, when calling cfg.InitCliConfig, you must first populate the schema.ConfigAndStacksInfo struct with global flag values using flags.ParseGlobalFlags(cmd, v) rather than passing an empty struct. The LoadConfig function (pkg/config/load.go) reads config selection fields (AtmosConfigFilesFromArg, AtmosConfigDirsFromArg, BasePath, ProfilesFromArg) directly from the ConfigAndStacksInfo struct, NOT from Viper. Passing an empty struct causes config selection flags (--base-path, --config, --config-path, --profile) to be silently ignored. Correct pattern: parse flags → populate struct → call InitCliConfig. See cmd/terraform/plan_diff.go for reference implementation.

Applied to files:

  • internal/exec/stack_processor_process_stacks.go
  • pkg/schema/schema_test.go
  • pkg/schema/schema.go
  • cmd/cmd_utils.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2025-10-13T18:13:54.020Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1622
File: pkg/perf/perf.go:140-184
Timestamp: 2025-10-13T18:13:54.020Z
Learning: In pkg/perf/perf.go, the `trackWithSimpleStack` function intentionally skips ownership checks at call stack depth > 1 to avoid expensive `getGoroutineID()` calls on every nested function. This is a performance optimization for the common single-goroutine execution case (most Atmos commands), accepting the rare edge case of potential metric corruption if multi-goroutine execution occurs at depth > 1. The ~19× performance improvement justifies this trade-off.

Applied to files:

  • internal/exec/stack_processor_process_stacks.go
📚 Learning: 2025-07-05T20:59:02.914Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1363
File: internal/exec/template_utils.go:18-18
Timestamp: 2025-07-05T20:59:02.914Z
Learning: In the Atmos project, gomplate v4 is imported with a blank import (`_ "github.com/hairyhenderson/gomplate/v4"`) alongside v3 imports to resolve AWS SDK version conflicts. V3 uses older AWS SDK versions that conflict with newer AWS modules used by Atmos. A full migration to v4 requires extensive refactoring due to API changes and should be handled in a separate PR.

Applied to files:

  • internal/exec/stack_processor_process_stacks.go
  • go.mod
  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.

Applied to files:

  • pkg/schema/schema_test.go
  • pkg/schema/schema.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • cmd/cmd_utils.go
  • pkg/config/load.go
  • internal/exec/workflow_utils.go
📚 Learning: 2024-12-12T15:17:45.245Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos.d/atmos.d/tools/helmfile.yml:10-10
Timestamp: 2024-12-12T15:17:45.245Z
Learning: In `examples/demo-atmos.d/atmos.d/tools/helmfile.yml`, when suggesting changes to `kubeconfig_path`, ensure that the values use valid Go template syntax.

Applied to files:

  • pkg/schema/schema_test.go
📚 Learning: 2025-11-10T23:23:39.771Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.

Applied to files:

  • pkg/schema/schema_test.go
📚 Learning: 2024-10-20T13:12:46.499Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 736
File: pkg/config/const.go:6-6
Timestamp: 2024-10-20T13:12:46.499Z
Learning: In `cmd/cmd_utils.go`, it's acceptable to have hardcoded references to `atmos.yaml` in logs, and it's not necessary to update them to use the `CliConfigFileName` constant.

Applied to files:

  • pkg/schema/schema_test.go
  • pkg/schema/schema.go
  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Use table-driven tests for testing multiple scenarios in Go

Applied to files:

  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages

Applied to files:

  • pkg/env/file_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Include integration tests for command flows and test CLI end-to-end when possible with test fixtures

Applied to files:

  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: The atmos codebase has a custom extension to *testing.T that provides a Chdir method, allowing test functions to call t.Chdir() to change working directories during tests. This is used consistently across test files in the codebase.

Applied to files:

  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults

Applied to files:

  • pkg/env/file_test.go
  • pkg/schema/schema.go
  • pkg/env/file.go
  • pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests - use interfaces and dependency injection for testability, generate mocks with `go.uber.org/mock/mockgen`, use table-driven tests, target >80% coverage

Applied to files:

  • pkg/env/file_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method call on *testing.T objects and works correctly for changing directories in tests. This is implemented through custom testing framework extensions and is used consistently throughout the test suite.

Applied to files:

  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method call on *testing.T objects and works correctly for changing directories in tests.

Applied to files:

  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method that can be called on *testing.T objects. This functionality is implemented through custom testing framework extensions and is used consistently throughout the test suite for changing working directories during tests.

Applied to files:

  • pkg/env/file_test.go
  • internal/exec/shell_utils_test.go
📚 Learning: 2024-12-25T20:28:47.526Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 887
File: internal/exec/stack_processor_utils.go:380-380
Timestamp: 2024-12-25T20:28:47.526Z
Learning: Windows path handling often requires `filepath.Join` to ensure correct separators and comparisons. Insufficient tests can break cross-platform compatibility, so migrating from `path.Join` to `filepath.Join` needs thorough testing on Windows before merging.

Applied to files:

  • pkg/env/file_test.go
📚 Learning: 2024-10-27T04:28:40.966Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:155-175
Timestamp: 2024-10-27T04:28:40.966Z
Learning: In the `CollectDirectoryObjects` function in `internal/exec/terraform_clean.go`, recursive search through all subdirectories is not needed.

Applied to files:

  • pkg/env/file_test.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/{pkg,internal,cmd}/**/*.go : Add `defer perf.Track(atmosConfig, "pkg.FuncName")()` plus blank line to all public functions, using `nil` if no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions

Applied to files:

  • pkg/schema/schema.go
  • pkg/env/file.go
  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.

Applied to files:

  • pkg/schema/schema.go
  • pkg/config/load.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.

Applied to files:

  • pkg/schema/schema.go
  • cmd/cmd_utils.go
  • internal/exec/workflow_utils.go
📚 Learning: 2025-01-25T15:21:40.413Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos-cli-imports/atmos.yaml:8-8
Timestamp: 2025-01-25T15:21:40.413Z
Learning: In Atmos, when a directory is specified for configuration loading (e.g., in the `import` section of atmos.yaml), all files within that directory should be treated as Atmos configurations. Do not suggest restricting file extensions in directory-based glob patterns.

Applied to files:

  • pkg/schema/schema.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Use Viper for managing configuration, environment variables, and flags in CLI commands

Applied to files:

  • pkg/schema/schema.go
  • go.mod
  • pkg/config/load.go
📚 Learning: 2024-11-16T17:30:52.893Z
Learnt from: pkbhowmick
Repo: cloudposse/atmos PR: 786
File: internal/exec/shell_utils.go:159-162
Timestamp: 2024-11-16T17:30:52.893Z
Learning: For the `atmos terraform shell` command in `internal/exec/shell_utils.go`, input validation for the custom shell prompt is not required, as users will use this as a CLI tool and any issues will impact themselves.

Applied to files:

  • internal/exec/workflow_adapters.go
  • internal/exec/shell_utils_test.go
  • internal/exec/shell_utils.go
📚 Learning: 2025-08-16T23:33:07.477Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1405
File: internal/exec/describe_dependents_test.go:651-652
Timestamp: 2025-08-16T23:33:07.477Z
Learning: In the cloudposse/atmos Go codebase, ExecuteDescribeDependents expects a pointer to AtmosConfiguration (*schema.AtmosConfiguration), so when calling it with a value returned by cfg.InitCliConfig (which returns schema.AtmosConfiguration), the address-of operator (&) is necessary: ExecuteDescribeDependents(&atmosConfig, ...).

Applied to files:

  • internal/exec/workflow_adapters.go
  • cmd/cmd_utils.go
  • internal/exec/workflow_utils.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to cmd/**/*_test.go : Always use `cmd.NewTestKit(t)` for cmd tests to auto-clean RootCmd state

Applied to files:

  • internal/exec/shell_utils_test.go
📚 Learning: 2025-12-10T18:32:51.237Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1808
File: cmd/terraform/backend/backend_delete_test.go:9-23
Timestamp: 2025-12-10T18:32:51.237Z
Learning: In cmd subpackages (e.g., cmd/terraform/backend/), tests cannot use cmd.NewTestKit(t) due to Go's test visibility rules (NewTestKit is in a parent package test file). These tests only need TestKit if they execute commands through RootCmd or modify RootCmd state. Structural tests that only verify command structure/flags without touching RootCmd don't require TestKit cleanup.

Applied to files:

  • internal/exec/shell_utils_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to {go.mod,go.sum} : Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies

Applied to files:

  • go.mod
  • pkg/env/file.go
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: Go version 1.23.0 was deliberately introduced by the maintainer (aknysh) in January 2025. While this might be a pre-release or development version of Go, it has been approved for use in this project.

Applied to files:

  • go.mod
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: The project uses Go version 1.23.0 which has been confirmed by the maintainer to be working in production for months. Do not flag this as an invalid Go version.

Applied to files:

  • go.mod
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.

Applied to files:

  • go.mod
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 1195
File: internal/exec/terraform_clean.go:99-99
Timestamp: 2025-04-26T15:54:10.506Z
Learning: The error variable `ErrRelPath` is defined in `internal/exec/terraform_clean_util.go` and is used across files in the `exec` package, including in `terraform_clean.go`. This is part of an approach to standardize error handling in the codebase.

Applied to files:

  • go.mod
📚 Learning: 2025-03-12T21:38:42.699Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1139
File: pkg/config/go-homedir/homedir.go:183-196
Timestamp: 2025-03-12T21:38:42.699Z
Learning: The code in pkg/config/go-homedir is a direct fork of the mitchellh/go-homedir package and was intentionally imported as-is without modifications to maintain consistency with the original source. Security concerns or other improvements may be addressed in future PRs.

Applied to files:

  • go.mod
📚 Learning: 2025-04-10T20:48:22.687Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1147
File: pkg/config/load.go:0-0
Timestamp: 2025-04-10T20:48:22.687Z
Learning: In the `bindEnv` function in `pkg/config/load.go`, panic is used deliberately instead of returning errors because errors from `BindEnv` would only occur due to developer mistakes. Using panic helps with early detection of these developer errors during initialization.

Applied to files:

  • pkg/env/file.go
  • pkg/config/load.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • internal/exec/shell_utils.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*.go : Use colors from `pkg/ui/theme/colors.go` for all UI theming in Go code

Applied to files:

  • internal/exec/shell_utils.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*.go : Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (`cfg`, `log`, `u`, `errUtils`)

Applied to files:

  • internal/exec/shell_utils.go
  • pkg/config/load.go
📚 Learning: 2025-11-09T19:06:58.470Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1752
File: pkg/profile/list/formatter_table.go:27-29
Timestamp: 2025-11-09T19:06:58.470Z
Learning: In the cloudposse/atmos repository, performance tracking with `defer perf.Track()` is enforced on all functions via linting, including high-frequency utility functions, formatters, and renderers. This is a repository-wide policy to maintain consistency and avoid making case-by-case judgment calls about which functions should have profiling.

Applied to files:

  • internal/exec/shell_utils.go
📚 Learning: 2024-10-28T01:51:30.811Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:329-332
Timestamp: 2024-10-28T01:51:30.811Z
Learning: In the Atmos Go code, when deleting directories or handling file paths (e.g., in `terraform_clean.go`), always resolve the absolute path using `filepath.Abs` and use the logger `u.LogWarning` for logging messages instead of using `fmt.Printf`.

Applied to files:

  • internal/exec/shell_utils.go
📚 Learning: 2025-02-06T13:38:07.216Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 984
File: internal/exec/copy_glob.go:0-0
Timestamp: 2025-02-06T13:38:07.216Z
Learning: The `u.LogTrace` function in the `cloudposse/atmos` repository accepts `atmosConfig` as its first parameter, followed by the message string.

Applied to files:

  • internal/exec/shell_utils.go
📚 Learning: 2025-09-27T20:50:20.564Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1533
File: pkg/config/load.go:585-637
Timestamp: 2025-09-27T20:50:20.564Z
Learning: In the cloudposse/atmos repository, command merging prioritizes precedence over display ordering. Help commands are displayed lexicographically regardless of internal array order, so the mergeCommandArrays function focuses on ensuring the correct precedence chain (top-level file wins) rather than maintaining specific display order.

Applied to files:

  • internal/exec/shell_utils.go
📚 Learning: 2025-05-30T03:21:37.197Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1274
File: go.mod:63-63
Timestamp: 2025-05-30T03:21:37.197Z
Learning: The redis dependency (github.com/redis/go-redis/v9) in the atmos project is only used in tests, not in production code.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: New config templates support Go templating with `FuncMap()` from `internal/exec/template_funcs.go`

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-09-23T04:43:31.857Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1430
File: pkg/config/config.go:98-107
Timestamp: 2025-09-23T04:43:31.857Z
Learning: In the Atmos codebase, NO_PAGER environment variable handling is intentionally kept as direct os.Getenv() access in pkg/config/config.go rather than using Viper binding, because adding no_pager to the config file would be confusing for users. This is an acknowledged exception to the normal Viper binding pattern for environment variables.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
Repo: cloudposse/atmos PR: 1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • internal/exec/workflow_utils.go
🧬 Code graph analysis (9)
cmd/auth_exec.go (1)
pkg/env/global.go (1)
  • MergeGlobalEnv (16-35)
pkg/schema/schema_test.go (1)
pkg/schema/schema.go (2)
  • AtmosConfiguration (75-120)
  • EnvConfig (67-72)
pkg/env/file_test.go (1)
pkg/env/file.go (4)
  • LoadEnvFiles (19-27)
  • LoadFromDirectory (33-69)
  • MergeEnvMaps (72-82)
  • MergeEnvSlices (85-100)
pkg/schema/schema.go (1)
pkg/config/casemap/casemap.go (1)
  • CaseMaps (20-22)
internal/exec/workflow_adapters.go (2)
pkg/perf/perf.go (1)
  • Track (121-138)
internal/exec/shell_utils.go (1)
  • ExecuteShell (133-191)
cmd/cmd_utils.go (2)
pkg/env/global.go (1)
  • MergeGlobalEnv (16-35)
internal/exec/shell_utils.go (1)
  • ExecuteShell (133-191)
pkg/env/file.go (2)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/env/global.go (1)
  • ConvertMapToSlice (39-51)
internal/exec/shell_utils.go (2)
pkg/env/global.go (3)
  • MergeGlobalEnv (16-35)
  • MergeSystemEnvWithGlobal (87-91)
  • MergeSystemEnvSimpleWithGlobal (105-109)
pkg/env/file.go (3)
  • LoadFromDirectory (33-69)
  • MergeEnvSlices (85-100)
  • MapToSlice (104-108)
internal/exec/workflow_utils.go (1)
internal/exec/shell_utils.go (1)
  • ExecuteShell (133-191)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (21)
pkg/env/file.go (6)

19-27: LGTM.

Clean delegation with proper empty pattern handling.


33-69: LGTM — parent directory walking logic is correct.

The precedence model (repo root lowest, working dir highest) aligns with the expected behavior. Error handling propagates correctly.


72-82: LGTM.

Simple and correct. Nil maps are handled gracefully.


85-100: LGTM.

Properly handles values containing = by splitting only at the first occurrence. Entries without = or with empty keys are silently skipped, which is reasonable.


164-213: LGTM — security boundary enforced correctly.

The isWithinOrEqual check at Line 187 prevents walking beyond repo root. Path normalization with filepath.Abs and filepath.Clean ensures cross-platform compatibility.


216-231: LGTM — path containment check is robust.

Adding the separator before the prefix check (Line 229) correctly prevents false positives like /a/b/c-other matching /a/b/c.

pkg/env/file_test.go (4)

353-377: LGTM — comprehensive table-driven tests for path containment.

Good coverage of edge cases including trailing slashes and similar prefixes. The hardcoded Unix paths work because isWithinOrEqual uses filepath.Clean which normalizes separators.


12-125: LGTM — thorough test coverage for LoadEnvFiles.

Tests cover key scenarios: single file, glob patterns, missing files, case preservation, empty patterns, values with equals, quoted values, and directory filtering.


127-230: LGTM — LoadFromDirectory tests validate parent traversal and security boundaries.

The test at Line 172-200 correctly verifies that .env files outside repo root are not loaded.


279-281: No issue here. The splitStringAtFirstOccurrence helper is defined in pkg/env/env.go at line 55 and is accessible throughout the package.

cmd/auth_exec.go (1)

111-111: LGTM — updated to use case-sensitive env vars.

Consistent with the broader refactor to GetCaseSensitiveEnvVars() across the codebase.

internal/exec/shell_utils_test.go (2)

600-609: LGTM — nil atmosConfig is appropriate for basic shell tests.

These tests verify shell execution mechanics, not Atmos-specific env var handling.


611-669: LGTM — remaining ExecuteShell test updates are consistent.

All test cases correctly pass nil as the first argument with appropriate comments.

internal/exec/workflow_adapters.go (1)

34-40: LGTM — nil atmosConfig is intentional for workflow shell commands.

Per the learning, workflow non-identity steps use baseWorkflowEnv. The comment clearly documents the rationale: shell commands don't need atmosConfig for basic execution.

go.mod (1)

71-71: LGTM — godotenv promoted to direct dependency.

This correctly reflects the new direct import in pkg/env/file.go. v1.5.1 is the latest stable version.

internal/exec/stack_processor_process_stacks.go (1)

211-215: LGTM — atmos.yaml env correctly positioned as lowest priority in merge chain.

GetCaseSensitiveEnvVars() provides case-preserved env vars from atmos.yaml. The merge order ensures component-level env overrides global env, which overrides atmos.yaml env.

internal/exec/workflow_utils.go (1)

324-334: Workflow env handling now correctly uses case‑preserving env access

Wiring prepareStepEnvironment to atmosConfig.GetCaseSensitiveEnvVars() and passing &atmosConfig into ExecuteShell keeps workflow steps in line with the new EnvConfig / .env behavior and perf tracking. The change is consistent with how other call sites are being updated.

internal/exec/shell_utils.go (3)

133-191: ExecuteShell updates correctly integrate global env and per‑dir .env support

Passing *schema.AtmosConfiguration into ExecuteShell and merging:

  • os.Environ()
  • global env via atmosConfig.GetCaseSensitiveEnvVars()
  • per‑directory .env via LoadFromDirectory

before applying envVars gives shells the same enriched environment as workflows and other exec paths, while still allowing the caller‑supplied entries to override. The atmosConfig == nil guard keeps tests and non‑Atmos usage safe.


210-305: Terraform shell now respects global env via GetCaseSensitiveEnvVars

Switching execTerraformShellCommand to build mergedEnv with:

mergedEnv := envpkg.MergeSystemEnvWithGlobal(componentEnvList, atmosConfig.GetCaseSensitiveEnvVars())

ensures both legacy flat env and structured env.vars feed into the Terraform shell’s environment with proper case restoration, while still letting the per‑component entries in componentEnvList take precedence. This keeps the Terraform shell consistent with the rest of the env pipeline.

Also applies to: 297-304


361-419: Auth shell correctly layers global env under auth‑specific vars

In ExecAuthShellCommand, using MergeSystemEnvSimpleWithGlobal(authEnvList, atmosConfig.GetCaseSensitiveEnvVars()) makes the auth shell’s environment:

  • Start from the host env.
  • Add global env from Atmos config (case‑preserved).
  • Finally overlay the auth/env list (including ATMOS_IDENTITY and provider‑specific credentials).

That matches the documented precedence and keeps auth shells aligned with the new env model.

Also applies to: 402-403

pkg/schema/schema_test.go (1)

3-10: Import path resolves correctly — go.yaml.in/yaml/v3 is declared as a direct dependency in go.mod, so no resolution issues here.

The inconsistency you noticed is real (codebase mixes go.yaml.in/yaml/v3 and gopkg.in/yaml.v3), but both import paths are intentionally maintained as separate dependencies. If consistency across the codebase matters for maintenance, that's a separate refactoring conversation.

Likely an incorrect or invalid review comment.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jan 4, 2026
@osterman Erik Osterman (Cloud Posse) (osterman) added the minor New features that do not break anything label Jan 5, 2026
@github-actions

github-actions Bot commented Jan 8, 2026

Copy link
Copy Markdown

Warning

Release Documentation Required

This PR is labeled minor or major and requires documentation updates:

  • Changelog entry - Add a blog post in website/blog/YYYY-MM-DD-feature-name.mdx
  • Roadmap update - Update website/src/data/roadmap.js with the new milestone

Alternatively: If this change doesn't require release documentation, remove the minor or major label.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
pkg/config/load.go (2)

1243-1275: Consider more robust structured form detection.

The detection at lines 1259-1260 checks only for key existence, not value type. If a flat env map contains a key literally named vars or files, it would be misinterpreted as structured form.

♻️ More robust detection
-	// Detect structured form by presence of "vars" or "files" keys.
-	_, hasVars := envMap["vars"]
-	_, hasFiles := envMap["files"]
+	// Detect structured form by presence of "vars" or "files" keys with map values.
+	varsVal, hasVars := envMap["vars"]
+	filesVal, hasFiles := envMap["files"]
+	
+	// Only treat as structured if the values are maps/objects, not simple strings.
+	if hasVars {
+		if _, ok := varsVal.(map[string]any); !ok {
+			hasVars = false
+		}
+	}
+	if hasFiles {
+		if _, ok := filesVal.(map[string]any); !ok {
+			hasFiles = false
+		}
+	}

1318-1320: Consider moving UI reporting to the caller.

The ui.Success() calls create side effects in the config loading function, which is called from many places. This could be noisy in test environments or when config is reloaded.

Since the function already returns loadedFiles, consider letting the caller handle UI reporting:

// In LoadConfig (line 284):
loadedFiles := loadEnvFilesEarly(v, v.GetString("base_path"))
for _, file := range loadedFiles {
    ui.Success(fmt.Sprintf("Loaded %s", filepath.Base(file)))
}

Then remove the UI calls from inside loadEnvFilesEarly. This separates concerns and makes the config loading function more testable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 268f81f and addb84d.

📒 Files selected for processing (5)
  • cmd/auth_exec.go
  • cmd/cmd_utils.go
  • go.mod
  • internal/exec/stack_processor_process_stacks.go
  • pkg/config/load.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/exec/stack_processor_process_stacks.go
  • cmd/cmd_utils.go
🧰 Additional context used
📓 Path-based instructions (4)
cmd/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands, implementing each command in a separate file under cmd/ directory
Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions
Provide meaningful feedback to users and include progress indicators for long-running operations in CLI commands

Files:

  • cmd/auth_exec.go
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
All code must pass golangci-lint checks
Follow Go's error handling idioms: use meaningful error messages, wrap errors with context using fmt.Errorf("context: %w", err), and consider using custom error types for domain-specific errors
Follow standard Go coding style: use gofmt and goimports to format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables
Document all exported functions, types, and methods following Go's documentation conventions
Document complex logic with inline comments in Go code
Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging

**/*.go: All comments must end with periods (enforced by godot linter) in Go code
Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (cfg, log, u, errUtils)
All errors MUST be wrapped using static errors defined in errors/errors.go - use errors.Join for combining errors, fmt.Errorf with %w for context, and errors.Is() for error checking
Never manually create mocks - use go.uber.org/mock/mockgen with //go:generate directives in Go code
Keep files small and focused - under 600 lines with one cmd/impl per file, co-locate tests, never use //revive:disable:file-length-limit
Use colors from pkg/ui/theme/colors.go for all UI theming in Go code
Code must be compatible with Linux, macOS, and Windows - use SDKs over binaries, use filepath.Join() instead of h...

Files:

  • cmd/auth_exec.go
  • pkg/config/load.go
**/{pkg,internal,cmd}/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Add defer perf.Track(atmosConfig, "pkg.FuncName")() plus blank line to all public functions, using nil if no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions

Files:

  • cmd/auth_exec.go
  • pkg/config/load.go
{go.mod,go.sum}

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies

Files:

  • go.mod
🧠 Learnings (37)
📓 Common learnings
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-01-19T22:30:27.600Z
Learning: The Atmos YAML function `!env` is used to retrieve environment variables and assign them to sections in stack manifests. It supports both simple types (string, number, boolean) and complex types (JSON-encoded lists, maps, objects).
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.
Learnt from: RoseSecurity
Repo: cloudposse/atmos PR: 725
File: internal/exec/vendor_component_utils.go:55-62
Timestamp: 2024-10-15T17:36:08.040Z
Learning: In the 'atmos' project, when adding support for multiple file extensions, the preferred approach is to directly check for the existence of the files rather than modifying constants or adding helper functions.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos-cli-imports/atmos.yaml:8-8
Timestamp: 2025-01-25T15:21:40.413Z
Learning: In Atmos, when a directory is specified for configuration loading (e.g., in the `import` section of atmos.yaml), all files within that directory should be treated as Atmos configurations. Do not suggest restricting file extensions in directory-based glob patterns.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1475
File: pkg/auth/providers/github/oidc.go:96-100
Timestamp: 2025-09-10T17:34:52.568Z
Learning: The ATMOS_ environment variable binding guideline applies to Atmos configuration variables, not external service-required environment variables like GitHub Actions OIDC variables (GITHUB_ACTIONS, ACTIONS_ID_TOKEN_*) which must use their standard names.
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : Use `viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")` for environment variables - ATMOS_ prefix required in Go code
📚 Learning: 2025-12-13T06:10:25.156Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: internal/exec/workflow_utils.go:0-0
Timestamp: 2025-12-13T06:10:25.156Z
Learning: Atmos workflows: In internal/exec/workflow_utils.go ExecuteWorkflow, non-identity steps intentionally use baseWorkflowEnv, which is constructed from the parent environment with PATH modifications for the toolchain. Avoid appending os.Environ() again; prefer documenting this behavior and testing that standard environment variables are preserved.

Applied to files:

  • cmd/auth_exec.go
  • go.mod
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2025-11-08T19:56:18.660Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : Use `viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")` for environment variables - ATMOS_ prefix required in Go code

Applied to files:

  • cmd/auth_exec.go
  • go.mod
  • pkg/config/load.go
📚 Learning: 2025-11-11T03:47:59.576Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1202
File: pkg/utils/yaml_func_exec.go:104-104
Timestamp: 2025-04-23T15:02:50.246Z
Learning: In the Atmos codebase, direct calls to `os.Getenv` should be avoided. Instead, use `viper.BindEnv` for environment variable access. This provides a consistent approach to configuration management across the codebase.

Applied to files:

  • cmd/auth_exec.go
  • go.mod
  • pkg/config/load.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2025-11-11T03:47:45.878Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.

Applied to files:

  • cmd/auth_exec.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.

Applied to files:

  • cmd/auth_exec.go
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • cmd/auth_exec.go
📚 Learning: 2025-09-07T18:07:00.549Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1452
File: cmd/auth_login.go:43-44
Timestamp: 2025-09-07T18:07:00.549Z
Learning: In the atmos project, the identity flag is defined as a persistent flag on the auth root command (cmd/auth.go), making it available to all auth subcommands without needing to be redefined in each individual subcommand.

Applied to files:

  • cmd/auth_exec.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2025-12-13T04:37:25.223Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/root.go:0-0
Timestamp: 2025-12-13T04:37:25.223Z
Learning: In Atmos cmd/root.go Execute(), after cfg.InitCliConfig, we must call both toolchainCmd.SetAtmosConfig(&atmosConfig) and toolchain.SetAtmosConfig(&atmosConfig) so the CLI wrapper and the toolchain package receive configuration; missing either can cause nil-pointer panics in toolchain path resolution.

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2025-08-15T14:43:41.030Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.

Applied to files:

  • cmd/auth_exec.go
📚 Learning: 2025-12-13T04:37:40.435Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/toolchain/get.go:23-40
Timestamp: 2025-12-13T04:37:40.435Z
Learning: In Go CLI command files using Cobra, constrain the subcommand to accept at most one positional argument (MaximumNArgs(1)) so it supports both listing all items (zero args) and fetching a specific item (one arg). Define and parse flags with a standard parser (e.g., flags.NewStandardParser()) and avoid binding flags to Viper (no viper.BindEnv/BindPFlag). This promotes explicit argument handling and predictable flag behavior across command files.

Applied to files:

  • cmd/auth_exec.go
📚 Learning: 2025-12-21T04:10:29.030Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1891
File: internal/exec/describe_affected.go:468-468
Timestamp: 2025-12-21T04:10:29.030Z
Learning: In Go, package-level declarations (constants, variables, types, and functions) are visible to all files in the same package without imports. During reviews in cloudposse/atmos (and similar Go codebases), before suggesting to declare a new identifier, first check if it already exists in another file of the same package. If it exists, you can avoid adding a new declaration; if not, proceed with a proper package-level declaration. 

Applied to files:

  • cmd/auth_exec.go
  • pkg/config/load.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to {go.mod,go.sum} : Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies

Applied to files:

  • go.mod
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: Go version 1.23.0 was deliberately introduced by the maintainer (aknysh) in January 2025. While this might be a pre-release or development version of Go, it has been approved for use in this project.

Applied to files:

  • go.mod
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: The project uses Go version 1.23.0 which has been confirmed by the maintainer to be working in production for months. Do not flag this as an invalid Go version.

Applied to files:

  • go.mod
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.

Applied to files:

  • go.mod
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 1195
File: internal/exec/terraform_clean.go:99-99
Timestamp: 2025-04-26T15:54:10.506Z
Learning: The error variable `ErrRelPath` is defined in `internal/exec/terraform_clean_util.go` and is used across files in the `exec` package, including in `terraform_clean.go`. This is part of an approach to standardize error handling in the codebase.

Applied to files:

  • go.mod
📚 Learning: 2025-03-12T21:38:42.699Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1139
File: pkg/config/go-homedir/homedir.go:183-196
Timestamp: 2025-03-12T21:38:42.699Z
Learning: The code in pkg/config/go-homedir is a direct fork of the mitchellh/go-homedir package and was intentionally imported as-is without modifications to maintain consistency with the original source. Security concerns or other improvements may be addressed in future PRs.

Applied to files:

  • go.mod
📚 Learning: 2025-07-05T20:59:02.914Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1363
File: internal/exec/template_utils.go:18-18
Timestamp: 2025-07-05T20:59:02.914Z
Learning: In the Atmos project, gomplate v4 is imported with a blank import (`_ "github.com/hairyhenderson/gomplate/v4"`) alongside v3 imports to resolve AWS SDK version conflicts. V3 uses older AWS SDK versions that conflict with newer AWS modules used by Atmos. A full migration to v4 requires extensive refactoring due to API changes and should be handled in a separate PR.

Applied to files:

  • go.mod
  • pkg/config/load.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Use Viper for managing configuration, environment variables, and flags in CLI commands

Applied to files:

  • go.mod
  • pkg/config/load.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-04-10T20:48:22.687Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1147
File: pkg/config/load.go:0-0
Timestamp: 2025-04-10T20:48:22.687Z
Learning: In the `bindEnv` function in `pkg/config/load.go`, panic is used deliberately instead of returning errors because errors from `BindEnv` would only occur due to developer mistakes. Using panic helps with early detection of these developer errors during initialization.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-12-13T03:21:35.786Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1813
File: cmd/terraform/shell.go:28-73
Timestamp: 2025-12-13T03:21:35.786Z
Learning: In Atmos, when calling cfg.InitCliConfig, you must first populate the schema.ConfigAndStacksInfo struct with global flag values using flags.ParseGlobalFlags(cmd, v) rather than passing an empty struct. The LoadConfig function (pkg/config/load.go) reads config selection fields (AtmosConfigFilesFromArg, AtmosConfigDirsFromArg, BasePath, ProfilesFromArg) directly from the ConfigAndStacksInfo struct, NOT from Viper. Passing an empty struct causes config selection flags (--base-path, --config, --config-path, --profile) to be silently ignored. Correct pattern: parse flags → populate struct → call InitCliConfig. See cmd/terraform/plan_diff.go for reference implementation.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/{pkg,internal,cmd}/**/*.go : Add `defer perf.Track(atmosConfig, "pkg.FuncName")()` plus blank line to all public functions, using `nil` if no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions

Applied to files:

  • pkg/config/load.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-05-30T03:21:37.197Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1274
File: go.mod:63-63
Timestamp: 2025-05-30T03:21:37.197Z
Learning: The redis dependency (github.com/redis/go-redis/v9) in the atmos project is only used in tests, not in production code.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (`cfg`, `log`, `u`, `errUtils`)

Applied to files:

  • pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: New config templates support Go templating with `FuncMap()` from `internal/exec/template_funcs.go`

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-09-23T04:43:31.857Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1430
File: pkg/config/config.go:98-107
Timestamp: 2025-09-23T04:43:31.857Z
Learning: In the Atmos codebase, NO_PAGER environment variable handling is intentionally kept as direct os.Getenv() access in pkg/config/config.go rather than using Viper binding, because adding no_pager to the config file would be confusing for users. This is an acknowledged exception to the normal Viper binding pattern for environment variables.

Applied to files:

  • pkg/config/load.go
📚 Learning: 2025-09-29T15:47:10.908Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/terraform_cli_args_utils.go:64-73
Timestamp: 2025-09-29T15:47:10.908Z
Learning: In the Atmos codebase, viper.BindEnv is required for CLI commands in the cmd/ package, but internal utilities can use os.Getenv directly when parsing environment variables for business logic purposes. The requirement to use viper is specific to the CLI interface layer, not all environment variable access throughout the codebase.

Applied to files:

  • pkg/config/load.go
🧬 Code graph analysis (2)
cmd/auth_exec.go (1)
pkg/env/global.go (1)
  • MergeGlobalEnv (16-35)
pkg/config/load.go (3)
pkg/schema/schema.go (1)
  • AtmosConfiguration (75-121)
pkg/env/file.go (1)
  • LoadEnvFiles (19-27)
pkg/ui/formatter.go (1)
  • Success (204-211)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (5)
go.mod (1)

74-74: Solid dependency addition. Moving joho/godotenv to direct dependency is the right call since it's now a first-class feature. Version v1.5.1 is the latest stable release, so you're good to go.

cmd/auth_exec.go (1)

113-113: LGTM! Proper use of case-sensitive env access.

The switch to GetCaseSensitiveEnvVars() correctly aligns with the new case-sensitive environment handling introduced in this PR.

pkg/config/load.go (3)

22-22: LGTM! Imports properly organized.

The new imports for env and ui packages are correctly placed and follow the three-group organization pattern.

Also applies to: 26-26


281-284: Correct placement for early .env loading.

The placement before profile detection is essential and well-documented. This enables ATMOS_PROFILE and other ATMOS_* variables from .env files to influence Atmos behavior during initialization.


1328-1331: Good catch on dual-form case preservation.

Adding both env (flat form) and env.vars (structured form) ensures environment variable names maintain correct casing regardless of which configuration format is used.

@github-actions

Copy link
Copy Markdown

Warning

Release Documentation Required

This PR is labeled minor or major and requires documentation updates:

  • Changelog entry - Add a blog post in website/blog/YYYY-MM-DD-feature-name.mdx
  • Roadmap update - Update website/src/data/roadmap.js with the new milestone

Alternatively: If this change doesn't require release documentation, remove the minor or major label.

1 similar comment
@github-actions

Copy link
Copy Markdown

Warning

Release Documentation Required

This PR is labeled minor or major and requires documentation updates:

  • Changelog entry - Add a blog post in website/blog/YYYY-MM-DD-feature-name.mdx
  • Roadmap update - Update website/src/data/roadmap.js with the new milestone

Alternatively: If this change doesn't require release documentation, remove the minor or major label.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jan 14, 2026
@github-actions

Copy link
Copy Markdown

Warning

Release Documentation Required

This PR is labeled minor or major and requires documentation updates:

  • Changelog entry - Add a blog post in website/blog/YYYY-MM-DD-feature-name.mdx
  • Roadmap update - Update website/src/data/roadmap.js with the new milestone

Alternatively: If this change doesn't require release documentation, remove the minor or major label.

@github-actions

Copy link
Copy Markdown

Warning

Release Documentation Required

This PR is labeled minor or major and requires documentation updates:

  • Changelog entry - Add a blog post in website/blog/YYYY-MM-DD-feature-name.mdx
  • Roadmap update - Update website/src/data/roadmap.js with the new milestone

Alternatively: If this change doesn't require release documentation, remove the minor or major label.

@mergify

mergify Bot commented Jan 16, 2026

Copy link
Copy Markdown
Contributor

Warning

This PR exceeds the recommended limit of 1,000 lines.

Large PRs are difficult to review and may be rejected due to their size.

Please verify that this PR does not address multiple issues.
Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.

Erik Osterman (Cloud Posse) (osterman) added a commit that referenced this pull request Jan 16, 2026
- Add blog post announcing .env file support feature
- Add milestone to DX initiative in roadmap
- Link to PR #1930

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@mergify

mergify Bot commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added conflict This PR has conflicts and removed conflict This PR has conflicts labels Jan 17, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@pkg/config/load.go`:
- Around line 1286-1307: The early .env loader (loadEnvFilesEarly) currently
calls env.LoadEnvFiles(basePath, paths) which ignores the env.files.parents
flag; change it to call env.LoadFromDirectory(basePath, paths,
v.GetBool("env.files.parents"), v.GetString("repo_root")) so parent traversal is
honored during early loading and profile detection, ensuring it uses the same
repoRoot and parents flag as the main loader; preserve returned envVars,
loadedFiles and existing error handling (log.Debug and behavior) after the
switch.
- Around line 1251-1278: The code currently treats presence of "vars" or "files"
keys (via viper-lowercased envMap["vars"/"files"]) as indicating structured form
even when those keys are flat string values; update the detection logic to
verify the actual types before assuming structured form: check envMap["vars"] is
a map[string]any (or can be decoded by GetStringMapString) and envMap["files"]
is a map[string]any or a slice/struct expected by atmosConfig.Env.Files, only
then set hasVars/hasFiles true and use
GetStringMapString("env.vars")/GetBool/GetStringSlice; otherwise fall back to
the flat form and populate atmosConfig.Env.Vars from
v.GetStringMapString("env"). Ensure you reference and update the existing
symbols envRaw, envMap, envMap["vars"], envMap["files"], hasVars/hasFiles,
GetStringMapString("env.vars"), and atmosConfig.Env.Files handling so legacy
string values are not lost.
🧹 Nitpick comments (3)
pkg/schema/schema.go (1)

264-273: Fallback logic may be redundant.

Both GetCaseSensitiveMap("env.vars") and GetCaseSensitiveMap("env") return a.Env.Vars per lines 252-253. The fallback on line 272 would only differ if the casemap has different keys registered for each path. If that's the intent, it works. Otherwise, the fallback is effectively a no-op when vars is empty.

Consider adding a brief comment explaining when the fallback would return different results, or simplify if both paths always return identical data.

website/blog/2025-01-15-dotenv-file-support.mdx (1)

37-56: Consider a brief note about .env secrets and gitignore.
A short reminder to avoid committing .env / .env.local would help readers.

✏️ Optional doc tweak
 Environment variables are now available to all Atmos commands including Terraform, Helmfile, workflows, and custom commands.
+
+Note: `.env` files often contain secrets. Add `.env.local` to `.gitignore` and avoid committing sensitive values.
website/docs/cli/configuration/env.mdx (1)

126-209: Optional: add a brief note about missing files being skipped.
This matches the “load only when they exist” behavior and prevents confusion.

✏️ Optional doc tweak
 Enable loading in `atmos.yaml`:
 
 <File title="atmos.yaml">
 ```yaml
 env:
   files:
     enabled: true
     paths:
       - .env
+ +Missing files are skipped silently; only existing matches are loaded. ```

Comment thread pkg/config/load.go Outdated
Comment thread pkg/config/load.go Outdated
@mergify

mergify Bot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify

mergify Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Jun 10, 2026
…support-for-env-files

# Conflicts:
#	examples/demo-localstack/stacks/mixins/localstack.yaml
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026
…files per project

Promote ATMOS_-prefixed keys from the base config `env:` section (e.g. via
`env: !include .env`) into Atmos' own process environment during config load,
before profile resolution. This lets a project pin ATMOS_PROFILE (and other
ATMOS_* settings) in a committed `.env`. Exported env vars always win, and only
ATMOS_*-prefixed keys are promoted; other keys still flow only to subprocesses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
TestLoadConfig_PinsAtmosProfileFromEnvSection asserted AWS_REGION was unset to
prove non-ATMOS_ keys are not promoted, but CI runners (AWS) have AWS_REGION set
in the ambient environment, so the assertion failed. Assert on a uniquely-named
non-ATMOS_ key that cannot exist in the host environment instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@aknysh
Andriy Knysh (aknysh) merged commit 3ed8648 into main Jun 14, 2026
60 checks passed
@aknysh
Andriy Knysh (aknysh) deleted the feature/dev-2990-add-support-for-env-files branch June 14, 2026 17:15
@atmos-pro

atmos-pro Bot commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

No affected stacks workflow was detected for this pull request.
If this is expected, no action is needed.
Learn More. Ask AI.

@mergify mergify Bot removed the needs-cloudposse Needs Cloud Posse assistance label Jun 14, 2026
@github-actions

Copy link
Copy Markdown

Warning

Release Documentation Required

This PR is labeled minor or major and requires documentation updates:

  • Changelog entry - Add a blog post in website/blog/YYYY-MM-DD-feature-name.mdx
  • Roadmap update - Update website/src/data/roadmap.js with the new milestone

Alternatively: If this change doesn't require release documentation, remove the minor or major label.

@github-actions

Copy link
Copy Markdown

These changes were released in v1.222.0-rc.0.

Erik Osterman (Cloud Posse) (osterman) added a commit that referenced this pull request Aug 3, 2026
These nine carried `authors: [atmos]`, the generic team byline the changelog
skill says to avoid. Attribution follows the pull request that implemented the
feature, not the commit that added or later renamed the post file.

That distinction mattered. Five of the nine appear in `git log --diff-filter=A`
as added by #2753, a chronology-correction pass that renamed post files to match
their publication dates. Following renames instead points at the real work:

  list-components-fix                    #1949  osterman
  chdir-config-isolation                 #1941  osterman
  introducing-atmos-lsp                  #2030  aknysh
  introducing-atmos-ai                   #2030  aknysh
  ci-comments-env-var                    #2300  osterman
  list-instances-matrix                  #2322  johncblandii
  terraform-all-dependency-order-wired-up #2486  thejrose1984
  dotenv-include-support                 #1930  osterman
  toolchain-proxies                      #1687  osterman

Each byline is the GitHub pull request author rather than the git commit author,
because squash merges attribute the commit to whoever merged it.

#2300 needed a judgment call. It was authored by `app/copilot-swe-agent`, a bot.
The byline goes to osterman, who is the assignee and the human who drove the
change. A bot is not a contributor byline, and the person who merged it (aknysh)
did not do the work either.

johncblandii and thejrose1984 were missing from `authors.yml` and are added here,
which the changelog skill requires in the same change that references them.
thejrose1984 publishes no display name on GitHub, so the login stands in rather
than inventing one.

Verified: all 263 posts now resolve to a real `authors.yml` entry, no post
carries the generic byline, and the site builds with no author warnings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
preview — 35f4a595 Deployed Jun 14, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor New features that do not break anything size/l Large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants