# NousResearch/hermes-agent · Terminal safety filter false positives on quoted keywords

## Open now

- Nothing open on GitHub.

Multiple bug reports and fix attempts addressing false positives in the terminal safety filter when background-wrapper keywords like nohup, disown, and setsid appear inside quoted strings. The fixes focus on stripping or ignoring quoted content before applying the regex scan.

## TL;DR

- 8 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 6 PR(s) closed without merging.
- A fix was merged to main in PR #25784. Verify it addresses your case.
- **Recommended:** read PR #25784 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `unresolved`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.25`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #20064: bug(terminal): safety filter false-positives on background wrapper keywords inside quoted strings

## Prior & competing PRs

- **#20099: fix: reduce false positives in terminal safety filter for nohup/disown/setsid**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `364ddd45e8dbfbcdf365794e7ca8e3a3e49de100`, `#20064`, `#20066`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#20101: fix(terminal): strip quoted strings before safety-filter regex scan (#20064)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#20146: fix(terminal): stop false-positive on quoted nohup/disown/setsid (#20064)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `364ddd45e8dbfbcdf365794e7ca8e3a3e49de100`, `#20064`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#25784: fix(terminal): prevent safety filter false positives on quoted background-wrap (#25616)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `tools/terminal_tool.py`
  - fix hunks:
  - `tools/terminal_tool.py`

    ```diff
    @@ -1544,9 +1544,29 @@ def _command_requires_pipe_stdin(command: str) -> bool:
         )
     
     
    -_SHELL_LEVEL_BACKGROUND_RE = re.compile(r"\b(?:nohup|disown|setsid)\b", re.IGNORECASE)
    +_SHELL_LEVEL_BACKGROUND_RE = re.compile(
    +    r"(?:^|[;&|]\s*|&&\s*|\|\|\s*|\$\(\s*)(?:nohup|disown|setsid)\b", re.IGNORECASE | re.MULTILINE
    +)
     _INLINE_BACKGROUND_AMP_RE = re.compile(r"\s&\s")
     _TRAILING_BACKGROUND_AMP_RE = re.compile(r"\s&\s*(?:#.*)?$")
    +
    +
    +def _strip_quotes(command: str) -> str:
    +    """Remove single- and double-quoted content so regex checks don't match inside strings.
    +
    +    This prevents false positives when keywords like 'nohup' or 'setsid' appear
    +    in commit messages, Python -c code, echo arguments, or PR body text.
    +    Also strips backtick-quoted content and heredoc-style inline text.
    +    """
    +    # Remove single-quoted strings (no escaping inside single quotes in shell)
    +    result = re.sub(r"'[^']*'", "''", command)
    +    # Remove double-quoted strings (handle escaped quotes)
    +    result = re.sub(r'"(?:[^"\\]|\\.)*"', '""', result)
    +    # Remove backtick-quoted strings
    +    result = re.sub(r"`[^`]*`", "``", result)
    +    return result
    +
    +
     _LONG_LIVED_FOREGROUND_PATTERNS = (
         re.compile(r"\b(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|start|serve|watch)\b", re.IGNORECASE),
         re.compile(r"\bdocker\s+compose\s+up\b", re.IGNORECASE),
    ```

    ```diff
    @@ -1579,21 +1599,25 @@ def _foreground_background_guidance(command: str) -> str | None:
         if _looks_like_help_or_version_command(command):
             return None
     
    -    if _SHELL_LEVEL_BACKGROUND_RE.search(command):
    +    # Strip quoted content so keywords inside strings/arguments don't trigger
    +    # false positives (e.g., git commit -m "... setsid ...", python3 -c "os.setsid").
    +    unquoted = _strip_quotes(command)
    +
    +    if _SHELL_LEVEL_BACKGROUND_RE.search(unquoted):
             return (
                 "Foreground command uses shell-level background wrappers (nohup/disown/setsid). "
                 "Use terminal(background=true) so Hermes can track the process, then run "
                 "readiness checks and tests in separate commands."
             )
     
    -    if _INLINE_BACKGROUND_AMP_RE.search(command) or _TRAILING_BACKGROUND_AMP_RE.search(command):
    +    if _INLINE_BACKGROUND_AMP_RE.search(unquoted) or _TRAILING_BACKGROUND_AMP_RE.search(unquoted):
             return (
                 "Foreground command uses '&' backgrounding. Use terminal(background=true) for long-lived "
                 "processes, then run health checks and tests in follow-up terminal calls."
             )
     
         for pattern in _LONG_LIVED_FOREGROUND_PATTERNS:
    -        if pattern.search(command):
    +        if pattern.search(unquoted):
                 return (
                     "This foreground command appears to start a long-lived server/watch process. "
                     "Run it with background=true, verify readiness (health endpoint/log signal), "
    ```
- **#20066: fix(terminal): prevent safety filter false positives on keywords inside quoted strings**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#20064`
- **#20079: fix(terminal): prevent safety filter false positives on keywords inside quoted strings**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#20066`, `#20064`, `#20066`
- **#25616: fix(terminal): prevent safety filter false positives on quoted background-wrapper keywords (salvage #20066)**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#25784`

## Fix status

- Merged to main in PR #25784 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-05-14`.
- Subsystem: `environments`
