Skip to content

feat: Add file-scoped locals to stack configurations#1883

Merged
aknysh merged 5 commits intomainfrom
osterman/locals-prd
Dec 17, 2025
Merged

feat: Add file-scoped locals to stack configurations#1883
aknysh merged 5 commits intomainfrom
osterman/locals-prd

Conversation

@osterman
Copy link
Copy Markdown
Member

@osterman osterman commented Dec 17, 2025

what

Implements file-scoped locals for Atmos stack manifests, enabling temporary variables that reduce repetition and improve readability. Locals are resolved in dependency order with automatic cycle detection.

  • File-scoped locals: Define at global, component-type (terraform/helmfile/packer), or component level
  • Dependency resolution: Locals can reference other locals with topological sorting
  • Circular dependency detection: Clear error messages for circular references
  • File-scoped isolation: Locals do not inherit across imports (unlike vars)
  • Provenance tracking: atmos describe locals command shows where each local is defined

why

Users working with complex stack configurations often repeat values (naming conventions, tags, etc.) across multiple components. File-scoped locals provide a DRY solution similar to Terraform and Terragrunt, reducing error-prone manual repetition and making configurations more maintainable.

references

  • PRD: docs/prd/file-scoped-locals.md
  • Blog post: website/blog/2025-12-16-file-scoped-locals.mdx
  • Test scenarios: tests/fixtures/scenarios/locals/ and tests/fixtures/scenarios/locals-circular/

Summary by CodeRabbit

  • New Features

    • File-scoped locals: declare temporary variables (global, component-type, component) with templating, dependency-aware resolution, deterministic ordering, and circular-dependency detection; locals are isolated to their file and injected during template processing.
  • Schema

    • Manifest/schema updates to allow a locals section across supported component/tool scopes.
  • Documentation

    • PRD, user docs, CLI/describe updates, and a blog post with examples and guidance.
  • Tests

    • Extensive unit and fixture tests covering resolution, templating, inheritance within a file, cycles, and error cases.

✏️ Tip: You can customize this high-level summary in your review settings.

Implements file-scoped locals for Atmos stack manifests, similar to Terraform and Terragrunt. Locals enable temporary variables that are available within a single file with dependency resolution and circular dependency detection.

Key features:
- Locals defined at global, component-type, and component scopes
- Dependency resolution using topological sorting
- Circular dependency detection with clear error messages
- File-scoped isolation (no inheritance across imports)
- Integration with describe locals command with provenance tracking

Includes comprehensive test scenarios and documentation.

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@osterman osterman requested a review from a team as a code owner December 17, 2025 03:55
@github-actions github-actions bot added the size/xl Extra large size PR label Dec 17, 2025
@osterman osterman added the minor New features that do not break anything label Dec 17, 2025
@mergify
Copy link
Copy Markdown

mergify bot commented Dec 17, 2025

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.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 17, 2025

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@codecov
Copy link
Copy Markdown

codecov bot commented Dec 17, 2025

Codecov Report

❌ Patch coverage is 93.91101% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.20%. Comparing base (41250de) to head (9c292d7).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/locals/resolver.go 93.01% 10 Missing and 6 partials ⚠️
pkg/template/ast.go 90.82% 5 Missing and 5 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1883      +/-   ##
==========================================
+ Coverage   73.00%   73.20%   +0.19%     
==========================================
  Files         606      609       +3     
  Lines       56339    56766     +427     
==========================================
+ Hits        41133    41553     +420     
  Misses      12293    12293              
