feat(pre-commit): generate a managed .gitattributes pinning the tree to LF #1164

Merged
coilysiren merged 1 commit from feat/managed-gitattributes into main 2026-08-20 10:20:59 +00:00
Owner

* text=auto is a trap that four repos are currently in. It marks a file as text without pinning what the working tree gets, so under core.autocrlf=true a Windows checkout takes CRLF and a Linux one takes LF. The index agrees and git diff is empty, so nothing looks wrong until a tool reads bytes.

It has already cost us twice:

  • agent-compose read two byte-identical copies of repo-coilysiren as a non-identical collision and refused to compose a role.
  • shellcheck reports SC1017 on every line of the skill scripts here, which is why this repo's .gitattributes had grown seven per-extension patches and an agentic-os#317 comment. eol=lf is what those patches were reaching for, and it replaces all of them.

Where the fleet stands

  • Already correct (* text=auto eol=lf): agent-compose, cli-guard, infrastructure, ward, coilysiren
  • The broken middle (* text=auto, no eol): agentic-os, agentic-os-kai, eco-mods, eco-ops
  • Barely anything (*.sh only): agentic-os-xxx, deploy, eco-app
  • Nothing at all: agentic-os-hardware

Shape

The rollout now writes a marker-delimited block into each consumer's .gitattributes, beside the pre-commit block it already manages:

* text=auto eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf

Batch keeps CRLF as the one format where LF genuinely misbehaves. PowerShell does not need it: infrastructure already ships 13 .ps1 files under this rule.

The block goes first, never appended, because git takes the last matching pattern per attribute and a general * below a repo's LFS lines would override them. A tree under [tool.agentic-os.managed-hooks] vendored gets -text and keeps upstream's bytes, reusing the declaration the fixer excludes already read rather than inventing a second list.

Vendor orgs

VENDOR_ORGS skips an org dir of upstream checkouts whole. This closes a hazard that predates the change: iter_workspace_repos is owner-agnostic by design, so a full run would have written a .pre-commit-config.yaml into StrangeLoopGames/Eco, and a managed * rule would have overridden its deliberate *.cs text eol=crlf.

Verified

pre-commit run --all-files in this repo is clean for the first time on a Windows checkout, shellcheck included. Five new tests cover the pin, vendored -text, first-not-last placement, idempotent refresh, and the vendor-org skip.

A dry run across the fleet covers 11 repos and skips four:

agentic-os-hardware   dryrun   refresh agentic-os block, gitattributes create
agentic-os-kai        dryrun   refresh agentic-os block, gitattributes prepend
...
agentic-os            skipped  self (source repo)
coilysiren            skipped  opted out (.agentic-os-ignore)
Eco                   skipped  vendor org (StrangeLoopGames)
Eco.wiki              skipped  vendor org (StrangeLoopGames)

Not in this PR

