Skip to content

Operational repos: line endings follow the consuming app's platform - #288

Merged
ptr727 merged 2 commits into
developfrom
feature/operational-eol-per-repo
Jul 13, 2026
Merged

Operational repos: line endings follow the consuming app's platform#288
ptr727 merged 2 commits into
developfrom
feature/operational-eol-per-repo

Conversation

@ptr727

@ptr727 ptr727 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

A config repo is a view into an application's configuration directory (often the exact tree mounted into that app's container), so its files must use the line ending the app itself reads and writes - not the fleet CRLF default. Encode this per repo instead of forcing one rule on all config repos.

  • AGENTS.md "Line Endings": operational repos set the global [*] end_of_line default to the consuming app's native platform - LF for Linux-native/container config (ESPHome, Home Assistant, devcontainer-only/HACS), CRLF for a Windows-native editor (Vantage-Config / Design Center). Execution-sensitive LF pins still apply; do not re-normalize such a repo to the fleet default.
  • registry: new lineEndings field (lf | crlf); set lf on ESPHome-Config, HomeAssistant-Config, HomeAutomation and crlf on Vantage-Config; schema + validate.py enforce the enum.
  • spec/project-types.json recurring.eol: the global default is CRLF for release repos or the registry lineEndings value for operational repos.

Context

Surfaced during the operational-repo rollout: ESPHome-Config uses a global end_of_line = lf (it is edited as the ESPHome container's /config view). Matching the app's platform is correct; converging it to fleet-CRLF would be over-normalization.

Verification

python3 spec/validate.py passes (rejects an invalid lineEndings); markdownlint + cspell clean on AGENTS.md.

🤖 Generated with Claude Code

A config repo is a view into an application's configuration directory (often
the tree mounted into that app's container), so its files must use the ending
the app itself reads and writes - not the fleet CRLF default. Encode this per
repo instead of forcing one rule on all config repos.

- AGENTS.md "Line Endings": operational repos set the global [*] end_of_line
  default to the app's native platform (LF for Linux-native/container config -
  ESPHome, Home Assistant, devcontainer-only/HACS; CRLF for a Windows-native
  editor - Vantage/Design Center); execution-sensitive LF pins still apply;
  do not re-normalize such a repo to the fleet CRLF default.
- registry: add a lineEndings field (lf | crlf); set lf on ESPHome-Config,
  HomeAssistant-Config, HomeAutomation and crlf on Vantage-Config; schema +
  validate.py enforce the enum.
- spec/project-types.json recurring.eol: the global default is CRLF for
  release repos or the registry lineEndings value for operational repos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 16:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces per-repository line-ending policy for operational (config) repos, so their global .editorconfig default can match the consuming application's native platform instead of forcing the fleet CRLF default.

Changes:

  • Add a lineEndings (lf | crlf) field to the fleet registry schema and set it for selected operational repos.
  • Extend spec/validate.py to validate lineEndings values in registry entries.
  • Update governance/docs assertions (AGENTS.md + project-types recurring checks) to describe the operational-repo line-ending rule.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/validate.py Adds validation for the new lineEndings registry field.
spec/project-types.json Updates the recurring EOL check text to incorporate operational-repo defaults from the registry.
registry/repos.schema.json Adds the lineEndings field definition to the registry schema.
registry/repos.json Populates lineEndings for specific operational repos (LF for Linux-native configs, CRLF for Windows-native editor configs).
AGENTS.md Documents the operational-repo exception: global EOL default follows the consuming app platform.

Comment thread registry/repos.schema.json
Comment thread spec/validate.py
Enforce the intended invariant both ways: registry schema adds a conditional
(if workflowModel == operational then lineEndings required), and validate.py
fails an operational repo that omits lineEndings. Release repos still omit it
and use the fleet CRLF default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 16:31
@ptr727
ptr727 merged commit b3a0827 into develop Jul 13, 2026
7 checks passed
@ptr727
ptr727 deleted the feature/operational-eol-per-repo branch July 13, 2026 16:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread spec/validate.py
Comment on lines +127 to +133
eol = repo.get("lineEndings")
if eol is not None and eol not in ("lf", "crlf"):
errors.append(f"{name}: lineEndings '{eol}' invalid (expected lf or crlf)")
# An operational repo's endings follow the consuming app's platform, so they must be declared; a release
# repo omits the field and uses the fleet CRLF default.
if model == "operational" and eol is None:
errors.append(f"{name}: operational repo must declare lineEndings (lf or crlf)")
Comment on lines +34 to +40
"allOf": [
{
"comment": "An operational repo must declare its line endings (release repos use the fleet CRLF default).",
"if": { "properties": { "workflowModel": { "const": "operational" } }, "required": ["workflowModel"] },
"then": { "required": ["lineEndings"] }
}
],
Comment thread AGENTS.md

