fe66596df3
write_file/patch targeting AGENTS.md, CLAUDE.md, SOUL.md, .cursorrules, or a project-local .hermes config dir now ALWAYS prompt the human for approval — even under --yolo/auto-approve — and fail closed when no human channel exists. These files steer future agent behavior, so an injected write to them is a prompt-injection persistence vector. Design: - New _check_protected_instruction_write() in tools/file_tools.py, a sibling of _check_sensitive_path that returns approval-required rather than a hard error. It realpaths before matching (symlink lesson from #41351), matches basenames case-insensitively in ANY directory, rejects './x/../AGENTS.md' traversal via normpath, and gates files whose immediate parent dir is `.hermes` (project-local config) while exempting the authoritative ~/.hermes home (governed by its own guards). - Approval is ONE-OPERATION only: no session/permanent persistence, no yolo bypass — intentionally does not route through _run_approval_gate. Gateway sessions get the button round-trip with allow_permanent and allow_session both False; CLI uses the per-thread approval callback; no channel at all = BLOCKED (fail closed). - Multi-file V4A patches: ONE protected file gates the ENTIRE patch (a single prompt lists all protected targets; deny applies nothing). - Config: security.protected_instruction_files (default true) and security.protected_instruction_extra_patterns (fnmatch on basename). Config read failure keeps the gate ON. Tests: 22 new cases in tests/tools/test_file_write_safety.py covering the adversarial checklist — deny/approve/yolo-bypass attempt, symlink at a protected target, case variants, relative traversal, arbitrary-directory basenames, project-local .hermes, checkout-nested-under-~/.hermes non-gating, patch replace + V4A multi-file atomicity, gateway round-trip, fail-closed with no human, config off/extra patterns. Ported from: RooCodeInc/Roo-Code RooProtectedController (Apache-2.0); companion: #58631 (terminal vector), symlink lesson from #41351.