night-market-config-catalog · git:20260703.19ab4d6 · 2026-07-03 · sha256 24a85bc489ecb8da
night-market-config-catalog git:20260703.19ab4d6A
Immutable. This exact content is served forever at /api/v1/blob/24a85bc489ecb8da.
---
name: night-market-config-catalog
description: Catalog every config axis, its defaults and guards. Use when adding or auditing configuration. Do not use for running gates; use night-market-operations.
---
# 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:
- **Axis**: one independently tunable configuration surface (a
file, a key, or an environment variable).
- **Guard**: the mechanism that notices when the axis breaks or
drifts (a test, a pre-commit hook, a CI job, or a script).
- **Shadow mode**: a hook that evaluates and warns but does not
block. The blocking posture is opt-in.
## Axis table
| 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).
## Quality gate dimensions (.claude/quality_gates.json)
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 tool tables
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 and
assert allowances; `**/__init__.py` gets F401; `**/hooks/*.py`
gets BLE001, PLC0415, E402 (resilience lazy imports);
`scripts/*.py` gets E402.
- `[tool.pytest.ini_options]`: `norecursedirs` includes
`plugins/*`, 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-leaning
flags (`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.
## Manifest trio and the two semver namespaces
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:
1. The ecosystem version (`"version": "1.9.15"`), bumped in
lockstep from `marketplace.json` by
`plugins/sanctum/scripts/update_versions.py <version>`.
2. Capability dependency ranges, for example imbue declares
`"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.
## Environment variables
| 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 |
## Experimental and opt-in flags
Both current experiments follow the same pattern: default off,
guard tests, blocking behavior only on explicit opt-in.
### egregore completion_integrity
- Key: `pipeline.completion_integrity`, a bool defaulting to
`False` in the `PipelineConfig` dataclass at
`plugins/egregore/scripts/config.py` (line 49 at compile
time).
- Stored in the target repo's `.egregore/config.json`, read by
the summon skill alongside `.egregore/manifest.json`.
- When `True`: a quality verdict of "fix-required" becomes a
step failure (cannot advance to ship) and merge is held for
human review regardless of `auto_merge`.
- Guards: `plugins/egregore/tests/test_config.py` covers the
False default, the opt-in roundtrip, and loading from a
hand-written raw JSON file.
### herald LLM second shot
- The Stop hook itself is production (registered in
`plugins/herald/hooks/hooks.json` with `timeout: 10`).
- The LLM tiebreaker is gated three ways: `DOUBLE_SHOT_LATTE_LLM`
must 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-second
registered 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.
## Adding a config axis
Checklist for any new flag, threshold, or env var:
- [ ] Default preserves current behavior (default off, or the
value the system already exhibits).
- [ ] A guard test asserts the default AND the opt-in path,
including loading from raw serialized config
(model: `plugins/egregore/tests/test_config.py`).
- [ ] Env vars validate their input and fall back to the default
on unknown values with a warning
(model: `plugins/conserve/hooks/session-start.sh`).
- [ ] Any timeout inside a hook is asserted against the hook's
registered budget in `hooks.json`.
- [ ] Add a row to the axis or env var table in this file, with
status (production or experimental) and guard.
- [ ] Add a one-line re-verification command under Provenance.
- [ ] If the axis affects gating or review policy, update
`docs/quality-gates.md` and route the change through
night-market-change-control.
## When NOT to use
- Running tests, lint, gates, or releases: use
night-market-operations.
- Deciding whether a config change is allowed at all, or how to
review it: use night-market-change-control.
- Plugin/skill/hook mechanics (what `hooks.json` fields mean,
how manifests load): use claude-code-plugin-reference.
- Recreating the toolchain (uv, Python versions, skrills): use
night-market-build-and-env.
- Diagnosing a broken gate or hook: use
night-market-debugging-playbook.
## Exit Criteria
- [ ] Every re-verification command under Provenance exits 0 and
its output matches the value stated in this catalog.
- [ ] `jq -r '.version' .claude-plugin/marketplace.json` equals
the `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 -l`
returns 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.py`
matches. If the default changed, the Experimental section
here is wrong and must be rewritten.
- [ ] A new config axis added by the current change appears in
the axis or env var table with a guard and a
re-verification one-liner.
## Provenance and maintenance
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:
```bash
# 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).