- Partials     2913     2920       +7     
Flag Coverage Δ
unittests 73.20% <93.91%> (+0.19%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
errors/errors.go 100.00% <ø> (ø)
internal/exec/stack_processor_locals.go 100.00% <100.00%> (ø)
pkg/template/ast.go 90.82% <90.82%> (ø)
pkg/locals/resolver.go 93.01% <93.01%> (ø)

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 17, 2025

📝 Walkthrough

Walkthrough

Adds file-scoped "locals": schema and constant, template AST utilities, a dependency-aware locals resolver with cycle detection and templating, stack-processing integration to extract/resolve/strip locals across scopes, tests, fixtures, PRD, and website/docs updates.

Changes

Cohort / File(s) Change Summary
Errors
errors/errors.go
Added locals-related error sentinels: ErrLocalsInvalidType, ErrLocalsCircularDep, ErrLocalsDependencyExtract, ErrLocalsResolution.
Config constant & schemas
pkg/config/const.go, pkg/datafetcher/schema/atmos/manifest/1.0.json, examples/.../schemas/atmos-manifest.json, tests/fixtures/schemas/.../atmos-manifest.json, website/static/schemas/.../atmos-manifest.json
Added LocalsSectionName constant and introduced locals definition/property across root and section schemas; relaxed some components object validation and removed obsolete stack usage in workflow/depends_on schemas.
Stack processing
internal/exec/stack_processor_locals.go, internal/exec/stack_processor_locals_test.go
Implemented locals extraction/resolution and lifecycle: ExtractAndResolveLocals, ProcessStackLocals, ResolveComponentLocals, StripLocalsFromSection, LocalsContext, merging/inheritance semantics, instrumentation, and tests covering templating, cycles, merging, stripping, and errors.
Locals resolver
pkg/locals/resolver.go, pkg/locals/resolver_test.go
New Resolver building dependency graph from template AST, topological sort and DFS cycle detection, recursive resolution of strings/maps/slices using templates (Sprig), parent merging, detailed errors, GetDependencies, and comprehensive unit tests.
Template AST utilities
pkg/template/ast.go, pkg/template/ast_test.go
Added FieldRef and AST helpers: ExtractFieldRefs, ExtractFieldRefsByPrefix, ExtractAllFieldRefsByPrefix, HasTemplateActions, AST walkers, and tests.
Docs & PRD
docs/prd/file-scoped-locals.md, website/blog/2025-12-16-file-scoped-locals.mdx, website/docs/**/locals*.mdx, other site updates
New PRD, blog post, and multiple documentation pages/CLI notes describing locals, scopes, rules, examples, and describe output changes.
Fixtures & examples
tests/fixtures/scenarios/locals/*, tests/fixtures/scenarios/locals-circular/*, examples/demo-*/schemas/*, examples/demo-context/schemas/atmos-manifest.json
Added manifest fixtures demonstrating locals usage (dev/prod), mixin isolation, circular-deps scenario, and updated example schemas to include locals support.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant File as ManifestFile
  participant Processor as StackProcessor
  participant Resolver as LocalsResolver
  participant AST as TemplateAST
  participant Parent as ParentLocals

  Note over File,Processor: Process manifest file
  Processor->>File: Extract `locals` section
  Processor->>Resolver: NewResolver(locals, filePath)
  Resolver->>AST: ExtractFieldRefs(locals) → dependencies
  AST-->>Resolver: Field references
  Resolver->>Resolver: buildDependencyGraph() / topologicalSort()
  alt cycle detected
    Resolver-->>Processor: ErrLocalsCircularDep (cycle info)
  else no cycle
    Resolver->>Parent: merge parentLocals (if provided)
    Resolver->>Resolver: resolve locals in topo order
    Resolver->>AST: render templates with merged context
    AST-->>Resolver: evaluated values
    Resolver-->>Processor: resolved locals map
    Processor->>Processor: merge scope locals and StripLocalsFromSection
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus review on:
    • pkg/locals/resolver.go — dependency extraction, topo sort, DFS cycle detection, template rendering and error messages
    • internal/exec/stack_processor_locals.go — scope merging, inheritance semantics, stripping to avoid cross-file leakage
    • pkg/template/ast.go — AST traversal correctness and prefix extraction edge cases
    • JSON schema updates — consistent placement of locals and any implications for tooling/validation

Suggested reviewers

  • osterman

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.51% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature being added: file-scoped locals for stack configurations, which is the core objective of this comprehensive PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch osterman/locals-prd

📜 Recent 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 b1f34e9 and 9c292d7.

📒 Files selected for processing (6)
  • docs/prd/file-scoped-locals.md (1 hunks)
  • pkg/locals/resolver.go (1 hunks)
  • pkg/locals/resolver_test.go (1 hunks)
  • pkg/template/ast.go (1 hunks)
  • pkg/template/ast_test.go (1 hunks)
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/template/ast.go
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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: NEVER use fmt.Fprintf(os.Stdout/Stderr) or fmt.Println(); use data.* or ui.* functions instead
All comments must end with periods (enforced by godot linter)
Organize imports in three groups separated by blank lines, sorted alphabetically: 1) Go stdlib, 2) 3rd-party (NOT cloudposse/atmos), 3) Atmos packages; maintain aliases: cfg, log, u, errUtils
Add defer perf.Track(atmosConfig, "pkg.FuncName")() + blank line to all public functions for performance tracking; use nil if no atmosConfig param
All errors MUST be wrapped using static errors defined in errors/errors.go; use errors.Join for combining multiple errors; use fmt.Errorf with %w for adding string context; use error builder for complex errors; use errors.Is() for error checking; NEVER use dynamic errors directly
Use go.uber.org/mock/mockgen with //go:generate directives for mock generation; never create manual mocks
Keep files small...

Files:

  • pkg/locals/resolver_test.go
  • pkg/template/ast_test.go
  • pkg/locals/resolver.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

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + dependency injection for testability; generate mocks with go.uber.org/mock/mockgen; use table-driven tests; target >80% coverage
Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Files:

  • pkg/locals/resolver_test.go
  • pkg/template/ast_test.go
docs/prd/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

All Product Requirement Documents (PRDs) MUST be placed in docs/prd/ with kebab-case filenames

Files:

  • docs/prd/file-scoped-locals.md
🧠 Learnings (10)
📓 Common learnings
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: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
📚 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/locals/resolver_test.go
  • pkg/template/ast_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*_test.go : Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Applied to files:

  • pkg/locals/resolver_test.go
  • pkg/template/ast_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 : Use table-driven tests for testing multiple scenarios in Go

Applied to files:

  • pkg/locals/resolver_test.go
  • pkg/template/ast_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/locals/resolver_test.go
  • pkg/template/ast_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : Keep files small and focused (<600 lines); one cmd/impl per file; co-locate tests; never use //revive:disable:file-length-limit

Applied to files:

  • pkg/locals/resolver_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests; use interfaces + dependency injection for testability; generate mocks with go.uber.org/mock/mockgen; use table-driven tests; target >80% coverage

Applied to files:

  • pkg/template/ast_test.go
📚 Learning: 2025-01-25T03:51:57.689Z
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.

Applied to files:

  • docs/prd/file-scoped-locals.md
📚 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:

  • docs/prd/file-scoped-locals.md
📚 Learning: 2025-12-13T06:07:34.794Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:34.794Z
Learning: For docs in the cloudposse/atmos repository under docs/prd/, markdownlint issues MD040, MD010, and MD034 should be deferred to a separate documentation cleanup commit and must not block the current PR. If needed, address these issues in a follow-up PR dedicated to documentation improvements.

Applied to files:

  • docs/prd/file-scoped-locals.md
🧬 Code graph analysis (2)
pkg/locals/resolver_test.go (3)
pkg/locals/resolver.go (1)
  • NewResolver (37-46)
errors/errors.go (1)
  • ErrLocalsCircularDep (664-664)
cmd/cmd_utils.go (1)
  • Contains (1257-1264)
pkg/template/ast_test.go (1)
pkg/template/ast.go (5)
  • ExtractFieldRefs (29-61)
  • ExtractFieldRefsByPrefix (66-86)
  • ExtractAllFieldRefsByPrefix (205-226)
  • HasTemplateActions (172-199)
  • FieldRef (15-17)
🪛 LanguageTool
docs/prd/file-scoped-locals.md

[grammar] ~297-~297: Please add a punctuation mark at the end of paragraph.
Context: ...r, making each available for subsequent locals ``` Example: locals = {c: "{{.locals.b...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~386-~386: Consider using typographic quotation marks here.
Context: ...mplate context instead. ### No Special "Promote" Syntax To use a local value in vars/se...

(EN_QUOTES)


[typographical] ~438-~438: To join two clauses or introduce examples, consider using an em dash.
Context: ...tation ### New Package: pkg/template/ - Template AST Utilities The locals featu...

(DASH_RULE)


[typographical] ~443-~443: Consider using a typographic close quote here.
Context: ...* - "prefer pkg/ over internal/exec/" 3. Enables future enhancements - De...

(EN_QUOTES)


[typographical] ~446-~446: To join two clauses or introduce examples, consider using an em dash.
Context: ...dation, etc. #### pkg/template/ast.go - Template AST Inspection ```go package t...

(DASH_RULE)


[typographical] ~602-~602: To join two clauses or introduce examples, consider using an em dash.
Context: ...l } #### `pkg/template/ast_test.go` - Comprehensive Tests go package templ...

(DASH_RULE)


[typographical] ~721-~721: To join two clauses or introduce examples, consider using an em dash.
Context: ...cies - Existing IsGolangTemplate() - Could migrate to use `HasTemplateActions...

(DASH_RULE)


[typographical] ~722-~722: To join two clauses or introduce examples, consider using an em dash.
Context: ...TemplateActions()` - Future features - Template validation, dependency analysis...

(DASH_RULE)


[typographical] ~728-~728: To join two clauses or introduce examples, consider using an em dash.
Context: ...to Create #### pkg/locals/resolver.go - Core Locals Resolution ```go package lo...

(DASH_RULE)


[typographical] ~950-~950: To join two clauses or introduce examples, consider using an em dash.
Context: ...to Modify #### 1. pkg/config/const.go - Add Constant ```go // Add to existing c...

(DASH_RULE)


[typographical] ~957-~957: To join two clauses or introduce examples, consider using an em dash.
Context: ...ack_processor_process_stacks_helpers.go` - Add to Processor Options ```go // Add t...

(DASH_RULE)


[typographical] ~972-~972: To join two clauses or introduce examples, consider using an em dash.
Context: .../exec/stack_processor_process_stacks.go` - Extract & Resolve Locals Integration po...

(DASH_RULE)


[typographical] ~1031-~1031: To join two clauses or introduce examples, consider using an em dash.
Context: ...or_process_stacks_helpers_extraction.go` - Component Locals Add extraction of comp...

(DASH_RULE)


[typographical] ~1058-~1058: To join two clauses or introduce examples, consider using an em dash.
Context: ...### 5. internal/exec/template_utils.go - Add Locals to Template Context When bui...

(DASH_RULE)


[typographical] ~1074-~1074: To join two clauses or introduce examples, consider using an em dash.
Context: ...internal/exec/stack_processor_merge.go - Exclude Locals from Merge Ensure locals...

(DASH_RULE)


[typographical] ~1095-~1095: To join two clauses or introduce examples, consider using an em dash.
Context: ...her/schema/stacks/stack-config/1.0.json- Schema Updates Addlocals` to allowed ...

(DASH_RULE)


[grammar] ~1153-~1153: Please add a punctuation mark at the end of paragraph.
Context: ...s describe locals command, follow this pattern 2. **Flag Handling** (pkg/flags/`): ...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1355-~1355: Consider using a typographic opening quote here.
Context: ...lable locals list - Add typo detection ("did you mean?") using Levenshtein distan...

(EN_QUOTES)


[typographical] ~1355-~1355: Consider using a typographic close quote here.
Context: ...ist - Add typo detection ("did you mean?") using Levenshtein distance **Optional...

(EN_QUOTES)


[grammar] ~1355-~1355: Please add a punctuation mark at the end of paragraph.
Context: ...ion ("did you mean?") using Levenshtein distance Optional: Migrate IsGolangTemplate...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1391-~1391: Consider using typographic quotation marks here.
Context: ...]string- Filter refs by prefix (e.g., "locals") -walkAST(node, fn)` - Recursive AST ...

(EN_QUOTES)


[grammar] ~1393-~1393: Please add a punctuation mark at the end of paragraph.
Context: ...l` - Detect if string contains template actions Test coverage: - Simple field refs...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1619-~1619: Consider using a typographic opening quote here.
Context: ...locals on failure - Typo detection with "did you mean?" suggestions - `atmos desc...

(EN_QUOTES)


[typographical] ~1619-~1619: Consider using a typographic close quote here.
Context: ...ure - Typo detection with "did you mean?" suggestions - atmos describe locals c...

(EN_QUOTES)


[grammar] ~1779-~1779: Please add a punctuation mark at the end of paragraph.
Context: ...omponentEnvSection` - Contains resolved values **2. Stack Processor (where locals are...

(PUNCTUATION_PARAGRAPH_END)


[style] ~1790-~1790: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...g/component/provider.go:** No changes needed. The ComponentConfig map[string]any` a...

(EN_REPEATEDWORDS_NEED)

🪛 markdownlint-cli2 (0.18.1)
docs/prd/file-scoped-locals.md

299-299: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1383-1383: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1408-1408: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1486-1486: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1576-1576: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1594-1594: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1751-1751: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ 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). (3)
  • GitHub Check: Acceptance Tests (macos)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary
🔇 Additional comments (26)
pkg/template/ast_test.go (6)

11-70: LGTM! Comprehensive table-driven tests for field reference extraction.

The test covers all essential scenarios: simple fields, nesting, duplicates, and edge cases. Good use of table-driven patterns and proper nil handling.


72-208: Excellent comprehensive test coverage for prefix-based extraction.

The 22 test cases cover complex template scenarios including conditionals, pipes, ranges, with blocks, and edge cases. The deterministic sorting ensures reliable test execution.


210-249: LGTM! Tests verify full-path extraction correctly.

The tests clearly demonstrate the distinction between single-level and full-path extraction, with proper deterministic sorting.


251-271: LGTM! Action detection tests cover key scenarios.

Tests verify detection of various template actions and correctly handle non-template content.


273-291: LGTM! String representation tests are complete.

Covers all path variations including edge cases like nil and empty paths.


293-442: LGTM! Comprehensive edge case coverage.

The additional tests cover error conditions, complex template constructs, and corner cases. Particularly good coverage of:

  • Invalid template handling
  • Context changes in with blocks
  • Pipe declarations and command arguments
  • Nested control structures (range/if chains)
  • else-if chains

The test suite demonstrates thorough behavior testing as per coding guidelines.

docs/prd/file-scoped-locals.md (6)

1-25: LGTM! Clear problem statement and solution overview.

The PRD effectively establishes the need for file-scoped locals and distinguishes them from existing vars and settings sections.


26-203: Excellent user-facing documentation with practical examples.

The examples effectively demonstrate:

  • Basic locals usage
  • Dependency resolution and order independence
  • Circular dependency detection
  • Scope hierarchy
  • File isolation behavior

The comparison table on line 196 provides a clear reference for when to use locals vs. vars vs. settings.


204-274: LGTM! Clear error handling and edge case documentation.

The error message examples provide excellent guidance for users, especially the hints about file-scoped behavior and cross-file references.


276-723: LGTM! Thorough implementation guidance.

The processing order, resolution algorithm, and design decisions are well-documented. The topological sort algorithm example (lines 299-308) effectively explains the resolution process.


724-1361: LGTM! Implementation details align with actual code.

The code examples and integration points in the PRD match the implementation in the PR. The test strategy section provides good guidance for comprehensive testing.


1362-1834: LGTM! Complete implementation plan and success criteria.

The phased implementation approach, risk mitigation, and debugging support are well-thought-out. The component registry analysis (lines 1732-1832) correctly identifies that locals are consumed during stack processing and don't need to be passed to component providers.

Based on learnings, the markdownlint issues (MD040 for missing code fence languages) can be addressed in a separate documentation cleanup commit.

pkg/locals/resolver_test.go (6)

14-75: LGTM! Core resolution functionality well-tested.

The basic tests cover essential scenarios: simple resolution, chained dependencies, order independence, and parent scope access. All tests follow best practices with clear names and appropriate assertions.


77-104: LGTM! Cycle detection tests follow coding guidelines.

The tests correctly use errors.Is() to check for the sentinel error (line 88), following the error handling guidelines. Good coverage of both multi-node cycles and self-references.


106-261: LGTM! Comprehensive value type coverage.

The tests thoroughly verify handling of:

  • Non-string values (numbers, booleans, collections)
  • Empty and nil cases
  • Templates in strings, maps, and slices (including nested structures)
  • Sprig template functions
  • Conditional templates

Good coverage of both happy paths and edge cases.


263-314: LGTM! Dependency graph and parent scope tests are solid.

The tests verify that:

  • Dependency graphs are built correctly
  • Parent local references don't create false cycles
  • Child locals can override parent locals

315-412: LGTM! Error handling and complex dependency tests are thorough.

The tests verify:

  • Clear error messages for undefined locals
  • Invalid template syntax handling
  • Complex dependency patterns (diamond, chains)
  • Helpful error messages that list available locals

Good attention to user experience in error cases.


414-615: LGTM! Comprehensive coverage of complex scenarios and edge cases.

The remaining tests thoroughly cover:

  • Complex cycle detection patterns
  • Deeply nested structures with dependencies
  • Mixed type handling in collections
  • Large cycles and multiple self-references
  • Parent scope interactions with dependency graphs

The test suite demonstrates >80% coverage target and follows table-driven patterns where appropriate.

Note: File is 615 lines (slightly over the 600-line guideline), but this is acceptable given the comprehensive test coverage required for a critical feature.

pkg/locals/resolver.go (8)

1-24: LGTM! Package documentation and imports follow guidelines.

The package documentation clearly explains the key features (file-scoped, dependency resolution, cycle detection, multi-scope). Import organization follows the three-group pattern with proper aliases.


26-46: LGTM! Resolver struct and constructor are well-designed.

The struct fields are clearly documented, and the constructor follows the guideline of adding defer perf.Track() to public functions.


48-93: LGTM! Main Resolve method is well-structured.

The method follows a clear algorithm:

  1. Handle edge cases
  2. Build dependency graph
  3. Topological sort with cycle detection
  4. Merge parent locals
  5. Resolve in sorted order

Good use of perf tracking and clear step-by-step comments.


95-172: LGTM! Dependency extraction follows coding guidelines.

The dependency extraction correctly:

  • Wraps errors with static error sentinel ErrLocalsDependencyExtract using %w (line 103)
  • Uses template AST utilities from pkg/template for field reference extraction
  • Handles recursive structures (maps, slices)
  • Deduplicates dependencies

174-258: LGTM! Topological sort correctly implements Kahn's algorithm.

The implementation:

  • Wraps cycle errors with ErrLocalsCircularDep sentinel (line 189)
  • Uses Kahn's algorithm for topological ordering
  • Ensures deterministic results with sort.Strings() (lines 220, 255)
  • Properly separates concerns with focused helper methods

260-348: LGTM! Cycle detection correctly implements DFS.

The DFS-based cycle detection:

  • Ensures deterministic cycle finding with sorted names (line 285)
  • Properly handles recursion stack for cycle detection
  • Skips parent scope dependencies to avoid false positives
  • Formats cycle paths clearly for error messages

350-443: LGTM! Value resolution with helpful error messages.

The resolution methods:

  • Use Sprig template functions (line 405)
  • Enable strict missing key checking with missingkey=error (line 411)
  • Provide helpful error messages listing available locals (line 417)
  • Recursively handle nested structures (maps, slices)
  • Quick-exit for strings without template delimiters (line 395)

445-454: LGTM! GetDependencies provides safe access for debugging.

The method correctly returns a copy of the dependency graph to prevent external mutation, and includes perf tracking as per guidelines.


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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 (5)
pkg/template/ast.go (2)

20-24: perf.Track on a trivial string join may add overhead without benefit.

FieldRef.String() is a simple strings.Join. The deferred perf.Track call likely costs more than the operation itself. Consider removing instrumentation from this micro-method.

 func (f FieldRef) String() string {
-	defer perf.Track(nil, "template.FieldRef.String")()
-
 	return strings.Join(f.Path, ".")
 }

190-198: Consider early exit once an action is found.

The walk continues even after hasActions becomes true. An early return would avoid unnecessary traversal.

 hasActions := false
+done := false
 walkAST(tree.Root, func(node parse.Node) {
+	if done {
+		return
+	}
 	switch node.(type) {
 	case *parse.ActionNode, *parse.IfNode, *parse.RangeNode, *parse.WithNode:
 		hasActions = true
+		done = true
 	}
 })

Alternatively, consider a dedicated walk function that returns a bool to allow short-circuiting.

internal/exec/stack_processor_locals.go (2)

138-152: Consider moving type definition before its first use.

LocalsContext is returned by ProcessStackLocals on line 90, but defined on line 140. Moving the type definition earlier improves readability.


187-209: Inconsistent return semantics: copy vs original.

When locals key exists, a copy is returned. When it doesn't, the original section is returned. This could surprise callers who expect consistent behavior. Consider always returning a copy, or document this nuance clearly.

 // If no locals section, return as-is.
 if _, exists := section[cfg.LocalsSectionName]; !exists {
-	return section
+	// Return as-is (no copy needed since no mutation required).
+	return section
 }

At minimum, the comment clarifies intent. Alternatively, always copy for predictable behavior.

pkg/locals/resolver.go (1)

239-253: Sorting after every insertion is inefficient for large graphs.

sort.Strings(queue) on line 247 runs after every new node is added. For n nodes with k average dependents, this is O(n * k * n log n). For typical usage (few locals), this is fine. For pathological cases, consider a priority queue.

Not urgent—likely acceptable for expected local counts.

📜 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 40387cd and ee65bef.

📒 Files selected for processing (17)
  • docs/prd/file-scoped-locals.md (1 hunks)
  • errors/errors.go (1 hunks)
  • internal/exec/stack_processor_locals.go (1 hunks)
  • internal/exec/stack_processor_locals_test.go (1 hunks)
  • pkg/config/const.go (1 hunks)
  • pkg/datafetcher/schema/atmos/manifest/1.0.json (8 hunks)
  • pkg/locals/resolver.go (1 hunks)
  • pkg/locals/resolver_test.go (1 hunks)
  • pkg/template/ast.go (1 hunks)
  • pkg/template/ast_test.go (1 hunks)
  • tests/fixtures/scenarios/locals-circular/atmos.yaml (1 hunks)
  • tests/fixtures/scenarios/locals-circular/stacks/deploy/circular.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/atmos.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/stacks/mixins/region.yaml (1 hunks)
  • website/blog/2025-12-16-file-scoped-locals.mdx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.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: NEVER use fmt.Fprintf(os.Stdout/Stderr) or fmt.Println(); use data.* or ui.* functions instead
All comments must end with periods (enforced by godot linter)
Organize imports in three groups separated by blank lines, sorted alphabetically: 1) Go stdlib, 2) 3rd-party (NOT cloudposse/atmos), 3) Atmos packages; maintain aliases: cfg, log, u, errUtils
Add defer perf.Track(atmosConfig, "pkg.FuncName")() + blank line to all public functions for performance tracking; use nil if no atmosConfig param
All errors MUST be wrapped using static errors defined in errors/errors.go; use errors.Join for combining multiple errors; use fmt.Errorf with %w for adding string context; use error builder for complex errors; use errors.Is() for error checking; NEVER use dynamic errors directly
Use go.uber.org/mock/mockgen with //go:generate directives for mock generation; never create manual mocks
Keep files small...

Files:

  • errors/errors.go
  • pkg/template/ast.go
  • pkg/template/ast_test.go
  • internal/exec/stack_processor_locals.go
  • pkg/config/const.go
  • internal/exec/stack_processor_locals_test.go
  • pkg/locals/resolver_test.go
  • pkg/locals/resolver.go
docs/prd/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

All Product Requirement Documents (PRDs) MUST be placed in docs/prd/ with kebab-case filenames

Files:

  • docs/prd/file-scoped-locals.md
**/*_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

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + dependency injection for testability; generate mocks with go.uber.org/mock/mockgen; use table-driven tests; target >80% coverage
Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Files:

  • pkg/template/ast_test.go
  • internal/exec/stack_processor_locals_test.go
  • pkg/locals/resolver_test.go
website/**

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

website/**: Update website documentation in the website/ directory when adding new features, ensure consistency between CLI help text and website documentation, and follow the website's documentation structure and style
Keep website code in the website/ directory, follow the existing website architecture and style, and test website changes locally before committing
Keep CLI documentation and website documentation in sync and document new features on the website with examples and use cases

Files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
website/blog/**/*.mdx

📄 CodeRabbit inference engine (CLAUDE.md)

website/blog/**/*.mdx: Follow PR template (what/why/references); PRs labeled minor/major MUST include blog post at website/blog/YYYY-MM-DD-feature-name.mdx with YAML front matter, after intro, and only tags from website/blog/tags.yml
Blog posts MUST use only tags defined in website/blog/tags.yml and authors defined in website/blog/authors.yml; valid tags are: feature, enhancement, bugfix, dx, breaking-change, security, documentation, deprecation, core; never invent new tags

Files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
🧠 Learnings (40)
📓 Common learnings
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: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
📚 Learning: 2025-10-02T19:17:51.630Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1504
File: pkg/profiler/profiler.go:20-31
Timestamp: 2025-10-02T19:17:51.630Z
Learning: In pkg/profiler/profiler.go, profiler-specific errors (ErrUnsupportedProfileType, ErrStartCPUProfile, ErrStartTraceProfile, ErrCreateProfileFile) must remain local and cannot be moved to errors/errors.go due to an import cycle: pkg/profiler → errors → pkg/schema → pkg/profiler. This is a valid exception to the centralized errors policy.

Applied to files:

  • errors/errors.go
📚 Learning: 2025-12-13T06:10:13.688Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.

Applied to files:

  • errors/errors.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : All errors MUST be wrapped using static errors defined in errors/errors.go; use errors.Join for combining multiple errors; use fmt.Errorf with %w for adding string context; use error builder for complex errors; use errors.Is() for error checking; NEVER use dynamic errors directly

Applied to files:

  • errors/errors.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 : 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

Applied to files:

  • errors/errors.go
📚 Learning: 2025-02-03T06:00:11.419Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 959
File: cmd/describe_config.go:20-20
Timestamp: 2025-02-03T06:00:11.419Z
Learning: Commands should use `PrintErrorMarkdownAndExit` with empty title and suggestion (`"", err, ""`) for general error handling. Specific titles like "Invalid Usage" or "File Not Found" should only be used for validation or specific error scenarios.

Applied to files:

  • errors/errors.go
📚 Learning: 2024-12-05T22:33:40.955Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 820
File: cmd/list_components.go:53-54
Timestamp: 2024-12-05T22:33:40.955Z
Learning: In the Atmos CLI Go codebase, using `u.LogErrorAndExit` within completion functions is acceptable because it logs the error and exits the command execution.

Applied to files:

  • errors/errors.go
📚 Learning: 2024-11-25T17:17:15.703Z
Learnt from: RoseSecurity
Repo: cloudposse/atmos PR: 797
File: pkg/list/atmos.yaml:213-214
Timestamp: 2024-11-25T17:17:15.703Z
Learning: The file `pkg/list/atmos.yaml` is primarily intended for testing purposes.

Applied to files:

  • tests/fixtures/scenarios/locals/stacks/mixins/region.yaml
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals-circular/stacks/deploy/circular.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
📚 Learning: 2025-12-13T06:07:34.794Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:34.794Z
Learning: For docs in the cloudposse/atmos repository under docs/prd/, markdownlint issues MD040, MD010, and MD034 should be deferred to a separate documentation cleanup commit and must not block the current PR. If needed, address these issues in a follow-up PR dedicated to documentation improvements.

Applied to files:

  • docs/prd/file-scoped-locals.md
📚 Learning: 2025-01-25T03:51:57.689Z
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.

Applied to files:

  • docs/prd/file-scoped-locals.md
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
📚 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/template/ast_test.go
  • pkg/locals/resolver_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/template/ast_test.go
  • internal/exec/stack_processor_locals_test.go
  • pkg/locals/resolver_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*_test.go : Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Applied to files:

  • pkg/template/ast_test.go
  • internal/exec/stack_processor_locals_test.go
  • pkg/locals/resolver_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/template/ast_test.go
  • internal/exec/stack_processor_locals_test.go
  • pkg/locals/resolver_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests; use interfaces + dependency injection for testability; generate mocks with go.uber.org/mock/mockgen; use table-driven tests; target >80% coverage

Applied to files:

  • pkg/template/ast_test.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_locals.go
  • internal/exec/stack_processor_locals_test.go
📚 Learning: 2024-11-19T23:00:45.899Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 795
File: internal/exec/stack_processor_utils.go:378-386
Timestamp: 2024-11-19T23:00:45.899Z
Learning: In the `ProcessYAMLConfigFile` function within `internal/exec/stack_processor_utils.go`, directory traversal in stack imports is acceptable and should not be restricted.

Applied to files:

  • internal/exec/stack_processor_locals.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:

  • internal/exec/stack_processor_locals.go
📚 Learning: 2025-10-08T06:48:07.499Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1602
File: internal/exec/stack_processor_utils.go:968-1003
Timestamp: 2025-10-08T06:48:07.499Z
Learning: The `FindComponentDependenciesLegacy` function in `internal/exec/stack_processor_utils.go` is legacy code that is not actively used and is kept only for backward compatibility purposes.

Applied to files:

  • internal/exec/stack_processor_locals.go
📚 Learning: 2024-10-20T00:57:53.500Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 731
File: internal/exec/validate_stacks.go:0-0
Timestamp: 2024-10-20T00:57:53.500Z
Learning: In `internal/exec/validate_stacks.go`, when downloading the Atmos JSON Schema file to the temp directory, the temporary file is overwritten each time, so explicit removal is not necessary.

Applied to files:

  • internal/exec/stack_processor_locals.go
📚 Learning: 2025-09-29T02:20:11.636Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/validate_component.go:117-118
Timestamp: 2025-09-29T02:20:11.636Z
Learning: The ValidateComponent function in internal/exec/validate_component.go had its componentSection parameter type refined from `any` to `map[string]any` without adding new parameters. This is a type safety improvement, not a signature change requiring call site updates.

Applied to files:

  • internal/exec/stack_processor_locals.go
📚 Learning: 2025-03-18T12:26:25.329Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1149
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:7-7
Timestamp: 2025-03-18T12:26:25.329Z
Learning: In the Atmos project, typos or inconsistencies in test snapshot files (such as "terrafrom" instead of "terraform") may be intentional as they capture the exact output of commands and should not be flagged as issues requiring correction.

Applied to files:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
📚 Learning: 2025-09-10T21:17:55.273Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/http_client_test.go:3-10
Timestamp: 2025-09-10T21:17:55.273Z
Learning: In the cloudposse/atmos repository, imports should never be changed as per samtholiya's coding guidelines.

Applied to files:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
📚 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:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
📚 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:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
📚 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:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • internal/exec/stack_processor_locals_test.go
  • tests/fixtures/scenarios/locals/atmos.yaml
📚 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:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
📚 Learning: 2025-09-24T20:45:40.401Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1475
File: tests/fixtures/scenarios/atmos-auth/stacks/deploy/nonprod.yaml:3-4
Timestamp: 2025-09-24T20:45:40.401Z
Learning: In Atmos stack files, the correct syntax for importing other stack files is `import:` (singular), not `imports:` (plural). All stack files in the Atmos codebase consistently use `import:` followed by a list of paths to import.

Applied to files:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
📚 Learning: 2024-12-01T00:33:20.298Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml:28-32
Timestamp: 2024-12-01T00:33:20.298Z
Learning: In `examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml`, `!exec atmos terraform output` is used in examples to demonstrate its usage, even though `!terraform.output` is the recommended approach according to the documentation.

Applied to files:

  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • website/blog/2025-12-16-file-scoped-locals.mdx
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
📚 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:

  • internal/exec/stack_processor_locals_test.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:

  • internal/exec/stack_processor_locals_test.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:

  • internal/exec/stack_processor_locals_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : Keep files small and focused (<600 lines); one cmd/impl per file; co-locate tests; never use //revive:disable:file-length-limit

Applied to files:

  • pkg/locals/resolver_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to website/blog/**/*.mdx : Follow PR template (what/why/references); PRs labeled minor/major MUST include blog post at website/blog/YYYY-MM-DD-feature-name.mdx with YAML front matter, <!--truncate--> after intro, and only tags from website/blog/tags.yml

Applied to files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to website/blog/**/*.mdx : Blog posts MUST use only tags defined in website/blog/tags.yml and authors defined in website/blog/authors.yml; valid tags are: feature, enhancement, bugfix, dx, breaking-change, security, documentation, deprecation, core; never invent new tags

Applied to files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
📚 Learning: 2024-12-03T04:01:16.446Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:0-0
Timestamp: 2024-12-03T04:01:16.446Z
Learning: In the `terraform.output.mdx` documentation file (`website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx`), the cache invalidation and cache scope behavior for the `!terraform.output` function are already described.

Applied to files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: New configs support Go templating with FuncMap() from internal/exec/template_funcs.go

Applied to files:

  • tests/fixtures/scenarios/locals/atmos.yaml
🧬 Code graph analysis (4)
pkg/template/ast.go (1)
pkg/perf/perf.go (1)
  • Track (121-138)
internal/exec/stack_processor_locals.go (4)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/config/const.go (4)
  • LocalsSectionName (71-71)
  • TerraformSectionName (81-81)
  • HelmfileSectionName (82-82)
  • PackerSectionName (83-83)
errors/errors.go (1)
  • ErrLocalsInvalidType (663-663)
pkg/locals/resolver.go (1)
  • NewResolver (37-46)
internal/exec/stack_processor_locals_test.go (2)
internal/exec/stack_processor_locals.go (5)
  • ExtractAndResolveLocals (16-47)
  • ProcessStackLocals (86-136)
  • LocalsContext (140-152)
  • ResolveComponentLocals (176-185)
  • StripLocalsFromSection (190-210)
pkg/config/const.go (3)
  • TerraformSectionName (81-81)
  • HelmfileSectionName (82-82)
  • PackerSectionName (83-83)
pkg/locals/resolver_test.go (2)
pkg/locals/resolver.go (1)
  • NewResolver (37-46)
cmd/cmd_utils.go (1)
  • Contains (1256-1263)
🪛 LanguageTool
docs/prd/file-scoped-locals.md

[grammar] ~297-~297: Please add a punctuation mark at the end of paragraph.
Context: ...r, making each available for subsequent locals ``` Example: locals = {c: "{{.locals.b...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~386-~386: Consider using typographic quotation marks here.
Context: ...mplate context instead. ### No Special "Promote" Syntax To use a local value in vars/se...

(EN_QUOTES)


[typographical] ~438-~438: To join two clauses or introduce examples, consider using an em dash.
Context: ...tation ### New Package: pkg/template/ - Template AST Utilities The locals featu...

(DASH_RULE)


[typographical] ~443-~443: Consider using a typographic close quote here.
Context: ...* - "prefer pkg/ over internal/exec/" 3. Enables future enhancements - De...

(EN_QUOTES)


[typographical] ~446-~446: To join two clauses or introduce examples, consider using an em dash.
Context: ...dation, etc. #### pkg/template/ast.go - Template AST Inspection ```go package t...

(DASH_RULE)


[typographical] ~602-~602: To join two clauses or introduce examples, consider using an em dash.
Context: ...l } #### `pkg/template/ast_test.go` - Comprehensive Tests go package templ...

