Skip to main content
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 CLI provides commands for starting, monitoring, and managing the PraisonAI Gateway server and its daemon service, including channel supervision controls for resilient bot management.
This page documents the WebSocket multi-agent Gateway daemon. The canonical CLI is praisonai-bot gateway (bot-tier package). When the praisonai wrapper is co-installed, praisonai gateway <subcommand> works as a convenience alias for every subcommand documented on this page — start, status, stop, restart, doctor, test, channels, pause / resume / reconnect, install / uninstall, mint-link, logs, send, hooks, and sessions.For the UI-Gateway (Pattern C integration), see praisonai serve ui-gateway.For detailed information about channel resilience and operator controls, see Channel Supervision.
The user runs praisonai gateway start; the CLI launches the daemon, supervises channels, and keeps the WebSocket gateway reachable.

How It Works

Quick Start

The gateway runs in the foreground. The daemon is installed by praisonai-bot gateway install (or automatically by praisonai-bot onboard).
1

Start Gateway

With no --config, start auto-discovers the onboarded config and prints the file it picked before binding:
Only one gateway can run per host:port. Stop the existing one with praisonai-bot gateway stop first, or use a different port.
2

Check Status

3

Test Health Endpoint


Commands

Unknown subcommands degrade gracefully. praisonai gateway <typo> prints the standard usage/error message and exits with a non-zero code, rather than dead-ending with a static list. This applies to both the canonical and wrapper entry points.
praisonai gateway … and praisonai-bot gateway … now route through one command app, so both expose the same verbs and the same start. A degraded gateway’s retry hints — praisonai gateway doctor, doctor --fix, test — name commands you can run from either binary. An unknown verb (for example praisonai gateway doctr) now prints a rendered usage error and exits non-zero instead of the old Available commands: start, status, hooks dead-end, so a new error format is expected.

Which verb do I need?

Gateway Management

praisonai-bot gateway status is safe to run on any platform. On Windows, if PID-lock inspection can’t complete, the /health probe still runs and shows the authoritative gateway status. On POSIX, a foreign-uid gateway is now correctly reported as running (rather than being treated as dead) — see PraisonAI #4197.

Daemon Service

The installed unit stops (not restarts) on the gateway’s fatal-config exit code (78, EX_CONFIG). See Gateway Exit Codes for the full contract.

Channel Control

Inbound Hooks

See Gateway Inbound Hooks for full details.

Testing & Debugging

Diagnostics

praisonai gateway diagnostics export writes a portable, pre-sanitised .zip you can attach to a bug report. Full details in Diagnostics Export.

Command Reference

For the channel-control verbs (pause / resume / reconnect), when --url is omitted the target is resolved from --host / --port (defaulting to the GATEWAY_PORT environment variable, then 127.0.0.1:8765). Previously the URL was always probed at 127.0.0.1:8765 — operators running the gateway on a non-default endpoint had to hand-type the WebSocket URL for every channel control call.
The lifecycle flags synthesize a lifecycle: block, so CLI overrides win over YAML. --scale-to-zero arms and quiesces even without a wake_url — the gateway keeps its listening socket open and self-wakes on the next inbound message. See Scale-to-Zero, Drain Trigger, and Crash-Loop Guard.
--reliability overrides the reliability: / gateway.reliability: key in YAML. See Gateway Reliability Presets for profile details and precedence rules.
--identity-store gives every paired/linked user one continuous session across channels and overrides the identity: block in gateway.yaml. See Cross-Platform Sessions → In the gateway for the full precedence ladder.
Corporate proxies / SSL-inspecting networks. A preflight failure caused only by SSLCertVerificationError / certificate_verify_failed does not abort the start — the token is usually valid and the runtime adapter’s SSL stack is more permissive. The gateway prints a one-line warning naming the three CA-bundle env vars and continues.If any channel also fails for a non-SSL reason (bad token, unreachable host, timeout), preflight still hard-aborts — fix that channel or pass --no-preflight. See Corporate CA bundle (SSL-inspecting networks).
--verify-turn is governed by its own toggle, independent of --preflight. --no-preflight --verify-turn skips the channel-credential probe but still runs one real model round-trip. Both checks run by default and the turn check never replaces the channel probe. On failure it prints the error and exits 1. Prompt and timeout are YAML-only (gateway.preflight.verify_turn_prompt / verify_turn_timeout) — there is no --verify-turn-prompt flag. See Gateway Readiness → Turn pre-flight.

Config discovery

You no longer need --config if you have onboarded — praisonai gateway start discovers the config praisonai onboard wrote. Every gateway command (start, doctor, test, status, send, channels) uses the same canonical resolution order, so onboard, start, and doctor cannot drift apart.
bot.yaml is the canonical name. gateway.yaml continues to load without warning as a backward-compatible alias — it is not the new preferred name. When the optional praisonai-code package is installed, its resolve_bot_config_path resolver is used; a lean install without it falls through to an equivalent inline resolver that agrees on every path.

start with no config

praisonai gateway start (no --config, no --agents) discovers the onboarded config, prints Using gateway config: <path>, then binds with channels instead of the earlier silent WebSocket-only no-op. If nothing is found it prints a hint and exits 78:
Passing --agents <path> selects single-agent mode and skips channel-config discovery.

doctor / test / status / send / channels

These commands default --config to a gateway.yaml sentinel. When you leave it at the default, they run the same discovery order as start — so praisonai gateway doctor after praisonai onboard inspects the onboarded ~/.praisonai/bot.yaml, not a file onboarding never wrote. An explicit --config always wins.
The Path to gateway.yaml [default: gateway.yaml] help text on these commands resolves to the onboarded ~/.praisonai/bot.yaml when present — the literal gateway.yaml file is only used as the final alias fallback.

Version validation

praisonai gateway start also validates the config’s config_version before binding, applying the same forward-migration doctor --fix uses. A config from a newer build refuses to start (exit 78) rather than being silently downgraded. See Gateway Config Migration › Config version stamp.

What the user sees

The whole reason this discovery exists: before, an onboarded operator who ran praisonai gateway start with no flag started silently channel-less, so their Telegram user got no reply.
Two behaviours change observably for existing operators — the CLI stopped silently doing the wrong thing.
  1. gateway start with no flag now discovers ~/.praisonai/bot.yaml. A deploy that relied on the old silent channel-less shape (WebSocket daemon only) now starts with the onboarded channels attached. To keep the old behaviour, point --config at a channel-less YAML explicitly, or remove ~/.praisonai/bot.yaml.
  2. gateway start refuses to run a config from a newer build. A host that pinned an older praisonaiagents while keeping a newer config now sees exit 78 at start instead of a silent downgrade. Upgrade the wrapper, or roll the config back to the version the wrapper supports.
For a focused, standalone walkthrough of this resolution, see Gateway Config Discovery. Start-time version validation is documented in Config Migration → At start time.

Pre-flight credential check

praisonai gateway doctor validates every channel’s token before the gateway starts, so a bad or expired credential fails fast with a precise per-channel reason instead of disappearing into the supervisor’s silent reconnect loop.

Examples

Quick health check:
A non-SSL failure keeps the bare error string:
CI-friendly JSON — a single document with a probes block (and a secrets block when any channel uses a secret reference):
The whole output is now one JSON document ({probes, secrets}), parseable with a single json.loads. Operator scripts that read the earlier two-document output (a probe block plus a separate availability block) must switch to reading payload["probes"]. A weak gateway auth_token adds a third top-level key, gateway_auth_token — see Weak-secret check.
Same verdict via the listing command:

Credential availability (without revealing values)

praisonai gateway doctor also prints a per-channel credential availability table so operators can validate secret wiring — including the secret-reference form on token, app_token, and verify_token — without ever printing a value.
An exec-sourced reference reports configured without running its command: the command has side effects (a one-shot / rate-limited / rotating secret-manager call) and the network probe resolves the same reference moments later, so executing it here would run it twice. These states now map cleanly to runtime isolation at boot — a configured-but-unavailable or missing channel credential isolates just that channel as degraded rather than aborting the gateway. See Degraded Channel Isolation. After boot, GET /health emits the same degraded / reason: "credential unavailable" verdict for a channel whose token is rejected at runtime (401/403, revoked/rotated/expired) — no new flags. See Runtime credential rejection. The --json output is a single document with probes and secrets keys:
Breaking change to the --json layout. Previously doctor printed the availability and probe blocks as two separate top-level documents (invalid JSON). It now emits one document with probes and secrets keys, so json.loads can parse the whole output. The secrets key is present only when at least one channel configures a credential field.

