← All skills
Tencent SkillHub · Communication & Collaboration

Towns Protocol Skills

Use when building Towns Protocol bots - covers SDK initialization, slash commands, message handlers, reactions, interactive forms, blockchain operations, and deployment. Triggers: "towns bot", "makeTownsBot", "onSlashCommand", "onMessage", "sendInteractionRequest", "webhook", "bot deployment", "@towns-protocol/bot"

skill openclawclawhub Free
0 Downloads
0 Stars
0 Installs
0 Score
High Signal

Use when building Towns Protocol bots - covers SDK initialization, slash commands, message handlers, reactions, interactive forms, blockchain operations, and deployment. Triggers: "towns bot", "makeTownsBot", "onSlashCommand", "onMessage", "sendInteractionRequest", "webhook", "bot deployment", "@towns-protocol/bot"

⬇ 0 downloads ★ 0 stars Unverified but indexed

Install for OpenClaw

Quick setup
  1. Download the package from Yavira.
  2. Extract the archive and review SKILL.md first.
  3. Import or place the package into your OpenClaw setup.

Requirements

Target platform
OpenClaw
Install method
Manual import
Extraction
Extract archive
Prerequisites
OpenClaw
Primary doc
SKILL.md

Package facts

Download mode
Yavira redirect
Package format
ZIP package
Source platform
Tencent SkillHub
What's included
SKILL.md, references/BLOCKCHAIN.md, references/DEBUGGING.md, references/DEPLOYMENT.md, references/INTERACTIVE.md, references/MESSAGING.md

Validation

  • Use the Yavira download entry.
  • Review SKILL.md after the package is downloaded.
  • Confirm the extracted package contains the expected setup assets.

Install with your agent

Agent handoff

Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.

  1. Download the package from Yavira.
  2. Extract it into a folder your agent can access.
  3. Paste one of the prompts below and point your agent at the extracted folder.
New install

I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.

Upgrade existing

I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.

Trust & source

Release facts

Source
Tencent SkillHub
Verification
Indexed source record
Version
2.0.0

Documentation

ClawHub primary doc Primary doc: SKILL.md 16 sections Open source page

Critical Rules

MUST follow these rules - violations cause silent failures: User IDs are Ethereum addresses - Always 0x... format, never usernames Mentions require BOTH - <@{userId}> format in text AND mentions array in options Two-wallet architecture: bot.viem.account.address = Gas wallet (signs & pays fees) - MUST fund with Base ETH bot.appAddress = Treasury (optional, for transfers) Slash commands DON'T trigger onMessage - They're exclusive handlers Interactive forms use type property - Not case (e.g., type: 'form') Never trust txHash alone - Verify receipt.status === 'success' before granting access

Key Imports

import { makeTownsBot, getSmartAccountFromUserId } from '@towns-protocol/bot' import type { BotCommand, BotHandler } from '@towns-protocol/bot' import { Permission } from '@towns-protocol/web3' import { parseEther, formatEther, erc20Abi, zeroAddress } from 'viem' import { readContract, waitForTransactionReceipt } from 'viem/actions' import { execute } from 'viem/experimental/erc7821'

Handler Methods

MethodSignatureNotessendMessage(channelId, text, opts?) → { eventId }opts: { threadId?, replyId?, mentions?, attachments? }editMessage(channelId, eventId, text)Bot's own messages onlyremoveEvent(channelId, eventId)Bot's own messages onlysendReaction(channelId, messageId, emoji)sendInteractionRequest(channelId, payload)Forms, transactions, signatureshasAdminPermission(userId, spaceId) → booleanban / unban(userId, spaceId)Needs ModifyBanning permission

Bot Properties

PropertyDescriptionbot.viemViem client for blockchainbot.viem.account.addressGas wallet - MUST fund with Base ETHbot.appAddressTreasury wallet (optional)bot.botIdBot identifier For detailed guides, see references/: Messaging API - Mentions, threads, attachments, formatting Blockchain Operations - Read/write contracts, verify transactions Interactive Components - Forms, transaction requests Deployment - Local dev, Render, tunnels Debugging - Troubleshooting guide

Project Initialization

bunx towns-bot init my-bot cd my-bot bun install

Environment Variables

APP_PRIVATE_DATA=<base64_credentials> # From app.towns.com/developer JWT_SECRET=<webhook_secret> # Min 32 chars PORT=3000 BASE_RPC_URL=https://base-mainnet.g.alchemy.com/v2/KEY # Recommended

