CI linting setup
How the project init wizard (see setup.md) wires keep-the-why-lint into a project's CI, and optionally into pre-commit. The linter validates the structure of .keep-the-why and the context directory — required fields, valid values, index consistency, hidden-content red flags — gated by the project's context-schema. It never judges content; that stays a human call. Consumer-facing documentation, the version scheme, and every finding code: https://keepthewhy.com/linting/
Detect, don't assume
Decide what to offer from what the repository actually shows — the same rule as autostart.md: don't invent or fake a mechanism for a platform the evidence doesn't support.
| Evidence | Offer |
|---|---|
.github/ directory exists, or the origin remote host is github.com |
GitHub Actions workflow |
.gitlab-ci.yml exists, or the origin remote host contains gitlab |
GitLab CI job |
Another CI's config is recognizable (Jenkinsfile, .circleci/, azure-pipelines.yml, .woodpecker.yml, ...) |
The generic pip snippet, shown — not written: don't author config for a CI whose format can't be verified here |
| No CI evidence at all | Nothing to write; mention the generic snippet once in case CI comes later |
.pre-commit-config.yaml exists |
Also offer the pre-commit hook |
No .pre-commit-config.yaml |
Don't offer pre-commit — introducing a new tool into a project that doesn't use it isn't setup, it's a separate decision |
Before writing anything, check that nothing equivalent already exists (a workflow or job that already runs ktw-lint, or references keep-the-why) — if it does, say so and skip; don't add a second copy.
What gets written
- GitHub Actions:
.github/workflows/ktw-lint.yml, the snippet below verbatim. The root of thekeep-the-whyrepository is a composite action that installs the latest linter from PyPI, so the consumer never pins anything. - GitLab CI: the
ktw-lintjob below, appended to.gitlab-ci.yml. If the file definesstages:, give the job astage:from that list (testif present, otherwise ask which) — a job without a stage falls back totest, which fails the pipeline when custom stages don't include it. If there's no.gitlab-ci.ymlat all but the remote is GitLab, creating one with only this job makes it the project's first pipeline — say that plainly before doing it. - pre-commit: the hook below, added under an existing
repo: localentry if there is one, otherwise as a new one. The keep-the-why repository root is not a Python package, so the hook pulls the linter from PyPI viaadditional_dependenciesrather than pointingrepo:at the skill repository. strict: "false"/ no--strictby default: warnings (a missingTypeon an old entry, a missing guard file) are "next time touched" material per the skill's own rules and shouldn't block a fresh project's CI. Mention that--strictexists.
None of this is committed by the wizard — same as every other file setup writes (rule 7): staged in the working tree, committed when the user says so.
GitHub Actions — .github/workflows/ktw-lint.yml:
name: ktw-lint
on:
push:
branches: [main]
pull_request:
jobs:
ktw-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oliver-zehentleitner/keep-the-why@latest
with:
path: "."
strict: "false" # "true" turns warnings (e.g. missing Type on old entries) into failures
# version: "0.10.1.0" # optional: pin the linter instead of tracking latest
GitLab CI — job for .gitlab-ci.yml:
ktw-lint:
image: python:3.12
script:
- pip install keep-the-why-lint
- ktw-lint .
pre-commit — hook for .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: ktw-lint
name: keep-the-why-lint
entry: ktw-lint .
language: python
additional_dependencies: ["keep-the-why-lint"]
pass_filenames: false
Any other CI, or locally:
pip install keep-the-why-lint
ktw-lint . # exit 0 clean, 1 findings, 2 usage error
ktw-lint . --strict # warnings fail too
Adding it to an existing project later
Nothing about this is tied to first-time setup: a project that declined, or was set up before the linter existed, adds the same files by hand or by asking the agent to — the detection table above applies just the same. There's no config field recording whether linting is set up; the workflow file's presence is the state.