Third-Party Integration Builder
Scaffold new external service integrations with credentials, auth polling, and settings UI.
Installation
- Make sure Claude is on your device and in your terminal.
Skills load from
~/.claude/skills/when Claude Code starts up β so you need it on your machine first. If you don't have it yet, install it once with the command below, then runclaudein any terminal to verify.One-time setupnpm i -g @anthropic-ai/claude-codeAlready have it? Skip ahead.
- Paste into Claude Code or into your terminal.
This copies the whole skill folder into
~/.claude/skills/add-integration-kdlbs/β the SKILL.md plus any scripts, reference docs, or templates the skill ships with. Safe default: works for every skill.Faster alternative (instruction-only skills)
Skips the clone and grabs only the SKILL.md file. Don't use this if the skill ships Python scripts, reference markdowns, or asset templates β they won't be downloaded and the skill will fail when it tries to load them.
Quick install (SKILL.md only)Sign up to copy - Restart Claude Code.
Quit and reopen Claude Code (or any other agent that loads from
~/.claude/skills/). New skills are picked up on startup. - Just ask Claude.
Skills auto-activate when your request matches the skill's description β no slash command needed. Trigger phrases live in the skill's own frontmatter; you can read them in the βWhat this skill doesβ section above.
Prefer to read the source first? Open on GitHub.
When Claude uses it
Add a new third-party integration (Jira/Linear-style) β per-workspace credentials, 90s auth-health poller, settings page, link/import buttons. Use when scaffolding a new external service integration.
What this skill does
Adding a new third-party integration
Planner Entry
Load /spec-driven-development for a substantial integration. The primary
session plans, investigates existing patterns, and may directly implement a
small localized slice. Delegate only independent backend, frontend, test, or
documentation packets whose isolation clearly helps; workers do not spawn.
Jira and Linear are the model: per-workspace credentials, a 90s auth-health poller, a settings page with status banner + reconnect CTA, link/import buttons that gate on availability. New integrations should reuse the shared shapes rather than copying either.
Backend (apps/backend/internal/<name>/)
- Mirror the package layout:
service.go,store.go,client.go,provider.go,handlers.go,models.go,poller.go. ExposeProvide(writer, reader *sqlx.DB, secrets SecretStore, eventBus bus.EventBus, log *logger.Logger) (*Service, func() error, error). PassnilforeventBuswhen the integration doesn't publish events; both Jira and Linear take and use it for issue-watch publishing. - Use
internal/integrations/secretadapterinstead of writing your own upsert wrapper aroundsecrets.SecretStore. The adapter satisfies any per-integrationSecretStoreinterface shaped as{Reveal, Set, Delete, Exists}. - Use
internal/integrations/healthpollfor the auth-health loop. Implement theProberinterface (ListConfiguredWorkspaces+RecordAuthHealth) on a small adapter and lethealthpoll.New("name", prober, log)own Start/Stop/ticker. Keep integration-specific loops (JQL polling, webhook reconciliation, etc.) separate, like jira's issue-watch loop. - Wire the service via a per-domain
init<Name>Service(...)helper incmd/kandev/services.go, not inline inprovideServices. - Ship a
mock_client.go+mock_controller.gonext to the real client.Providebranches onKANDEV_MOCK_<NAME>=trueand returns the in-memory client;RegisterMockRoutes(router, svc, log)mounts/api/v1/<name>/mock/*only when the service was built with the mock. The e2e backend fixture sets the env var so Playwright tests drive the mock viaapiClient.mock<Name>*()helpers β see jira/linear for the layout.
Frontend
- Hooks live under
hooks/domains/<name>/, notcomponents/<name>/. - Use
hooks/domains/integrations/use-integration-availability.tsanduse-integration-enabled.tsβ each integration'suseXAvailable/useXEnabledshould be a one-line wrapper passing the storage key + sync event + config-fetch function. - Settings page reuses
<IntegrationAuthStatusBanner>(components/integrations/auth-status-banner.tsx). - "Auth required / reconnect" UI reuses
<IntegrationAuthErrorMessage>(components/integrations/auth-error-message.tsx) β supply the integration's display name, regex check, and reconnect href. - Link / import popovers reuse
<ValidatedPopover>(components/integrations/validated-popover.tsx) β supply the icon, label, key regex, fetch function, and success callback.
Where Jira and Linear deliberately diverge
- Issue model: Jira uses transitions + JQL; Linear uses state IDs + structured filters. Don't merge these schemas β the upstream APIs are genuinely different.
- Watch filter persistence: Jira stores the JQL string verbatim; Linear stores the structured
SearchFilteras JSON infilter_json(Linear has no JQL equivalent). The orchestrator emitsNewJiraIssueEvent/NewLinearIssueEventrespectively and dedups by issue key (Jira) vs identifier (Linear). - Health column extras: Linear's
linear_configsrow carries anorg_slugcaptured from successful probes; Jira's row does not.
Related skills
Generative Code Art
anthropics
Create algorithmic art with p5.js using randomness and interactive parameters.
Poster & Visual Design
anthropics
Create original posters and visual art in PNG and PDF formats.
Claude API Helper
anthropics
Build, debug, and optimize Claude API applications with caching and model migration support.
MCP Server Builder
anthropics
Build protocol servers that connect language models to external APIs and services.