Changing .gitattributes does not convert anything already checked out. git add --renormalize . does, and it rewrites the working tree, so each repo wants a clean tree and a deliberate commit. eco-ops in particular has an uncommitted whitespace sweep sitting in it (per #1159), so it needs care rather than a fleet sweep.

`* text=auto` is a trap that four repos are currently in. It marks a file as text without pinning what the working tree gets, so under `core.autocrlf=true` a Windows checkout takes CRLF and a Linux one takes LF. The index agrees and `git diff` is empty, so nothing looks wrong until a tool reads bytes. It has already cost us twice: * agent-compose read two byte-identical copies of `repo-coilysiren` as a non-identical collision and refused to compose a role. * `shellcheck` reports `SC1017` on every line of the skill scripts here, which is why this repo's `.gitattributes` had grown seven per-extension patches and an `agentic-os#317` comment. `eol=lf` is what those patches were reaching for, and it replaces all of them. ## Where the fleet stands * Already correct (`* text=auto eol=lf`): agent-compose, cli-guard, infrastructure, ward, coilysiren * The broken middle (`* text=auto`, no `eol`): agentic-os, agentic-os-kai, eco-mods, eco-ops * Barely anything (`*.sh` only): agentic-os-xxx, deploy, eco-app * Nothing at all: agentic-os-hardware ## Shape The rollout now writes a marker-delimited block into each consumer's `.gitattributes`, beside the pre-commit block it already manages: ```gitattributes * text=auto eol=lf *.bat text eol=crlf *.cmd text eol=crlf ``` Batch keeps CRLF as the one format where LF genuinely misbehaves. PowerShell does not need it: infrastructure already ships 13 `.ps1` files under this rule. The block goes **first**, never appended, because git takes the last matching pattern per attribute and a general `*` below a repo's LFS lines would override them. A tree under `[tool.agentic-os.managed-hooks] vendored` gets `-text` and keeps upstream's bytes, reusing the declaration the fixer excludes already read rather than inventing a second list. ## Vendor orgs `VENDOR_ORGS` skips an org dir of upstream checkouts whole. This closes a hazard that predates the change: `iter_workspace_repos` is owner-agnostic by design, so a full run would have written a `.pre-commit-config.yaml` into `StrangeLoopGames/Eco`, and a managed `*` rule would have overridden its deliberate `*.cs text eol=crlf`. ## Verified `pre-commit run --all-files` in this repo is clean for the first time on a Windows checkout, `shellcheck` included. Five new tests cover the pin, vendored `-text`, first-not-last placement, idempotent refresh, and the vendor-org skip. A dry run across the fleet covers 11 repos and skips four: ``` agentic-os-hardware dryrun refresh agentic-os block, gitattributes create agentic-os-kai dryrun refresh agentic-os block, gitattributes prepend ... agentic-os skipped self (source repo) coilysiren skipped opted out (.agentic-os-ignore) Eco skipped vendor org (StrangeLoopGames) Eco.wiki skipped vendor org (StrangeLoopGames) ``` ## Not in this PR Changing `.gitattributes` does not convert anything already checked out. `git add --renormalize .` does, and it rewrites the working tree, so each repo wants a clean tree and a deliberate commit. eco-ops in particular has an uncommitted whitespace sweep sitting in it (per #1159), so it needs care rather than a fleet sweep.
feat(pre-commit): generate a managed .gitattributes pinning the tree to LF
All checks were successful
ci / aos-cli-tests (pull_request) Successful in 3m39s
ci / aos-eval-tests (pull_request) Successful in 6s
ci / ward-doctor (pull_request) Successful in 3m19s
ci / gate (pull_request) Successful in 4m4s
f8b5571c9c
`* text=auto` is a trap that four repos are currently in. It marks a file
as text without pinning what the working tree gets, so under
core.autocrlf=true a Windows checkout takes CRLF and a Linux one takes
LF. The index agrees and `git diff` is empty, so nothing looks wrong
until a tool reads bytes.

It has already cost us twice. agent-compose read two byte-identical
copies of repo-coilysiren as a non-identical collision and refused to
compose. shellcheck reports SC1017 on every line of the skill scripts in
this repo, which is why this file had grown seven per-extension patches
and an agentic-os#317 comment. `eol=lf` is what those patches were
reaching for, and it replaces all of them.

## Shape

The rollout now writes a marker-delimited block into each consumer's
.gitattributes, beside the pre-commit block it already manages:

    * text=auto eol=lf
    *.bat text eol=crlf
    *.cmd text eol=crlf

Batch keeps CRLF as the one format where LF genuinely misbehaves.
PowerShell does not need it: infrastructure already ships 13 .ps1 files
under this rule.

The block goes first, never appended, because git takes the last
matching pattern per attribute and a general `*` below a repo's LFS
lines would override them. A tree under
`[tool.agentic-os.managed-hooks] vendored` gets `-text` and keeps
upstream's bytes, reusing the declaration the fixer excludes already
read rather than inventing a second list.

## Vendor orgs

VENDOR_ORGS skips an org dir of upstream checkouts whole. This closes a
hazard that predates the change: iter_workspace_repos is owner-agnostic,
so a full run would have written a .pre-commit-config.yaml into
StrangeLoopGames/Eco, and a managed `*` rule would have overridden its
deliberate `*.cs text eol=crlf`.

## Verified

`pre-commit run --all-files` in this repo is clean for the first time on
a Windows checkout, shellcheck included. A dry run across the fleet
covers 11 repos and skips four: the source repo, an opted-out repo, and
both vendor checkouts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
coilysiren deleted branch feat/managed-gitattributes 2026-08-20 10:20:59 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1164
No description provided.