Backend Atomic Commit
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.
Overview
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.
This skill ships inside the Backend Atomic Commit plugin and can be installed through the Claude Code marketplace or directly in Codex from its skill path.
Parent Surface
Parent docs: Backend Atomic Commit
Related wrapper commands from the parent plugin:
/backend-atomic-commit:commit/backend-atomic-commit:pre-commit/backend-atomic-commit:atomic-commit When to Use This Skill
Use this Skill in backend/Django repos (especially the Diversio monolith backend) when you want:
(formatting, imports, type hints, logging, etc.) so that it matches:
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.
- /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).
Modes
This Skill behaves differently based on how it is invoked:
to repo standards and pre-commit requirements.
The command markdown sets the mode. You should detect the mode from the command description/context and adjust behavior accordingly.
- 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.
Core Priorities
Emulate Monty’s backend engineering and review taste, tuned for pre-commit:
constraints come first.
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.
try/except blocks, hidden PII, or untyped payloads.
unrelated work.
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.
.pre-commit-config.yaml hooks as documented, not ad-hoc commands.
and structured logging over untyped dicts and log soup.
wrote them; this Skill should be invisible from git log.
Always prioritize [BLOCKING] issues over style and nits.
- 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.
Checks in Both Modes
In both pre-commit and atomic-commit modes, follow this pipeline:
requirements*.txt).
before any direct per-tool commands.
gate directly in the same pass.
CHECKS_ALLOW_FETCH_SKIP=1 when a local skip is explicitly acceptable.
staged, and unstaged tracked Python changes.
when the type hook is not already covered/passing via pre-commit:
before merge/commit, run that gate before final "ready" verdict.
type-check errors in that file—not just the ones you introduced. If CI checks modified files, pre-existing errors in touched files will still cause failures. Do not dismiss errors as "pre-existing" if the file is in your diff.
may satisfy ruff but break ty if the method signature must match a parent class (e.g., Django admin methods). Always run both checks together.
for atomic-commit mode or [SHOULD_FIX] for pre-commit mode.
pytest subsets based on changed apps:
“tests not run” as at least [SHOULD_FIX] and often [BLOCKING] for atomic-commit.
custom scripts).
appropriate.
referenced but not present), do not crash:
matters.
files).
escalate to wider runs only if required by repo policy.
intended files (atomic commits should not accidentally grow).
3 times with the same approach. If the same error (or substantively identical error) reappears after 3 real fix attempts, that check is stuck.
across the session. After 10, stop and report.
You are stuck on a check when any of these are true:
fix is not working or is being reverted by another tool).
ruff flags → you fix → djlint re-reformats the same spot).
When stuck:
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.).
- 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.
- 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 mode:
- run on modified tracked + untracked files:
- If pre-commit already executed a gate successfully, do not rerun the same gate directly in the same pass.
- 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/..HEAD, staged, and unstaged tracked Python changes.
- Detect the type gate in this order (unless repo docs/CI explicitly differ):
- ty if configured ([tool.ty], ty.toml, .bin/ty, or CI/pre-commit).
- Else pyright if configured.
- Else mypy if configured.
- Run the active checker on modified Python files only during iteration when the type hook is not already covered/passing via pre-commit:
- Scoped checks are for speed only; if the repo/CI requires a wider check before merge/commit, run that gate before final "ready" verdict.
- IMPORTANT: For any file you touch, you must resolve ALL active type-check errors in that file—not just the ones you introduced. If CI checks modified files, pre-existing errors in touched files will still cause failures. Do not dismiss errors as "pre-existing" if the file is in your diff.
- Common pitfall: Fixing ruff ARG002 (unused argument) by prefixing with _ may satisfy ruff but break ty if the method signature must match a parent class (e.g., Django admin methods). Always run both checks together.
- Treat any active type-check errors in modified files as [BLOCKING] for atomic-commit mode or [SHOULD_FIX] for pre-commit mode.
- 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.
- 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.
- 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: 1. Re-run the smallest scoped failing check on the relevant files. 2. Fix only the reported file(s). 3. Re-run the same check until it passes. 4. 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).
- 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.
- 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.
- The exact error.
- What you tried (briefly).
- Why it is not resolving (tool conflict, unfamiliar pattern, etc.). 3. Continue fixing other unrelated issues if any remain. 4. In final output, clearly separate "Fixed" from "Stuck / Needs Human".
pre-commit run --files $(git diff --cached --name-only --diff-filter=ACMR) 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 Resources
Declared allowed tools:
BashReadEditGlobGrep References
backend-taste-and-fix-rules.mdusage-examples.mdworkflow-boundary.md
Installation
Switch between Claude Code and Codex, then copy the install command for the runtime you use.
claude plugin marketplace add DiversioTeam/agent-skills-marketplace
claude plugin install backend-atomic-commit@diversiotech CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
python3 "$CODEX_HOME/skills/.system/skill-installer/scripts/install-skill-from-github.py" \
--repo DiversioTeam/agent-skills-marketplace \
--path plugins/backend-atomic-commit/skills/backend-atomic-commit Invocation:
/backend-atomic-commit:commit
/backend-atomic-commit:pre-commit
/backend-atomic-commit:atomic-commit name: backend-atomic-commit