pre-commit as the unified lint/test gate¶
Goal: (1) each repo runs pre-commit hooks (lints at commit stage, tests at pre-push stage); (2) the wrapper installs the hooks after cloning so the agent's commits/pushes are gated; (3) CI runs pre-commit run instead of hardcoded lints. Pilot tatara-cli + the shared wrapper change end-to-end, then expand to the other repos.
Decisions (user, 2026-06-14): tests at pre-push stage (lints at commit stage); the agent's own commits run hooks (gated), the wrapper's safety-net CommitAndPush uses --no-verify (never loses work; CI is the backstop). Builds on the mise rollout. Reference: infra .mise.toml pins pre-commit = '4.6.0' + [hooks] postinstall = ["pre-commit install || true"].
Per-repo changes¶
.mise.toml (every repo)¶
Add to [tools]: pre-commit = "4.6.0". Add (or extend) hooks:
[hooks] for helm plugins - append, don't replace.) .pre-commit-config.yaml¶
- cli + memory: HAVE lint hooks (eof, trailing-ws, check-yaml, gitleaks, yamllint, go-fmt, golangci-lint, config-verify). ADD a pre-push test hook.
- operator, chat, ingester, wrapper: CREATE the file - copy cli's lint hooks (adjust: ingester needs cgo for the golangci-lint/test; chat/operator have charts -> keep yaml/helm lint as-is) + the test hook.
Test hook (local, pre-push stage, full suite, no filename filter):
- repo: local
hooks:
- id: go-test
name: go test (mise)
entry: mise run test
language: system
pass_filenames: false
stages: [pre-push]
types: [go]
CI .github/workflows/ci.yml¶
- lint job: replace the hardcoded
gofmtstep +mise run lintwithpre-commit run --all-files(runs all commit-stage hooks: gofmt, golangci-lint, yamllint, gitleaks, eof). Keep thejdx/mise-action@v2step (installs go, golangci-lint, pre-commit). Nomakeneeded for the lint job (pre-commit calls hooks directly). - test job: keep
mise run test(build-essential stays for make/cgo). Optionallypre-commit run --hook-stage pre-push --all-filesinstead - either is fine; keepmise run testfor simplicity. - Leave secscan/image/chart jobs unchanged (gitleaks is also in pre-commit now - dedup is a later cleanup, note in ROADMAP).
Wrapper change (shared, one-time) - tatara-claude-code-wrapper/internal/bootstrap¶
- Install hooks after clone+checkout. In
Render, aftercheckoutTaskBranchfor each repo dir, runmise install(its.mise.tomlpostinstall runspre-commit install), then explicitlypre-commit install --hook-type pre-commit --hook-type pre-push(literal + idempotent; tolerate error if no.pre-commit-config.yaml). Best-effort: a failure must NOT abort the clone (some repos may lack a config). Pass the git/cmd runner appropriately (Render uses GitRunner for git; pre-commit/mise are non-git commands - use the CmdRunner seam or extend). Check howRegisterTataraMCPruns non-git commands (app.go execRunner) and mirror that, OR runmise/pre-commitvia the GitRunner's underlying exec (add a small runner). KISS: add acmdrunner param or reuse the existing pattern. - Safety-net commit bypasses hooks. In
CommitAndPush(repo.go), add--no-verifyto thegit commitso the wrapper's enforced commit never fails on a hook (the agent's own commits remain gated; CI is the backstop). The push is unaffected (pre-push hook would run on the wrapper's push - also bypass withgit push --no-verifyto keep the safety-net push reliable).
TDD the bootstrap change with the existing fake runners.
Pilot (tatara-cli + wrapper) - test ALL levels before expanding¶
- cli
.mise.toml+.pre-commit-config.yaml(test hook) + CI (lint -> pre-commit). - wrapper bootstrap (install hooks + --no-verify) + wrapper's own
.mise.toml/.pre-commit-config.yaml. - LOCAL verification (cli):
mise install-> installs pre-commit + runs postinstall;.git/hooks/pre-commitand.git/hooks/pre-pushexist.pre-commit run --all-files-> all lint hooks pass.pre-commit run --all-files --hook-stage pre-push-> the go-test hook runsmise run testand passes.- A deliberately mis-formatted file ->
git commitis BLOCKED by the commit hook (proves gating); fix -> commits. - LOCAL verification (wrapper bootstrap): unit tests assert
pre-commit install ...is invoked after checkout andgit commit --no-verifyis used in CommitAndPush. - CI: cli PR runs the pre-commit lint job green; wrapper PR builds.
Only after the pilot is green end-to-end, expand to operator/memory/chat/ingester.
Expand (after pilot)¶
operator, memory, chat, ingester: same .mise.toml pre-commit + .pre-commit-config.yaml (create where missing, add test hook) + CI lint -> pre-commit. Each tested locally (mise install, pre-commit run --all-files, pre-push test).
Out of scope (ROADMAP)¶
Dedup the separate gitleaks secscan job now that pre-commit runs gitleaks; a reusable shared CI workflow.