Skip to content

docs: bring the manual current with today's merges - #113

Merged
TheSmokeDev merged 2 commits into
mainfrom
docs/post-sweep
Sep 3, 2026
Merged

docs: bring the manual current with today's merges#113
TheSmokeDev merged 2 commits into
mainfrom
docs/post-sweep

Conversation

@TheSmokeDev

@TheSmokeDev TheSmokeDev commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Eighteen PRs merged today; the manual did not move with them. Docs and markdown only — no Python, no version bump, no tag, no release cut.

Every claim below was read out of the code. Nothing was taken from a PR body.

What changed, per file

docs/OPERATING.md

Gap Fix
No row for any of the four TALK_ECHO_GATE* knobs (#83) All four in the Audio table with their real defaults and real parse behaviour
PulseAudio WebRTC AEC (#81) undocumented Documented with the exact conditions that gate it, and the load-bearing fact that it bypasses the software gate
execution_mode / resource_keys (#101) undocumented New subsection under Agent lanes
Discord section listed join/leave/status only /talk pause and /talk resume added (#100)
Nothing named the announcement-starvation warning Troubleshooting entry keyed to the literal string an operator would search for

Two deliberate placement calls:

  • execution_mode / resource_keys are tool ARGUMENTS, not environment variables. "Configuration — every knob" opens with "All variables are resolved at call time" and is an env-var table throughout. Putting two tool args in it would have made the table lie about what it is. They live in a sibling subsection headed "Admission declarations — arguments, not variables", directly under TALK_TRUST_DECLARED_READ_ONLY, which is the operator half of the same contract.
  • ANNOUNCE_STARVATION_WARN_S is a module constant, not an env vartalk_cli.py:234, = 30.0, exported in __all__, read directly at talk_cli.py:778. There is no os.environ read anywhere for it. Documenting it as a knob would have sent operators to set a variable that does nothing, so it is in Troubleshooting, explicitly flagged as not settable.

docs/VOICE-COMMANDS.md

  • Broken anchor fixed. Line 23 pointed at OPERATING.md#2-talk_status--the-one-command; that heading is now ### 4. \talk_status` — the in-session command (docs/OPERATING.md:150`). It was the only broken anchor in the repo.
  • delegate_task gained a row for the admission declaration, including the refusal sentence.
  • New "Pausing the mic — and the way back" section: both rooms' controls, the platform difference in how the key is read, and the three places the tool is deliberately not advertised.

docs/REALTIME-ORCHESTRATOR.md

Four stale facts and one whole missing module — see the verification list.

CHANGELOG.md

[Unreleased] carried two separate ### Changed blocks. Merged, and the section regrouped under Added / Changed / Fixed / Security. #81 credited to @kvnloo.

Nothing was cut. Machine-checked: 24 bullets in, 24 bullets out, and a token-level set diff of old-vs-new [Unreleased] returns zero words present before and absent after. No release cut, no version bumped, no link-reference block touched.

I did not add PR-number annotations. The file's house style cites the driving issue bare (#100, #101, #97, #95) and never the PR; adding [#105]-style refs would have been a voice change, not a correction. The one link added is the kvnloo credit, in the README's own credit style.

Also fixed two Markdown rendering bugs in the same file: ## [0.16.0] and ## [0.15.1] both sat directly against the preceding line with no blank line, so neither rendered as a heading. Zero content change.

Verification list

Every claim, with the file:line it came from.

Echo gatetalk_audio.py:74-85 (_echo_gate_settings), :59-61 (defaults 0.015 / 0.04 / 0.65), :63-72 (_env_float: blank/unparseable/negative → default; value >= 0 so 0 is honored), :277-281 (read in DuplexAudio.__init__, not at import), :363-370 (the gate runs only if self._echo_gate_enabled and not self._pulse_webrtc.active; threshold is max(min_barge_in, output_level * ratio) — hence "the larger of the two").
TALK_ECHO_GATE disables on {"0","off","false","no","disabled"} after .strip().lower(); everything else, junk included, leaves it enabled (talk_audio.py:77-78).

PulseAudio routetalk_audio.py:157-205. Returns unchanged unless input_device is None and output_device is None and sys.platform == "linux" (:162); needs shutil.which("pactl") (:164-166); module-echo-cancel aec_method=webrtc … noise_suppression=1 (:172-186); timeout=5 (:185); any OSError/SubprocessError/ValueError falls back silently (:190-191); talk_audio.py:296-308 retries on the original devices if the routed stream will not open. active is self._module_id is not None (:151-155).

ANNOUNCE_STARVATION_WARN_Stalk_cli.py:234 (constant 30.0), :778-782 (fires once per batch, > 0 gates it), :2419 (in __all__), :2151-2153 (the operator string: an update has been waiting {waited:.0f}s for a safe opening), :1661-1662 (on_error prints \n[talk] {text} to stderr). The busy predicate at :2146-2150 includes speaker_busy() — the #87 playback-drain gate (:1638-1656).

Admission controltalk_runs.py:140-141 (EXECUTION_MODES), :142 (MAX_RESOURCE_KEYS = 8), :180-212 (normalize_resource_keys: whitespace-collapsed, casefold()ed, deduped, and refused rather than truncated past 8 — :211), :215-231 (resolve_execution_mode: None → exclusive; parallel_read_only downgraded unless the knob is on), :245-275 (_admission_conflict_locked: if not keys: return None — no keys, no fence), :154-176 (AdmissionRefused raised before acceptance). Knob: talk_config.py:873-885, raw in {"1","true","yes","on"} — default off. Tool schema: talk_tools.py:164-187.

Pause — advertised iff a resume control exists: talk_cli.py:1522-1527 (discordRESUME_COMMAND; cli and keyboard_control and keyboard_pause_control_available()RESUME_KEYBOARD; else None), :1533 (default_talk_tools(pausable=resume_control is not None)), talk_tools.py:469-470. keyboard_pause_control_available is stdin.isatty() (talk_cli.py:1149-1163) — the docstring names Git Bash's mintty as the false case. keyboard_control is True only for standalone hermes talk (talk_cli.py:2406-2407); /talk at the Hermes prompt passes False (__init__.py:212-215). Execution-side gate: talk_pause.py:150-153 (NO_RESUME_PATH), and resuming is always allowed. Keys: talk_cli.py:1087-1096 (Enter = toggle, p/r explicit) and :1118-1146 (msvcrt char-at-a-time on Windows with the extended-key prefix consumed; select + readline in cooked mode elsewhere). Discord commands: __init__.py:170, :221-224; paused state in /talk status at talk_discord.py:1383-1387. Read-only classification: talk_operator_auth.py:45, :59.

hermes talk check / diagnostics — flags match §3b and §7 exactly. talk_cli.py:2286-2320 (--json, --no-run, --timeout SECONDS, --provider with choices=talk_check.LIVE_PROVIDERS) and :2322-2345 (--json, --bundle [PATH] via nargs="?"). Defaults: talk_check.py:75-76 (PROVIDER_STEP_TIMEOUT_S = 60.0, RUN_STEP_TIMEOUT_S = 180.0), :60 (STEP_ORDER), :73 (MAGIC_WORD), :58 (SCHEMA_VERSION = 1), LIVE_PROVIDERS = talk_config.TALK_PROVIDERS = ("openai","grok","gemini") (talk_config.py:30). Exit codes: talk_check.py:773 (0 if report["ok"] else 1), talk_diagnostics.py:555/560/563 (1 only when a requested write failed). Both sections read true and were left alone.

Upgrade runbook — re-read; nothing today changed hermes plugins update or the gateway-restart requirement. Left alone.

REALTIME-ORCHESTRATOR corrections — tool list vs talk_tools.py:454-473 (ten unconditional, resolve_approval at :465 was missing from the doc, pause_voice_input at :470 was missing, search_vault at :473 is conditional and the doc showed it as not); capture call site is __init__.py:237, not ~185; version is 0.16.0 (plugin.yaml:2, pyproject.toml:3), not 0.8.0; doctor is 10 checks, not 8 — talk_doctor.py:45-56 (CHECK_ORDER) and :831-843, where assert tuple(check["id"] for check in checks) == CHECK_ORDER makes the count deterministic rather than a guess. talk_core_provider.py added: __init__.py:112-141 (feature-detected registration), talk_core_provider.py:69-71 (the three lane ids), :442/:513/:578 (per-lane capability declarations), talk_tools.py:756-758 (the legacy-provider-executor label that keeps the two lanes apart).

Links — a script resolved every relative target in README.md, CONTRIBUTING.md, SECURITY.md, and docs/*.md, checking each #anchor against the destination's real headings: 77 relative links, 23 with anchors, 0 broken after this PR (1 broken before).

Second commit — the machine-specific detail is gone

42099de acts on findings 1 and 2 below, which the first commit only reported.

docs/REALTIME-ORCHESTRATOR.md was publishing one operator's box to a public repo: an absolute C:\Users\<name>\AppData\Local\hermes HERMES_HOME, an isolated-dev checkout path, a hermes-agent fork branch name, and a pre-merge commit SHA offered "if rollback is needed". Section retitled "Install layout and restart rules" and rewritten to carry only operator-independent fact: how HERMES_HOME actually resolves (host resolver first, ~/.hermes only as the not-importable fallback — talk_config.py:153-164), why a ~/.hermes/plugins/hermes-talk directory is not proof of what is loaded, that the gateway keeps running the code it loaded until restarted, and kill the specific PID only.

"This machine" was in four places, not one — the header's source line, talk_openai_realtime.py's voice, talk_auth.py's winning lane, and the section heading. All four now state the general fact and point at hermes talk doctor for the local one. Same for "install is 0.20.0" in Known limits.

Both unverifiable upstream claims dropped. The attachment module's "not yet upstream (NousResearch PR pending)" and #79716's "pending" were assertions about a different repository's merge state, made in this one. Each now says explicitly that this page cannot verify it and points at hermes-agent and at doctor. In their place is the plugin-side fact that IS verifiable here: the capture is feature-detected (__init__.py:237), so a host without the attachment simply takes the other lane.

Repo-wide sweep for the same class. git grep over the whole tree for C:\Users\, /Users/<user>, /home/<user>, isolated-dev, the operator name, private-range IPs, personal emails, and the fork branch/SHA:

Where Hits Call
docs/REALTIME-ORCHESTRATOR.md 3 Fixed — the section above
tests/ (test_check.py:504,754, test_diagnostics.py:26, test_doctor.py:344, test_progress.py:149, redact-rm-rf.fixture:1) 6 Left deliberately. Synthetic placeholders (someone, operator) that exist to be scrubbed — they are the inputs to the redaction and path-scrub assertions. Rewriting them would weaken the tests that prove paths never reach a bundle.
tests/test_dashboard_api.py:477,508,511 3 Left — 10.0.0.7 is a synthetic non-loopback host proving the auth gate fires.
docs/plans/grok-oauth/01-spec.md:160 1 Left — %LOCALAPPDATA%\hermes / ~/.hermes are the correct generic platform paths.
Prose matches on "live install" / "this machine" (README.md:477, CONTRIBUTING.md:125, CHANGELOG.md:349,365,770, talk_cli.py:559, talk_vault.py:284) 7 Left — all generic, addressed to the reader; none carries a path, name, or SHA.

No personal email, real name, or non-loopback private host anywhere in the tree.

Found, not fixed — and why

  1. The "834 passed / 7 skipped" test receipt — I replaced the stale hardcoded command with the current uv invocation and pointed at CONTRIBUTING for the baseline, rather than substituting today's number, which would go stale the same way.
  2. CHANGELOG.md:770 ("On this box that left three real runs stuck at running forever") is a released historical entry describing an observed symptom. No path, no identity — and rewriting shipped changelog entries is not what this PR is for. Flagging it rather than touching it.
  3. docs/CAPABILITY-KERNEL-PORT.md — verified, untouched. Every current-state claim in "What already exists here" checks out (plugin.yaml:1-11 and the three hooks wired at __init__.py:300-323; register(ctx) at :258; talk_capabilities.py:230/267/297-303; redaction at talk_doctor.py:74-116/861/1040). The rest of the page is explicitly labelled a forward-looking design contract that hermes-talk does not yet claim, so it is accurate as written.
  4. The grep for forward-looking language returned three hits total across README.md, CONTRIBUTING.md, SECURITY.md, and docs/*.md. None was falsified by today's merges — all three describe genuinely unbuilt work (the CAPABILITY-KERNEL-PORT schema extension; REALTIME-ORCHESTRATOR's "Next phase (agreed direction, not built)", confirmed unbuilt by grepping the tree for its own vocabulary). All eight of today's features are already described in present tense wherever they appear. Nothing needed correcting there.

Gates

  • uv run --extra dev ruff check .All checks passed (untouched by this PR).
  • uv run --extra dev pytest -q1637 passed, 40 skipped, 5 xfailed, 0 failed. The twelve test: host-summary and capabilities tests fail on any box where hermes-agent is importable #93 failures do not reproduce in this worktree's venv (Hermes is not importable here, so they skip). No failure is mine.
  • git diff --stat is byte-identical to git diff --ignore-all-space --stat — no whitespace churn, no line-ending flip (CHANGELOG.md is LF in HEAD and LF in the working tree; the three docs/*.md stayed CRLF).

One near-miss worth recording: drafting the CHANGELOG I typed a literal U+FEFF into the entry that describes PR #92 — the entry about a literal U+FEFF taking the repo to a BLOCKED plugin_guard verdict. Caught on a byte-level check before staging; the committed file has the ASCII escape the original had, and the tree contains zero EF BB BF sequences.

🤖 Generated with Claude Code

TheSmokeDev and others added 2 commits September 3, 2026 14:49
Eighteen PRs merged today and the manual did not move with them. Every
claim below was read out of the code, not out of a PR body.

OPERATING.md
- The Audio table had no row for any of the four TALK_ECHO_GATE knobs,
  which #83 made cross-platform and tunable. All four documented with
  their real defaults and their real parse behaviour: the gate is ON
  unless explicitly disabled, and the three numeric knobs fail soft.
- The PulseAudio WebRTC route (#81) is documented with the conditions
  that actually gate it and the fact that it BYPASSES the software gate.
- New subsection for delegate_task's execution_mode / resource_keys.
  They are tool ARGUMENTS, not variables, so they sit next to the knob
  that governs them rather than inside a table of environment variables.
- The Discord section listed join/leave/status but not /talk pause and
  /talk resume, which #105 added.
- Troubleshooting gained the announcement-starvation line, keyed to the
  string an operator would actually search for.

VOICE-COMMANDS.md
- Fixed a broken anchor: the talk_status row pointed at
  #2-talk_status--the-one-command, a heading that is now section 4 and
  differently worded.
- delegate_task gained a row for the admission declaration, including
  what the refusal sounds like.
- New "Pausing the mic" section: both rooms' controls, the platform
  difference in how the key is read, and the three places the tool is
  deliberately NOT advertised.

REALTIME-ORCHESTRATOR.md
- The tool list was missing resolve_approval and pause_voice_input and
  presented search_vault as unconditional; it is not.
- talk_core_provider.py was entirely undocumented. Added, including the
  detail that the core lane is input-only and does not execute tools.
- The capture line number (185 -> 237), the version (0.8.0), and the
  doctor receipt (8/8 -> 10/10, fixed by CHECK_ORDER) were all stale.

CHANGELOG.md
- [Unreleased] carried TWO "### Changed" blocks. Merged, and the whole
  section regrouped under Added / Changed / Fixed / Security.
- #81 is credited to @kvnloo — the first outside contribution to a live
  lane.
- No release cut, no version bumped, no entry rewritten away: 24 bullets
  in, 24 bullets out, zero tokens lost.

Docs only. ruff clean; 1637 passed / 40 skipped / 5 xfailed, no failures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The "Live install layout (this machine)" section published one operator's
absolute home paths, a hermes-agent fork branch, and a pre-merge SHA to a
public repo. Rewritten as "Install layout and restart rules", carrying only
what is true for any operator: how HERMES_HOME actually resolves, why a
directory on disk is not proof of what is loaded, that the gateway must be
restarted after any plugin or host update, and kill the specific PID only.

"This machine" was in four places, not one — the header's source line, the
OpenAI provider's voice, the winning auth lane, and the section heading. All
four now state the general fact and point at `hermes talk doctor` for the
local one.

Two claims about a DIFFERENT repository's merge state were being asserted as
fact here and cannot be verified from this one: the execution-attachment
module's upstream status, and whether PR #79716 has landed. Both now say so
and point at hermes-agent and at doctor, rather than guessing in either
direction. The plugin-side contract is stated instead, which IS verifiable:
the capture is feature-detected, so a host without it takes the other lane.

Repo-wide sweep for the same class found no other hit outside tests. The
test hits are synthetic redaction fixtures (`someone`, `operator`,
`10.0.0.7`) whose whole job is to be scrubbed — left alone deliberately.

Docs only. ruff clean; 1637 passed / 40 skipped / 5 xfailed, no failures.
77 relative links, 23 anchors, 0 broken.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@TheSmokeDev
TheSmokeDev merged commit 9f39e46 into main Sep 3, 2026
11 checks passed
@TheSmokeDev
TheSmokeDev deleted the docs/post-sweep branch September 3, 2026 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant