# External event context

Exact channel metadata projected into hosted extension tools and lifecycle hooks.

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:

```js
pi.on('before_agent_start', (event, ctx) => {
  const external = ctx.external;
});
```

Every custom tool receives it as the fifth argument:

```js
async execute(toolCallId, params, signal, onUpdate, ctx) {
  const external = ctx.external;
}
```

## Common envelope

```js
{
  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

```js
{
  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

```js
{
  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](/docs/integrations/channel-recipes).
