The gateway now ships in the
praisonai-bot package. praisonai serve gateway still works exactly as documented here; for a standalone install see praisonai-bot Migration.gateway.yaml against the running config and restarts only affected agents or channels. The WebSocket server keeps running.
gateway.yaml on disk; the watcher diffs changes and reloads only affected agents or channels while the WebSocket server stays up.
How It Works
Quick Start
1
Run the gateway
2
Edit live
Change agent instructions or a single channel token in
gateway.yaml and save. The watcher applies a selective reload within ~5 seconds (1s debounce). Credential fields can also be secret references ({source, id}) instead of plaintext.3
Trigger reload manually with SIGHUP
Send
SIGHUP to reload without editing a file — useful for orchestration scripts and systemd:Event-driven vs Polling
The watcher prefers event-driven file notifications via the optionalwatchdog package and falls back gracefully to mtime polling when watchdog is unavailable or an observer cannot start.
Both modes apply the same 1s debounce to coalesce rapid saves.
Install
watchdog for faster reload detection:
watchdog is optional — without it, polling continues exactly as before. Install it only when faster reaction times matter.Operator-triggered Reload via SIGHUP
start_with_config installs a SIGHUP handler that runs the same reload_config path as a file-change reload — no shutdown, no dropped connections.
Reload via SIGHUP is best-effort — it is silently skipped on platforms without SIGHUP support (e.g. Windows).
Drain-coordinated Channel Restart
When a reload triggers a channel restart, the gateway drains in-flight turns before bouncing the channel — no mid-conversation cuts. The drain window for reload-triggered restarts is controlled by a new YAML key:Hot-Apply (no restart)
Some config paths are safe to apply in place — the gateway mutates the live subsystem without restarting agents or channels. When the diff only touches these paths, no drain runs, no client sees a blip. An operator raisinggateway.reload_drain_timeout at 3am does not disconnect a live conversation:
gateway.yaml triggers the hot-apply on the next SIGHUP / file save — no restart, no client disconnect, no drain:
Anything not in this registry falls through to the existing restart-based plans — restart is always the safe default for unknown or structural changes. Invalid values (e.g. a non-numeric timeout) are ignored so one bad key never aborts an otherwise-good reload; the applied paths appear in the reload summary line as
hot[...] and in health().reload.changed_paths.
Restart Scope
Each Effect is prefixed with the canonicalReloadScope value that classify_reload(path) returns for that section.
Full restart stops and starts all channels but does not restart the WebSocket server — connected clients stay connected.
Changing
unknown_user_policy on a channel with an empty allowed_users re-fires the startup warning with the new policy’s text (PR #2856). Existing sessions are unaffected — the change applies to inbound DMs after the reload commits.Observability
The gateway records every reload outcome so operators can confirm the last edit took effect without scraping logs. Reloads still log a concise summary line on completion:reload applied: <changed-sections>; restart[<channels>]. Grep for reload applied to trace all reloads in your log stream.
Reload status in health()
health() surfaces the reload outcome and config revisions when the gateway runs from a config file:
health() consumers see no change:
ReloadStatus fields
ReloadStatus is a frozen dataclass describing the most recent reload attempt:
Compare configs offline
compute_config_revision returns the same 12-character revision id used by health(), so you can check an on-disk config before deploying it:
None config returns the sentinel "000000000000".
Inspect the hot-apply registry
HOT_APPLIABLE_KEYS and is_hot_appliable are public exports from praisonaiagents.gateway, so you can query which paths are zero-restart before an edit:
SupportsHotReload protocol is runtime_checkable — a gateway implementation opts in by defining an apply_hot_reload(paths, new_config) -> None method. Third-party gateway subclasses that want the wrapper’s hot-apply behaviour implement this method; core owns the classification so every runtime reloads identically.
Programmatic reload-scope classification
ReloadScope and classify_reload are public exports from praisonaiagents.gateway that tell you exactly what an edit to gateway.yaml will do — before you save it.
classify_reload is canonical and side-effect-free — every runtime (core, wrapper, third-party gateway subclasses) uses the same classifier, so a pre-flight check reflects exactly what happens at reload time. Anything not explicitly recognised falls through to ReloadScope.FULL, keeping full restart the fail-safe default.
Reload observability flow
Inspect reload from the CLI
praisonai gateway status prints the reload result, watcher state, and config drift alongside the existing status:
When config_drift is true
A drift means the config on disk has not taken effect — walk this path to recover:
The reload machinery is additive:
ReloadStatus and compute_config_revision are new exports from praisonaiagents.gateway, and the existing reload applied: … log line is unchanged. Pre-existing health() consumers are unaffected.Tuning
Backward compatibility: Leaving
reload_drain_timeout unset preserves the prior immediate-restart behaviour. Not installing watchdog keeps polling as before. This is a fully additive change. The HOT_APPLIABLE_KEYS set is a closed core registry; unknown or structural changes still trigger the existing restart plans, so upgrading is drop-in and cannot silently skip a needed restart.Best Practices
Prefer agent-only edits for prompt tweaks
Prefer agent-only edits for prompt tweaks
Changing
agents.* avoids dropping live Telegram/Discord sessions.Scope channel edits narrowly
Scope channel edits narrowly
Edit one channel block to restart only that platform.
Validate YAML before saving
Validate YAML before saving
Invalid saves are ignored — the previous config keeps running.
Use SIGHUP in systemd for zero-downtime config pushes
Use SIGHUP in systemd for zero-downtime config pushes
Add
ExecReload=kill -HUP $MAINPID to your systemd unit so systemctl reload triggers a drain-coordinated reload without stopping the process.Related
Bot Gateway
Gateway server overview
Gateway Channel Supervision
Self-healing channels
Code-Skew Guard
Detect in-place code updates and refuse hot operations until the process restarts.
Gateway Reliability Preset
One switch to compose drain + admission control

