Skip to content

feat(terminal): interpret signal-termination exit codes (port from kilocode#12698) - #78074

Merged
teknium1 merged 1 commit into
mainfrom
kilocode-port/signal-exit-notes
Aug 17, 2026
Merged

feat(terminal): interpret signal-termination exit codes (port from kilocode#12698)#78074
teknium1 merged 1 commit into
mainfrom
kilocode-port/signal-exit-notes

Conversation

@teknium1

@teknium1 teknium1 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

The terminal tool now tells the model why a command died when it was killed by a signal — exit_code=137 gets an exit_code_meaning note naming SIGKILL and the likely OOM cause instead of leaving the model to burn turns re-running and mis-diagnosing.

Ported from Kilo-Org/kilocode#12698 ("settle signal-terminated shell commands as 128 + signum"). Kilo's bug was a hang because their spawner produced no numeric code on signal death; Hermes already produces numeric codes (Python subprocess -signum, or the shell's 128+signum), so the adaptation targets the remaining gap: the model can't read them.

Changes

  • tools/terminal_tool.py: new _interpret_signal_exit() wired into _interpret_exit_code() ahead of the per-command semantics table.
    • Negative codes (definite signal death from subprocess) → "Command terminated by signal N: …" for a curated table (SIGKILL/SIGSEGV/SIGTERM/SIGABRT/SIGBUS/SIGFPE/SIGPIPE/SIGQUIT/SIGILL/SIGXCPU/SIGXFSZ), generic fallback for uncurated signums.
    • 128+signum band (shell convention, ambiguous — a program can exit 139) → hedged "usually means…" note, curated signals only; uncurated codes stay silent so legitimate application exit codes are never mislabeled.
    • SIGINT excluded on both paths — rc=130 already has bespoke interrupt-marker handling in the executor.
  • tests/tools/test_terminal_signal_exit.py: 26 tests covering both encodings, exclusions, hedging, and precedence over the command-semantics table (a SIGKILLed grep reports the signal, not "no matches").

Validation

Before After
python3 SIGSEGV (real process, E2E) exit_code: 139, no note exit_code_meaning: Exit code 139 usually means … SIGSEGV (segmentation fault…)
bash -c 'kill -9 $$' (E2E) exit_code: 137, no note … SIGKILL — often the kernel OOM killer …
grep no-match / diff / existing semantics unchanged unchanged (56/56 targeted tests pass)

E2E was run through the real terminal_tool() with an isolated temp HERMES_HOME and genuinely signal-killed processes, not mocks.

Architectural notes

  • Kilo's change sits in their process spawner (Effect/Node); Hermes' equivalent gap was presentation, so the port lands in the existing exit-code semantics tier (_interpret_exit_code) — zero new tool surface, no behavior change for non-signal exits.
  • Notes ride the existing exit_code_meaning field the model already knows from grep/diff semantics.

Infographic

Signal-aware terminal exit codes

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 8de5cb3 — feat(terminal): interpret signal-termination exit codes for

⚠️ Warnings

CI timings · View report · View job

Wall time 25m13s vs 8m (+215.2%). 10 job(s) slower, 12 faster, 2 unchanged.

  • Python tests / Run tests slice 1/12: +51.0s
  • Python tests / Run tests slice 7/12: -39.0s
  • Python tests / Run tests slice 4/12: -31.0s
  • Python tests / Run tests slice 6/12: -25.0s
  • Python tests / Run tests slice 2/12: -21.0s

OSV vulnerability scan · View job

5 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.

@alt-glitch alt-glitch added type/feature New feature or request tool/terminal Terminal execution and process management P3 Low — cosmetic, nice to have labels Aug 4, 2026
Port from Kilo-Org/kilocode#12698: report signal-terminated commands with
a human-readable note instead of a bare numeric exit code.

Kilo's fix settles a signal-killed process as the conventional 128+signum
exit code so its bash tool stops hanging. Hermes already produces numeric
codes for signal deaths (subprocess -signum, or the shell's 128+signum),
but the model saw a bare exit_code=-9 or 137 and burned turns
mis-diagnosing (137 = OOM kill being the most common). This adapts the
idea to Hermes' existing exit-code semantics tier:

- _interpret_signal_exit(): maps negative codes (definite signal death)
  and the 128+signum band (hedged with 'usually') to a note naming the
  signal and its likely cause, wired into _interpret_exit_code() ahead of
  the per-command semantics table.
- Curated signal table (SIGKILL/SIGSEGV/SIGTERM/SIGABRT/...) so ambiguous
  application exit codes are never mislabeled; uncurated 128+N codes stay
  silent, SIGINT is excluded (executor's interrupt-marker path owns
  rc=130).
- Notes surface via the existing exit_code_meaning result field.

E2E verified against real SIGSEGV/SIGKILL processes.
@teknium1
teknium1 force-pushed the kilocode-port/signal-exit-notes branch from e355512 to 8de5cb3 Compare August 17, 2026 02:57
@teknium1
teknium1 merged commit 204302b into main Aug 17, 2026
45 checks passed
@teknium1
teknium1 deleted the kilocode-port/signal-exit-notes branch August 17, 2026 05:06
teknium1 added a commit that referenced this pull request Aug 17, 2026
…scout-slate wave

Post-merge docs sweep for the Aug 16 scout slate. Two pages:

- mcp.md: tool-result sanitization section — invisible Unicode TAG chars
  (U+E0000-E007F) stripped from results/resources/descriptions (#80689);
  vendor _meta surfaced to the model minus protocol-reserved
  modelcontextprotocol/mcp prefixes (#80712)
- tools.md: tool result annotations section — signal-death exit notes
  (subprocess -signum definite, shell 128+signum hedged) (#78074); UTF-16
  read_file transcoding with disclosure hint and 10MB cap (#80717)

Security-policy docs (approvals/allowlist) intentionally untouched.
teknium1 added a commit that referenced this pull request Aug 17, 2026
…scout-slate wave

Post-merge docs sweep for the Aug 16 scout slate. Two pages:

- mcp.md: tool-result sanitization section — invisible Unicode TAG chars
  (U+E0000-E007F) stripped from results/resources/descriptions (#80689);
  vendor _meta surfaced to the model minus protocol-reserved
  modelcontextprotocol/mcp prefixes (#80712)
- tools.md: tool result annotations section — signal-death exit notes
  (subprocess -signum definite, shell 128+signum hedged) (#78074); UTF-16
  read_file transcoding with disclosure hint and 10MB cap (#80717)

Security-policy docs (approvals/allowlist) intentionally untouched.
lisajlau pushed a commit to lisajlau/hermes-agent that referenced this pull request Aug 20, 2026
…scout-slate wave

Post-merge docs sweep for the Aug 16 scout slate. Two pages:

- mcp.md: tool-result sanitization section — invisible Unicode TAG chars
  (U+E0000-E007F) stripped from results/resources/descriptions (NousResearch#80689);
  vendor _meta surfaced to the model minus protocol-reserved
  modelcontextprotocol/mcp prefixes (NousResearch#80712)
- tools.md: tool result annotations section — signal-death exit notes
  (subprocess -signum definite, shell 128+signum hedged) (NousResearch#78074); UTF-16
  read_file transcoding with disclosure hint and 10MB cap (NousResearch#80717)

Security-policy docs (approvals/allowlist) intentionally untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have tool/terminal Terminal execution and process management type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants