CtrlK
BlogDocsLog inGet started
Tessl Logo

add-channel-setup-guide

Add a new chat channel's layer-1 setup guide — the in-dashboard <Channel>SetupGuide that walks a developer through connecting the channel itself (create app/bot → save credentials → install/verify → send first message) with live connection detection — in apps/dashboard, following the existing Slack, MS Teams, and Telegram guides. Use when a new agent channel needs its numbered setup stepper, credential drawer wiring, and connectedAt polling under components/agents.

76

Quality

96%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Add a Channel's Setup Guide (Layer 1)

Layer 1 = connecting the channel itself: the numbered stepper a developer follows to create the provider app/bot, save its credentials in Novu, install/verify, and send a first message — with a live "Listening… / Connected" indicator. ResolveAgentIntegrationGuide renders this <Channel>SetupGuide as the setup view until the integration is connected, then swaps to the connected/"what's next" view (separate add-channel-whats-next-onboarding skill).

Files live in apps/dashboard/src/components/agents/. Siblings: slack-setup-guide.tsx (quick/manual modes + manifest), teams-setup-guide.tsx, telegram-setup-guide.tsx (simplest), whatsapp-setup-guide.tsx.

How it works

<Channel>SetupGuide
  ├─ useFetchIntegrations()         → find integration by _id + providerId
  ├─ SetupStepperRail
  │    └─ SetupStep × N             → create app · save creds · install/verify
  │         └─ SetupButton / IntegrationCredentialsSidebar trigger
  ├─ ListeningStatus                → polls listAgentIntegrations every 1s;
  │                                    fires onConnected + confetti when connectedAt is set
  └─ IntegrationCredentialsSidebar  → generic credential save (useUpdateIntegration)

Connection is detected, not asserted. A channel is "connected" only when the backend sets connectedAt on the integration link (on the first real inbound message). Saving credentials or finishing OAuth/install does not mean connected — keep those as separate local states.

Building blocks

All from setup-guide-primitives.tsx and setup-guide-step-utils.ts:

SymbolRole
SetupStepperRailVertical numbered rail wrapping the steps column
SetupStepOne step: index, status, title, description, rightContent?, extraContent?, fullWidthContent?, headerSlot?, dimmed?, sectionLabel?, inlineSectionLabel?
SetupButtonSecondary outline action; href opens a new tab, else onClick; supports leadingIcon, disabled
SetupModeToggle + SetupMode ('quick' | 'manual')Optional dual-path setup (Slack)
IntegrationCredentialsSidebarDrawer that saves provider credentials via the generic integration form; onSaveSuccess, agentOnboarding
ListeningStatusPolls listAgentIntegrations; fires onConnected + confetti on connectedAt
deriveStepStatus(i, firstIncomplete)'completed' | 'current' | 'upcoming'
hasIntegrationCredentials(credentials)True once any string credential is saved

Step 0 — Prerequisites

  • ChatProviderIdEnum.<Channel> exists in @novu/shared, and the provider exists in packages/providers (brand-new providers are ask-first).
  • The integration can be created/selected (the "add provider" flow passes you an integrationId).

File checklist

Copy the closest sibling, then rename. Full template: see reference.md.

  • CREATE apps/dashboard/src/components/agents/<channel>-setup-guide.tsx — export <Channel>SetupGuide
  • EDIT agent-integration-guides/resolve-agent-integration-guide.tsx — in the setup switch, render <Channel>SetupGuide ... embedded /> and set setupDisplayName (the add-channel-whats-next-onboarding skill covers the rest of this resolver)
  • (optional) Add a provider-specific server action in @/api/agents or @/api/integrations only if the channel needs webhook registration / quick-setup / subscriber-link beyond a plain credential save

Component contract

Props: { agent: AgentResponse; integrationId: string; stepOffset?: number; onStepsCompleted?: () => void; embedded?: boolean } (stepOffset defaults to 1; Overview mounts the guide at a higher base, the Integrations detail page at 1).

State machine:

  1. Resolve selectedIntegration from useFetchIntegrations() by _id === integrationId && providerId === ChatProviderIdEnum.<Channel>.
  2. Track progress: hasIntegrationCredentials(...) ‖ a local credentialsSavedLocally, plus any install/connected flags. Reset all of it in useEffect([integrationId]).
  3. Derive const base = stepOffset → compute firstIncompleteStepderiveStepStatus(stepIndex, firstIncompleteStep) per SetupStep.
  4. Render the steps in SetupStepperRail, then ListeningStatus (in a pl-8 wrapper), then IntegrationCredentialsSidebar.
  5. ListeningStatus.onConnected → mark connected and call onStepsCompleted?.().
  6. Provide both an embedded return (no Overview chrome — used by the resolver) and the standalone return.

Typical 3-step recipe

  1. Create the app/botSetupButton href= the provider console. Optional: a manifest (CodeBlock, escape injected values) or a quick-setup input that calls a server action.
  2. Save credentials in NovuSetupButton onClick={() => setIsCredentialsSidebarOpen(true)}; the sidebar's onSaveSuccess flips credentialsSavedLocally (and may trigger a provider action like webhook registration).
  3. Install / verify + send first message — a provider connect button or copyable instructions; ListeningStatus watches for connectedAt.

Conventions & gotchas

  • Keep installed/credentialed and connected as distinct states — only connectedAt advances the final step (see the Slack guide's comments).
  • Server state through TanStack Query; after a mutation, invalidate getAgentIntegrationsQueryKey(currentEnvironment?._id, agent.identifier).
  • Escape any value injected into a manifest/snippet (e.g. Slack YAML double-quoted strings).
  • Reset local state when integrationId changes so switching integrations doesn't leak progress.
  • Novu/dashboard conventions: type (not interface) on the frontend, named exports, blank line before every return, no nested ternaries, animations from motion/react. Don't build/start the dashboard (port 4201) — check types via diagnostics.

Build & verify

  1. Don't start the dashboard — check types via Cursor diagnostics.
  2. From the agent Integrations tab, add/open a <Channel> integration: confirm steps advance as credentials save, the credential drawer opens/saves, and "Listening…" flips to "Connected" with confetti once a real message lands.
Repository
novuhq/novu
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.