用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/lukemcqueen/hermes-cortex --skill doctor-warning-resolution命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
Cross-server agent health monitoring using binary status vectors — deploy health endpoints on each agent, poll from orchestrator, alert on state transitions.
Wire a self-hosted Langfuse instance to Hermes Agent — generate API keys, configure env vars, enable the bundled plugin, install SDK, and verify traces flow.
Use before enforcement code changes or shared-repo commits.
| name | doctor-warning-resolution |
| version | 1.0.0 |
| category | devops |
| description | Use when fixing cortex-doctor naming/cron drift warnings. |
| author | Hermes Cortex |
| license | MIT |
| platforms | ["linux","macOS"] |
Use when the cortex-doctor emits a WARN or FAIL and you need to trace it to the check function, understand what it validates, and fix all references.
Trace a doctor warning end-to-end:
Read the warning message — note the exact check label (e.g. "Script naming", "Script prefix", "Cron expected missing", "Cron extra"). The label matches the function that produced it.
Find the check function — open ops/scripts/manage/cortex_doctor/checks.py
and search for the label string. Each check is a def check_* function that
calls res.add(label, severity, message, hint).
Read the check logic — understand what the function validates. Key checks:
check_script_naming() — validates cron name-to-script alignmentparse_expected_crons() — reads expected cron list from install script uninstall arraysparse_orch_crons() — same for orchestrator install scriptFind the cron definition — search ~/.hermes/cron/jobs.json for the cron name.
Read name, script, schedule, deliver, and no_agent fields.
Check the install scripts — search install-crons.sh and install-orch-crons.sh
for the cron name. If not found, it was created ad-hoc (local-only cron).
Search ALL cross-references — grep the entire repo for the old name: docs, plists, skills, agent registries, manifest files, deployment scripts. A rename can touch 15-20 files.
Apply fix — rename/move files, update all references, update runtime cron.
Deploy and verify — cortex-update.sh then doctor with --quiet.
The function at checks.py:2361 runs two independent checks on every cron
job that has both a name and a script field:
if not script_norm.startswith(name_norm) and not name_norm.startswith(script_norm):
res.add("Script naming: <name>", "WARN", ...)
The script stem (filename minus extension) must either:
agent-foo.py → cron agent-foo)agent-foo.py → cron agent-foo-weekday)This allows shared scripts: agent-foo-weekday and agent-foo-weekend both
use agent-foo.py ✅
if name.startswith("agent-") and not script_stem.startswith("agent-"):
res.add("Script prefix: <name>", "WARN", "script lacks 'agent-' prefix")
elif name.startswith("orch-") and not script_stem.startswith("orch-"): ...
elif name.startswith("local-") and not script_stem.startswith("local-"): ...
The cron prefix must match the script prefix. Only agent-, orch-, and
local- are checked — all others pass silently.
Rename the script so its stem (no extension) matches or starts with the cron name AND carries the same prefix:
| Cron name | Old script | New script |
|---|---|---|
local-health-push | health-vector-push.sh | local-health-push.sh |
agent-foo-workday | foo.py | agent-foo-workday.py |
local-* crons are excluded from expected-cron checks but NOT from
script naming checks. A local-* cron with a mismatched script still fires._ and - are normalized to - for comparison
(agent-session_cache matches agent-session-cache). The actual filename
stays the same.Path(manage/agent-foo.sh).stem = agent-foo.
The directory prefix doesn't participate in the check.The doctor reads expected cron names from the uninstall arrays in
install-crons.sh and install-orch-crons.sh. It does NOT read the
create_cron blocks. This architecture creates a two-way sync requirement:
After any rename cycle, run fix-cron-duplicates.py to verify sync:
python3 ~/hermes-cortex/ops/scripts/manage/fix-cron-duplicates.py
Zero issues = arrays are in sync.
When a renamed script is referenced across the repo (always assume this):
git mv the script to its new path# Formerly known as: old-name)cortex-update.sh register callsetup-reference.md, DOCS-INDEX.md, integration-audit.md,
service-layer-decision.mdagent-registry.template.json, agent-registry.json.examplehermes cron edit <job-id> --script <new-name>cortex-update.shpython3 ~/hermes-cortex/ops/scripts/manage/cortex-doctor.py --quiet| Warning label | Most likely cause | Fix |
|---|---|---|
| "Script naming: X" | Script filename doesn't share a base with cron name | Rename script to match cron name |
| "Script prefix: X" | Script filename lacks the cron's prefix (agent-, orch-, local-) | Rename script to add the prefix |
| "Cron expected missing: X" | Doctor expects X but it's not in the job list | Cron was removed or renamed without updating uninstall array |
| "Cron extra: X" | A live cron that isn't in any expected list | Rename to local-<name> (opt out) or add to uninstall array |
| "Cron status: X — last run: error" | X was interrupted mid-run by a cortex update purging its governance lock | Re-run via cronjob action='run' job_id=<id> (scheduler refresh, NOT manual script) |
| "MCP server (agent-bus): not configured" on a non-orch host | Register_orch service expected unconditionally in EXPECTED_MCP_SERVERS | Role-gate the check on AGENT_ROLE == "orchestrator" |
| "Stale deploy: scripts/agent-bus-mcp.py" on a non-orch host | Orch-only file deployed where it shouldn't be | Remove the file — it's a CORRECT warning, don't suppress it |
When the doctor reports ❌ PENDING cycles, some may belong to other
sessions still running on the host (concurrent agents mid-task). Scoring
someone else's active cycle corrupts their governance — their end_change will
find the cycle already consumed. Before scoring a foreign PENDING cycle:
cycle_query(unreviewed=true) — note each cycle's session_idls ~/.hermes-cortex/state/.hermes-session-*.id and
ps -p <pid> for each (skip the current symlink)A stale lock file (.governance-<session>.json with expired heartbeat) whose
owner pid is gone is safe to leave or purge; a PENDING cycle from a live pid is
never yours to touch.
LLM crons killed with last_activity=waiting for non-streaming API response
are not hung — cron turns are hardcoded non-streaming (deadlock fix #62151),
so a slow-but-alive DeepSeek response produces zero activity deltas and the
watchdog (default 600s) kills it before the API-side 1800s bound. Fix: raise
HERMES_CRON_TIMEOUT in ~/.hermes/.env (e.g. 1800) — NOT reduce the timeout.
Full detail (code paths, dead-config trap, streaming as the real fix):
references/cron-timeout-and-soul-trim-2026-08-03.md.
These warnings appear right after a "pull latest / update cortex" session and are often misread as broken crons or configs.
cortex-update.sh purges ALL governance locks — including a running cron session's lock. An in-flight LLM cron loses its lock mid-run and is marked interrupted:
gateway.run: Shutdown (post-interrupt): marked 1 in-flight cron job(s) interrupted: <job_id>
The doctor then reports ⚠️ Cron status (<name>) — last run: error even though the cron itself is fine.
Fix: re-run the cron through the scheduler to refresh last_status:
cronjob action='run' job_id=<id>
A manual python3 script.py does NOT update the scheduler's status — only a scheduler run does.
When a service is deployed via register_orch (orchestrator-only), the doctor's EXPECTED_MCP_SERVERS (in cortex_doctor/config.py) must also be role-aware — otherwise non-orch hosts get FAIL: MCP server (agent-bus) not configured while the file was never supposed to deploy there. Pattern used for the agent-bus MCP server:
is_orch = AGENT_ROLE == "orchestrator"
if name == "agent-bus" and not is_orch:
# WARN if present (leftover), PASS if absent
The stale-deploy check (check_stale_deploys) already skips register_orch entries on non-orch hosts — so an orch-only file present on a non-orch host is a correct warning: remove the file, don't suppress the warning.
loop-gov-mcp.py derives repo_slug from the gateway's cwd via git rev-parse. If the gateway runs from inside ~/.hermes/hermes-agent (a git repo), every MCP-created lock says repo_slug: hermes-agent. The pre-commit hook in ~/hermes-cortex derives repo_slug: hermes-cortex and refuses to match:
❌ No active governance session.
...even though check_lock says the lock is active. The enforcer plugin accepts the lock (matches by session_id), but the pre-commit hook matches strictly by repo_slug.
Fix (workaround): the DB cycle is the source of truth; the lock file is disposable. Write a corrected lock mirroring the active session with the right slug:
import json, os, glob
src = glob.glob(os.path.expanduser('~/.hermes-cortex/state/.governance-<session>.json'))
state = json.load(open(src[0]))
state['repo_slug'] = 'hermes-cortex' # or the repo you're committing to
json.dump(state, open(os.path.expanduser('~/.hermes-cortex/state/.governance-hermes-cortex.json'), 'w'), indent=2)
Report to Moses: systemic flaw — the hook's hint ("cd into the repo before begin_change") is impossible from the MCP side since the MCP server derives the slug from the gateway process cwd, not the agent's terminal cwd.
Renaming a shared doc (e.g. agent-bus-setup.md → orch-bus-setup.md) touches every consumer: DOCS-INDEX.md, onboarding, runbooks, docs/stale-paths-audit.md, skill references, and even systemd Documentation= lines. Sweep --include="*.md" --include="*.sh" --include="*.py" --include="*.yaml" --include="*.service" and verify zero remaining matches before committing. Also: git mv fails with destination exists when the refactored target already exists (a prior partial rename) — check git ls-files | grep <name> first; if the target exists, the real work is git rm the stale duplicate + update all references to the surviving canonical file.
inactivity-timeout incident (non-streaming cron turns vs 600s watchdog vs
1800s API bound), HERMES_CRON_TIMEOUT fix, dead-config trap, SOUL.md
15K trim recipe (keep markers + scripture anchor), stale-retired-cron removal, and the live-session PENDING-cycle rule.