用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/lukemcqueen/hermes-cortex --skill enforcer-modification-considerations命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | enforcer-modification-considerations |
| version | 1.0.0 |
| category | devops |
| description | Use before modifying any enforcer/governance code. |
| author | Moses |
| platforms | ["linux","macos"] |
Load this skill BEFORE modifying plugins/governance-enforcer/__init__.py, mcp-servers/loop-gov-mcp.py, or any governance enforcement code.
Hermes creates sessions with different ID prefixes depending on the session type. Every guard in the enforcer must cover ALL non-interactive prefixes.
| Prefix | Source | Marker behaviour (per-session, 2026-08-01+) |
|---|---|---|
20260730_... (date-based) | Interactive Telegram/DM / CLI | Owns its own marker file — never touches other sessions' |
cron_... | Scheduled cron job | Owns its own marker (bootstrap-created) |
bg_... | Background subagent (delegate_task, etc.) | Owns its own marker |
cli-source date-based | CLI-invoked session (cron/terminal hermes runs) | Owns its own marker |
Per-session markers (2026-08-01): the shared .skills-loaded file race is
structurally eliminated — each session writes its own proof at
state/skills-loaded/<session_id>, so no session can ever stomp another's.
The entire guard class bolted onto the shared file (daemon guard, subagent
guard, sticky-marker-per-governance-lock) is obsolete and was removed.
This was gap-doc P1-A candidate #3 ("per-session marker files"), the
documented structural fix.
Rule: When adding a session-type guard, use session_id.startswith("cron_") or session_id.startswith("bg_"). Do NOT create separate is_cron and is_bg booleans — future prefixes will be missed.
Guard locations in the enforcer:
_auto_create_skills_marker() — writes state/skills-loaded/<session_id> (atomic temp+rename)_check_skills_loaded_marker() — reads THIS session's own marker; exact content match_on_session_start() — cron bootstrap creates the cron session's OWN markerChecklist when modifying:
grep -n 'cron_\|bg_' plugins/governance-enforcer/__init__.pybg_ sessions?not session_id.startswith("2026") as fallback).The begin_change() MCP tool has a DOGFOOD check: if the deployed enforcer (~/.hermes/plugins/governance-enforcer/__init__.py) differs from the repo source (plugins/governance-enforcer/__init__.py), begin_change() rejects the request.
The problem: This blocks a new change when the mismatch is caused by ANOTHER agent's commit arriving via git pull — not by un-deployed local work.
How to break the loop (fixed 2026-08-04 — the sanctioned command is now lock-free):
bash ~/hermes-cortex/ops/scripts/cortex-update.sh
(No sudo, no chaining, no other flags beyond
--dry-run/--status/--delta/--clean-stale — the
enforcer's _is_sanctioned_cortex_update_command() matches exactly.)skill_view() callsbegin_change() should now succeed (repo == deployed)If the skills gate blocks the terminal call (no skills marker yet):
core.hooksPath ~/.hermes-cortex/hooks is global: the pre-commit/pre-push
hooks run in EVERY git repo on the host, including project repos (client-alpha,
client-works, and other client repos) that have no ops/ tree and no .hermes-cortex/
directory inside them. Any hook/enforcer path built on $REPO_ROOT (the repo
being committed IN) and assuming cortex layout will break every commit there.
Regression 2026-08-04 (faa0e929 → fix 72d6cdc3): the adversarial gate
hard-resolved to $REPO_ROOT/ops/scripts/quality/adversarial-verify.py —
project repos lack that path, so ALL their commits failed fail-closed.
Fix pattern: candidate loop, repo-local first, then the canonically-deployed
copy at $HOME/.hermes-cortex/scripts/ (registered by cortex-update.sh on
both Linux and macOS). Fail closed only if BOTH are missing. See
enforcement-change-safety Rule 6 for the full pattern and the 3-branch
verification (cortex repo / project repo / tool-missing).
When modifying hooks or the enforcer, test in a scratch project repo
(git init /tmp/t && git config core.hooksPath ~/.hermes-cortex/hooks)
before shipping — a cortex-repo-only test proves nothing about project repos.
cortex-update.sh copies the new enforcer to
~/.hermes/plugins/governance-enforcer/ and re-locks it — but the RUNNING
gateway keeps executing the OLD module from memory. The plugin manager is a
process-global singleton: hermes plugins disable/enable only writes
config.yaml; it does NOT hot-reload loaded modules.
bash ~/hermes-cortex/ops/scripts/cortex-update.sh --status still returns
GOVERNANCE LOCK REQUIRED → pending restart, not a code bug.hermes gateway restart — agents cannot run it (lifecycle guard);
the host operator (Luke) must. Verify with the positive control (--status
passes lock-free) and negative control (... && echo hi still blocked).The old design: .skills-loaded at ~/.hermes-cortex/state/ was a single
file. ALL concurrent Hermes sessions wrote to it. When session B loaded skills,
it overwrote session A's marker. Session A's writes were then blocked because
_check_skills_loaded_marker() saw session B's ID.
The fix: per-session marker files at ~/.hermes-cortex/state/skills-loaded/<session_id>,
plus per-session state at state/skills-state/<session_id>.json. Each session
writes and reads only its OWN files — concurrent sessions (telegram, cli 1,
cli 2 on one server) can never stomp each other. The daemon guard, subagent
guard, and sticky-marker-per-lock rules were removed; they're no longer needed.
If your writes are blocked (marker missing or wrong content):
cat ~/.hermes-cortex/state/skills-loaded/<your-session-id>
# → session:<your-session-id> (valid)
# → empty / missing (skills not loaded this session)
Fix:
skill_view() → your session's marker
is auto-createdLegacy files: the old ~/.hermes-cortex/state/.skills-loaded and
skills-state.json files are inert — the enforcer no longer reads them. They
can be deleted once all sessions have restarted with the new enforcer.
When a single Hermes installation manages multiple repos (e.g., hermes-cortex + other projects), the repo_slug field in governance lock files must be derived dynamically, not hardcoded.
The problem:
~/.hermes-cortex/state/.governance-{session_id}.json contains "repo_slug": "hermes-cortex""hermes-cortex"hermes-agent (different name), the slug won't matchFix:
basename "${CORTEX_REPO:-${HOME}/hermes-cortex}"_derive_repo_slug() which runs git rev-parse --show-toplevel and takes the directory basenameFiles to check:
ops/scripts/manage/agent-nginx-threat-pipeline.sh — hardcoded slug (fixed)ops/scripts/agent/agent-ip-submission.sh — hardcoded slug (fixed)plugins/governance-enforcer/__init__.py — dynamic via _derive_repo_slug() ✓ops/scripts/pre-commit-score — dynamic via git rev-parse ✓Search pattern for hardcoded slugs:
grep -rn '"repo_slug"' ops/scripts/ plugins/
The pre-commit hook enforces orchestrator-only paths (from docs/orchestrator-only-paths.txt). If an agent has stale hooks (hasn't run cortex-update.sh after the guard was added), non-orchestrators can modify restricted paths like plugins/, skills/, ops/scripts/.
The fix chain:
check_hook_drift() detects deployed hooks that differ from repo sourcecortex-update.sh to redeploy hooksIf you're adding a new restricted path:
docs/orchestrator-only-paths.txtAGENTS.md which lists the canonical restricted pathscortex-update.shTwo mechanisms deploy the enforcer:
| Mechanism | Trigger | How | Caveat |
|---|---|---|---|
| Pre-commit DOGFOOD | git commit | Copies repo → deployed + unlock/lock | Only runs during commits |
cortex-update.sh | Manual run | deploy_governance_plugin() function | Runs at end of deploy cycle |
The DOGFOOD auto-deploy is faster but only works during commits. If another agent's enforcer change arrives via git pull, the DOGFOOD check in begin_change() blocks you because the deployed copy is stale. Run cortex-update.sh to sync.
When modifying the enforcer, test these scenarios:
TestSkillsMarkerPerSession::test_second_session_does_not_invalidate_first)bg_): owns its own markercortex-update.sh — does begin_change() work?Quick test for per-session markers:
echo "session:test" > ~/.hermes-cortex/state/skills-loaded/test-session
# Check: does _check_skills_loaded_marker("test-session") accept only exact content?
The domain-skill gate (_check_domain_skill_gate) is an EDUCATIONAL mechanism
for interactive sessions: it makes the agent load the craft skill (e.g.
documentation-auditing for .md) before writing. Cron sessions (cron_
prefix) and background subagent sessions (bg_ prefix) execute pre-vetted
prompts whose write targets were declared at install time, and their
enabled_toolsets may exclude the skills toolset entirely (e.g.
["terminal","file"]) — skill_view() is NOT in the tool registry, so the
gate is structurally unsatisfiable and every write deadlocks.
Regression 2026-08-06: agent-mycortex-dream-nightly (toolsets
[terminal,file]) was blocked writing ~/brain/<agent>/dreams/*.md because
the .md extension demands documentation-auditing, which the cron cannot
load. Same class affects memory-pruning (MEMORY.md), agents-md-prune-apply
(AGENTS.md), soul-refinement (SOUL.md), orch-skill-lifecycle (skills/).
Fix (commit b8bbaf52): _check_domain_skill_gate returns None early when
_session_type(session_id) in ("cron", "bg"). This mirrors the always-skills
cron bootstrap rationale (cron agents may not have skill_view()). Security is
NOT weakened: PII content gate, adversarial commit gate, bypass-debt mandate,
and governance lock still apply to cron/bg writes.
Checklist when modifying the domain gate:
_session_type() returns "interactive"
for date-format and empty session IDs — the gate still fires for them.tests/test_runtime/test_governance_bypass.py::TestDomainSkillGate
— cron/bg pass, interactive blocks, empty/None session still enforced.enabled_toolsets or every write deadlocks again.plugins/governance-enforcer/__init__.py — the enforcer itselfdocs/orchestrator-only-paths.txt — restricted pathsops/scripts/pre-commit-score — pre-commit hook with orchestrator guardops/scripts/manage/cortex_doctor/checks.py — doctor checks (hook drift, enforcer permissions)ops/scripts/cortex-update.sh — deploy script with deploy_governance_plugin()skills/devops/cortex-preflight/SKILL.md — Pitfall 3 covers skills-loaded marker