🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@useatlas/plugin-sdk

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@useatlas/plugin-sdk

Type definitions and helpers for authoring Atlas plugins

Source
npmnpm
Version
0.0.14
Version published
Weekly downloads
716
-42.9%
Maintainers
1
Weekly downloads
 
Created
Source

@useatlas/plugin-sdk

Type definitions and helpers for authoring Atlas plugins. Plugins extend Atlas with new datasources, context providers, interaction surfaces, actions, and sandbox backends.

Quick Start

import { createPlugin } from "@useatlas/plugin-sdk";
import { z } from "zod";

export const myPlugin = createPlugin({
  configSchema: z.object({ url: z.string() }),
  create: (config) => ({
    id: "my-datasource",
    types: ["datasource"] as const,
    version: "1.0.0",
    config,
    connection: {
      create: () => makeConnection(config.url),
      dbType: "postgres",
    },
  }),
});

Register in atlas.config.ts:

import { defineConfig } from "@atlas/api/lib/config";
import { myPlugin } from "./my-plugin";

export default defineConfig({
  plugins: [myPlugin({ url: process.env.MY_DB_URL! })],
});

Plugin Types

Atlas has five plugin types. Each extends AtlasPluginBase with variant-specific fields.

Datasource (AtlasDatasourcePlugin)

Connect to a database. Provides a connection factory, SQL dialect hints, and optional entity definitions.

A datasource plugin must provide at least one connection factory: create() for a static config-defined connection, createFromConfig() for a DB-stored (admin-registered) per-workspace connection, or both. A plugin with only createFromConfig() is an adapter-only plugin — registered for use but with no static datasource (the multi-tenant SaaS model, where every connection is added per workspace).

FieldTypeRequiredDescription
connection.create()() => PluginDBConnection | Promise<PluginDBConnection>One of create/createFromConfigFactory that returns a connection with query() and close() from the plugin's config-time config (static / self-host)
connection.createFromConfig()(config) => PluginDBConnection | Promise<PluginDBConnection>One of create/createFromConfigFactory that builds a connection from a DB-stored per-(workspace, install) config (adapter-only / SaaS)
connection.dbTypePluginDBTypeYesDatabase type identifier (postgres, mysql, clickhouse, snowflake, duckdb, or custom)
entitiesEntityProviderNoSemantic layer fragments merged into the table whitelist at boot
dialectstringNoSQL dialect guidance injected into the agent system prompt

Reference: clickhouse

Context (AtlasContextPlugin)

Inject knowledge into the agent. Context plugins load additional system prompt fragments, semantic layer extensions, or external metadata.

FieldTypeRequiredDescription
contextProvider.load()() => Promise<string>YesReturns context string appended to the agent system prompt
contextProvider.refresh()() => Promise<void>NoCache invalidation hook

Reference: yaml-context

Interaction (AtlasInteractionPlugin)

Add communication surfaces. Interaction plugins mount HTTP routes or manage non-HTTP transports (stdio, SSE).

FieldTypeRequiredDescription
routes(app: Hono) => voidNoMount Hono routes for webhooks, OAuth, etc. Optional for non-HTTP transports

Reference: chat, mcp

Action (AtlasActionPlugin)

Enable agent side-effects. Action plugins provide AI SDK tools with approval controls.

FieldTypeRequiredDescription
actionsPluginAction[]YesArray of action definitions
actions[].namestringYesTool name
actions[].toolToolSet[string]YesAI SDK tool definition
actions[].actionTypestringYesCategory identifier (e.g. jira:create)
actions[].reversiblebooleanYesWhether the action can be undone
actions[].defaultApprovalActionApprovalModeYesauto, manual, or admin-only
actions[].requiredCredentialsstring[]YesConfig fields needed at runtime

Reference: jira, email

Sandbox (AtlasSandboxPlugin)

Provide code isolation for the explore tool. Sandbox plugins create backends that execute shell commands in an isolated environment.

FieldTypeRequiredDescription
sandbox.create(semanticRoot)(string) => PluginExploreBackendYesFactory that creates an explore backend
sandbox.prioritynumberNoHigher = tried first. Built-in: Vercel=100, E2B=90, Daytona=85, nsjail=75, sidecar=50, just-bash=0. Plugin default: 60
securityobjectNoInformational metadata about isolation guarantees

Reference: nsjail, vercel-sandbox

Base Fields

All plugins share these fields from AtlasPluginBase:

FieldTypeRequiredDescription
idstringYesUnique identifier (e.g. clickhouse-datasource)
typePluginTypeYesOne of datasource, context, interaction, action, sandbox
versionstringYesSemVer version
namestringNoHuman-readable display name
configTConfigNoPlugin-specific configuration
initialize(ctx)(AtlasPluginContext) => Promise<void>NoCalled once at server boot. Throw to block startup
healthCheck()() => Promise<PluginHealthResult>NoPeriodic health probe
teardown()() => Promise<void>NoGraceful shutdown (LIFO order)
onUninstall(workspaceId)(string) => Promise<void> | voidNoPer-workspace uninstall hook — revoke external webhook subscriptions / OAuth grants the plugin registered for that workspace
hooksPluginHooksNoAgent lifecycle and HTTP hooks
schemaRecord<string, PluginTableDefinition>NoDeclarative table definitions for the internal DB

