feat(log): tag Turn-ended diag line with cron task id (task=)#11
Merged
Conversation
… session token (NousResearch#38926) The documented path for connecting Hermes Desktop to a remote backend was `--insecure` + a pinned HERMES_DASHBOARD_SESSION_TOKEN — an unauthenticated bind plus a copy-pasted token. Replace it everywhere with the bundled username/password dashboard-auth provider: set HERMES_DASHBOARD_BASIC_AUTH_*, run `hermes dashboard --host 0.0.0.0` (the non-loopback bind engages the auth gate), and Sign in from the app. - desktop.md: rewrite 'Connecting to a remote backend' for the user/pass + Sign in flow - web-dashboard.md: rewrite both remote-backend sections (overview + dedicated); reframe the auth-gate section so --insecure is a discouraged escape hatch, not a co-equal use case; drop the removed --tui flag from the systemd example - environment-variables.md: lead with HERMES_DASHBOARD_BASIC_AUTH_*; drop the session-token / HERMES_DESKTOP_REMOTE_TOKEN remote-connect entries - docker.md: mention the username/password provider as the simplest gate provider
…lback (NousResearch#38928) The classic CLI left its live bottom chrome — the status bar, input box, and separator rules — frozen in terminal scrollback after exit, on every exit path (/exit, /quit, Ctrl+C, EOF) and on both Linux and Windows. The prior erase_when_done=True fix (bf82a7f) routes prompt_toolkit's teardown through renderer.erase(), but that walks back by the renderer's internal cursor model and does not reliably wipe the chrome in practice — users still saw a dead status bar + the rest of the session sitting above the resume summary. Clear the screen + scrollback directly at the single exit funnel instead. All exit paths converge on _print_exit_summary() (called from the run-loop finally block after app.run() returns and prompt_toolkit has restored terminal modes), so a new _clear_terminal_on_exit() helper runs there before the summary prints. It writes ESC[3J ESC[2J ESC[H (erase scrollback, erase screen, home cursor) on a real TTY, no-ops silently when stdout is not a terminal (pipes/redirects), and falls back to the platform clear command if the escape write fails. Works on Linux, macOS, and modern Windows terminals (Terminal/conhost with VT processing, already enabled by prompt_toolkit). The resume/goodbye summary now prints at a clean top-left with nothing stranded above it. Fixes NousResearch#38252.
…OOT) The reboot/shutdown family is on the unconditional hardline blocklist — the correct default for most agents, but a hard blocker for fleet/ops agents that legitimately need to restart the Linux hosts they manage. Add an opt-in escape hatch: when HERMES_ALLOW_REBOOT is set truthy, the reboot/shutdown family downgrades from HARDLINE to the DANGEROUS layer — still approval-gated, and yolo / approvals.mode=off can pass it through. Every other catastrophic pattern (root recursive delete, filesystem format, raw-device overwrite, fork bomb, kill -1) stays unconditionally hardline. Default (flag unset) is byte-identical to the historical always-block behavior. Verified: 129 tests pass including new downgrade and isolation tests.
The cron scheduler already threads the job id into the agent as task_id (cron/scheduler.py -> run_conversation(task_id=...) -> effective_task_id). Surface it in the per-turn 'Turn ended' diagnostic log as task=<id> so cron turns can be attributed to their job. Enables model-fallback-check.py to detect when a model-pinned cron silently ran on a fallback model, replacing an unreliable time-window heuristic with exact job-id attribution. Additive logging only — no control flow change. Both logger.info and the 'pending tool result' logger.warning branch share _diag_msg/_diag_args, so both gain the field. Format-specifier/arg count kept in lockstep (guarded by test). tests/agent/test_turn_ended_task_id_log.py: 3 contract tests (task= present, specifiers==args, last arg is effective_task_id).
🔎 Lint report:
|
| Rule | Count |
|---|---|
deprecated |
1 |
First entries
cli.py:12760: [deprecated] deprecated: The function `system` is deprecated: Soft deprecated. Use the subprocess module instead.
✅ Fixed issues: none
Unchanged: 5116 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
Kyzcreig
added a commit
that referenced
this pull request
Jun 5, 2026
* docs: remote desktop connect uses username/password, not --insecure + session token (NousResearch#38926) The documented path for connecting Hermes Desktop to a remote backend was `--insecure` + a pinned HERMES_DASHBOARD_SESSION_TOKEN — an unauthenticated bind plus a copy-pasted token. Replace it everywhere with the bundled username/password dashboard-auth provider: set HERMES_DASHBOARD_BASIC_AUTH_*, run `hermes dashboard --host 0.0.0.0` (the non-loopback bind engages the auth gate), and Sign in from the app. - desktop.md: rewrite 'Connecting to a remote backend' for the user/pass + Sign in flow - web-dashboard.md: rewrite both remote-backend sections (overview + dedicated); reframe the auth-gate section so --insecure is a discouraged escape hatch, not a co-equal use case; drop the removed --tui flag from the systemd example - environment-variables.md: lead with HERMES_DASHBOARD_BASIC_AUTH_*; drop the session-token / HERMES_DESKTOP_REMOTE_TOKEN remote-connect entries - docker.md: mention the username/password provider as the simplest gate provider * fix(cli): clear screen on exit so live chrome isn't stranded in scrollback (NousResearch#38928) The classic CLI left its live bottom chrome — the status bar, input box, and separator rules — frozen in terminal scrollback after exit, on every exit path (/exit, /quit, Ctrl+C, EOF) and on both Linux and Windows. The prior erase_when_done=True fix (bf82a7f) routes prompt_toolkit's teardown through renderer.erase(), but that walks back by the renderer's internal cursor model and does not reliably wipe the chrome in practice — users still saw a dead status bar + the rest of the session sitting above the resume summary. Clear the screen + scrollback directly at the single exit funnel instead. All exit paths converge on _print_exit_summary() (called from the run-loop finally block after app.run() returns and prompt_toolkit has restored terminal modes), so a new _clear_terminal_on_exit() helper runs there before the summary prints. It writes ESC[3J ESC[2J ESC[H (erase scrollback, erase screen, home cursor) on a real TTY, no-ops silently when stdout is not a terminal (pipes/redirects), and falls back to the platform clear command if the escape write fails. Works on Linux, macOS, and modern Windows terminals (Terminal/conhost with VT processing, already enabled by prompt_toolkit). The resume/goodbye summary now prints at a clean top-left with nothing stranded above it. Fixes NousResearch#38252. * feat(approval): env-gated reboot/shutdown downgrade (HERMES_ALLOW_REBOOT) The reboot/shutdown family is on the unconditional hardline blocklist — the correct default for most agents, but a hard blocker for fleet/ops agents that legitimately need to restart the Linux hosts they manage. Add an opt-in escape hatch: when HERMES_ALLOW_REBOOT is set truthy, the reboot/shutdown family downgrades from HARDLINE to the DANGEROUS layer — still approval-gated, and yolo / approvals.mode=off can pass it through. Every other catastrophic pattern (root recursive delete, filesystem format, raw-device overwrite, fork bomb, kill -1) stays unconditionally hardline. Default (flag unset) is byte-identical to the historical always-block behavior. Verified: 129 tests pass including new downgrade and isolation tests. * feat(log): tag Turn-ended diag line with cron task id (task=) The cron scheduler already threads the job id into the agent as task_id (cron/scheduler.py -> run_conversation(task_id=...) -> effective_task_id). Surface it in the per-turn 'Turn ended' diagnostic log as task=<id> so cron turns can be attributed to their job. Enables model-fallback-check.py to detect when a model-pinned cron silently ran on a fallback model, replacing an unreliable time-window heuristic with exact job-id attribution. Additive logging only — no control flow change. Both logger.info and the 'pending tool result' logger.warning branch share _diag_msg/_diag_args, so both gain the field. Format-specifier/arg count kept in lockstep (guarded by test). tests/agent/test_turn_ended_task_id_log.py: 3 contract tests (task= present, specifiers==args, last arg is effective_task_id). --------- Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com> Co-authored-by: Kyzcreig <9063726+Kyzcreig@users.noreply.github.com> Co-authored-by: Aegis <aegis@hermes.local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
task=<id>to the per-turnTurn ended:diagnostic log line inagent/conversation_loop.py.Why
The cron scheduler already threads the job id into the agent as
task_id(cron/scheduler.py:1132→run_conversation(task_id=...)→effective_task_id), but it was never logged. Surfacing it letsmodel-fallback-check.pyattribute a logged turn to the exact cron job that produced it — detecting when a model-pinned cron silently ran on a fallback model (429/outage), replacing an unreliable time-window heuristic.Change
task=%sin_diag_msg,effective_task_id or "none"in_diag_args.logger.infoand the pending-tool-resultlogger.warningbranch share the pair, so both gain it.Tests
tests/agent/test_turn_ended_task_id_log.py— 3 contract tests (task= present; specifiers==args; last arg is effective_task_id). All green. Empirically verified the format renders...session=… task=<job_id>.