docs(skills): document browse.sh source (#28939)
Add browse.sh (browse-sh) to the supported-sources table and
integrated-hubs section in user-guide/features/skills.md, and to the
--source notes in reference/cli-commands.md. Companion to the
BrowseShSource adapter merged in #28936.
docs(web-search): document xAI Web Search backend (#29052)
Follow-up to #29042 (xAI Web Search provider plugin). Adds xAI to the
canonical user-facing and developer-facing docs, with the search-only
caveat and the LLM-in-a-trench-coat trust model carried over from the
class docstring.
- user-guide/features/web-search.md
- Backends table: new xAI row + extended search-only note
- New 'xAI (Grok)' setup section with config knobs and trust-model
caution admonition
- Single-backend yaml comment now lists 'xai'
- Auto-detection table: explicitly note that xAI is NOT auto-detected
(XAI_API_KEY is shared with inference/TTS/image-gen so we don't
silently take over web for users who only set it for chat)
- developer-guide/web-search-provider-plugin.md
- Added plugins/web/xai/ to the 'study these next' reference list
- reference/environment-variables.md
- XAI_API_KEY description now also mentions web search
docs: deep audit — fix stale config keys, missing commands, and registry drift (#22784)
* docs: deep audit — fix stale config keys, missing commands, and registry drift
Cross-checked ~80 high-impact docs pages (getting-started, reference, top-level
user-guide, user-guide/features) against the live registries:
hermes_cli/commands.py COMMAND_REGISTRY (slash commands)
hermes_cli/auth.py PROVIDER_REGISTRY (providers)
hermes_cli/config.py DEFAULT_CONFIG (config keys)
toolsets.py TOOLSETS (toolsets)
tools/registry.py get_all_tool_names() (tools)
python -m hermes_cli.main <subcmd> --help (CLI args)
reference/
- cli-commands.md: drop duplicate hermes fallback row + duplicate section,
add stepfun/lmstudio to --provider enum, expand auth/mcp/curator subcommand
lists to match --help output (status/logout/spotify, login, archive/prune/
list-archived).
- slash-commands.md: add missing /sessions and /reload-skills entries +
correct the cross-platform Notes line.
- tools-reference.md: drop bogus '68 tools' headline, drop fictional
'browser-cdp toolset' (these tools live in 'browser' and are runtime-gated),
add missing 'kanban' and 'video' toolset sections, fix MCP example to use
the real mcp_<server>_<tool> prefix.
- toolsets-reference.md: list browser_cdp/browser_dialog inside the 'browser'
row, add missing 'kanban' and 'video' toolset rows, drop the stale
'38 tools' count for hermes-cli.
- profile-commands.md: add missing install/update/info subcommands, document
fish completion.
- environment-variables.md: dedupe GMI_API_KEY/GMI_BASE_URL rows (kept the
one with the correct gmi-serving.com default).
- faq.md: Anthropic/Google/OpenAI examples — direct providers exist (not just
via OpenRouter), refresh the OpenAI model list.
getting-started/
- installation.md: PortableGit (not MinGit) is what the Windows installer
fetches; document the 32-bit MinGit fallback.
- installation.md / termux.md: installer prefers .[termux-all] then falls
back to .[termux].
- nix-setup.md: Python 3.12 (not 3.11), Node.js 22 (not 20); fix invalid
'nix flake update --flake' invocation.
- updating.md: 'hermes backup restore --state pre-update' doesn't exist —
point at the snapshot/quick-snapshot flow; correct config key
'updates.pre_update_backup' (was 'update.backup').
user-guide/
- configuration.md: api_max_retries default 3 (not 2); display.runtime_footer
is the real key (not display.runtime_metadata_footer); checkpoints defaults
enabled=false / max_snapshots=20 (not true / 50).
- configuring-models.md: 'hermes model list' / 'hermes model set ...' don't
exist — hermes model is interactive only.
- tui.md: busy_indicator -> tui_status_indicator with values
kaomoji|emoji|unicode|ascii (not kawaii|minimal|dots|wings|none).
- security.md: SSH backend keys (TERMINAL_SSH_HOST/USER/KEY) live in .env,
not config.yaml.
- windows-wsl-quickstart.md: there is no 'hermes api' subcommand — the
OpenAI-compatible API server runs inside hermes gateway.
user-guide/features/
- computer-use.md: approvals.mode (not security.approval_level); fix broken
./browser-use.md link to ./browser.md.
- fallback-providers.md: top-level fallback_providers (not
model.fallback_providers); the picker is subcommand-based, not modal.
- api-server.md: API_SERVER_* are env vars — write to per-profile .env,
not 'hermes config set' which targets YAML.
- web-search.md: drop web_crawl as a registered tool (it isn't); deep-crawl
modes are exposed through web_extract.
- kanban.md: failure_limit default is 2, not '~5'.
- plugins.md: drop hard-coded '33 providers' count.
- honcho.md: fix unclosed quote in echo HONCHO_API_KEY snippet; document
that 'hermes honcho' subcommand is gated on memory.provider=honcho;
reconcile subcommand list with actual --help output.
- memory-providers.md: legacy 'hermes honcho setup' redirect documented.
Verified via 'npm run build' — site builds cleanly; broken-link count went
from 149 to 146 (no regressions, fixed a few in passing).
* docs: round 2 audit fixes + regenerate skill catalogs
Follow-up to the previous commit on this branch:
Round 2 manual fixes:
- quickstart.md: KIMI_CODING_API_KEY mentioned alongside KIMI_API_KEY;
voice-mode and ACP install commands rewritten — bare 'pip install ...'
doesn't work for curl-installed setups (no pip on PATH, not in repo
dir); replaced with 'cd ~/.hermes/hermes-agent && uv pip install -e
".[voice]"'. ACP already ships in [all] so the curl install includes it.
- cli.md / configuration.md: 'auxiliary.compression.model' shown as
'google/gemini-3-flash-preview' (the doc's own claimed default);
actual default is empty (= use main model). Reworded as 'leave empty
(default) or pin a cheap model'.
- built-in-plugins.md: added the bundled 'kanban/dashboard' plugin row
that was missing from the table.
Regenerated skill catalogs:
- ran website/scripts/generate-skill-docs.py to refresh all 163 per-skill
pages and both reference catalogs (skills-catalog.md,
optional-skills-catalog.md). This adds the entries that were genuinely
missing — productivity/teams-meeting-pipeline (bundled),
optional/finance/* (entire category — 7 skills:
3-statement-model, comps-analysis, dcf-model, excel-author, lbo-model,
merger-model, pptx-author), creative/hyperframes,
creative/kanban-video-orchestrator, devops/watchers,
productivity/shop-app, research/searxng-search,
apple/macos-computer-use — and rewrites every other per-skill page from
the current SKILL.md. Most diffs are tiny (one line of refreshed
metadata).
Validation:
- 'npm run build' succeeded.
- Broken-link count moved 146 -> 155 — the +9 are zh-Hans translation
shells that lag every newly-added skill page (pre-existing pattern).
No regressions on any en/ page.
feat: add supports_parallel_tool_calls for MCP servers (#26825)
Port from openai/codex#17667: MCP servers can now opt-in to parallel
tool execution by setting supports_parallel_tool_calls: true in their
config. This allows tools from the same server to run concurrently
within a single tool-call batch, matching the behavior already available
for built-in tools like web_search and read_file.
Previously all MCP tools were forced sequential because they weren't in
the _PARALLEL_SAFE_TOOLS set. Now _should_parallelize_tool_batch checks
is_mcp_tool_parallel_safe() which looks up the server's config flag.
Config example:
mcp_servers:
docs:
command: "docs-server"
supports_parallel_tool_calls: true
Changes:
- tools/mcp_tool.py: Track parallel-safe servers in _parallel_safe_servers
set, populated during register_mcp_servers(). Add is_mcp_tool_parallel_safe()
public API.
- run_agent.py: Add _is_mcp_tool_parallel_safe() lazy-import wrapper. Update
_should_parallelize_tool_batch() to check MCP tools against server config.
- 11 new tests covering the feature end-to-end.
- Updated MCP docs and config reference.
feat(models): remote model catalog manifest for OpenRouter + Nous Portal (#16033)
OpenRouter and Nous Portal curated picker lists now resolve via a JSON
manifest served by the docs site, falling back to the in-repo snapshot
when unreachable. Lets us update model lists without shipping a release.
Live URL: https://hermes-agent.nousresearch.com/docs/api/model-catalog.json
(source at website/static/api/model-catalog.json; auto-deploys via the
existing deploy-site.yml GitHub Pages pipeline on every merge to main).
Schema (v1) carries id + optional description + free-form metadata at
manifest, provider, and model levels. Pricing and context length stay
live-fetched via existing machinery (/v1/models endpoints, models.dev).
Config (new model_catalog section, default enabled):
model_catalog.url master manifest URL
model_catalog.ttl_hours disk cache TTL (default 24h)
model_catalog.providers.<name>.url optional per-provider override
Fetch pipeline: in-process cache -> disk cache (fresh < TTL) -> HTTP
fetch -> disk-cache-on-failure fallback -> in-repo snapshot as last
resort. Never raises to callers; at worst returns the bundled list.
Changes:
- website/static/api/model-catalog.json initial manifest (35 OR + 31 Nous)
- scripts/build_model_catalog.py regenerator from in-repo lists
- hermes_cli/model_catalog.py fetch + validate + cache module
- hermes_cli/models.py fetch_openrouter_models() +
new get_curated_nous_model_ids()
- hermes_cli/main.py, hermes_cli/auth.py Nous flows use the helper
- hermes_cli/config.py model_catalog defaults
- website/docs/reference/model-catalog.md + sidebars.ts
- tests/hermes_cli/test_model_catalog.py 21 tests (validation, fetch
success/failure, accessors,
disabled, overrides, integration)
feat(skills): add osint-investigation optional skill (closes #355) (#26729)
* feat(skills): add osint-investigation optional skill (closes #355)
Phase-1 public-records OSINT investigation framework adapted from
ShinMegamiBoson/OpenPlanter (MIT). Lives in optional-skills/research/.
Six data-source wiki entries (FEC, SEC EDGAR, USAspending, Senate LD,
OFAC SDN, ICIJ Offshore Leaks), each following the 9-section template:
summary, access, schema, coverage, cross-reference keys, data quality,
acquisition, legal, references.
Six stdlib-only acquisition scripts that emit normalized CSV, plus three
analysis scripts:
- entity_resolution.py — three-tier match (exact / fuzzy / token overlap)
with explicit confidence per row
- timing_analysis.py — permutation test for donation/contract timing
correlation, joins through cross-links
- build_findings.py — assembles structured findings.json with
evidence chains pointing back to source rows
Validation: full pipeline runs end-to-end on synthetic fixtures. Entity
resolution found 24 cross-matches with 0 false positives on a 5-row /
4-row test set. Timing analysis on 5 donations clustered near 3 awards
returned p=0.000, effect size 2.41 SD. Findings JSON correctly tags
HIGH-severity timing pattern. All 9 scripts pass --help and py_compile.
Docs site page auto-generated by website/scripts/generate-skill-docs.py;
sidebar + catalog entries updated by the same generator.
* fix(osint-investigation): live API fixes from end-to-end sweep
Live-tested the skill on a real public-citizen query and found three bugs
the synthetic E2E missed. All three are now fixed and re-verified.
1. FEC fetch hung on contributor name searches.
The combination of two_year_transaction_period + sort=date +
contributor_name puts the OpenFEC query plan on a slow path that the
upstream gateway times out (25s+). Switched to min_date/max_date with no
explicit sort. Renamed --candidate to --contributor (the original name
was misleading: FEC searches by donor, not by candidate; --candidate is
kept as a deprecated alias). Added --state filter for narrowing.
2. ICIJ Offshore Leaks reconcile endpoint returns 404.
ICIJ removed the Open Refine reconciliation API. Rewrote
fetch_icij_offshore.py to download the official bulk CSV ZIP (~70 MB,
public, no auth) and search it locally. Cached under
$HERMES_OSINT_CACHE/icij/ (default ~/.cache/hermes-osint/icij/) for
30 days, --force-refresh to refetch. Verified live: 'PUTIN' query
returns 5 Panama Papers officer matches in 0.5s after first download.
3. SEC EDGAR silently returned 0 when the company-name resolver matched
an individual Form 3/4/5 filer (insider trading disclosures).
Now surfaces 'Resolved company X → CIK Y (Z)' on stderr, prints a
filing-type histogram when the type filter wipes results, and
explicitly warns when the matched CIK appears to be an individual
filer rather than a corporate registrant.
Bonus: _http.py was retrying 429 responses with exponential backoff plus
honoring (often-missing) Retry-After headers, which compounded into
multi-second hangs per page when the upstream key was over quota.
Changed to fail-fast on 429 with a clear, actionable error showing the
upstream's quota message. Verified: 0.3s fast-fail vs the previous 60s
hang on DEMO_KEY rate-limit exhaustion.
Updated SKILL.md, fec.md, and icij-offshore.md to match the new CLI
flags and ICIJ bulk-cache flow. Regenerated the docusaurus page via
website/scripts/generate-skill-docs.py.
Live sweep results across all 6 sources for 'Dillon Rolnick, New York':
- OFAC SDN: 0 matches ✓ (correctly not sanctioned)
- USAspending: 0 matches ✓ (correctly not a federal contractor)
- Senate LDA: 0 matches ✓ (correctly not a lobbying client)
- SEC EDGAR: warns it resolved to 'Rolnick Michael' (CIK 0001845264)
who is an individual Form 3 filer, not a corporate registrant
- ICIJ: 0 matches ✓ (correctly not in any offshore leak)
- FEC: rate-limited (DEMO_KEY); fails fast with clear quota message
* feat(osint-investigation): expand to 12 sources covering identity, property, courts, archives, news
Phase-2 expansion per Teknium feedback that the original 6-source skill
(federal financial/regulatory only) wasn't a complete OSINT toolkit. Adds
6 more sources covering the major omissions a real investigation would
reach for first.
New sources (6 fetch scripts + 6 wiki entries):
1. NYC ACRIS — Real property records (deeds, mortgages, liens) via the
city's Socrata API. Search by party name or property address. Joins
Parties to Master to populate doc_type, dates, borough, and amount.
Coverage: 5 NYC boroughs, ~70M party records, 1966-present.
2. OpenCorporates — Global corporate registry covering 130+ jurisdictions
(~200M companies). Free API token at
https://opencorporates.com/api_accounts/new raises the rate limit;
HTML fallback works without one (limited fields).
3. CourtListener (Free Law Project) — federal + state court opinions
(~10M back to colonial era) + PACER dockets via RECAP. Anonymous v4
search works; COURTLISTENER_TOKEN raises rate limits.
4. Wayback Machine CDX — historical web captures (~900B+). Used both for
surveillance-of-record (when did this site change?) and as a
content-recovery layer when other sources point to dead URLs.
5. Wikipedia + Wikidata — narrative bio + structured facts. Wikipedia
OpenSearch for article matching, REST summary for extracts, Wikidata
Action API (wbgetentities) for claims. Avoids the SPARQL Query
Service which is aggressively rate-limited.
6. GDELT 2.0 DOC API — global news monitoring in 100+ languages,
~2015-present. Auto-retries with 6s backoff on the standard
1-req-per-5-sec throttle.
Other changes in this commit:
- SEC EDGAR no longer raises SystemExit when the company-name resolver
finds no CIK; writes an empty CSV with header so the rest of a
pipeline can keep moving and the warning is just on stderr.
- _http.py User-Agent updated per Wikimedia policy: includes app name,
version, and a 'set HERMES_OSINT_UA to identify yourself' instruction.
- SKILL.md workflow now groups sources into two clusters (federal
financial vs identity/property/courts/archives/news) with bash
examples for each. 'When to use this skill' lists the broader set of
investigation patterns the expanded sources unlock.
Live sweep results on 'Dillon Rolnick, New York' across all 12 sources:
ofac ✓ 0 (correctly clean)
icij ✓ 0 (correctly not in any leak)
usaspending ✓ 0 (correctly not a federal contractor)
senate_lda ✓ 0 (correctly not a lobbying client)
sec_edgar ✓ 0, warns: resolved to 'Rolnick Michael' (CIK 0001845264),
individual Form 3 filer, NOT a corporate registrant
fec — rate-limited (DEMO_KEY exhausted), fails fast with
clear quota message
nyc_acris ✓ 200 records named Rolnick across NYC; 48 records at
571 Hudson (the property the web identifies as his)
opencorporates ✓ 0 (no API token configured; HTML fallback)
courtlistener ✓ 0 for 'Dillon Rolnick'; 20 for 'Rolnick' generally;
5 for 'Microsoft' sanity check
wayback ✓ 30 captures of nousresearch.com from 2011-present
wikipedia ✓ 0 (correctly not notable enough); Bill Gates sanity
returns full structured facts (occupation, employer,
DOB, place of birth, country)
gdelt ✓ 0 for 'Dillon Rolnick'; 5 for 'Nous Research'
All 17 scripts compile clean and pass --help. Synthetic analysis pipeline
regression still passes (entity_resolution 30 matches, timing p=0.000,
findings 2).
* feat(osint-investigation): remove FEC; DEMO_KEY rate-limits make it unreliable
The FEC fetcher consistently failed the live sweep because the OpenFEC
DEMO_KEY tier (40 calls/hour) exhausts on a single investigation, and
the upstream returns slow-path query plans for unindexed contributor-name
searches that the gateway times out. Without a real API key it's not
usable; with one the user has to sign up at api.data.gov first. That's
too much setup friction for a skill that should work out of the box.
Removed:
- scripts/fetch_fec.py
- references/sources/fec.md
Updated:
- SKILL.md frontmatter description + tags
- 'When NOT to use' now points users at https://www.fec.gov/data/ for
federal donations
- entity_resolution example switched from donor↔contractor to
lobbying-client↔contractor (Senate LDA + USAspending pair)
- timing_analysis example switched to lobbying-filings vs awards
- 8 wiki entries had their 'FEC ↔ ...' cross-reference bullets removed
11 sources remain (5 federal financial + 6 identity/property/courts/
archives/news). All scripts compile, pass --help, and the synthetic
analysis pipeline still passes on the new lobbying-shaped regression
fixture (30 matches, p=0.000 on tight clustering, 2 findings).
docs: align kanban readiness docs and smoke tests
Salvages #28199 by @bensargotest-sys. Aligns Kanban docs with current
tool registration: dispatcher-spawned task workers get task tools,
profiles that explicitly enable the kanban toolset get orchestrator
routing tools (kanban_list, kanban_unblock). Corrects failure-limit
text to current default of 2. Hardens the e2e subprocess script to
resolve repo root and use the spawnable default assignee. Updates the
diagnostics severity fixture to assert error below the critical
threshold.