CLI: Channels
Channels are the entry points for messages into your agents. Each channel has a type (webhook, slack, telegram, email, mcp, cron, heartbeat) and belongs to exactly one agent with a configurable session strategy.
Browse the channel catalog
# List all catalog entries
valet channels catalog
# Show details for a specific entry
valet channels catalog get <name>$ valet channels catalog
github-webhook webhook WEBHOOK_SECRET GitHub webhook (HMAC-SHA256)
slack-events webhook WEBHOOK_SECRET Slack Events APICreate from catalog
valet channels create <entry> [--agent <agent>] [--org <org>] [--as <name>]If the argument matches a catalog entry, provisions a channel using that entry's default configuration. Managed secrets are auto-generated for any secret slots the entry defines. Use --as to give the channel a custom name.
Create a webhook channel
valet channels create webhook [name] \
[--agent <agent>] [--org <org>] \
[--verify <scheme>] [--secret-name <NAME>] [--signature-header <header>] \
[--delivery-key-header <header>] [--delivery-key-path <path>]Generates a webhook URL and a managed signing secret used to verify inbound requests. The managed secret is stored as a secret-kind env var (valet env) and can be rotated with valet env set. When --secret-name is provided, the channel references an existing secret by that name instead of auto-generating one — use this for services like Stripe or Svix where you control the signing key.
Verification schemes:
- hmac-sha256 (default) — HMAC-SHA256 of the raw body. Default header:
X-Webhook-Signature; change it with--signature-header. - stripe — HMAC-SHA256 of
{timestamp}.{body}, parsed from theStripe-Signatureheader. Use--signature-headerfor providers that use the same format with a different header (e.g. WorkOS). Requires--secret-name. - mercury — Same HMAC-SHA256 envelope as
stripewith theMercury-Signatureheader. Requires--secret-name. - svix — HMAC-SHA256 of
{msg_id}.{timestamp}.{body}; reads thesvix-*headers, falling back towebhook-*(standard-webhooks senders). Requires--secret-name. - slack — Slack Events API verification: HMAC-SHA256 of
v0:{timestamp}:{body}, readingX-Slack-Request-TimestampandX-Slack-Signature. Handlesurl_verificationchallenges automatically. Requires--secret-name. - static-token — Constant-time comparison of a bearer token.
- none — No verification. Use for testing or trusted networks.
Use --delivery-key-header (e.g. X-GitHub-Delivery) or --delivery-key-path (e.g. event.id) to deduplicate deliveries by a unique ID.
# Default hmac-sha256 verification (auto-generates managed secret)
$ valet channels create webhook my-channel
Creating webhook channel on my-agent agent in acme org... done, my-channel
type: webhook
url: https://gateway.valet.dev/webhook/abc123
secret: whsec_abc123
managed: MY_CHANNEL_WEBHOOK_SECRET
verify: hmac-sha256 (X-Webhook-Signature)
agent: my-agent
strategy: per_invocation
prompt: channels/my-channel.md
# Stripe webhooks with a managed secret reference
$ valet channels create webhook stripe-events \
--verify stripe \
--secret-name STRIPE_WEBHOOK_SECRETCreate a Slack channel
valet channels create slack [name] [--agent <agent>] [--org <org>] \
[--bot-name <display-name>]Setup is two-phase:
- Per-org — run with
--orgto connect Slack to the org. The CLI prompts for a Slack app configuration token and refresh token (generate them athttps://api.slack.com/appsunder "Your App Configuration Tokens"). - Per-agent — run with
--agent(or from a linked project directory) to create a dedicated Slack app for that agent. Requires an existing org-level Slack connection. Use--bot-nameto customize the bot display name (default: the agent name).
# Connect the org to Slack first (prompts for config token + refresh token)
$ valet channels create slack --org acme
Slack app configuration token: ********
Slack app refresh token: ********
Connected to Acme (T12345)
# Then create a per-agent Slack channel
$ valet channels create slack my-slack-bot --bot-name support-bot
Checking Slack connection... connected (Acme)
Creating slack channel on my-agent agent in acme org... done, my-slack-bot
type: slack
bot: @support-bot
workspace: Acme (T12345)
agent: my-agent
strategy: per_conversation
prompt: channels/my-slack-bot.mdSlack activity levels
valet channels slack [--agent <agent>]
valet channels slack add <#conversation>
valet channels slack set <#conversation> <level>
valet channels slack set-default <level>An activity level controls what wakes the agent in a conversation: mentions (only @-mentions), emails (@-mentions and forwarded emails), or all (every message). The channel default is a template stamped onto each conversation when the bot joins it; changing the default never re-points conversations the bot is already in. Running valet channels slack with no subcommand lists the bot's conversations with each conversation's effective level.
Create a Telegram channel
valet channels create telegram [name] [--agent <agent>]After creating the channel, connect it by visiting the Telegram deep link (a t.me URL) shown in the output.
Create an email channel
valet channels create email [name] [--agent <agent>] \
[--local-part <part>] [--mailbox <address>] [--sender-policy open|allowlist|org]Creates an email channel backed by a @valet.run mailbox. By default a new mailbox is minted with a randomly generated address in the org's namespace. Pass --local-part to choose the address's local part, or --mailbox to bind the exact existing address of an org-owned mailbox. The --sender-policy flag controls which senders may reach the agent: open (any sender passing the gates), allowlist, or org (org members only). An agent may have several named email channels, each bound to a distinct mailbox and prompt.
$ valet channels create email inbox
Creating email channel on my-agent agent in acme org... done, inbox
type: email
address: wandering-brook-7h3k@acme.valet.run
policy: open
agent: my-agent
strategy: persistent
prompt: channels/inbox.mdCreate an MCP channel
valet channels create mcp [name] [--agent <agent>]Exposes the agent as an MCP server over Streamable HTTP at the endpoint URL shown in the output. It exposes a built-in ask_<agent> tool that takes a message and returns the agent's response. Define additional tools by adding mcp/<tool>.md files to the agent.
MCP channel tokens
valet channels token mint <channel> <token-name> \
[--tools <names>] [--expires <duration|timestamp>] [--rate-limit <per-minute>]
valet channels token list <channel>
valet channels token revoke <channel> <token-name>Clients authenticate with bearer credentials minted via valet channels token mint. The plaintext token is printed exactly once; store it securely. Use --tools to narrow the credential to specific tools, --expires to set an expiry, and --rate-limit to cap tool calls per minute. Revocation is immediate and permanent.
Create a cron channel
# Human-readable schedule
valet channels create cron daily-report --schedule "every day at 9:00am"
# Raw crontab expression
valet channels create cron weekly --cron "0 9 * * 1" --timezone US/EasternProvide either --schedule with a human-readable description or --cron with a raw crontab expression. The two flags are mutually exclusive. Use --timezone to specify an IANA timezone (default: UTC).
Create a heartbeat channel
valet channels create heartbeat health-check --every 5mTriggers at a fixed interval. The --every flag is required and specifies the interval (e.g. 5m, 1h, 30s).
Attach and detach
valet channels attach <channel-name> [--agent <agent>] [--as <alias>] \
[--events <types>] [--bot-name <name>]
valet channels detach <alias> [--agent <agent>] [--force]Attach an org-scoped channel to an agent. Use --events to filter which event types are routed to the agent (comma-separated). The --as flag gives the attachment a custom alias. For Slack channels, attaching provisions a per-agent Slack bot with its own identity in the workspace; detaching destroys it (use --force to skip the confirmation prompt). Detaching never deletes the org channel itself.
Reauthorize a channel
valet channels reauthorize <name> [--agent <agent>] [--print-url]Mints a fresh authorization URL for a channel that holds third-party credentials and opens it in your browser. For Slack channels, this pushes the current bot scopes to the Slack app's manifest and returns the reinstall URL. For Telegram channels, it regenerates the deep link. Channels with no credentials (cron, heartbeat, webhook) cannot be reauthorized. Use --print-url to print the URL instead of opening a browser (for SSH or CI).
List channels
valet channels [--org <org>] [--agent <agent>]Lists channels visible to you. Resolution order when no flags are provided: linked agent in the current directory, then the default org.
Channel info
valet channels info <name> [-a <agent>] [-o <org>]Shows the channel's type, webhook URL, signing secret, managed secret name, verification scheme, status, owning org or agent, session strategy, and prompt path.
Destroy a channel
valet channels destroy <name> [-a <agent>] [-o <org>]Permanently removes the channel. Cannot be undone. Destroying an org-level Slack channel cascades: all per-agent Slack bots are destroyed first, then the org Slack connection is removed.