| name | backend-atomic-commit |
| description | Pedantic backend pre-commit + atomic-commit skill for Django/Optimo repos that enforces local AGENTS.md, repo-local docs, pre-commit hooks, and repo-local commit hygiene without AI signatures. |
| allowed-tools | Bash Read Edit Glob Grep |
Backend Atomic Commit Skill
When to Use This Skill
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:
- Local
AGENTS.md, linked repo-local docs, and quality gates.
.pre-commit-config.yaml expectations.
.security/ diff helpers (ruff and local imports).
- Monty’s backend taste.
/backend-atomic-commit:atomic-commit – to run the same checks plus:
- Enforce that the staged changes are atomic (one coherent change).
- Ensure all quality gates are green (no shortcuts).
- Propose a commit message that follows the repo-local harness without any Claude or AI signatures.
/backend-atomic-commit:commit – to run atomic-commit, then create the commit once all gates are green (no bypassing commit-msg hooks).
Representative prompt shapes live in references/usage-examples.md.
If you’re not in a backend repo (no manage.py, no backend-style AGENTS.md,
no .pre-commit-config.yaml, no backend quality docs), this Skill should say
so explicitly and fall back to a lighter “generic Python pre-commit” behavior.
Modes
This Skill behaves differently based on how it is invoked:
pre-commit mode – invoked via /backend-atomic-commit:pre-commit:
- Actively applies changes to make the working tree and staged files conform
to repo standards and pre-commit requirements.
- Runs all relevant static checks and auto-fixers.
- Does not propose or drive a commit.
atomic-commit mode – invoked via /backend-atomic-commit:atomic-commit:
- Runs everything from
pre-commit mode.
- Enforces atomicity of staged changes.
- Requires all gates to be green.
- Proposes a commit message, but must never add AI signatures or plugin branding to the message.
commit mode – invoked via /backend-atomic-commit:commit:
- Runs everything from
atomic-commit mode.
- Creates the commit once all gates are green.
- Must still never add AI signatures or plugin branding to the message.
The command markdown sets the mode. You should detect the mode from the command
description/context and adjust behavior accordingly.
Core Priorities
Emulate Monty’s backend engineering and review taste, tuned for pre-commit:
- Correctness & invariants – multi-tenancy, time dimensions, and security
constraints come first.
- Never eyeball date/time math (day-of-week, "yesterday", timezone edges).
Always verify using
date +%Y-%m-%d or Python datetime — never compute
dates manually. Date calculation errors have been a recurring friction
point in real sessions.
- Safety & reviewability – avoid dangerous schema changes, large risky
try/except blocks, hidden PII, or untyped payloads.
- Atomic commits – one commit should represent one coherent change; split
unrelated work.
- Local harness first – treat
AGENTS.md as the canonical entrypoint,
follow linked repo-local docs and directory-scoped AGENTS.md files for
per-topic truth, and do not treat CLAUDE.md as a unique rule source.
- Tooling alignment – use uv wrappers,
.security/* helpers, and
.pre-commit-config.yaml hooks as documented, not ad-hoc commands.
- Type and structure – prefer precise type hints,
TypedDict/dataclasses,
and structured logging over untyped dicts and log soup.
- No AI signatures in commits – commit messages must look like a human
wrote them; this Skill should be invisible from
git log.
Always prioritize [BLOCKING] issues over style and nits.
Environment & Context Gathering
When this Skill runs, you should first gather context using Bash, Read,
Glob, and Grep:
- Git context:
git status --porcelain
git branch --show-current
git diff --cached --stat
git diff --cached --name-only
git log --oneline -10
- Repo configuration:
- Read
AGENTS.md first for repo-specific rules and doc routing.
- Load linked repo-local docs relevant to the changed files, especially
quality gates, runbooks, architecture docs, directory-scoped
AGENTS.md
files, and any GitHub-first workflow sections covering branch naming,
issue linkage, or PR readiness.
- If
CLAUDE.md exists, treat it as a pointer to AGENTS.md, not as a
source of unique behavioral rules.
- If the harness is missing or obviously stale, recommend generating or
canonicalizing docs via the
repo-docs plugin so rules stop living in
tribal knowledge.
- Detect
.pre-commit-config.yaml.
- Detect
.security/ scripts, especially:
./.security/gate_cache.sh
./.security/ruff_pr_diff.sh
./.security/local_imports_pr_diff.sh
- Detect
manage.py / Django project layout.
- Tool availability:
uv and .bin/ wrappers:
.bin/ruff, .bin/ty, .bin/pyright, .bin/mypy, .bin/django,
.bin/pytest.
- Detect repo-owned local-ci support only when
local-ci is on PATH and
repo root contains .local-ci.toml.
- Fallback to
uv run or plain python / pytest / ruff where necessary.
- Read local typing policy docs when present (for example:
docs/python-typing-3.14-best-practices.md, TY_MIGRATION_GUIDE.md) and
follow them over this default.
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).
Gate cache behavior (when available)
If ./.security/gate_cache.sh exists, treat it as the canonical wrapper for
heavy deterministic checks. Use it by default for type gates and Django checks.
./.security/gate_cache.sh --gate ty-check --scope index -- .bin/ty check .
./.security/gate_cache.sh --gate django-system-check --scope index -- uv run python manage.py check --fail-level WARNING
Use scope=index for commit-focused gating and scope=working when results are
expected to depend on unstaged edits. Do not bypass cache unless explicitly
requested or debugging:
CHECK_CACHE_BUST=1 ./.security/gate_cache.sh --gate ty-check --scope index -- .bin/ty check .
./.security/gate_cache.sh --clear-this-checkout
For Ruff/local-import diff helpers, call the scripts directly. They already use
cache-aware execution internally and include local staged/unstaged tracked files.
Prefer running them through pre-commit hooks first; call scripts directly only
for targeted diagnosis or when a matching hook is missing/disabled.
Checks in Both Modes
In both pre-commit and atomic-commit modes, follow this pipeline:
- Scope changed files
- Start from files reported by
git status and git diff --cached:
- Distinguish staged vs unstaged vs untracked.
- Categorize by type:
- Python (src vs tests;
optimo_*, dashboardapp, survey, etc.).
- Templates (Django HTML).
- Config (YAML, JSON,
.pre-commit-config.yaml, pyproject.toml,
requirements*.txt).
- Docs/markdown.
-
Run pre-commit first (primary execution path)
- If
.pre-commit-config.yaml exists, run hooks on the intended file set
before any direct per-tool commands.
atomic-commit mode:
- run on staged files only:
pre-commit run --files $(git diff --cached --name-only --diff-filter=ACMR)
pre-commit mode:
- run on modified tracked + untracked files:
CHANGED_FILES="$(
{
git diff --name-only --diff-filter=ACMR
git ls-files --others --exclude-standard
} | sed '/^$/d' | sort -u
)"
pre-commit run --files $CHANGED_FILES
- If pre-commit already executed a gate successfully, do not rerun the same
gate directly in the same pass.
-
Direct command fallback (targeted, non-duplicative)
- Run direct commands only when:
- a corresponding hook failed and you need focused diagnosis/fix loops, or
- the repository does not expose that gate via pre-commit hooks.
- Keep fetch behavior strict by default (fail closed); only allow
CHECKS_ALLOW_FETCH_SKIP=1 when a local skip is explicitly acceptable.
- For Ruff/local-import helpers, direct invocation is:
./.security/ruff_pr_diff.sh
./.security/local_imports_pr_diff.sh
- These helpers intentionally evaluate the union of
origin/<base>..HEAD,
staged, and unstaged tracked Python changes.
-
Type checking with active repository gate (ty-first)
-
Django system checks
- If Django check hook already passed via pre-commit, do not rerun directly.
- Otherwise run through cache wrapper when present:
./.security/gate_cache.sh --gate django-system-check --scope index -- uv run python manage.py check --fail-level WARNING
- If wrapper is missing, run
.bin/django check or equivalent:
uv run python manage.py check --fail-level WARNING.
- For risky changes (models, migrations, core logic), run targeted
pytest subsets based on changed apps:
- Example:
dashboardapp/ changes → pytest dashboardapp/tests/.
- If tests cannot be run (e.g. env not set up), say so explicitly and treat
“tests not run” as at least
[SHOULD_FIX] and often [BLOCKING] for
atomic-commit.
-
Interaction with pre-commit hooks
- If
.pre-commit-config.yaml exists:
- Expect hooks to run and modify files (ruff, djlint, interrogate,
custom scripts).
- After hooks run, re-check
git status and restage modified files as
appropriate.
- If a hook executable is missing (e.g.
check_prepare_commit_msg_hook.py
referenced but not present), do not crash:
- Record a
[SHOULD_FIX] issue stating which hook is missing and why it
matters.
-
Convergence loop (do not stop early)
- Treat the pipeline above as iterative, not one-shot.
- You are not done until:
- The relevant pre-commit hooks pass, and
- Ruff/type-gate/djlint/Django checks you ran are green, and
- The index/working tree is stable (hooks are no longer rewriting
files).
- Use a tight fix → rerun loop:
- Re-run the smallest scoped failing check on the relevant files.
- Fix only the reported file(s).
- Re-run the same check until it passes.
- Only then advance to the next gate.
- Prefer rerunning only failing hooks/checks on the same file scope, then
escalate to wider runs only if required by repo policy.
- If hooks modify files, always re-check
git status and restage only the
intended files (atomic commits should not accidentally grow).
Iteration budgets
- Per-check limit: Do not attempt to fix the same check failure more than
3 times with the same approach. If the same error (or substantively
identical error) reappears after 3 real fix attempts, that check is
stuck.
- Total pipeline limit: Do not run more than 10 full pipeline passes
across the session. After 10, stop and report.
Stuck detection
You are stuck on a check when any of these are true:
- The same error message reappears after you applied a fix for it (your
fix is not working or is being reverted by another tool).
- A fix for one tool breaks another in a cycle (e.g., djlint reformats →
ruff flags → you fix → djlint re-reformats the same spot).
- You have exhausted the 3-attempt per-check budget.
When stuck:
- Stop attempting that specific fix.
- Report it as
[BLOCKING] with:
- The exact error.
- What you tried (briefly).
- Why it is not resolving (tool conflict, unfamiliar pattern, etc.).
- Continue fixing other unrelated issues if any remain.
- In final output, clearly separate "Fixed" from "Stuck / Needs Human".
No TodoWrite for this pipeline
Do not use TodoWrite or TaskCreate to track individual gate results.
This is a fixed, known sequence — not an open-ended task list. Tracking ruff/
djlint/type-check failures as todo items wastes tokens and context window. Report
results directly in the final output using the existing severity-tagged
sections (Checks run, Needs changes, etc.).
-
Repo-owned local-ci validation (when available)
- Only after the normal gates above are green and the tree is stable, run:
local-ci run --no-github
- Do this only when
local-ci is on PATH and repo root has .local-ci.toml.
- This skill must not publish GitHub statuses or trigger deploy helpers.
Backend Fix Rules
When you need concrete auto-fix heuristics, load:
references/backend-taste-and-fix-rules.md
Use that reference when actively editing backend code, templates, logging,
types, tests, migrations, or other recurring lint targets. It contains the
safe-fix guidance that used to live inline here.
If you discover a recurring failure that is hard to infer from the repo
harness, emit a [SHOULD_FIX] follow-up recommending a docs, wrapper, or CI
improvement instead of letting the rule stay tribal.
Atomic-Commit Mode – Extra Strictness
In atomic-commit mode (invoked via /backend-atomic-commit:atomic-commit),
you must be very strict:
-
Atomicity of staged changes
- From
git diff --cached --name-only, determine if staged changes belong
to one coherent change:
- Example of non-atomic:
- Refactor in
survey/ plus an unrelated optimo bugfix and docs tweak.
- Emit:
[BLOCKING] if the staged set is clearly multiple logical changes.
[SHOULD_FIX] for minor opportunistic cleanups that could be split.
- You may suggest a split (e.g. “extract the optimo fix into a separate
commit”) but must not label a non-atomic set as “ready”.
-
All gates must be green
- The commit is not ready if any of these fail:
./.security/ruff_pr_diff.sh
./.security/local_imports_pr_diff.sh
.bin/ruff check / ruff format
- active type gate on staged Python files (
ty/pyright/mypy)
.bin/django check / manage.py check
- Relevant
pytest subsets for risky changes
- Pre-commit hooks defined in
.pre-commit-config.yaml
local-ci run --no-github when the repo supports local-ci
- A passing pre-commit hook execution counts as satisfying the matching gate.
Do not require duplicate direct-command reruns unless diagnosing failures.
- Where available, heavy gates should run via
./.security/gate_cache.sh
instead of ad-hoc direct invocation.
- In
--auto style usage, you may skip conversational confirmation, but
you must not relax these gates.
- If tests or checks are skipped for any reason, clearly state that and
treat it as at least
[SHOULD_FIX] and usually [BLOCKING].
-
Commit message generation (no AI signature)
- Read the local repo harness first:
AGENTS.md
- linked workflow docs
- any commit-msg hooks that actually enforce a pattern
- Follow the documented repo-local convention instead of inventing a global
ticket-prefix rule.
- If the repo only asks for a clear summary, propose a clear summary.
- If the repo uses issue references for traceability, include them only when
the repo docs or active hooks expect them.
- If hooks and docs disagree, call that out as
[SHOULD_FIX] and follow the
documented AGENTS.md convention for suggestions.
- Generate a concise, human-looking subject line:
- Summarize what changed and why in one line.
- Do not mention Claude, AI, this Skill, or plugin names.
- Do not add any footer or signature:
- No “via Claude Code”.
- No “Generated by backend-atomic-commit”.
- Commit messages must look like a human wrote them.
- Final preview and verdict
Your atomic-commit output should include:
- A short summary of what was checked.
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.
Workflow notes – only when the current branch appears inconsistent with repo-local branch or PR conventions.
- An explicit verdict: “✅ Commit ready” only if there are no
[BLOCKING] items; otherwise “❌ Not ready to commit” with concrete next steps.
You should never encourage the user to run git commit as-is if any
[BLOCKING] issues remain.
Workflow boundary: this skill does not own branch creation or PR state by
itself. See references/workflow-boundary.md.
Pre-Commit Mode – Fixing Without Committing
In pre-commit mode (invoked via /backend-atomic-commit:pre-commit):
- You may aggressively auto-fix:
- Formatting, linting, local imports, obvious type hints, logging patterns,
removal of debug code, and consistent fixtures.
- You must:
- Run the same gates described above (Ruff,
.security/*, active type gate, Django
checks, tests as appropriate).
- Re-run or re-stage files modified by tools or hooks.
- You do not propose a commit or check atomicity.
- Your output should focus on:
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.
Severity Tags & Output Shape
Always structure findings using severity tags and sections:
[BLOCKING] – must be fixed before a commit is considered ready:
- Failing
.security scripts or pre-commit hooks.
- New banned patterns from
AGENTS.md (e.g., Ninja Query constants, legacy
survey models).
- Obvious multi-tenant or security regressions.
- Non-atomic staged changes in
atomic-commit mode.
[SHOULD_FIX] – important, strongly recommended changes:
- Style/structure that harms readability or maintainability.
- Missing type hints where types are clear.
- Ambiguous commented code or TODOs without tickets.
- Missing tests for non-trivial new behavior.
[NIT] – minor cleanups:
- Docstring tone/punctuation.
- Minor naming and formatting nits not covered by Ruff.
Output shape for both modes:
- 1–3 sentence summary of what was checked.
- Sections (when appropriate):
What’s aligned
Needs changes
Checks run
Harness follow-ups (only when docs/tooling should be improved)
Proposed 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.
Compatibility Notes
Works in both Claude Code and OpenAI Codex. For installation, see this repo's
README.md.