Files
iris_x_hermes/docs/15-hermes-reference.md
ARIA 7a6d922d12
CI / Kotlin tests (android host + desktop) (push) Successful in 8m5s
CI / Gateway plugin tests (push) Successful in 9m47s
Add QR pairing (terminal QR, in-app scanner, iris://pair deep link)
2026-08-22 22:43:13 +02:00

7.5 KiB

15 — hermes-agent Source Reference Map

A cheat-sheet of the exact hermes-agent files/lines to read for each integration point. Paths are relative to hermes-agent/ (the read-only reference). This lets a coder jump straight to the right code instead of re-deriving the architecture.

⚠️ Read-only. We install our plugin into ~/.hermes/plugins/iris; we never edit these files.

Plugin / platform registration

What Where
How to add a platform (Plugin Path) gateway/platforms/ADDING_A_PLATFORM.md
Canonical plugin-platform example plugins/platforms/irc/adapter.py (esp. register(ctx) at :953, _env_enablement :677, _standalone_send :743, _get_scoped_secret :42)
ntfy plugin example (push-ish) plugins/platforms/ntfy/adapter.py, plugin.yaml
register_platform() (PluginContext) hermes_cli/plugins.py:2774
PlatformEntry dataclass (all fields) gateway/platform_registry.py:63
Platform enum gateway/config.py
Plugin discovery (PluginManager) hermes_cli/plugins.py

Base adapter contract

What Where
BasePlatformAdapter (ABC) gateway/platforms/base.py:2890
MessageEvent (inbound) gateway/platforms/base.py:2300
MessageType gateway/platforms/base.py:2278
SendResult gateway/platforms/base.py:2466
build_source(...) (SessionSource) gateway/platforms/base.py:7047
handle_message(event) gateway/platforms/base.py:5981
send() / edit_message() / delete_message() base.py:3920 / 3976 / 4005
send_typing / stop_typing base.py:4298 / 4307
Media send: send_image/video/document/voice/animation/image_file/multiple_images base.py:4396 / 4632 / 4659 / 4486 / 4415 / 4339 / 7834(tg)
extract_images / extract_media / extract_local_files base.py:4439 / 4884 / 5020
Media cache helpers: cache_image/audio/video/document_from_bytes base.py:854 / 1005 / 1122 / 2126
Inbound media size: get_inbound_media_max_bytes / validate_inbound_media_size base.py:758 / 779
Media delivery security: validate_media_delivery_path + roots/recency/denied base.py:1684 / 1312-1480
Interactive: send_slash_confirm / send_clarify / send_private_notice base.py:4169 / 4204 / 4278
create_handoff_thread base.py:3949
Streaming hooks: supports_draft_streaming / send_draft / render_message_event / format_tool_event base.py:3215 / 3274 / 3316 / 3337
Scoped secret read pattern (profile-safe) plugins/platforms/irc/adapter.py:42
Scoped lock (profile-safe bind) gateway/status.py (acquire_scoped_lock)

Streaming (legacy callback path — what the main gateway uses)

What Where
GatewayStreamConsumer (the sink) gateway/stream_consumer.py:156
on_delta / on_commentary / on_segment_break / finish stream_consumer.py:611 / 518 / 514 / 623
Consumer run() loop (edit cadence) stream_consumer.py:781
Structured events (ACP-only, NOT main gateway) gateway/stream_events.py, gateway/stream_dispatch.py:40
Callback wiring (agent → consumer) gateway/run.py:5642-5704 (tool_progress_callback, stream_delta_callback, interim_assistant_callback, status_callback, event_callback)
send_progress_messages (tool progress → send) gateway/run.py:4603
Progress metadata gateway/run.py:28089

Reasoning display

What Where
Reasoning prepended to final response gateway/run.py:20089-20127
show_reasoning / reasoning_style defaults + per-platform gateway/display_config.py:33-181
resolve_display_setting() gateway/display_config.py:187
last_reasoning in agent result gateway/run.py:6471
Think-tag filtering in consumer stream_consumer.py:175-185, 627+

Display settings (tool progress, interim, streaming, etc.)

What Where
All overrideable display keys + defaults gateway/display_config.py:33 (tool_progress, show_reasoning, reasoning_style, tool_preview_length, streaming, interim_assistant_messages, long_running_notifications, cleanup_progress, live_status)
Per-platform tiers gateway/display_config.py:81-181

Slash commands

What Where
COMMAND_REGISTRY / CommandDef (all commands) hermes_cli/commands.py:144+
GATEWAY_KNOWN_COMMANDS / is_gateway_known_command / resolve_command hermes_cli/commands.py
Gateway command dispatch (alias, access, hooks) gateway/run.py:16974-17099
send_model_picker / send_choice_picker (Telegram ref) plugins/platforms/telegram/adapter.py:6350 / 6424
Picker invocation from gateway gateway/slash_commands.py:1859, 2157, 3622-3657
Button-callback id conventions (cl:, appr:, sc:) gateway/platforms/ADDING_A_PLATFORM.md (Interactive UX)

Cron delivery

What Where
Resolve a delivery target (platform:chat_id[:thread_id]) cron/scheduler.py:2148 (_resolve_single_delivery_target)
_resolve_delivery_targets / routing tokens (all) cron/scheduler.py:2296 / 2278
cron_deliver_env_var handling (home channel) cron/scheduler.py:1903+
deliver param normalization cron/scheduler.py:2251
send_message tool target resolution (resolve_send_target, prepare_send_message_platforms) tools/send_message_tool.py
parse_target_ref_fn usage tools/send_message_tool.py (_parse_target_ref)
Cron mirror delivery (default off) cron/scheduler.py:1520
cronjob tool schema (deliver description) tools/cronjob_tools.py

Search (FTS5)

What Where
Session store (SQLite + FTS5) hermes_state.py
Search implementation hermes_state_search.py
Schema hermes_state_schema.py

Config / env / profiles

What Where
get_hermes_home() / display_hermes_home() (profile-safe paths) hermes_constants.py
DEFAULT_CONFIG / OPTIONAL_ENV_VARS hermes_cli/config.py
Gateway config load (load_gateway_config, _apply_env_overrides) gateway/config.py
Profile override (_apply_profile_override) hermes_cli/main.py
Secret scope (multiplex fail-closed) agent/secret_scope.py
PII redaction agent/redact.py

Dependencies (confirm zero new deps)

What Where
websockets==15.0.1 (core) pyproject.toml:111
httpx[socks]==0.28.1 (core) pyproject.toml:44
aiohttp (messaging extra, NOT core) pyproject.toml:185
Dependency pinning policy pyproject.toml:19-39, root AGENTS.md

Testing

What Where
Hermetic test runner (use this, not bare pytest) scripts/run_tests.sh
_isolate_hermes_home fixture tests/conftest.py
Example platform tests tests/gateway/test_*.py (e.g. test_google_chat.py, test_line_plugin.py)
Stream-event tests (dispatcher) tests/gateway/test_stream_events.py

Existing desktop app (for reference only — we do NOT reuse its backend)

What Where
Electron desktop app apps/desktop/ (its own AGENTS.md, DESIGN.md)
Shared JSON-RPC WS client (tui_gateway protocol) apps/shared/src/json-rpc-gateway.ts
tui_gateway WS transport (mobile-client-ready) tui_gateway/ws.py
tui_gateway method catalog tui_gateway/server.py

Note: the existing desktop app talks to the tui_gateway backend (hermes serve), a different process from the messaging gateway. Our apps talk to the messaging gateway via our own plugin + protocol. We borrow naming conventions only.