(DASH_RULE)


[typographical] ~721-~721: To join two clauses or introduce examples, consider using an em dash.
Context: ...cies - Existing IsGolangTemplate() - Could migrate to use `HasTemplateActions...

(DASH_RULE)


[typographical] ~722-~722: To join two clauses or introduce examples, consider using an em dash.
Context: ...TemplateActions()` - Future features - Template validation, dependency analysis...

(DASH_RULE)


[typographical] ~728-~728: To join two clauses or introduce examples, consider using an em dash.
Context: ...to Create #### pkg/locals/resolver.go - Core Locals Resolution ```go package lo...

(DASH_RULE)


[typographical] ~966-~966: To join two clauses or introduce examples, consider using an em dash.
Context: ...to Modify #### 1. pkg/config/const.go - Add Constant ```go // Add to existing c...

(DASH_RULE)


[typographical] ~973-~973: To join two clauses or introduce examples, consider using an em dash.
Context: ...ack_processor_process_stacks_helpers.go` - Add to Processor Options ```go // Add t...

(DASH_RULE)


[typographical] ~988-~988: To join two clauses or introduce examples, consider using an em dash.
Context: .../exec/stack_processor_process_stacks.go` - Extract & Resolve Locals Integration po...

(DASH_RULE)


[typographical] ~1047-~1047: To join two clauses or introduce examples, consider using an em dash.
Context: ...or_process_stacks_helpers_extraction.go` - Component Locals Add extraction of comp...

(DASH_RULE)


[typographical] ~1074-~1074: To join two clauses or introduce examples, consider using an em dash.
Context: ...### 5. internal/exec/template_utils.go - Add Locals to Template Context When bui...

(DASH_RULE)


[typographical] ~1090-~1090: To join two clauses or introduce examples, consider using an em dash.
Context: ...internal/exec/stack_processor_merge.go - Exclude Locals from Merge Ensure locals...

(DASH_RULE)


[typographical] ~1111-~1111: To join two clauses or introduce examples, consider using an em dash.
Context: ...her/schema/stacks/stack-config/1.0.json- Schema Updates Addlocals` to allowed ...

(DASH_RULE)


[grammar] ~1169-~1169: Please add a punctuation mark at the end of paragraph.
Context: ...s describe locals command, follow this pattern 2. **Flag Handling** (pkg/flags/`): ...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1371-~1371: Consider using a typographic opening quote here.
Context: ...lable locals list - Add typo detection ("did you mean?") using Levenshtein distan...

(EN_QUOTES)


[typographical] ~1371-~1371: Consider using a typographic close quote here.
Context: ...ist - Add typo detection ("did you mean?") using Levenshtein distance **Optional...

(EN_QUOTES)


[grammar] ~1371-~1371: Please add a punctuation mark at the end of paragraph.
Context: ...ion ("did you mean?") using Levenshtein distance Optional: Migrate IsGolangTemplate...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1407-~1407: Consider using typographic quotation marks here.
Context: ...]string- Filter refs by prefix (e.g., "locals") -walkAST(node, fn)` - Recursive AST ...

(EN_QUOTES)


[grammar] ~1409-~1409: Please add a punctuation mark at the end of paragraph.
Context: ...l` - Detect if string contains template actions Test coverage: - Simple field refs...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1635-~1635: Consider using a typographic opening quote here.
Context: ...locals on failure - Typo detection with "did you mean?" suggestions - `atmos desc...

(EN_QUOTES)


[typographical] ~1635-~1635: Consider using a typographic close quote here.
Context: ...ure - Typo detection with "did you mean?" suggestions - atmos describe locals c...

(EN_QUOTES)


[grammar] ~1795-~1795: Please add a punctuation mark at the end of paragraph.
Context: ...omponentEnvSection` - Contains resolved values **2. Stack Processor (where locals are...

(PUNCTUATION_PARAGRAPH_END)


[style] ~1806-~1806: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...g/component/provider.go:** No changes needed. The ComponentConfig map[string]any` a...

(EN_REPEATEDWORDS_NEED)

website/blog/2025-12-16-file-scoped-locals.mdx

[typographical] ~325-~325: To join two clauses or introduce examples, consider using an em dash.
Context: ...plates](/core-concepts/stacks/templates) - Go templating in stack manifests - [Conf...

(DASH_RULE)


[typographical] ~326-~326: To join two clauses or introduce examples, consider using an em dash.
Context: ...nance](/cli/commands/describe/component) - Track where values come from - [YAML Fun...

(DASH_RULE)


[typographical] ~327-~327: To join two clauses or introduce examples, consider using an em dash.
Context: ...s](/core-concepts/stacks/yaml-functions) - Dynamic configuration with `!terraform.o...

(DASH_RULE)

🪛 markdownlint-cli2 (0.18.1)
docs/prd/file-scoped-locals.md

207-207: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


218-218: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


227-227: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


299-299: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1399-1399: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1424-1424: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1502-1502: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1592-1592: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1610-1610: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1767-1767: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ 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). (3)
  • GitHub Check: Acceptance Tests (macos)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Summary
