From Hermes to Flowly
register(ctx) entry point, the same hook event names, the same registration methods. Most Hermes plugins port over with import-path and conventional-path renames, no logic changes.What changes
The differences fall into four buckets:
| Concern | Hermes | Flowly |
|---|---|---|
| Imports | hermes_cli.*, plugins.* | flowly.*, .* (relative) |
| Home dir | $HERMES_HOME | $FLOWLY_HOME |
| Temp paths | /tmp/hermes-* | /tmp/flowly-* |
Manifest kind | backend / standalone / exclusive | standalone (only one supported) |
BlockAction, RewriteAction, SkipAction) are 1:1 with Hermes. Hooks don't need rewriting.Imports
Most Hermes plugins do absolute imports against their own package:
# Hermes
from plugins.spotify.tools import SPOTIFY_PLAYBACK_SCHEMA, _handle_spotify_playback
from plugins.spotify.client import SpotifyClient
from hermes_cli.auth import get_auth_status, resolve_spotify_runtime_credentials
from tools.registry import tool_error, tool_resultFlowly loads plugins under a synthetic namespace, so absolute imports inside the plugin won't resolve. Convert to relative imports for intra-plugin references; replace Hermes core helpers with the Flowly equivalent or inline them.
# Flowly
from .tools import SPOTIFY_PLAYBACK_SCHEMA, _handle_spotify_playback
from .client import SpotifyClient
# Auth helpers don't have a 1:1 in Flowly v1 — see Auth section below.
# tool_error/tool_result are just JSON wrappers; inline them as small helpers.The find/replace pass for most plugins:
# Inside your plugin source
sed -i '' 's/from plugins\.<your-plugin>\./from \./g' *.py
sed -i '' 's/HERMES_HOME/FLOWLY_HOME/g' *.py
sed -i '' 's|/tmp/hermes-|/tmp/flowly-|g' *.pyPath conventions
Replace the home-directory helper:
# Hermes
from hermes_constants import get_hermes_home
def _state_dir() -> Path:
return get_hermes_home() / "my-plugin"# Flowly
from flowly.profile import get_flowly_home
def _state_dir() -> Path:
return get_flowly_home() / "my-plugin"Anywhere your plugin scans for paths inside HERMES_HOME (e.g. disk-cleanup's safety check), update the safety filter to match the Flowly profile-aware home + the new /tmp/flowly-*convention.
def is_safe_path(path: Path) -> bool:
"""Accept only paths under FLOWLY_HOME or /tmp/flowly-*."""
flowly_home = get_flowly_home()
try:
path.resolve().relative_to(flowly_home)
return True
except (ValueError, OSError):
pass
parts = path.parts
if len(parts) >= 3 and parts[1] == "tmp" and parts[2].startswith("flowly-"):
return True
return FalseManifest
Most fields are identical. Two adjustments for v1:
kind: Hermes supportsstandalone,backend, andexclusive. Flowly v1 only supportsstandalone. If your plugin usedbackend(e.g. animage_genprovider), change tostandaloneand lift the runtime registration into yourregister(ctx)directly — Flowly doesn't have a separate backend registry yet.manifest_version: Flowly v1 supports manifests up to version1. Hermes uses the same value, so usually no change.
# Hermes — for an image_gen backend
kind: backend
# Flowly v1 — for the same plugin
kind: standalone
# (and inside register(ctx), invoke whatever your provider needs to do
# to make itself usable — usually just register a tool)Auth & credentials
This is the largest gap. Hermes ships a shared auth layer in hermes_cli/auth.py with helpers for OAuth flows (PKCE callback servers, token persistence, refresh logic). Plugins like spotify import resolve_spotify_runtime_credentials() and never see the underlying flow.
Flowly v1 does not have an equivalent shared auth layer. If you're porting a plugin that uses hermes_cli.auth, you have two options:
- Vendor the auth helpers into the plugin. Copy the relevant functions from
hermes_cli/auth.pyinto your plugin's package. The PKCE OAuth flow is around 200 lines and self-contained. - Simplify to env-var or pre-filled credentials. Drop the OAuth dance and require the user to bring an existing access token via env var or a pre-populated credentials file under
$FLOWLY_HOME/<plugin>/credentials.json. Less polish, much smaller patch.
Already-ported plugins
Two Hermes plugins are already in Flowly's bundled set, both with public source you can read for porting patterns:
disk-cleanup— standalone, hook-only, no auth. Smallest possible port: imports updated, paths renamed, safety filter adjusted. Source atflowly/plugins_bundled/disk-cleanup/.auto-commit— written for Flowly directly but follows the Hermes plugin pattern. Useful as a reference for the audit-log + slash-command + config.json convention if you're porting a plugin that needs persistent state. Source atflowly/plugins_bundled/auto-commit/.
For larger ports (Hermes' spotify, google_meet), the work item count grows but the pattern is the same: imports first, paths next, then auth, then test against an isolated FLOWLY_HOME.