When a supported communication channel creates a turn, Salambo projects a bounded, JSON-safe context into the sandbox extension host. API and other non-channel turns receive null.

Where it is available

Every lifecycle handler receives it as the second argument:
pi.on('before_agent_start', (event, ctx) => {
  const external = ctx.external;
});
Every custom tool receives it as the fifth argument:
async execute(toolCallId, params, signal, onUpdate, ctx) {
  const external = ctx.external;
}

Common envelope

{
  provider: 'slack' | 'microsoft_teams',
  integrationId: 'integration-id',
  workspaceId: 'provider-workspace-or-tenant-id',
  conversationId: 'stable-salambo-conversation-id',
  messageId: 'provider-message-or-activity-id',
  senderId: 'provider-user-id',
  conversationType: 'dm' | 'channel' | 'group' | 'unknown',
  refs: {},
}
workspaceId and senderId may be null. Provider-specific values are normalized under refs.

Slack context

{
  provider: 'slack',
  integrationId: 'integration_123',
  workspaceId: 'T123',
  conversationId: 'slack:C123:1779375000.000001',
  messageId: '1779375927.497229',
  senderId: 'U123',
  conversationType: 'channel',
  refs: {
    teamId: 'T123',
    channelId: 'C123',
    channelType: 'channel',
    threadTs: '1779375000.000001',
    messageTs: '1779375927.497229',
  },
}
Each Slack reference may be null when the incoming event does not provide it.

Microsoft Teams context

{
  provider: 'microsoft_teams',
  integrationId: 'integration_456',
  workspaceId: 'tenant-123',
  conversationId: 'teams:conversation-123',
  messageId: 'activity-456',
  senderId: 'user-789',
  conversationType: 'channel',
  refs: {
    tenantId: 'tenant-123',
    teamId: 'team-123',
    channelId: 'channel-123',
    conversationId: 'provider-conversation-123',
    replyToId: 'parent-activity-123',
    activityId: 'activity-456',
    serviceUrl: 'https://smba.trafficmanager.net/emea/',
    botFrameworkChannelId: 'msteams',
  },
}
tenantId, teamId, channelId, replyToId, serviceUrl, and botFrameworkChannelId may be null.

Message content

The human’s message is the normal agent input. For before_agent_start, it is available as event.prompt. Salambo does not duplicate message text in ctx.external.

Security boundary

The context never contains provider access tokens, client secrets, signing secrets, Salambo credentials, or the raw webhook body. It is cloned into a bounded JSON projection before reaching the sandbox. Use these identifiers only for product behavior that genuinely needs channel context. Continue with channel-aware recipes.