claude-code-plugin-ref…
Explain plugin, skill, command, agent, and hook mechanics used here. Use when authoring or debugging plugins. Do not use for ops; use night-market-operations.
Triage night-market failures by symptom (hooks, CI, tests). Use when a check fails unexpectedly. Do not use for routine gates; use night-market-operations.
$ npx -y skills add athola/claude-night-market --skill night-market-debugging-playbook --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/night-market-debugging-playbookContext preview
The summary Claude sees to decide when to auto-load this skill.
Triage night-market failures by symptom (hooks, CI, tests). Use when a check fails unexpectedly. Do not use for routine gates; use night-market-operations.
name: night-market-debugging-playbook description: Triage night-market failures by symptom (hooks, CI, tests). Use when a check fails unexpectedly. Do not use for routine gates; use night-market-operations.
Match the symptom to a row, run the one discriminating command, apply the known fix. Every row below is a failure this repo has already paid for, with the commit hash that settled it. Do not re-derive a diagnosis that archaeology already produced.
Terms used throughout, defined once:
PostToolUse, Stop, SessionStart). Registered in a plugin's `hooks/hooks.json` with a `command` and a `timeout`.
kills the hook when it expires, before any output is honored.
system Python (floor: 3.9), NOT the repo's uv-managed 3.12 venv. Third-party packages a plugin declares are not guaranteed present.
Every Makefile target that uses it has a Python fallback.
including the plugin's `__init__.py`.
| # | Symptom | Likely cause | Story | |---|---------|--------------|-------| | 1 | PreToolUse hook error / ModuleNotFoundError on every `git commit` | Unguarded third-party import in a plugin `__init__.py` reachable from a hook | 45dd77ef, 9bfc0a7a | | 2 | `python39-compat` is the only failing CI check | A 3.10+/3.11+ construct (`datetime.UTC`, bare `X \| Y` union) entered a hook import chain | 18c9340d, PR #511 | | 3 | Hook exits 0 but never does anything | Hook reads `CLAUDE_TOOL_*` env vars instead of stdin JSON | CHANGELOG 1.9.14 | | 4 | `capabilities-sync` CI fails | plugin.json registrations drifted from the book reference | capabilities-sync.yml | | 5 | Root `pytest` raises ImportPathMismatchError | Plugin tests collected from repo root instead of per plugin | conftest.py, pyproject norecursedirs | | 6 | `slop-check` fails on a PR | Slop score over 3.0 in a `docs/` or `book/src/` markdown file | slop-check.yml | | 7 | Stop hook produces no verdict at all | Inner subprocess timeout >= registered hook budget | 268cff89 | | 8 | CI broken on a GitHub action or tool pin | Stale or nonexistent pinned version | f81d89a5, 25bf5a9d | | 9 | Scanner reports nothing on input you know is bad | Swallowed exception (except-and-continue) drops files silently | 666171c3, b6de71cf | | 10 | `skrills: not found` | Missing optional binary (a Python fallback exists) | Makefile validate-skills |
First command (substitute the hook path from the error message):
echo '{}' | python3 plugins/gauntlet/hooks/precommit_gate.py; echo "exit=$?"What the result means: a traceback names the module whose import chain pulls in a package the host interpreter lacks. Exit 0 with no output means the hook is import-safe and the problem is elsewhere (check the hook registration in `hooks/hooks.json`).
Fix: guard the import at module level or defer it into the function that needs it. The gauntlet incident: `precommit_gate.py` imported `gauntlet.knowledge_store`, whose `__init__.py` eagerly imported modules doing bare `import yaml` and `import anthropic`. Guarded in 45dd77ef (#518), deferred in 9bfc0a7a. Add a regression test that blocks the package via a `sys.meta_path` blocker and re-imports the hook (pattern in `plugins/gauntlet/tests/unit/test_challenges.py`).
The repo is Python 3.12, but hook scripts and their transitive imports must stay importable under Python 3.9 (`.github/workflows/ python39-compat.yml`). First command:
uv run ruff check --select UP007 --target-version py39 plugins/<plugin>/hooks/ rg -n 'datetime\.UTC|from datetime import UTC' plugins/<plugin>/
What the result means: UP007 hits are bare `X | Y` union annotations that raise TypeError at import time on 3.9. The `rg` hits are the `datetime.UTC` alias (3.11+), which UP007 does not catch. Either one in a hook import chain breaks every hook at once: on PR #511 a single `datetime.UTC` in `leyline.quota_tracker` produced three cascade failures (18c9340d).
Fix: use `from datetime import timezone` with `timezone.utc`, and `typing.Union`/`Optional` or a `from __future__ import annotations` line for unions. To mirror CI's Gate 2 locally (verified 2026-07-02):
uv venv --python 3.9 /tmp/hook39 VIRTUAL_ENV=/tmp/hook39 uv pip install pytest pyyaml cd plugins/abstract /tmp/hook39/bin/python -m pytest tests/hooks --override-ini="addopts="
The `addopts` override strips per-plugin coverage flags that need packages the bare venv lacks. See also the linter trap below: ruff will fight this fix.
First command:
rg -l 'CLAUDE_TOOL_' plugins/*/hooks/ rg -ln 'read_hook_payload' plugins/*/hooks/
What the result means: Claude Code never sets `CLAUDE_TOOL_*` environment variables. The payload arrives as JSON on stdin. A hook reading only env vars is a silent no-op: it exits 0, CI is green, and nothing downstream ever happens. This starved the `[Learning]` discussion digests for two months (last digest 2026-04-25) before anyone noticed (CHANGELOG 1.9.14).
Fix: read stdin first via the canonical reader `plugins/abstract/hooks/shared/hook_io.py` (`read_hook_payload`, stdin-first with env-var fallback for the test harness). Then verify the hook actually fires: pipe a realistic payload in and check for the side effect rather than the exit code alone.
First command:
bash scripts/capabilities-sync-check.sh
What the result means: the script diffs every plugin's `.claude-plugin/plugin.json` registrations agai
A plugin marketplace for Claude Code. Install only the plugins you need to run git workflows, code review, spec-driven development, and autonomous agents from inside your Claude Code session.
Explain plugin, skill, command, agent, and hook mechanics used here. Use when authoring or debugging plugins. Do not use for ops; use night-market-operations.
States load-bearing decisions, invariants, and weak points. Use when judging a design change. Do not use for gating; use night-market-change-control.
Rebuild the dev environment: uv, Python tiers, pins, traps. Use when onboarding or toolchain breaks. Do not use for daily commands; use night-market-operations.
Classify, gate, and review changes. Use when landing a PR, releasing, or amending rules. Do not use for failure triage; use night-market-debugging-playbook.
Search and record project memory (Discussions, journal, ADRs). Use before re-investigating anything. Do not use for settled battles; see failure-archaeology.
Bind loop 'done' to unfakeable gates. Use to harden egregore/herald loops or promote completion_integrity. Not for QA gates; use night-market-validation-and-qa.