🔇 Additional comments (62)
pkg/config/const.go (1)

71-71: LGTM!

The LocalsSectionName constant follows the established naming pattern and integrates cleanly with existing section constants.

tests/fixtures/scenarios/locals/stacks/mixins/region.yaml (1)

1-10: LGTM!

This mixin fixture correctly demonstrates file-scoped isolation of locals. The comment clarifies the expected behavior: locals defined here should not propagate to importing files.

tests/fixtures/scenarios/locals-circular/stacks/deploy/circular.yaml (1)

1-18: LGTM!

This fixture correctly models a circular dependency chain for testing error detection. The three-node cycle (a → b → c → a) should be caught by the resolver.

tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml (1)

1-45: LGTM!

This fixture comprehensively exercises locals at all three scopes (global, component-type, and component). The dependency chains are well-structured and demonstrate the intended resolution behavior.

tests/fixtures/scenarios/locals-circular/atmos.yaml (1)

1-31: LGTM!

Config properly enables template processing for locals resolution. The single evaluation pass is appropriate since locals are resolved before other sections.

errors/errors.go (1)

661-666: LGTM!

The Locals error sentinels follow established patterns and provide clear, actionable messages for each failure mode in the locals resolution workflow.

pkg/datafetcher/schema/atmos/manifest/1.0.json (3)

31-33: LGTM!

Top-level locals property properly added to the schema.


210-212: LGTM!

Locals references are consistently added across all component-type and component manifest scopes (terraform, helmfile, packer).

Also applies to: 285-287, 335-337, 395-397, 427-429, 487-489


709-722: LGTM!

The locals definition clearly documents the file-scoped behavior and matches the pattern of other section definitions. The description explicitly calls out the non-inheritance characteristic.

tests/fixtures/scenarios/locals/atmos.yaml (1)

1-34: LGTM!

Config properly enables template processing and excludes mixin files from stack processing. The exclusion patterns ensure mixins are only imported, not treated as standalone stacks.

website/blog/2025-12-16-file-scoped-locals.mdx (3)

1-10: Front matter looks good.

Valid tags (feature, dx), proper author reference, and correct date format. The <!--truncate--> marker is correctly placed after the intro.


110-117: Terminal component example is clear.

The circular dependency error example effectively demonstrates the user experience. The cycle notation a → b → c → a matches what the implementation produces.


321-328: Fix broken documentation links in Related Features section.

The blog post references documentation paths that don't exist or are incorrect:

  • /core-concepts/stacks/locals — no documentation exists for this
  • /core-concepts/stacks/templates — should be /templates
  • /cli/commands/describe/component — ✓ correct
  • /core-concepts/stacks/yaml-functions — should be /functions/yaml

Update the links to reference the actual documentation paths.

⛔ Skipped due to learnings
Learnt from: osterman
Repo: cloudposse/atmos PR: 1588
File: website/docs/learn/mindset.mdx:36-39
Timestamp: 2025-12-04T02:40:41.767Z
Learning: In Docusaurus documentation, when a sidebar category has a `link` configuration like `link: {type: "doc", id: "quick-start/simple/simple"}`, the category URL path (e.g., `/quick-start/simple`) correctly resolves to the linked document. Links should use the shorter category path, not the full document path, as this is the proper Docusaurus routing pattern.
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 website/** : Update website documentation in the `website/` directory when adding new features, ensure consistency between CLI help text and website documentation, and follow the website's documentation structure and style
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:0-0
Timestamp: 2024-12-03T04:01:16.446Z
Learning: In the `terraform.output.mdx` documentation file (`website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx`), the cache invalidation and cache scope behavior for the `!terraform.output` function are already described.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml:28-32
Timestamp: 2024-12-01T00:33:20.298Z
Learning: In `examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml`, `!exec atmos terraform output` is used in examples to demonstrate its usage, even though `!terraform.output` is the recommended approach according to the documentation.
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: aknysh
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-01-19T22:30:27.600Z
Learning: The Atmos YAML function `!include` allows downloading local or remote files from different sources and assigning their contents to sections in stack manifests. It supports various protocols (file, http, git, s3, etc.) and can filter content using YQ expressions.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:104-110
Timestamp: 2024-12-03T03:49:30.395Z
Learning: In the documentation for `!terraform.output`, warnings about template variable availability are already covered in other sections, so no need to suggest adding them here.
pkg/locals/resolver_test.go (7)

1-9: Imports are correctly organized.

Standard library first, then third-party. Good.


11-56: Core resolution tests are solid.

Good coverage of simple, chained, and order-independent resolution. These validate the topological sort behavior.


74-100: Cycle detection tests are thorough.

Both multi-node cycles and self-references are covered. The assertions check for "circular dependency" and the arrow notation.


102-146: Edge case handling is well tested.

Non-string values pass through, empty locals return empty maps, nil locals handled gracefully. Parent-only scenarios also covered.


163-190: Sprig function and conditional template tests add value.

These ensure the resolver integrates properly with Go template functionality.


259-278: GetDependencies test validates dependency graph construction.

Sorting before comparison ensures deterministic assertions. The diamond dependency test (lines 336-358) is particularly valuable for validating complex DAG handling.


311-334: Error case tests verify proper failure modes.

Undefined local and invalid template syntax both produce appropriate errors with context (file path included).

tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml (3)

1-26: Global locals and vars setup is correct.

The fixture demonstrates the key feature: locals referencing other locals (name_prefix references namespace and environment, full_name references name_prefix). Vars referencing locals is also shown.


27-40: Terraform-scope locals inheritance works well.

backend_bucket references global locals (namespace, environment), demonstrating the scope chain. The backend config then uses the resolved local.


41-66: Component-level locals are properly structured.

Both mock/instance-1 and mock/instance-2 define component-specific locals that reference parent scopes. Good symmetry for testing consistency.

pkg/template/ast_test.go (6)

1-9: Imports organized correctly.

Standard library, then testify. Good.


11-70: ExtractFieldRefs tests cover the essentials.

Simple, nested, multiple, deeply nested paths, duplicate deduplication, and edge cases (no template, empty string). Table-driven approach is clean.


72-208: ExtractFieldRefsByPrefix is comprehensively tested.

Great coverage: conditionals, pipes, ranges, with blocks (context change correctly noted), mixed prefixes, nested conditionals, else-if chains, printf with multiple refs. The "deep path - only first level after prefix" case is important.


109-114: With block context change is correctly documented.

The comment clarifies that .name inside with .locals.config refers to the config's name, not .locals.name. This is a subtle Go template behavior worth highlighting.


251-271: HasTemplateActions tests are concise and effective.

Covers action nodes, control structures, and plain text. Good.


293-309: Invalid template error handling is properly tested.

All three extraction functions correctly return errors for malformed templates.

docs/prd/file-scoped-locals.md (7)

1-24: PRD overview and problem statement are clear.

Good articulation of the gap (no file-scoped temp variables) and the solution boundaries (file-scoped only, not inherited, not passed to tools).


44-86: Locals referencing locals is well documented.

The dependency resolution and cycle detection examples are practical. The order-independence guarantee is valuable UX.


192-203: Comparison table is helpful.

Clear differentiation between locals, vars, and settings. This will help users choose the right mechanism.


276-308: Implementation algorithm is well specified.

The step-by-step breakdown and example walkthrough provide clear guidance for implementers.


436-600: Template AST package design is sound.

The walkAST function handles all Go template node types. Good separation into pkg/template/ for reusability.


1540-1605: atmos describe locals command spec is thorough.

Provenance tracking with file/line numbers, scope separation, and JSON output for automation are well thought out.


207-237: Note: Markdownlint MD040 issues are acceptable.

Per learnings, MD040 (fenced code language) issues in docs/prd/ can be handled in a separate cleanup commit. Based on learnings.

internal/exec/stack_processor_locals_test.go (8)

1-11: Imports are properly organized.

Standard library, testify, then Atmos packages. Follows the three-group convention.


13-29: Basic resolution test validates core functionality.

Templates are resolved in the correct order. Good.


31-56: Edge cases for missing/empty locals are covered.

No locals section returns nil; empty locals returns non-nil empty map. The distinction matters for downstream processing.


58-86: Parent locals inheritance tests are solid.

Both with and without a section, parent locals are correctly propagated. This validates the scope chain behavior.


88-113: Error cases are properly validated.

Invalid type and circular dependency both produce meaningful errors. The assertions check for expected substrings.


115-175: ProcessStackLocals tests all component types.

Global, terraform, helmfile, and packer scopes are all tested. The no-locals scenario correctly returns nil for all scopes.


177-194: LocalsContext.GetForComponentType tests are thorough.

Covers all known types plus unknown fallback to global. Nil receiver test prevents panics.


196-250: ResolveComponentLocals and StripLocalsFromSection tests complete the coverage.

Component resolution with parent context works. Strip function correctly removes locals while preserving other keys. Nil handling is safe.

pkg/template/ast.go (5)

6-12: Import grouping follows guidelines.

Imports are correctly organized: stdlib first, then Atmos internal packages. Clean structure.


29-61: Solid implementation with appropriate optimizations.

Quick-check for {{ before parsing avoids unnecessary work. Deduplication via seen map is correct. The AST walking correctly extracts FieldNode references.


63-86: Clean prefix filtering logic.

Correctly filters references by prefix and returns the second-level identifier. Deduplication prevents duplicates in the result.


88-123: AST traversal covers key node types.

The traversal handles the primary control-flow nodes (if/range/with/template) and action/pipe/command chains. FieldNode extraction happens in the callback. This should capture all .locals.X references in typical templates.


201-226: Correctly extracts full nested paths.

Returns the complete path after the prefix, enabling support for nested local references like .locals.config.nested. Well implemented.

internal/exec/stack_processor_locals.go (5)

3-11: Imports correctly organized.

Stdlib (fmt) first, then Atmos internal packages with appropriate aliases (errUtils, cfg). Follows guidelines.


16-47: Well-structured extraction with proper nil handling.

Clear flow: nil section → copy parent; no locals key → copy parent; type check → error; empty map → copy/create parent; otherwise resolve. Error wrapping includes file path for context.


49-71: Shallow copy is appropriate here.

The distinction between returning nil vs empty map is semantically meaningful for downstream consumers. Shallow copy suffices since resolved locals values aren't mutated after resolution.


103-133: Consider whether non-map sections should trigger a warning or error.

When terraform/helmfile/packer sections exist but aren't maps (e.g., they're strings or arrays), the code silently falls back to global locals. This could hide configuration mistakes.

Is this intentional behavior? If these sections must always be maps when present, consider returning an error or at minimum logging a warning for malformed sections.


154-172: Good nil-safe accessor with sensible default.

Handles nil receiver and unknown component types gracefully by falling back to Global locals.

pkg/locals/resolver.go (8)

12-24: Imports properly organized.

Stdlib first, then third-party (sprig), then Atmos packages with aliases. Follows guidelines.


26-46: Clean resolver initialization.

Maps are properly initialized in constructor, preventing nil map assignment panics during resolution.


48-93: Well-structured resolution flow.

Clear 4-step process: build graph → sort → merge parent → resolve. The algorithm is sound.

One note: r.resolved is returned directly, meaning callers share the internal map. This is fine if Resolver is single-use, but could cause issues if reused. Document this or return a copy.

Verify that Resolver instances are not reused after Resolve() is called.


126-133: Silently ignoring parse errors is intentional but worth noting.

The error from ExtractFieldRefsByPrefix is discarded. The comment explains this is deliberate—actual errors surface during resolution. This is acceptable.


255-343: Solid cycle detection with clear error formatting.

DFS-based cycle detection is correct. The formatted output (a → b → c → a) clearly shows the cycle to users. Deterministic ordering via sorted names ensures reproducible error messages.


345-385: Correct recursive resolution without mutating originals.

New maps and slices are created for resolved values. Original local definitions remain unchanged.


387-417: Template resolution always returns string.

Go templates produce string output. If a local like count: "{{ add 1 2 }}" should be numeric, it remains "3" (string). This is consistent with Go template behavior but worth documenting if type coercion is expected elsewhere.

Confirm that downstream consumers handle string-typed template results appropriately, or consider adding YAML unmarshaling of the result if type preservation is needed.


419-449: Helpful debugging utilities.

getAvailableLocals provides clear error context. GetDependencies returns a defensive copy, preventing tests from mutating internal state.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 17, 2025
🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 17, 2025
@mergify
Copy link
Copy Markdown

mergify bot commented Dec 17, 2025

Important

Cloud Posse Engineering Team Review Required

This pull request modifies files that require Cloud Posse's review. Please be patient, and a core maintainer will review your changes.

To expedite this process, reach out to us on Slack in the #pr-reviews channel.

@mergify mergify bot added the needs-cloudposse Needs Cloud Posse assistance label Dec 17, 2025
@aknysh
Copy link
Copy Markdown
Member

aknysh commented Dec 17, 2025

@coderabbitai full review please

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 17, 2025

@aknysh: I'll conduct a full review of this file-scoped locals feature implementation. This is a substantial PR introducing:

Core Feature:

  • File-scoped locals section with dependency-aware resolution
  • Topological sorting with circular dependency detection
  • Multi-level scopes (global, component-type, component)
  • File isolation (no inheritance across imports)

Key Components to Review:

  • Documentation: PRD and blog post describing the feature
  • Implementation: Stack processor locals, resolver with dependency graph, template AST utilities
  • Schema: JSON schema updates for locals support
  • Tests: Comprehensive unit tests and fixtures including circular dependency scenarios
  • Error handling: New error sentinels for locals-specific failures

The PR includes new packages (pkg/locals, pkg/template) and integrates across the stack processing pipeline. I'll review the implementation quality, test coverage, error handling, and architectural patterns.


🧠 Learnings used
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: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.

Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 (3)
website/docs/cli/commands/terraform/usage.mdx (1)

429-429: LGTM—locals correctly added to queryable sections.

The addition of locals to the list of available Atmos sections is accurate and aligns with the file-scoped locals feature introduced in this PR.

Consider adding an example demonstrating a query with .locals to make the feature more discoverable:

         atmos terraform apply --query '.vars.tags.team == "eks"' --stack <stack>
         atmos terraform apply --query '.settings.context.account_id == 12345'
+        atmos terraform apply --query '.locals.environment == "production"'
         atmos terraform deploy --query '.vars.tags.team == "data"' --dry-run --logs-level=Debug
pkg/locals/resolver_test.go (2)

266-278: Consider exposing dependency info without requiring buildDependencyGraph() call.

Tests call the unexported buildDependencyGraph() before GetDependencies(). This couples tests to internals. If GetDependencies() is part of the public API, consider having it build the graph lazily or require Resolve() to be called first.

 func TestResolver_GetDependencies(t *testing.T) {
 	locals := map[string]any{
 		"a": "value",
 		"b": "{{ .locals.a }}",
 		"c": "{{ .locals.a }}-{{ .locals.b }}",
 	}

 	resolver := NewResolver(locals, "test.yaml")
-	err := resolver.buildDependencyGraph()
-	require.NoError(t, err)
+	// Option: Resolve first, then get dependencies
+	_, err := resolver.Resolve(nil)
+	require.NoError(t, err)

 	deps := resolver.GetDependencies()

204-208: Optional: Use type assertion with ok check for clarity.

Direct type assertions like result["config"].(map[string]any) panic on mismatch. Tests still fail, but using require provides clearer error messages.

-	config := result["config"].(map[string]any)
-	assert.Equal(t, "app-service", config["name"])
+	config, ok := result["config"].(map[string]any)
+	require.True(t, ok, "expected config to be map[string]any")
+	assert.Equal(t, "app-service", config["name"])
📜 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 d369e22 and b1f34e9.

📒 Files selected for processing (21)
  • examples/demo-context/schemas/atmos-manifest.json (9 hunks)
  • examples/demo-helmfile/schemas/atmos-manifest.json (9 hunks)
  • examples/demo-localstack/schemas/atmos-manifest.json (9 hunks)
  • internal/exec/stack_processor_locals_test.go (1 hunks)
  • pkg/locals/resolver_test.go (1 hunks)
  • pkg/template/ast_test.go (1 hunks)
  • tests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json (11 hunks)
  • website/docs/cli/commands/terraform/usage.mdx (1 hunks)
  • website/docs/cli/configuration/stacks/index.mdx (1 hunks)
  • website/docs/describe/stacks.mdx (1 hunks)
  • website/docs/design-patterns/component-catalog/index.mdx (1 hunks)
  • website/docs/learn/yaml-guide.mdx (1 hunks)
  • website/docs/stacks/components/index.mdx (1 hunks)
  • website/docs/stacks/env.mdx (1 hunks)
  • website/docs/stacks/imports.mdx (1 hunks)
  • website/docs/stacks/locals.mdx (1 hunks)
  • website/docs/stacks/overrides.mdx (1 hunks)
  • website/docs/stacks/settings/index.mdx (1 hunks)
  • website/docs/stacks/stacks.mdx (1 hunks)
  • website/docs/stacks/vars.mdx (1 hunks)
  • website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json (11 hunks)
✅ Files skipped from review due to trivial changes (5)
  • website/docs/stacks/vars.mdx
  • website/docs/stacks/overrides.mdx
  • website/docs/stacks/components/index.mdx
  • pkg/template/ast_test.go
  • website/docs/describe/stacks.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/exec/stack_processor_locals_test.go
🧰 Additional context used
📓 Path-based instructions (4)
website/**

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

website/**: Update website documentation in the website/ directory when adding new features, ensure consistency between CLI help text and website documentation, and follow the website's documentation structure and style
Keep website code in the website/ directory, follow the existing website architecture and style, and test website changes locally before committing
Keep CLI documentation and website documentation in sync and document new features on the website with examples and use cases

Files:

  • website/docs/stacks/stacks.mdx
  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/stacks/settings/index.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/env.mdx
  • website/docs/stacks/locals.mdx
  • website/docs/design-patterns/component-catalog/index.mdx
  • website/docs/stacks/imports.mdx
  • website/docs/learn/yaml-guide.mdx
  • website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
website/docs/cli/commands/**/*.mdx

