mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-05 18:27:04 +08:00
Compare commits
14 Commits
kilocode-p
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4bb5cca31d | ||
|
|
601e5f1d57 | ||
|
|
2333b7a7ec | ||
|
|
3f023450dd | ||
|
|
69aeba0df7 | ||
|
|
10f89d7b72 | ||
|
|
93869b48ab | ||
|
|
ef94aa201f | ||
|
|
c77a6e3faa | ||
|
|
1d938832a7 | ||
|
|
f7918c9349 | ||
|
|
a1bed18194 | ||
|
|
d12f59aa53 | ||
|
|
2bc82bb504 |
44
.github/dependabot.yml
vendored
Normal file
44
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# Dependabot configuration for hermes-agent.
|
||||
#
|
||||
# Deliberately scoped to github-actions only.
|
||||
#
|
||||
# We do NOT enable Dependabot for pip / npm / any source-dependency ecosystem
|
||||
# because we pin source dependencies exactly (uv.lock, package-lock.json) as
|
||||
# part of our supply-chain posture. Automatic version-bump PRs against those
|
||||
# pins would undermine the strategy — pins are moved deliberately, after
|
||||
# review, not on a schedule.
|
||||
#
|
||||
# github-actions is the exception: action pins (we use full commit SHAs per
|
||||
# supply-chain policy) must be updated when upstream actions publish
|
||||
# patches — usually themselves security fixes. Dependabot opens a PR with
|
||||
# the new SHA and release notes; we review and merge like any other PR.
|
||||
#
|
||||
# Security-update PRs for source dependencies (opened ONLY when a CVE is
|
||||
# published affecting a currently-pinned version) are enabled separately
|
||||
# via the repo's Dependabot security updates setting
|
||||
# (Settings → Code security → Dependabot → Dependabot security updates).
|
||||
# Those are CVE-only, not schedule-driven, and do not conflict with our
|
||||
# pinning strategy — they fire when a pinned version becomes known-bad,
|
||||
# which is exactly when we want to move the pin.
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
commit-message:
|
||||
prefix: "chore(actions)"
|
||||
include: "scope"
|
||||
groups:
|
||||
# Batch routine action bumps into one PR per week to reduce noise.
|
||||
# Security updates still open individually and bypass grouping.
|
||||
actions-minor-patch:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
2
.github/workflows/deploy-site.yml
vendored
2
.github/workflows/deploy-site.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
cache: npm
|
||||
cache-dependency-path: website/package-lock.json
|
||||
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
|
||||
2
.github/workflows/docs-site-checks.yml
vendored
2
.github/workflows/docs-site-checks.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
run: npm ci
|
||||
working-directory: website
|
||||
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
|
||||
67
.github/workflows/osv-scanner.yml
vendored
Normal file
67
.github/workflows/osv-scanner.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: OSV-Scanner
|
||||
|
||||
# Scans lockfiles (uv.lock, package-lock.json) against the OSV vulnerability
|
||||
# database. Runs on every PR that touches a lockfile and on a weekly schedule
|
||||
# against main.
|
||||
#
|
||||
# This is detection-only — OSV-Scanner does NOT open PRs or modify pins.
|
||||
# It reports known CVEs in currently-pinned dependency versions so we can
|
||||
# decide when and how to patch on our own schedule. Our pinning strategy
|
||||
# (full SHA / exact version) is preserved; only the notification signal
|
||||
# is added.
|
||||
#
|
||||
# Complements the existing supply-chain-audit.yml workflow (which scans
|
||||
# for malicious code patterns in PR diffs) by covering the orthogonal
|
||||
# "currently-pinned dep became known-vulnerable" case.
|
||||
#
|
||||
# Uses Google's officially-recommended reusable workflow, pinned by SHA.
|
||||
# Findings land in the repo's Security tab (Code Scanning > OSV-Scanner).
|
||||
# fail-on-vuln is disabled so the job does not block merges on pre-existing
|
||||
# vulnerabilities in pinned deps that we may need to patch deliberately.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'uv.lock'
|
||||
- 'pyproject.toml'
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'ui-tui/package.json'
|
||||
- 'ui-tui/package-lock.json'
|
||||
- 'website/package.json'
|
||||
- 'website/package-lock.json'
|
||||
- '.github/workflows/osv-scanner.yml'
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'uv.lock'
|
||||
- 'pyproject.toml'
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'ui-tui/package-lock.json'
|
||||
- 'website/package-lock.json'
|
||||
schedule:
|
||||
# Weekly scan against main — catches CVEs published after merge for
|
||||
# deps that haven't changed since.
|
||||
- cron: '0 9 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
# Required by the reusable workflow to upload SARIF to the Security tab.
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
name: Scan lockfiles
|
||||
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@c51854704019a247608d928f370c98740469d4b5 # v2.3.5
|
||||
with:
|
||||
# Scan explicit lockfiles rather than recursing, so we only look at
|
||||
# the three sources of truth and skip vendored / test / worktree dirs.
|
||||
scan-args: |-
|
||||
--lockfile=uv.lock
|
||||
--lockfile=ui-tui/package-lock.json
|
||||
--lockfile=website/package-lock.json
|
||||
fail-on-vuln: false
|
||||
4
.github/workflows/skills-index.yml
vendored
4
.github/workflows/skills-index.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
cache: npm
|
||||
cache-dependency-path: website/package-lock.json
|
||||
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
|
||||
@@ -509,7 +509,20 @@ class TeamsAdapter(BasePlatformAdapter):
|
||||
|
||||
for chunk in chunks:
|
||||
try:
|
||||
result = await self._app.send(chat_id, chunk)
|
||||
if reply_to and reply_to.isdigit() and reply_to != "0":
|
||||
try:
|
||||
result = await self._app.reply(chat_id, reply_to, chunk)
|
||||
except Exception as reply_err:
|
||||
# Group chats 400 on threaded sends; the Teams SDK
|
||||
# doesn't expose typed HTTP errors, so fall back on
|
||||
# any exception and log for diagnostics.
|
||||
logger.debug(
|
||||
"Teams reply() failed, falling back to flat send: %s",
|
||||
reply_err,
|
||||
)
|
||||
result = await self._app.send(chat_id, chunk)
|
||||
else:
|
||||
result = await self._app.send(chat_id, chunk)
|
||||
last_message_id = getattr(result, "id", None)
|
||||
except Exception as e:
|
||||
return SendResult(success=False, error=str(e), retryable=True)
|
||||
|
||||
@@ -32,6 +32,9 @@ def _ensure_teams_mock():
|
||||
microsoft_teams_api_activities_invoke_adaptive_card = types.ModuleType(
|
||||
"microsoft_teams.api.activities.invoke.adaptive_card"
|
||||
)
|
||||
microsoft_teams_common = types.ModuleType("microsoft_teams.common")
|
||||
microsoft_teams_common_http = types.ModuleType("microsoft_teams.common.http")
|
||||
microsoft_teams_common_http_client = types.ModuleType("microsoft_teams.common.http.client")
|
||||
microsoft_teams_api_models = types.ModuleType("microsoft_teams.api.models")
|
||||
microsoft_teams_api_models_adaptive_card = types.ModuleType("microsoft_teams.api.models.adaptive_card")
|
||||
microsoft_teams_api_models_invoke_response = types.ModuleType("microsoft_teams.api.models.invoke_response")
|
||||
@@ -76,6 +79,7 @@ def _ensure_teams_mock():
|
||||
|
||||
microsoft_teams_apps.App = MockApp
|
||||
microsoft_teams_apps.ActivityContext = MagicMock
|
||||
microsoft_teams_common_http_client.ClientOptions = MagicMock
|
||||
|
||||
# MessageActivity mock
|
||||
microsoft_teams_api.MessageActivity = MagicMock
|
||||
@@ -143,6 +147,9 @@ def _ensure_teams_mock():
|
||||
"microsoft_teams.api.activities.typing": microsoft_teams_api_activities_typing,
|
||||
"microsoft_teams.api.activities.invoke": microsoft_teams_api_activities_invoke,
|
||||
"microsoft_teams.api.activities.invoke.adaptive_card": microsoft_teams_api_activities_invoke_adaptive_card,
|
||||
"microsoft_teams.common": microsoft_teams_common,
|
||||
"microsoft_teams.common.http": microsoft_teams_common_http,
|
||||
"microsoft_teams.common.http.client": microsoft_teams_common_http_client,
|
||||
"microsoft_teams.api.models": microsoft_teams_api_models,
|
||||
"microsoft_teams.api.models.adaptive_card": microsoft_teams_api_models_adaptive_card,
|
||||
"microsoft_teams.api.models.invoke_response": microsoft_teams_api_models_invoke_response,
|
||||
@@ -162,6 +169,13 @@ _teams_mod = load_plugin_adapter("teams")
|
||||
_teams_mod.TEAMS_SDK_AVAILABLE = True
|
||||
_teams_mod.AIOHTTP_AVAILABLE = True
|
||||
|
||||
# Ensure SDK symbols that were None (import failed on Python <3.12) are
|
||||
# replaced with the mocked versions so runtime calls don't silently no-op.
|
||||
import sys as _sys
|
||||
_mt = _sys.modules.get("microsoft_teams.api.activities.typing")
|
||||
if _mt and _teams_mod.TypingActivityInput is None:
|
||||
_teams_mod.TypingActivityInput = _mt.TypingActivityInput
|
||||
|
||||
TeamsAdapter = _teams_mod.TeamsAdapter
|
||||
check_requirements = _teams_mod.check_requirements
|
||||
check_teams_requirements = _teams_mod.check_teams_requirements
|
||||
|
||||
@@ -37,7 +37,7 @@ def test_project_env_is_sanitized_before_loading(tmp_path, monkeypatch):
|
||||
home = tmp_path / "hermes"
|
||||
project_env = tmp_path / ".env"
|
||||
project_env.write_text(
|
||||
"TELEGRAM_BOT_TOKEN=8356550917:AAGGEkzg06Hrc3Hjb3Sa1jkGVDOdU_lYy2Q"
|
||||
"TELEGRAM_BOT_TOKEN=0123456789:test"
|
||||
"ANTHROPIC_API_KEY=sk-ant-test123\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
@@ -48,7 +48,7 @@ def test_project_env_is_sanitized_before_loading(tmp_path, monkeypatch):
|
||||
loaded = load_hermes_dotenv(hermes_home=home, project_env=project_env)
|
||||
|
||||
assert loaded == [project_env]
|
||||
assert os.getenv("TELEGRAM_BOT_TOKEN") == "8356550917:AAGGEkzg06Hrc3Hjb3Sa1jkGVDOdU_lYy2Q"
|
||||
assert os.getenv("TELEGRAM_BOT_TOKEN") == "0123456789:test"
|
||||
assert os.getenv("ANTHROPIC_API_KEY") == "sk-ant-test123"
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ def test_load_env_sanitizes_concatenated_lines():
|
||||
"""
|
||||
from hermes_cli.config import load_env
|
||||
|
||||
token = "8356550917:AAGGEkzg06Hrc3Hjb3Sa1jkGVDOdU_lYy2Q"
|
||||
token = "0123456789:test"
|
||||
# Simulate concatenated line: TOKEN=xxx followed immediately by another key
|
||||
corrupted = f"TELEGRAM_BOT_TOKEN={token}ANTHROPIC_API_KEY=sk-ant-test123\n"
|
||||
|
||||
@@ -67,7 +67,7 @@ def test_env_loader_sanitizes_before_dotenv():
|
||||
"""Verify env_loader._sanitize_env_file_if_needed fixes corrupted files."""
|
||||
from hermes_cli.env_loader import _sanitize_env_file_if_needed
|
||||
|
||||
token = "8356550917:AAGGEkzg06Hrc3Hjb3Sa1jkGVDOdU_lYy2Q"
|
||||
token = "0123456789:test"
|
||||
corrupted = f"TELEGRAM_BOT_TOKEN={token}ANTHROPIC_API_KEY=sk-ant-test\n"
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
|
||||
@@ -505,9 +505,11 @@ def test_ws_events_rejects_when_token_required(tmp_path, monkeypatch):
|
||||
kb.init_db()
|
||||
|
||||
# Stub web_server so _check_ws_token has a token to compare against.
|
||||
import hermes_cli
|
||||
import types
|
||||
stub = types.SimpleNamespace(_SESSION_TOKEN="secret-xyz")
|
||||
monkeypatch.setitem(sys.modules, "hermes_cli.web_server", stub)
|
||||
monkeypatch.setattr(hermes_cli, "web_server", stub, raising=False)
|
||||
|
||||
app = FastAPI()
|
||||
app.include_router(_load_plugin_router(), prefix="/api/plugins/kanban")
|
||||
|
||||
@@ -204,7 +204,7 @@ Only after the base chat works. Pick what you need:
|
||||
hermes gateway setup # Interactive platform configuration
|
||||
```
|
||||
|
||||
Connect [Telegram](/docs/user-guide/messaging/telegram), [Discord](/docs/user-guide/messaging/discord), [Slack](/docs/user-guide/messaging/slack), [WhatsApp](/docs/user-guide/messaging/whatsapp), [Signal](/docs/user-guide/messaging/signal), [Email](/docs/user-guide/messaging/email), or [Home Assistant](/docs/user-guide/messaging/homeassistant).
|
||||
Connect [Telegram](/docs/user-guide/messaging/telegram), [Discord](/docs/user-guide/messaging/discord), [Slack](/docs/user-guide/messaging/slack), [WhatsApp](/docs/user-guide/messaging/whatsapp), [Signal](/docs/user-guide/messaging/signal), [Email](/docs/user-guide/messaging/email), or [Home Assistant](/docs/user-guide/messaging/homeassistant), or [Microsoft Teams](/docs/user-guide/messaging/teams).
|
||||
|
||||
### Automation and tools
|
||||
|
||||
@@ -307,7 +307,7 @@ That sequence gets you from "broken vibes" back to a known state fast.
|
||||
|
||||
- **[CLI Guide](../user-guide/cli.md)** — Master the terminal interface
|
||||
- **[Configuration](../user-guide/configuration.md)** — Customize your setup
|
||||
- **[Messaging Gateway](../user-guide/messaging/index.md)** — Connect Telegram, Discord, Slack, WhatsApp, Signal, Email, or Home Assistant
|
||||
- **[Messaging Gateway](../user-guide/messaging/index.md)** — Connect Telegram, Discord, Slack, WhatsApp, Signal, Email, Home Assistant, Teams, and more
|
||||
- **[Tools & Toolsets](../user-guide/features/tools.md)** — Explore available capabilities
|
||||
- **[AI Providers](../integrations/providers.md)** — Full provider list and setup details
|
||||
- **[Skills System](../user-guide/features/skills.md)** — Reusable workflows and knowledge
|
||||
|
||||
@@ -107,7 +107,7 @@ Compare against the latest release at the [GitHub releases page](https://github.
|
||||
|
||||
### Updating from Messaging Platforms
|
||||
|
||||
You can also update directly from Telegram, Discord, Slack, or WhatsApp by sending:
|
||||
You can also update directly from Telegram, Discord, Slack, WhatsApp, or Teams by sending:
|
||||
|
||||
```
|
||||
/update
|
||||
|
||||
@@ -28,7 +28,7 @@ It's not a coding copilot tethered to an IDE or a chatbot wrapper around a singl
|
||||
| 📖 **[Quickstart Tutorial](/docs/getting-started/quickstart)** | Your first conversation and key features to try |
|
||||
| 🗺️ **[Learning Path](/docs/getting-started/learning-path)** | Find the right docs for your experience level |
|
||||
| ⚙️ **[Configuration](/docs/user-guide/configuration)** | Config file, providers, models, and options |
|
||||
| 💬 **[Messaging Gateway](/docs/user-guide/messaging)** | Set up Telegram, Discord, Slack, or WhatsApp |
|
||||
| 💬 **[Messaging Gateway](/docs/user-guide/messaging)** | Set up Telegram, Discord, Slack, WhatsApp, Teams, or more |
|
||||
| 🔧 **[Tools & Toolsets](/docs/user-guide/features/tools)** | 68 built-in tools and how to configure them |
|
||||
| 🧠 **[Memory System](/docs/user-guide/features/memory)** | Persistent memory that grows across sessions |
|
||||
| 📚 **[Skills System](/docs/user-guide/features/skills)** | Procedural memory the agent creates and reuses |
|
||||
@@ -47,7 +47,7 @@ It's not a coding copilot tethered to an IDE or a chatbot wrapper around a singl
|
||||
|
||||
- **A closed learning loop** — Agent-curated memory with periodic nudges, autonomous skill creation, skill self-improvement during use, FTS5 cross-session recall with LLM summarization, and [Honcho](https://github.com/plastic-labs/honcho) dialectic user modeling
|
||||
- **Runs anywhere, not just your laptop** — 6 terminal backends: local, Docker, SSH, Daytona, Singularity, Modal. Daytona and Modal offer serverless persistence — your environment hibernates when idle, costing nearly nothing
|
||||
- **Lives where you do** — CLI, Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Mattermost, Email, SMS, DingTalk, Feishu, WeCom, BlueBubbles, Home Assistant — 15+ platforms from one gateway
|
||||
- **Lives where you do** — CLI, Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Mattermost, Email, SMS, DingTalk, Feishu, WeCom, BlueBubbles, Home Assistant, Microsoft Teams — 15+ platforms from one gateway
|
||||
- **Built by model trainers** — Created by [Nous Research](https://nousresearch.com), the lab behind Hermes, Nomos, and Psyche. Works with [Nous Portal](https://portal.nousresearch.com), [OpenRouter](https://openrouter.ai), OpenAI, or any endpoint
|
||||
- **Scheduled automations** — Built-in cron with delivery to any platform
|
||||
- **Delegates & parallelizes** — Spawn isolated subagents for parallel workstreams. Programmatic Tool Calling via `execute_code` collapses multi-step pipelines into single inference calls
|
||||
|
||||
@@ -82,7 +82,7 @@ Speech-to-text supports six providers: local faster-whisper (free, runs on-devic
|
||||
|
||||
Hermes runs as a gateway bot on 15+ messaging platforms, all configured through the same `gateway` subsystem:
|
||||
|
||||
- **[Telegram](/docs/user-guide/messaging/telegram)**, **[Discord](/docs/user-guide/messaging/discord)**, **[Slack](/docs/user-guide/messaging/slack)**, **[WhatsApp](/docs/user-guide/messaging/whatsapp)**, **[Signal](/docs/user-guide/messaging/signal)**, **[Matrix](/docs/user-guide/messaging/matrix)**, **[Mattermost](/docs/user-guide/messaging/mattermost)**, **[Email](/docs/user-guide/messaging/email)**, **[SMS](/docs/user-guide/messaging/sms)**, **[DingTalk](/docs/user-guide/messaging/dingtalk)**, **[Feishu/Lark](/docs/user-guide/messaging/feishu)**, **[WeCom](/docs/user-guide/messaging/wecom)**, **[WeCom Callback](/docs/user-guide/messaging/wecom-callback)**, **[Weixin](/docs/user-guide/messaging/weixin)**, **[BlueBubbles](/docs/user-guide/messaging/bluebubbles)**, **[QQ Bot](/docs/user-guide/messaging/qqbot)**, **[Home Assistant](/docs/user-guide/messaging/homeassistant)**, **[Webhooks](/docs/user-guide/messaging/webhooks)**
|
||||
- **[Telegram](/docs/user-guide/messaging/telegram)**, **[Discord](/docs/user-guide/messaging/discord)**, **[Slack](/docs/user-guide/messaging/slack)**, **[WhatsApp](/docs/user-guide/messaging/whatsapp)**, **[Signal](/docs/user-guide/messaging/signal)**, **[Matrix](/docs/user-guide/messaging/matrix)**, **[Mattermost](/docs/user-guide/messaging/mattermost)**, **[Email](/docs/user-guide/messaging/email)**, **[SMS](/docs/user-guide/messaging/sms)**, **[DingTalk](/docs/user-guide/messaging/dingtalk)**, **[Feishu/Lark](/docs/user-guide/messaging/feishu)**, **[WeCom](/docs/user-guide/messaging/wecom)**, **[WeCom Callback](/docs/user-guide/messaging/wecom-callback)**, **[Weixin](/docs/user-guide/messaging/weixin)**, **[BlueBubbles](/docs/user-guide/messaging/bluebubbles)**, **[QQ Bot](/docs/user-guide/messaging/qqbot)**, **[Home Assistant](/docs/user-guide/messaging/homeassistant)**, **[Microsoft Teams](/docs/user-guide/messaging/teams)**, **[Webhooks](/docs/user-guide/messaging/webhooks)**
|
||||
|
||||
See the [Messaging Gateway overview](/docs/user-guide/messaging) for the platform comparison table and setup guide.
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ Commands support prefix matching: typing `/h` resolves to `/help`, `/mod` resolv
|
||||
|
||||
## Messaging slash commands
|
||||
|
||||
The messaging gateway supports the following built-in commands inside Telegram, Discord, Slack, WhatsApp, Signal, Email, and Home Assistant chats:
|
||||
The messaging gateway supports the following built-in commands inside Telegram, Discord, Slack, WhatsApp, Signal, Email, Home Assistant, and Teams chats:
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
|
||||
@@ -103,7 +103,7 @@ For cloud sandboxes such as Modal, Daytona, and Vercel Sandbox, `container_persi
|
||||
| Backend | Where commands run | Isolation | Best for |
|
||||
|---------|-------------------|-----------|----------|
|
||||
| **local** | Your machine directly | None | Development, personal use |
|
||||
| **docker** | Docker container | Full (namespaces, cap-drop) | Safe sandboxing, CI/CD |
|
||||
| **docker** | Single persistent Docker container (shared across session, `/new`, subagents) | Full (namespaces, cap-drop) | Safe sandboxing, CI/CD |
|
||||
| **ssh** | Remote server via SSH | Network boundary | Remote dev, powerful hardware |
|
||||
| **modal** | Modal cloud sandbox | Full (cloud VM) | Ephemeral cloud compute, evals |
|
||||
| **daytona** | Daytona workspace | Full (cloud container) | Managed cloud dev environments |
|
||||
@@ -127,6 +127,8 @@ The agent has the same filesystem access as your user account. Use `hermes tools
|
||||
|
||||
Runs commands inside a Docker container with security hardening (all capabilities dropped, no privilege escalation, PID limits).
|
||||
|
||||
**Single persistent container, not per-command.** Hermes starts ONE long-lived container on first use and routes every terminal, file, and `execute_code` call through `docker exec` into that same container — across sessions, `/new`, `/reset`, and `delegate_task` subagents — for the lifetime of the Hermes process. Working-directory changes, installed packages, and files in `/workspace` carry over from one tool call to the next, just like a local shell. The container is stopped and removed on shutdown. See **Container lifecycle** below for details.
|
||||
|
||||
```yaml
|
||||
terminal:
|
||||
backend: docker
|
||||
|
||||
@@ -9,7 +9,7 @@ description: "Running Hermes Agent in Docker and using Docker as a terminal back
|
||||
There are two distinct ways Docker intersects with Hermes Agent:
|
||||
|
||||
1. **Running Hermes IN Docker** — the agent itself runs inside a container (this page's primary focus)
|
||||
2. **Docker as a terminal backend** — the agent runs on your host but executes commands inside a Docker sandbox (see [Configuration → terminal.backend](./configuration.md))
|
||||
2. **Docker as a terminal backend** — the agent runs on your host but executes every command inside a single, persistent Docker sandbox container that survives across tool calls, `/new`, and subagents for the life of the Hermes process (see [Configuration → Docker Backend](./configuration.md#docker-backend))
|
||||
|
||||
This page covers option 1. The container stores all user data (config, API keys, sessions, skills, memories) in a single directory mounted from the host at `/opt/data`. The image itself is stateless and can be upgraded by pulling a new version without losing any configuration.
|
||||
|
||||
@@ -279,7 +279,7 @@ docker compose up -d
|
||||
|
||||
## Skills and credential files
|
||||
|
||||
When using Docker as the execution environment (not the methods above, but when the agent runs commands inside a Docker sandbox), Hermes automatically bind-mounts the skills directory (`~/.hermes/skills/`) and any credential files declared by skills into the container as read-only volumes. This means skill scripts, templates, and references are available inside the sandbox without manual configuration.
|
||||
When using Docker as the execution environment (not the methods above, but when the agent runs commands inside a Docker sandbox — see [Configuration → Docker Backend](./configuration.md#docker-backend)), Hermes reuses a single long-lived container for all tool calls and automatically bind-mounts the skills directory (`~/.hermes/skills/`) and any credential files declared by skills into that container as read-only volumes. Skill scripts, templates, and references are available inside the sandbox without manual configuration, and because the container persists for the life of the Hermes process, any dependencies you install or files you write stay around for the next tool call.
|
||||
|
||||
The same syncing happens for SSH and Modal backends — skills and credential files are uploaded via rsync or the Modal mount API before each command.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ All three systems are non-blocking — errors in any hook are caught and logged,
|
||||
|
||||
## Gateway Event Hooks
|
||||
|
||||
Gateway hooks fire automatically during gateway operation (Telegram, Discord, Slack, WhatsApp) without blocking the main agent pipeline.
|
||||
Gateway hooks fire automatically during gateway operation (Telegram, Discord, Slack, WhatsApp, Teams) without blocking the main agent pipeline.
|
||||
|
||||
### Creating a Hook
|
||||
|
||||
@@ -346,7 +346,7 @@ An earlier version of Hermes shipped this as a built-in hook and silently spawne
|
||||
5. Errors in any handler are caught and logged — a broken hook never crashes the agent
|
||||
|
||||
:::info
|
||||
Gateway hooks only fire in the **gateway** (Telegram, Discord, Slack, WhatsApp). The CLI does not load gateway hooks. For hooks that work everywhere, use [plugin hooks](#plugin-hooks).
|
||||
Gateway hooks only fire in the **gateway** (Telegram, Discord, Slack, WhatsApp, Teams). The CLI does not load gateway hooks. For hooks that work everywhere, use [plugin hooks](#plugin-hooks).
|
||||
:::
|
||||
|
||||
## Plugin Hooks
|
||||
|
||||
@@ -84,6 +84,10 @@ terminal:
|
||||
docker_image: python:3.11-slim
|
||||
```
|
||||
|
||||
**One persistent container, shared across the whole process.** Hermes starts a single long-lived container on first use (`docker run -d ... sleep 2h`) and routes every terminal, file, and `execute_code` call through `docker exec` into that same container. Working-directory changes, installed packages, environment tweaks, and files written to `/workspace` all carry over from one tool call to the next, across `/new`, `/reset`, and `delegate_task` subagents, for the lifetime of the Hermes process. The container is stopped and removed on shutdown.
|
||||
|
||||
This means the Docker backend behaves like a persistent sandbox VM, not a fresh container per command. If you `pip install foo` once, it's there for the rest of the session. If you `cd /workspace/project`, subsequent `ls` calls see that directory. See [Configuration → Docker Backend](../configuration.md#docker-backend) for the full lifecycle details and the `container_persistent` flag that controls whether `/workspace` and `/root` survive across Hermes restarts.
|
||||
|
||||
### SSH Backend
|
||||
|
||||
Recommended for security — agent can't modify its own code:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
title: "Messaging Gateway"
|
||||
description: "Chat with Hermes from Telegram, Discord, Slack, WhatsApp, Signal, SMS, Email, Home Assistant, Mattermost, Matrix, DingTalk, Yuanbao, Webhooks, or any OpenAI-compatible frontend via the API server — architecture and setup overview"
|
||||
description: "Chat with Hermes from Telegram, Discord, Slack, WhatsApp, Signal, SMS, Email, Home Assistant, Mattermost, Matrix, DingTalk, Yuanbao, Microsoft Teams, Webhooks, or any OpenAI-compatible frontend via the API server — architecture and setup overview"
|
||||
---
|
||||
|
||||
# Messaging Gateway
|
||||
|
||||
Chat with Hermes from Telegram, Discord, Slack, WhatsApp, Signal, SMS, Email, Home Assistant, Mattermost, Matrix, DingTalk, Feishu/Lark, WeCom, Weixin, BlueBubbles (iMessage), QQ, Yuanbao, or your browser. The gateway is a single background process that connects to all your configured platforms, handles sessions, runs cron jobs, and delivers voice messages.
|
||||
Chat with Hermes from Telegram, Discord, Slack, WhatsApp, Signal, SMS, Email, Home Assistant, Mattermost, Matrix, DingTalk, Feishu/Lark, WeCom, Weixin, BlueBubbles (iMessage), QQ, Yuanbao, Microsoft Teams, or your browser. The gateway is a single background process that connects to all your configured platforms, handles sessions, runs cron jobs, and delivers voice messages.
|
||||
|
||||
For the full voice feature set — including CLI microphone mode, spoken replies in messaging, and Discord voice-channel conversations — see [Voice Mode](/docs/user-guide/features/voice-mode) and [Use Voice Mode with Hermes](/docs/guides/use-voice-mode-with-hermes).
|
||||
|
||||
@@ -32,6 +32,7 @@ For the full voice feature set — including CLI microphone mode, spoken replies
|
||||
| BlueBubbles | — | ✅ | ✅ | — | ✅ | ✅ | — |
|
||||
| QQ | ✅ | ✅ | ✅ | — | — | ✅ | — |
|
||||
| Yuanbao | ✅ | ✅ | ✅ | — | — | ✅ | ✅ |
|
||||
| Microsoft Teams | — | ✅ | — | ✅ | — | ✅ | — |
|
||||
|
||||
**Voice** = TTS audio replies and/or voice message transcription. **Images** = send/receive images. **Files** = send/receive file attachments. **Threads** = threaded conversations. **Reactions** = emoji reactions on messages. **Typing** = typing indicator while processing. **Streaming** = progressive message updates via editing.
|
||||
|
||||
@@ -59,8 +60,9 @@ flowchart TB
|
||||
bb[BlueBubbles]
|
||||
qq[QQ]
|
||||
yb[Yuanbao]
|
||||
api["API Server<br/>(OpenAI-compatible)"]
|
||||
wh[Webhooks]
|
||||
ms[Microsoft Teams]
|
||||
api["API Server<br/>(OpenAI-compatible)"]
|
||||
wh[Webhooks]
|
||||
end
|
||||
|
||||
store["Session store<br/>per chat"]
|
||||
@@ -86,6 +88,7 @@ flowchart TB
|
||||
bb --> store
|
||||
qq --> store
|
||||
yb --> store
|
||||
ms --> store
|
||||
api --> store
|
||||
wh --> store
|
||||
store --> agent
|
||||
@@ -189,6 +192,7 @@ DINGTALK_ALLOWED_USERS=user-id-1
|
||||
FEISHU_ALLOWED_USERS=ou_xxxxxxxx,ou_yyyyyyyy
|
||||
WECOM_ALLOWED_USERS=user-id-1,user-id-2
|
||||
WECOM_CALLBACK_ALLOWED_USERS=user-id-1,user-id-2
|
||||
TEAMS_ALLOWED_USERS=aad-object-id-1,aad-object-id-2
|
||||
|
||||
# Or allow
|
||||
GATEWAY_ALLOWED_USERS=123456789,987654321
|
||||
@@ -393,6 +397,7 @@ Each platform has its own toolset:
|
||||
| BlueBubbles | `hermes-bluebubbles` | Full tools including terminal |
|
||||
| QQBot | `hermes-qqbot` | Full tools including terminal |
|
||||
| Yuanbao | `hermes-yuanbao` | Full tools including terminal |
|
||||
| Microsoft Teams | `hermes-teams` | Full tools including terminal |
|
||||
| API Server | `hermes` (default) | Full tools including terminal |
|
||||
| Webhooks | `hermes-webhook` | Full tools including terminal |
|
||||
|
||||
@@ -416,5 +421,6 @@ Each platform has its own toolset:
|
||||
- [BlueBubbles Setup (iMessage)](bluebubbles.md)
|
||||
- [QQBot Setup](qqbot.md)
|
||||
- [Yuanbao Setup](yuanbao.md)
|
||||
- [Microsoft Teams Setup](teams.md)
|
||||
- [Open WebUI + API Server](open-webui.md)
|
||||
- [Webhooks](webhooks.md)
|
||||
@@ -10,7 +10,7 @@ Hermes Agent automatically saves every conversation as a session. Sessions enabl
|
||||
|
||||
## How Sessions Work
|
||||
|
||||
Every conversation — whether from the CLI, Telegram, Discord, Slack, WhatsApp, Signal, Matrix, or any other messaging platform — is stored as a session with full message history. Sessions are tracked in two complementary systems:
|
||||
Every conversation — whether from the CLI, Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Teams, or any other messaging platform — is stored as a session with full message history. Sessions are tracked in two complementary systems:
|
||||
|
||||
1. **SQLite database** (`~/.hermes/state.db`) — structured session metadata with FTS5 full-text search
|
||||
2. **JSONL transcripts** (`~/.hermes/sessions/`) — raw conversation transcripts including tool calls (gateway)
|
||||
|
||||
@@ -165,7 +165,7 @@ hermes gateway status Check status
|
||||
hermes gateway setup Configure platforms
|
||||
```
|
||||
|
||||
Supported platforms: Telegram, Discord, Slack, WhatsApp, Signal, Email, SMS, Matrix, Mattermost, Home Assistant, DingTalk, Feishu, WeCom, BlueBubbles (iMessage), Weixin (WeChat), API Server, Webhooks. Open WebUI connects via the API Server adapter.
|
||||
Supported platforms: Telegram, Discord, Slack, WhatsApp, Signal, Email, SMS, Matrix, Mattermost, Home Assistant, DingTalk, Feishu, WeCom, BlueBubbles (iMessage), Weixin (WeChat), Microsoft Teams, API Server, Webhooks. Open WebUI connects via the API Server adapter.
|
||||
|
||||
Platform docs: https://hermes-agent.nousresearch.com/docs/user-guide/messaging/
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ const sidebars: SidebarsConfig = {
|
||||
'user-guide/messaging/bluebubbles',
|
||||
'user-guide/messaging/qqbot',
|
||||
'user-guide/messaging/yuanbao',
|
||||
'user-guide/messaging/teams',
|
||||
'user-guide/messaging/open-webui',
|
||||
'user-guide/messaging/webhooks',
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user