executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
creating-inline-actionsInteractive button-based UI for XMTP agents following XIP-67. Use when creating menus, confirmation dialogs, selection options, or any button-based interaction. Triggers on inline actions, buttons, menus, or ActionBuilder.
Independent GitHub snapshot · Automated classification · Original documentation governs
Interactive button-based UI for XMTP agents following the XIP-67 specification. Users can tap buttons instead of typing commands.
Reference these guidelines when:
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | ActionBuilder | CRITICAL | builder- |
| 2 | Helpers | HIGH | helpers- |
| 3 | App Config | MEDIUM | config- |
| 4 | Validators | MEDIUM | validators- |
builder-create - Create action menus with ActionBuilderbuilder-send - Send actions to conversationhelpers-confirmation - Send confirmation dialogshelpers-selection - Send selection menushelpers-navigation - Show navigation optionsconfig-menus - Configure multi-menu applicationsconfig-initialize - Initialize app from configvalidators-inbox-id - Validate inbox ID formatvalidators-ethereum-address - Validate Ethereum address// 1. Add middleware to handle intent messages
agent.use(inlineActionsMiddleware);
// 2. Register action handlers
registerAction("my-action", async (ctx) => {
await ctx.conversation.sendText("Action executed!");
});
// 3. Send interactive buttons
await ActionBuilder.create("my-menu", "Choose an option:")
.add("my-action", "Click Me")
.add("other-action", "Cancel")
.send(ctx);
Action registry and handler:
import type { AgentMiddleware, MessageContext } from "@xmtp/agent-sdk";
import type { Intent } from "@xmtp/node-sdk";
type ActionHandler = (ctx: MessageContext) => Promise<void>;
const actionHandlers = new Map<string, ActionHandler>();
const registerAction = (id: string, handler: ActionHandler) => {
actionHandlers.set(id, handler);
};
Inline actions middleware:
const inlineActionsMiddleware: AgentMiddleware = async (ctx, next) => {
if (ctx.message.contentType?.typeId === "intent") {
const intent = ctx.message.content as Intent;
const handler = actionHandlers.get(intent.actionId);
if (handler) await handler(ctx);
else await ctx.conversation.sendText(`Unknown action: ${intent.actionId}`);
return;
}
await next();
};
ActionBuilder class:
import { ActionStyle } from "@xmtp/node-sdk";
class ActionBuilder {
private actions: { id: string; label: string; style?: ActionStyle }[] = [];
constructor(private id: string, private description: string) {}
static create(id: string, description: string) {
return new ActionBuilder(id, description);
}
add(id: string, label: string, style?: ActionStyle) {
this.actions.push({ id, label, style });
return this;
}
async send(ctx: MessageContext) {
await ctx.conversation.sendActions({
id: this.id,
description: this.description,
actions: this.actions,
});
}
}
Confirmation helper:
const sendConfirmation = async (
ctx: MessageContext, message: string,
onYes: ActionHandler, onNo?: ActionHandler
) => {
const ts = Date.now();
registerAction(`yes-${ts}`, onYes);
registerAction(`no-${ts}`, onNo || (async (c) => c.conversation.sendText("Cancelled")));
await ActionBuilder.create(`confirm-${ts}`, message)
.add(`yes-${ts}`, "Yes").add(`no-${ts}`, "No", ActionStyle.Danger).send(ctx);
};
Read individual rule files for detailed explanations:
rules/builder-create.md
rules/helpers-confirmation.md
rules/config-menus.md