Skip to main content
Different scope from the Run-State Journal. The inbound journal deduplicates and recovers webhook messages. The run-state journal persists the execution cursor of a single run. A webhook may spawn a run; the two journals track the two halves of the pipeline.
Inbound Journal tracks messages before agents process them, providing deduplication of webhook redeliveries and crash-safe replay of in-flight messages. The user sends a webhook message; the journal deduplicates redeliveries and tracks in-flight work.
On by default for gateway/bot runs — Every bot started via praisonai bot start, onboard, or bot.yaml gets the journal automatically. No code needed. The journal lives at ~/.praisonai/state/<platform>/ingress.sqlite. Set delivery.durable: false to opt out.

Default behavior (no config needed)

Every bot started through build_session_manager (all shipped adapters) automatically gets an Inbound Journal at:
For example, a Telegram bot journals messages at ~/.praisonai/state/telegram/ingress.sqlite. A Discord bot uses ~/.praisonai/state/discord/ingress.sqlite. Each platform is fully isolated — no cross-platform dedup collisions. Set PRAISONAI_HOME to override the base directory:

Opt out or override path

Add a delivery: block to any channel in your bot.yaml or gateway.yaml:
Override the store directory:

Quick Start (advanced: manual setup)

Most users get the journal automatically. For custom setups outside build_session_manager:
1

Create journal that survives restarts

2

Enable on your bot

You don’t need to call complete() yourself when using BotSessionManager.chat() — successful chats mark the journal entry as completed automatically. You only need to call complete() manually if you’re driving InboundJournal directly without BotSessionManager.

How It Works

Before PR #1980, the default chat() path claimed entries but never called complete(). On startup, journal.replay() could re-issue messages the user had already received answers to. Upgrade to a release after 2026-06-19 — replay then only covers genuinely incomplete entries.

When to use which option


Configuration Options


Per-platform examples


Common Patterns

Pattern 1: Dedup-only (webhook redelivery protection)

Pattern 2: Crash recovery + replay loop on startup

After PR #1989, redelivery of a still-pending message also retries automatically — you no longer need to wait for a restart plus replay() to recover from a mid-flight crash if the platform redelivers the same message_id. replay() is still the right call on startup to recover any orphaned claims.

Pattern 3: Combining with InboundDLQ for full durability stack


Best Practices

The journal’s SQLite file must survive restarts for crash recovery to work. Use an absolute path or a location that persists across deployments.
Set claim_timeout to be longer than your p99 agent.chat() latency to avoid false stale entry detection.
Always replay stale entries when your bot starts to recover from crashes.
The account parameter is part of the deduplication key. Keep it consistent for each bot instance.
Platforms redeliver webhooks at fixed intervals (Telegram retries within seconds, Slack waits ~3s before its first retry, etc.). Set claim_timeout shorter than your platform’s redelivery window so that a crashed worker’s claim becomes stale before the next redelivery arrives — that’s what enables automatic recovery without a restart.

Delivery Config

Full reference for the delivery: channel config block — defaults, opt-out, and path override

Inbound DLQ

Failure-side durability when agent execution fails

Durable Outbound Delivery

Outbound counterpart — persist outgoing messages with retry and idempotency

Bot Routing

Multi-channel session routing for complex bot setups