Search documentation

Search for docs or ask AI

Setting Up Actions

This guide walks through implementing actions in your application. For a conceptual overview of what actions are and why they matter, see Actions.

Build with AI

Use this prompt with Cursor or Claude Code to automatically generate actions tailored to your application:

Tip: Use.to enable Plan mode in Cursor for best results
# Build Pillar SDK Actions for My App

I want to implement Pillar SDK actions for my application. Help me create a comprehensive set of actions that will make my app's co-pilot useful.

## Pillar SDK Overview

Pillar actions are defined using `defineActions()` and registered with handlers. Here's the pattern:

```tsx
// lib/pillar/actions.ts
import { defineActions } from '@pillar-ai/sdk';

export const actions = defineActions({
  action_name: {
    description: 'AI-friendly description of what this does',
    type: 'navigate' | 'trigger_action' | 'inline_ui' | 'external_link' | 'copy_text',
    examples: ['phrases users might say'],
    path: '/route',           // for navigate
    autoRun: true,            // execute without clicking
    autoComplete: true,       // mark done immediately
    dataSchema: { ... },      // JSON Schema for data extraction
    requiredContext: { ... }, // context filtering
    handler: (data) => { ... },
  },
});
```

### Action Types
- **navigate**: Go to a page (use with `path` and `autoRun: true`)
- **trigger_action**: Run custom logic (modals, wizards, toggles)
- **inline_ui**: Show interactive UI in chat
- **external_link**: Open URL in new tab
- **copy_text**: Copy to clipboard

### Handler Pattern
```tsx
// components/PillarActionHandlers.tsx
import { usePillar } from '@pillar-ai/react';

export function PillarActionHandlers() {
  const { pillar } = usePillar();
  const router = useRouter();

  useEffect(() => {
    if (!pillar) return;
    const handlers = [
      pillar.onTask('navigate', ({ path }) => {
        router.push(path);
        return { success: true };
      }),
      // ... more handlers
    ];
    return () => handlers.forEach(unsub => unsub?.());
  }, [pillar, router]);

  return null;
}
```

## Your Task

1. **Analyze my codebase** to understand:
   - Framework (Next.js, React, Vue, etc.)
   - Routing pattern and all navigable pages
   - Modal/dialog systems (what modals exist?)
   - Key user flows and features
   - Authentication and role patterns

2. **Identify valuable actions** in these categories:

   **Navigation Actions** (type: 'navigate')
   - All main pages users might want to reach
   - Settings sections (account, billing, notifications, etc.)
   - Dashboard views and detail pages
   - Use `autoRun: true` for simple navigations

   **Trigger Actions** (type: 'trigger_action')
   - Modals: invite users, create items, confirmations
   - Wizards: onboarding, setup flows, multi-step processes
   - Feature toggles: dark mode, sidebar, notifications
   - Actions that open forms or dialogs

   **Context-Filtered Actions**
   - Admin-only actions with `requiredContext: { userRole: 'admin' }`
   - Feature-gated actions based on subscription/plan
   - Page-specific actions

3. **Generate implementation files:**

   a. `lib/pillar/actions.ts`:
      - 15-25 well-described actions
      - Clear, specific descriptions that help AI matching
      - Example phrases for each action (3-5 per action)
      - dataSchema for actions that need extracted data

   b. `components/PillarActionHandlers.tsx`:
      - Centralized handler component
      - Proper cleanup with useEffect
      - Error handling with user-friendly messages
      - Router integration for navigation

4. **For each action, include:**
   - A specific description (not generic)
   - Multiple example phrases users might say
   - The right action type
   - Any required context filtering

## Start Here

First, explore my codebase:
1. Look at the routing structure (pages/, app/, or routes/)
2. Find modal/dialog components
3. Identify settings pages and their sections
4. Look for admin-only features
5. Find any existing navigation patterns

Then ask me about:
- What are the main features of my app?
- What user roles exist?
- What actions do users ask about most often?

