.claude-plugin/skills/config-default-model-drift/SKILL.md
# Skill: config-default-model-drift ## Overview | Field | Value | |-------------|------------------------------------------------------------------------| | Date | 2026-02-20 | | Issue | #793 | | PR | #838 | | Obj
npx skillsauth add homericintelligence/projectscylla .claude-plugin/skills/config-default-model-driftInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Field | Value |
|-------------|------------------------------------------------------------------------|
| Date | 2026-02-20 |
| Issue | #793 |
| PR | #838 |
| Objective | Eliminate hardcoded model-ID literals that silently drift from config |
| Outcome | Success — single source of truth in config/defaults.yaml |
| Category | architecture |
Trigger when you see any of the following:
"claude-opus-4-5-20251101") in CLI or orchestrator codemodel or "<literal>" fallback patterns instead of reading from configgrep -rn "claude-opus-4-5" scylla/
Expect: scylla/cli/main.py and scylla/orchestrator.py (possibly docstrings too).
default_model to config/defaults.yaml# Default model used when no --model flag is provided
default_model: "claude-opus-4-5-20251101"
Place it at the top level (not nested under a section).
DefaultsConfigIn scylla/config/models.py, inside DefaultsConfig:
default_model: str = Field(
default="claude-opus-4-5-20251101",
description="Default model ID when none is specified",
)
The Python-level default keeps backward-compat for callers that don't supply the YAML key
(e.g. test fixtures that use a trimmed defaults.yaml).
In scylla/cli/main.py:
# Before (stale literal)
model_id = model or "claude-opus-4-5-20251101"
# After (reads from config)
from scylla.config import ConfigLoader
model_id = model or ConfigLoader().load_defaults().default_model
ConfigLoader() with no arguments resolves relative to Path(".") (the cwd at runtime).
In scylla/orchestrator.py the class docstring had a copy of the literal as an example.
Replace with ConfigLoader().load_defaults().default_model to keep it consistent
and searchable.
Add to tests/unit/cli/test_cli.py:
def test_run_default_model_from_config(self) -> None:
"""Default model_id is read from ConfigLoader, not a hardcoded literal."""
sentinel_model = "test-model-from-config"
mock_defaults = MagicMock()
mock_defaults.default_model = sentinel_model
mock_loader_instance = MagicMock()
mock_loader_instance.load_defaults.return_value = mock_defaults
captured: dict[str, str] = {}
mock_orchestrator_instance = MagicMock()
mock_orchestrator_instance.run_batch.return_value = []
def capture_config(config: object) -> MagicMock:
captured["model"] = getattr(config, "model", None)
return mock_orchestrator_instance
runner = CliRunner()
with (
patch("scylla.cli.main.ConfigLoader", return_value=mock_loader_instance),
patch("scylla.cli.main.EvalOrchestrator", side_effect=capture_config),
):
runner.invoke(cli, ["run", "001-test", "--tier", "T0", "--runs", "1"])
assert captured.get("model") == sentinel_model
Key points:
scylla.cli.main.ConfigLoader (the import in the module under test, not the source).OrchestratorConfig.model via side_effect=capture_config on EvalOrchestrator.config/defaults.yaml on disk — it proves the wiring, not the value.tests/fixtures/config/defaults.yaml does not need to be updated because DefaultsConfig
has a Python-level Pydantic default for default_model. Existing fixture-based tests keep passing.
pixi run python -m pytest tests/ --no-cov # all tests pass
pre-commit run --all-files # all hooks pass
None in this session — the pattern was clean and straightforward.
| Parameter | Value | |-------------------|------------------------------| | Files changed | 5 | | Lines added | 41 | | Lines removed | 2 | | Tests added | 1 | | Total tests | 2267 (all passing) | | Pre-commit hooks | 13 / 13 passing |
| File | Change |
|----------------------------------|---------------------------------------------------------|
| config/defaults.yaml | Added default_model key |
| scylla/config/models.py | Added default_model field to DefaultsConfig |
| scylla/cli/main.py | Replaced literal with ConfigLoader().load_defaults()… |
| scylla/orchestrator.py | Updated docstring example |
| tests/unit/cli/test_cli.py | Added test_run_default_model_from_config |
When ConfigLoader() is instantiated without a base_path, it defaults to Path(".").
This is fine at CLI runtime (cwd is the project root) but would fail in a unit test without
mocking. Always mock scylla.cli.main.ConfigLoader (the reference in the module, not the
original import path) when testing CLI code that calls ConfigLoader() at the module level.
development
# Skill: docs-status-fix ## Overview | Field | Value | |------------|----------------------------------------------------| | Date | 2026-02-19 | | Category | documentation | | Objective | Fix stale "Current Status" in CLAUDE.md | | Issue | #753 | | PR | #810
tools
# Skill: preflight-closing-issues-fix ## Overview | Field | Value | |-------|-------| | Date | 2026-02-21 | | Issue | #802 | | PR | #912 | | Category | tooling | | Objective | Fix `preflight_check.sh` Check 3 false positives caused by free-text PR search matching issue numbers in unrelated PR titles/bodies | | Outcome | Success — 6 bash tests pass, all pre-commit hooks green, PR created with auto-merge | ## When to Use Trigger this skill when: - A preflight/guard script uses `gh pr list --s
tools
# Preflight Check Skill Propagation ## Overview | Field | Value | |-------|-------| | Date | 2026-02-21 | | Issue | #803 | | Objective | Add preflight check to `worktree-create` skill so developers bypassing `gh-implement-issue` still run the 6-check safety gate | | Outcome | Success — PR #917 created, auto-merge enabled | | Files Changed | `tests/claude-code/shared/skills/worktree/worktree-create/SKILL.md` | ## When to Use Use this pattern when: - A safety/quality gate exists in one entry-
tools
# Orphan Config Detection ## Overview | Field | Value | |------------|-----------------------------------------------------------------| | Date | 2026-02-20 | | Issue | #777 | | PR | #824 | | Objective | Warn when a `config/models/*.yaml` file