Merge branch 'main' of github.com:NousResearch/hermes-agent into bb/gui
This commit is contained in:
@@ -418,6 +418,31 @@ App-only credentials for the Microsoft Graph REST client used by the upcoming Te
|
||||
| `MSGRAPH_SCOPE` | OAuth2 scope for the client-credentials token request (default: `https://graph.microsoft.com/.default`). |
|
||||
| `MSGRAPH_AUTHORITY_URL` | Microsoft identity platform authority (default: `https://login.microsoftonline.com`). Override only for national/sovereign clouds (e.g. `https://login.microsoftonline.us` for GCC High). |
|
||||
|
||||
### Microsoft Graph Webhook Listener
|
||||
|
||||
Inbound change-notification listener for Graph events (Teams meetings, calendar, chat, etc.). See [Microsoft Graph Webhook Listener](/docs/user-guide/messaging/msgraph-webhook) for setup and security hardening.
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `MSGRAPH_WEBHOOK_ENABLED` | Enable the `msgraph_webhook` gateway platform (`true`/`1`/`yes`). |
|
||||
| `MSGRAPH_WEBHOOK_PORT` | Port the listener binds to (default: `8646`). |
|
||||
| `MSGRAPH_WEBHOOK_CLIENT_STATE` | Shared secret Graph echoes in every notification; compared with `hmac.compare_digest`. Generate with `openssl rand -hex 32`. |
|
||||
| `MSGRAPH_WEBHOOK_ACCEPTED_RESOURCES` | Comma-separated allowlist of Graph resource paths/patterns (e.g. `communications/onlineMeetings,chats/*/messages`). Trailing `*` is prefix-matching. Empty = accept all. |
|
||||
| `MSGRAPH_WEBHOOK_ALLOWED_SOURCE_CIDRS` | Comma-separated CIDR ranges allowed to POST to the listener (e.g. `52.96.0.0/14,52.104.0.0/14`). Empty = allow all (default). Restrict to Microsoft Graph's published egress ranges in production. |
|
||||
|
||||
### Teams Meeting Summary Delivery
|
||||
|
||||
Only used when the [`teams_pipeline` plugin](/docs/user-guide/messaging/msgraph-webhook) is enabled. Settings are also configurable under `platforms.teams.extra` in `config.yaml` — env vars take priority when both are set. See [Microsoft Teams → Meeting Summary Delivery](/docs/user-guide/messaging/teams#meeting-summary-delivery-teams-meeting-pipeline).
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `TEAMS_DELIVERY_MODE` | `graph` or `incoming_webhook`. |
|
||||
| `TEAMS_INCOMING_WEBHOOK_URL` | Teams-generated webhook URL; required when `TEAMS_DELIVERY_MODE=incoming_webhook`. |
|
||||
| `TEAMS_GRAPH_ACCESS_TOKEN` | Pre-acquired delegated access token for Graph delivery. Rarely needed — the writer falls back to the `MSGRAPH_*` app credentials when unset. |
|
||||
| `TEAMS_TEAM_ID` | Target Team ID for channel delivery (`graph` mode). |
|
||||
| `TEAMS_CHANNEL_ID` | Target channel ID (paired with `TEAMS_TEAM_ID`). |
|
||||
| `TEAMS_CHAT_ID` | Target 1:1 or group chat ID (alternative to team+channel for `graph` mode). |
|
||||
|
||||
### Advanced Messaging Tuning
|
||||
|
||||
Advanced per-platform knobs for throttling the outbound message batcher. Most users never need to touch these; defaults are set to respect each platform's rate limits without feeling sluggish.
|
||||
|
||||
@@ -245,6 +245,10 @@ hermes profile import ./work-2026-03-29.tar.gz --name work-restored
|
||||
|
||||
## Distribution commands
|
||||
|
||||
:::tip
|
||||
**New to distributions?** Start with the [Profile Distributions user guide](../user-guide/profile-distributions.md) — it covers the why, when, and how with full examples. The sections below are a dry CLI reference for when you know what you want.
|
||||
:::
|
||||
|
||||
Distributions turn a profile into a shareable, versioned artifact published
|
||||
as a **git repository**. A recipient installs the distribution with a single
|
||||
command and can update it in place later without touching their local
|
||||
|
||||
@@ -20,6 +20,7 @@ If a skill is missing from this list but present in the repo, the catalog is reg
|
||||
| [`apple-reminders`](/docs/user-guide/skills/bundled/apple/apple-apple-reminders) | Apple Reminders via remindctl: add, list, complete. | `apple/apple-reminders` |
|
||||
| [`findmy`](/docs/user-guide/skills/bundled/apple/apple-findmy) | Track Apple devices/AirTags via FindMy.app on macOS. | `apple/findmy` |
|
||||
| [`imessage`](/docs/user-guide/skills/bundled/apple/apple-imessage) | Send and receive iMessages/SMS via the imsg CLI on macOS. | `apple/imessage` |
|
||||
| [`macos-computer-use`](/docs/user-guide/skills/bundled/apple/apple-macos-computer-use) | Drive the macOS desktop in the background via the `computer_use` tool — screenshots, mouse, keyboard, scroll, drag — without stealing the user's cursor or keyboard focus. Works with any tool-capable model. | `apple/macos-computer-use` |
|
||||
|
||||
## autonomous-ai-agents
|
||||
|
||||
|
||||
@@ -99,6 +99,13 @@ Scoped to the Feishu document-comment handler. Drives comment read/write operati
|
||||
| `ha_list_entities` | List Home Assistant entities. Optionally filter by domain (light, switch, climate, sensor, binary_sensor, cover, fan, etc.) or by area name (living room, kitchen, bedroom, etc.). | — |
|
||||
| `ha_list_services` | List available Home Assistant services (actions) for device control. Shows what actions can be performed on each device type and what parameters they accept. Use this to discover how to control devices found via ha_list_entities. | — |
|
||||
|
||||
## `computer_use` toolset
|
||||
|
||||
| Tool | Description | Requires environment |
|
||||
|------|-------------|----------------------|
|
||||
| `computer_use` | Background macOS desktop control via cua-driver — screenshots (SOM / vision / AX), click / drag / scroll / type / key / wait, list_apps, focus_app. Does NOT steal the user's cursor or keyboard focus. Works with any tool-capable model. macOS only. | `cua-driver` on `$PATH` (install via `hermes tools`). |
|
||||
|
||||
|
||||
:::note
|
||||
**Honcho tools** (`honcho_profile`, `honcho_search`, `honcho_context`, `honcho_reasoning`, `honcho_conclude`) are no longer built-in. They are available via the Honcho memory provider plugin at `plugins/memory/honcho/`. See [Memory Providers](../user-guide/features/memory-providers.md) for installation and usage.
|
||||
:::
|
||||
|
||||
@@ -64,6 +64,7 @@ Or in-session:
|
||||
| `feishu_drive` | `feishu_drive_add_comment`, `feishu_drive_list_comments`, `feishu_drive_list_comment_replies`, `feishu_drive_reply_comment` | Feishu/Lark drive comment operations. Scoped to the comment agent; not exposed on `hermes-cli` or other messaging toolsets. |
|
||||
| `file` | `patch`, `read_file`, `search_files`, `write_file` | File reading, writing, searching, and editing. |
|
||||
| `homeassistant` | `ha_call_service`, `ha_get_state`, `ha_list_entities`, `ha_list_services` | Smart home control via Home Assistant. Only available when `HASS_TOKEN` is set. |
|
||||
| `computer_use` | `computer_use` | Background macOS desktop control via cua-driver — does not steal cursor/focus. Works with any tool-capable model. macOS only; requires `cua-driver` on `$PATH`. |
|
||||
| `image_gen` | `image_generate` | Text-to-image generation via FAL.ai (with opt-in OpenAI / xAI backends). |
|
||||
| `memory` | `memory` | Persistent cross-session memory management. |
|
||||
| `messaging` | `send_message` | Send messages to other platforms (Telegram, Discord, etc.) from within a session. |
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
# Computer Use (macOS)
|
||||
|
||||
Hermes Agent can drive your Mac's desktop — clicking, typing, scrolling,
|
||||
dragging — in the **background**. Your cursor doesn't move, keyboard focus
|
||||
doesn't change, and macOS doesn't switch Spaces on you. You and the agent
|
||||
co-work on the same machine.
|
||||
|
||||
Unlike most computer-use integrations, this works with **any tool-capable
|
||||
model** — Claude, GPT, Gemini, or an open model on a local vLLM endpoint.
|
||||
There's no Anthropic-native schema to worry about.
|
||||
|
||||
## How it works
|
||||
|
||||
The `computer_use` toolset speaks MCP over stdio to [`cua-driver`](https://github.com/trycua/cua),
|
||||
a macOS driver that uses SkyLight private SPIs (`SLEventPostToPid`,
|
||||
`SLPSPostEventRecordTo`) and the `_AXObserverAddNotificationAndCheckRemote`
|
||||
accessibility SPI to:
|
||||
|
||||
- Post synthesized events directly to target processes — no HID event tap,
|
||||
no cursor warp.
|
||||
- Flip AppKit active-state without raising windows — no Space switching.
|
||||
- Keep Chromium/Electron accessibility trees alive when windows are
|
||||
occluded.
|
||||
|
||||
That combination is what OpenAI's Codex "background computer-use" ships.
|
||||
cua-driver is the open-source equivalent.
|
||||
|
||||
## Enabling
|
||||
|
||||
1. Run `hermes tools`, pick `🖱️ Computer Use (macOS)` → `cua-driver (background)`.
|
||||
2. The setup runs the upstream installer:
|
||||
`curl -fsSL https://raw.githubusercontent.com/trycua/cua/main/libs/cua-driver/scripts/install.sh`.
|
||||
3. Grant macOS permissions when prompted:
|
||||
- **System Settings → Privacy & Security → Accessibility** → allow the
|
||||
terminal (or Hermes app).
|
||||
- **System Settings → Privacy & Security → Screen Recording** → allow
|
||||
the same.
|
||||
4. Start a session with the toolset enabled:
|
||||
```
|
||||
hermes -t computer_use chat
|
||||
```
|
||||
or add `computer_use` to your enabled toolsets in `~/.hermes/config.yaml`.
|
||||
|
||||
## Quick example
|
||||
|
||||
User prompt: *"Find my latest email from Stripe and summarise what they want me to do."*
|
||||
|
||||
The agent's plan:
|
||||
|
||||
1. `computer_use(action="capture", mode="som", app="Mail")` — gets a
|
||||
screenshot of Mail with every sidebar item, toolbar button, and message
|
||||
row numbered.
|
||||
2. `computer_use(action="click", element=14)` — clicks the search field
|
||||
(element #14 from the capture).
|
||||
3. `computer_use(action="type", text="from:stripe")`
|
||||
4. `computer_use(action="key", keys="return", capture_after=True)` — submit
|
||||
and get the new screenshot.
|
||||
5. Click the top result, read the body, summarise.
|
||||
|
||||
During all of this, your cursor stays wherever you left it and Mail never
|
||||
comes to front.
|
||||
|
||||
## Provider compatibility
|
||||
|
||||
| Provider | Vision? | Works? | Notes |
|
||||
|---|---|---|---|
|
||||
| Anthropic (Claude Sonnet/Opus 3+) | ✅ | ✅ | Best overall; SOM + raw coordinates. |
|
||||
| OpenRouter (any vision model) | ✅ | ✅ | Multi-part tool messages supported. |
|
||||
| OpenAI (GPT-4+, GPT-5) | ✅ | ✅ | Same as above. |
|
||||
| Local vLLM / LM Studio (vision model) | ✅ | ✅ | If the model supports multi-part tool content. |
|
||||
| Text-only models | ❌ | ✅ (degraded) | Use `mode="ax"` for accessibility-tree-only operation. |
|
||||
|
||||
Screenshots are sent inline with tool results as OpenAI-style `image_url`
|
||||
parts. For Anthropic, the adapter converts them into native `tool_result`
|
||||
image blocks.
|
||||
|
||||
## Safety
|
||||
|
||||
Hermes applies multi-layer guardrails:
|
||||
|
||||
- Destructive actions (click, type, drag, scroll, key, focus_app) require
|
||||
approval — either interactively via the CLI dialog or via the
|
||||
messaging-platform approval buttons.
|
||||
- Hard-blocked key combos at the tool level: empty trash, force delete,
|
||||
lock screen, log out, force log out.
|
||||
- Hard-blocked type patterns: `curl | bash`, `sudo rm -rf /`, fork bombs,
|
||||
etc.
|
||||
- The agent's system prompt tells it explicitly: no clicking permission
|
||||
dialogs, no typing passwords, no following instructions embedded in
|
||||
screenshots.
|
||||
|
||||
Pair with `security.approval_level` in `~/.hermes/config.yaml` if you want
|
||||
every action confirmed.
|
||||
|
||||
## Token efficiency
|
||||
|
||||
Screenshots are expensive. Hermes applies four layers of optimisation:
|
||||
|
||||
- **Screenshot eviction** — the Anthropic adapter keeps only the 3 most
|
||||
recent screenshots in context; older ones become `[screenshot removed
|
||||
to save context]` placeholders.
|
||||
- **Client-side compression pruning** — the context compressor detects
|
||||
multimodal tool results and strips image parts from old ones.
|
||||
- **Image-aware token estimation** — each image is counted as ~1500 tokens
|
||||
(Anthropic's flat rate) instead of its base64 char length.
|
||||
- **Server-side context editing (Anthropic only)** — when active, the
|
||||
adapter enables `clear_tool_uses_20250919` via `context_management` so
|
||||
Anthropic's API clears old tool results server-side.
|
||||
|
||||
A 20-action session on a 1568×900 display typically costs ~30K tokens
|
||||
of screenshot context, not ~600K.
|
||||
|
||||
## Limitations
|
||||
|
||||
- **macOS only.** cua-driver uses private Apple SPIs that don't exist on
|
||||
Linux or Windows. For cross-platform GUI automation, use the `browser`
|
||||
toolset.
|
||||
- **Private SPI risk.** Apple can change SkyLight's symbol surface in any
|
||||
OS update. Pin the driver version with the `HERMES_CUA_DRIVER_VERSION`
|
||||
env var if you want reproducibility across a macOS bump.
|
||||
- **Performance.** Background mode is slower than foreground —
|
||||
SkyLight-routed events take ~5-20ms vs direct HID posting. Not
|
||||
noticeable for agent-speed clicking; noticeable if you try to record a
|
||||
speed-run.
|
||||
- **No keyboard password entry.** `type` has hard-block patterns on
|
||||
command-shell payloads; for passwords, use the system's autofill.
|
||||
|
||||
## Configuration
|
||||
|
||||
Override the driver binary path (tests / CI):
|
||||
|
||||
```
|
||||
HERMES_CUA_DRIVER_CMD=/opt/homebrew/bin/cua-driver
|
||||
HERMES_CUA_DRIVER_VERSION=0.5.0 # optional pin
|
||||
```
|
||||
|
||||
Swap the backend entirely (for testing):
|
||||
|
||||
```
|
||||
HERMES_COMPUTER_USE_BACKEND=noop # records calls, no side effects
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**`computer_use backend unavailable: cua-driver is not installed`** — Run
|
||||
`hermes tools` and enable Computer Use.
|
||||
|
||||
**Clicks seem to have no effect** — Capture and verify. A modal you
|
||||
didn't see may be blocking input. Dismiss it with `escape` or the close
|
||||
button.
|
||||
|
||||
**Element indices are stale** — SOM indices are only valid until the
|
||||
next `capture`. Re-capture after any state-changing action.
|
||||
|
||||
**"blocked pattern in type text"** — The text you tried to `type`
|
||||
matches the dangerous-shell-pattern list. Break the command up or
|
||||
reconsider.
|
||||
|
||||
## See also
|
||||
|
||||
- [Universal skill: `macos-computer-use`](https://github.com/NousResearch/hermes-agent/blob/main/skills/apple/macos-computer-use/SKILL.md)
|
||||
- [cua-driver source (trycua/cua)](https://github.com/trycua/cua)
|
||||
- [Browser automation](./browser-use.md) for cross-platform web tasks.
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
sidebar_position: 23
|
||||
title: "Microsoft Graph Webhook Listener"
|
||||
description: "Receive Microsoft Graph change notifications (meetings, calendar, chat, etc.) in Hermes"
|
||||
---
|
||||
|
||||
# Microsoft Graph Webhook Listener
|
||||
|
||||
The `msgraph_webhook` gateway platform is an inbound event listener. It's how Hermes receives **change notifications** from Microsoft Graph — "a Teams meeting ended," "a new message landed in this chat," "this calendar event was updated." Different from the `teams` platform (which is a chat bot users type to) — this one is M365 telling Hermes something happened, not a person.
|
||||
|
||||
Right now the primary consumer is the Teams meeting summary pipeline: Graph notifies when a meeting produces a transcript, the pipeline fetches it, and Hermes posts a summary back into Teams. Other Graph resources (`/chats/.../messages`, `/users/.../events`) use the same listener — the pipeline consumers land with their own PRs.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Microsoft Graph application credentials — [Register a Microsoft Graph Application](/docs/guides/microsoft-graph-app-registration)
|
||||
- A **public HTTPS URL** that Microsoft Graph can reach (Graph does not call private endpoints). A dev tunnel works for testing; production needs a real domain with a valid certificate.
|
||||
- A strong shared secret to use as the `clientState` value. Generate with `openssl rand -hex 32` and put it in `~/.hermes/.env` as `MSGRAPH_WEBHOOK_CLIENT_STATE`.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Minimum `~/.hermes/config.yaml`:
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
msgraph_webhook:
|
||||
enabled: true
|
||||
extra:
|
||||
port: 8646
|
||||
client_state: "replace-with-a-strong-secret"
|
||||
accepted_resources:
|
||||
- "communications/onlineMeetings"
|
||||
```
|
||||
|
||||
Or via env vars in `~/.hermes/.env` (auto-merged on startup):
|
||||
|
||||
```bash
|
||||
MSGRAPH_WEBHOOK_ENABLED=true
|
||||
MSGRAPH_WEBHOOK_PORT=8646
|
||||
MSGRAPH_WEBHOOK_CLIENT_STATE=<generate-with-openssl-rand-hex-32>
|
||||
MSGRAPH_WEBHOOK_ACCEPTED_RESOURCES=communications/onlineMeetings
|
||||
```
|
||||
|
||||
Start the gateway: `hermes gateway run`. The listener exposes:
|
||||
|
||||
- `POST /msgraph/webhook` — change notifications from Graph
|
||||
- `GET /msgraph/webhook?validationToken=...` — Graph subscription validation handshake
|
||||
- `GET /health` — readiness probe with accepted/duplicate counters
|
||||
|
||||
Expose the listener publicly (reverse proxy, dev tunnel, ingress). Your notification URL for Graph subscriptions is your public HTTPS origin followed by `/msgraph/webhook`:
|
||||
|
||||
```
|
||||
https://ops.example.com/msgraph/webhook
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings go under `platforms.msgraph_webhook.extra`:
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| `host` | `0.0.0.0` | Bind address for the HTTP listener. |
|
||||
| `port` | `8646` | Bind port. |
|
||||
| `webhook_path` | `/msgraph/webhook` | URL path Graph POSTs to. |
|
||||
| `health_path` | `/health` | Readiness endpoint. |
|
||||
| `client_state` | — | Shared secret Graph echoes in every notification. Compared with `hmac.compare_digest` — generate with `openssl rand -hex 32`. |
|
||||
| `accepted_resources` | `[]` (accept all) | Allowlist of Graph resource paths/patterns. Trailing `*` acts as prefix match. Leading `/` is tolerated. Example: `["communications/onlineMeetings", "chats/*/messages"]`. |
|
||||
| `max_seen_receipts` | `5000` | Dedupe cache size for notification IDs. Oldest entries evicted when the cap is hit. |
|
||||
| `allowed_source_cidrs` | `[]` (allow all) | Optional source-IP allowlist. See below. |
|
||||
|
||||
Each setting also has an equivalent env var (`MSGRAPH_WEBHOOK_*`) that merges into the config at gateway startup — see the [environment variables reference](/docs/reference/environment-variables#microsoft-graph-teams-meetings).
|
||||
|
||||
## Security Hardening
|
||||
|
||||
### clientState is the primary auth check
|
||||
|
||||
Every Graph notification includes the `clientState` string your subscription registered with. The listener rejects any notification whose `clientState` doesn't match, using timing-safe comparison. This is Microsoft's documented mechanism — treat the value as a strong shared secret.
|
||||
|
||||
If `client_state` is unset, the listener accepts every well-formed POST. **Don't run without it in production.**
|
||||
|
||||
### Source-IP allowlisting (production deployments)
|
||||
|
||||
For production, restrict the listener to Microsoft's published Graph webhook source IP ranges. Microsoft documents the egress ranges under the [Office 365 IP Address and URL Web service](https://learn.microsoft.com/en-us/microsoft-365/enterprise/urls-and-ip-address-ranges). Configure them as:
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
msgraph_webhook:
|
||||
enabled: true
|
||||
extra:
|
||||
client_state: "..."
|
||||
allowed_source_cidrs:
|
||||
- "52.96.0.0/14"
|
||||
- "52.104.0.0/14"
|
||||
# ...add the current Microsoft 365 "Common" + "Teams" category egress ranges
|
||||
```
|
||||
|
||||
Or as an env var:
|
||||
|
||||
```bash
|
||||
MSGRAPH_WEBHOOK_ALLOWED_SOURCE_CIDRS="52.96.0.0/14,52.104.0.0/14"
|
||||
```
|
||||
|
||||
Empty allowlist = accept from anywhere (default; preserves dev-tunnel workflows). Invalid CIDR strings log a warning and are ignored. **Review the Microsoft IP list quarterly** — it changes.
|
||||
|
||||
### HTTPS termination
|
||||
|
||||
The listener speaks plain HTTP. Terminate TLS at your reverse proxy (Caddy, Nginx, Cloudflare Tunnel, AWS ALB) and proxy to the listener over the local network. Graph refuses to deliver to non-HTTPS endpoints, so there's no path for unencrypted traffic to reach you from Graph itself.
|
||||
|
||||
### Response hygiene
|
||||
|
||||
On success the listener returns `202 Accepted` with an empty body — internal counters stay out of the wire response. Operators can observe counts via `/health`.
|
||||
|
||||
Status code table:
|
||||
|
||||
| Outcome | Status |
|
||||
|---------|--------|
|
||||
| Notification(s) accepted or deduped | 202 |
|
||||
| Validation handshake (GET with `validationToken`) | 200 (echoes the token) |
|
||||
| Every item in batch failed clientState | 403 |
|
||||
| Malformed JSON / missing `value` array / unknown resource | 400 |
|
||||
| Source IP not in allowlist | 403 |
|
||||
| Bare GET without `validationToken` | 400 |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | What to check |
|
||||
|---------|---------------|
|
||||
| Graph subscription validation fails | Public URL is reachable, `/msgraph/webhook` path matches, GET with `validationToken` echoes the token verbatim as `text/plain` within 10 seconds. |
|
||||
| Notifications POST but nothing ingests | `client_state` matches what you registered the subscription with. Re-run `openssl rand -hex 32` and create a new subscription if the value drifted. Check `accepted_resources` includes the resource path Graph is sending. |
|
||||
| Every notification 403s | `clientState` mismatch (forged, or subscription registered with a different value). Re-create the subscription with `hermes teams-pipeline subscribe --client-state "$MSGRAPH_WEBHOOK_CLIENT_STATE" ...` (ships with the pipeline runtime PR). |
|
||||
| Listener starts but `curl http://localhost:8646/health` hangs | Port binding collision. Check `ss -tlnp \| grep 8646` and change `port:` if needed. |
|
||||
| Real Graph requests from Microsoft get 403'd | Source IP allowlist is too narrow. Remove `allowed_source_cidrs` temporarily, confirm traffic flows, then widen the list to include the current Microsoft egress ranges. |
|
||||
|
||||
## Related Docs
|
||||
|
||||
- [Register a Microsoft Graph Application](/docs/guides/microsoft-graph-app-registration) — Azure app registration prereq
|
||||
- [Environment Variables → Microsoft Graph](/docs/reference/environment-variables#microsoft-graph-teams-meetings) — full env var list
|
||||
- [Microsoft Teams bot setup](/docs/user-guide/messaging/teams) — the different platform that lets users chat with Hermes in Teams
|
||||
@@ -164,6 +164,37 @@ When the agent needs to run a potentially dangerous command, it sends an Adaptiv
|
||||
|
||||
Clicking a button resolves the approval inline and replaces the card with the decision.
|
||||
|
||||
### Meeting Summary Delivery (Teams Meeting Pipeline)
|
||||
|
||||
When the [Teams meeting pipeline plugin](/docs/user-guide/messaging/msgraph-webhook) is enabled, this adapter also handles outbound delivery of meeting summaries — one Teams integration surface, not two. After a meeting's transcript is summarized, the writer posts the summary into your chosen Teams target.
|
||||
|
||||
Pipeline summary delivery is configured under the `teams` platform entry alongside the bot config:
|
||||
|
||||
```yaml
|
||||
platforms:
|
||||
teams:
|
||||
enabled: true
|
||||
extra:
|
||||
# existing bot config (client_id, client_secret, tenant_id, port) ...
|
||||
|
||||
# Meeting summary delivery (only used when the teams_pipeline plugin is enabled)
|
||||
delivery_mode: "graph" # or "incoming_webhook"
|
||||
# For delivery_mode: graph — pick ONE of:
|
||||
chat_id: "19:meeting_..." # post into a Teams chat
|
||||
# team_id: "..." # OR post into a channel
|
||||
# channel_id: "..."
|
||||
# access_token: "..." # optional; falls back to MSGRAPH_* app credentials
|
||||
# For delivery_mode: incoming_webhook:
|
||||
# incoming_webhook_url: "https://outlook.office.com/webhook/..."
|
||||
```
|
||||
|
||||
| Mode | Use when | Trade-off |
|
||||
|------|----------|-----------|
|
||||
| `incoming_webhook` | Simple "post a summary into this channel" with a static Teams-generated URL. | No reply threading, no reactions, shows as the webhook's configured identity. |
|
||||
| `graph` | Threaded channel posts or 1:1/group chat posts under the bot's identity via Microsoft Graph. | Requires the [Graph app registration](/docs/guides/microsoft-graph-app-registration) with `ChannelMessage.Send` (channel) or `Chat.ReadWrite.All` (chat) application permissions. |
|
||||
|
||||
If the `teams_pipeline` plugin is **not** enabled, these settings are inert — they only wire up when the pipeline runtime binds to the Graph webhook ingress.
|
||||
|
||||
---
|
||||
|
||||
## Production Deployment
|
||||
|
||||
@@ -0,0 +1,573 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Profile Distributions: Share a Whole Agent
|
||||
|
||||
A **profile distribution** packages a complete Hermes agent — personality, skills, cron jobs, MCP connections, config — as a git repository. Anyone with access to the repo can install the whole agent with one command, update it in place, and keep their own memories, sessions, and API keys untouched.
|
||||
|
||||
If a [profile](./profiles.md) is a local agent, a distribution is that agent made shareable.
|
||||
|
||||
## What this means
|
||||
|
||||
Before distributions, sharing a Hermes agent meant sending someone:
|
||||
|
||||
1. Your SOUL.md
|
||||
2. A list of skills to install
|
||||
3. Your config.yaml, minus the secrets
|
||||
4. A description of which MCP servers you wired up
|
||||
5. Any cron jobs you scheduled
|
||||
6. Instructions for which env vars to set
|
||||
|
||||
…and hoping they assembled it correctly. Every version bump or bug fix meant repeating the handoff.
|
||||
|
||||
With distributions, all of that lives in one git repo:
|
||||
|
||||
```
|
||||
my-research-agent/
|
||||
├── distribution.yaml # manifest: name, version, env-var requirements
|
||||
├── SOUL.md # the agent's personality / system prompt
|
||||
├── config.yaml # model, temperature, reasoning, tool defaults
|
||||
├── skills/ # bundled skills that come with the agent
|
||||
├── cron/ # scheduled tasks the agent runs
|
||||
└── mcp.json # MCP servers the agent connects to
|
||||
```
|
||||
|
||||
Recipients run:
|
||||
|
||||
```bash
|
||||
hermes profile install github.com/you/my-research-agent --alias
|
||||
```
|
||||
|
||||
…and they now have the whole agent. They fill in their own API keys (`.env.EXAMPLE` → `.env`), and they can run `my-research-agent chat` or address it through Telegram / Discord / Slack / any gateway platform. When you push a new version, they run `hermes profile update my-research-agent` and pull your changes — their memories and sessions stay put.
|
||||
|
||||
## Why git?
|
||||
|
||||
We considered tarballs, HTTP archives, a custom format. None of them beat git:
|
||||
|
||||
- **Zero build step for authors.** Push to GitHub; consumers install. There's no "pack this, upload that, update the index" loop.
|
||||
- **Tags, branches, and commits are already the versioning system.** A tag push does for us what "pack + upload a release" does for other tools.
|
||||
- **Updates are a fetch.** Not a re-download of the whole archive.
|
||||
- **Transparent.** Users can browse the repo, read diffs between versions, open issues against it, fork it to customize.
|
||||
- **Private repos work for free.** SSH keys, `git credential` helpers, GitHub CLI stored credentials — whatever auth your terminal is already set up for applies transparently.
|
||||
- **Reproducibility is a commit SHA.** The same thing pip and npm record.
|
||||
|
||||
The tradeoff: recipients need git installed. On any machine running Hermes in 2026, that's already true.
|
||||
|
||||
## When should you use a distribution?
|
||||
|
||||
Good fits:
|
||||
|
||||
- **You're sharing a specialized agent** — a compliance monitor, a code reviewer, a research assistant, a customer-support bot — with a team or with the community.
|
||||
- **You're deploying the same agent to multiple machines** and don't want to copy files manually each time.
|
||||
- **You're iterating on an agent** and want recipients to pick up new versions with one command.
|
||||
- **You're building an agent as a product** — opinionated defaults, curated skills, tuned prompts — that other people should use as a starting point.
|
||||
|
||||
Not a fit:
|
||||
|
||||
- **You just want to back up a profile on your own machine.** Use [`hermes profile export` / `import`](../reference/profile-commands.md#hermes-profile-export) — that's what those are for.
|
||||
- **You want to share API keys alongside the agent.** `auth.json` and `.env` are deliberately excluded from distributions. Each installer brings their own credentials.
|
||||
- **You want to share memories / sessions / conversation history.** Those are user data, not distribution content. Never shipped.
|
||||
|
||||
## The lifecycle: author to installer to update
|
||||
|
||||
Below is the full end-to-end flow. Pick the side you care about.
|
||||
|
||||
---
|
||||
|
||||
## For authors: publishing a distribution
|
||||
|
||||
### Step 1 — Start from a working profile
|
||||
|
||||
Build and refine the agent like any other profile:
|
||||
|
||||
```bash
|
||||
hermes profile create research-bot
|
||||
research-bot setup # configure model, API keys
|
||||
# Edit ~/.hermes/profiles/research-bot/SOUL.md
|
||||
# Install skills, wire up MCP servers, schedule cron jobs, etc.
|
||||
research-bot chat # dogfood until it feels right
|
||||
```
|
||||
|
||||
### Step 2 — Add a `distribution.yaml`
|
||||
|
||||
Create `~/.hermes/profiles/research-bot/distribution.yaml`:
|
||||
|
||||
```yaml
|
||||
name: research-bot
|
||||
version: 1.0.0
|
||||
description: "Autonomous research assistant with arXiv and web tools"
|
||||
hermes_requires: ">=0.12.0"
|
||||
author: "Your Name"
|
||||
license: "MIT"
|
||||
|
||||
# Tell installers which env vars the agent needs. These are checked against
|
||||
# the installer's shell and existing .env file so they don't get nagged
|
||||
# about keys they already have configured.
|
||||
env_requires:
|
||||
- name: OPENAI_API_KEY
|
||||
description: "OpenAI API key (for model access)"
|
||||
required: true
|
||||
- name: SERPAPI_KEY
|
||||
description: "SerpAPI key for web search"
|
||||
required: false
|
||||
default: ""
|
||||
```
|
||||
|
||||
That's the whole manifest. Every field except `name` has a sensible default.
|
||||
|
||||
### Step 3 — Push to a git repo
|
||||
|
||||
```bash
|
||||
cd ~/.hermes/profiles/research-bot
|
||||
git init
|
||||
git add .
|
||||
git commit -m "v1.0.0"
|
||||
git remote add origin git@github.com:you/research-bot.git
|
||||
git tag v1.0.0
|
||||
git push -u origin main --tags
|
||||
```
|
||||
|
||||
The repo is now a distribution. Anyone with access can install it.
|
||||
|
||||
:::note
|
||||
The git repo contains **everything in the profile directory except things already excluded from distributions**: `auth.json`, `.env`, `memories/`, `sessions/`, `state.db*`, `logs/`, `workspace/`, `*_cache/`, `local/`. Those stay on your machine. You can also add a `.gitignore` if you want to exclude additional paths.
|
||||
:::
|
||||
|
||||
### Step 4 — Tag versioned releases
|
||||
|
||||
Every time the agent reaches a stable point, bump the version and tag:
|
||||
|
||||
```bash
|
||||
# Edit distribution.yaml: version: 1.1.0
|
||||
git add distribution.yaml SOUL.md skills/
|
||||
git commit -m "v1.1.0: tighter research SOUL, add arxiv skill"
|
||||
git tag v1.1.0
|
||||
git push --tags
|
||||
```
|
||||
|
||||
Recipients who run `hermes profile update research-bot` will pull the latest.
|
||||
|
||||
### What the repo looks like
|
||||
|
||||
A complete authored distribution:
|
||||
|
||||
```
|
||||
research-bot/
|
||||
├── distribution.yaml # required
|
||||
├── SOUL.md # strongly recommended
|
||||
├── config.yaml # model, provider, tool defaults
|
||||
├── mcp.json # MCP server connections
|
||||
├── skills/
|
||||
│ ├── arxiv-search/SKILL.md
|
||||
│ ├── paper-summarization/SKILL.md
|
||||
│ └── citation-lookup/SKILL.md
|
||||
├── cron/
|
||||
│ └── weekly-digest.json # scheduled tasks
|
||||
└── README.md # human-facing description (optional)
|
||||
```
|
||||
|
||||
### Distribution-owned vs user-owned
|
||||
|
||||
When an installer updates to a new version, some things get replaced (author's domain) and some things stay put (installer's domain). Defaults:
|
||||
|
||||
| Category | Paths | On update |
|
||||
|---|---|---|
|
||||
| **Distribution-owned** | `SOUL.md`, `config.yaml`, `mcp.json`, `skills/`, `cron/`, `distribution.yaml` | Replaced from the new clone |
|
||||
| **Config override** | `config.yaml` | Actually preserved by default — the installer may have tuned model or provider. Pass `--force-config` on update to reset. |
|
||||
| **User-owned** | `memories/`, `sessions/`, `state.db*`, `auth.json`, `.env`, `logs/`, `workspace/`, `plans/`, `home/`, `*_cache/`, `local/` | Never touched |
|
||||
|
||||
You can override the distribution-owned list in the manifest:
|
||||
|
||||
```yaml
|
||||
distribution_owned:
|
||||
- SOUL.md
|
||||
- skills/research/ # only my research skills; other installed skills stay
|
||||
- cron/digest.json
|
||||
```
|
||||
|
||||
When omitted, the defaults above apply — which is what most distributions want.
|
||||
|
||||
---
|
||||
|
||||
## For installers: using a distribution
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
hermes profile install github.com/you/research-bot --alias
|
||||
```
|
||||
|
||||
What happens:
|
||||
|
||||
1. Clones the repo into a temporary directory.
|
||||
2. Reads `distribution.yaml`, shows you the manifest (name, version, description, author, required env vars).
|
||||
3. Checks each required env var against your shell environment and the target profile's existing `.env`. Marks each as `✓ set` or `needs setting` so you know exactly what to configure.
|
||||
4. Asks for confirmation. Pass `-y` / `--yes` to skip.
|
||||
5. Copies distribution-owned files into `~/.hermes/profiles/research-bot/` (or wherever the manifest's `name` resolves).
|
||||
6. Writes `.env.EXAMPLE` with the required keys commented out — copy to `.env` and fill in.
|
||||
7. With `--alias`, creates a wrapper so you can run `research-bot chat` directly.
|
||||
|
||||
### Source types
|
||||
|
||||
Any git URL works:
|
||||
|
||||
```bash
|
||||
# GitHub shorthand
|
||||
hermes profile install github.com/you/research-bot
|
||||
|
||||
# Full HTTPS
|
||||
hermes profile install https://github.com/you/research-bot.git
|
||||
|
||||
# SSH
|
||||
hermes profile install git@github.com:you/research-bot.git
|
||||
|
||||
# Self-hosted, GitLab, Gitea, Forgejo — any Git host
|
||||
hermes profile install https://git.example.com/team/research-bot.git
|
||||
|
||||
# Private repo using your configured git auth
|
||||
hermes profile install git@github.com:your-org/internal-bot.git
|
||||
|
||||
# Local directory during development (no git push needed)
|
||||
hermes profile install ~/my-profile-in-progress/
|
||||
```
|
||||
|
||||
### Override the profile name
|
||||
|
||||
Two users wanting the same distribution under different profile names:
|
||||
|
||||
```bash
|
||||
# Alice
|
||||
hermes profile install github.com/acme/support-bot --name support-us --alias
|
||||
# Bob (same distribution, different local name)
|
||||
hermes profile install github.com/acme/support-bot --name support-eu --alias
|
||||
```
|
||||
|
||||
### Fill in env vars
|
||||
|
||||
After install, the agent's profile contains a `.env.EXAMPLE`:
|
||||
|
||||
```
|
||||
# Environment variables required by this Hermes distribution.
|
||||
# Copy to `.env` and fill in your own values before running.
|
||||
|
||||
# OpenAI API key (for model access)
|
||||
# (required)
|
||||
OPENAI_API_KEY=
|
||||
|
||||
# SerpAPI key for web search
|
||||
# (optional)
|
||||
# SERPAPI_KEY=
|
||||
```
|
||||
|
||||
Copy it:
|
||||
|
||||
```bash
|
||||
cp ~/.hermes/profiles/research-bot/.env.EXAMPLE ~/.hermes/profiles/research-bot/.env
|
||||
# Edit .env, paste your real keys
|
||||
```
|
||||
|
||||
Required keys that were already in your shell environment (e.g. `OPENAI_API_KEY` exported in your `~/.zshrc`) are marked `✓ set` during install — you don't need to duplicate them in `.env`.
|
||||
|
||||
### Check what you installed
|
||||
|
||||
```bash
|
||||
hermes profile info research-bot
|
||||
```
|
||||
|
||||
Shows:
|
||||
|
||||
```
|
||||
Distribution: research-bot
|
||||
Version: 1.0.0
|
||||
Description: Autonomous research assistant with arXiv and web tools
|
||||
Author: Your Name
|
||||
Requires: Hermes >=0.12.0
|
||||
Source: https://github.com/you/research-bot
|
||||
Installed: 2026-05-08T17:04:32+00:00
|
||||
|
||||
Environment variables:
|
||||
OPENAI_API_KEY (required) — OpenAI API key (for model access)
|
||||
SERPAPI_KEY (optional) — SerpAPI key for web search
|
||||
```
|
||||
|
||||
`hermes profile list` also shows a `Distribution` column so at a glance you can see which of your profiles came from repos and which you hand-built:
|
||||
|
||||
```
|
||||
Profile Model Gateway Alias Distribution
|
||||
─────────────── ─────────────────────────── ─────────── ─────────── ────────────────────
|
||||
◆default claude-sonnet-4 stopped — —
|
||||
coder gpt-5 stopped coder —
|
||||
research-bot claude-opus-4 stopped research-bot research-bot@1.0.0
|
||||
telemetry claude-sonnet-4 running telemetry telemetry@2.3.1
|
||||
```
|
||||
|
||||
### Update
|
||||
|
||||
```bash
|
||||
hermes profile update research-bot
|
||||
```
|
||||
|
||||
What happens:
|
||||
|
||||
1. Re-clones the repo from the recorded source URL.
|
||||
2. Replaces distribution-owned files (SOUL, skills, cron, mcp.json).
|
||||
3. **Preserves** your `config.yaml` — you may have tuned the model, temperature, or other settings. Pass `--force-config` to overwrite.
|
||||
4. **Never touches** user data: memories, sessions, auth, `.env`, logs, state.
|
||||
|
||||
No re-downloading the whole archive. No stomping your local changes to config. No deleting your conversation history.
|
||||
|
||||
### Remove
|
||||
|
||||
```bash
|
||||
hermes profile delete research-bot
|
||||
```
|
||||
|
||||
The delete prompt surfaces distribution info before asking you to confirm:
|
||||
|
||||
```
|
||||
Profile: research-bot
|
||||
Path: ~/.hermes/profiles/research-bot
|
||||
Model: claude-opus-4 (anthropic)
|
||||
Skills: 12
|
||||
Distribution: research-bot@1.0.0
|
||||
Installed from: https://github.com/you/research-bot
|
||||
|
||||
This will permanently delete:
|
||||
• All config, API keys, memories, sessions, skills, cron jobs
|
||||
• Command alias (~/.local/bin/research-bot)
|
||||
|
||||
Type 'research-bot' to confirm:
|
||||
```
|
||||
|
||||
So you never accidentally delete an agent without knowing where it came from or being able to re-install it.
|
||||
|
||||
---
|
||||
|
||||
## Use cases and patterns
|
||||
|
||||
### Personal: sync one agent across machines
|
||||
|
||||
You built a research assistant on your laptop. You want the same agent on your workstation.
|
||||
|
||||
```bash
|
||||
# Laptop
|
||||
cd ~/.hermes/profiles/research-bot
|
||||
git init && git add . && git commit -m "initial"
|
||||
git remote add origin git@github.com:you/research-bot.git
|
||||
git push -u origin main
|
||||
|
||||
# Workstation
|
||||
hermes profile install github.com/you/research-bot --alias
|
||||
# Fill in .env. Done.
|
||||
```
|
||||
|
||||
Any iteration on the laptop (`git commit && push`) pulls onto the workstation with `hermes profile update research-bot`. Memories stay per-machine — the laptop remembers its own conversations, the workstation remembers its own, they don't collide.
|
||||
|
||||
### Team: ship a reviewed internal agent
|
||||
|
||||
Your engineering team wants a shared PR-review bot with a specific SOUL, specific skills, and a cron that runs every PR through it.
|
||||
|
||||
```bash
|
||||
# Engineering lead
|
||||
cd ~/.hermes/profiles/pr-reviewer
|
||||
# ... build and tune ...
|
||||
git init && git add . && git commit -m "v1.0 PR reviewer"
|
||||
git tag v1.0.0
|
||||
git push -u origin main --tags # push to your company's internal Git host
|
||||
|
||||
# Each engineer
|
||||
hermes profile install git@github.com:your-org/pr-reviewer.git --alias
|
||||
# Fill in .env with their own API key (billed to them), .env.EXAMPLE points at what's required
|
||||
pr-reviewer chat
|
||||
```
|
||||
|
||||
When the lead ships v1.1 (better SOUL, new skill), engineers run `hermes profile update pr-reviewer` and everyone's on the new version within minutes.
|
||||
|
||||
### Community: publish a public agent
|
||||
|
||||
You built something novel — maybe a "Polymarket trader" or an "academic paper summarizer" or a "Minecraft server ops assistant." You want to share it.
|
||||
|
||||
```bash
|
||||
# You
|
||||
cd ~/.hermes/profiles/polymarket-trader
|
||||
# Write a solid README.md at the repo root — GitHub shows it on the repo page
|
||||
git init && git add . && git commit -m "v1.0"
|
||||
git tag v1.0.0
|
||||
# Publish to a public GitHub repo
|
||||
git remote add origin https://github.com/you/hermes-polymarket-trader.git
|
||||
git push -u origin main --tags
|
||||
|
||||
# Anyone
|
||||
hermes profile install github.com/you/hermes-polymarket-trader --alias
|
||||
```
|
||||
|
||||
Tweet the install command. People who try it send you issues and PRs. If someone wants to customize, they fork — same git workflow everyone already knows.
|
||||
|
||||
### Product: ship an opinionated agent
|
||||
|
||||
You built Hermes-on-top — maybe a compliance-monitoring harness, a customer-support stack, a domain-specific research platform. You want to distribute it as a product.
|
||||
|
||||
```yaml
|
||||
# distribution.yaml
|
||||
name: telemetry-harness
|
||||
version: 2.3.1
|
||||
description: "Compliance telemetry harness — monitors and reviews regulated workflows"
|
||||
hermes_requires: ">=0.13.0"
|
||||
author: "Acme Compliance Inc."
|
||||
license: "Commercial"
|
||||
|
||||
env_requires:
|
||||
- name: ACME_API_KEY
|
||||
description: "Your Acme Compliance license key (email support@acme.com)"
|
||||
required: true
|
||||
- name: OPENAI_API_KEY
|
||||
description: "OpenAI API key for model access"
|
||||
required: true
|
||||
- name: GRAPHITI_MCP_URL
|
||||
description: "URL for your Graphiti knowledge graph instance"
|
||||
required: false
|
||||
default: "http://127.0.0.1:8000/sse"
|
||||
```
|
||||
|
||||
Your customers install via a single command; the install preview tells them exactly which keys to have ready; updates roll out the moment you tag a new release; their compliance data (`memories/`, `sessions/`) never leaves their machine.
|
||||
|
||||
### Ephemeral: one-off scripts on shared infra
|
||||
|
||||
You're the ops lead. You want a temporary agent that diagnoses a production incident — a canned SOUL with the right tools and MCP connections — and runs on three on-call engineers' laptops for the next week.
|
||||
|
||||
```bash
|
||||
# You
|
||||
# Build the profile, commit, push a private repo
|
||||
git push -u origin main
|
||||
|
||||
# Each on-call
|
||||
hermes profile install git@github.com:your-org/incident-2026-q2.git --alias
|
||||
|
||||
# Incident resolved — tear it down
|
||||
hermes profile delete incident-2026-q2
|
||||
```
|
||||
|
||||
The install-delete cycle is cheap enough to be disposable.
|
||||
|
||||
---
|
||||
|
||||
## Recipes
|
||||
|
||||
### Pin to a specific version
|
||||
|
||||
:::note
|
||||
Git ref pinning (`#v1.2.0`) is planned but not in the initial release — install currently tracks the default branch. Track your installed version via `hermes profile info <name>` and hold off on updates until you're ready.
|
||||
:::
|
||||
|
||||
### Check what version you're on vs. latest
|
||||
|
||||
```bash
|
||||
# Your installed version
|
||||
hermes profile info research-bot | grep Version
|
||||
|
||||
# Latest upstream (without installing)
|
||||
git ls-remote --tags https://github.com/you/research-bot | tail -5
|
||||
```
|
||||
|
||||
### Keep local config customizations through updates
|
||||
|
||||
The default update behavior already does this: `config.yaml` is preserved. To be safe, write your local tweaks to a file the distribution doesn't own:
|
||||
|
||||
```yaml
|
||||
# ~/.hermes/profiles/research-bot/local/my-overrides.yaml
|
||||
# (distribution never touches local/)
|
||||
```
|
||||
|
||||
…and reference it from `config.yaml` or your SOUL as needed.
|
||||
|
||||
### Force a clean re-install
|
||||
|
||||
```bash
|
||||
# Nuke and re-install from scratch (loses memories/sessions too)
|
||||
hermes profile delete research-bot --yes
|
||||
hermes profile install github.com/you/research-bot --alias
|
||||
|
||||
# Update to current main but reset config.yaml to the distribution's default
|
||||
hermes profile update research-bot --force-config --yes
|
||||
```
|
||||
|
||||
### Fork and customize
|
||||
|
||||
The standard git workflow — distributions are just repos:
|
||||
|
||||
```bash
|
||||
# Fork the repo on GitHub, then install your fork
|
||||
hermes profile install github.com/yourname/forked-research-bot --alias
|
||||
|
||||
# Iterate locally in ~/.hermes/profiles/forked-research-bot/
|
||||
# Edit SOUL.md, commit, push to your fork
|
||||
# Upstream changes: pull them into your fork the usual way
|
||||
```
|
||||
|
||||
### Test a distribution before pushing
|
||||
|
||||
From the author's machine:
|
||||
|
||||
```bash
|
||||
# Install from a local directory (no git push needed)
|
||||
hermes profile install ~/.hermes/profiles/research-bot --name research-bot-test --alias
|
||||
|
||||
# Tweak, delete, re-install until it's right
|
||||
hermes profile delete research-bot-test --yes
|
||||
hermes profile install ~/.hermes/profiles/research-bot --name research-bot-test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What's NOT in a distribution (ever)
|
||||
|
||||
The installer hard-excludes these paths even if an author accidentally ships them. No config option lets you override this — the safety guard is a regression-tested invariant:
|
||||
|
||||
- `auth.json` — OAuth tokens, platform credentials
|
||||
- `.env` — API keys, secrets
|
||||
- `memories/` — conversation memory
|
||||
- `sessions/` — conversation history
|
||||
- `state.db`, `state.db-shm`, `state.db-wal` — session metadata
|
||||
- `logs/` — agent and error logs
|
||||
- `workspace/` — generated working files
|
||||
- `plans/` — scratch plans
|
||||
- `home/` — user's home mount in Docker backends
|
||||
- `*_cache/` — image / audio / document caches
|
||||
- `local/` — user-reserved customization namespace
|
||||
|
||||
When you clone a distribution, these simply aren't there. When you update, they stay put. If you installed the same distribution on five machines, you have five isolated sets of this data — one per machine.
|
||||
|
||||
## Security and trust
|
||||
|
||||
Profile distributions are unsigned by default. You're trusting:
|
||||
|
||||
- **The git host** (GitHub / GitLab / wherever) to serve the bytes the author pushed.
|
||||
- **The author** to not ship a malicious SOUL, skills, or cron jobs.
|
||||
|
||||
Cron jobs from a distribution are **not auto-scheduled** — the installer prints `hermes -p <name> cron list` and you enable them explicitly. SOUL.md and skills ARE active as soon as you start chatting with the profile, so read them before your first run if you're installing from someone you don't know.
|
||||
|
||||
Rough analogy: installing a distribution is like installing a browser extension or a VS Code extension. Low friction, high power, trust the source. For internal company distributions, use a private repo and your normal git auth — nothing new to configure.
|
||||
|
||||
Future versions may add signing, a lockfile (`.distribution-lock.yaml`) with a resolved commit SHA, and a `--dry-run` flag that prints the diff before applying an update. None of those are shipping yet.
|
||||
|
||||
## Under the hood
|
||||
|
||||
For implementation details, precise CLI behavior, and all flags, see the [Profile Commands reference](../reference/profile-commands.md#distribution-commands).
|
||||
|
||||
The short version:
|
||||
|
||||
- `install`, `update`, `info` live inside `hermes profile` — not a parallel command tree.
|
||||
- The manifest format is YAML with a tiny required schema (`name` only).
|
||||
- The installer uses your local `git` binary for cloning, so any auth your shell already handles (SSH keys, credential helpers) works transparently.
|
||||
- After clone, `.git/` is stripped — the installed profile isn't itself a git checkout, avoiding "oh my, I accidentally committed my `.env` to the distribution's git history" traps.
|
||||
- Reserved profile names (`hermes`, `test`, `tmp`, `root`, `sudo`) are rejected at install time to avoid collisions with common binaries.
|
||||
|
||||
## See also
|
||||
|
||||
- [Profiles: Running Multiple Agents](./profiles.md) — the base concept
|
||||
- [Profile Commands reference](../reference/profile-commands.md) — every flag, every option
|
||||
- [`hermes profile export` / `import`](../reference/profile-commands.md#hermes-profile-export) — local backup / restore (not distribution)
|
||||
- [Using SOUL with Hermes](../guides/use-soul-with-hermes.md) — authoring personalities
|
||||
- [Personality & SOUL](./features/personality.md) — how SOUL fits into the agent
|
||||
- [Skills catalog](../reference/skills-catalog.md) — skills you can bundle
|
||||
@@ -238,3 +238,17 @@ Profiles use the `HERMES_HOME` environment variable. When you run `coder chat`,
|
||||
This is separate from terminal working directory. Tool execution starts from `terminal.cwd` (or the launch directory when `cwd: "."` on the local backend), not automatically from `HERMES_HOME`.
|
||||
|
||||
The default profile is simply `~/.hermes` itself. No migration needed — existing installs work identically.
|
||||
|
||||
## Sharing profiles as distributions
|
||||
|
||||
A profile you built on one machine can be packaged as a **git repository** and installed with one command on another machine — your own workstation, a teammate's laptop, or a community user's environment. The shared package includes the SOUL, config, skills, cron jobs, and MCP connections. Credentials, memories, and sessions stay per-machine.
|
||||
|
||||
```bash
|
||||
# Install a whole agent from a git repo
|
||||
hermes profile install github.com/you/research-bot --alias
|
||||
|
||||
# Update later when the author ships a new version (keeps your memories + .env)
|
||||
hermes profile update research-bot
|
||||
```
|
||||
|
||||
See **[Profile Distributions: Share a Whole Agent](./profile-distributions.md)** for the full guide — authoring, publishing, update semantics, security model, and use cases.
|
||||
|
||||
Reference in New Issue
Block a user