Gateway Channel Lifecycle

Add, update, disable, or remove one gateway channel non-interactively — CLI and Python, no wizard, no hand-editing.

Edit one channel in gateway.yaml / bot.yaml with a single command — other channels and settings stay untouched, and invalid edits are never written.

Diagram

Channel Lifecycle

➕ add

📄 gateway.yaml

✏️ update

⏸️ disable

🗑️ remove

🧪 Validate schema

💾 Atomic write

Quick Start

  1. Let an agent manage channels
    python
    from praisonaiagents import Agent
    from praisonai_bot import edit_gateway_channel
    
    def disable_channel(name: str) -> str:
        """Stop serving one gateway channel but keep its config."""
        edit_gateway_channel("gateway.yaml", name, {"enabled": False})
        return f"Disabled {name}"
    
    agent = Agent(
        name="gateway-ops",
        instructions="Manage my chat channels — pause them when asked.",
        tools=[disable_channel],
    )
    agent.start("Pause the Slack channel.")
  2. Or run the CLI directly
    bash
    # Add a channel (token defaults to the platform's ${VAR} reference)
    praisonai gateway channels add telegram
    
    # Add a channel with extra fields in one shot
    praisonai gateway channels add discord --set group_policy=mention_only
    
    # Rotate a token and change a policy
    praisonai gateway channels update telegram --token '${NEW_TELEGRAM_TOKEN}' --set group_policy=mention_only
    
    # Stop serving a channel but keep its config
    praisonai gateway channels disable slack
    
    # Delete the channel block entirely
    praisonai gateway channels remove slack
  3. Or call the Python helper
    python
    from praisonai_bot import edit_gateway_channel
    
    edit_gateway_channel("gateway.yaml", "discord", {"token": "${DISCORD_BOT_TOKEN}"})   # add
    edit_gateway_channel("gateway.yaml", "telegram", {"group_policy": "mention_only"})   # update
    edit_gateway_channel("gateway.yaml", "telegram", {"enabled": False})                 # disable
    edit_gateway_channel("gateway.yaml", "slack", remove=True)                           # remove

How It Works

Every edit is a locked read-modify-write: read the file, merge the change into channels[name], validate the whole document, then atomically replace the file.

Diagram
gateway.yamlGatewayConfigSchema.lock sidecaredit_gateway_channel()praisonai gateway channelsOperator / CIgateway.yamlGatewayConfigSchema.lock sidecaredit_gateway_channel()praisonai gateway channelsOperator / CIalt[invalid][valid]add discord –set group_policy=mention_onlyedit_gateway_channel(path, “discord”, settings)exclusive lockread current YAMLmigrate legacy platform: / platforms: → channels:merge settings into channels[“discord”]validate_gateway_config(cfg)ValueErrorrelease (file left unchanged)raiseError: <reason> (exit 1)temp file + os.replace (atomic)releasechannel blockAdded channel ‘discord’.

A failed validation leaves the file byte-for-byte unchanged, so a bad edit can never take a running gateway down on its next reload.


Choosing a Subcommand

Pick the subcommand by what should happen to the channel block.

Diagram

Create a channel block that is not there yet

Change fields on an existing channel

Stop serving but keep the config

Delete the block entirely

Just see what is configured

What do you need?

channels add

channels update

channels disable

channels remove

channels &(no subcommand&)


CLI Reference

All four subcommands accept --config / -c; when omitted they use the parent gateway channels --config value, which falls back to gateway.yaml and the onboarded ~/.praisonai/bot.yaml (see Config Discovery).

add

Argument / OptionTypeDefaultDescription
namepositional—Channel name, e.g. telegram. Must not already exist.
--platformstrthe channel namePlatform id, e.g. --platform discord for a channel named support.
--tokenstr`${

_BOT_TOKEN}-style reference | Channel token or ${VAR} reference. Defaults to the platform's documented credential env var. | | –set key=value | repeatable | — | Extra fields merged into the block. Values are YAML-parsed (enabled=false writes a boolean). | | –config, -c | str | parent –config` | Config path. |

bash
praisonai gateway channels add support --platform discord --set group_policy=mention_only

update

