Behavior guides
Each channel has its own conventions: Slack threads, WhatsApp's 24-hour window, SMS segment length, iMessage plain text. Caspian hands your agent a ready-to-inject block of per-channel etiquette so its replies read native on every platform. It is opt-in: use it, tweak it, or ignore it.
Behavior guides are for the agent's brain, the LLM writing the reply. That is different from SKILL.md, which is for the coding agent wiring up the integration.
The mental model
You write one on_message handler for every channel. But a good reply on Slack is a bad reply over SMS: Slack wants mrkdwn in a thread, SMS wants one short plain-text line. Behavior guides encode those differences as plain-text instructions your model can follow. You append them to your system prompt and let the LLM pick the right convention for whichever channel the message arrived on.
Get the combined prompt
behavior_prompt() returns a single system-prompt block covering exactly the channels your project has connected. Append it to your agent's system prompt before you start replying.
from caspian_sdk import CommClient
client = CommClient()
client.connect_email()
client.install_slack(display_name="Acme Bot")
# Etiquette for the channels you connected, as one block of text.
guide = client.behavior_prompt()
SYSTEM_PROMPT = f"""You are Acme's support agent. Be helpful and concise.
{guide}"""
@client.on_message
def handle(message):
reply = my_llm(system=SYSTEM_PROMPT, user=message.text)
message.reply(reply)
client.listen()import { CommClient } from "caspian-sdk";
const client = new CommClient();
await client.connectEmail();
await client.installSlack({ displayName: "Acme Bot" });
// Etiquette for the channels you connected, as one block of text.
const guide = await client.behaviorPrompt();
const SYSTEM_PROMPT = `You are Acme's support agent. Be helpful and concise.
${guide}`;
client.onMessage(async (message) => {
const reply = await myLlm({ system: SYSTEM_PROMPT, user: message.text });
await message.reply(reply);
});
await client.listen();The block only lists channels you have actually connected, so the prompt never wastes tokens on platforms your agent doesn't use. If nothing is connected yet, it returns an empty string, safe to append unconditionally.
Call behavior_prompt() once at startup after your connect_*() calls and cache the result. The text is stable; you don't need to fetch it per message.
Get one channel's guide
channel_guide("slack") returns the etiquette for a single channel by its logical name, handy for docs, testing, or building your own prompt by hand. This endpoint is public: it describes the channel in general, not your project's connections.
print(client.channel_guide("slack"))
print(client.channel_guide("whatsapp"))console.log(await client.channelGuide("slack"));
console.log(await client.channelGuide("whatsapp"));Channel names are the logical channel, not the provider: for example slack, whatsapp, x, imessage, phone (SMS), email, telegram, discord. An unknown channel returns a 404.
What the guides encode
Each guide is a few plain-text lines about threading, formatting, length, and etiquette for that surface. A sampling:
| Channel | What the guide tells the agent |
|---|---|
| Slack | Stay in the thread reply() posts to; respond only when @-mentioned or in a DM; use Slack mrkdwn (*bold*, not **bold**); keep it chat-length. |
| Discord | Reply in the same channel or thread; standard markdown works; hard ~2000-character limit per message, split longer answers. |
| Plain, personal 1:1 text; you can reply freely only within the 24-hour customer-service window, so answer promptly. | |
| SMS | Plain text, no formatting, very short: long messages split into multiple billed segments; avoid links. |
| iMessage | Plain text only: markdown and code blocks render as literal characters; short texting-style messages. |
| X (Twitter) | Public replies capped at 280 characters (links count); DMs allow ~10,000 chars, plain, no markdown. |
| Longer-form is fine; replies quote and thread automatically, so don't restate the whole thread; assume plain rendering. | |
| Telegram | Supports Markdown (*bold*, _italic_, `code`); keep messages fairly short and personal. |
The combined behavior_prompt() block prepends a short header explaining that one handler serves several channels and the agent should follow whichever section matches the incoming message's channel.
Opt-in by design
Nothing about behavior guides is mandatory. They are text, not policy: Caspian never rewrites your replies. Three ways to use them:
- Use as-is: append
behavior_prompt()to your system prompt and move on. - Tweak: fetch a guide, edit the parts you disagree with, and inject your version.
- Ignore: write your own channel rules, or none at all. Your handler still works.
Under the hood: behavior_prompt() calls GET /v1/behavior-prompt (authenticated, scoped to your project's active connections) and channel_guide() calls GET /v1/channels/{channel}/guide (public). Both return plain text.