Lifecycle

register → initialize(ctx) → healthCheck() → ... → teardown()
                          └── onUninstall(workspaceId)   (per-workspace, at uninstall time)
  • Register — Plugins are listed in the plugins array in atlas.config.ts. Config is validated at factory call time (before server starts).
  • Initialize — Called once at server boot with AtlasPluginContext. Throw to signal fatal initialization failure. Context provides:
    • ctx.db — Internal Postgres (auth/audit DB). Null when DATABASE_URL is not set.
    • ctx.connections — Connection registry for analytics datasources.
    • ctx.tools — Tool registry for adding agent tools.
    • ctx.logger — Pino-compatible child logger scoped to the plugin.
    • ctx.config — Resolved Atlas configuration.
  • Health check — Periodic probe. Return { healthy: false, message } to signal degradation. Never throw. Results surface in the plugins component of GET /api/health — a failing probe shifts the top-level status to degraded (HTTP 200, never 503).
  • Teardown — Graceful shutdown in reverse registration order (LIFO). Use teardown() to release process-level state — third-party connections, drained queues, timers. Note: teardown() runs on server shutdown, not on a per-workspace uninstall (uninstall is a DB-row removal, not a process event) — per-workspace cleanup belongs in onUninstall.
  • Per-workspace uninstallonUninstall(workspaceId) fires when a workspace uninstalls the plugin (both the marketplace DELETE route and WorkspaceInstaller.uninstall), before Atlas removes the install row and credential stores — so the plugin can still authenticate against the external platform. Use it to revoke webhook subscriptions, OAuth grants, or any other external state registered for that workspace. Attribution rule: never revoke a subscription you can't positively attribute to the uninstalling workspace (recorded id, metadata tag, or workspace marker in the callback URL) — the credential may be shared with other workspaces or out-of-band tooling. Best-effort: a thrown error is logged with the plugin id + workspaceId and the uninstall proceeds (each invocation also runs against a 15s host-side deadline); never rely on it for load-bearing cleanup. It does not fire on datasource disconnects or a workspace purge — only the two plugin-uninstall paths above. See packages/api/src/lib/integrations/jira/lazy-builder.ts for a reference implementation (revokes only workspace-attributed Jira dynamic webhook subscriptions).

v1.1 note: AtlasPluginContext will gain executeQuery, conversations, and actions fields for full host-level decoupling. Currently, interaction plugins that need these inject them via config callbacks.

Uninstall Contract

DELETE /api/v1/admin/marketplace/:id removes a plugin from a workspace. The cleanup contract:

StateSurvives uninstall?Notes
workspace_plugins rowNo (deleted)Canonical "is this plugin installed?" record.
scheduled_tasks rows tagged with the plugin's catalog_idNo (deleted)Scoped by (plugin_id, org_id) so cleanup never crosses workspaces. scheduled_task_runs cascade via FK. Cleanup runs in a separate statement after the install row is removed; partial failure leaves the uninstall committed and is recorded as a cleanupFailed: true audit event.
plugin_<pluginId>_* tables (declared via schema)Yes (retained)Reinstall picks up where it left off — cached digest history, sync cursors, etc. Hard-reset only via workspace purge.
In-process hook registrationsNot detached on uninstall — teardown() runs only at server shutdownHooks become inert for the uninstalled workspace because dispatch checks workspace_plugins for the installation.
Webhook subscriptions registered with external platformsYes — unless your onUninstall(workspaceId) revokes themAtlas has no visibility into external state. Implement onUninstall to revoke the subscription — it fires before the install row and credentials are removed, so your plugin can still authenticate. Revoke only subscriptions attributable to the uninstalling workspace. An un-revoked webhook keeps delivering events to a workspace that no longer has the plugin installed. Note the hook fires only on plugin uninstalls — datasource disconnects and workspace purges skip it.

If your plugin creates scheduled_tasks rows, set plugin_id = $catalogId and org_id = $orgId on insert so the uninstall cleanup picks them up. Untagged tasks (plugin_id IS NULL) are treated as user-created and survive uninstall. See the authoring guide for the full lifecycle.

Config Validation

Use createPlugin() with a Zod schema for typed, validated configuration:

import { createPlugin } from "@useatlas/plugin-sdk";
import { z } from "zod";

const configSchema = z.object({
  url: z.string().url(),
  poolSize: z.number().int().positive().optional(),
});

export const myPlugin = createPlugin({
  configSchema,
  create: (config) => ({
    id: "my-datasource",
    types: ["datasource"] as const,
    version: "1.0.0",
    config,
    connection: { create: () => connect(config.url), dbType: "postgres" },
  }),
});

