Pedantic backend pre-commit and atomic commit Skill for Django/Optimo-style repos. Enforces local AGENTS.md / CLAUDE.md, pre-commit hooks, .security/* helpers, and Monty’s backend engineering taste – with no AI signatures in commit messages.
This skill is limited to using the following tools:
Use this Skill in backend/Django repos (especially the Diversio monolith backend) when you want:
/backend-atomic-commit:pre-commit – to actively fix the current code
(formatting, imports, type hints, logging, etc.) so that it matches:
AGENTS.md / CLAUDE.md rules..pre-commit-config.yaml expectations..security/ diff helpers (ruff and local imports)./backend-atomic-commit:atomic-commit – to run the same checks plus:
/backend-atomic-commit:pre-commit on this repo and actively fix all
files in git status so they obey backend AGENTS.md, .pre-commit-config.yaml,
.security/* helpers, and Monty’s taste (no local imports, strong typing,
structured logging). Then summarize what you changed and what’s still
[BLOCKING].”/backend-atomic-commit:atomic-commit to prepare an atomic commit for
the staged changes in backend/. Enforce all pre-commit hooks and
.security scripts, run Ruff, ty, Django checks, and relevant pytest
subsets, then propose a ticket-prefixed commit message with no AI
signature and clearly mark any [BLOCKING] issues.”/backend-atomic-commit:pre-commit in a strict mode: eliminate local
imports, fix type hints (no Any, no string-based annotations), clean up
debug statements, and ensure Ruff, .security/local_imports_pr_diff.sh,
ty, and Django checks are happy."optimo_* changes, run
/backend-atomic-commit:atomic-commit --auto to:
TypedDict payloads,.security/* scripts,
and then tell me whether the commit is ready and what the commit message
should be.”If you’re not in a backend repo (no manage.py, no backend-style AGENTS.md,
no .pre-commit-config.yaml), this Skill should say so explicitly and fall
back to a lighter “generic Python pre-commit” behavior.
This Skill behaves differently based on how it is invoked:
pre-commit mode – invoked via /backend-atomic-commit:pre-commit:
atomic-commit mode – invoked via /backend-atomic-commit:atomic-commit:
pre-commit mode.The command markdown sets the mode. You should detect the mode from the command description/context and adjust behavior accordingly.
Emulate Monty’s backend engineering and review taste, tuned for pre-commit:
AGENTS.md and CLAUDE.md as the source
of truth when present; this Skill is a default baseline..security/* helpers, and
.pre-commit-config.yaml hooks as documented, not ad-hoc commands.TypedDict/dataclasses,
and structured logging over untyped dicts and log soup.git log.Always prioritize [BLOCKING] issues over style and nits.
When this Skill runs, you should first gather context using Bash, Read,
Glob, and Grep:
git status --porcelaingit branch --show-currentgit diff --cached --statgit diff --cached --name-onlygit log --oneline -10AGENTS.md and CLAUDE.md (if present) for repo-specific rules..pre-commit-config.yaml..security/ scripts, especially:
./.security/ruff_pr_diff.sh./.security/local_imports_pr_diff.shmanage.py / Django project layout.uv and .bin/ wrappers:
.bin/ruff, .bin/ty, .bin/django, .bin/pytest.uv run or plain python / pytest / ruff where necessary.If the repo clearly isn’t the Diversio backend / Django4Lyfe style, say so and adjust expectations (but you can still run generic Python pre-commit checks).
In both pre-commit and atomic-commit modes, follow this pipeline:
Scope changed files
git status and git diff --cached:
optimo_*, dashboardapp, survey, etc.)..pre-commit-config.yaml, pyproject.toml,
requirements*.txt).Static formatting/linting
./.security/ruff_pr_diff.sh if present..bin/ruff / ruff check on changed Python files.ruff format / .bin/ruff format on those files.djlint-reformat-django and djlint-django on changed templates
when configured in .pre-commit-config.yaml..pre-commit-config.yaml; run
pre-commit run on relevant files when possible.Backend-specific .security gates
.security scripts where present:
./.security/ruff_pr_diff.sh – Ruff on changed files vs base branch../.security/local_imports_pr_diff.sh – check for local imports.[SHOULD_FIX] and usually [BLOCKING] for
atomic-commit.Type/system checks
.bin/ty or ./ty_checks.py for type checking (respecting any
documented baseline, but treating new issues seriously)..bin/django check or equivalent:
uv run python manage.py check --fail-level WARNING.pytest subsets based on changed apps:
dashboardapp/ changes → pytest dashboardapp/tests/.[SHOULD_FIX] and often [BLOCKING] for
atomic-commit.Interaction with pre-commit hooks
.pre-commit-config.yaml exists:
git status and restage modified files as
appropriate.check_prepare_commit_msg_hook.py
referenced but not present), do not crash:
[SHOULD_FIX] issue stating which hook is missing and why it
matters.When running in pre-commit mode, you are allowed and expected to actively
edit code to align with Monty’s backend taste where it is clearly safe. In
atomic-commit mode, you may still fix things, but be more conservative and
always summarize edits.
from myapp.models import MyModel inside functions or methods just
to dodge cyclic imports..security/local_imports_pr_diff.sh as the first line of defense.from __future__ import annotations) when needed.[SHOULD_FIX].logger.info("optimo_event", extra={"company_uuid": str(company.uuid)}).logger.info("Company %s did %s", company.name, something).optimo_* apps, treat unstructured logging as at least [SHOULD_FIX].assignment.employee.email; this is enforced by
pre-commit hooks already, but you should also conceptually check.logger.exception for expected error paths; use error or warning
with explicit messages.try/except blocks:
try body to only the lines that can raise.except: or except Exception: with specific exceptions
whenever possible.[BLOCKING] for
behaviorally important code.getattr/hasattr as a crutch:
hasattr() when truly needed (e.g. cross-version adapters) and
document why.Any as much as possible; prefer precise types and generics."OptimoRiskQuestionBank"; use real types
and proper imports.optimo_*, dashboardapp, and other core apps.Dict[str, Any] or ad-hoc dict payloads with TypedDict or
dataclasses when the shape is stable and local.AGENTS.md (e.g. responses
in survey tests, company/survey fixtures that respect multi-tenant
relationships).TestCase classes in optimo_* apps; use
pytest + fixtures.[BLOCKING] when they affect
correctness.company.surveys.all() to Survey.objects.filter(company=company)
when it avoids extra imports and is idiomatic.[SHOULD_FIX] for hot paths or performance-sensitive code.print(...), pdb.set_trace(), ipdb.set_trace(), breakpoint() in
non-test code.[SHOULD_FIX] and suggest either deleting them or moving
rationale into docs.TODO / FIXME without ticket IDs:
TODO(GH-123): ... or
TODO(27pfu0): ...) or moving the note into ClickUp.% formatting or .format() with f-strings when not blocked
by translation/i18n constraints.[BLOCKING] and suggest using environment variables and 1Password..env, google_creds.json, google_drive_creds.json, etc..gitignore updates where appropriate.[BLOCKING] and recommend a two-step rollout:
[SHOULD_FIX] or [BLOCKING] depending on risk.AGENTS.md:
Query() module-level constants that break parameter
resolution (e.g. Q_INCLUDE_INACTIVE = Query(False, ...)).OptimoEmployeeSurvey or employee_survey.[BLOCKING].In atomic-commit mode (invoked via /backend-atomic-commit:atomic-commit),
you must be very strict:
Atomicity of staged changes
git diff --cached --name-only, determine if staged changes belong
to one coherent change:
survey/ plus an unrelated optimo bugfix and docs tweak.[BLOCKING] if the staged set is clearly multiple logical changes.[SHOULD_FIX] for minor opportunistic cleanups that could be split.All gates must be green
./.security/ruff_pr_diff.sh./.security/local_imports_pr_diff.sh.bin/ruff / ruff format.bin/ty / ./ty_checks.py.bin/django check / manage.py checkpytest subsets for risky changes.pre-commit-config.yaml--auto style usage, you may skip conversational confirmation, but
you must not relax these gates.[SHOULD_FIX] and usually [BLOCKING].Commit message generation (no AI signature)
clickup_<ticket_id>_...AGENTS.md: <ticket_id>: Description.commit_msg_hook.py exist:
[SHOULD_FIX] and follow
the documented AGENTS.md convention for suggestions.Your atomic-commit output should include:
Checks run – listing each gate and its status.What’s aligned – strengths and good patterns in the staged changes.Needs changes – bullets with [BLOCKING], [SHOULD_FIX], [NIT].Proposed commit – suggested commit message and list of files.[BLOCKING] items.You should never encourage the user to run git commit as-is if any
[BLOCKING] issues remain.
In pre-commit mode (invoked via /backend-atomic-commit:pre-commit):
.security/*, ty, Django
checks, tests as appropriate).Fixes applied – concrete edits you made.Remaining issues – with severity tags.Checks run – which gates passed/failed.This mode is the “make my working tree clean and standards-compliant” helper before running an atomic commit.
Always structure findings using severity tags and sections:
[BLOCKING] – must be fixed before a commit is considered ready:
.security scripts or pre-commit hooks.AGENTS.md (e.g., Ninja Query constants, legacy
survey models).atomic-commit mode.[SHOULD_FIX] – important, strongly recommended changes:
[NIT] – minor cleanups:
Output shape for both modes:
What’s alignedNeeds changesChecks runProposed commit (only in atomic-commit mode)Be direct, specific, and actionable in each bullet, pointing to file/area and suggesting concrete corrections. Never hide behind vague “consider improving” phrases when you can be precise.