Defining Actions

Define and export your actions:

examples/guides/actions/define-actions-basic.ts
// lib/pillar/actions/index.ts
import type { SyncActionDefinitions } from '@pillar-ai/sdk';
export const actions = {
open_settings: {
description: 'Navigate to the settings page',
type: 'navigate' as const,
path: '/settings',
autoRun: true,
autoComplete: true,
},
invite_member: {
description: 'Open the invite team member modal',
examples: [
'invite someone to my team',
'add a new user',
'how do I invite people?',
],
type: 'trigger_action' as const,
},
view_billing: {
description: 'Navigate to billing and subscription settings',
type: 'navigate' as const,
path: '/settings/billing',
autoRun: true,
autoComplete: true,
},
} as const satisfies SyncActionDefinitions;
export default actions;

Action Types

TypeDescriptionUse Case
navigateNavigate to a page in your appSettings, dashboard, detail pages
trigger_actionRun custom logicOpen modals, start wizards, toggle features
inline_uiShow interactive UI in chatForms, confirmations, previews
external_linkOpen URL in new tabDocumentation, external resources
copy_textCopy text to clipboardAPI keys, code snippets

Action Properties

examples/guides/actions/action-properties.ts
{
// Required
description: string, // AI uses this to match user intent
type: ActionType, // One of the types above
handler: (data) => void, // Your execution logic
// Optional
examples?: string[], // Example phrases that trigger this action
path?: string, // For navigate actions
externalUrl?: string, // For external_link actions
autoRun?: boolean, // Execute without user clicking (default: false)
autoComplete?: boolean, // Mark done immediately (default: false)
dataSchema?: object, // JSON Schema for data extraction
defaultData?: object, // Default values passed to handler
requiredContext?: object, // Context required for action to be available
}

Registering Handlers

When you initialize the Pillar SDK, you can register an action handler via the onTask prop:

examples/guides/actions/provider-on-task.js
import { Pillar } from '@pillar-ai/sdk';
// Initialize the SDK
const pillar = await Pillar.init({
helpCenter: '...',
publicKey: '...',
edgeTrigger: { enabled: true },
panel: { position: 'right' },
});
// Register task handlers
pillar.onTask('navigate', ({ path }) => {
window.location.href = path;
});
pillar.onTask('invite_member', ({ email, role }) => {
showInviteModal({ email, role });
});
// Or handle all tasks with a single handler
pillar.on('task:execute', (task) => {
switch (task.name) {
case 'navigate':
window.location.href = task.data.path;
break;
case 'invite_member':
showInviteModal(task.data);
break;
}
});

Handler Return Values

Handlers can return execution status:

examples/guides/actions/handler-return-values.tsx
// Success
return { success: true };
// Success with message
return { success: true, message: 'Invite sent!' };
// Failure
return { success: false, message: 'Something went wrong' };

Wizard Actions

For actions that open multi-step flows (wizards, modals with multiple steps), signal completion when the user finishes:

examples/guides/actions/wizard-complete-action.js
// When your wizard/modal flow completes, signal to Pillar
function handleWizardComplete(source) {
// 1. Your app logic
saveSource(source);
// 2. Tell Pillar the action is done
pillar.completeAction('add_source', true, { sourceId: source.id });
}
// If the user cancels the wizard
function handleWizardCancel() {
pillar.completeAction('add_source', false);
}

For simple actions (navigation, toggles), the SDK handles completion automatically when your handler returns { success: true }. You only need to call completeAction() for flows where the SDK can't know when the user is "done"—like multi-step wizards or forms that require user input.

Built-in Handlers

Pillar provides fallback handlers for common action types:

TypeDefault Behavior
navigatewindow.location.href = path
external_linkwindow.open(url, '_blank')
copy_textnavigator.clipboard.writeText(text)

Register your own handlers to override these defaults.

Type-Safe Handlers

Get full TypeScript inference for your action data:

