Principles¶
Reusable technical claims, each one a thing I would want true in any of my work (if applicable). Start here if you are setting up a project and want the settled answers.
Listed roughly in the order they build on each other rather than alphabetically, starting from the most general.
- Treat warnings as errors - the most general of these: keep the warning count at zero so a new one is visible
- Guard invariants at commit-time, not review-time - the case for spending automation instead of reviewer attention
- Mirror every local guard in CI - why the commit hook alone is not the boundary
- Autofix in the hook, don't just flag - when a hook should edit the file rather than complain about it
- Order auto-fixers so later ones do not re-dirty earlier output - what goes wrong once you have more than one fixer
- Verify a pre-commit hook's file-type filter actually matches your file - how a hook can pass without ever having looked at your file
- A markdown autofixer can corrupt YAML frontmatter it treats as content - the specific way an autofixer eats a frontmatter block
- Pin pre-commit hooks to frozen revisions - hooks run arbitrary code on your tree, so pin them like dependencies
- Pin GitHub Actions to full commit SHAs - the same argument for CI, where a tag is a mutable pointer at your secrets
- Pin transitive runtime dependencies, not just the tool - pinning the tool is not enough when the tool launches a browser
- Install from a frozen lockfile in CI - making CI fail on a stale lockfile instead of quietly resolving around it
- Batch dependency updates with a cooldown, not a firehose - how to keep an update bot from becoming noise you learn to ignore
- Keep transitive dependencies in the regular update cycle - the packages nobody chose, which is why nobody is watching them
- Keep declared toolchain versions in sync, and guard it - what to do when the same fact has to live in two files
- Validate config files against their published schema - linting the configuration, not just the content
- Document a rationale for every disabled lint rule - why a bare suppression is indistinguishable from an accident
- Grant least-privilege CI permissions at both workflow and job level - scoping a CI token twice, so a job holds only what it uses
- Split CI jobs for attributable failure and minimal dependencies - cutting a workflow where you want the red check to point
- Name every CI step so the run log reads as a narrative - making a failing run readable before you expand anything
- Bound every CI job with an explicit timeout - the six-hour default, and why it is never what you meant
- Cancel superseded CI runs with a concurrency group - not spending a runner on a commit nobody is waiting for any more
- Run CI steps under a strict shell (errexit, pipefail) - the failure a lenient shell swallows in the middle of a pipe
- A test that cannot run must fail loudly, never skip into a green result - the difference between a check that passed and a check that never ran
- A sandbox test must use the live working-tree source and rebuild fresh each run - how a sandbox test starts testing a stale copy of itself
- End-to-end test an LLM skill by driving a real agent in a disposable fake HOME - testing a markdown procedure by running an agent against it, not by grepping it
- A microbenchmark body must not mutate state that outlives one iteration - what the harness measures once it is running your setup's leftovers instead of your input
- Enforce LF line endings everywhere - declaring line endings in more than one place, because one is not believed
- Declare formatting once, editor-agnostically, via .editorconfig - the one formatting declaration every editor already reads
- Keep filenames lowercase with no whitespace - a portability constraint worth a guard, where it applies
- Make support-tool config files dotfiles - keeping the repo root about the project rather than its plumbing
- Track every committed binary type in .gitattributes - not trusting Git to guess which of your files are opaque
- Enforce a canonical author identity via .mailmap - one person, one identity in the history, checked mechanically
- Keep a linear history: block merge, fixup and squash commits - what it takes to actually get the linear history you asked for
- Make the build interface a self-documenting Makefile - one entry point whose help text cannot drift from its targets
- Fail early on a missing tool with a message that names it and points at the fix - the difference between a guard and a bare command not found
- Do not make a tool a prerequisite for work it is not needed for - checking that a listed requirement is on a path anyone walks
- Resolve a repo's own dev tools through an ephemeral runner, not a project virtualenv - why a git hook must not depend on a virtualenv being active
- Use PEP 723 inline script metadata for zero-install tooling scripts - a standalone script that carries its own dependencies
- A declared-but-inert config documents intent, not enforcement - keeping a rule that fires on nothing, without believing it protects you
- Test a config layering assumption with a marker key - the one-line experiment that says whether layers merge or replace, before you copy a setting into all of them
- Enforce the intersection of all renderers and consumers - writing for the least capable tool that will read it
- Structure docs as the reader's task path - lead with action, defer rationale - organising a guide around what the reader does next
- Hand the reader one idea at a time - why honest, jargon-free prose can still be exhausting to read
- Name the concrete behaviour, not its abstract label - the re-read a category name causes where a behaviour would not
- Write in a calm, quantified, settled-fact voice - not a promotional one - the voice these pages are written in, and its tells on both sides
- Give every cross-cutting concept one definitional home - single source of truth, applied to prose instead of code
- Route a rule to the layer that reaches whoever must obey it - a page, a hook, a skill or an always-on instruction, chosen by who has to obey
Backlinks¶
The following pages link to this page:
- A declared-but-inert config documents intent, not enforcement
- A markdown autofixer can corrupt YAML frontmatter it treats as content
- A microbenchmark body must not mutate state that outlives one iteration
- A sandbox test must use the live working-tree source and rebuild fresh each run
- A test that cannot run must fail loudly, never skip into a green result
- Autofix in the hook, don't just flag
- Batch dependency updates with a cooldown, not a firehose
- Bound every CI job with an explicit timeout
- Cancel superseded CI runs with a concurrency group
- Declare formatting once, editor-agnostically, via .editorconfig
- Do not make a tool a prerequisite for work it is not needed for
- Document a rationale for every disabled lint rule
- End-to-end test an LLM skill by driving a real agent in a disposable fake HOME
- Enforce LF line endings everywhere
- Enforce a canonical author identity via .mailmap
- Enforce the intersection of all renderers and consumers
- Fail early on a missing tool with a message that names it and points at the fix
- Give every cross-cutting concept one definitional home
- Grant least-privilege CI permissions at both workflow and job level
- Guard invariants at commit-time, not review-time
- Hand the reader one idea at a time
- Index
- Install from a frozen lockfile in CI
- Keep a linear history: block merge, fixup and squash commits
- Keep declared toolchain versions in sync, and guard it
- Keep filenames lowercase with no whitespace
- Keep transitive dependencies in the regular update cycle
- Make support-tool config files dotfiles
- Make the build interface a self-documenting Makefile
- Mirror every local guard in CI
- Name every CI step so the run log reads as a narrative
- Name the concrete behaviour, not its abstract label
- Order auto-fixers so later ones do not re-dirty earlier output
- Pin GitHub Actions to full commit SHAs
- Pin pre-commit hooks to frozen revisions
- Pin transitive runtime dependencies, not just the tool
- Resolve a repo's own dev tools through an ephemeral runner, not a project virtualenv
- Route a rule to the layer that reaches whoever must obey it
- Run CI steps under a strict shell (errexit, pipefail)
- Split CI jobs for attributable failure and minimal dependencies
- Structure docs as the reader's task path - lead with action, defer rationale
- Test a config layering assumption with a marker key
- Track every committed binary type in .gitattributes
- Treat warnings as errors
- Use PEP 723 inline script metadata for zero-install tooling scripts
- Validate config files against their published schema
- Verify a pre-commit hook's file-type filter actually matches your file
- Write in a calm, quantified, settled-fact voice - not a promotional one