Current runtime: native Hermes chat, optional cloud delivery only. The
production platform adapter does not construct a Link chat client or start its
paired Direct listener, even when old cloud credentials remain configured.
Native APIs use the dashboard address and authentication already configured by its operator, including no-sign-in dashboards. Legacy Link protocol details below are
retained for compatibility tests and existing data; they are not a production
chat transport. Native voice uses /api/plugins/loopdy/native/voice/* for media
control and the app's ordinary Hermes chat for work.
Loopdy is a native Hermes platform for the Loopdy mobile app. It provides authenticated native integrations, optional notifications, lifecycle events, media control, and Generative UI. Hermes remains authoritative for agents, sessions, scheduled tasks, policy, event details, and transcripts.
Direct-first native clients use stock authenticated hermes serve REST and /api/ws.
The plugin's native HTTP foundation adds verified
host-grant or provider-person/process-profile context and fixed data-only card-template routes without a
Loopdy account. Existing forms, attachments and host-granted Files routes are
reused. Native Wiki uses verified Hermes login and
principal/profile-scoped connections, without another pairing or device-key
ceremony. Native iPhone tools use a foreground device channel on the same Hermes dashboard
connection. Personalized hosted-group context retains its separate provenance gates.
Supported current-main hosts can also expose opt-in, view-scoped
room tool observations, with explicit loss/reset
semantics rather than durable replay or inferred tool success.
The older paired Direct listener and direct APNs provider are different
features and do not provide this native authentication path.
Native chat prompt attachments are files-only. Native prompt images remain unavailable until an official message-bound image surface is verified. Existing Wiki image reads and assistant artifact/image downloads do not authorize image uploads into native prompts; there is no custom image-upload shim or fallback.
Native Project Git provides fixed read-only capabilities/status/diff for an exact registered Project and stored session, including proven hidden canonical Bot Chat. It reuses content-derived tokens and bounded side-specific diffs; incomplete status and unsupported conflict diffs fail explicitly. No Files grant or Git mutation is created.
Native workspace operations use Hermes REST and /api/ws. The host does not
open an outbound cloud WebSocket for chat or depend on a cloud device catalog.
Cloud notification enrollment is a separate opt-in operation.
Scheduled-task output choices come from Hermes' own cron delivery-target catalog. Loopdy accepts enabled catalog targets or a validated canonical platform:chat_id[:thread] value and sends that value through the official cron deliver field.
For optional push-notification delivery, the plugin exposes two provider choices. These are not native chat transport choices, and neither is required for native Hermes login or workspace access:
relay, the default: a managed HTTPS relay forwards encrypted alerts to APNs. The relay is an authenticated delivery service only; Hermes remains authoritative for sessions, policy, and the local notification ledger.direct: the Hermes host signs requests with the user's Apple developer key and sends them directly to APNs.
The older managed Expo provider remains accepted for stored registrations and command-line
compatibility, but the app does not offer it for new selection.
All notification provider modes support proactive messages even when no chat session is active.
Loopdy 2.14.0 supports the Hermes 0.21.1 baseline as well as 0.21.2. New
optional features use the runtime's published capabilities, rather than making
the entire plugin require the newest Hermes release. The manifest lists baseline
hooks; room-member activity is registered only when Hermes advertises
on_room_member_activity in its supported hook registry.
On a runtime without that hook, the native context omits room activity and its routes return an explicit unavailable response. Core plugin registration, chat, approvals, and card tools remain available. On a runtime with the hook, the full room-activity feature remains enabled. Doctor may report that this optional hook is registered without a manifest declaration; it still validates the hook name and callback against the real runtime. No scanner or Doctor checks are bypassed.
Run test_runtime_compatibility.py and test_plugin_update_installation.py with
each supported Hermes checkout, including the oldest supported one. These use
real runtime discovery and the supported installer in disposable profiles. The
app's native workspace protocol has its own host capability requirements;
plugin compatibility does not imply every newer Hermes API exists on an older host.
The plugin also uses the current public module locations for configuration, model options, skills, MCP, and scheduled-task delivery. These locations exist on both supported runtimes. Compatibility tests exercise Doctor with the legacy import removal policy enabled; no deprecated-import override is required.
Ordinary Link chat does not require the optional Hermes ToolExecutionContext
extension. The adapter adds the runtime-only context argument only when the host
exports its context type and MessageEvent accepts that field. Hosts without
both parts keep normal chat, attachment and busy-input routing. Native iPhone
Health, Calendar, and Reminders tools use Hermes' public tool_execution
middleware when available, with the actual session, turn, and tool-call IDs.
The plugin advertises native-device-tools-v1 only when that integration is
registered. It does not reconstruct tool authority from model arguments or
require a Hermes core patch.
Codex Live Voice needs the Loopdy plugin and a Codex subscription signed in on the Hermes host. The iOS Voice settings page checks the selected host and offers to install or enable the plugin. Delegated work uses the ordinary native Hermes chat connection; notifications are optional.
Device access settings offer the same plugin setup for Health, Calendar, and Reminders. Plugin installation grants no iOS permissions. The user separately chooses which data and operations to allow on this iPhone for the selected host. Keep Loopdy in the foreground while an agent uses the phone. Closing the chat, changing hosts or permissions, locking the device, or moving to the background retires its device channel. An expired or uncertain phone request is not replayed. No cloud account, relay, or notification enrollment is required for this channel.
Fixes immediate delivery_uncertain failures after iPhone permissions and query
validation succeed. Hermes executes async tools on worker event loops, while the
paired Link connection belongs to the gateway loop. The bridge now schedules
the complete request/result operation on that connection's loop, including its
send lock, pending futures and response correlation. Disconnect and permission
revocation still invalidate waiting calls.
Update the host plugin and restart its gateway to activate the fix. The current iOS build and granted permissions remain compatible. Regression coverage uses the registered Health handler, a separate worker thread, the real encrypted Link client and a contended send lock; a single-loop fake client cannot catch this bug.
Fixes invalid_arguments before a valid iPhone Health request reaches the phone.
Hermes supplies composite session:task:nonce turn IDs; the plugin now preserves
those IDs in requests and replies instead of rejecting their colons. The same
correction applies to Calendar and Reminders. IDs remain bounded to 512 bytes,
and authenticated ownership and exact reply correlation remain required.
Update the host plugin to activate this fix. No new iOS build or permission reset is required. Regression tests cover the registered tools through the real bridge, the observed Health query formats, mismatched replies, and identifier bounds.
Adds iphone_health, iphone_calendar, and iphone_reminders through the
existing end-to-end encrypted Loopdy Link connection. Each capability is off by
default and must be enabled independently in Loopdy on the originating iPhone.
Health is read-only; Calendar and Reminders support bounded list, create, update,
and delete operations. The phone must be foregrounded, unlocked, connected, and
selected for the authenticated Hermes host.
Requests are directed to one verified phone and bind its authorization epoch,
selected host, agent, session, turn, and tool call. The transport has no broadcast
fallback. Updates and deletes require an exact item plus its expected revision;
mutation identities and bounded outcomes are journaled to prevent blind duplicate
writes, while Health, Calendar, and Reminder read contents are not retained in the
plugin. This release requires the matching Hermes ToolExecutionContext runtime
support and a Loopdy build advertising directed-frames-v1. See
iPhone device tools for the full security and privacy
architecture.
Adds agent-scoped voice_settings.get and voice_settings.set over the existing
encrypted workspace transport, advertised by voice-settings-v1. Loopdy iOS
2.0.1 (11) uses these for OpenAI and ElevenLabs provider, Voice ID, and API key
settings. Hermes remains the synthesizer and owns provider selection, profile
configuration and credential persistence. No new HTTP service or direct iOS
provider integration is introduced.
Reads expose the current provider and key-presence flags, never key material. Writes require the loaded revision and explicit confirmation; an omitted/blank key preserves the saved credential. Profile ownership, concurrent changes, readback and no-op behavior are validated before reporting success. The next synthesis uses saved settings without a restart. Installing this plugin version still requires the normal gateway activation step.
Project Git returns project_not_repository only for a confirmed non-repository
folder. The app presents N/A without Retry. git_unavailable, unsafe configuration,
timeouts and actual repository failures retain their distinct errors.
Repairs Scheduled Tasks after Hermes moved its cron workers into
hermes_cli.web_routers.cron and hermes_cli.web_server_cron. List, create,
edit, pause, resume, run and delete keep using Hermes' own workers. The compatibility
regression imports the installed Hermes modules and exercises every bridge so a
successful app build cannot hide a broken host import.
The plugin must be installed and activated on the selected Hermes host; an iOS update alone does not repair the scheduler bridge.
Adds the official Hermes hosted-room groups.* operations to authenticated
Loopdy Link workspace control for Loopdy iOS 2.0.1 (9). Hermes owns room execution,
typed history, task retry and stop. Clients must negotiate protocol 2 and a
running driver before enabling Bot Mode. This does not implement or replace the
separate Loopdy Native harness under development.
Publish and activate the plugin separately from the iOS TestFlight build. Use
hermes loopdy update --restart and verify the completed updater receipt plus
live groups capabilities. Existing account, Wiki and activity fixes are retained.
This release aligns the host with Loopdy app 1.8.0: exact-call generated image and video resolution, agent artifacts up to 25 MiB, complete Markdown/text Project previews, and statically registered card-template workspace operations. Phone uploads retain their separate 8 MiB/file and 24 MiB/message limits. See Generated media for the host-side contract.
The standalone plugin retains context/cache reporting through Hermes' public
post_api_request and on_session_reset hooks, explicit read-only workspace
Files grants, the restart-safe updater, and Marketplace release trust. Publishing
this source does not install or activate it on a Hermes host. Compatible app and
host activation remain separate release steps.
The plugin can expose explicitly granted workspace folders through a read-only host CLI and authenticated plugin API. Browsing includes unchanged files, directory-local name search and revision-bound file reads. Git inspection reuses the fixed-command engine with mutation permissions disabled. No folder is exposed until a host operator grants it, and the feature does not access private Hermes Project/session databases.
This is the plugin foundation, not an enabled mobile Files screen. App and encrypted Link wiring follow review and merge. Capable POSIX hosts are supported first; hosts without secure descriptor-relative traversal fail closed. See Workspace Files for the contract, security limits and examples.
model-names.json is a data-only catalog for friendly model labels. In a compatible app, Settings → Connectivity → Update Model Names fetches the latest catalog from this repository without installing plugin code or restarting the gateway. A bundled fallback and the last valid cached catalog remain available when offline or when an update fails.
The version-1 JSON object contains version, revision, and a models mapping from exact model IDs to display labels. For example, "gpt-6-astra": "GPT-6 Astra". Keep model IDs unchanged. This catalog changes names, not which models a provider offers. Clients validate the full response (256 KiB maximum; 2,000 entries; IDs up to 256 characters and labels up to 100) before replacing their cached data.
After installing a version that includes the updater:
hermes loopdy update
hermes loopdy update-status
hermes loopdy update --restartThe updater resolves this repository's main to an exact commit, checks the recognized existing installation, scans and validates the candidate, backs up the prior plugin, and uses Hermes' pinned installer. Pairing, credentials and configuration remain in place. Added privileged capabilities require a separate attended host approval. Modified or unrecognized installations are refused instead of overwritten.
Without --restart, the command reports installation separately from activation. With it, one gateway restart is requested. Status survives that restart; timeouts remain unconfirmed rather than causing another restart. A compatible paired-Link app exposes Update Loopdy Plugin in Settings with an interruption warning and checks the same durable operation until the exact new plugin runtime and authenticated Link response are verified. This Link updater contract is not a requirement for native HTTP connectivity. Closing and reopening the app does not start another update.
This optional update flow needs macOS launchd or Linux user systemd. Windows and unsupported/shared-installation layouts fail closed. Earlier plugin releases require one host-side installation before the new app control can work.
Install and enable the plugin in the active Hermes profile:
hermes plugins install promptclickrun/loopdy-plugin --enable
hermes gateway restartFor a committed local checkout:
macOS or Linux shell:
hermes plugins install "file://$PWD" --enable
hermes gateway restartWindows PowerShell:
$repo = [System.Uri]::new((Get-Location).Path).AbsoluteUri
hermes plugins install "$repo" --enable
hermes gateway restartHermes' file installer reads Git content, so local plugin changes must be committed first.
The plugin supports Hermes on Linux, macOS, and Windows, with individual features
gated by host capabilities. It uses Hermes' own Python dependencies and
profile/config writers and stores data under the active Hermes home directory.
Paired Link chat uses outbound HTTPS/WebSocket connections without an inbound
listener. Native HTTP routes use the operator-configured stock hermes serve
listener and native authentication; they do not start another listener.
The optional paired Direct listener is separate and still uses account lifecycle
leases, as described in Direct streaming.
Optional self-update
uses a separate launchd job on macOS or a user systemd unit on Linux so it can
survive gateway restart; self-update is unavailable on unsupported hosts.
Long-running process management remains the responsibility of the normal Hermes installation.
For native use, connect to the selected stock Hermes endpoint and authenticate
with that host's native login. No Loopdy account or Link pairing is required.
Installation and activation of the plugin in the serving process remain
separate operator actions; the gateway commands above describe platform-adapter
activation, not proof that an existing hermes serve process reloaded it.
To use Link instead, create or sign in to the minimal passkey-backed Loopdy account in the app, then start host pairing:
hermes loopdy link pairThe command prints a short-lived code, pairing URL, and separate 16-character host-key verification code. In Loopdy, open Settings → Loopdy Link → Pair a Device. QR pairing carries the full host-key commitment; manual pairing requires both the six-character code and the separate verification code. The app recomputes that commitment from the inspected host signing and agreement keys before it releases the account key. Pairing also reconciles APNs registration for that iPhone or iPad and pins Loopdy Link's wake-relay signing keys. That account-scoped wake channel is independent of the host's optional notification-relay tenant, so no shared relay credential is installed on Hermes. After storing the host credentials, the pairing command asks the official Hermes lifecycle command to activate the gateway automatically. No additional app or gateway configuration is required.
These commands are optional diagnostics if connectivity does not become ready:
hermes loopdy link status
hermes loopdy statusPair each additional Hermes host independently. All phone, tablet, and host devices can be named, renamed, inspected, and revoked from the same Loopdy account.
Signed Loopdy builds include a Notification Service Extension. Ordinary alert copy arrives as an encrypted payload and is shown only after the extension validates the pinned relay sender key, signature, recipient key, authenticated metadata, and bounded plaintext. Verification failure keeps the generic fallback notification and never exposes unverified content.
Verify the optional Loopdy notification channel:
hermes loopdy status
hermes loopdy test --target allDirect mode is optional. It requires an Apple Developer account, a signed app build for the configured bundle ID, and a P-256 APNs token key stored on the Hermes host. The key file must be owner-readable only.
The values below are placeholders. Use identifiers from your own Apple Developer account and never commit an APNs key.
chmod 600 /private/path/AuthKey_KEYID12345.p8
hermes loopdy configure-apns \
--team-id TEAMID1234 \
--key-id KEYID12345 \
--topic app.example.loopdy \
--environment production \
--key-path /private/path/AuthKey_KEYID12345.p8
hermes loopdy status
hermes loopdy test --target allSelect direct delivery after configuration with:
hermes loopdy provider directRelay mode is the app default and is designed for hosts that cannot receive inbound connections. Configure
the relay origin, tenant, and references to owner-controlled HMAC/signing-key material in the active
Hermes profile. Secret references are resolved on the Hermes host and are never sent to the mobile
client or written to relay request bodies. Plugin release 2.3.0 carries Link and relay wire version 1;
the two version layers are independent. An authenticated encrypted user.message may include the
optional wire-version-1 behavior value steer, queue, or interrupt. The adapter maps those values
to Hermes' registered platform controls, preserves normal approval and clarification interception, and
uses the normal message path when the field is absent. The relay uses authenticated HTTPS,
revisioned/idempotent device and tenant operations, and encrypted ordinary alert payloads. Live
Activity state is deliberately sanitized and contains no message text, credentials, or filesystem
paths.
Workspace selection follows Hermes' native lifecycle semantics. A new Loopdy chat seeds its selected
Project path before the first turn without creating an empty stored session. Moving an existing chat
updates its persisted CWD, updates the live terminal/file-tool CWD immediately, and invalidates the
cached agent so the next turn rebuilds from the moved Project context. A tool call already in progress
finishes in the directory where it started, matching session.workspace.move.
The native Swift client starts one ActivityKit activity per active session, registers its push token through Loopdy Link, projects bounded reasoning/tool/delegation progress, and revokes the activity when the final response settles or the account boundary closes. Sanitized state is server-readable while the Worker builds the APNs payload; prompts, tool arguments, attachments, credentials, and complete model output are excluded.
Relay registration, acknowledgement, revocation, delivery, and Live Activity operations are
authenticated, origin-bound, and fail closed on invalid revisions or response coordinates. A relay
response is accepted only for the operation that created it. Removing or replacing local relay
configuration disables existing local relay routing until devices are explicitly registered for the
current configuration; it does not silently revoke remote tenant state. Explicit tenant revoke and
delete operations update local tombstones only after a valid relay response.
Use the base app bundle identifier as the registration topic; the provider appends
.push-type.liveactivity exactly once when sending a Live Activity update.
The relay stores only the minimum encrypted delivery data needed to forward a request and does not replace Hermes history or approval storage. Ordinary alert copy is end-to-end encrypted, while sanitized Live Activity state is visible to the Worker during APNs submission. See PROTOCOL.md, SECURITY.md, and the repository security and privacy inventory for the complete public trust boundary and data-flow description.
Remove the saved direct configuration with:
hermes loopdy remove-apns --yesLoopdy registers a normal Hermes platform named loopdy with these targets:
alldevice:<id>group:<id>
Examples:
hermes send --to loopdy:all "Task completed"
hermes send --to loopdy:device:phone-123 "Review requested"Scheduled tasks can use deliver="loopdy". LOOPDY_HOME_TARGET selects the default target and defaults to all. The standalone sender uses the same local device registry, provider configuration, preferences, quiet hours, and delivery ledger, so it does not require a live chat session.
When a card answers the current Loopdy conversation, call the renderer on that
active conversation response path. The validated result returns to the open
chat as part of its turn. Do not use the notification channel just to answer the current chat, and do not target loopdy:all or a device merely to render it.
For an ordinary proactive channel message or a scheduled task, explicitly
target the loopdy platform. No script or extra API is needed: call one
registered loopdy_render_* tool and make its exact validated returned envelope
the complete delivered content, with no Markdown fence or additional prose.
Hermes' official channel boundary passes the adapter only that final content and
normal metadata such as cron job_id; an earlier inline renderer result does not auto-forward to the channel. The adapter revalidates complete envelopes before
persisting and pushing cards, while invalid or missing cards safely fall back to
text. Never script or reconstruct an envelope; forward the exact official
renderer return value. The installed loopdy:generative-ui skill contains both
pathways, their decision rule, and scheduled/ordinary channel examples.
A scheduled prompt must explicitly require the final response to be the
exact renderer-returned JSON. A sentence such as "card delivered" is only text,
not a delivery receipt. Keep [SILENT] as the complete final response when the
job's existing silence policy applies; do not render a card in that branch.
The dashboard.load response validates events[].detail.generative_ui as an
independently bounded renderer document. Its containing arrays do not consume
the card's depth budget. Secret-key screening, generic workspace limits, and the
aggregate response byte cap remain in force. Invalid optional cards are omitted
from the response copy without changing the stored event or unrelated data.
The plugin registers loopdy_render_summary, loopdy_render_metrics, loopdy_render_list, loopdy_render_timeline, and the typed v2 renderers as first-class Hermes model tools. When the exact renderer is visible in the current tool list, agents call it directly. When Hermes has hidden it through progressive disclosure, agents use the official progressive-disclosure bridge—tool_search, tool_describe, and tool_call—to find and invoke that exact renderer. A visible renderer should not be needlessly routed through the bridge, and a different tool must never substitute for it.
The read-only namespaced skill loopdy:generative-ui documents selection guidance and bounded payload examples. Hermes can load it with skill_view("loopdy:generative-ui"); installation does not copy or modify the user's ordinary skill directory.
loopdy_render_card accepts one display-only loopdy.card version 1 document
built from the finite native component catalog. Build 3 supports static Cards
only: all displayed values must be embedded in the payload and data_sources
must be empty. The plugin rejects live sources, unknown fields, components,
bindings, expressions, formats, broken trees, and bounded-size violations. It
canonicalizes a valid input, adds content_hash, card_id, created_at, and
origin, then returns the exact result through the normal generated-interface
path. Do not reconstruct the renderer result or mix it with prose.
The app receives the original static Card once through encrypted Loopdy Link, validates it again, and renders its embedded values natively. Opening a Card makes no third-party Card data request. Live Card refresh remains reserved for a later security-reviewed release.
Template bundles remain declarative data. Encrypted workspace operations
cards.templates.list, cards.templates.install, and
cards.templates.remove synchronize reviewed installs between the app and the
profile-scoped plugin store. The generic template tools are
loopdy_search_card_templates, loopdy_get_card_template, and
loopdy_render_card_template; all rendered output still passes through
loopdy_render_card. Templates cannot install native code or expand the v1
component catalog. No production template catalog URL is configured.
Marketplace support adds the static marketplace.skills.install and
marketplace.skills.status workspace operations. Install requests contain only
the selected agent, immutable item/version/digest, short-lived approval, and
request IDs; they cannot supply a URL or filesystem destination. The host
redeems approval with its existing signed Link identity, fetches release bytes
only from the paired Link origin, verifies the exact Ed25519-signed manifest and
artifact digest, and installs through Hermes' profile-aware Skills Hub CLI.
Name conflicts and locally installed skills are never replaced. A receipt is
returned only after Hermes reports the marketplace skill in the selected
profile.
The plugin bundles the public release trust anchor for the official Loopdy
marketplace. LOOPDY_MARKETPLACE_TRUSTED_ED25519_KEYS, when explicitly set,
replaces that set with a JSON object mapping key IDs to padded standard-base64
32-byte Ed25519 public keys. Set an empty string to disable marketplace release
trust. Invalid overrides fail closed; they do not fall back to bundled keys.
These are public verification keys, never private signing material. A paired
Link socket advertises cards-templates-v1; it adds
marketplace-skills-hub-v1 only when at least one valid trust anchor is
configured. No fixture key is trusted. Backend enablement and plugin activation
remain separate from merging this source for the coordinated release.
The read-only namespaced skill loopdy:loopdy-marketplace-publish guides
agent-assisted private draft preparation. For a selected theme attachment or
saved card template, loopdy_marketplace_prepare_upload supports a no-network
validateOnly pass followed by private draft creation and exact readback in
Loopdy Marketplace > My Uploads. It exposes no submit or publish operation.
Skill uploads use the app's reviewed package picker because Hermes does not
provide a supported non-preprocessed raw skill export API. Secrets, unsafe
paths, live card sources, undeclared scripts, invalid theme palettes, binaries,
archives, and size-limit violations block upload.
See the repository Loopdy Cards guide and the wire protocol for the complete example, component table, static-data policy, visible error states, lifecycle, and legacy compatibility.
Loopdy Cards credits Sameer Gupta's
Generative UI DSL for the
constrained JSON-tree and fixed native component-catalog approach.
Google A2UI and
json-render are related designs only. Loopdy does
not claim adoption, endorsement, API compatibility, or copied code from any of
these projects.
Loopdy provides Hermes-parity delivery for assistant-generated images and files. The mobile client resolves assistant history through the authenticated plugin API, displays images inline, and presents other artifacts as named file cards. Downloads use the existing dashboard authentication headers or cookies with redirects disabled for token-bearing requests. Gateway credentials and local source paths are never placed in attachment URLs or returned to the client.
These are host-to-client reads, not a native image-message upload contract. Native prompt attachments remain files-only; Wiki and artifact image reads do not change that boundary.
Hermes native send_image_file, send_document, send_video, and send_voice callbacks are projected
through the same policy-backed resolver. This covers media dispatched separately after streamed text;
the iOS client resolves both request-owned finals and later unsolicited attachment messages before
rendering them.
Resolution delegates extraction, extension routing, and path authorization to Hermes' public BasePlatformAdapter media API. The active Hermes settings remain authoritative, including gateway.strict, gateway.media_delivery_allow_dirs, gateway.trust_recent_files, and gateway.trust_recent_files_seconds. Their runtime environment equivalents (HERMES_MEDIA_DELIVERY_STRICT, HERMES_MEDIA_ALLOW_DIRS, HERMES_MEDIA_TRUST_RECENT_FILES, and HERMES_MEDIA_TRUST_RECENT_SECONDS) are honored by the same adapter.
Approved artifacts are copied into a profile-scoped durable cache and addressed by opaque IDs. This lets reopened sessions retrieve attachments without retaining or disclosing the original filesystem path. Requests are bounded to 200 message items, 100,000 aggregate UTF-8 text bytes, 20 attachments per item, 25 MiB per artifact, and 240 UTF-8 bytes per display filename. Each profile cache is capped at 500 artifacts or 250 MiB and evicts the oldest entries first. Missing, denied, stale, malformed, and oversized references fail closed.
Native workspace clients use Hermes' supported native approval operations and their exact offered scopes. They do not need to select the optional Loopdy approval transport below. Installation does not activate that transport; to opt in for the Loopdy platform, configure the active Hermes profile:
security:
approval:
transport: loopdy
transport_fallback: denyRestart the process that runs Hermes sessions after changing configuration. Loopdy preserves the exact approval scopes offered by Hermes: once, session, always, and deny. The app never invents a scope that Hermes omitted. Missing, expired, duplicate, unoffered, or digest-mismatched responses fail closed.
hermes loopdy status
hermes loopdy link pair [--base-url https://link.loopdy.app]
hermes loopdy link status
hermes loopdy link unpair --yes
hermes loopdy provider [relay|direct]
hermes loopdy configure-apns --team-id ID --key-id ID --topic BUNDLE_ID --environment production|sandbox --key-path PATH
hermes loopdy remove-apns --yes
hermes loopdy recover-terminal-relay-registration --yes
hermes loopdy test [--target TARGET]
status reports only token fingerprints and the APNs key filename. link status reports only the public origin, opaque device ID, authorization epoch, and connection state. Neither command prints device tokens, account keys, private keys, private-key paths, or key contents.
recover-terminal-relay-registration --yes is a bounded, local-only repair for an exact legacy
terminal registration conflict that already has a stored relay response. It revalidates the current
relay generation, request/response coordinates, and local sender-key pins before applying that
response. It never contacts the relay and prints aggregate counts only.
Hermes mounts the established routes below under its normal dashboard
authentication policy. Additional /native/* routes and their stricter verified
interactive Session/context requirements are documented in
Native workspace API; they do not borrow Link
credentials.
GET /api/plugins/loopdy/capabilities
GET /api/plugins/loopdy/provider
PUT /api/plugins/loopdy/provider
GET /api/plugins/loopdy/devices
POST /api/plugins/loopdy/devices
DELETE /api/plugins/loopdy/devices/{device_id}
PUT /api/plugins/loopdy/devices/{device_id}/preferences
POST /api/plugins/loopdy/test
GET /api/plugins/loopdy/events
GET /api/plugins/loopdy/events/{event_id}
GET /api/plugins/loopdy/approvals/{approval_id}
POST /api/plugins/loopdy/approvals/{approval_id}/respond
POST /api/plugins/loopdy/attachments/resolve
GET /api/plugins/loopdy/attachments/{attachment_id}?profile={profile}
See PROTOCOL.md for request contracts and SECURITY.md for trust boundaries.
Run the suite with an isolated HERMES_HOME and a real temporary directory outside
any Git worktree. On macOS, use /private/tmp rather than its symlinked alias;
otherwise filesystem-security fixtures correctly reject the parent path. Tests
must not inherit a live profile's paired connection or personalization.
From this repository's root, run the deterministic offline suite with the Python environment bundled with Hermes:
HERMES_HOME=/path/to/disposable-profile TMPDIR=/private/tmp \
PYTHONPATH=/path/to/hermes-agent:"$PWD":"$PWD/tests" \
/path/to/hermes-agent/venv/bin/python \
-m unittest discover -s tests -v
hermes plugins doctor . --ciNative Wiki uses verified Hermes principal/profile authority without extra pairing; its exact routes, cross-device ownership and explicit disconnect are documented in Native Wiki. It does not adopt Link grants. The following account-scoped behavior applies specifically to paired Link:
A compatible paired-Link app can use Add Wiki to browse/type an existing safe folder and Save an account-scoped read/write connection through wiki.connect, without separate host approval or a Wiki device allowlist. The operation must be advertised alongside wiki.v1; older hosts require a plugin update. Hosts without secure descriptor-relative traversal, including Windows, omit Wiki operations. Explicit selection creates an account connection or upgrades an existing exact same-authority/profile file grant, rotating its generation when permissions change. wiki.resolve, reads, directory suggestions and Files grants do not create or upgrade Wiki access. Generated, mirrored and exported sources remain read-only. Nested Markdown is discovered by bounded recursive search.
On hosted installations with a custom, non-credential-named Hermes home such as /opt/data, an ordinary Wiki subfolder can be selected directly from the authenticated app. The host home itself, its ancestors, credential/system folders and host-control subtrees remain excluded. The standard ~/.hermes tree and other credential/control-named paths remain ungrantable. Directory identity, profile/authority isolation, overlapping grants and symlink protections still apply. Enter the canonical absolute folder path without a trailing slash; the request contract does not normalize paths. The durable account connection is available to replacement devices on that same paired account; device identities still fence individual in-flight save operations, not Wiki access.
References opens with a bounded recursive file catalog for connected Wikis, even without a typed query. It visits at most eight roots and 32 directories per browse, includes up to 100 visible results, and reports incomplete discovery. Ordinary non-Markdown files offer File location only: JSON source path and size metadata, never decoded or ingested binary contents. Selection and send-time checks re-list the parent directory against the live grant, with at most ten revision-bound pages. The snapshot revision identifies parent directory metadata (including the file's identity/stat), not a content digest. Markdown retains explicit page/section content selection.