examples/guides/actions/type-safe-handlers.tsx
import { usePillar } from '@pillar-ai/react';
import type { actions } from '@/lib/pillar/actions';
function ActionHandlers() {
const { onTask } = usePillar<typeof actions>();
useEffect(() => {
// TypeScript knows the data shape for each action
onTask('invite_member', (data) => {
console.log(data.email); // Typed!
console.log(data.role); // Typed!
});
}, [onTask]);
return null;
}

Data Extraction

Define a schema to have the AI extract structured data from user messages:

examples/guides/actions/data-extraction-schema.tsx
add_source: {
description: 'Add a new knowledge source',
type: 'trigger_action',
dataSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: 'URL of the source to add',
},
name: {
type: 'string',
description: 'Display name for the source',
},
},
required: ['url'],
},
handler: (data) => {
openAddSourceWizard({
prefillUrl: data.url,
prefillName: data.name,
});
},
}

Now when a user says "Add my docs site at docs.example.com", the AI extracts the URL and passes it to your handler.

Context-Based Action Filtering

Use requiredContext to control which actions the AI suggests based on user context. This is useful for:

  • Admin-only actions
  • Feature-gated actions based on user plan
  • Actions that only make sense on certain pages

Admin-Only Actions

examples/guides/actions/admin-only-action.tsx
delete_user: {
description: 'Delete a user from the organization',
type: 'trigger_action',
requiredContext: { userRole: 'admin' },
handler: ({ userId }) => deleteUser(userId),
}

This action will only be suggested when the user's context includes userRole: 'admin'.

Setting Context in Your App

For requiredContext to work, you need to set the user's context:

examples/guides/actions/user-context-sync.tsx
// In your app
import { usePillar } from '@pillar-ai/react';
function UserContextSync() {
const { pillar } = usePillar();
const { user } = useAuth();
useEffect(() => {
if (user && pillar) {
pillar.setContext({
userRole: user.role, // 'admin', 'member', 'viewer', etc.
});
}
}, [pillar, user]);
return null;
}

How It Works

  1. You define actions with requiredContext: { userRole: 'admin' }
  2. Your app calls pillar.setContext({ userRole: user.role })
  3. When searching for actions, Pillar filters out actions where the user doesn't match the required context
  4. Only matching actions are suggested by the AI

Multiple Context Requirements

You can require multiple context fields:

examples/guides/actions/multiple-context-requirements.tsx
billing_settings: {
description: 'Access billing settings',
type: 'navigate',
path: '/settings/billing',
requiredContext: {
userRole: 'admin',
userState: 'active', // Not during trial
},
}

See Context API for all available context properties.

Best Practices

Write Clear Descriptions

The AI matches user queries to your action descriptions. Be specific:

examples/guides/actions/good-descriptions.tsx
// Good - specific about when to use
description: 'Navigate to billing page. Suggest when user asks about payments, invoices, or subscription.'
// Less helpful - too generic
description: 'Go to billing'

Add Example Phrases

Help the AI understand different ways users might phrase requests:

examples/guides/actions/example-phrases.tsx
examples: [
'invite someone to my team',
'add a new team member',
'how do I add users?',
'share access with someone',
]

Handle Errors Gracefully

examples/guides/actions/error-handling.tsx
pillar.onTask('export_data', async (data) => {
try {
await exportData(data);
return { success: true };
} catch (error) {
console.error('Export failed:', error);
return {
success: false,
message: 'Export failed. Please try again.',
};
}
});

Close Panel When Appropriate

For actions that take over the screen:

examples/guides/actions/close-panel.tsx
pillar.onTask('start_tour', () => {
pillar.close(); // Close panel first
startOnboardingTour();
return { success: true };
});

Next Steps

  • Sync your actions to Pillar's backend with the CLI
  • Learn how the AI combines actions into Plans for multi-step tasks
  • Create Custom Cards for rich confirmation UI
  • Pass Context to help the AI suggest relevant actions