7.5 KiB
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_gatewaybackend (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.