Weak-secret check

gateway doctor also flags the gateway’s own auth_token when it matches a well-known placeholder — fails on an external bind, warns on loopback. On an external bind with a weak token, doctor prints the full refusal message and exits 1:
On a loopback bind, doctor prints a warning and still exits 0:
A strong token prints nothing extra — silence is a pass, consistent with the credential-availability table. The --json output gains a top-level gateway_auth_token key (present only when the verdict is weak), alongside probes and secrets. When --fix is passed, an optional fix key carries the repair report:

Weak Secret Guard

Full denylist, bind-aware behaviour matrix, and how to fix a weak change-me-style token

Auto-repair with --fix

Prefer Python for CI, tests, or per-tenant provisioning? The same repair lifecycle is exposed as praisonai_bot.repair_gateway_config — see Gateway Admin API.
--fix repairs safe findings, then re-validates that each finding cleared. Repair a weak token, then confirm it cleared:
Preview the repair without writing anything:
--dry-run still exits 1 when a repairable finding is present, so CI catches un-fixed states before anything is written.
--fix writes to ~/.praisonai/.env and may rewrite an explicit weak auth_token in gateway.yaml in place. Run --fix --dry-run first in production to preview the change. ${ENV} references in YAML are left untouched — they resolve from the env store the env-var repair already fixed.

Pre-flight gate on start

praisonai gateway start runs the same probe automatically before launch when invoked with --config gateway.yaml:
To bypass during local dev (e.g. flaky probe network):

Route/binding target check

praisonai gateway doctor also validates that every routes, routing, and bindings.agent target names an agent declared in the sibling agents: map. A typo — including in the default slot — fails with a “did you mean X?” hint instead of silently misrouting traffic.
This runs only for multi-agent configs (an agents: map is present). Single-bot configs (top-level platform + token) are unaffected. See Fail-Fast Validation for the full behaviour.

Corporate CA bundle (SSL-inspecting networks)

On networks that intercept TLS with a corporate CA (proxy / MITM), the probe’s HTTP client can reject the certificate chain even though the token is valid and the runtime adapter connects fine. Preflight classifies these SSL cert-verify failures separately and soft-fails when they are the only failures.
The probe decides its action from the mix of failures:
Only certificate-verify failures soft-fail. Other TLS handshake failures — WRONG_VERSION_NUMBER, NO_SHARED_CIPHER, HANDSHAKE_FAILURE — still hard-abort, because they usually indicate a real bug that also breaks the channel at runtime.
Point the probe at your corporate CA with one of three env vars, highest precedence first:
A configured-but-missing path warns and leaves the SSL env vars untouched:
The runtime adapter reads the same three env vars, so setting one fixes both the preflight probe and long-lived channel connections.

Token resolution

The probe loads ~/.praisonai/.env first, so ${VAR} placeholders set by praisonai onboard resolve exactly like they do at runtime — doctor, channels --probe, and start --preflight all share the same token-resolution path.

Per-channel timeout

Each probe is bounded by a 15-second deadline; a stuck adapter is reported as "probe timed out after 15s" and does not hang the aggregate.

Exit codes

When to use which


Pre-flight tool check

praisonai gateway start validates every tool named in your config before the gateway binds, so a typo or an uninstalled optional package fails fast with a per-name reason instead of silently starting a quietly under-powered bot.
Default changed 2026-07-31. Before PR #3555 an unresolved tool was silently skipped with only a log warning. The default is now --strict-tools, which aborts start with exit 78 and a per-name fix hint. Configs with typo’d or unavailable tools that previously started will now fail — pass --no-strict-tools or set strict_tools: false in gateway.yaml to restore the old warn-and-continue behaviour.
This gate runs one layer above the core resolver’s PRAISONAI_STRICT_TOOLS / ToolResolutionError mechanism — it fires at start-time, before GatewayHandler.start() builds any agent. See Tool Resolution for the complementary core-resolver behaviour.

