# NousResearch/hermes-agent · Bump skill usage when cron jobs load skills

## Open now

- Nothing open on GitHub.

All three members have near-identical titles about incrementing skill usage when cron jobs load skills; two are scoped to 'cron' and one to 'curator'. The titles suggest duplicate or closely related changes, but no further detail is available from the titles alone.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #19433. Verify it addresses your case.
- **Recommended:** read PR #19433 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-19433`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #18810: fix(curator): bump skill usage when cron jobs load skills

## Prior & competing PRs

- **#19433: fix(cron): bump skill usage when cron jobs load skills**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `cron/scheduler.py`, `tests/cron/test_scheduler.py`
  - fix hunks:
  - `cron/scheduler.py`

    ```diff
    @@ -782,6 +782,7 @@ def _build_job_prompt(job: dict, prerun_script: Optional[tuple] = None) -> str:
             return prompt
     
         from tools.skills_tool import skill_view
    +    from tools.skill_usage import bump_use
     
         parts = []
         skipped: list[str] = []
    ```

    ```diff
    @@ -793,6 +794,12 @@ def _build_job_prompt(job: dict, prerun_script: Optional[tuple] = None) -> str:
                 skipped.append(skill_name)
                 continue
     
    +        # Bump usage so the curator sees this skill as actively used.
    +        try:
    +            bump_use(skill_name)
    +        except Exception:
    +            logger.debug("Cron job: failed to bump skill usage for '%s'", skill_name, exc_info=True)
    +
             content = str(loaded.get("content") or "").strip()
             if parts:
                 parts.append("")
    ```
  - `tests/cron/test_scheduler.py`

    ```diff
    @@ -1857,6 +1857,54 @@ def _mixed_skill_view(name: str) -> str:
             assert "go" in result
     
     
    +class TestBuildJobPromptBumpUse:
    +    """Verify that cron jobs bump skill usage counters so the curator sees them as active."""
    +
    +    def test_bump_use_called_for_loaded_skill(self):
    +        """bump_use is called for each successfully loaded skill."""
    +
    +        def _skill_view(name: str) -> str:
    +            return json.dumps({"success": True, "content": f"Content for {name}."})
    +
    +        with patch("tools.skills_tool.skill_view", side_effect=_skill_view), \
    +             patch("tools.skill_usage.bump_use") as mock_bump:
    +            _build_job_prompt({"skills": ["alpha", "beta"], "prompt": "go"})
    +
    +        assert mock_bump.call_count == 2
    +        calls = [c[0][0] for c in mock_bump.call_args_list]
    +        assert "alpha" in calls
    +        assert "beta" in calls
    +
    +    def test_bump_use_not_called_for_missing_skill(self):
    +        """bump_use is NOT called when a skill fails to load."""
    +
    +        def _missing_view(name: str) -> str:
    +            return json.dumps({"success": False, "error": "not found"})
    +
    +        with patch("tools.skills_tool.skill_view", side_effect=_missing_view), \
    +             patch("tools.skill_usage.bump_use") as mock_bump:
    +            _build_job_prompt({"skills": ["ghost"], "prompt": "go"})
    +
    +        assert mock_bump.call_count == 0
    +
    +    def test_bump_failure_does_not_break_prompt(self, caplog):
    +        """If bump_use raises, the prompt still builds — error is logged at DEBUG."""
    +
    +        def _skill_view(name: str) -> str:
    +            return json.dumps({"success": True, "content": "Works."})
    +
    +        with patch("tools.skills_tool.skill_view", side_effect=_skill_view), \
    +             patch("tools.skill_usage.bump_use", side_effect=RuntimeError("boom")), \
    +             caplog.at_level(logging.DEBUG, logger="cron.scheduler"):
    +            result = _build_job_prompt({"skills": ["good-skill"], "prompt": "go"})
    +
    +        # Prompt should still contain the skill content and original instruction
    +        assert "Works." in result
    +        assert "go" in result
    +        # The error should be logged at DEBUG level, not crash
    +        assert any("failed to bump" in r.message for r in caplog.records)
    +
    +
     class TestSendMediaViaAdapter:
         """Unit tests for _send_media_via_adapter — routes files to typed adapter methods."""
     
    ```
- **#18811: fix(cron): bump skill usage when cron jobs load skills**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#19433`

## Fix status

- Merged to main in PR #19433 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-05-04`.
