Skip to content

feat(prompt): load global HERMES.md operational context - #23412

Open
DoGMaTiiC wants to merge 1 commit into
NousResearch:mainfrom
DoGMaTiiC:feat/global-hermes-md-operational-context
Open

DoGMaTiiC wants to merge 1 commit into
NousResearch:mainfrom
DoGMaTiiC:feat/global-hermes-md-operational-context

Conversation

@DoGMaTiiC

Copy link
Copy Markdown
Contributor

Summary

Adds a Hermes-native global operational context file loaded from HERMES_HOME:

  • SOUL.md remains the global identity/personality file.
  • HERMES.md becomes the preferred global operational policy/context file.
  • AGENTS.md and CLAUDE.md are accepted as compatibility aliases.
  • Only the first non-empty global operational file is loaded, in priority order: HERMES.md → AGENTS.md → CLAUDE.md.
  • Project/cwd context still loads separately after the global operational file, so project rules can refine/override instance-wide defaults.
  • No default HERMES.md is seeded automatically; the feature is opt-in.

This addresses the gap where gateway/cron/non-project sessions can load SOUL.md globally, but have no equivalent global operational instruction file similar to Claude Code's global CLAUDE.md or Codex-style global AGENTS.md.

Related issues / PRs

Related:

This PR differs from the existing approaches by preferring a Hermes-native HERMES.md filename and by loading only one global operational file instead of concatenating multiple global aliases.

Behavior

Prompt context order becomes:

  1. SOUL.md as the identity slot, unchanged.
  2. Global operational context from $HERMES_HOME/HERMES.md or alias.
  3. Project context from cwd: .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=' -q

Result:

132 passed

…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 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:1360 in the PR. Current main requires context_length and a concrete read_path for 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.

Comment thread agent/prompt_builder.py
label = f"{name} (global)"
content = _scan_context_content(content, label)
result = f"## {label}\n\n{content}"
return _truncate_content(result, label)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread agent/prompt_builder.py
# 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()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 13, 2026
birkschmithuesen added a commit to birkschmithuesen/hermes-agent that referenced this pull request Sep 16, 2026
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.
birkschmithuesen added a commit to birkschmithuesen/hermes-agent that referenced this pull request Sep 17, 2026
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.
birkschmithuesen added a commit to birkschmithuesen/hermes-agent that referenced this pull request Sep 22, 2026
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.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants