diff --git a/.agents/skills/python-codestyle/references/code-style.md b/.agents/skills/python-codestyle/references/code-style.md index 45f355bc..1941e0f3 100644 --- a/.agents/skills/python-codestyle/references/code-style.md +++ b/.agents/skills/python-codestyle/references/code-style.md @@ -64,7 +64,8 @@ ## Naming -- `snake_case` for functions, methods, variables, modules, package directories. +- `snake_case` for functions, methods, variables, modules, package directories. A module's file + name follows CODESTYLE.md's "Script and Utility File Names". - `PascalCase` for classes, type aliases, type vars, enum members. - `UPPER_SNAKE_CASE` for module-level constants. - Single leading underscore for module-private, double leading underscore for name-mangled (rare, diff --git a/.claude-plugin/fleet-skills/.source-digests/python-codestyle b/.claude-plugin/fleet-skills/.source-digests/python-codestyle index 6859deaa..07ed7b54 100644 --- a/.claude-plugin/fleet-skills/.source-digests/python-codestyle +++ b/.claude-plugin/fleet-skills/.source-digests/python-codestyle @@ -1 +1 @@ -047e89b805ed646f +bba583635a70530a diff --git a/.claude-plugin/fleet-skills/skills/python-codestyle/references/code-style.md b/.claude-plugin/fleet-skills/skills/python-codestyle/references/code-style.md index 45f355bc..1941e0f3 100644 --- a/.claude-plugin/fleet-skills/skills/python-codestyle/references/code-style.md +++ b/.claude-plugin/fleet-skills/skills/python-codestyle/references/code-style.md @@ -64,7 +64,8 @@ ## Naming -- `snake_case` for functions, methods, variables, modules, package directories. +- `snake_case` for functions, methods, variables, modules, package directories. A module's file + name follows CODESTYLE.md's "Script and Utility File Names". - `PascalCase` for classes, type aliases, type vars, enum members. - `UPPER_SNAKE_CASE` for module-level constants. - Single leading underscore for module-private, double leading underscore for name-mangled (rare, diff --git a/.github/skills/python-codestyle/references/code-style.md b/.github/skills/python-codestyle/references/code-style.md index 45f355bc..1941e0f3 100644 --- a/.github/skills/python-codestyle/references/code-style.md +++ b/.github/skills/python-codestyle/references/code-style.md @@ -64,7 +64,8 @@ ## Naming -- `snake_case` for functions, methods, variables, modules, package directories. +- `snake_case` for functions, methods, variables, modules, package directories. A module's file + name follows CODESTYLE.md's "Script and Utility File Names". - `PascalCase` for classes, type aliases, type vars, enum members. - `UPPER_SNAKE_CASE` for module-level constants. - Single leading underscore for module-private, double leading underscore for name-mangled (rare, diff --git a/CODESTYLE.md b/CODESTYLE.md index fa23048c..da7f86f5 100644 --- a/CODESTYLE.md +++ b/CODESTYLE.md @@ -41,6 +41,27 @@ A command-line script is one a person or an agent runs by name. A hook its host - **Every command-line script answers `--help` and `-h`** with the same text on stdout, then exits 0, changing nothing. That text opens on a usage line naming the script. An agent learns a script's interface by asking it, so a script that reads `--help` as an input acts in a way nobody predicted. - **An argument the script does not recognize is refused**, with a non-zero exit before any read or write. The refusal names it as an unknown or unrecognized option, argument, flag, or parameter, and PowerShell's own refusal of a parameter it cannot bind counts. An unrecognized first argument is never taken as a default mode or as a target. +### Script and Utility File Names + +| Type | Rule | Basis | +| --- | --- | --- | +| Python `.py` | lowercase snake_case | [PEP 8][pep8-names-link] module naming. A hyphenated module also cannot be named in an `import` statement | +| Shell `.sh` and PowerShell `.ps1` | lowercase-hyphenated | The Linux command convention. A cross-platform pair keeps one name, `sync-tools.sh` beside `sync-tools.ps1` | +| Windows batch `.cmd` and `.bat` | lowercase-hyphenated | The same convention as shell and PowerShell. A shim that puts a command on `PATH` takes the name of the command it provides, `sync-tools.cmd` launching `sync-tools.ps1` | +| PowerShell functions inside a `.ps1` | Verb-Noun with an approved verb (`Get-Verb`) | PSScriptAnalyzer `PSUseApprovedVerbs`. This is a command rule, not a file rule | +| Env and secret files | lowercase snake_case stem | `mail_relay.env`, `db_root_password` | +| Env variable names and CI secret names | UPPER_SNAKE_CASE | The POSIX and GitHub convention | + +- **Installed commands.** An executable or launcher on `PATH` or in a system slot (systemd, cron, run-parts, motd) is named as a command, whatever its language. That name is lowercase-hyphenated. It carries no extension unless the platform needs one to run it, such as `.cmd` or `.ps1` on Windows. +- **Wrapper exemption.** A thin launcher whose only job is to run a Python tool keeps that tool's stem, so `fetch_report.py`, `fetch_report.sh`, and `fetch_report.ps1` stay grouped together. It covers only a launcher run by its path. A launcher installed onto `PATH` or into a system slot is an installed command instead, such as `fetch-report` rather than `fetch_report`. +- **Externally fixed names are exempt.** That covers Git hook names, `__init__.py`, `conftest.py`, and Pester's `.Tests.ps1` suffix, whose stem mirrors the script under test. It covers a PowerShell data file (`.psd1`) whose name a tool fixes, such as a module manifest named for its module. `PSScriptAnalyzerSettings.psd1` is another, since PSScriptAnalyzer finds it by that name. It also covers any name a platform defines. +- **Directories are out of scope.** + +Departures, stated on purpose so a reader does not "fix" them back: + +- The [Google Shell Style Guide][google-shell-link] asks for underscores in shell file names. The fleet uses hyphens instead, matching installed Linux commands. +- Microsoft's [approved verbs][ps-approved-verbs-link] govern command names. A `.ps1` run by path is a file rather than an exported command, so the file takes the shell convention and its functions take Verb-Noun. + ### Markdown and Spelling These apply repo-wide, in every directory: Markdown lints clean via `markdownlint-cli2` against the shared config, spelling is US English via CSpell against the shared `cspell.json`, the CI spelling gate covers `README.md` and `HISTORY.md` only, `HISTORY.md` mirrors the README's opening, and "Markdown" is a proper noun in prose. A repo excluding a subtree of its own that it does not treat as authored prose, a committed data archive, a vendored theme, or a hand-maintained record, puts a `.markdownlint-cli2.jsonc` carrying its own `ignores` beside that content rather than editing the shared root config, whose contents are fleet-fixed. Those `ignores` patterns resolve against the directory holding them rather than against the repo root, so a repo-root-relative entry there matches nothing and reports no error saying so, and excluding through the CI workflow's own negated Markdown glob input instead is a CI-only fix that leaves the same files flagged for anyone running the linter locally. The full rules are in the `comment-and-doc-style` Skill referenced above. @@ -71,3 +92,9 @@ Bash, and only where a program cannot be Python: a bootstrap that installs the i [governance-verification-discipline]: ./GOVERNANCE.md#verification-discipline [readme]: ./README.md [root]: ./.editorconfig + + + +[google-shell-link]: https://google.github.io/styleguide/shellguide.html +[pep8-names-link]: https://peps.python.org/pep-0008/#package-and-module-names +[ps-approved-verbs-link]: https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 9038d571..e71c9501 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -109,6 +109,7 @@ Line-ending governance for an operational repo is in [Line Endings](#line-ending A repo whose own stacks or scripts read local runtime credentials from disk, most commonly an operational repo's Docker Compose stack, keeps them in a dotted `.secrets/` directory at the repo root. This is the repo-scoped counterpart to the host-scoped `~/.secrets/` convention a repo's own `OPERATIONS.md` may document, and it is a different thing from `spec/secrets.json`, the CI/GitHub Actions secret-name registry `spec/audit.py` cross-checks. `spec/secrets.json` governs what a workflow reads from GitHub Actions. This convention governs what a repo's own process reads from its own checkout. - **The directory is named `.secrets/`, dotted, never a bare `secrets/`.** +- **A secret file's stem is lowercase snake_case** (`homeassistant_db_password`, `mail_relay.env`), per [`CODESTYLE.md` "Script and Utility File Names"](./CODESTYLE.md#script-and-utility-file-names). - **A single opaque credential file carries no extension** (`homeassistant_db_password`, not `homeassistant_db_password.txt`), the same reason `README` and `LICENSE` carry none. It is a security property, read but never sourced, not a formatting preference. - **A structured credential keeps its format's extension** (`.json` for structured config). - **The shared env file is named for what it configures**, not a bare `.env` (`docker.env` for a repo whose stacks are Docker Compose), so a second env-shaped file added later stays unambiguous.