add-integration

$npx mdskill add kdlbs/kandev/add-integration

Scaffolds a new third-party integration with shared patterns.

  • Solves per-workspace credential management and auth health polling.
  • Depends on secretadapter, sqlx, event bus, and logger packages.
  • Reuses shared shapes from Jira/Linear rather than copying code.
  • Delivers backend service, store, client, provider, handlers, models, and poller.

SKILL.md

.github/skills/add-integrationView on GitHub ↗
---
name: add-integration
description: 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.
---

# Adding a new third-party integration

## Planner Entry

Load `/spec-driven-development`. The user-started
primary session plans the integration and delegates each backend, frontend,
test, and documentation task to bounded workers. It does not scaffold or verify
the integration directly. An explicitly assigned implementer follows the
relevant sections below and does not spawn other workers.

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`. Expose `Provide(writer, reader *sqlx.DB, secrets SecretStore, eventBus bus.EventBus, log *logger.Logger) (*Service, func() error, error)`. Pass `nil` for `eventBus` when the integration doesn't publish events; both Jira and Linear take and use it for issue-watch publishing.
- Use `internal/integrations/secretadapter` instead of writing your own upsert wrapper around `secrets.SecretStore`. The adapter satisfies any per-integration `SecretStore` interface shaped as `{Reveal, Set, Delete, Exists}`.
- Use `internal/integrations/healthpoll` for the auth-health loop. Implement the `Prober` interface (`ListConfiguredWorkspaces` + `RecordAuthHealth`) on a small adapter and let `healthpoll.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 in `cmd/kandev/services.go`, not inline in `provideServices`.
- Ship a `mock_client.go` + `mock_controller.go` next to the real client. `Provide` branches on `KANDEV_MOCK_<NAME>=true` and 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 via `apiClient.mock<Name>*()` helpers — see jira/linear for the layout.

## Frontend

- Hooks live under `hooks/domains/<name>/`, **not** `components/<name>/`.
- Use `hooks/domains/integrations/use-integration-availability.ts` and `use-integration-enabled.ts` — each integration's `useXAvailable` / `useXEnabled` should 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 `SearchFilter` as JSON in `filter_json` (Linear has no JQL equivalent). The orchestrator emits `NewJiraIssueEvent` / `NewLinearIssueEvent` respectively and dedups by issue key (Jira) vs identifier (Linear).
- **Health column extras:** Linear's `linear_configs` row carries an `org_slug` captured from successful probes; Jira's row does not.

More from kdlbs/kandev

SkillDescription
acp-debugDebug an ACP agent CLI by spawning it, speaking raw JSON-RPC, and capturing every frame to a JSONL file. Use when the user asks to probe an agent's capabilities, compare agents, test a prompt against an agent, inspect raw ACP wire frames, or investigate why an agent fails to initialize.
clean-branchesDelete local branches whose remote has been deleted ([gone]), including their worktrees. Use for branch cleanup after merging PRs.
create-kandev-pluginCreate, modify, debug, test, package, or publish a Kandev runtime plugin in its dedicated repository. Use only when the requested work targets a Kandev plugin implementation or its release and marketplace lifecycle, including fixing a bug in an existing plugin. Do not use for agent skills, MCP servers, general integrations, or Kandev host, SDK, loader, and registry changes that do not also change a plugin.
docs-maintainerKeep public Kandev docs current when code or behavior changes affect CLI commands, config keys, install/deploy flows, workflows, executors, APIs, screenshots, or user-facing terminology. Use this before finishing any change with public documentation impact, and when reviewing whether a change needs docs.
harness-improvementImprove Kandev's AI harness from session learnings or explicit requests. Use when the user asks to record learnings, update or create skills, agents, subagents, commands, AGENTS.md/CLAUDE.md guidance, or adapt harness files across Claude, Codex, Cursor, or OpenCode.
kandev-approvalsClear the CEO approval queue when hire requests, budget grants, or other sensitive Office mutations are waiting for approve or reject decisions.
kandev-config-syncSynchronize Office workspace configuration with the .kandev folder when exporting reviewable config, importing committed config, seeding a workspace, or reviewing a config diff.
kandev-escalationEscalate to a human when required information, access, credentials, or a product decision blocks completion and no reasonable default is available.
kandev-projectsList and create Office projects, then place new tasks in the correct project when organizing workspace work by repository.
kandev-protocolFollow the core Office agent protocol on wakeup, including parsing KANDEV_* context, checking blockers, commenting progress, updating status, and using the CLI safely.