hermes - 💡(How to fix) Fix Feature request: `transform_subprocess_env(env, command)` plugin hook [1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#28758Fetched 2026-05-20 04:02:12
View on GitHub
Comments
1
Participants
1
Timeline
6
Reactions
0
Author
Participants
Timeline (top)
labeled ×4closed ×1commented ×1

Fix Action

Fix / Workaround

Multiple plugins compose — each receives the env from the previous plugin's return value (or the original env if no prior plugin modified it). Hook failures are logged but don't crash the subprocess spawn (the original env is used). Same defensive shape as the existing pre_tool_call and pre_gateway_dispatch hooks.

Current workaround

Source patch on tools/environments/local.py::_make_run_env that injects the three TORII_* env vars into the dict it constructs. Reads a per-user runtime file (set by an earlier pre_gateway_dispatch hook) for the values. Anchor: the env-dict-mutation line just before _make_run_env returns. The patch re-applies on every Hermes upgrade.

Code Example

def my_hook(
    env: dict[str, str],
    command: list[str],
    *,
    session_id: str = "",
    task_id: str = "",
    **kwargs,
) -> Optional[dict[str, str]]:
    # Return None → pass the env unchanged
    # Return a dict   → use that env instead (callee may add/remove/modify keys)
    ...
RAW_BUFFERClick to expand / collapse

Feature request: transform_subprocess_env(env, command) plugin hook

Problem

tools/environments/local.py::_make_run_env constructs the env dict for subprocess invocations from the terminal tool. It already does internal env hygiene (PATH expansion, scrubbing per-platform safety filters, etc.) but there's no extension point for plugins to inject additional env vars before the subprocess spawns. Today a plugin that needs to expose state to the subprocess can write to os.environ (visible to everyone) or to a file (the subprocess has to read it), but it can't cleanly say "for THIS invocation only, add FOO=bar to the subprocess env."

Use case

Provenance metadata that should reach a CLI tool spawned via terminal but should NOT pollute the parent process's env. In our case: a wrapped Torii CLI tool spawned by the agent reads $TORII_ACTING_AS, $TORII_ORIGIN, and $TORII_MODE from its bash env to emit a "Acting as: …" provenance line in its output. These vars are per-invocation (different identity per Slack user), so writing them to os.environ is wrong and racy. We need them on the subprocess env only.

Generalizes to: per-request tracing IDs, per-invocation feature flags, secrets that should be visible to a specific CLI tool but not to all subprocesses, anything tied to the conversation/session context that doesn't fit on the command line.

Proposal

A transform_subprocess_env plugin hook called from _make_run_env:

def my_hook(
    env: dict[str, str],
    command: list[str],
    *,
    session_id: str = "",
    task_id: str = "",
    **kwargs,
) -> Optional[dict[str, str]]:
    # Return None → pass the env unchanged
    # Return a dict   → use that env instead (callee may add/remove/modify keys)
    ...

Multiple plugins compose — each receives the env from the previous plugin's return value (or the original env if no prior plugin modified it). Hook failures are logged but don't crash the subprocess spawn (the original env is used). Same defensive shape as the existing pre_tool_call and pre_gateway_dispatch hooks.

Why a plugin hook (not os.environ)

os.environ is process-wide, so concurrent requests with different identities would race. The terminal tool's _make_run_env is the only natural per-request env construction point — every other approach (file-based, ContextVar, etc.) either pollutes shared state or doesn't survive the subprocess boundary.

Current workaround

Source patch on tools/environments/local.py::_make_run_env that injects the three TORII_* env vars into the dict it constructs. Reads a per-user runtime file (set by an earlier pre_gateway_dispatch hook) for the values. Anchor: the env-dict-mutation line just before _make_run_env returns. The patch re-applies on every Hermes upgrade.

Offer

If the API surface above is acceptable, happy to open a PR. The implementation is essentially one invoke_hook("transform_subprocess_env", env=env, command=command, ...) call inside _make_run_env, plus aggregator semantics in hermes_cli/plugins.py (analogous to pre_tool_call's "first valid block wins"). Tests would cover the multi-plugin chain + the defensive fall-through when a hook returns garbage.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix Feature request: `transform_subprocess_env(env, command)` plugin hook [1 comments, 1 participants]