docs: bring the manual current with today's merges - #113
Merged
Conversation
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>
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.
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.mdTALK_ECHO_GATE*knobs (#83)execution_mode/resource_keys(#101) undocumentedjoin/leave/statusonly/talk pauseand/talk resumeadded (#100)Two deliberate placement calls:
execution_mode/resource_keysare 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 underTALK_TRUST_DECLARED_READ_ONLY, which is the operator half of the same contract.ANNOUNCE_STARVATION_WARN_Sis a module constant, not an env var —talk_cli.py:234,= 30.0, exported in__all__, read directly attalk_cli.py:778. There is noos.environread 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.mdOPERATING.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_taskgained a row for the admission declaration, including the refusal sentence.docs/REALTIME-ORCHESTRATOR.mdFour stale facts and one whole missing module — see the verification list.
CHANGELOG.md[Unreleased]carried two separate### Changedblocks. Merged, and the section regrouped under Added / Changed / Fixed / Security.#81credited 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 gate —
talk_audio.py:74-85(_echo_gate_settings),:59-61(defaults0.015/0.04/0.65),:63-72(_env_float: blank/unparseable/negative → default;value >= 0so0is honored),:277-281(read inDuplexAudio.__init__, not at import),:363-370(the gate runs onlyif self._echo_gate_enabled and not self._pulse_webrtc.active; threshold ismax(min_barge_in, output_level * ratio)— hence "the larger of the two").TALK_ECHO_GATEdisables on{"0","off","false","no","disabled"}after.strip().lower(); everything else, junk included, leaves it enabled (talk_audio.py:77-78).PulseAudio route —
talk_audio.py:157-205. Returns unchanged unlessinput_device is None and output_device is None and sys.platform == "linux"(:162); needsshutil.which("pactl")(:164-166);module-echo-cancel aec_method=webrtc … noise_suppression=1(:172-186);timeout=5(:185); anyOSError/SubprocessError/ValueErrorfalls back silently (:190-191);talk_audio.py:296-308retries on the original devices if the routed stream will not open.activeisself._module_id is not None(:151-155).ANNOUNCE_STARVATION_WARN_S—talk_cli.py:234(constant30.0),:778-782(fires once per batch,> 0gates it),:2419(in__all__),:2151-2153(the operator string:an update has been waiting {waited:.0f}s for a safe opening),:1661-1662(on_errorprints\n[talk] {text}to stderr). The busy predicate at:2146-2150includesspeaker_busy()— the #87 playback-drain gate (:1638-1656).Admission control —
talk_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_onlydowngraded unless the knob is on),:245-275(_admission_conflict_locked:if not keys: return None— no keys, no fence),:154-176(AdmissionRefusedraised 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(discord→RESUME_COMMAND;cli and keyboard_control and keyboard_pause_control_available()→RESUME_KEYBOARD; elseNone),:1533(default_talk_tools(pausable=resume_control is not None)),talk_tools.py:469-470.keyboard_pause_control_availableisstdin.isatty()(talk_cli.py:1149-1163) — the docstring names Git Bash's mintty as the false case.keyboard_controlis True only for standalonehermes talk(talk_cli.py:2406-2407);/talkat 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/rexplicit) and:1118-1146(msvcrt char-at-a-time on Windows with the extended-key prefix consumed;select+readlinein cooked mode elsewhere). Discord commands:__init__.py:170,:221-224; paused state in/talk statusattalk_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,--providerwithchoices=talk_check.LIVE_PROVIDERS) and:2322-2345(--json,--bundle [PATH]vianargs="?"). 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 updateor the gateway-restart requirement. Left alone.REALTIME-ORCHESTRATOR corrections — tool list vs
talk_tools.py:454-473(ten unconditional,resolve_approvalat:465was missing from the doc,pause_voice_inputat:470was missing,search_vaultat:473is conditional and the doc showed it as not); capture call site is__init__.py:237, not ~185; version is0.16.0(plugin.yaml:2,pyproject.toml:3), not0.8.0; doctor is 10 checks, not 8 —talk_doctor.py:45-56(CHECK_ORDER) and:831-843, whereassert tuple(check["id"] for check in checks) == CHECK_ORDERmakes the count deterministic rather than a guess.talk_core_provider.pyadded:__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(thelegacy-provider-executorlabel that keeps the two lanes apart).Links — a script resolved every relative target in
README.md,CONTRIBUTING.md,SECURITY.md, anddocs/*.md, checking each#anchoragainst 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
42099deacts on findings 1 and 2 below, which the first commit only reported.docs/REALTIME-ORCHESTRATOR.mdwas publishing one operator's box to a public repo: an absoluteC:\Users\<name>\AppData\Local\hermesHERMES_HOME, anisolated-devcheckout path, ahermes-agentfork 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: howHERMES_HOMEactually resolves (host resolver first,~/.hermesonly as the not-importable fallback —talk_config.py:153-164), why a~/.hermes/plugins/hermes-talkdirectory 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 athermes talk doctorfor 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 grepover the whole tree forC:\Users\,/Users/<user>,/home/<user>,isolated-dev, the operator name, private-range IPs, personal emails, and the fork branch/SHA:docs/REALTIME-ORCHESTRATOR.mdtests/(test_check.py:504,754,test_diagnostics.py:26,test_doctor.py:344,test_progress.py:149,redact-rm-rf.fixture:1)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,51110.0.0.7is a synthetic non-loopback host proving the auth gate fires.docs/plans/grok-oauth/01-spec.md:160%LOCALAPPDATA%\hermes/~/.hermesare the correct generic platform paths.README.md:477,CONTRIBUTING.md:125,CHANGELOG.md:349,365,770,talk_cli.py:559,talk_vault.py:284)No personal email, real name, or non-loopback private host anywhere in the tree.
Found, not fixed — and why
uvinvocation and pointed at CONTRIBUTING for the baseline, rather than substituting today's number, which would go stale the same way.CHANGELOG.md:770("On this box that left three real runs stuck atrunningforever") 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.docs/CAPABILITY-KERNEL-PORT.md— verified, untouched. Every current-state claim in "What already exists here" checks out (plugin.yaml:1-11and the three hooks wired at__init__.py:300-323;register(ctx)at:258;talk_capabilities.py:230/267/297-303; redaction attalk_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.grepfor forward-looking language returned three hits total acrossREADME.md,CONTRIBUTING.md,SECURITY.md, anddocs/*.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 -q— 1637 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 --statis byte-identical togit diff --ignore-all-space --stat— no whitespace churn, no line-ending flip (CHANGELOG.mdis LF in HEAD and LF in the working tree; the threedocs/*.mdstayed 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_guardverdict. Caught on a byte-level check before staging; the committed file has the ASCII escape the original had, and the tree contains zeroEF BB BFsequences.🤖 Generated with Claude Code