📄 CodeRabbit inference engine (CLAUDE.md)

All CLI commands/flags need Docusaurus documentation in website/docs/cli/commands/ with specific structure: frontmatter, Intro component, Screengrab component, Usage section, Arguments/Flags using

/
, and Examples section

Files:

  • website/docs/cli/commands/terraform/usage.mdx
**/*.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: NEVER use fmt.Fprintf(os.Stdout/Stderr) or fmt.Println(); use data.* or ui.* functions instead
All comments must end with periods (enforced by godot linter)
Organize imports in three groups separated by blank lines, sorted alphabetically: 1) Go stdlib, 2) 3rd-party (NOT cloudposse/atmos), 3) Atmos packages; maintain aliases: cfg, log, u, errUtils
Add defer perf.Track(atmosConfig, "pkg.FuncName")() + blank line to all public functions for performance tracking; use nil if no atmosConfig param
All errors MUST be wrapped using static errors defined in errors/errors.go; use errors.Join for combining multiple errors; use fmt.Errorf with %w for adding string context; use error builder for complex errors; use errors.Is() for error checking; NEVER use dynamic errors directly
Use go.uber.org/mock/mockgen with //go:generate directives for mock generation; never create manual mocks
Keep files small...

Files:

  • pkg/locals/resolver_test.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

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + dependency injection for testability; generate mocks with go.uber.org/mock/mockgen; use table-driven tests; target >80% coverage
Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Files:

  • pkg/locals/resolver_test.go
🧠 Learnings (31)
📓 Common learnings
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: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
📚 Learning: 2025-01-19T22:30:27.600Z
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).

Applied to files:

  • website/docs/stacks/stacks.mdx
  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/stacks/settings/index.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
  • website/docs/learn/yaml-guide.mdx
📚 Learning: 2024-12-03T03:49:30.395Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:104-110
Timestamp: 2024-12-03T03:49:30.395Z
Learning: In the documentation for `!terraform.output`, warnings about template variable availability are already covered in other sections, so no need to suggest adding them here.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
📚 Learning: 2024-12-03T04:01:16.446Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:0-0
Timestamp: 2024-12-03T04:01:16.446Z
Learning: In the `terraform.output.mdx` documentation file (`website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx`), the cache invalidation and cache scope behavior for the `!terraform.output` function are already described.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
📚 Learning: 2024-12-01T00:33:20.298Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml:28-32
Timestamp: 2024-12-01T00:33:20.298Z
Learning: In `examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml`, `!exec atmos terraform output` is used in examples to demonstrate its usage, even though `!terraform.output` is the recommended approach according to the documentation.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/design-patterns/component-catalog/index.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-03-18T12:26:25.329Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1149
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:7-7
Timestamp: 2025-03-18T12:26:25.329Z
Learning: In the Atmos project, typos or inconsistencies in test snapshot files (such as "terrafrom" instead of "terraform") may be intentional as they capture the exact output of commands and should not be flagged as issues requiring correction.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
📚 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:

  • website/docs/cli/commands/terraform/usage.mdx
📚 Learning: 2025-01-19T22:30:27.600Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-01-19T22:30:27.600Z
Learning: The Atmos YAML function `!include` allows downloading local or remote files from different sources and assigning their contents to sections in stack manifests. It supports various protocols (file, http, git, s3, etc.) and can filter content using YQ expressions.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
  • website/docs/learn/yaml-guide.mdx
📚 Learning: 2025-01-19T15:49:15.593Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 955
File: tests/snapshots/TestCLICommands_atmos_validate_editorconfig_--help.stdout.golden:0-0
Timestamp: 2025-01-19T15:49:15.593Z
Learning: In future commits, the help text for Atmos CLI commands should be limited to only show component and stack parameters for commands that actually use them. This applies to the example usage section in command help text.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/cli/configuration/stacks/index.mdx
📚 Learning: 2025-02-11T08:21:33.143Z
Learnt from: shirkevich
Repo: cloudposse/atmos PR: 1034
File: website/docs/core-concepts/projects/configuration/stores.mdx:173-177
Timestamp: 2025-02-11T08:21:33.143Z
Learning: The parameter for configuring stack path delimiter in store configurations is consistently named `stack_delimiter` (not `stacks_delimiter`) across all store types in Atmos.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
📚 Learning: 2025-01-25T03:51:57.689Z
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.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
  • examples/demo-localstack/schemas/atmos-manifest.json
  • website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
  • examples/demo-helmfile/schemas/atmos-manifest.json
📚 Learning: 2025-09-24T20:45:40.401Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1475
File: tests/fixtures/scenarios/atmos-auth/stacks/deploy/nonprod.yaml:3-4
Timestamp: 2025-09-24T20:45:40.401Z
Learning: In Atmos stack files, the correct syntax for importing other stack files is `import:` (singular), not `imports:` (plural). All stack files in the Atmos codebase consistently use `import:` followed by a list of paths to import.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/learn/yaml-guide.mdx
📚 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:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 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:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: New configs support Go templating with FuncMap() from internal/exec/template_funcs.go

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : Use ATMOS_ prefix for environment variables with viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 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:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-01-25T03:49:03.951Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: internal/exec/template_utils.go:268-271
Timestamp: 2025-01-25T03:49:03.951Z
Learning: The `ProcessTmplWithDatasourcesGomplate` function in `internal/exec/template_utils.go` is used for documentation generation purposes, where simple environment variable handling is acceptable and thread-safety concerns are not critical.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
📚 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/locals/resolver_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*_test.go : Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Applied to files:

  • pkg/locals/resolver_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 : Use table-driven tests for testing multiple scenarios in Go

Applied to files:

  • pkg/locals/resolver_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : Keep files small and focused (<600 lines); one cmd/impl per file; co-locate tests; never use //revive:disable:file-length-limit

Applied to files:

  • pkg/locals/resolver_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/locals/resolver_test.go
📚 Learning: 2025-01-25T03:46:21.660Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: examples/quick-start-advanced/components/terraform/vpc/README.md.gotmpl:0-0
Timestamp: 2025-01-25T03:46:21.660Z
Learning: Template formatting and content changes in `.gotmpl` files are out of scope for review unless explicitly requested.

Applied to files:

  • website/docs/stacks/imports.mdx
📚 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:

  • website/docs/stacks/imports.mdx
📚 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:

  • website/docs/stacks/imports.mdx
  • website/docs/learn/yaml-guide.mdx
📚 Learning: 2024-12-12T15:15:46.457Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos-cli-imports/atmos.yaml:7-7
Timestamp: 2024-12-12T15:15:46.457Z
Learning: In example configuration files, such as `examples/demo-atmos-cli-imports/atmos.yaml`, it's acceptable to use `refs/heads/main` in remote URLs.

Applied to files:

  • website/docs/stacks/imports.mdx
  • website/docs/learn/yaml-guide.mdx
📚 Learning: 2025-09-10T21:17:55.273Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/http_client_test.go:3-10
Timestamp: 2025-09-10T21:17:55.273Z
Learning: In the cloudposse/atmos repository, imports should never be changed as per samtholiya's coding guidelines.

Applied to files:

  • examples/demo-localstack/schemas/atmos-manifest.json
  • examples/demo-context/schemas/atmos-manifest.json
  • website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
  • examples/demo-helmfile/schemas/atmos-manifest.json
  • tests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • website/docs/learn/yaml-guide.mdx
📚 Learning: 2025-09-24T22:20:39.209Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1505
File: website/docs/cli/commands/completion.mdx:124-127
Timestamp: 2025-09-24T22:20:39.209Z
Learning: In Docusaurus (specifically the cloudposse/atmos repository), backticks render correctly as code formatting even when used inside HTML elements like <dl>/<dt>/<dd> tags in MDX files. No need to replace with <code> tags.

Applied to files:

  • website/docs/learn/yaml-guide.mdx
🧬 Code graph analysis (1)
pkg/locals/resolver_test.go (2)
pkg/locals/resolver.go (1)
  • NewResolver (37-46)
cmd/cmd_utils.go (1)
  • Contains (1257-1264)
🪛 LanguageTool
website/docs/stacks/locals.mdx

[style] ~162-~162: Since ownership is already implied, this phrasing may be redundant.
Context: ...re NOT available here # You must define your own locals in this file locals: namespace...

(PRP_OWN)


[typographical] ~278-~278: Consider using a typographic opening quote here.
Context: ...t-1 # Computed values name_prefix: "{{ .locals.namespace }}-{{ .locals.tenan...

(EN_QUOTES)


[typographical] ~283-~283: Consider using a typographic opening quote here.
Context: ...red tags default_tags: Namespace: "{{ .locals.namespace }}" Tenant: "{{...

(EN_QUOTES)


[typographical] ~291-~291: Consider using a typographic opening quote here.
Context: ...e locals in global vars vars: region: "{{ .locals.stage }}" tags: "{{ .locals...

(EN_QUOTES)


[typographical] ~297-~297: Consider using a typographic opening quote here.
Context: ...ic locals locals: backend_bucket: "{{ .locals.namespace }}-{{ .locals.envir...

(EN_QUOTES)


[typographical] ~302-~302: Consider using a typographic opening quote here.
Context: ...pe: s3 backend: s3: bucket: "{{ .locals.backend_bucket }}" regi...

(EN_QUOTES)


[typographical] ~311-~311: Consider using a typographic opening quote here.
Context: ...ponent-specific local vpc_name: "{{ .locals.full_name }}-vpc" vars:...

(EN_QUOTES)


[typographical] ~314-~314: Consider using a typographic close quote here.
Context: ...ame }}" cidr_block: "10.0.0.0/16" tags: Name: "{{ .loca...

(EN_QUOTES)


[typographical] ~316-~316: Consider using a typographic opening quote here.
Context: ...0.0.0/16" tags: Name: "{{ .locals.vpc_name }}" eks: ...

(EN_QUOTES)

⏰ 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). (3)
  • GitHub Check: Acceptance Tests (windows)
  • GitHub Check: Acceptance Tests (macos)
  • GitHub Check: Summary
🔇 Additional comments (22)
website/docs/cli/configuration/stacks/index.mdx (1)

90-90: LGTM!

Clean addition of locals to the available sections for name_template. Consistent with the new file-scoped locals feature.

website/docs/stacks/imports.mdx (1)

340-340: LGTM!

Good documentation update. Adding locals to the list of parameterizable sections aligns with the feature.

pkg/locals/resolver_test.go (1)

1-9: Solid test coverage.

Comprehensive tests covering resolution, chaining, cycles, parent scopes, nested structures, and error paths. Good use of testify assertions.

website/docs/stacks/env.mdx (1)

302-302: LGTM!

Good addition of the locals reference in the Related section.

website/docs/stacks/settings/index.mdx (1)

258-258: LGTM!

Consistent with other doc updates. Good cross-linking to the new locals feature.

website/docs/stacks/stacks.mdx (1)

25-25: LGTM! Locals section properly documented.

The table entry follows the existing format and correctly describes the new locals section with accurate scopes and a clear description.

website/docs/learn/yaml-guide.mdx (1)

233-233: LGTM! Dot notation tip correctly updated.

The addition of locals to the list is accurate and maintains proper ordering (vars → locals → settings → env).

website/docs/design-patterns/component-catalog/index.mdx (1)

80-80: LGTM! Locals added to catalog pattern guidance.

The placement between vars and env is correct and consistent with the broader schema structure.

website/docs/stacks/locals.mdx (1)

1-367: LGTM! Comprehensive and well-structured locals documentation.

This new documentation page is thorough and hits all the key points:

  • Clear introduction emphasizing file-scoped nature
  • Well-organized sections covering scopes, inheritance, isolation, dependency resolution, and cycle detection
  • Practical examples at each level of complexity
  • Helpful comparison table distinguishing locals from vars
  • Solid best practices guidance

The examples are syntactically correct and demonstrate real-world usage patterns.

examples/demo-context/schemas/atmos-manifest.json (3)

31-33: LGTM! Root locals property and definition correctly added.

The new locals definition follows the established pattern for vars/env/settings with:

  • Clear description emphasizing file-scoped nature and no inheritance
  • oneOf structure supporting both !include pattern and object types
  • Proper title and description fields

Also applies to: 709-722


210-212: LGTM! Locals properly integrated across all component types.

The locals property has been correctly added to:

  • terraform (global and component manifest)
  • helmfile (global and component manifest)
  • packer (global and component manifest)

All references point to #/definitions/locals consistently.

Also applies to: 285-287, 335-337, 395-397, 427-429, 487-489


170-170: Schema additionalProperties alignment: components section allows flexibility.

The components definition at line 170 sets additionalProperties: true while maintaining explicit validation for terraform, helmfile, and packer via $ref. This pattern is consistent across all example and reference schemas in the repository. The structure preserves validation for known component types while allowing future extensibility.

If this represents a deliberate policy shift to support additional component types, ensure the versioning strategy and documentation reflect the intentional schema flexibility.

website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json (3)

31-33: LGTM! Canonical schema correctly defines locals.

The official schema in website/static properly adds locals with the same structure as the example schemas, maintaining consistency.

Also applies to: 709-722


533-533: Good documentation improvements in metadata.

Two description enhancements:

  • Adding "OpenTofu" to component description (line 533) acknowledges Terraform forks
  • Clarifying that custom config is "not inherited by derived components" (line 567) helps users understand behavior

Also applies to: 567-567


170-170: LGTM! Schema changes consistent with example schemas.

The same pattern applied here:

  • components additionalProperties relaxed to true
  • locals added to all component type scopes

Also applies to: 210-212, 285-287, 335-337, 395-397, 427-429, 487-489

examples/demo-helmfile/schemas/atmos-manifest.json (1)

31-33: LGTM! Schema changes consistent across demo-helmfile.

All locals additions follow the same pattern as other schema files:

  • Root locals property (31-33)
  • components additionalProperties relaxed (170)
  • locals in all component type scopes (210-489)
  • Standard locals definition (709-722)

Consistency across schema files is maintained.

Also applies to: 170-170, 210-212, 285-287, 335-337, 395-397, 427-429, 487-489, 709-722

examples/demo-localstack/schemas/atmos-manifest.json (1)

31-33: LGTM! Schema changes consistent across demo-localstack.

Final schema file follows the same pattern as all others:

  • Root locals property added
  • components schema relaxed
  • locals integrated into terraform/helmfile/packer scopes
  • Standard locals definition provided

All schema files are now consistently updated for the locals feature.

Also applies to: 170-170, 210-212, 285-287, 335-337, 395-397, 427-429, 487-489, 709-722

tests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json (5)

31-33: LGTM!

Root-level locals property correctly references the new definition. Placement is consistent with other root properties.


168-184: Verify the intent behind loosening schema validation.

Setting additionalProperties: true allows arbitrary properties beyond the defined terraform, helmfile, and packer component types. If this is intentional for extensibility, that's fine. If not, it could reduce validation effectiveness.


210-212: LGTM!

Locals property consistently added across all three component types (terraform, helmfile, packer) and their respective component manifests. This enables the three-level locals hierarchy described in the PR objectives.

Also applies to: 285-287, 335-337, 395-397, 427-429, 487-489


533-534: LGTM!

Description updates improve clarity. The custom configuration note about non-inheritance aligns with the file-scoped locals semantics.

Also applies to: 567-567


709-722: LGTM!

The new locals definition is well-structured and follows the same pattern as vars and env definitions. The description clearly documents the key semantics: file-scoped, resolved before other sections, can reference each other, and do not inherit across file boundaries.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 17, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 17, 2025

@aknysh: I'll conduct a comprehensive review of all changes in this PR, including:

  • Core Implementation: Stack processor locals, dependency resolver, template AST utilities
  • Schema Updates: JSON schema changes across all manifest definitions
  • Error Handling: New error sentinels and error propagation
  • Test Coverage: Unit tests and fixture scenarios (including circular dependency cases)
  • Documentation: PRD, blog post, and user-facing docs
  • Architecture: New packages (pkg/locals, pkg/template) and integration patterns

Starting the full review now.


🧠 Learnings used
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1327
File: internal/exec/describe_affected_utils_2.go:248-248
Timestamp: 2025-06-23T18:50:33.614Z
Learning: When aknysh mentions that a suggestion is not related to the current PR and needs separate tests to be reviewed in a separate PR, this indicates their preference for maintaining focused PR scope and proper test coverage for each change.

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.

Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.

Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.

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.
✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 (10)
tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml (2)

7-15: Global locals demonstrate the feature well.

Template references and dependency chain look correct.

Minor: the stage field holds a region value ("us-east-1") which might confuse readers since "stage" usually means environment tier. Consider renaming to region for clarity in future fixtures.


21-31: Terraform-scoped locals work correctly.

The backend_bucket reference at line 29 properly demonstrates accessing terraform-scoped locals.

Consider using region: "{{ .locals.stage }}" at line 31 instead of hardcoding "us-east-1" to stay consistent with line 19 and better showcase the feature.

pkg/locals/resolver_test.go (1)

74-88: Consider using errors.Is() for error type assertions.

The current approach validates error message content, which is fine for testing user-facing messages. For stricter type checking, you could additionally verify the error type:

require.Error(t, err)
assert.True(t, errors.Is(err, errUtils.ErrLocalsCircularDep))

This ensures the correct sentinel error is returned, making tests more resilient to message changes.

pkg/template/ast_test.go (2)

428-434: Consider using exact assertion for else-if chain test.

The test comment says "Should find a, b, c, d" but uses GreaterOrEqual. If exactly 4 refs are expected, assert.Len(t, refs, 4) would be more precise and catch regressions where extra refs leak in.

-	assert.GreaterOrEqual(t, len(refs), 4)
+	assert.Len(t, refs, 4)

357-363: Range-with-else test has weak assertion.

The assert.NotEmpty(t, refs) doesn't verify the expected refs. Consider checking for specific paths like .items, .name, .empty to ensure correctness.

pkg/template/ast.go (1)

19-24: Consider removing perf.Track from FieldRef.String().

This method is a simple strings.Join call. The perf.Track overhead may be disproportionate for such a lightweight operation, especially if called frequently during dependency resolution.

 func (f FieldRef) String() string {
-	defer perf.Track(nil, "template.FieldRef.String")()
-
 	return strings.Join(f.Path, ".")
 }
internal/exec/stack_processor_locals.go (1)

49-71: Shallow copy is mitigated by resolver creating fresh nested structures; consider adding test coverage.

The shallow copy concern is technically valid for Go maps, but the resolver's resolveValue function already creates new instances of nested maps and slices during resolution (not just copying references). Since parentLocals always originates from previous resolutions, nested structures are already isolated.

However, the test at line 520-531 only covers string values. Add a test case with nested maps/slices to ensure isolation is maintained as the code evolves.

pkg/locals/resolver.go (1)

240-253: Consider deferring sort until queue is fully populated.

Calling sort.Strings(queue) on line 247 after each append results in O(n² log n) complexity for large dependency graphs. For typical Atmos use cases with small locals counts, this is fine, but if locals grow significantly, consider batching zero-degree nodes and sorting once.

docs/prd/file-scoped-locals.md (2)

815-841: Dead code block in pseudocode example.

Lines 815-828 build an inDegree map that's immediately discarded and rebuilt at lines 832-841. This could confuse implementers. Consider removing the first block or adding a clarifying comment that it was intentionally left to show the thought process.

-    // Count incoming edges
-    for _, deps := range r.dependencies {
-        for _, dep := range deps {
-            // Only count if dep is in current scope (not parent)
-            if _, exists := r.locals[dep]; exists {
-                inDegree[dep]++ // Note: reversed - dep needs to come before dependent
-            }
-        }
-    }
-
-    // Actually, let's use standard topological sort
     // inDegree[x] = number of locals that x depends on (within this scope)
-    inDegree = make(map[string]int)
     for name, deps := range r.dependencies {

207-237: Fenced code blocks lack language specifiers.

Static analysis flagged MD040 on several code blocks (lines 207, 218, 227, 299, and others). Based on learnings, these markdownlint issues can be addressed in a separate documentation cleanup commit and shouldn't block this PR.

📜 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 41250de and b1f34e9.

📒 Files selected for processing (35)
  • docs/prd/file-scoped-locals.md (1 hunks)
  • errors/errors.go (1 hunks)
  • examples/demo-context/schemas/atmos-manifest.json (9 hunks)
  • examples/demo-helmfile/schemas/atmos-manifest.json (9 hunks)
  • examples/demo-localstack/schemas/atmos-manifest.json (9 hunks)
  • internal/exec/stack_processor_locals.go (1 hunks)
  • internal/exec/stack_processor_locals_test.go (1 hunks)
  • pkg/config/const.go (1 hunks)
  • pkg/datafetcher/schema/atmos/manifest/1.0.json (8 hunks)
  • pkg/locals/resolver.go (1 hunks)
  • pkg/locals/resolver_test.go (1 hunks)
  • pkg/template/ast.go (1 hunks)
  • pkg/template/ast_test.go (1 hunks)
  • tests/fixtures/scenarios/locals-circular/atmos.yaml (1 hunks)
  • tests/fixtures/scenarios/locals-circular/stacks/deploy/circular.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/atmos.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml (1 hunks)
  • tests/fixtures/scenarios/locals/stacks/mixins/region.yaml (1 hunks)
  • tests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json (11 hunks)
  • website/blog/2025-12-16-file-scoped-locals.mdx (1 hunks)
  • website/docs/cli/commands/terraform/usage.mdx (1 hunks)
  • website/docs/cli/configuration/stacks/index.mdx (1 hunks)
  • website/docs/describe/stacks.mdx (1 hunks)
  • website/docs/design-patterns/component-catalog/index.mdx (1 hunks)
  • website/docs/learn/yaml-guide.mdx (1 hunks)
  • website/docs/stacks/components/index.mdx (1 hunks)
  • website/docs/stacks/env.mdx (1 hunks)
  • website/docs/stacks/imports.mdx (1 hunks)
  • website/docs/stacks/locals.mdx (1 hunks)
  • website/docs/stacks/overrides.mdx (1 hunks)
  • website/docs/stacks/settings/index.mdx (1 hunks)
  • website/docs/stacks/stacks.mdx (1 hunks)
  • website/docs/stacks/vars.mdx (1 hunks)
  • website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json (11 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
website/**

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

website/**: Update website documentation in the website/ directory when adding new features, ensure consistency between CLI help text and website documentation, and follow the website's documentation structure and style
Keep website code in the website/ directory, follow the existing website architecture and style, and test website changes locally before committing
Keep CLI documentation and website documentation in sync and document new features on the website with examples and use cases

Files:

  • website/docs/stacks/vars.mdx
  • website/docs/stacks/stacks.mdx
  • website/docs/stacks/components/index.mdx
  • website/docs/stacks/env.mdx
  • website/docs/stacks/settings/index.mdx
  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/stacks/locals.mdx
  • website/docs/design-patterns/component-catalog/index.mdx
  • website/docs/learn/yaml-guide.mdx
  • website/docs/stacks/overrides.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/blog/2025-12-16-file-scoped-locals.mdx
  • website/docs/stacks/imports.mdx
  • website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
  • website/docs/describe/stacks.mdx
website/docs/cli/commands/**/*.mdx