Strict mode (default) — fail fast

Non-strict — warn and continue

Two equivalent ways:
Either produces:

“Did you mean?” mechanics

Suggestions use stdlib difflib.get_close_matches (cutoff 0.7, one suggestion per unknown). A tool that is registered but currently unloadable (e.g. an optional package not installed) is excluded from its own candidates, so it yields an install hint rather than suggesting the same name back:
A project tools.py that exists but is gated by the local-tools env var is flagged explicitly:
An unknown toolset name is reported the same way:

Precedence

YAML strict_tools: false opts a bot out permanently; --no-strict-tools is per-invocation. A strict CLI default does not override a YAML strict_tools: false.

Env loading

The gate loads ~/.praisonai/.env before resolving, so PRAISONAI_ALLOW_LOCAL_TOOLS=true stored there by praisonai onboard is honoured and a gated local tools.py is not falsely reported as unresolved. The load is idempotent and existing process env wins — GatewayHandler.start() re-loads the same file moments later.

Exit code

Strict failure exits with 78 (EX_CONFIG), which the OS units generated by praisonai gateway install treat as do-not-restart — an unresolvable tool in the config would loop the daemon otherwise. See Gateway Exit Codes.

Environment Variables

The GATEWAY_PORT environment variable is used by start, stop, and status commands when the --port option is not explicitly provided. Invalid values silently fall back to 8765.

Supervisor exit codes

praisonai gateway start returns a supervisor-friendly exit code so a service manager (launchd / systemd / a scheduled task) knows whether to restart the gateway or stop and wait for an operator. The installed OS unit maps 78 (EX_CONFIG) to do-not-restart so a broken config cannot crash-loop the daemon, and treats 75 (EX_TEMPFAIL) as restartable. See Gateway Exit Codes for the full contract and per-platform wiring.
The doctor verb uses a simpler 0 / 1 scheme (pass / fix-me) documented under Pre-flight credential check → Exit codes — that is separate from the start supervisor protocol above.

Single-Instance Enforcement

PraisonAI enforces a single gateway instance per host:port combination using PID locks. Lock File Location: ~/.praisonai/gateway-<safe_host>-<port>.pid The safe_host replaces : and . with _ (so 127.0.0.1 becomes 127_0_0_1). Each host:port combination gets its own lock file, allowing multiple gateways on different ports.

PID-Lock Status Reference

praisonai gateway status prints one PID-lock line before the /health probe. Look up any line you see: The port line (Port <host>:<port>: In use / Available) follows the same section unless PID-lock inspection fails, in which case the single PID lock status: Unavailable (<error>) line replaces both.
Since PR #4197, the lock records a PID + start-time fingerprint (a 5th line). “Running” means the PID is alive and its start time matches, so a recycled PID is not mistaken for the original gateway. A missing fingerprint (older 4-line lock or psutil unavailable) degrades gracefully to the previous PID-only check. On POSIX, a live gateway owned by another user (PermissionError from os.kill) is also treated as running, so its lock is preserved.

Restart the Gateway

Use praisonai gateway restart — it drains in-flight turns, then relaunches (via the installed service manager when present, otherwise directly).
gateway restart is daemon-aware: if the gateway is installed as an OS service (praisonai gateway install), the platform service manager restarts it (launchctl kickstart -k, systemctl --user restart praisonai-bot, or schtasks /End && /Run) so the installed unit’s launch flags are preserved. Otherwise the CLI drains the running PID and relaunches directly in the foreground.
The direct (non-service) fallback now replays the CLI-only flags the original process was started with (--openai-api, --mcp, --reliability, --max-concurrent-runs, --queue-depth, --overflow-policy, --identity-store, --scale-to-zero, --idle-minutes, --drain-marker, --agents, --config, --drain-timeout) from a persisted start-flags artefact — see Persisted start-flags artefact. Flags passed explicitly to restart still win; anything else replays the value the running process was launched with.

Options

Persisted start-flags artefact