The factory validates config at call time — invalid config fails fast during startup, not at first use. The configSchema accepts any object with a parse(input) method (Zod schemas satisfy this).

For simple plugins without config validation, use definePlugin():

import { definePlugin } from "@useatlas/plugin-sdk";

export default definePlugin({
  id: "my-context",
  types: ["context"],
  version: "1.0.0",
  contextProvider: { async load() { return "Extra context..."; } },
});

Hooks

Hooks use a matcher + handler pattern inspired by Better Auth. Matchers are optional — omit to always fire.

hooks: {
  beforeQuery: [{
    matcher: (ctx) => ctx.connectionId === "warehouse",
    handler: (ctx) => {
      // Return { sql } to rewrite, throw to reject, return void to pass through
      return { sql: ctx.sql.replace(/SELECT \*/, "SELECT id, name") };
    },
  }],
  afterQuery: [{
    handler: (ctx) => {
      console.log(`Query took ${ctx.durationMs}ms, returned ${ctx.result.rows.length} rows`);
    },
  }],
}
HookContextMutationDescription
beforeQuery{ sql, connectionId? }{ sql }Fires before SQL execution. Return to rewrite, throw to reject
afterQuery{ sql, connectionId?, result, durationMs }Fires after SQL execution
beforeExplore{ command }{ command }Fires before explore command. Return to rewrite, throw to reject
afterExplore{ command, output }Fires after explore command
onRequest{ path, method, headers }HTTP-level: fires before routing
onResponse{ path, method, status }HTTP-level: fires after response

Schema Migrations

Plugins declare internal database tables via the schema property:

schema: {
  slack_installations: {
    fields: {
      team_id: { type: "string", required: true, unique: true },
      bot_token: { type: "string", required: true },
      installed_at: { type: "date" },
    },
  },
},

Run migrations with the CLI:

atlas migrate          # Preview migration SQL
atlas migrate --apply  # Apply to internal DB

Tables are prefixed with the plugin ID to avoid collisions.

$InferServerPlugin

Extract plugin types on the client side without importing server code:

import type { $InferServerPlugin } from "@useatlas/plugin-sdk";
import type { clickhousePlugin } from "@useatlas/clickhouse";

type CH = $InferServerPlugin<typeof clickhousePlugin>;
// CH["Config"]   → { url: string; database?: string }
// CH["Type"]     → "datasource"
// CH["DbType"]   → "clickhouse"
// CH["Actions"]  → never (not an action plugin)
// CH["Security"] → never (not a sandbox plugin)

Works with both createPlugin() factory functions and definePlugin() direct objects.

Available inferred fields: Config, Type, Id, Name, Version, DbType (datasource only), Actions (action only), Security (sandbox only).

CLI

atlas plugin list                              # List installed plugins from atlas.config.ts
atlas plugin create <name> --type <type>       # Scaffold a new plugin (datasource|context|interaction|action|sandbox)
atlas plugin add <package-name>                # Install a plugin package via bun

atlas plugin create generates a plugins/<name>/ directory with src/index.ts, src/index.test.ts, package.json, and tsconfig.json.

Type Guards

import {
  isDatasourcePlugin,
  isContextPlugin,
  isInteractionPlugin,
  isActionPlugin,
  isSandboxPlugin,
} from "@useatlas/plugin-sdk";

if (isDatasourcePlugin(plugin)) {
  // plugin is AtlasDatasourcePlugin — connection, entities, dialect available
}

Reference Implementations

Note: These are workspace packages (@useatlas/*) within the monorepo. Use them as reference when authoring your own plugins.

PluginTypePackageDescription
clickhouseDatasource@useatlas/clickhouseClickHouse HTTP transport adapter
mysqlDatasource@useatlas/mysqlMySQL pool-based adapter
snowflakeDatasource@useatlas/snowflakeSnowflake callback-based adapter
duckdbDatasource@useatlas/duckdbDuckDB in-process adapter
yaml-contextContext@useatlas/yaml-contextYAML semantic layer context provider
mcpInteraction@useatlas/mcpMCP server lifecycle (stdio + SSE)
chatInteraction@useatlas/chatChat SDK bridge — Slack, Teams, Discord, etc. via unified adapter
jiraAction@useatlas/jiraCreate JIRA tickets from analysis
emailAction@useatlas/emailSend email reports via Resend
nsjailSandbox@useatlas/nsjailLinux namespace isolation via nsjail
sidecarSandbox@useatlas/sidecarHTTP-isolated container sidecar
vercel-sandboxSandbox@useatlas/vercel-sandboxFirecracker microVM via @vercel/sandbox
daytonaSandbox@useatlas/daytonaDaytona managed cloud sandbox
e2bSandbox@useatlas/e2bE2B Firecracker microVM (managed)

Source

The definitive type definitions are in src/types.ts. Factory functions and type guards are in src/helpers.ts.

Keywords

atlas

FAQs

Package last updated on 15 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts