Port from earendil-works/pi#7681: support AGENTS.override.md context override
AGENTS.override.md now takes priority over AGENTS.md in both startup project-context loading (prompt_builder) and progressive subdirectory hint discovery (subdirectory_hints). Lets developers keep a personal, typically-gitignored override next to committed project instructions without editing the tracked file.
This commit is contained in:
parent
0957277f2f
commit
41efb0ab1b
|
|
@ -2059,8 +2059,14 @@ def _load_hermes_md(cwd_path: Path, context_length: Optional[int] = None) -> str
|
|||
|
||||
|
||||
def _load_agents_md(cwd_path: Path, context_length: Optional[int] = None) -> str:
|
||||
"""AGENTS.md — top-level only (no recursive walk)."""
|
||||
for name in ["AGENTS.md", "agents.md"]:
|
||||
"""AGENTS.override.md / AGENTS.md — top-level only (no recursive walk).
|
||||
|
||||
``AGENTS.override.md`` wins over ``AGENTS.md`` so a developer can keep a
|
||||
personal, typically-gitignored override next to the committed project
|
||||
instructions without editing the tracked file (same convention as
|
||||
earendil-works/pi#7681).
|
||||
"""
|
||||
for name in ["AGENTS.override.md", "AGENTS.md", "agents.md"]:
|
||||
candidate = cwd_path / name
|
||||
if candidate.exists():
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ logger = logging.getLogger(__name__)
|
|||
# Same filenames as prompt_builder.py but we load ALL found (not first-wins)
|
||||
# since different subdirectories may use different conventions.
|
||||
_HINT_FILENAMES = [
|
||||
"AGENTS.override.md",
|
||||
"AGENTS.md", "agents.md",
|
||||
"CLAUDE.md", "claude.md",
|
||||
".cursorrules",
|
||||
|
|
|
|||
|
|
@ -449,6 +449,27 @@ class TestBuildContextFilesPrompt:
|
|||
assert "Ruff for linting" in result
|
||||
assert "Project Context" in result
|
||||
|
||||
def test_agents_override_md_wins_over_agents_md(self, tmp_path):
|
||||
(tmp_path / "AGENTS.md").write_text("Use Ruff for linting.")
|
||||
(tmp_path / "AGENTS.override.md").write_text("Use Black instead.")
|
||||
result = build_context_files_prompt(cwd=str(tmp_path))
|
||||
assert "Use Black instead" in result
|
||||
assert "Ruff for linting" not in result
|
||||
assert "AGENTS.override.md" in result
|
||||
|
||||
def test_agents_override_md_loads_alone(self, tmp_path):
|
||||
(tmp_path / "AGENTS.override.md").write_text("Override-only context.")
|
||||
result = build_context_files_prompt(cwd=str(tmp_path))
|
||||
assert "Override-only context" in result
|
||||
assert "Project Context" in result
|
||||
|
||||
def test_hermes_md_still_wins_over_agents_override(self, tmp_path):
|
||||
(tmp_path / ".hermes.md").write_text("Hermes-first context.")
|
||||
(tmp_path / "AGENTS.override.md").write_text("Override context.")
|
||||
result = build_context_files_prompt(cwd=str(tmp_path))
|
||||
assert "Hermes-first context" in result
|
||||
assert "Override context" not in result
|
||||
|
||||
def test_skips_agents_md_in_install_tree_on_fallback(self, monkeypatch, tmp_path):
|
||||
# A backend that FALLS BACK into the install tree (cwd=None → getcwd,
|
||||
# the desktop default) must not load that tree's contributor AGENTS.md
|
||||
|
|
|
|||
|
|
@ -284,3 +284,16 @@ class TestExcludedDirectories:
|
|||
tracker = SubdirectoryHintTracker(working_dir=str(tmp_path))
|
||||
result = tracker.check_tool_call("read_file", {"path": str(normal / "f.py")})
|
||||
assert result is not None and "Backend rules" in result
|
||||
|
||||
def test_agents_override_md_wins_in_subdirectory(self, tmp_path):
|
||||
"""AGENTS.override.md takes priority over AGENTS.md per directory."""
|
||||
sub = tmp_path / "backend"
|
||||
sub.mkdir()
|
||||
(sub / "AGENTS.md").write_text("Committed backend rules")
|
||||
(sub / "AGENTS.override.md").write_text("Personal backend override")
|
||||
|
||||
tracker = SubdirectoryHintTracker(working_dir=str(tmp_path))
|
||||
result = tracker.check_tool_call("read_file", {"path": str(sub / "f.py")})
|
||||
assert result is not None
|
||||
assert "Personal backend override" in result
|
||||
assert "Committed backend rules" not in result
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ Hermes Agent automatically discovers and loads context files that shape how it b
|
|||
| File | Purpose | Discovery |
|
||||
|------|---------|-----------|
|
||||
| **.hermes.md** / **HERMES.md** | Project instructions (highest priority) | Walks to git root |
|
||||
| **AGENTS.override.md** | Personal, per-directory override of AGENTS.md (typically gitignored) | CWD at startup + subdirectories progressively |
|
||||
| **AGENTS.md** | Project instructions, conventions, architecture | CWD at startup + subdirectories progressively |
|
||||
| **CLAUDE.md** | Claude Code context files (also detected) | CWD at startup + subdirectories progressively |
|
||||
| **SOUL.md** | Global personality and tone customization for this Hermes instance | `HERMES_HOME/SOUL.md` only |
|
||||
|
|
@ -20,7 +21,9 @@ Hermes Agent automatically discovers and loads context files that shape how it b
|
|||
| **.cursor/rules/*.mdc** | Cursor IDE rule modules | CWD only |
|
||||
|
||||
:::info Priority system
|
||||
Only **one** project context type is loaded per session (first match wins): `.hermes.md` → `AGENTS.md` → `CLAUDE.md` → `.cursorrules`. **SOUL.md** is always loaded independently as the agent identity (slot #1).
|
||||
Only **one** project context type is loaded per session (first match wins): `.hermes.md` → `AGENTS.override.md` → `AGENTS.md` → `CLAUDE.md` → `.cursorrules`. **SOUL.md** is always loaded independently as the agent identity (slot #1).
|
||||
|
||||
If an `AGENTS.override.md` exists next to an `AGENTS.md`, the override is loaded **instead of** the committed file — keep a personal (usually gitignored) `AGENTS.override.md` when you want different instructions than the ones checked into the repo, without editing the tracked `AGENTS.md`.
|
||||
:::
|
||||
|
||||
## AGENTS.md
|
||||
|
|
|
|||
Loading…
Reference in New Issue