praisonai gateway start persists the CLI-only runtime flags it was launched with to ~/.praisonai/gateway.start.<host>.<port>.json so a later praisonai gateway restart (direct, non-service path) reproduces the exact posture instead of silently reverting to defaults. Path: ~/.praisonai/gateway.start.<safe_host>.<port>.json (or $PRAISONAI_HOME/gateway.start.<safe_host>.<port>.json when set). safe_host replaces : with _, so IPv6 hosts work. The artefact is keyed by host:port — multiple gateways on one machine each keep their own posture. Persisted keys (only non-None values are stored — None means “fall back to YAML”): Write timing: the artefact is written only after startup validation passes (config parse, agent-file parse, admission wiring), immediately before the gateway binds. A start attempt that fails validation on the same host:port never clobbers the running gateway’s saved posture — otherwise the next restart would faithfully replay a rejected attempt.
On restart, gateway restart prints Replaying persisted start flags: <sorted keys> before relaunching, so operators see exactly which flags were replayed.
Precedence on restart: An omitted --drain-timeout on restart no longer forces a fixed 10s window; it replays the persisted value (and only falls back to 10.0 when nothing is persisted). An explicit --drain-timeout still wins over the persisted value for both the OLD-process drain and the relaunch, so a long configured drain is not silently cut off. Fixes #3349.
On Windows, gateway restart aborts if schtasks /End fails — this prevents a duplicate / colliding gateway relaunch that the raw /End && /Run chain would silently produce.

Advanced: OS-native restart

If you need to bypass the CLI (e.g. from a systemd ExecStartPre), the same platform commands the daemon dispatcher uses are:
Bypassing gateway restart skips the graceful drain — in-flight agent turns will be interrupted mid-response. Prefer the CLI verb.

Status Output Examples

Healthy Gateway

PID Lock Unavailable (Windows)

On Windows, os.kill(pid, 0) can raise SystemError. From PraisonAI ≥ v4.6.141 the PID-lock inspection is advisory only — this line replaces Gateway PID lock: … / Port …: … when the check fails, and the /health probe still runs so you still see the real status.

Daemon Issues

Not Installed


Platform Support

Gateway CLI works across platforms with native daemon integration:
Each generated unit stops (not restarts) on the gateway’s fatal-config exit code (78, EX_CONFIG) — systemd via RestartPreventExitStatus=78, launchd via KeepAlive/ThrottleInterval, Windows via a .cmd wrapper that maps 78 to a clean exit. See Gateway Exit Codes.

Configuration Files


Common Patterns

Diagnose → repair → verify

Inspect first, repair only if needed, then confirm the gateway came back healthy.

Zero-downtime posture change

restart drains in-flight turns for the given window, then relaunches — replaying the launch posture saved in ~/.praisonai/gateway.start.<host>.<port>.json, so the process comes back with the same flags it was started with.

Add an inbound trigger

Register a webhook that hands inbound events to an agent and delivers the reply to a channel.

Best Practices

Use --daemon-only flag when monitoring daemon status in scripts or CI/CD pipelines to avoid gateway connection attempts.
Always check praisonai gateway logs when the daemon is running but gateway is unreachable - this reveals startup errors.
Use praisonai gateway send to test channel bot configuration before deploying to production environments.
Set up monitoring that runs praisonai gateway status --daemon-only to detect service failures quickly.
Stop, restart with the new flag once, and every subsequent praisonai gateway restart replays it automatically — ~/.praisonai/gateway.start.<host>.<port>.json is your on-host record of what the process was launched with. To reset, delete the artefact.
rm ~/.praisonai/gateway.start.<safe_host>.<port>.json before the next restart to revert to the YAML defaults (or an empty CLI baseline). A corrupt or unreadable artefact is treated as absent — the restart falls back to explicit flags and defaults.

Gateway Server

Gateway architecture and configuration

Config Discovery

Where every gateway command looks for the config when --config is omitted

Troubleshooting

Common gateway issues and solutions

Secret References

Load credentials from files, env vars, or secret managers

Cross-Platform Sessions

--identity-store — one session per user across channels

Route Bindings

Fail-fast validation — route/binding typos caught at config load

Exit Codes

Exit 78 from the strict tool pre-flight — do-not-restart contract

Tool Resolution

Core-resolver PRAISONAI_STRICT_TOOLS — complementary to this start-time gate