📄 CodeRabbit inference engine (CLAUDE.md)

All CLI commands/flags need Docusaurus documentation in website/docs/cli/commands/ with specific structure: frontmatter, Intro component, Screengrab component, Usage section, Arguments/Flags using

/
, and Examples section

Files:

  • website/docs/cli/commands/terraform/usage.mdx
**/*.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: NEVER use fmt.Fprintf(os.Stdout/Stderr) or fmt.Println(); use data.* or ui.* functions instead
All comments must end with periods (enforced by godot linter)
Organize imports in three groups separated by blank lines, sorted alphabetically: 1) Go stdlib, 2) 3rd-party (NOT cloudposse/atmos), 3) Atmos packages; maintain aliases: cfg, log, u, errUtils
Add defer perf.Track(atmosConfig, "pkg.FuncName")() + blank line to all public functions for performance tracking; use nil if no atmosConfig param
All errors MUST be wrapped using static errors defined in errors/errors.go; use errors.Join for combining multiple errors; use fmt.Errorf with %w for adding string context; use error builder for complex errors; use errors.Is() for error checking; NEVER use dynamic errors directly
Use go.uber.org/mock/mockgen with //go:generate directives for mock generation; never create manual mocks
Keep files small...

Files:

  • errors/errors.go
  • internal/exec/stack_processor_locals_test.go
  • pkg/template/ast.go
  • pkg/template/ast_test.go
  • pkg/config/const.go
  • pkg/locals/resolver_test.go
  • internal/exec/stack_processor_locals.go
  • pkg/locals/resolver.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

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + dependency injection for testability; generate mocks with go.uber.org/mock/mockgen; use table-driven tests; target >80% coverage
Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Files:

  • internal/exec/stack_processor_locals_test.go
  • pkg/template/ast_test.go
  • pkg/locals/resolver_test.go
website/blog/**/*.mdx

📄 CodeRabbit inference engine (CLAUDE.md)

website/blog/**/*.mdx: Follow PR template (what/why/references); PRs labeled minor/major MUST include blog post at website/blog/YYYY-MM-DD-feature-name.mdx with YAML front matter, after intro, and only tags from website/blog/tags.yml
Blog posts MUST use only tags defined in website/blog/tags.yml and authors defined in website/blog/authors.yml; valid tags are: feature, enhancement, bugfix, dx, breaking-change, security, documentation, deprecation, core; never invent new tags

Files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
docs/prd/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

All Product Requirement Documents (PRDs) MUST be placed in docs/prd/ with kebab-case filenames

Files:

  • docs/prd/file-scoped-locals.md
🧠 Learnings (53)
📓 Common learnings
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: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:37.766Z
Learning: cloudposse/atmos: For PRD docs (docs/prd/*.md), markdownlint issues like MD040/MD010/MD034 can be handled in a separate documentation cleanup commit and should not block the current PR.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
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.
📚 Learning: 2025-01-19T22:30:27.600Z
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).

Applied to files:

  • website/docs/stacks/vars.mdx
  • website/docs/stacks/stacks.mdx
  • website/docs/stacks/components/index.mdx
  • website/docs/stacks/settings/index.mdx
  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/learn/yaml-guide.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2024-11-25T17:17:15.703Z
Learnt from: RoseSecurity
Repo: cloudposse/atmos PR: 797
File: pkg/list/atmos.yaml:213-214
Timestamp: 2024-11-25T17:17:15.703Z
Learning: The file `pkg/list/atmos.yaml` is primarily intended for testing purposes.

Applied to files:

  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • website/docs/design-patterns/component-catalog/index.mdx
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • tests/fixtures/scenarios/locals-circular/stacks/deploy/circular.yaml
📚 Learning: 2025-09-10T21:17:55.273Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/http_client_test.go:3-10
Timestamp: 2025-09-10T21:17:55.273Z
Learning: In the cloudposse/atmos repository, imports should never be changed as per samtholiya's coding guidelines.

Applied to files:

  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • website/docs/design-patterns/component-catalog/index.mdx
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • examples/demo-context/schemas/atmos-manifest.json
  • website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
  • tests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json
  • examples/demo-helmfile/schemas/atmos-manifest.json
📚 Learning: 2025-01-25T03:51:57.689Z
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.

Applied to files:

  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
  • website/docs/cli/configuration/stacks/index.mdx
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • examples/demo-context/schemas/atmos-manifest.json
  • examples/demo-helmfile/schemas/atmos-manifest.json
📚 Learning: 2024-12-01T00:33:20.298Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml:28-32
Timestamp: 2024-12-01T00:33:20.298Z
Learning: In `examples/tests/stacks/catalog/terraform/template-functions-test2/defaults.yaml`, `!exec atmos terraform output` is used in examples to demonstrate its usage, even though `!terraform.output` is the recommended approach according to the documentation.

Applied to files:

  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
  • website/docs/cli/commands/terraform/usage.mdx
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • website/docs/design-patterns/component-catalog/index.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/blog/2025-12-16-file-scoped-locals.mdx
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • website/docs/stacks/imports.mdx
  • website/docs/describe/stacks.mdx
📚 Learning: 2025-03-18T12:26:25.329Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 1149
File: tests/snapshots/TestCLICommands_atmos_vendor_pull_ssh.stderr.golden:7-7
Timestamp: 2025-03-18T12:26:25.329Z
Learning: In the Atmos project, typos or inconsistencies in test snapshot files (such as "terrafrom" instead of "terraform") may be intentional as they capture the exact output of commands and should not be flagged as issues requiring correction.

Applied to files:

  • tests/fixtures/scenarios/locals/stacks/deploy/prod.yaml
  • tests/fixtures/scenarios/locals/stacks/deploy/dev.yaml
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • examples/demo-context/schemas/atmos-manifest.json
📚 Learning: 2024-12-03T03:49:30.395Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:104-110
Timestamp: 2024-12-03T03:49:30.395Z
Learning: In the documentation for `!terraform.output`, warnings about template variable availability are already covered in other sections, so no need to suggest adding them here.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
📚 Learning: 2024-12-03T04:01:16.446Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx:0-0
Timestamp: 2024-12-03T04:01:16.446Z
Learning: In the `terraform.output.mdx` documentation file (`website/docs/core-concepts/stacks/yaml-functions/terraform.output.mdx`), the cache invalidation and cache scope behavior for the `!terraform.output` function are already described.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/stacks/locals.mdx
  • website/docs/describe/stacks.mdx
📚 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:

  • website/docs/cli/commands/terraform/usage.mdx
📚 Learning: 2025-01-19T22:30:27.600Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-01-19T22:30:27.600Z
Learning: The Atmos YAML function `!include` allows downloading local or remote files from different sources and assigning their contents to sections in stack manifests. It supports various protocols (file, http, git, s3, etc.) and can filter content using YQ expressions.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/learn/yaml-guide.mdx
  • website/docs/stacks/overrides.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-01-19T15:49:15.593Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 955
File: tests/snapshots/TestCLICommands_atmos_validate_editorconfig_--help.stdout.golden:0-0
Timestamp: 2025-01-19T15:49:15.593Z
Learning: In future commits, the help text for Atmos CLI commands should be limited to only show component and stack parameters for commands that actually use them. This applies to the example usage section in command help text.

Applied to files:

  • website/docs/cli/commands/terraform/usage.mdx
  • website/docs/design-patterns/component-catalog/index.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/describe/stacks.mdx
📚 Learning: 2025-10-02T19:17:51.630Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1504
File: pkg/profiler/profiler.go:20-31
Timestamp: 2025-10-02T19:17:51.630Z
Learning: In pkg/profiler/profiler.go, profiler-specific errors (ErrUnsupportedProfileType, ErrStartCPUProfile, ErrStartTraceProfile, ErrCreateProfileFile) must remain local and cannot be moved to errors/errors.go due to an import cycle: pkg/profiler → errors → pkg/schema → pkg/profiler. This is a valid exception to the centralized errors policy.

Applied to files:

  • errors/errors.go
📚 Learning: 2025-12-13T06:10:13.688Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.

Applied to files:

  • errors/errors.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : All errors MUST be wrapped using static errors defined in errors/errors.go; use errors.Join for combining multiple errors; use fmt.Errorf with %w for adding string context; use error builder for complex errors; use errors.Is() for error checking; NEVER use dynamic errors directly

Applied to files:

  • errors/errors.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 : 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

Applied to files:

  • errors/errors.go
📚 Learning: 2025-02-03T06:00:11.419Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 959
File: cmd/describe_config.go:20-20
Timestamp: 2025-02-03T06:00:11.419Z
Learning: Commands should use `PrintErrorMarkdownAndExit` with empty title and suggestion (`"", err, ""`) for general error handling. Specific titles like "Invalid Usage" or "File Not Found" should only be used for validation or specific error scenarios.

Applied to files:

  • errors/errors.go
📚 Learning: 2024-12-05T22:33:40.955Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 820
File: cmd/list_components.go:53-54
Timestamp: 2024-12-05T22:33:40.955Z
Learning: In the Atmos CLI Go codebase, using `u.LogErrorAndExit` within completion functions is acceptable because it logs the error and exits the command execution.

Applied to files:

  • errors/errors.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:

  • internal/exec/stack_processor_locals_test.go
  • pkg/template/ast_test.go
  • pkg/locals/resolver_test.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_locals_test.go
  • internal/exec/stack_processor_locals.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:

  • internal/exec/stack_processor_locals_test.go
  • pkg/template/ast_test.go
  • pkg/locals/resolver_test.go
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*_test.go : Test behavior, not implementation; never test stub functions; avoid tautological tests; make code testable via DI; no coverage theater; remove always-skipped tests; use errors.Is() for error checking

Applied to files:

  • internal/exec/stack_processor_locals_test.go
  • pkg/template/ast_test.go
  • pkg/locals/resolver_test.go
📚 Learning: 2024-11-19T23:00:45.899Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 795
File: internal/exec/stack_processor_utils.go:378-386
Timestamp: 2024-11-19T23:00:45.899Z
Learning: In the `ProcessYAMLConfigFile` function within `internal/exec/stack_processor_utils.go`, directory traversal in stack imports is acceptable and should not be restricted.

Applied to files:

  • internal/exec/stack_processor_locals_test.go
  • internal/exec/stack_processor_locals.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:

  • internal/exec/stack_processor_locals_test.go
  • website/docs/cli/configuration/stacks/index.mdx
  • internal/exec/stack_processor_locals.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:

  • internal/exec/stack_processor_locals_test.go
  • pkg/template/ast_test.go
  • pkg/locals/resolver_test.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:

  • website/docs/design-patterns/component-catalog/index.mdx
  • tests/fixtures/scenarios/locals/atmos.yaml
  • website/docs/cli/configuration/stacks/index.mdx
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests; use interfaces + dependency injection for testability; generate mocks with go.uber.org/mock/mockgen; use table-driven tests; target >80% coverage

Applied to files:

  • pkg/template/ast_test.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:

  • website/docs/learn/yaml-guide.mdx
  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.

Applied to files:

  • website/docs/learn/yaml-guide.mdx
  • website/docs/cli/configuration/stacks/index.mdx
📚 Learning: 2025-09-24T20:45:40.401Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1475
File: tests/fixtures/scenarios/atmos-auth/stacks/deploy/nonprod.yaml:3-4
Timestamp: 2025-09-24T20:45:40.401Z
Learning: In Atmos stack files, the correct syntax for importing other stack files is `import:` (singular), not `imports:` (plural). All stack files in the Atmos codebase consistently use `import:` followed by a list of paths to import.

Applied to files:

  • website/docs/learn/yaml-guide.mdx
  • website/docs/stacks/overrides.mdx
  • website/docs/cli/configuration/stacks/index.mdx
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
📚 Learning: 2024-12-12T15:15:46.457Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos-cli-imports/atmos.yaml:7-7
Timestamp: 2024-12-12T15:15:46.457Z
Learning: In example configuration files, such as `examples/demo-atmos-cli-imports/atmos.yaml`, it's acceptable to use `refs/heads/main` in remote URLs.

Applied to files:

  • website/docs/learn/yaml-guide.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-09-24T22:20:39.209Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1505
File: website/docs/cli/commands/completion.mdx:124-127
Timestamp: 2025-09-24T22:20:39.209Z
Learning: In Docusaurus (specifically the cloudposse/atmos repository), backticks render correctly as code formatting even when used inside HTML elements like <dl>/<dt>/<dd> tags in MDX files. No need to replace with <code> tags.

Applied to files:

  • website/docs/learn/yaml-guide.mdx
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
  • website/docs/cli/configuration/stacks/index.mdx
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
  • website/docs/stacks/imports.mdx
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
  • tests/fixtures/scenarios/locals-circular/atmos.yaml
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 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:

  • tests/fixtures/scenarios/locals/atmos.yaml
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: New configs support Go templating with FuncMap() from internal/exec/template_funcs.go

Applied to files:

  • tests/fixtures/scenarios/locals/atmos.yaml
  • website/docs/cli/configuration/stacks/index.mdx
📚 Learning: 2025-02-11T08:21:33.143Z
Learnt from: shirkevich
Repo: cloudposse/atmos PR: 1034
File: website/docs/core-concepts/projects/configuration/stores.mdx:173-177
Timestamp: 2025-02-11T08:21:33.143Z
Learning: The parameter for configuring stack path delimiter in store configurations is consistently named `stack_delimiter` (not `stacks_delimiter`) across all store types in Atmos.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : Use ATMOS_ prefix for environment variables with viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/stacks/imports.mdx
📚 Learning: 2025-01-25T03:49:03.951Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: internal/exec/template_utils.go:268-271
Timestamp: 2025-01-25T03:49:03.951Z
Learning: The `ProcessTmplWithDatasourcesGomplate` function in `internal/exec/template_utils.go` is used for documentation generation purposes, where simple environment variable handling is acceptable and thread-safety concerns are not critical.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
📚 Learning: 2025-10-07T00:25:16.333Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1498
File: website/src/components/Screengrabs/atmos-terraform-metadata--help.html:25-55
Timestamp: 2025-10-07T00:25:16.333Z
Learning: In Atmos CLI, subcommands inherit flags from their parent commands via Cobra's command inheritance. For example, `atmos terraform metadata --help` shows `--affected` and related flags inherited from the parent `terraform` command (defined in cmd/terraform.go), even though the metadata subcommand doesn't explicitly define these flags. This is expected Cobra behavior and auto-generated help screengrabs accurately reflect this inheritance.

Applied to files:

  • website/docs/cli/configuration/stacks/index.mdx
  • website/docs/describe/stacks.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to website/blog/**/*.mdx : Follow PR template (what/why/references); PRs labeled minor/major MUST include blog post at website/blog/YYYY-MM-DD-feature-name.mdx with YAML front matter, <!--truncate--> after intro, and only tags from website/blog/tags.yml

Applied to files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to website/blog/**/*.mdx : Blog posts MUST use only tags defined in website/blog/tags.yml and authors defined in website/blog/authors.yml; valid tags are: feature, enhancement, bugfix, dx, breaking-change, security, documentation, deprecation, core; never invent new tags

Applied to files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
📚 Learning: 2024-12-03T05:18:49.169Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 810
File: internal/exec/terraform_utils.go:40-213
Timestamp: 2024-12-03T05:18:49.169Z
Learning: In the context of the Atmos project, it's acceptable for functions like `execTerraformOutput` to remain as single functions if they perform a single purpose, such as retrieving Terraform outputs for a component in a stack, even if the function is lengthy.

Applied to files:

  • website/blog/2025-12-16-file-scoped-locals.mdx
📚 Learning: 2025-12-16T18:20:55.614Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T18:20:55.614Z
Learning: Applies to **/*.go : Keep files small and focused (<600 lines); one cmd/impl per file; co-locate tests; never use //revive:disable:file-length-limit

Applied to files:

  • pkg/locals/resolver_test.go
📚 Learning: 2025-10-08T06:48:07.499Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1602
File: internal/exec/stack_processor_utils.go:968-1003
Timestamp: 2025-10-08T06:48:07.499Z
Learning: The `FindComponentDependenciesLegacy` function in `internal/exec/stack_processor_utils.go` is legacy code that is not actively used and is kept only for backward compatibility purposes.

Applied to files:

  • internal/exec/stack_processor_locals.go
📚 Learning: 2024-10-20T00:57:53.500Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 731
File: internal/exec/validate_stacks.go:0-0
Timestamp: 2024-10-20T00:57:53.500Z
Learning: In `internal/exec/validate_stacks.go`, when downloading the Atmos JSON Schema file to the temp directory, the temporary file is overwritten each time, so explicit removal is not necessary.

Applied to files:

  • internal/exec/stack_processor_locals.go
📚 Learning: 2025-09-29T02:20:11.636Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/validate_component.go:117-118
Timestamp: 2025-09-29T02:20:11.636Z
Learning: The ValidateComponent function in internal/exec/validate_component.go had its componentSection parameter type refined from `any` to `map[string]any` without adding new parameters. This is a type safety improvement, not a signature change requiring call site updates.

Applied to files:

  • internal/exec/stack_processor_locals.go
  • docs/prd/file-scoped-locals.md
📚 Learning: 2025-12-13T06:07:34.794Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: docs/prd/tool-dependencies-integration.md:58-64
Timestamp: 2025-12-13T06:07:34.794Z
Learning: For docs in the cloudposse/atmos repository under docs/prd/, markdownlint issues MD040, MD010, and MD034 should be deferred to a separate documentation cleanup commit and must not block the current PR. If needed, address these issues in a follow-up PR dedicated to documentation improvements.

Applied to files:

  • docs/prd/file-scoped-locals.md
📚 Learning: 2025-01-25T03:46:21.660Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: examples/quick-start-advanced/components/terraform/vpc/README.md.gotmpl:0-0
Timestamp: 2025-01-25T03:46:21.660Z
Learning: Template formatting and content changes in `.gotmpl` files are out of scope for review unless explicitly requested.

Applied to files:

  • website/docs/stacks/imports.mdx
📚 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:

  • website/docs/stacks/imports.mdx
📚 Learning: 2025-06-23T02:14:30.937Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1327
File: cmd/terraform.go:111-117
Timestamp: 2025-06-23T02:14:30.937Z
Learning: In cmd/terraform.go, flags for the DescribeAffected function are added dynamically at runtime when info.Affected is true. This is intentional to avoid exposing internal flags like "file", "format", "verbose", "include-spacelift-admin-stacks", "include-settings", and "upload" in the terraform command interface, while still providing them for the shared DescribeAffected function used by both `atmos describe affected` and `atmos terraform apply --affected`.

Applied to files:

  • website/docs/describe/stacks.mdx
🧬 Code graph analysis (4)
internal/exec/stack_processor_locals_test.go (3)
internal/exec/stack_processor_locals.go (5)
  • ExtractAndResolveLocals (16-47)
  • ProcessStackLocals (86-136)
  • LocalsContext (140-152)
  • ResolveComponentLocals (176-185)
  • StripLocalsFromSection (190-210)
cmd/cmd_utils.go (1)
  • Contains (1257-1264)
pkg/config/const.go (3)
  • TerraformSectionName (81-81)
  • HelmfileSectionName (82-82)
  • PackerSectionName (83-83)
pkg/template/ast.go (1)
pkg/perf/perf.go (1)
  • Track (121-138)
pkg/template/ast_test.go (1)
pkg/template/ast.go (5)
  • ExtractFieldRefs (29-61)
  • ExtractFieldRefsByPrefix (66-86)
  • ExtractAllFieldRefsByPrefix (205-226)
  • HasTemplateActions (172-199)
  • FieldRef (15-17)
pkg/locals/resolver_test.go (2)
pkg/locals/resolver.go (1)
  • NewResolver (37-46)
cmd/cmd_utils.go (1)
  • Contains (1257-1264)
🪛 LanguageTool
website/docs/stacks/locals.mdx

[style] ~162-~162: Since ownership is already implied, this phrasing may be redundant.
Context: ...re NOT available here # You must define your own locals in this file locals: namespace...

(PRP_OWN)


[typographical] ~278-~278: Consider using a typographic opening quote here.
Context: ...t-1 # Computed values name_prefix: "{{ .locals.namespace }}-{{ .locals.tenan...

(EN_QUOTES)


[typographical] ~283-~283: Consider using a typographic opening quote here.
Context: ...red tags default_tags: Namespace: "{{ .locals.namespace }}" Tenant: "{{...

(EN_QUOTES)


[typographical] ~291-~291: Consider using a typographic opening quote here.
Context: ...e locals in global vars vars: region: "{{ .locals.stage }}" tags: "{{ .locals...

(EN_QUOTES)


[typographical] ~297-~297: Consider using a typographic opening quote here.
Context: ...ic locals locals: backend_bucket: "{{ .locals.namespace }}-{{ .locals.envir...

(EN_QUOTES)


[typographical] ~302-~302: Consider using a typographic opening quote here.
Context: ...pe: s3 backend: s3: bucket: "{{ .locals.backend_bucket }}" regi...

(EN_QUOTES)


[typographical] ~311-~311: Consider using a typographic opening quote here.
Context: ...ponent-specific local vpc_name: "{{ .locals.full_name }}-vpc" vars:...

(EN_QUOTES)


[typographical] ~314-~314: Consider using a typographic close quote here.
Context: ...ame }}" cidr_block: "10.0.0.0/16" tags: Name: "{{ .loca...

(EN_QUOTES)


[typographical] ~316-~316: Consider using a typographic opening quote here.
Context: ...0.0.0/16" tags: Name: "{{ .locals.vpc_name }}" eks: ...

(EN_QUOTES)

website/blog/2025-12-16-file-scoped-locals.mdx

[typographical] ~323-~323: To join two clauses or introduce examples, consider using an em dash.
Context: ...eatures - Stack Templates - Go templating in stack manifests - [Conf...

(DASH_RULE)


[typographical] ~324-~324: To join two clauses or introduce examples, consider using an em dash.
Context: ...nance](/cli/commands/describe/component) - Track where values come from - [YAML Fun...

(DASH_RULE)


[typographical] ~325-~325: To join two clauses or introduce examples, consider using an em dash.
Context: ...from - YAML Functions - Dynamic configuration with `!terraform.o...

(DASH_RULE)

docs/prd/file-scoped-locals.md

[grammar] ~297-~297: Please add a punctuation mark at the end of paragraph.
Context: ...r, making each available for subsequent locals ``` Example: locals = {c: "{{.locals.b...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~386-~386: Consider using typographic quotation marks here.
Context: ...mplate context instead. ### No Special "Promote" Syntax To use a local value in vars/se...

(EN_QUOTES)


[typographical] ~438-~438: To join two clauses or introduce examples, consider using an em dash.
Context: ...tation ### New Package: pkg/template/ - Template AST Utilities The locals featu...

(DASH_RULE)


[typographical] ~443-~443: Consider using a typographic close quote here.
Context: ...* - "prefer pkg/ over internal/exec/" 3. Enables future enhancements - De...

(EN_QUOTES)


[typographical] ~446-~446: To join two clauses or introduce examples, consider using an em dash.
Context: ...dation, etc. #### pkg/template/ast.go - Template AST Inspection ```go package t...

(DASH_RULE)


[typographical] ~602-~602: To join two clauses or introduce examples, consider using an em dash.
Context: ...l } #### `pkg/template/ast_test.go` - Comprehensive Tests go package templ...

(DASH_RULE)


[typographical] ~721-~721: To join two clauses or introduce examples, consider using an em dash.
Context: ...cies - Existing IsGolangTemplate() - Could migrate to use `HasTemplateActions...

(DASH_RULE)


[typographical] ~722-~722: To join two clauses or introduce examples, consider using an em dash.
Context: ...TemplateActions()` - Future features - Template validation, dependency analysis...

(DASH_RULE)


[typographical] ~728-~728: To join two clauses or introduce examples, consider using an em dash.
Context: ...to Create #### pkg/locals/resolver.go - Core Locals Resolution ```go package lo...

(DASH_RULE)


[typographical] ~966-~966: To join two clauses or introduce examples, consider using an em dash.
Context: ...to Modify #### 1. pkg/config/const.go - Add Constant ```go // Add to existing c...

(DASH_RULE)


[typographical] ~973-~973: To join two clauses or introduce examples, consider using an em dash.
Context: ...ack_processor_process_stacks_helpers.go` - Add to Processor Options ```go // Add t...

(DASH_RULE)


[typographical] ~988-~988: To join two clauses or introduce examples, consider using an em dash.
Context: .../exec/stack_processor_process_stacks.go` - Extract & Resolve Locals Integration po...

(DASH_RULE)


[typographical] ~1047-~1047: To join two clauses or introduce examples, consider using an em dash.
Context: ...or_process_stacks_helpers_extraction.go` - Component Locals Add extraction of comp...

(DASH_RULE)


[typographical] ~1074-~1074: To join two clauses or introduce examples, consider using an em dash.
Context: ...### 5. internal/exec/template_utils.go - Add Locals to Template Context When bui...

(DASH_RULE)


[typographical] ~1090-~1090: To join two clauses or introduce examples, consider using an em dash.
Context: ...internal/exec/stack_processor_merge.go - Exclude Locals from Merge Ensure locals...

(DASH_RULE)


[typographical] ~1111-~1111: To join two clauses or introduce examples, consider using an em dash.
Context: ...her/schema/stacks/stack-config/1.0.json- Schema Updates Addlocals` to allowed ...

(DASH_RULE)


[grammar] ~1169-~1169: Please add a punctuation mark at the end of paragraph.
Context: ...s describe locals command, follow this pattern 2. **Flag Handling** (pkg/flags/`): ...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1371-~1371: Consider using a typographic opening quote here.
Context: ...lable locals list - Add typo detection ("did you mean?") using Levenshtein distan...

(EN_QUOTES)


[typographical] ~1371-~1371: Consider using a typographic close quote here.
Context: ...ist - Add typo detection ("did you mean?") using Levenshtein distance **Optional...

(EN_QUOTES)


[grammar] ~1371-~1371: Please add a punctuation mark at the end of paragraph.
Context: ...ion ("did you mean?") using Levenshtein distance Optional: Migrate IsGolangTemplate...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1407-~1407: Consider using typographic quotation marks here.
Context: ...]string- Filter refs by prefix (e.g., "locals") -walkAST(node, fn)` - Recursive AST ...

(EN_QUOTES)


[grammar] ~1409-~1409: Please add a punctuation mark at the end of paragraph.
Context: ...l` - Detect if string contains template actions Test coverage: - Simple field refs...

(PUNCTUATION_PARAGRAPH_END)


[typographical] ~1635-~1635: Consider using a typographic opening quote here.
Context: ...locals on failure - Typo detection with "did you mean?" suggestions - `atmos desc...

(EN_QUOTES)


[typographical] ~1635-~1635: Consider using a typographic close quote here.
Context: ...ure - Typo detection with "did you mean?" suggestions - atmos describe locals c...

(EN_QUOTES)


[grammar] ~1795-~1795: Please add a punctuation mark at the end of paragraph.
Context: ...omponentEnvSection` - Contains resolved values **2. Stack Processor (where locals are...

(PUNCTUATION_PARAGRAPH_END)


[style] ~1806-~1806: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...g/component/provider.go:** No changes needed. The ComponentConfig map[string]any` a...

(EN_REPEATEDWORDS_NEED)

🪛 markdownlint-cli2 (0.18.1)
docs/prd/file-scoped-locals.md

207-207: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


218-218: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


227-227: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


299-299: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1399-1399: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1424-1424: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1502-1502: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1592-1592: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1610-1610: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1767-1767: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ 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

@aknysh aknysh merged commit 3840735 into main Dec 17, 2025
57 checks passed
@aknysh aknysh deleted the osterman/locals-prd branch December 17, 2025 18:26
@mergify mergify bot removed the needs-cloudposse Needs Cloud Posse assistance label Dec 17, 2025
@github-actions
Copy link
Copy Markdown

Warning

Changelog Entry Required

This PR is labeled minor or major but doesn't include a changelog entry.

Action needed: Add a new blog post in website/blog/ to announce this change.

Example filename: website/blog/2025-12-17-feature-name.mdx

Alternatively: If this change doesn't require a changelog entry, remove the minor or major label.

@github-actions
Copy link
Copy Markdown

These changes were released in v1.202.0-rc.5.

osterman added a commit that referenced this pull request Dec 18, 2025
* feat: Add file-scoped locals to stack configurations

Implements file-scoped locals for Atmos stack manifests, similar to Terraform and Terragrunt. Locals enable temporary variables that are available within a single file with dependency resolution and circular dependency detection.

Key features:
- Locals defined at global, component-type, and component scopes
- Dependency resolution using topological sorting
- Circular dependency detection with clear error messages
- File-scoped isolation (no inheritance across imports)
- Integration with describe locals command with provenance tracking

Includes comprehensive test scenarios and documentation.

🤖 Generated with Claude Code

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

* fix: Correct broken links in file-scoped locals blog post

🤖 Generated with Claude Code

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

* add tests, fix issues, add/update docs

* address comments, update docs

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>
Co-authored-by: aknysh <andriy.knysh@gmail.com>
aknysh added a commit that referenced this pull request Dec 18, 2025
* feat: Add file-scoped locals to stack configurations

Implements file-scoped locals for Atmos stack manifests, similar to Terraform and Terragrunt. Locals enable temporary variables that are available within a single file with dependency resolution and circular dependency detection.

Key features:
- Locals defined at global, component-type, and component scopes
- Dependency resolution using topological sorting
- Circular dependency detection with clear error messages
- File-scoped isolation (no inheritance across imports)
- Integration with describe locals command with provenance tracking

Includes comprehensive test scenarios and documentation.

🤖 Generated with Claude Code



* fix: Correct broken links in file-scoped locals blog post

🤖 Generated with Claude Code



* add tests, fix issues, add/update docs

* address comments, update docs

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>
Co-authored-by: aknysh <andriy.knysh@gmail.com>
@github-actions
Copy link
Copy Markdown

These changes were released in v1.203.0-test.1.

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/xl Extra large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants