Skip to main content
Use this checklist before starting a gateway or relying on a Slack/Telegram bot in production.
praisonai gateway test --turn and praisonai gateway doctor --turn run an offline agent turn via BotSessionManager.chat. They do not exercise Slack Bolt/socket handlers or @mention routing. A passing turn test does not guarantee live @mention delivery.

Turn pre-flight

Your bot’s model credential is now checked at startup — not on the first user message. praisonai gateway start runs one real agent turn (prompt "ping") before serving, so a missing, invalid, or out-of-quota model key fails at start with exit 1 instead of surfacing on the first inbound message.
This differs from the channel/tool probes below: those prove wiring (tokens resolve, tools load) but never exercise a model round-trip. The turn pre-flight sends a real prompt to the agent and waits for a reply. The turn pre-flight is governed by its own toggle, independent of --preflight / --no-preflight. Running --no-preflight --verify-turn still exercises the model round-trip. It runs against the first configured channel by default.

YAML keys

The turn pre-flight uses the same per-agent base_url / api_key overrides as the live gateway, so a custom provider is tested against the same endpoint it will serve — not the default provider.

Five-tier diagnostics

Sessions ≠ liveness. gateway sessions list shows stored conversation history only. Use --check-inbound to verify live Slack delivery.

Three-tier checklist

1

Static config (offline)

Validates YAML, env vars, security settings, and shell wiring (gateway_shell_readiness) without network or LLM calls.
2

Live credential probe

Probes each channel (auth.test, getMe, …) and surfaces bot identity (e.g. @test).gateway doctor also confirms route/binding targets resolve to declared agents — a typo in routes[], routing[], or bindings.agent (including the default slot) fails here with a closest-agent hint. See Fail-Fast Validation.
3

Full readiness (recommended)

Combines credential probes + offline shell wiring. Add optional flags:
4

Extended status and sessions

5

Start and confirm live traffic

After @mentioning the bot in Slack, confirm inbound events in logs:
If the turn test passes but Slack is silent, check for duplicate bots, stale sessions, or messages not reaching this gateway process.

Command matrix

JSON automation

Both commands support --json with a single top-level document:
Keys: probes, secrets (optional), shell, runtime (with --check-runtime), running (with --check-running), inbound (with --check-inbound), duplicates (with --check-duplicates), turn (with --turn).

Sub-object schema

Each top-level key maps to a per-channel or per-check sub-object:

/health channels schema

GET /health returns a rich per-channel object under channels[<name>], plus a top-level last_inbound_at.
The reason field comes from evaluate_channel_health(...) and takes one of these values:
Watch for ok=false, reason=stale-socket — this is the “gateway is up but not receiving messages” signal. It means the socket is connected but no inbound has arrived within stale_after.

Health liveness config

The health: block under gateway: tunes when a channel flips from healthy to stale-socket.
Lowering stale_after / startup_grace too aggressively causes false-positive alerts on legitimately idle bots. Values are clamped to sane lower bounds and unresolved env placeholders fall back to defaults.

Runtime tier (--check-runtime)

--check-runtime (or check_runtime(config)) probes /info, /health, /ready, and /live. /ready requires ready=true and /live requires alive=true in the body; the bearer token is only attached to /info over loopback or HTTPS (never over remote plaintext HTTP).

Credential probe warnings

A channel’s probes.<channel>.details.warnings[] array surfaces non-fatal setup issues. For Slack, a missing app token appends:
This warning fires even when bot.probe() succeeds with SLACK_BOT_TOKEN alone — because inbound Socket Mode still needs SLACK_APP_TOKEN (xapp-…). See Inbound Message Gate → Slack @mentions.

Inbound tier (--check-inbound)

--check-inbound proves live delivery two ways: it scans the gateway log for @mention received: markers and scrapes the messages_inbound_total metric to compute a delta.

How inbound is detected

The CLI parses ~/.praisonai/logs/bot-stderr.log (default_log_path()) for lines containing the literal marker @mention received: within the --since window. parse_inbound_log extracts count, ISO timestamp, and mention text.
If the daemon writes logs elsewhere or a custom log format filters out the marker, --check-inbound will falsely report no delivery. Preserve INFO-level log output from the Slack bot module.

Metrics baseline state file

--check-inbound persists the last scraped messages_inbound_total per host/port to:
  • First run seeds the baseline and may return metrics_inbound_delta=null — but still passes if messages_inbound_total > 0.
  • Later runs return the delta within the --since window.
  • Reset by deleting the file.