- **[`.editorconfig`](./.editorconfig) sets the line ending:** `[*] end_of_line = crlf` is the **default** - every file type is CRLF unless pinned otherwise - with **LF** pinned for the execution-sensitive exceptions - `*.sh`, Dockerfiles, and any individual `.py` executed directly via its shebang (pinned **by path**, e.g. `spec/validate.py`; vanilla `.py` stays CRLF, since Python's universal newlines accept it and it is commonly edited on Windows). Only the LF exceptions are declared; the redundant per-type CRLF rules are intentionally omitted. `.gitattributes` mirrors it: `* -text` (git stores the exact bytes you commit and will **not** normalize) plus the matching LF pins.
- **Choosing an ending for a new file type:** CRLF is the **default** - cross-platform editors on Windows produce it, and it is harmless on Linux for everything except shell. Use LF only when the type **requires** it or CRLF **breaks how it is consumed**: executable scripts/shebangs (`*.sh`, s6, husky), Dockerfiles (CRLF breaks `RUN` heredocs/continuations), and tool-owned formats with a native LF ending (KiCad). **Non-workflow YAML stays CRLF** - GitHub Actions' parser tolerates it (a repo that also runs yamllint sets `new-lines: disable` to defer to `.editorconfig`). **Workflow YAML (`.github/workflows/*.{yml,yaml}`) is pinned LF** in `.editorconfig` - Dependabot and Actions rewrite it with LF, so declaring LF keeps it consistent instead of mixed on every bump. This (and the catalog snippet workflows in `catalog/snippets/workflows/*`, pinned LF the same way) is an LF class **not** backed by a `.gitattributes` pin: git keeps `* -text` (no normalization), and CI's `editorconfig-checker` (EOL-only) catches a mismatch instead. Distinguish where a file is *consumed* from where it is *edited*: consumption on Linux alone does not force LF. A config or pattern file consumed by a Linux tool stays CRLF when the tool tolerates a trailing CR: `.dockerignore` and `.gitignore` are CRLF (their parsers strip the CR), and only a *Dockerfile* - interpreted, where a CR breaks `RUN` heredocs and line continuations - is LF.
- **Operational (config) repos: the global default follows the consuming application's native platform, not the fleet CRLF default.** A config repo (registry `workflowModel: operational`) is a *view into an application's configuration directory* - often the exact tree mounted into that app's container - so its files must use the ending the app itself reads and writes, and forcing the fleet CRLF default would fight the app. Set the `[*] end_of_line` default to the app's native ending and record it in the registry [`lineEndings`](./registry/repos.json) field (`lf` | `crlf`): **LF** for a Linux-native app whose config lives in a Linux container - ESPHome, Home Assistant, a devcontainer-only or HACS config - and **CRLF** for a Windows-native editor - e.g. Vantage-Config, edited by Design Center on Windows. The execution-sensitive LF pins (`*.sh`, Dockerfiles, workflow YAML) still apply on top, and `.gitattributes` still mirrors the chosen default. This override is for operational repos only; `release` repos keep the `[*] end_of_line = crlf` fleet default above. Do **not** re-normalize such a repo to the fleet default - that is exactly the over-normalization these per-repo endings prevent.
ptr727 added a commit that referenced this pull request Jul 13, 2026
…epos (#292)

Promote the current `develop` snapshot to `main`.

Adds the **operational** workflow model and its supporting rules/tooling
(PRs #287-#291):

- **#287** operational `workflowModel` (direct-to-`develop` live-config
repos; shared `main` ruleset; dispatch-only releases; model-aware
`configure.sh`).
- **#288** per-repo `lineEndings` field (operational repos follow the
consuming app's platform; validated).
- **#289** mixed-consumer EOL guidance (prefer splitting by platform);
dropped the standalone Vantage-Config catalog entry (later re-added,
recreated single-platform).
- **#290** renamed `HomeAutomation` -> `HomeAutomation-Config`; EOL
guidance leads with the split-preferred approach.
- **#291** CODESTYLE.md defers line-ending governance to AGENTS.md (was
hardcoding CRLF, contradicting `lf` operational repos).

Applied end-to-end to ESPHome-Config, HomeAutomation-Config,
HomeAssistant-Config (lf) and the recreated Vantage-Config (crlf).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants