Skip to content

docs(bot-security): update Gateway Pairing section — document list_pending schema, CLI subcommands, and REST API (follow-up to PraisonAI#1520) #231

@MervinPraison

Description

@MervinPraison

Context

Follow-up documentation work triggered by MervinPraison/PraisonAI#1520fix(gateway): remove duplicate PairingStore.list_pending and preserve legacy keys (merged 2026-04-22).

That PR:

  • Removed a duplicate list_pending() method on PairingStore (the second definition was silently overriding the first at class-define time).
  • Consolidated the response so list_pending() now returns both the canonical keys used by the CLI / tests and the UI-friendly aliases used by the praisonai.ui._pairing banner.
  • Added optional channel_type filtering.

Because the PR codifies the stable response schema for list_pending() and surfaces the fact that multiple consumers (CLI, UI banner, REST endpoint GET /api/pairing/pending) depend on it, this is the right moment to close several existing documentation gaps around gateway pairing.

This issue is scoped for a doc-writing agent. All paths below are relative to the MervinPraison/PraisonAIDocs repo unless stated otherwise.

Note

Per AGENTS.md §1.8, all new/updated pages must live under docs/features/, docs/guides/, docs/cli/, docs/tools/, or docs/best-practices/ — never docs/concepts/. The existing Gateway Pairing content already lives in docs/best-practices/bot-security.mdx, which is allowed.


SDK Ground Truth (read these BEFORE writing docs)

Per AGENTS.md §1.2 (SDK-First Documentation Cycle), read each file before documenting any symbol from it. All paths are in MervinPraison/PraisonAI @ main (merged commit 3d8a3dc):

File Why it matters
src/praisonai/praisonai/gateway/pairing.py PairingStore class — authoritative for list_pending, list_paired, generate_code, verify_and_pair, is_paired, approve, revoke.
src/praisonai/praisonai/gateway/pairing_routes.py Starlette routes — authoritative for GET /api/pairing/pending, POST /api/pairing/approve, POST /api/pairing/revoke.
src/praisonai/praisonai/cli/commands/pairing.py typer app — authoritative for praisonai pairing {list,approve,revoke,clear} CLI subcommands.
src/praisonai/praisonai/cli/app.py Line 537: app.add_typer(pairing_app, name="pairing", ...) registers the subcommand group.
src/praisonai/praisonai/ui/_pairing.py UI banner consumer — confirms why the channel / user_id / user_name / age_seconds aliases are retained.
src/praisonai/praisonai/bots/_unknown_user.py (line 171) and _auth.py (line 129) Both emit the hint praisonai pairing approve {platform} {code} to users — confirms the CLI command is public/user-facing.
src/praisonai/tests/unit/gateway/test_gateway_approval.py::test_pending_persists_across_instances Authoritative contract for `list_pending()[*]["code"

Recommendation: Update existing content, do NOT create a new page

After reviewing the change and the existing docs, this is an UPDATE, not a new page:

  • The Gateway Pairing section already exists in docs/best-practices/bot-security.mdx (lines ~215–265).
  • That section currently carries stale <Warning> callouts claiming the APIs are "planned functionality" and "conceptual". Those warnings are now incorrect — the APIs ship, are tested, and are referenced from the bot error messages users see in production.
  • There are real gaps (CLI subcommands, REST endpoints, list_pending response schema) that fit naturally as subsections of the existing Gateway Pairing area rather than a new top-level page.

If the existing section grows past ~300 lines after these updates, the doc author may split CLI and REST content into a dedicated docs/features/gateway-pairing.mdx page and link to it from bot-security.mdx. Default to updating in place.


Changes Required

Change 1 — Remove stale "planned functionality" warnings

File: docs/best-practices/bot-security.mdx

At lines ~217–219, remove:

<Warning>
**Note:** The pairing system described below represents planned functionality. Current SDK implementation may differ. Verify against actual SDK documentation.
</Warning>

Also remove the inline code comment # Note: This API is conceptual - verify implementation at ~line 236, and the # Note: Verify this API exists in current SDK at ~line 258.

Rationale: PairingStore ships today. Tests (test_gateway_approval.py) cover it. The CLI (praisonai pairing ...) is wired up in cli/app.py. Bot auth errors reference it. The warnings are misleading.

Keep the unrelated Doctor warning at ~line 269 unchanged — that one concerns a different command.


Change 2 — Document the list_pending() response schema

File: docs/best-practices/bot-security.mdx, inside the Gateway Pairing subsection (after the existing §4 "Check Status" block, ~line 265).

Add a new "List Pending Requests" subsection showing both keys. Follow AGENTS.md §6 style rules — one-sentence intros, active voice, no forbidden phrases.

Minimum code example:

from praisonaiagents.gateway.pairing import PairingStore

store = PairingStore()

# All pending codes across every channel
for req in store.list_pending():
    print(req["code"], req["channel_type"], req["channel_id"], req["age_seconds"])

# Filter by channel
telegram_only = store.list_pending(channel_type="telegram")

Important

The exact import path is from praisonaiagents.gateway.pairing import PairingStore only if the praisonaiagents package re-exports it. The ground-truth source file lives at src/praisonai/praisonai/gateway/pairing.py inside the praisonai CLI package, not praisonai-agents. Before publishing, the doc agent must verify the correct import path by checking praisonaiagents/gateway/__init__.py and praisonai/gateway/__init__.py in the synced source tree. Do not guess — AGENTS.md §1.2 forbids it.

Response schema table (extracted directly from pairing.py lines 295–305):

Key Type Source Notes
code str canonical 8-char pairing code
channel_type str canonical e.g. "telegram", "discord", "slack", "whatsapp"
channel_id str | None canonical Bound channel id if code was generated with one
created_at float canonical Unix timestamp (seconds) when code was generated
channel str UI alias Same value as channel_type, kept for UI banner compatibility
user_id str UI alias Currently equals code (see note in approve() docstring)
user_name str UI alias Formatted as "User {code}"
age_seconds int UI alias int(now - created_at)

Add a short <Note>:

Canonical keys (code, channel_type, channel_id, created_at) are the stable contract. The channel, user_id, user_name, and age_seconds aliases are provided for UI consumers and should not be relied on for scripting — use the canonical keys.


Change 3 — Document the praisonai pairing CLI subcommands

File: prefer extending existing docs/cli/bot.mdx with a new "Pairing Subcommands" section. If that page is the wrong home (check its scope first), create docs/cli/pairing.mdx and add it under the "CLI" group in docs.json (per AGENTS.md §1.8, never under "Concepts").

Commands to document (source: src/praisonai/praisonai/cli/commands/pairing.py):

Command Positional args Options Purpose
praisonai pairing list --store-dir List all paired channels
praisonai pairing approve PLATFORM CODE [CHANNEL_ID] platform, code, optional channel_id --label, --store-dir Approve an 8-char pairing code
praisonai pairing revoke PLATFORM CHANNEL_ID platform, channel_id --store-dir Revoke a paired channel
praisonai pairing clear --store-dir (verify flags in source) Clear all paired channels

Platform values: telegram, discord, slack, whatsapp (from typer Argument help text).

Required example — this is the exact command the bot prints to users, so it must appear verbatim in the docs:

praisonai pairing approve telegram abc12345

Include a Mermaid sequence diagram (per AGENTS.md §3.4) showing the end-to-end pairing flow:

User → Bot (DM)           : unknown, triggers pairing
Bot → PairingStore        : generate_code(channel_type, channel_id)
Bot → User                : "Ask owner to run: praisonai pairing approve telegram abc12345"
Owner → CLI               : praisonai pairing approve telegram abc12345
CLI → PairingStore        : verify_and_pair()
PairingStore → Disk       : _save() (atomic)
User → Bot                : now authorised

Use the standard color palette from AGENTS.md §3.1 (dark red #8B0000 for Agent/User, teal #189AB4 for tools/CLI, green #10B981 for success, white text).


Change 4 — Document the REST API endpoints

Target file: pick one of:

  • Extend docs/best-practices/bot-security.mdx with a final "REST API" subsection, or
  • Create docs/features/gateway-pairing-api.mdx if content exceeds a few paragraphs. Register under the "Features" group in docs.json (never "Concepts").

Endpoints (source: src/praisonai/praisonai/gateway/pairing_routes.py):

Method Path Body / Query Response Notes
GET /api/pairing/pending list_pending() schema (see Change 2) Rate-limited via pairing_pending bucket when a rate limiter is attached
POST /api/pairing/approve { "channel": str, "code": str } { "approved": true, ... } Rate-limited via pairing_approve bucket
POST /api/pairing/revoke { "channel": str, "user_id": str } { "revoked": true, ... } Rate-limited via pairing_revoke bucket

The doc agent must read pairing_routes.py end-to-end to confirm the exact request/response JSON shapes and any auth requirements — auth_checker is a required constructor argument on create_pairing_routes(...), so these endpoints are authenticated; call that out explicitly.


Change 5 — (Optional but recommended) Add a feature-level troubleshooting note

The Troubleshooting → Pairing Issues block already exists (~line 462 of bot-security.mdx). Extend it with a new bullet covering the symptom fixed by this PR, phrased as user-facing guidance (not SDK-internal):

Symptom: praisonai pairing approve reports "Invalid or expired code" even though a code was just generated from the UI (or vice versa).
Fix: Upgrade to praisonai >= <version that contains #1520>. Older builds shipped a duplicate internal method that stripped the canonical code key when the UI pairing banner was loaded.

The doc agent should replace <version that contains #1520> with the actual release version by checking CHANGELOG.md / pyproject.toml in MervinPraison/PraisonAI at the time of writing — do not leave the placeholder.


Out of Scope

  • Do not add or alter anything under docs/concepts/ (AGENTS.md §1.8 — human-approved only).
  • Do not touch auto-generated docs/js/* or docs/rust/* parity pages.
  • Do not document PairingStore._pending, _paired, _save, _prune_expired, or any other underscore-prefixed internals.
  • Do not regenerate docs.json from scratch — apply minimal additions only.

Acceptance Criteria

  • Stale "planned functionality" warnings in docs/best-practices/bot-security.mdx removed.
  • list_pending() response schema documented with both canonical + alias keys and a <Note> clarifying which to rely on.
  • praisonai pairing list | approve | revoke | clear documented with the exact approve telegram abc12345 command shown verbatim (matches the string emitted by _unknown_user.py and _auth.py).
  • /api/pairing/{pending,approve,revoke} documented with auth + rate-limit notes.
  • Mermaid diagram follows the §3.1 color palette (white text, #8B0000 / #189AB4 / #10B981).
  • Every code example runs copy-paste, includes all imports, uses no placeholder secrets (AGENTS.md §5.1).
  • Import paths verified against the actual praisonaiagents/gateway/__init__.py / praisonai/gateway/__init__.py — no guesses.
  • All touched files pass docs.json JSON validation (AGENTS.md §1.9 rule 8).

Notes for the Doc Agent

The working branch per the session instructions is claude/admiring-euler-ODEBP. Create and push to that branch, then open a draft PR against main in MervinPraison/PraisonAIDocs.

Remember AGENTS.md §1.1 item 6: these docs are user-focused, not SDK-focused. The auto-generated SDK reference covers parameter-by-parameter detail. This issue's target audience is a self-hosting bot operator who wants to know: "how do I approve a pending channel without reading Python source?"

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions