Skip to content

Repository files navigation

Engineering conventions

musher-dev/engineering-conventions is the authoritative home for Musher's shared engineering language, repository structures and implementation expectations. It defines the conventions, publishes the checks that validate them, and releases both as a versioned bundle that other repositories pin. It does not run application code, and it does not host CI for other repositories.

Status: v0, draft. Every requirement is proposed at severity warning: a finding is advice, not a failure. The GitHub Actions conventions are derived from checks owned by musher-dev/platform, which stays their authority until a single handoff moves them here; where they differ from the platform, the difference is a proposal it adopts then (decision 0002).

What a convention is

A convention is a published, versioned decision about how one part of a repository is named, structured or configured, written as requirements with permanent IDs that tools can check and people can cite.

Each piece has one job:

Piece Example What it is
Topic github-actions The part of a repository the conventions govern, named for its files or tool
Convention EC-0002 Workflow files A document that states related requirements and explains why
Requirement GHA-07 One normative statement, with an ID that never changes or gets reused
Check a Rego policy Code that finds violations of a requirement
Diagnostic warning [GHA-07] … A finding in your repository, linking back to the requirement's heading

For example, GHA-07 says a workflow's name is its filename stem in Title Case. A repository whose .github/workflows/validate.yml says name: CI gets:

GHA-07  warning  1 finding
A workflow's name is its filename stem in Title Case
https://github.com/musher-dev/engineering-conventions/blob/vX.Y.Z/engineering-conventions/definitions/conventions/github-actions/workflow-files.md#gha-07
  .github/workflows/validate.yml
    name "CI" should be "Validate": a workflow's name is its filename stem in Title Case

If it helps, think of a building code:

Building code Here
The code book The conventions
A numbered section of the code A requirement, such as GHA-07
The inspector's checklist The checks
The class of building (house, warehouse) A convention profile, such as base-repo
The edition a permit cites The release a repository pins
A granted variance, with an end date A waiver in .repo/conventions.toml

A convention is not a template you copy (nothing here is applied to your repository), not a matter of taste (each requirement names the failure it prevents), and not a definition of a word that another repository owns.

How it fits together

What is decided lives in definitions/. What checks it lives in checks/. Both ship as one release, and each repository pins a release and checks itself against it.

flowchart LR
  subgraph defined["Defined here: definitions/"]
    conventions["Conventions and requirements<br/>EC-0002, GHA-07"]
    terminology["Terminology"]
    profiles["Profiles"]
  end
  subgraph checked["Checked here: checks/"]
    rego["Rego policies"]
    schemas["JSON Schemas"]
    generated["index.json, Vale style<br/>(generated)"]
  end
  release[["Release vX.Y.Z<br/>bundle, checksums, attestation"]]
  subgraph yours["Your repository"]
    pin[".config/mise/config.toml pin"]
    declarations[".repo/conventions.toml<br/>.repo/outputs.toml<br/>.repo/repository.toml"]
    check["conventions check"]
  end
  upstream["Defined elsewhere<br/>platform, specifications,<br/>observability-schema-registry"]

  defined -- "task generate" --> generated
  generated --> rego
  defined --> release
  checked --> release
  release -- "pinned by" --> pin
  pin --> check
  declarations --> check
  check -. "diagnostic links to ### GHA-07" .-> conventions
  upstream -. "authority pointer" .-> terminology
Loading

Inside the product directory, engineering-conventions/, the layers are directories: definitions/ is decided, checks/ validates, examples/ shows a conforming repository, and bin/ and src/ are the tooling that runs the checks. How this repository is organized says where every file goes.

Find a convention by what it governs

Start from the part of your repository you are working on:

Topic Governs in your repository Conventions Requirements
Adoption The release pin in .config/mise/config.toml, .repo/conventions.toml EC-0001 ADOPT-01 – ADOPT-11
Agents CLAUDE.md, .claude/rules/, AGENTS.md EC-0013 AGENT-01 – AGENT-08
Configuration .config/, tool configuration at the root, scanner ignore files EC-0011, EC-0012 CONF-01 – CONF-12
Decisions docs/decisions/, the decision records EC-0021 DEC-01 – DEC-07
Dev containers .devcontainer/: devcontainer.json, its lockfile, its Dockerfile and compose stacks EC-0027, EC-0028 DEVC-01 – DEVC-13
Environment <product>/env.schema.yaml, .devcontainer/env.schema.yaml EC-0019, EC-0020 ENVS-01 – ENVS-15
Git hooks .config/lefthook.yml EC-0014 HOOKS-01 – HOOKS-11
GitHub Actions .github/workflows/, .github/actions/ EC-0002 – EC-0006, EC-0022, EC-0023 GHA-01 – GHA-49
Outputs .repo/outputs.toml, publish workflows EC-0007, EC-0008 OUT-01 – OUT-12
Releases .github/release-please/, the release tag ruleset, release.yml EC-0024 – EC-0026 REL-01 – REL-20
Repository .repo/repository.toml, the repository's name, where the product lives EC-0009, EC-0010, EC-0018 REPO-01 – REPO-22
Tasks Taskfile.yml, taskfiles/ EC-0015, EC-0016 TASK-01 – TASK-14
Toolchain .config/mise/config.toml and every version pinned outside it EC-0017 TOOL-01 – TOOL-11

A topic's README gives the reading order. Two other ways in:

  • By ID. A diagnostic names its requirement and links to the ### <ID> heading, its permanent address. The generated index of every ID lists every one ever issued, retired ones included.
  • By machine. engineering-conventions/checks/data/index.json holds every requirement with its title, status, severity, convention, path and anchor, plus the profiles and the vocabulary.

What this repository owns, and what it doesn't

The rule of thumb: it owns the rules about things, not the things. Something can live here when many repositories need the same answer and a check can cite it by ID. One repository's own rule stays in that repository, and a word or format another repository defines gets a pointer, not a copy.

Owned here Not owned here
That a workflow that publishes is named publish[-<scope>].yml (GHA-02) Your publish workflow, what it builds, when it runs
The format of .repo/outputs.toml and what each output states (EC-0007) The image, its registry, or a catalog that collects declarations
The repository-name grammar <system>-<component>, the registered systems, and .repo/repository.toml (EC-0009, EC-0010) Which teams exist and who is in them; applying names and properties to the organization
validate as a workflow token, and its banned synonyms ci and checks Platform domain nouns, telemetry names, the customer glossary
The checks, and the release that ships them Running them: your CI runs conventions check
What a waiver must state and how long it may last Whether your repository needs one

Where the rest lives:

Not owned here Owned by
How the company operates: rituals, planning, the operating model musher-dev/company
Telemetry names: spans, metrics, attributes, events musher-dev/observability-schema-registry
Document specifications: the component, blueprint and catalog formats musher-dev/specifications
Positioning, product vocabulary, the customer glossary, platform domain nouns musher-dev/platform and musher-dev/company
The development-container scaffold: the container, its toolchain setup, its stacks musher-dev/development-container
Teams and their membership musher-dev/company, applied by musher-dev/infra-github
Applying repository names, custom properties and rulesets to the organization musher-dev/infra-github
Rules local to one repository That repository

A repository's own rule may be stricter than a convention here, never contradictory. The charter is the authority for this boundary.

Using the conventions in another repository

Pin a release in .config/mise/config.toml and run one command, the same locally and in CI:

min_version = "2026.9.12"

[tools]
"github:musher-dev/engineering-conventions" = "0.6.3"  # x-release-please-version
conventions check

It prints a report grouped by requirement; --output json prints the findings for a program to read. mise verifies the release's checksum and build provenance, and Renovate raises the pin. To try it without changing anything:

mise exec github:musher-dev/engineering-conventions@0.6.3 -- conventions check  # x-release-please-version

The details, and the path without mise, are in Consuming the conventions.

Documentation

Read When you want to
Consuming the conventions adopt a release, declare outputs, read a diagnostic, add a waiver
Authoring conventions propose or change a requirement or a term
Versioning know what a release number promises
How this repository is organized know where a file goes
Decisions understand why the repository works the way it does

Working on this repository

Open the repository in its dev container (or install the pinned tools with mise), then:

task setup     # install the pinned toolchain, the authoring CLI and the git hooks
task check     # every gate CI runs, except the dev container build

To add or change a requirement, read Authoring conventions and CONTRIBUTING.md.

Releases

Releases are cut by release-please from Conventional Commit titles. Each vX.Y.Z release attaches the bundle tarball, the MusherConventions Vale package, a manifest, SHA256SUMS, and a build-provenance attestation. The version number says what an upgrade can break; see Versioning.

Security

See SECURITY.md to report a vulnerability.

About

The authoritative source for Musher's engineering conventions: shared terminology, repository and GitHub Actions requirements, and the Conftest, JSON Schema and Vale rules that check them.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages