hermes-shortcuts
Share to Hermes, ask Hermes with Siri, and photograph a task, all from iOS Shortcuts or Android HTTP Shortcuts.
hermes-shortcuts is a Hermes Agent gateway platform plugin. It adds one small, token-protected HTTP
endpoint that your phone can call:
| You do on the phone | What Hermes does | Where the answer goes |
|---|---|---|
| Share Sheet: Share → Hermes on a link, article, YouTube video, text, PDF or screenshot, then pick Summarize / Remember / Remind / Post / Auto | Runs a normal agent turn with that action preset (web tools, memory, cron, vision) | Shown in Shortcuts and sent to your Telegram home channel |
| "Hey Siri, Ask Hermes": dictate a question | Answers it | Siri speaks the reply (synchronous). If it takes longer than the timeout, Siri says "working on it" and the answer goes to Telegram |
| Photo as task: snap a receipt, whiteboard or document | Extracts the expense line, transcribes it and makes a checklist, or digitizes the document | Shortcuts + Telegram |
| Event triggers (Shortcuts Automations): Arrive home, Alarm stopped, Charger connected… | Runs the prompt you mapped to that event (morning briefing, evening recap…) | Telegram |
Quick start (iPhone, 3 steps)
- Server (once, after Install and an HTTPS tunnel, see Reaching it from your phone):
A QR code appears in the terminal. It holds your server URL and your token, so don't screenshot or share it.hermes shortcuts pair - iPhone: install Hermes Setup, run it, and scan the QR code. It saves the
pairing to iCloud Drive → Shortcuts →hermes.jsonand says "Hermes paired". - iPhone: install the shortcuts you want. They need no editing because they read
hermes.json:
Ask Hermes (Siri), Hermes (Share Sheet: links and text
from any app). Hermes Photo (recipe below) is optional.
Then say "Hey Siri, Ask Hermes", or share a link and choose Hermes.
hermes shortcuts pair options: --url https://your-host (else SHORTCUTS_PUBLIC_URL, else the URL of a
cloudflared quick tunnel running on this machine), --invert (light terminal background), --png FILE (saves a
0600 PNG; delete it after pairing), --show-token (also prints the token as text; off by default). If your Hermes
build has no plugin CLI commands, run python3 ~/.hermes/plugins/hermes-shortcuts/pair.py pair instead (with
Hermes' Python it reads the token through Hermes' secret scope; otherwise it asks for it, hidden).
Has the tunnel URL changed, or did you rotate the token? Run hermes shortcuts pair again and re-run Hermes Setup.
The other shortcuts don't need changes.
Maintainers, one-time step: Apple doesn't let you generate shortcuts as files, and an installable shortcut
only exists as an iCloud link from a real device. The three links above were built on an iPhone (recipes below). If you rebuild one, open
⋯ → Share (⤴) → Copy iCloud Link and update its link above. These shortcuts contain no URL or token, because both live
in each user'shermes.json. That makes the links safe to publish. Before you share, open each shortcut and check
that noAuthorizationvalue contains a literal token.
Why not the built-in webhook adapter?
Hermes already has a generic webhook adapter (port 8644). It's built for GitHub, Stripe and similar services and
needs HMAC-signed bodies, which iOS Shortcuts can't compute. hermes-shortcuts is made for phones:
- simple bearer token (one header in "Get Contents of URL")
- multipart file and photo uploads, plus raw image bodies
- action presets (
summarize,remember,remind,post,receipt,whiteboard,document,auto) - a synchronous reply that Siri can read aloud, with a timeout fallback to Telegram
- one-scan iPhone pairing (
hermes shortcuts pair+ the Hermes Setup shortcut) and ready-made recipes
Install
hermes plugins install sergo565456/hermes-shortcuts
hermes plugins enable hermes-shortcuts
# 1) a strong random token (256 bit), stored through Hermes' own credential route (~/.hermes/.env, never config.yaml).
# The plugin refuses to listen with a token that is missing, shorter than 32 chars, repetitive or a placeholder.
hermes config set SHORTCUTS_TOKEN "$(openssl rand -hex 32)"
# (no openssl? python3 -c 'import secrets;print(secrets.token_urlsafe(32))')
# 2) the gateway allowlist for this platform (requests always arrive as user "owner"; see Security)
hermes config set SHORTCUTS_ALLOWED_USERS owner
hermes gateway restart # or: systemctl --user restart hermes-gateway
The gateway log then shows [shortcuts] listening on http://127.0.0.1:8645 and ✓ shortcuts connected.
Check it from the server:
curl -s http://127.0.0.1:8645/health
T="$(grep ^SHORTCUTS_TOKEN= ~/.hermes/.env | cut -d= -f2-)" # stays in your shell, not in history or logs
printf 'header = "Authorization: Bearer %s"\n' "$T" | curl -s -K - -d "text=What's 2+2?" http://127.0.0.1:8645/v1/ask
unset T
(-K - reads the header from stdin, so the token never appears in ps output for other local users.)
To pair an iPhone, run hermes shortcuts pair (see Quick start). For manual or Android
setup you can read the token on the server with grep ^SHORTCUTS_TOKEN= ~/.hermes/.env | cut -d= -f2-. Don't paste it
into chats, issues or screenshots.
Replies are forwarded to the home channel of SHORTCUTS_NOTIFY_TARGET (default telegram). Set your
Telegram home channel once with /sethome in your bot chat (or TELEGRAM_HOME_CHANNEL).
Reaching it from your phone (HTTPS)
The listener binds 127.0.0.1 only by default. Put an HTTPS tunnel or reverse proxy in front of it and point the
Shortcut at that URL:
- Tailscale (most private):
tailscale serve --bg 8645keeps it inside your tailnet; nothing is on the public
internet. Needs the Tailscale app on the phone. - Cloudflare named tunnel + Cloudflare Access (recommended for a public URL): route a hostname on your domain to
http://127.0.0.1:8645and protect it with an Access application whose policy is Service Auth with a
service token. Add the two headersCF-Access-Client-Id/CF-Access-Client-Secretto every Shortcut next to
Authorization; requests without them never reach your server. SetSHORTCUTS_CLIENT_IP_HEADER=CF-Connecting-IP. - Cloudflare quick tunnel (testing only):
cloudflared tunnel --no-autoupdate --url http://127.0.0.1:8645gives a
randomhttps://<random>.trycloudflare.comURL that changes on every restart. There is no access control besides the
bearer token, and Cloudflare documents quick tunnels as not for production. - Caddy / nginx reverse proxy with a real certificate (needs root for ports 80/443). Proxy to 127.0.0.1 only, and
make sure the proxy's access log does not record theAuthorizationheader.
The plugin never trusts X-Forwarded-For for anything. If you set SHORTCUTS_CLIENT_IP_HEADER (e.g.
CF-Connecting-IP), that header is used only to key the auth-failure lockout per client (IPv6 per /64), and only
when the TCP peer is loopback (your local tunnel/proxy). Cloudflare refuses client-supplied CF-Connecting-IP, but
any local process that can reach 127.0.0.1 can set it, including traffic from a VPN/proxy server on the same
host (e.g. Xray/V2Ray/Hysteria with no rule blocking private destinations) and other local users. The lockout is a
convenience, not the security boundary: the 256-bit token is. A global cap (300 failed attempts / 5 min) still
applies to everyone, and the valid token is never locked out. If you run a proxy/VPN on the same server, block
private/loopback destinations in it.
Binding a non-loopback address directly requires SHORTCUTS_HOST=0.0.0.0 and
SHORTCUTS_ALLOW_PUBLIC_BIND=true. Plain HTTP over the internet would expose your token, so use a tunnel instead.
Configuration
All settings are environment entries read through agent.secret_scope.get_secret. Set them with hermes config set NAME value.
Optional YAML overrides go in config.yaml → gateway.platforms.shortcuts.extra.
| Env | Default | Meaning |
|---|---|---|
| SHORTCUTS_TOKEN | — (required, ≥32 random chars) | Bearer token. Without it the plugin doesn't listen |
| SHORTCUTS_ALLOWED_USERS | — | Set to owner (gateway allowlist) |
| SHORTCUTS_HOST | 127.0.0.1 | Bind address |
| SHORTCUTS_PORT | 8645 | Port |
| SHORTCUTS_ALLOW_PUBLIC_BIND | false | Required to bind a non-loopback address |
| SHORTCUTS_SYNC_TIMEOUT | 25 | Seconds to wait for a reply before answering "working on it" (3–120) |
| SHORTCUTS_NOTIFY_TARGET | telegram | Where replies are forwarded (any connected platform's home channel; none turns it off) |
| SHORTCUTS_RATE_LIMIT | 20 | Accepted requests per minute |
| SHORTCUTS_MAX_UPLOAD_MB | 15 | Upload cap per request (1–50) |
| SHORTCUTS_MAX_UPLOAD_MB_PER_HOUR | 200 | Total upload budget per hour (bounds media-cache disk use) |
| SHORTCUTS_TOOL_PROFILE | safe | safe: each action gets only the toolsets it needs (no terminal/file/code/browser). full: the platform's normal toolset |
| SHORTCUTS_PUBLIC_URL | — | Public HTTPS base URL that hermes shortcuts pair puts in the QR (else auto-detected from a local cloudflared quick tunnel) |
| SHORTCUTS_CLIENT_IP_HEADER | — | e.g. CF-Connecting-IP behind cloudflared; only honoured from a loopback peer, only for the lockout |
Custom event prompts (config.yaml):
gateway:
platforms:
shortcuts:
extra:
events:
arrived_home: "I'm home. What's left on my list for today?"
gym: "I'm at the gym. Give me today's workout."
Built-in events: arrived_home, arrived_office, alarm_off, charger_connected.
Per-action toolsets in the safe profile (override in config.yaml → gateway.platforms.shortcuts.extra.toolsets,
keys ask, event, remember, remind, _shared; values are Hermes toolset names):
| Action | Toolsets |
|---|---|
| summarize, auto, post, receipt, whiteboard, document | web, vision |
| remember | web, vision, memory |
| remind | web, vision, cronjob |
| ask (Siri) | web, vision, cronjob, todo |
| events | cronjob, todo |
Every list also carries no_mcp, so your globally enabled MCP servers are not added to shortcuts turns.
On top of that, a pre_tool_call hook (active only in shortcuts sessions, fail-closed) blocks any tool outside the
action's list (other plugins' tools, MCP tools, terminal/file/code even if a Hermes fallback widened the toolset), lets
cronjob only create or list jobs (no update/remove/run, no script, no_agent, monitor, workdir,
context_from, skills or model/provider), allows delivery only to your home channel, and forces every job created from
the phone to run with no tools (enabled_toolsets: []) and once (repeat: 1; raise the cap with
SHORTCUTS_MAX_REMINDER_REPEAT, max 100), at most 3 per request. Without that, a reminder job would run later with your
cron toolset, which includes the terminal by default, and injected text could start an every-minute job you can only
remove from Telegram or the CLI.
Backstop for the unlikely case that the plugin fails to load its hook: pin the platform's default too, so a Hermes
fallback can never be the full toolset:
platform_toolsets:
shortcuts: [web, vision, no_mcp]
HTTP API
Auth: Authorization: Bearer <token> (or X-Hermes-Token: <token>). Tokens in the URL are not accepted.
| Endpoint | Body | Notes |
|---|---|---|
| POST /v1/ask | text (JSON, form, or a text/plain body) | Plain question. Not forwarded to Telegram unless notify=true or it times out |
| POST /v1/share | action, text, url, file (multipart, up to 4), when (for remind), note | Also accepts a raw image/* or application/pdf body with ?action= |
| POST /v1/event | event | Runs the mapped event prompt |
| GET /health | — | Liveness only (no data) |
Common fields: notify (auto/true/false), sync (default true), timeout (seconds), format=text
(returns the bare reply text, which is handy for Speak Text).
Response (JSON):
{"ok": true, "status": "done", "action": "summarize", "reply": "TL;DR: …", "forwarded_to": "telegram"}
status: "accepted" (HTTP 202) means the sync wait timed out, and the result will arrive in Telegram.
Actions: ask, auto (Hermes decides), summarize, remember (saves to memory), remind (creates a cron
reminder delivered to Telegram; when is free text, default "tomorrow 09:00"), post (drafts a post and never
publishes it), receipt, whiteboard, document.
iOS Shortcuts recipes
All Hermes shortcuts share one config file written by Hermes Setup: hermes.json in the Shortcuts
folder of iCloud Drive (in the Files app: iCloud Drive → Shortcuts). Its content is the QR payload:
{"v": 1, "url": "https://your-host.example", "token": "…"}
Action names below are the English iOS 17/18 names.
To add an action, tap Add Action / the search field at the bottom and type its name.
To insert a variable into a field, tap the field and pick it from the bar above the keyboard, or long-press
the field and choose Select Variable.
0. "Hermes Setup" (scan the pairing QR, once per phone)
- Shortcuts → + → rename it Hermes Setup.
- Scan QR or Barcode.
- Get Dictionary from Input. Input: QR/Barcode, which is filled in automatically.
- Get Dictionary Value: Value for key
tokenin Dictionary. - If Dictionary Value has any value. Inside Otherwise: Show Alert "Not a Hermes pairing code", then Stop This Shortcut. Leave the If branch empty.
- After End If: Save File. Input: Dictionary (the result of step 3; tap the
input and pick Dictionary). Destination: Shortcuts (the default folder). Expand the action (›) and set:
Ask Where to Save off, Subpathhermes.json,
Overwrite If File Exists on. - Show Alert:
Hermes paired. - Run it. When asked, allow camera access, then scan the QR from
hermes shortcuts pair. Then typeclear
in the server terminal.
1. "Ask Hermes" (Siri voice)
Steps 1–6 are the config block. Every other Hermes shortcut starts with it.
- Get File. Tap the folder and choose Shortcuts. Turn Show Document Picker off, set File Path to
hermes.json, and turn
Error If Not Found on. - Get Dictionary from Input. Input: File.
- Get Dictionary Value: Value for key
urlin Dictionary. - Set Variable named
HermesURLto Dictionary Value. - Get Dictionary Value: Value for key
tokenin Dictionary (tap the input and pick the Dictionary
from step 2, not the previous value). - Set Variable
HermesTokento Dictionary Value. - Dictate Text. Expand it and set Stop Listening to After Pause.
- Get Contents of URL. In the URL field, insert the variable
HermesURL, then
type/v1/ask?format=textright after it, with no space. Expand it (›, Show More) and set:- Method:
POST - Headers → Add new header: Key
Authorization,
Value: typeBearerplus one space, then insert the variableHermesToken. - Request Body: JSON → Add new field → Text: Key
text, Value: Dictated Text.
- Method:
- Speak Text. Input: Contents of URL.
- Name it Ask Hermes. The name is the Siri phrase: "Hey Siri, Ask Hermes". The first run asks for permission
to readhermes.jsonand to connect to your host. Choose Always Allow.
Siri waits about 25 s (SHORTCUTS_SYNC_TIMEOUT). Longer jobs say "Working on it…" and finish in Telegram.
2. "Hermes" (Share Sheet: links and text PDFs, screenshots)
- New shortcut Hermes. Tap ⓘ (Details) → turn on Show in Share Sheet. In the Receive block at the top, choose URLs, Text, Safari web pages, Images, PDFs, Files.
If there's no input: Ask For → Text. - The config block (steps 1–6 of Ask Hermes).
- Choose from Menu, prompt
Hermes:, with itemsSummarize,Remember,Remind,Post,
Auto. Inside each item add Text with the lowercase action (summarize,remember, …). - After End Menu: Set Variable
Actionto Menu Result. - (Optional, for Remind) Ask for Input
When?, then Set VariableWhen. - Get Contents of URL. URL:
HermesURL+/v1/share. Method POST, headerAuthorization=
Bearer+HermesToken(as in Ask Hermes). Request Body Form with Text fields
action=Action,text= Shortcut Input, and optionallywhen=When. - Get Dictionary Value
replyfrom Contents of URL → Show Result.
3. "Hermes Photo" (photo as task)
- New shortcut Hermes Photo (add it to the Home Screen or the Action Button).
- The config block.
- Take Photo, or Select Photos → Convert Image to JPEG, quality ~0.7. HEIC is rejected, and JPEG keeps uploads small.
- Choose from Menu:
Receipt/Whiteboard/Document/Auto. Inside each item add Text with the
lowercase name, then after the menu Set VariableAction= Menu Result. - Get Contents of URL. URL:
HermesURL+/v1/share, POST, headerAuthorization=Bearer+
HermesToken. Request Body Form:action(Text) =Action,file(File) = Converted Image. - Get Dictionary Value
reply→ Show Result.
4. Event triggers (Automations)
Shortcuts → Automation → + → Arrive (Home), Alarm (is stopped), Charger (is
connected)… → Run Immediately. Add the config block, then Get Contents of URL:
HermesURL + /v1/event, POST, header Authorization = Bearer + HermesToken, JSON body event =
arrived_home (or alarm_off, charger_connected, a custom name). The reply goes to Telegram.
Troubleshooting
- "File not found" / "hermes.json": run Hermes Setup again. In the Files app, check that iCloud Drive →
Shortcuts containshermes.json(nothermes.json.txt). If iCloud Drive is off, look under On My iPhone →
Shortcuts. - 401 / "unauthorized": the token changed. Run
hermes shortcuts pairand Hermes Setup again. Also check that
the header value isBearer, one space, then the token. - Can't connect: the quick-tunnel URL changed. Run
hermes shortcuts pairagain and re-scan. - QR won't scan: run with
--invert, make the terminal font smaller or the window larger, or use
--png FILEand open the file on your computer (then delete it).
Android (HTTP Shortcuts app)
- Install HTTP Shortcuts (F-Droid / Play). Create a Variable
token(type Constant, value your token)
and a variableshared(type Text, check Allow receiving value from Share dialog). - New shortcut Hermes: summarize: Method POST, URL
https://YOUR-HOST/v1/share, header
Authorization: Bearer {{token}}, Request Body Form data:action=summarize,text={{shared}}.
Response handling: Show in dialog. Under Trigger & Execution, enable Show in share menu.
Duplicate it forremember,remind,post. - Photo: Request Body File (Form data with a file parameter
file, "Pick file / take photo"). - Voice: add a Text input variable
q(the keyboard mic does dictation) → POST/v1/ask?format=text
with bodytext={{q}}, and display the response. In Tasker, HTTP Request + Say gives spoken replies.
Security and disclosure
Read this before installing.
- What it runs: a long-lived HTTP listener (aiohttp) inside the Hermes gateway process on
127.0.0.1:8645. It does
nothing untilSHORTCUTS_TOKENis set and the plugin is enabled, and it refuses to start with a missing, short
(< 32 chars), repetitive or placeholder token. Binding a non-loopback address needsSHORTCUTS_HOSTand
SHORTCUTS_ALLOW_PUBLIC_BIND=true; don't do that, use a tunnel or proxy with HTTPS (plain HTTP leaks the token). - The token is the only identity. Every request arrives as the single user
owner;SHORTCUTS_ALLOWED_USERS=owner
just satisfies the gateway allowlist. There are no per-person accounts: anyone holding the token acts as you, so never
give it to anyone, and use one Hermes install per person. - What a request can do: it runs a normal agent turn. With the default
SHORTCUTS_TOOL_PROFILE=safe, shortcuts
turns only get the toolsets their action needs (table above): no terminal, file, code execution, browser,
computer-use, delegation, skill writing or MCP tools, enforced twice (see Per-action toolsets). Withfull, a token holder (or a prompt injection in a page you shared)
gets your gateway's full toolset, including the terminal on your server, and cron jobs it creates run later with
your cron toolset (terminal included). Only switch tofullif you need it. - Approvals are never bypassed or auto-approved. This surface has no approval buttons and
/approveis disabled here,
so a command that needs approval waits for the approval timeout and is then denied. Note that Hermes only asks for
approval for commands it considers dangerous; ordinary commands (e.g.curl) run without asking, which is why the
safeprofile removes the terminal entirely. - Untrusted input / prompt injection: links, PDFs, images and text you share can contain instructions aimed at the
agent. Shared content is fenced with a random per-request marker, fence-like text inside it is neutralised, control
characters are stripped, text is capped at 8,000 chars, and slash commands / gateway control are disabled
(allow_gateway_control=False). @-references are defanged: Hermes core expands@file:,@folder:,@url:,
@git:,@diffin every inbound message before the agent runs (no tool call, so no tool policy applies), relative to
the gateway's working directory; in shared text the plugin turns@into@so a shared note cannot pull e.g.
~/.hermes/logs/gateway.log(your Telegram message previews) into the turn./v1/sharewithaction=askis run as a
fencedautoturn. Fencing reduces but cannot eliminate injection; the restricted toolset is what limits
the damage. Hermes' own web tools block private/internal addresses (SSRF), but in thefullprofile the agent can
still reach them through the terminal. Stored injection:rememberwrites shared content into long-term memory, and memory is part of the
system prompt of every later session, including Telegram/CLI sessions that have the terminal. Userememberonly
on content you trust and review~/.hermes/memories/now and then.remindstores (part of) the shared content as
the cron prompt; jobs created from the phone run with no tools, so at worst they deliver odd text. - Exfiltration: every turn sees your memory and user profile (as on every platform). A malicious page could try
to make the agent put that text into aweb_extract/web_searchURL. The safe profile keepssession_search
(your whole chat history) out of every action, and events get no web tools. - Link previews (zero-click): Telegram fetches a preview of the first link in a bot message from its servers, so a
URL in a forwarded reply is fetched without you tapping it. The plugin puts every URL of a forwarded reply in a code
span (no link, no preview) and shows hidden markdown links astext (url). Also set
platforms.telegram.extra.disable_link_previews: trueinconfig.yamlto cover Telegram replies from other sessions. - Limits: uploads ≤ 15 MB per request and 200 MB per hour (configurable), ≤ 4 files, 20 requests/min, 3 concurrent,
auth-failure lockout (10 failures / 5 min per client, which never locks out the valid token). Images are
type-sniffed by magic bytes; HEIC is rejected; document names are reduced to a safe basename. Files from a rejected
request are deleted. - Privacy / data: shared content goes to your LLM provider like any message. Uploaded files are written to Hermes'
media cache (~/.hermes/cache/…, pruned after ~24 h). Every request is a fresh gateway session
(agent:main:shortcuts:dm:sc-…) kept in Hermes' session database (state.db) like your other chats. The plugin never
logs the token or request bodies, but Hermes core logs a short preview (~80 chars) of every inbound message and the
URLs its web tools fetch, as on every platform. Replies are forwarded to your home channel unlessnotify=false. - Outbound: replies go only to your own home channel on
SHORTCUTS_NOTIFY_TARGET(Telegram by default) through the
live gateway adapter; anything Hermes delivers to theshortcutshome channel (e.g. cron output) is forwarded there
too. The plugin makes no other network calls, has no telemetry and no self-update. - Credentials are read only through
agent.secret_scope.get_secret. The plugin never reads.envor credential files. - Pairing CLI:
hermes shortcuts pair(registered withregister_cli_command) prints the URL and a QR code that
contains the token. It never logs the token and prints it as text only with--show-token.--pngfiles are written
0600 without following symlinks. To find a quick-tunnel URL it queries only cloudflared's local metrics endpoint
(127.0.0.1:20241-20245/quicktunnel, no proxy). The QR is rendered by a vendored copy of Project Nayuki's MIT-licensed
pure-Python QR generator (_qrcodegen.py), so pairing installs nothing.
Your token on the phone
- With pairing (recommended): Hermes Setup stores the URL and token in plain text in
iCloud Drive/Shortcuts/hermes.json. The shortcuts themselves contain no token, so sharing or publishing a
shortcut never leaks it. Trade-offs, honestly:- The file syncs to iCloud and your other Apple devices, like everything in iCloud Drive. Apple holds the keys
unless you turn on Advanced Data Protection (Settings → your name → iCloud), which makes iCloud Drive
end-to-end encrypted. Shortcuts' Save File / Get File actions work in the Shortcuts folder of iCloud Drive, and
you can't pick a device-only location for it while iCloud Drive is on (with iCloud Drive off, the folder lives
On My iPhone). The manual alternative, pasting the token into each shortcut, is no better: the shortcuts sync
through iCloud too (also end-to-end only with ADP), and the token travels with every shortcut you share. - Any shortcut on the phone that you allow to read files in the Shortcuts folder can read
hermes.json. Only
install shortcuts you trust, and deny file access to ones that don't need it. - The QR code shown by
hermes shortcuts pairholds the token. Don't screenshot or photograph it, clear the
terminal afterwards, and delete any--pngfile.
- The file syncs to iCloud and your other Apple devices, like everything in iCloud Drive. Apple holds the keys
- Manual setup (no Setup shortcut): iOS Shortcuts stores header values in plain text inside the shortcut.
Sharing such a shortcut (iCloud link, AirDrop, file) shares your token with it. - Android HTTP Shortcuts keeps variables in the app's data, and app exports/backups contain them. Don't share
export files, and exclude thetokenvariable when exporting. - Never put the token in the URL. The plugin rejects tokens in query strings, and URLs end up in logs.
Rotating the token (do it if a phone is lost, a shortcut or QR was shared, or the token leaked)
- On the server:
hermes config set SHORTCUTS_TOKEN "$(openssl rand -hex 32)", thenhermes gateway restart. The
old token stops working immediately, including any old QR code and anyhermes.jsoncopy. - Run
hermes shortcuts pairand re-run Hermes Setup on each of your phones (it overwriteshermes.json).
With manual setup, update theAuthorizationheader in each shortcut or the HTTP Shortcuts variable instead. - If you use Cloudflare Access, also rotate the service token in the Zero Trust dashboard.
Development
cd tests && python3 -m pytest -q # unit + adapter tests (auth, lockout, toolsets, uploads, fencing)
hermes plugins validate ./hermes-shortcuts
hermes plugins doctor ./hermes-shortcuts --ci
Layout: plugin.yaml, __init__.py (exports register), adapter.py (gateway platform adapter and aiohttp listener),
actions.py (presets, prompt fencing, token and rate-limit helpers), pair.py (hermes shortcuts pair),
_qrcodegen.py (vendored QR generator, MIT), tests/, plugin-catalog/hermes-shortcuts.yaml (draft catalog entry).
License: MIT
README from the reviewed commit 241441e; it updates when the author re-pins.

sergo565456