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.Quick Start
1
Simplest setup — 5-minute idle timeout
_on_quiesce hook (if set). The next POST /_wake brings it back.2
Tighter timeout for more aggressive savings
3
With a compute-host suspend hook (Fly / Modal)
_on_quiesce is set as an attribute after construction (not a constructor kwarg). Set it before calling start() or run(). When a public setter is added in a future release, this section will be updated.4
Primary runtime — enable via gateway.yaml
Scale-to-zero is wired into the primary The gateway serves normally, then quiesces after
WebSocketGateway (praisonai gateway start) through a lifecycle: block.idle_minutes of no inbound or in-flight work. The next client frame wakes it.5
Primary runtime — enable via CLI flags (no YAML)
lifecycle: block, so CLI overrides win over gateway.yaml. No wake_url is needed — the listening socket is an inherent self-wake path.How It Works
Key behaviours:Configuration Options
ScaleToZeroPolicy constructor
Properties on the instance:
BotOS — idle policy field
BotOS runtime activity hooks
Imports
These names export from
praisonaiagents.gateway. Top-level praisonaiagents does not re-export them. BotOS itself imports from praisonai.bots.lifecycle.scale_to_zero: YAML block (WebSocketGateway)
The primary WebSocketGateway reads scale-to-zero from a lifecycle: block at the top level of gateway.yaml or nested under gateway:.
CLI flags (WebSocketGateway)
CLI flags win over YAML — they are folded into the
lifecycle: block before the policies are built.
Observability
When scale-to-zero (or a drain marker watch) is configured,health() adds a lifecycle object so operators can see the state without scraping logs.
The
lifecycle field is emitted only when a lifecycle feature is configured, so always-on gateways are unchanged.
Hot Reload
Enabling or disabling scale-to-zero via agateway.yaml reload takes effect without a full process restart. The gateway rebuilds the pure policy and cancels or relaunches only the idle loop whose enablement changed — an unchanged lifecycle: block leaves running tasks untouched. See Gateway Hot Reload.
Common Patterns
Fly Machines auto-suspend
/_wake route in your web framework calls await botos.wake(), which reconnects all transports and the gateway is live again within seconds.
Env-var kill switch
SCALE_TO_ZERO=1 in production. In dev, leave it unset — the policy stays disabled and the gateway runs always-on with zero overhead.
Tighter timeout for prototype bots
1 minute for disposable demo bots. Bump to 5+ minutes for production where users expect instant responses.
Best Practices
wake_url is required on BotOS, optional on WebSocketGateway
wake_url is required on BotOS, optional on WebSocketGateway
On
BotOS, without a wake_url should_arm returns False and the gateway logs "idle policy not armed (no wake path); staying always-on" — the policy refuses to quiesce into a state it cannot recover from.On the primary WebSocketGateway (praisonai gateway start), the listening socket is treated as an inherent self-wake path: the gateway stays dormant with the socket open and wakes on the next inbound client frame. So wake_url is only required when you also set an on_quiesce host-suspend hook (Fly / Modal / Daytona), which powers the host down and needs an external endpoint to bring it back. CLI-only --scale-to-zero arms and quiesces correctly without a wake_url.Keep idle_timeout_minutes ≥ 2 for chat bots
Keep idle_timeout_minutes ≥ 2 for chat bots
Humans pause between messages in the same conversation — typing, thinking, copy-pasting. A timeout under 2 minutes can spin transports down mid-conversation, adding a cold-start delay the user will feel. Start at 5 minutes for interactive bots and tune down once you have usage data.
Wire _on_quiesce after testing your wake path
Wire _on_quiesce after testing your wake path
Test that
curl -X POST https://your-bot.example.com/_wake successfully brings the bot back before you wire _on_quiesce to actually suspend the host. That way you can recover from a broken suspend hook without needing to redeploy.Don't disable scheduled jobs to force idle
Don't disable scheduled jobs to force idle
The policy already blocks dormancy whenever any enabled scheduled job exists. If you want true scale-to-zero, audit
praisonai schedule list and disable jobs that should not keep the bot resident. Never rely on a long timeout to “outlast” a scheduled job — the job will prevent quiescing for as long as it is enabled.Related
Gateway Overview
The gateway architecture this feature layers on top of.
Session Continuity
Sessions survive the suspend — what makes resume after wake work.
BotOS
The multi-platform orchestrator that hosts the idle policy.
Drain Trigger
Sibling lifecycle policy — epoch-safe external drain marker.
Crash-Loop Guard
Sibling lifecycle policy — stop auto-resuming a crash-looping channel.

