Conversation
…S_HOME Mirrors the SOUL.md global-load pattern for operational policy: HERMES_HOME/HERMES.md (preferred), with AGENTS.md and CLAUDE.md accepted as aliases. Loaded independently of cwd, injected before project context so projects can refine baseline policy. Skips cwd discovery when cwd equals HERMES_HOME to avoid duplicate injection. Goes through the same prompt-injection scan and 20k-char truncation as other context files.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for separating global operational policy from cwd project context; current main still has the global-context gap (agent/prompt_builder.py:1947-1994).
Problems
- The stated cron coverage is incomplete on current main: workdir-less jobs pass
skip_context_files=True(cron/scheduler.py:3069), and the prompt builder is only called when that flag is false (agent/system_prompt.py:446-455). This helper therefore cannot reach those cron jobs. - The new loader uses the former truncation contract at
agent/prompt_builder.py:1360in the PR. Current main requirescontext_lengthand a concreteread_pathfor each context loader (agent/prompt_builder.py:1850-1944,f80381c45).
Suggested changes
- Preserve the current dynamic-cap/read-path behavior in the global loader and cover it with a regression test.
- Decide and test the workdir-less cron contract; if global policy should apply there, load it separately from cwd project context.
Automated hermes-sweeper review.
| label = f"{name} (global)" | ||
| content = _scan_context_content(content, label) | ||
| result = f"## {label}\n\n{content}" | ||
| return _truncate_content(result, label) |
There was a problem hiding this comment.
Current main's context loaders pass context_length and read_path=str(candidate) to _truncate_content (f80381c45; current agent/prompt_builder.py:1850-1944). Thread those through this new loader too, otherwise global files keep the obsolete fixed cap and a truncation marker cannot name the real file.
| # CLAUDE.md, in priority order). Loaded independently of cwd so it | ||
| # follows the user across CLI, gateway, cron, and subagent sessions — | ||
| # symmetric with SOUL.md but for procedure rather than identity. | ||
| global_op = _load_global_operational_md() |
There was a problem hiding this comment.
This remains inside build_context_files_prompt, which current agent/system_prompt.py:446-455 skips whenever skip_context_files=True. In particular, workdir-less cron jobs set that flag at cron/scheduler.py:3069, so the stated cron-wide behavior needs separate wiring or narrower documentation.
Our addition on top of PR NousResearch#23331, which double-injects in this case (flagged by the sweeper review on NousResearch#23331 and handled by the competing NousResearch#23412). It bites the local CLI: that backend deliberately leaves TERMINAL_CWD unset, so resolve_context_cwd() returns None and build_context_files_prompt falls back to os.getcwd(). Running hermes from the profile dir makes cwd == HERMES_HOME and duplicates ~20k chars of AGENTS.md in the prompt. Skips the whole cwd chain rather than just _load_agents_md: the or-chain would otherwise fall through and inject CLAUDE.md (Claude-Code onboarding, not meant for Hermes), which would not have loaded before either. A regression test pins that, and a third test pins that the chain still runs when no home AGENTS.md exists.
Our addition on top of PR NousResearch#23331, which double-injects in this case (flagged by the sweeper review on NousResearch#23331 and handled by the competing NousResearch#23412). It bites the local CLI: that backend deliberately leaves TERMINAL_CWD unset, so resolve_context_cwd() returns None and build_context_files_prompt falls back to os.getcwd(). Running hermes from the profile dir makes cwd == HERMES_HOME and duplicates ~20k chars of AGENTS.md in the prompt. Skips the whole cwd chain rather than just _load_agents_md: the or-chain would otherwise fall through and inject CLAUDE.md (Claude-Code onboarding, not meant for Hermes), which would not have loaded before either. A regression test pins that, and a third test pins that the chain still runs when no home AGENTS.md exists.
Our addition on top of PR NousResearch#23331, which double-injects in this case (flagged by the sweeper review on NousResearch#23331 and handled by the competing NousResearch#23412). It bites the local CLI: that backend deliberately leaves TERMINAL_CWD unset, so resolve_context_cwd() returns None and build_context_files_prompt falls back to os.getcwd(). Running hermes from the profile dir makes cwd == HERMES_HOME and duplicates ~20k chars of AGENTS.md in the prompt. Skips the whole cwd chain rather than just _load_agents_md: the or-chain would otherwise fall through and inject CLAUDE.md (Claude-Code onboarding, not meant for Hermes), which would not have loaded before either. A regression test pins that, and a third test pins that the chain still runs when no home AGENTS.md exists.
Summary
Adds a Hermes-native global operational context file loaded from
HERMES_HOME:SOUL.mdremains the global identity/personality file.HERMES.mdbecomes the preferred global operational policy/context file.AGENTS.mdandCLAUDE.mdare accepted as compatibility aliases.HERMES.md→AGENTS.md→CLAUDE.md.HERMES.mdis seeded automatically; the feature is opt-in.This addresses the gap where gateway/cron/non-project sessions can load
SOUL.mdglobally, but have no equivalent global operational instruction file similar to Claude Code's globalCLAUDE.mdor Codex-style globalAGENTS.md.Related issues / PRs
Related:
This PR differs from the existing approaches by preferring a Hermes-native
HERMES.mdfilename and by loading only one global operational file instead of concatenating multiple global aliases.Behavior
Prompt context order becomes:
SOUL.mdas the identity slot, unchanged.$HERMES_HOME/HERMES.mdor alias..hermes.md/HERMES.md/AGENTS.md/CLAUDE.md/.cursorrules.If
cwd == HERMES_HOME, cwd discovery is skipped to avoid injecting the same file twice.Tests
python -m pytest tests/agent/test_prompt_builder.py -o 'addopts=' -qResult: