Skip to main content
Declare a standalone_sender on your channel’s descriptor and praisonai schedule tick delivers to it from OS cron, CI, or a scale-to-zero worker. You don’t need a gateway running.

Quick Start

1

Schedule an agent to a custom channel

Use the same deliver token you would for a built-in platform. Only the channel name changes.
Then run the tick from OS cron with no gateway running:
2

Add a standalone_sender to the plugin's descriptor

Add one method to the descriptor your praisonai.channels plugin already ships:
praisonai schedule tick is a fresh process. A register_platform(..., descriptor=...) call in your own app code never runs there. Put the descriptor on the adapter class as channel_descriptor (an attribute or a callable), so the registry finds it when it loads your entry point.

How It Works

Precedence

A bundled name always wins. If the descriptor lookup raises (a broken plugin, for example), the resolver logs at debug level and returns None. The run records delivery_error and the tick keeps going.

Sync or Async

Either form works. The executor awaits the result only when it is awaitable.
The sender receives the scheduler’s DeliveryTarget (target.channel, target.channel_id, target.thread_id) and the text to post.
Failure contract. Raise when the send fails: the run records delivered=False with delivery_error=str(exc). If you return False, the run is also recorded as delivered=False. Any other return value, including None, counts as success. This matches the live delivery_handler contract in Scheduler Delivery → Failure modes.
Retries are up to you. Each bundled sender has its own bounded in-process retry. A plugin sender doesn’t have to retry. If it raises on the first failure, that is correct behaviour: the run records delivery_error and the tick moves on.

End-to-end: cron deployment

1

Install the plugin and set its secret

2

Create a job with the custom-channel target

3

Schedule the tick in OS cron

4

Gateway off, cron fires, message lands

Cron fires, the job runs, the resolver falls through to your descriptor, and the brief arrives in ops. Run history shows delivered=True.

Best Practices

Don’t keep open sockets or cached connections. Make one push per call so the short-lived tick process exits cleanly.
The sender runs out of process, so the onboarding wizard never runs there. Every secret it needs should have an env= fallback on its ChannelField.
Don’t catch and swallow errors inside the sender. When an error reaches the executor, it records delivery_error, and operators can see the real reason in run history.
Both forms work. The executor runs on asyncio, so a sync sender blocks the event loop for as long as its HTTP call takes.

Channel Descriptor

The full descriptor surface

Scheduler Delivery

The scheduled delivery pipeline

Custom Gateway Channel

Zero-code channel registration

Bot Platform Plugins

Entry-point registration
Availability. Introduced in PraisonAI PR #6100 (fixes #6099). Earlier versions needed a resident gateway for a custom channel to receive scheduled deliveries.