Basic Bot Template

import { makeTownsBot } from '@towns-protocol/bot' import type { BotCommand } from '@towns-protocol/bot' const commands = [ { name: 'help', description: 'Show help' }, { name: 'ping', description: 'Check if alive' } ] as const satisfies BotCommand[] const bot = await makeTownsBot( process.env.APP_PRIVATE_DATA!, process.env.JWT_SECRET!, { commands } ) bot.onSlashCommand('ping', async (handler, event) => { const latency = Date.now() - event.createdAt.getTime() await handler.sendMessage(event.channelId, 'Pong! ' + latency + 'ms') }) export default bot.start()

Config Validation

import { z } from 'zod' const EnvSchema = z.object({ APP_PRIVATE_DATA: z.string().min(1), JWT_SECRET: z.string().min(32), DATABASE_URL: z.string().url().optional() }) const env = EnvSchema.safeParse(process.env) if (!env.success) { console.error('Invalid config:', env.error.issues) process.exit(1) }

onMessage

Triggers on regular messages (NOT slash commands). bot.onMessage(async (handler, event) => { // event: { userId, spaceId, channelId, eventId, message, isMentioned, threadId?, replyId? } if (event.isMentioned) { await handler.sendMessage(event.channelId, 'You mentioned me!') } })

onSlashCommand

Triggers on /command. Does NOT trigger onMessage. bot.onSlashCommand('weather', async (handler, { args, channelId }) => { // /weather San Francisco → args: ['San', 'Francisco'] const location = args.join(' ') if (!location) { await handler.sendMessage(channelId, 'Usage: /weather <location>') return } // ... fetch weather })

onReaction

bot.onReaction(async (handler, event) => { // event: { reaction, messageId, channelId } if (event.reaction === '👋') { await handler.sendMessage(event.channelId, 'I saw your wave!') } })

onTip

Requires "All Messages" mode in Developer Portal. bot.onTip(async (handler, event) => { // event: { senderAddress, receiverAddress, amount (bigint), currency } if (event.receiverAddress === bot.appAddress) { await handler.sendMessage(event.channelId, 'Thanks for ' + formatEther(event.amount) + ' ETH!') } })

onInteractionResponse

bot.onInteractionResponse(async (handler, event) => { switch (event.response.payload.content?.case) { case 'form': const form = event.response.payload.content.value for (const c of form.components) { if (c.component.case === 'button' && c.id === 'yes') { await handler.sendMessage(event.channelId, 'You clicked Yes!') } } break case 'transaction': const tx = event.response.payload.content.value if (tx.txHash) { // IMPORTANT: Verify on-chain before granting access // See references/BLOCKCHAIN.md for full verification pattern await handler.sendMessage(event.channelId, 'TX: https://basescan.org/tx/' + tx.txHash) } break } })

Event Context Validation

Always validate context before using: bot.onSlashCommand('cmd', async (handler, event) => { if (!event.spaceId || !event.channelId) { console.error('Missing context:', { userId: event.userId }) return } // Safe to proceed })

Common Mistakes

MistakeFixinsufficient funds for gasFund bot.viem.account.address with Base ETHMention not highlightingInclude BOTH <@userId> in text AND mentions arraySlash command not workingAdd to commands array in makeTownsBotHandler not triggeringCheck message forwarding mode in Developer PortalwriteContract failingUse execute() for external contractsGranting access on txHashVerify receipt.status === 'success' firstMessage lines overlappingUse \n\n (double newlines), not \nMissing event contextValidate spaceId/channelId before using

Resources

Developer Portal: https://app.towns.com/developer Documentation: https://docs.towns.com/build/bots SDK: https://www.npmjs.com/package/@towns-protocol/bot Chain ID: 8453 (Base Mainnet)

Category context

Messaging, meetings, inboxes, CRM, and teammate communication surfaces.

Source: Tencent SkillHub

Largest current source with strong distribution and engagement signals.

Package contents

Included in package
6 Docs
  • SKILL.md Primary doc
  • references/BLOCKCHAIN.md Docs
  • references/DEBUGGING.md Docs
  • references/DEPLOYMENT.md Docs
  • references/INTERACTIVE.md Docs
  • references/MESSAGING.md Docs