session_end or gateway_stop, to any shell command. You configure them in YAML and write no Python.
notify.sh. The script gets the event as JSON on stdin and the event name in PRAISON_EVENT.
Quick Start
1
Add a shell sink to gateway.yaml
Append each ended session to a local log file.
2
Forward multiple events at once
A single entry can listen to several events. Use
PRAISON_EVENT in your script to tell them apart.3
HTTP sink without a script
You can put
curl straight into command to POST the event JSON from stdin.Which Hook Surface Should I Use?
PraisonAI has three hook surfaces. Pick the one that matches the direction of the event and how you want to handle it.How It Works
Each entry registers a command hook on the default hook registry, which is the same registry the agents use to fire lifecycle events.Unknown keys are rejected when the config loads, so a typo like
timout produces an error instead of being silently ignored. A misspelled event name such as sesion_end is also rejected (Unknown hook event(s): sesion_end). If an entry is invalid at runtime, the gateway logs a warning and skips only that entry.Supported Events
You can list anyHookEvent value in events. The table shows the lifecycle events that are most useful to forward.
For every event and its full input fields, see Hook Events.
What the Command Receives
The event is written to the command’s stdin as a single line of JSON. Every payload has the same base fields (session_id, cwd, event_name, timestamp, agent_name), followed by the fields specific to that event.
Signed HTTP sink
To sign requests, wrap the call in a short script that computes an HMAC withopenssl and sends it as a header.
User Interaction Flow
Here is one complete example: a user blocks your bot, and on-call finds out within seconds.- Your Telegram bot has been running for a week. A user messages it and the agent writes a reply.
- The user has blocked the bot, so Telegram rejects the reply. Retries run out and the gateway fires
message_undelivered. - Your
hooks_outboundentry passes the event JSON to a three-line bash script that posts to Slack#ops: “User 12345 blocked the bot”. - On-call sees the alert about 2 seconds later, without anyone writing Python.
Reload-Safe
When the config reloads, the gateway first removes the outbound hooks it registered earlier and then applies the new config. Deleted entries and changed endpoints take effect without a restart. See Gateway Hot-Reload.Safe Mode
PRAISONAI_NO_PLUGINS=1 turns off outbound hook registration, the same as it does for inbound hooks. The gateway logs SAFE MODE: N outbound hook(s) disabled (PRAISONAI_NO_PLUGINS). See Gateway Safe Mode.
Shutdown Behaviour
gateway_stop hooks fire during graceful shutdown, including SIGINT and SIGTERM. When a shutdown watchdog is set, the hook must finish within the remaining drain and grace budget, so a slow sink cannot delay the exit. A child process whose hook is cancelled is killed rather than left running. After shutdown, the outbound hooks are unregistered.
Common Patterns
- Ops notifier: post to a Slack or Teams webhook on
gateway_stop. - Dead-letter alert: send
message_undeliveredto a PagerDuty incident. - Metrics ingest: send
session_end(total_turns,total_tokens) to statsd or a Prometheus pushgateway. - Audit log: append every event to
/var/log/praisonai/events.jsonl.
Best Practices
Keep the command fast
Keep the command fast
The default timeout is 30s. Most sinks should use
timeout: 5 or less. A slow sink only delays its own hook, but a gateway_stop sink runs as part of shutdown.Sign your HTTP sink
Sign your HTTP sink
Anything else on the network can send a plain
curl POST, so the receiver cannot trust it. Add an HMAC signature header with a small wrapper script, as shown in Signed HTTP sink.Pick events narrowly
Pick events narrowly
List only the events you need to forward. Each matching event starts a new process.
Handle deduplication in the sink
Handle deduplication in the sink
There are no built-in retries or dedup. If your downstream system must deduplicate, build its dedup key from the event’s
timestamp plus a stable id such as session_id or job_id.Related
Gateway Inbound Hooks
POST /hooks/<path>: the inbound HTTP trigger counterpart
Bot Lifecycle Hooks
In-process Python hooks on the same events, for when YAML isn’t enough
Hook Events
Full HookEvent reference with every input type’s fields
Gateway Safe Mode
How PRAISONAI_NO_PLUGINS suppresses outbound hooks
Gateway Hot-Reload
How outbound hook changes take effect without a restart
Undelivered-Message Notice
Enable message_undelivered so it can be forwarded

