Hermes VK Platform Plugin
VK Messenger / VK community bot platform adapter for Hermes Agent.
This plugin lets Hermes receive messages from VK community messages via VK Group Long Poll and reply through the VK messages.send API.
Features
- Inbound VK
message_newandmessage_editevents through Group Long Poll. - Outbound replies with
messages.send. - Direct messages and VK group conversations (
peer_id = 2000000000 + chat_id). - Safe allowlist controls for VK users, peers, and peer+user policies.
- TTL dedupe for repeated Long Poll
message_newevents after reconnect. - Optional cron/home-channel delivery through
VK_HOME_CHANNEL. - Message editing for Hermes tool-progress bubbles through
messages.edit. - Inbound media handling for photos, documents, voice messages, audio, video messages, and direct video files with bounded downloads.
- Outbound media upload for image files, documents, voice files, and videos.
- If VK
video.saverejects an MP4 with auth/permission errors under group-token auth, video delivery falls back to sending the MP4 as a document attachment. - Markdown-style Hermes output is converted to VK-readable plain text because the regular VK
messages.sendAPI has no Telegram-likeparse_modefor Markdown/HTML. - Optional per-channel prompts and skill bindings through Hermes config.
- Optional Telegram-style message-reaction acks (
VK_REACTIONS_ENABLED): a progress reaction while the agent works, then 👍/👎 on completion. - No mandatory third-party Python dependency; the adapter uses Python stdlib for VK HTTP calls.
Documentation
docs/development.md— plugin structure, runtime flow, testing, and release checks.docs/project-lanes.md— virtual project lanes, pinning, sorting, importer, cron lane routing, and accessibility rules.docs/update-guide.md— agent-facing checklist for updating the plugin against a new Hermes version.docs/troubleshooting.md— common setup and runtime failures.
Requirements
- Hermes Agent with plugin support.
- A VK community/group.
- Community messages enabled in VK.
- VK Group Long Poll API enabled for
message_new,message_editandmessage_event(callback buttons). - A VK community access token with
messagespermission.
Hermes registration compatibility
Requires Hermes Agent >=0.21.3. PyPI 0.19.0 is not supported.
The tested released baseline is GitHub tag
v2026.9.14,
commit 345cd2b057a452236de401d3534b8502a7465e8d, whose package version is
0.21.3. This is a supported baseline, not a claim about the earliest commit
containing every API. Unreleased main is not required.
GitHub release tags and PyPI packages may differ: at verification, PyPI still
published 0.19.0. Check the installed version and installation channel before
upgrading; do not migrate a production deployment just to try the plugin.
Version 0.2.2 declares the minimum in its manifest and rejects missing
MessageEvent.allow_gateway_control or BasePlatformAdapter._event_session_key
before registering VK, including on hosts that ignore the manifest requirement.
Hermes Agent v2026.9.14 includes the PlatformEntry.parse_target_ref_fn
contract used for project-lane outbound targets. Plugin version 0.2.1 also
supports registration when only that field is absent and the remaining host
API matches: all base
registration, configuration, access-control, and direct-peer send callbacks
remain registered. The plugin logs a compatibility warning in that case.
Lane-qualified outbound targets such as 2000000042:lane:alpha require a
Hermes build with parse_target_ref_fn. On a build without it, use a direct
numeric peer target or update Hermes. Do not redirect a lane target by guessing
or removing its lane suffix.
Registration compatibility is not a full VK end-to-end check. After an install or Hermes update, use this smoke checklist:
hermes plugins list --enabledshowsvk-platformenabled.hermes gateway statusshows VK configured/connected after the gateway is started with valid credentials.- Fresh gateway logs contain no VK plugin load or registration exception.
- If the compatibility warning appears, test only a direct numeric peer target; update Hermes before using project-lane outbound targets.
These checks prove plugin loading and connection state, not VK delivery. A full end-to-end check additionally requires an authorized live VK message and reply.
Install
From GitHub:
hermes plugins install web3blind/hermes-vk-platform --enable
Or with a full URL:
hermes plugins install https://github.com/web3blind/hermes-vk-platform.git --enable
Then configure and restart the gateway:
hermes gateway setup
hermes gateway restart
If you prefer manual setup, edit ~/.hermes/.env as shown below.
VK setup checklist
- Create or choose a VK community.
- Open community settings and enable community messages.
- Enable bot capabilities for conversations:
- allow messages from users;
- allow adding the community bot to chats/conversations;
- enable the option usually named like chat bot, bot can work in conversations, or messages in conversations.
- In VK's Russian UI this is often under Управление сообществом → Сообщения → Настройки для бота → Возможности ботов: set Возможности ботов to enabled and enable Разрешать добавлять сообщество в чаты.
- Enable Long Poll API for the community.
- Enable the
message_new,message_edit, andmessage_eventevent types.message_eventdelivers callback button clicks: Allow Once / Deny, slash-command confirmations, clarification choices (including Other), and inline project selection, pagination, pin/unpin and command buttons. Without it, buttons can appear but never reach Hermes; message-history fallback cannot recover these clicks. The persistent menu next to the message input remains a text keyboard. Typed commands and replies remain supported. After updating the plugin, restart the gateway and request a fresh keyboard: buttons in older messages keep their original action type. - Create a community token with
messagespermission. - If using group conversations, allow adding the community bot to chats and add it to the target chat.
- Configure allowlists before starting the gateway.
VK documentation entry points:
- Community tokens: https://dev.vk.com/en/api/access-token/community-token
- Bots Long Poll API: https://dev.vk.com/en/api/bots-long-poll/getting-started
- Messages API: https://dev.vk.com/en/method/messages.send
Configuration
Required environment variables
Store these in ~/.hermes/.env:
VK_GROUP_TOKEN=vk1.a.your-community-token
VK_GROUP_ID=123456789
VK_GROUP_ID is the numeric community id without a leading minus sign.
Multiple profiles in one gateway
Version 0.2.3 reads VK credentials, allowlists and environment settings through Hermes' active profile secret scope. A missing scoped value does not fall back to the default profile's process environment. Set credentials and access controls for each independently connected profile; a profile without its own VK connection settings must not inherit another profile's community token. Profile-specific configuration remains a valid fallback within that profile.
The legacy YAML bridge keeps values on the current profile's configuration instead of writing them to process-global environment variables when a profile scope is active. Both dictionary and object configuration forms are supported. Outside a profile scope, the existing single-profile environment behavior is preserved.
On connection, the adapter also invokes native handler factories registered by
other Hermes plugins through register_platform_handler. This enables that
existing extension surface; VK itself still registers no tools, hooks or
middleware.
Recommended allowlist
Do not run a personal Hermes agent open to all VK users. Configure at least one allowlist:
# Allow specific VK user ids:
VK_ALLOWED_USERS=123456,789012
# And/or allow specific VK peers/chats:
VK_ALLOWED_PEERS=123456,2000000001
By default the access policy is backward-compatible:
allowed user OR allowed peer
That means VK_ALLOWED_PEERS=2000000001 allows every participant of that VK chat to talk to Hermes. This can be useful for a small private chat whose membership you fully control, but it is risky for larger or public group conversations.
For stricter access, choose an explicit policy:
# Backward-compatible default: allowed user OR allowed peer.
VK_ACCESS_POLICY=any
# Only users from VK_ALLOWED_USERS may talk to Hermes.
VK_ACCESS_POLICY=user_only
# Only peers/chats from VK_ALLOWED_PEERS may talk to Hermes.
# Warning: in group chats, this allows every participant of the chat.
VK_ACCESS_POLICY=peer_only
# Sender must be in VK_ALLOWED_USERS AND chat must be in VK_ALLOWED_PEERS.
VK_ACCESS_POLICY=peer_and_user
You can also restrict particular chats to particular users:
# Format: peer:user|user;peer:user
VK_ALLOWED_USERS_BY_PEER=2000000001:123456|789012;2000000002:123456
VK_ALLOWED_USERS_BY_PEER takes precedence for the listed peer. If a peer is listed there, only the listed users are accepted in that peer.
For VK group conversations, peer id is:
peer_id = 2000000000 + chat_id
Example: VK chat id 1 becomes peer id 2000000001.
Global group invocation gate (optional)
Off by default. To require an invocation in all VK group conversations handled
by this adapter, add non-secret settings to config.yaml:
vk:
require_mention: true
mention_patterns:
- '(?<![\w@])(?:ИИЛада|курсор)\b'
Patterns are Python regular expressions, compiled case-insensitively with Unicode
word boundaries. This example accepts КУРСОР: помоги and ИИЛада?, not
суперкурсор, курсорный, ИИЛада2, ИИЛада_тест or @курсор.
Use YAML single quotes to preserve backslashes. Invalid patterns are ignored with
a warning; a malformed list does not disable the gate. No custom names are
hardcoded into the plugin.
The same keys are accepted under gateway.vk or platforms.vk.extra (the latter
overrides the shorthand). Use one configuration location to avoid ambiguity.
DMs are unaffected. A direct reply whose raw VK reply_message.from_id identifies
this bot community, or an explicit @club<ID> / [club<ID>|label] mention, also
invokes it. Quoted/forwarded text and attachment summaries never supply a trigger.
If a raw update lacks reply identity, it fails closed rather than fetching history
to discover a possible invocation.
This gate is not authorization: existing sender/peer ACLs run first, including
per-peer overrides. It adds no global owner-only rule and changes no other chat's
membership permissions. Restrict a particular chat with allowed_users_by_peer,
not a global user-only policy when other chats must retain their current access.
Non-control slash commands also require a name/native mention or a direct reply
to this bot (for example, reply /help to its message). /stop remains available
without a name; /approve and /deny bypass addressing only while the exact routed
session has a blocking approval. Existing button controls remain available.
Callback nonce, peer, prompt and
request checks remain in force. The core's exact bare-word approval replies (such
as yes / no) are promoted to slash controls only when the exact routed session
has a blocking approval; the core still authorizes and resolves that request.
An exact routed-session pending clarification
accepts an unaddressed text answer; the checked route and answer are preserved
without API enrichment or project selection. Merely being busy is not an invocation:
unaddressed conversation is dropped before downloads, reactions or agent dispatch.
Unsafe testing mode
Only for isolated test communities:
VK_ALLOW_ALL_USERS=true
Do not use this for a personal Hermes instance with tools enabled.
Optional settings
# Default VK peer for cron/home delivery:
VK_HOME_CHANNEL=2000000001
# Download all inbound attachments to Hermes cache, not only file-like direct URLs:
VK_DOWNLOAD_ATTACHMENTS=false
# Maximum inbound attachment download size in bytes. Default: 25 MiB.
VK_MAX_ATTACHMENT_BYTES=26214400
# In-memory duplicate event TTL in seconds. Default: 1800.
VK_DEDUPE_TTL_SECONDS=1800
# Recurring message-history fallback. Default: enabled.
# Set this ENV value explicitly to false to disable the extra VK API reads.
VK_FALLBACK_POLL_ENABLED=true
# Poll timing and per-peer conversation-message-id batch. Defaults shown.
# Runtime minimum interval: 5 seconds. Batch size is clamped to 1..100.
VK_FALLBACK_POLL_INTERVAL_SECONDS=15
VK_FALLBACK_POLL_BATCH_SIZE=25
# Optional user token for video metadata fallback. Not needed for normal chat usage.
VK_USER_TOKEN=
Message-history fallback polling
Fallback polling is enabled by default. In addition to Group Long Poll, the
adapter makes recurring messages.getByConversationMessageId reads for peers
present in VK_ALLOWED_PEERS, the configured home channel, or project-lane
configuration. This recovers ordinary user messages that Long Poll missed; it
does not recover message_event callback clicks.
To avoid these additional recurring VK reads, set
VK_FALLBACK_POLL_ENABLED=false explicitly in the environment and restart the
gateway. Do not rely on YAML boolean false for this toggle in version 0.2.3.
The runtime currently treats that YAML value as absent and keeps the default
enabled behavior.
Message reactions (👌 → 👍/👎)
Optional Telegram-style processing acks. When enabled, the bot reacts to the incoming message with a "seen, working on it" reaction as soon as processing starts, and swaps it for a final 👍 (success) or 👎 (failure) reaction when the agent finishes. Reactions are cosmetic: API failures never break message flow.
VK_REACTIONS_ENABLED=true
VK identifies reactions by numeric id, not emoji. The default community set:
1=❤️ 2=🔥 3=😂 4=👍 8=😡 10=👌 16=🎉. Defaults: progress 10
(👌 — there is no 👀 in the VK default set), OK 4 (👍), FAIL 8. If your
community rearranged reactions, override any step:
# Defaults shown:
VK_REACTION_PROGRESS=10
VK_REACTION_OK=4
VK_REACTION_FAIL=8
Set a step to 0 to disable it (e.g. VK_REACTION_PROGRESS=0 to only mark
final outcomes). On cancelled/interrupted turns the progress reaction is
removed. Requires the community token to have the messages permission; some
very old API versions do not expose messages.deleteReaction — the adapter
probes support lazily and degrades gracefully.
Optional YAML config
The plugin can also bridge a top-level vk: block from ~/.hermes/config.yaml into the platform config.
vk:
group_id: "123456789"
allowed_users:
- "123456"
allowed_peers:
- "2000000001"
access_policy: "peer_and_user"
allowed_users_by_peer:
"2000000001":
- "123456"
max_attachment_bytes: 26214400
dedupe_ttl_seconds: 1800
home_channel: "2000000001"
channel_prompts:
"2000000001": "This is a trusted VK chat. Keep replies concise."
channel_skill_bindings:
- id: "2000000001"
skills:
- research
Secrets such as group_token are better stored in .env, not config YAML.
Optional VK project lanes
VK community bots do not have Telegram-style topics or bot-managed Messenger folders. If one physical VK chat should host several Hermes project contexts, configure virtual project lanes as a VK plugin feature:
platforms:
vk:
extra:
project_lanes:
enabled: true
chats:
"2000000001":
base_folder: ai-projects
default_skills:
- coding
lanes:
- id: rialo
name: Rialo
description: ретродроп и аналитика проекта Rialo
folder: rialo
skills:
- blockchain-project-research
- coding
aliases:
- rialo
The legacy vk.project_lanes shape is still read for backward compatibility, but new automatic writes and imports use platforms.vk.extra.project_lanes.
Behavior:
- one VK
peer_idremains the physical chat container; - each lane is routed as a Hermes synthetic thread with
thread_id=lane:<id>; - active lane selection is stored per
peer_id + user_id; - the lane transcript is shared inside the synthetic thread, like Telegram topics / Discord threads;
/newwhile a lane is active resets only that lane session;/project search <query>searches configured and chat-created lanes;/project new <name> <skills_csv> <context...>creates a lane immediately when the id is safe and persists it to the approved VK project-lane config path;/project newandНовый проектcreate parseable labeled/free-form lanes immediately, or fall back to a normal Hermes agent turn for ambiguous input;/project edit <id> <what to change...>edits an existing lane immediately when the requested field changes can be parsed safely and persists the updated lane;/project editstarts the same lightweight guided flow for the active lane: parseable field changes are applied immediately, ambiguous text falls back to a normal Hermes agent turn with edit context;/project pinand/project unpinpin or unpin the active lane for that VK chat; pinned lanes stay above session-recency sorting;/invitereturns the current VK chat invite link from the bot usingmessages.getInviteLink(peer_id=<current>, reset=0);Команды//commandsshows a screen-reader-friendly text list of VK chat commands with clickable text-command buttons;/project offreturns that user to the root VK chat context;VK_HOME_CHANNELis not changed by project lanes.
Commands and buttons:
/project show current project/menu
/project list show project list
/project search <query> search configured and chat-created lanes
/project off disable active lane for you in this VK chat
/project <alias-or-id> switch active lane
@alias <text> send one message to a lane without switching
/project new start conversational project creation
/project new <name> <skills_csv> <context...>
fast fallback creation draft
/project edit start editing the active lane
/project edit <id> <what to change...>
fast fallback edit of an existing lane
/project pin pin active project first in this VK chat
/project unpin unpin active project
/invite show the current VK chat invite link
/commands show all VK chat commands
Project-list page navigation uses visible Предыдущая / Следующая text buttons. The hidden payload still carries the exact fallback command such as /project list 2; if VK sends only the visible label, the adapter falls back to saved per-user page state and moves relative to the last shown list page. Lists are ordered as pinned lanes first, then lanes with the newest Hermes synthetic-thread session activity, then lanes without activity in stable config/import order.
The Команды response includes an inline command keyboard with text buttons for copy-hostile commands such as /project list, /project new, /project edit, /project off, and /invite. These buttons deliberately use text actions so screen readers expose the command label and VK sends the same text a user could type manually.
VK keyboard actions useful for this plugin:
text— sends a visible button label as message text and may also carry payload. This is the preferred accessible/default action for project controls.callback— sends a callback event without normal message text. Avoid for core navigation in VK desktop/browser because it can be exposed unreliably or remain stuck as loading.open_link— opens a URL, useful for external resources, not for chat commands.- platform-specific actions such as location/app/payment are not appropriate for the project-lane command menu.
Example fallback draft command:
/project new Rialo blockchain-project-research,coding ретродроп и аналитика проекта Rialo
/project new without arguments and the Новый проект button start a normal Hermes agent-mediated creation flow. The VK adapter only records short-lived pending state and injects a strict project-creation instruction into the next ordinary Hermes turn; it does not directly call a model inside the VK callback path.
Configured/imported lanes live in platforms.vk.extra.project_lanes. Runtime UI state such as active lane, pinned lanes, pending create/edit prompts, editable list-message ids, and delivered-message lane anchors remains in ~/.hermes/vk_project_lanes_state.json. When a user creates or edits a lane from VK and the field changes are deterministic, the adapter writes the lane to the canonical config path automatically, similar to Hermes' topic/thread persistence model, so users do not need to remember a separate export step. If config writing fails, the adapter keeps a state overlay as a fail-safe and logs a warning.
Cron jobs can target a VK project lane with the explicit target form vk:<peer_id>:lane:<lane_id> or by using deliver=origin when the job origin is a VK synthetic thread. Cron-delivered VK messages are remembered by message id, so replying to the cron message routes into that lane even if the user's currently active project in the same physical VK chat is different.
To import existing mappings into a VK chat:
python plugins/platforms/vk/setup_helper.py lanes import --to-peer 2000000001 --from legacy,telegram,discord --telegram-chat-id -1001234567890 --dry-run
python plugins/platforms/vk/setup_helper.py lanes import --to-peer 2000000001 --from legacy,telegram,discord --telegram-chat-id -1001234567890
The importer reads Telegram topics from platforms.telegram.extra.group_topics and dm_topics (optionally filtered by --telegram-chat-id), legacy VK lanes from vk.project_lanes, and Discord thread mapping sections when present. It writes platforms.vk.extra.project_lanes.enabled: true and upserts lanes under chats.<peer>.lanes.
Persistent technical menu
By default, normal text and attachment replies in already eligible VK chats and DMs
attach the persistent Проекты / Новый проект / Команды / Новая сессия keyboard.
Eligibility is unchanged: an allowed peer/user ID, home channel, configured project
peer, or allow_all_users. This is a UI convenience, not an authorization grant.
Explicit project-menu responses retain their existing behavior by default.
To hide this menu in one chat without changing permissions or project routing, merge
these non-secret settings into your existing config.yaml:
platforms:
vk:
extra:
persistent_keyboard_enabled: true # global default; false disables the menu
persistent_keyboard_by_peer:
"2000000042": false # hide only in this example conversation
"123456789": true # optional DM override, even if the global default is false
Per-peer values override the global switch. Missing peer entries inherit it; the
global default is true. Use YAML booleans (true / false), not quoted strings.
Invalid global values fall back to true; invalid overrides are ignored. Numeric
YAML peer keys are accepted, but quoted IDs are recommended. Setting true never
makes an otherwise ineligible peer receive an automatic keyboard or grants access.
Legacy vk / gateway.vk settings are also accepted; canonical
platforms.vk.extra values take precedence.
Disabling applies to every new attachment of this persistent menu, including
project commands, old cmd / new_session button payloads and their replies.
It does not disable typed commands, project lanes, ACL checks, invocation rules,
or inline project lists, command buttons, approvals, confirmations and clarify choices.
No empty keyboard is sent automatically: VK clients may retain a keyboard already
shown before the change. Clearing that existing keyboard is a separate explicit
operator action. Activate configuration changes with your normal gateway restart;
this setting does not modify running gateway state by itself.
Project lists are sorted by latest Hermes thread-session activity for that VK peer. The most recently used project appears first; lanes without sessions stay below in config order.
Usage
Start or restart the Hermes gateway after configuration:
hermes gateway restart
Then send a message to the VK community or an allowed VK chat.
Hermes will create sessions keyed by VK platform, chat type, peer id, and sender id. This keeps different VK chats isolated.
Cron/home delivery
If VK_HOME_CHANNEL is set, cron jobs and messaging deliveries can target VK by platform name where Hermes supports plugin platform delivery.
VK_HOME_CHANNEL=2000000001
VK_HOME_CHANNEL is only the default peer for home/cron/notification delivery.
It is not the per-chat conversation context, and it should not be moved when a
new thematic VK chat is created unless the operator explicitly says to make that
new peer the default Home channel.
When creating a new thematic chat such as "content", "style", or "research":
- Create or choose the new VK conversation.
- Add its peer id to
VK_ALLOWED_PEERSor the relevant peer allowlist. - Add any matching
vk.channel_prompts/vk.channel_skill_bindingsfor that peer if a special context is needed. - Restart the gateway.
- Send a test message in the new chat.
Do not rewrite VK_HOME_CHANNEL as part of that flow unless the user asks to
move Home/default delivery. Keep the existing Home peer stable.
If an agent is asked to "create a content chat", it should confirm whether the request means:
- create/configure a separate allowed VK peer for content work; or
- move the default Home channel to that peer.
The safe default is the first option: create/configure a separate chat and leave Home unchanged.
Troubleshooting
Hermes does not answer
Check:
- Gateway is running:
hermes gateway status. - Plugin is enabled:
hermes plugins list --enabled. VK_GROUP_TOKENandVK_GROUP_IDare set in~/.hermes/.env.- VK Long Poll is enabled and
message_newevents are selected. - The sender or peer is allowlisted.
- Gateway was restarted after changing
.env.
Logs:
grep -i 'VK:' ~/.hermes/logs/gateway.log | tail -80
Unauthorized sender in logs
A log line like this means the adapter deliberately ignored the message:
VK: ignoring unauthorized sender=<user_id> peer=<peer_id>
Add the exact user id to VK_ALLOWED_USERS or the exact peer id to VK_ALLOWED_PEERS, then restart the gateway. If VK_ACCESS_POLICY=peer_and_user, both must match. If the peer is listed in VK_ALLOWED_USERS_BY_PEER, the sender must be listed for that peer.
Group chat peer id confusion
VK group conversation peer ids start at 2000000000.
If VK chat id is 42, use:
VK_ALLOWED_PEERS=2000000042
VK API error 912: This is a chat bot feature
This usually means the VK community exists and the bot may even be present in the chat, but the community is not yet allowed to work as a chat bot in group conversations.
Open the VK community settings and enable the conversation bot settings. VK's UI labels vary, but look for options like:
- Messages / community messages;
- Bot capabilities / Chat bot;
- Bot can work in conversations;
- Allow adding the community to chats/conversations;
- Long Poll API with
message_newenabled.
In VK's Russian UI, the exact path is commonly:
Управление сообществом
→ Сообщения
→ Настройки для бота
→ Возможности ботов
There enable:
- Возможности ботов;
- Разрешать добавлять сообщество в чаты.
If you are using Hermes with browser access to a logged-in VK admin account, Hermes can help navigate this UI and turn the setting on after you explicitly approve that account action. The plugin installer itself does not silently change VK community settings.
After changing VK settings, restart Hermes and test the peer again:
hermes gateway restart
Tool progress creates multiple messages or does not update
This plugin implements edit_message() via VK messages.edit. If progress editing fails, check that VK returned an editable conversation_message_id for sent messages and inspect gateway logs for VK API errors.
Long messages
VK messages are chunked according to the adapter max message length. The default is 4096 characters.
Inbound attachments and responsiveness
Attachment downloads run outside the Long Poll intake path. Each message keeps its original project/session routing, caption and media types. Ordinary messages in the same session wait for earlier attachments to be ready; another project can continue independently. Hermes still owns agent execution and busy/steering behavior.
Downloads use at most three worker slots. Pending delivery is bounded, with reserved room for controls; ordinary overflow receives a retry notice instead of silently disappearing. Completed cache files are published atomically. A failed repeated download cannot truncate or remove a completed file already handed to an agent. Download errors retain the existing URL fallback rather than pretending a partial file is ready.
Approval/clarification controls and callbacks do not wait behind downloads. /stop, /new and /reset cancel earlier queued work in their session; later messages follow the control operation. Controls sent as replies to media do not download that media or treat attachment summaries as command arguments. Disconnect joins download cleanup before releasing worker slots; an outstanding socket read may take up to its network timeout to finish.
Security model
- The adapter enforces its own allowlist before passing messages to Hermes.
VK_ALLOWED_PEERSpermits every participant in the listed group chat unless you useVK_ACCESS_POLICY=peer_and_userorVK_ALLOWED_USERS_BY_PEER.- Repeated Long Poll events are deduplicated in memory by
peer_id + conversation_message_idforVK_DEDUPE_TTL_SECONDS. - Inbound attachment downloads are streamed to cache and capped by
VK_MAX_ATTACHMENT_BYTES. - Tokens are redacted from adapter errors.
VK_ALLOW_ALL_USERS=trueis intentionally treated as unsafe.- Remote image URLs are sent as URLs instead of silently downloading arbitrary remote image data for outbound sends.
- Inbound downloadable attachments are stored under the Hermes cache directory for gateway media processing.
Development
See docs/development.md.
License
MIT. See LICENSE.
VK project lanes accessibility note: /project list must include project names and /project <id> fallback as plain text, not only VK keyboard buttons. Project selection buttons use VK text actions with visible labels, not callback-only actions; some VK desktop/browser clients hide or poorly expose callback/inline keyboards from the accessible tree.