The inbound result exposes metrics_inbound_total, metrics_inbound_delta, mentions_in_window, last_mention_at, and one of three hint strings: The --since window accepts Ns/Nm/Nh/Nd or a bare integer (seconds), parsed by parse_since_window.

Duplicates tier (Hermes conflict detection)

--check-duplicates (or check_duplicates(config)) scans for competing gateways and shared tokens. It inspects:
  • macOS LaunchAgents by label: ~/Library/LaunchAgents/ai.praison.bot.plist and ai.hermes.gateway.plist
  • both env files: ~/.praisonai/.env and ~/.hermes/.env
  • Hermes runtime state: ~/.hermes/gateway_state.json
  • the gateway PID lock (GatewayPIDLock)
  • the log tail for the Telegram Conflict: terminated by other getUpdates request string
Since PraisonAI ≥ #4197, the lock also carries a start-time fingerprint so a recycled PID is not mistaken for the original gateway — the “same PID, different process” case is now caught by the lock itself, not just by this scan. Token values (*_TOKEN) are fingerprinted with SHA-256 (first 12 hex chars) and flagged when the same fingerprint appears across processes.
Warnings it can emit:
  • Hermes Slack is connected — events may split if SLACK_APP_TOKEN is shared.
  • Hermes Telegram is connected — stopping ai.hermes.gateway affects Telegram.
  • Telegram getUpdates Conflict detected — another bot may be polling.
Only macOS LaunchAgents are scanned today (no systemd support). A PID mismatch between the LaunchAgent and GatewayPIDLock also triggers a warning. Token fingerprints are SHA-256 truncated — safe to include in support tickets.

Extended status (status --deep / --config)

praisonai gateway status accepts --config, -c PATH. Combining --deep with --config unlocks extra diagnostics. What --deep adds:
  • Per-channel rows: running / state / reason / last_activity / probe_ok (from /health).
  • A version-skew warning when the running gateway’s /info.version differs from the installed praisonai-bot package version.
What --deep --config adds on top:
  • The last 20 lines of the gateway log (get_logs(lines=20) from ~/.praisonai/logs/bot-stderr.log).
  • A DLQ (<name>): praisonai bot dlq list --path <sqlite> hint per channel (path from resolve_platform_dlq_path()).
The bearer token is only attached to the /info probe over loopback or HTTPS — never over remote plaintext HTTP.

Sessions (stored history)

gateway sessions list supports filtering and JSON output.
sessions show <ref> resolves the reference in order: exact session_id → exact filename → substring in filename (first alphabetical match wins). It prints Session: / Agent: header lines, truncates each message body to 200 chars, and always ends with a footer:
The “stored history ≠ live delivery” footer is intentional operator-safety copy — session files are conversation history, not proof that inbound is currently arriving.

Programmatic API

Import praisonai_bot.gateway.preflight to build custom health-check endpoints, CI gates, and monitoring integrations without shelling out to the CLI.
resolve_verify_turn and verify_turn_preflight are also re-exported from praisonai_bot.cli.commands.gateway. Gate CI on a successful real agent turn:

Tiered check helpers

These helpers back the --check-runtime|--check-inbound|--check-duplicates flags and the session/DLQ commands. All are re-exported from praisonai_bot.cli.commands.gateway for tests and third-party tooling.
Since #4197, the pid_lock dict (from GatewayPIDLock.get_lock_info()) includes an optional create_time: float | None field, and is_running returns True only when the PID and the fingerprint match. Older 4-line lock files (no fingerprint) fall back to the previous PID-only check.
Gate CI on runtime readiness:
parse_since_window accepts Ns/Nm/Nh/Nd and bare integers (seconds) — align custom scripts with the CLI’s --since semantics by reusing it directly.

Healthcheck endpoint

Expose channel readiness as a JSON endpoint — the same probe the CLI runs, embedded in your own service.

Offline shell + turn gate for CI

Fail a deploy when shell wiring is broken, before any network call.
apply_probe_ca_bundle() honours the CA-bundle precedence ladder — PRAISONAI_SSL_CA_BUNDLE > REQUESTS_CA_BUNDLE > SSL_CERT_FILE — so a corporate CA set once fixes both the probe and long-lived channel connections. See Corporate CA bundle.