Argument / OptionTypeDefaultDescription
namepositional—Channel to update. Must exist.
--tokenstr—Replace the channel’s token.
--set key=valuerepeatable—Fields to update, YAML-typed values.
--config, -cstrparent --configConfig path.

Exits 1 with nothing to update; pass --token and/or --set key=value when neither --token nor --set is given.

disable

Argument / OptionTypeDefaultDescription
namepositional—Channel to disable. Must exist.
--config, -cstrparent --configConfig path.

Sets enabled: false. There is no separate enable command — re-enable with praisonai gateway channels update <name> --set enabled=true.

remove

Argument / OptionTypeDefaultDescription
namepositional—Channel block to delete. Must exist.
--config, -cstrparent --configConfig path.

Python API

python
from praisonai_bot import edit_gateway_channel

edit_gateway_channel(config_path, name, settings=None, *, remove=False) -> dict
ParameterTypeDefaultDescription
config_pathstr \os.PathLike[str]—Path to bot.yaml / gateway.yaml.
namestr—Channel name to add, update, or remove.
settings`dict \None`NoneFields merged into channels[name]. platform defaults to name. Pass {"enabled": False} to disable. Ignored when remove=True.
removebool (keyword-only)FalseDelete the channel block instead of upserting it.

Returns the resulting channel block ({} when remove=True).

RaisesWhen
FileNotFoundErrorThe config file does not exist (no .lock file is created).
KeyErrorremove=True and the channel is not configured.
ValueErrorThe edited document fails validation — unknown platform, bad types, or no enabled channel left.

Validation

The edited document is validated before the write; anything rejected leaves the file unchanged.

RuleBehaviour
${VAR} referencesKept verbatim in the saved file. Validation runs on an env-resolved copy, so unset placeholders pass.
Unknown platformRejected (ValueError / exit 1).
Bad field typesRejected (ValueError / exit 1).
Removing or disabling the last enabled channelRejected: at least one enabled channel must remain configured.
CLI add of an existing channelRejected: channel '<name>' already exists in <path>; use 'update'.
CLI update / disable / remove of a missing channelRejected: channel '<name>' is not configured in <path>.
--set without =Rejected: --set expects key=value, got '<pair>'.
--set key= (empty value)Writes the empty string.

Legacy Config Migration

Older single-bot and BotOS files are converted to a channels: block on the first edit.

Input shapeBehaviour
channels: already presentEdited in place; other channels untouched.
Single-bot: top-level platform: + token:Becomes channels.<platform> with that token (or the platform’s ${VAR} reference). Slack’s app_token moves into the block; unknown_user_policy / owner_user_id are copied in. A ${VAR} platform is resolved first, as the loader does.
BotOS: top-level platforms: mapEach entry becomes channels.<name> with platform: <name>; the platforms: key is removed.

Concurrent-Edit Safety

Each edit holds an exclusive OS advisory lock on a sidecar <config_path>.lock file (fcntl.flock on POSIX, msvcrt.locking on Windows), so parallel edits of different channels never overwrite each other.


Common Patterns

Rotate a token from CI

bash
praisonai gateway channels update telegram --token '${TELEGRAM_BOT_TOKEN_V2}'

Add the same channel to many tenants

python
from praisonai_bot import edit_gateway_channel

for tenant in ["acme", "globex"]:
    edit_gateway_channel(
        f"/etc/praisonai/{tenant}/bot.yaml",
        "discord",
        {"token": f"${{{tenant.upper()}_DISCORD_TOKEN}}"},
    )

Add one channel to a running gateway

bash
praisonai gateway channels add discord

A running gateway picks up the change through Config Reload.


Best Practices

Prefer ${VAR} references over literal tokens

Store token: ${DISCORD_BOT_TOKEN} rather than the secret itself. add writes a reference by default, and references survive every later edit verbatim. See Secret References.

Re-enable with update, not a separate command

praisonai gateway channels update <name> --set enabled=true is the re-enable path — there is intentionally no enable subcommand.

Disable before you remove

disable keeps the block, so rolling back is one update --set enabled=true. Run remove once you are sure.

Let the schema reject bad values

Skip pre-validation in scripts. A rejected edit exits 1 (or raises ValueError) and writes nothing.


Related