athola/night-market-config-catalog
Catalog every config axis, its defaults and guards. Use when adding or auditing configuration. Do not use for running gates; use night-market-operations.
npx skills add https://github.com/athola/claude-night-market --skill night-market-config-catalog
Every configuration axis in this repo: where it lives, what the
options and defaults are, whether it is production policy or an
experimental opt-in, and what guards it. Flags drift, so every
axis ends with a one-line re-verification command. Run it before
trusting a value stated here.
Terms used once, defined once:
file, a key, or an environment variable).
drifts (a test, a pre-commit hook, a CI job, or a script).
block. The blocking posture is opt-in.
| Surface | File | Key options and defaults | Status | Guarded by |
|---------|------|--------------------------|--------|------------|
| Quality gate thresholds | .claude/quality_gates.json | enforce_blocking true, max_critical_issues 3, max_warnings_per_dimension 5; per-dimension keys below | Production policy | Documented in docs/quality-gates.md; consumed as policy prose by sanctum PR workflows (see caveat below) |
| Context governance | .claude/context_governance.json | enforce_strict_limits false, require_progressive_disclosure true, require_modular_structure true, require_optimization_level "standard", block_on_critical_violations false, max_violations_per_file 5 | Production, advisory | docs/quality-gates.md |
| Repo Claude settings | .claude/settings.json | Contains only a description key. NO hooks registered at repo level; all active hooks ship from plugins | Production invariant | Convention; see night-market-architecture-contract |
| Behavioral rules | .claude/rules/*.md (8 files) | bounded-discovery, markdown-formatting, plan-before-large-dispatch, prefer-invariants-over-fallbacks, prefer-rg-over-grep, shared-utility-consumer-rule, skill-exit-criteria, slop-scan-for-docs | Production | slop CI, pre-commit, review practice |
| Python toolchain | root pyproject.toml | See "Root pyproject tool tables" below | Production | Pre-commit hooks, typecheck.yml, security.yml |
| Per-plugin coverage | plugins/*/pyproject.toml [tool.nightmarket] | coverage_threshold = 90 in 19 plugins, 85 in gauntlet (20 files total) | Production | Read by scripts/run-plugin-tests.sh |
| Pre-commit pins | .pre-commit-config.yaml | Remote pins: pre-commit-hooks v6.0.0, bandit 1.8.6 (last release supporting the 3.9 system interpreter). Ruff runs from a local repo via the uv-managed binary so hook and make format share one version | Production | scripts/check_pinned_versions.py, python39-compat.yml |
| Plugin manifest trio | plugins/<p>/.claude-plugin/plugin.json, .claude-plugin/metadata.json, openpackage.yml | All three carry version in lockstep with the marketplace (1.9.15 at compile time) | Production | plugins/sanctum/scripts/update_versions.py, plugins/abstract/scripts/validate_plugin.py |
| Marketplace version | .claude-plugin/marketplace.json top-level version | Single ecosystem version, source of truth for the fan-out | Production | update_versions.py <version> bumper |
| MCP servers | .mcp.json | One stdio server: markitdown via uvx markitdown-mcp | Production | Manual |
| LSP config | .cclsp.json | pylsp for py/pyi; typescript-language-server for js/ts and markdown | Production | Manual |
| Feature-review scoring | .feature-review.yaml | version: 1; weight tables for value and cost; thresholds high_priority 2.8, medium_priority 1.8, confidence_warning 0.6 | Production | Consumed by imbue:feature-review |
| Egregore runtime config | .egregore/config.json (runtime file, created in the target repo, not committed here) | Nested dataclasses in plugins/egregore/scripts/config.py: overseer, alerts, pipeline, budget, discussions. pipeline.completion_integrity = False | Experimental opt-in flag inside production config | Unit tests in plugins/egregore/tests/test_config.py (default, roundtrip, and raw-JSON opt-in paths) |
| Herald Stop-hook judge | plugins/herald/hooks/hooks.json + env vars | Stop hook double_shot_latte.py registered with timeout: 10; internal LLM_TIMEOUT_SECONDS = 8 | Hook production, LLM path experimental | Guard test asserts LLM timeout stays under the registered hook budget |
Caveat on the two .claude/*.json policy files: no Python
script in the repo reads them directly. They are policy inputs
referenced by docs/quality-gates.md and by sanctum command
prose (prepare-pr, pr-review configuration). Treat them as
contract documents for review workflows, not as runtime config
a daemon loads. Direct programmatic consumers: none found at
compile time (candidate: wire one before tightening values).
Per-dimension keys and defaults:
| Dimension | Keys | Blocks? |
|-----------|------|---------|
| performance | max_file_size_kb 20, max_tokens_per_file 5000, max_function_lines 60, max_complexity_score 12 | No (block_on_violation false) |
| security | block_hardcoded_secrets true, block_insecure_functions true, require_input_validation true | Yes (block_on_violation true) |
| maintainability | max_technical_debt_ratio 0.3, max_nesting_depth 5 | No |
| compliance | require_plugin_structure true, require_proper_metadata true | No |
Security is the only blocking dimension. Everything else is
advisory, capped globally by max_critical_issues: 3.
Root pyproject.toml (version 1.9.15, requires-python >=3.12)
carries these tables:
[tool.ruff]: line-length 88, target-version py312.[tool.ruff.lint] select: E, W, F, I, B, C4, UP, PLC0415,PLR0913. extend-ignore: E501, B007, B008, B905, E402, and
UP017. UP017 is load-bearing: it keeps timezone.utc instead
of the 3.11+ datetime.UTC alias because hook scripts must
import under the system Python 3.9. Removing it re-breaks
hooks (this has happened three or more times, and an AST test
now holds the line).
[tool.ruff.lint.per-file-ignores]: tests get S-series andassert allowances; /__init__.py gets F401; /hooks/*.py
gets BLE001, PLC0415, E402 (resilience lazy imports);
scripts/*.py gets E402.
[tool.pytest.ini_options]: norecursedirs includesplugins/*, so plugin tests MUST run per-plugin. Markers:
unit, integration, e2e, slow, network, plugin, skill, hook,
command, bdd, benchmark. --strict-markers is on.
[tool.coverage.report]: fail_under = 85 at root.[tool.mypy]: python_version = "3.12" with strict-leaningflags (disallow_untyped_defs, warn_unused_ignores, etc.).
[tool.uv.workspace] members: plugins/abstract,plugins/leyline, plugins/conserve, plugins/core (a minimal set
for linting, not all 26 plugin dirs).
[tool.bandit] skips: B101, B103, B105, B108, B110, B112,B310, B311, B404, B603, B607, B608. Each skip has an inline
rationale comment in the file. Keep that pattern when adding
one.
Each plugin ships three manifests that must stay in sync:
.claude-plugin/plugin.json: name, version, component arrays..claude-plugin/metadata.json: version, dependencies,provides, claude integration block.
openpackage.yml: cross-framework manifest (name, version,description, keywords).
Two distinct semver namespaces appear in metadata.json and are
easy to confuse:
"version": "1.9.15"), bumped inlockstep from marketplace.json by
plugins/sanctum/scripts/update_versions.py <version>.
"dependencies": {"abstract": ">=2.0.0"}. That 2.0.0 is a
capability-contract version, NOT the marketplace version.
Do not "fix" it to 1.9.x during a bump.
| Variable | Consumer | Values and default | Effect | Status |
|----------|----------|--------------------|--------|--------|
| VOW_SHADOW_MODE | imbue hooks via plugins/imbue/hooks/shared/vow_utils.py | Default "1" (shadow). Set 0 to block | Vow hooks (bounded reads, scope ramp, package hallucination, no-AI-attribution, no-emoji-commits) warn instead of blocking | Shadow default is production; blocking posture experimental |
| UV_TOOL_DIR | root Makefile (line 9) | Default ./.uv-tools | Where uv installs tools; ruff resolves from $(UV_TOOL_DIR)/ruff/bin first on PATH | Production |
| SKRILLS_REPO | root Makefile (skrills-build) | Default $HOME/skrills | Source checkout used to cargo-build the skrills binary | Production (skrills itself optional; Python fallbacks exist) |
| CONSERVATION_MODE | plugins/conserve/hooks/session-start.sh | quick, deep, normal; default normal; unknown values warn and fall back to normal | How much conservation guidance loads at session start | Production |
| DOUBLE_SHOT_LATTE_LLM | plugins/herald/hooks/double_shot_latte.py | Set "1" to enable | Enables the LLM "second shot" tiebreaker, only on the single ambiguous Stop-hook outcome | Experimental opt-in, default off |
| DOUBLE_SHOT_LATTE_MODEL | same hook | Default "haiku" | Model used for the second shot | Experimental |
| DOUBLE_SHOT_LATTE_MAX_CONTINUATIONS | same hook | Integer (read from env; see hook source for cap semantics) | Caps forced continuations | Production guard |
| CLAUDE_HOOK_JUDGE_MODE | same hook | "true" disables the LLM path | Prevents the judge from invoking itself recursively | Production guard |
Both current experiments follow the same pattern: default off,
guard tests, blocking behavior only on explicit opt-in.
pipeline.completion_integrity, a bool defaulting toFalse in the PipelineConfig dataclass at
plugins/egregore/scripts/config.py (line 49 at compile
time).
.egregore/config.json, read bythe summon skill alongside .egregore/manifest.json.
True: a quality verdict of "fix-required" becomes astep failure (cannot advance to ship) and merge is held for
human review regardless of auto_merge.
plugins/egregore/tests/test_config.py covers theFalse default, the opt-in roundtrip, and loading from a
hand-written raw JSON file.
plugins/herald/hooks/hooks.json with timeout: 10).
DOUBLE_SHOT_LATTE_LLMmust be "1", judge mode must not be active, and the turn
must land on the single ambiguous outcome (every confident
verdict skips the LLM entirely).
LLM_TIMEOUT_SECONDS = 8 is deliberately under the 10-secondregistered budget. A value above the budget once made the harness
kill the hook before any verdict (full record:
night-market-failure-archaeology SB7). A guard test now asserts
the ordering. Never raise the LLM timeout without checking the
registered budget first.
Checklist for any new flag, threshold, or env var:
value the system already exhibits).
including loading from raw serialized config
(model: plugins/egregore/tests/test_config.py).
on unknown values with a warning
(model: plugins/conserve/hooks/session-start.sh).
registered budget in hooks.json.
status (production or experimental) and guard.
docs/quality-gates.md and route the change through
night-market-change-control.
night-market-operations.
review it: use night-market-change-control.
hooks.json fields mean,how manifests load): use claude-code-plugin-reference.
night-market-build-and-env.
night-market-debugging-playbook.
its output matches the value stated in this catalog.
jq -r '.version' .claude-plugin/marketplace.json equalsthe version in each plugin's plugin.json, metadata.json,
and openpackage.yml (spot-check at least one plugin).
rg -l "coverage_threshold" plugins/*/pyproject.toml | wc -lreturns 20. Any other count means this catalog is stale
and must be updated before use.
rg -n "completion_integrity: bool = False" plugins/egregore/scripts/config.pymatches. If the default changed, the Experimental section
here is wrong and must be rewritten.
the axis or env var table with a guard and a
re-verification one-liner.
Compiled 2026-07-02 against repo v1.9.15 (branch
discussions-fix-1.9.14). Line numbers and counts are volatile;
re-verify before quoting.
Re-verification one-liners per axis:
# Quality gates and context governance
jq . .claude/quality_gates.json
jq . .claude/context_governance.json
# Repo settings must stay hook-free
jq 'keys' .claude/settings.json # expect ["description"]
# Behavioral rules roster
ls -1 .claude/rules/
# Root toolchain tables
rg -n "fail_under|extend-ignore|^select|target-version" pyproject.toml
rg -n "\[tool.bandit\]" -A 20 pyproject.toml
rg -n "\[tool.uv.workspace\]" -A 8 pyproject.toml
# Per-plugin coverage thresholds
rg -n "coverage_threshold" plugins/*/pyproject.toml
# Pre-commit pins
rg -n "rev:" .pre-commit-config.yaml
# Marketplace version and manifest fan-out (imbue as sample)
jq -r '.version' .claude-plugin/marketplace.json
jq -r '.version' plugins/imbue/.claude-plugin/plugin.json
jq -r '.version, .dependencies' plugins/imbue/.claude-plugin/metadata.json
head -3 plugins/imbue/openpackage.yml
# Root dotfiles
jq . .mcp.json
jq '.servers[].command' .cclsp.json
rg -n "high_priority|medium_priority|confidence_warning" .feature-review.yaml
# Env vars
rg -n "VOW_SHADOW_MODE" plugins/imbue/hooks/shared/vow_utils.py
rg -n "UV_TOOL_DIR|SKRILLS_REPO" Makefile
rg -n "CONSERVATION_MODE" plugins/conserve/hooks/session-start.sh
# Experimental flags
rg -n "completion_integrity" plugins/egregore/scripts/config.py
rg -n "DOUBLE_SHOT_LATTE|LLM_TIMEOUT_SECONDS|JUDGE_MODE" plugins/herald/hooks/double_shot_latte.py
jq . plugins/herald/hooks/hooks.json
Known drift risks: pre-commit rev: pins (guarded by
scripts/check_pinned_versions.py), the coverage-threshold file
count (20 at compile time), the egregore config.py line number,
and the promotion status of the two experimental flags (see
night-market-completion-integrity-campaign for the promotion
question).
Take athola/night-market-config-catalog from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference uvx.
Without those the skill loads but fails at the first command.