diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json
index 351819a..4b80c6e 100644
--- a/.github/plugin/marketplace.json
+++ b/.github/plugin/marketplace.json
@@ -5,38 +5,50 @@
"email": "support@scalekit.com"
},
"metadata": {
- "description": "GitHub Copilot CLI plugins for authentication",
+ "description": "Scalekit Auth Stack for GitHub Copilot — AgentKit and SaaSKit plugins.",
"version": "1.0.0"
},
"plugins": [
{
- "name": "mcp-auth",
- "description": "Add OAuth 2.1 authorization to MCP servers using Scalekit.",
- "version": "1.0.0",
- "source": "./plugins/mcp-auth"
+ "name": "agentkit",
+ "description": "Authentication for AI agents. OAuth flows, token vault, 40+ connectors (Gmail, Slack, Salesforce, etc.), tool discovery, and live testing — so agents can act on behalf of users.",
+ "version": "2.0.0",
+ "source": "./plugins/agentkit"
},
{
- "name": "full-stack-auth",
- "description": "Production-ready authentication flows (sign-up, login, logout, sessions) using Scalekit full-stack auth across common stacks.",
- "version": "1.3.4",
- "source": "./plugins/full-stack-auth"
+ "name": "saaskit",
+ "description": "Production-ready auth for B2B SaaS apps. Login, sessions, SSO (Okta, Azure AD, Google), SCIM provisioning, RBAC, MCP server auth, and API key management.",
+ "version": "2.0.0",
+ "source": "./plugins/saaskit"
},
{
"name": "agent-auth",
- "description": "Implements Scalekit Agent Auth so AI agents can act in third-party apps (Gmail, Slack, Calendar, Notion) on behalf of users.",
- "version": "1.5.2",
+ "description": "Alias for agentkit — AI agent authentication with OAuth flows, token vault, and 40+ connectors.",
+ "version": "2.0.0",
"source": "./plugins/agent-auth"
},
+ {
+ "name": "mcp-auth",
+ "description": "Alias for saaskit — includes OAuth 2.1 for MCP servers alongside login, SSO, SCIM, and RBAC.",
+ "version": "2.0.0",
+ "source": "./plugins/mcp-auth"
+ },
+ {
+ "name": "full-stack-auth",
+ "description": "Alias for saaskit — full-stack authentication including login, sessions, SSO, SCIM, and RBAC.",
+ "version": "2.0.0",
+ "source": "./plugins/full-stack-auth"
+ },
{
"name": "modular-sso",
- "description": "Modular SSO flows using Scalekit for apps with existing user management, including IdP-initiated login and enterprise onboarding.",
- "version": "1.1.4",
+ "description": "Alias for saaskit — enterprise SSO is now part of the unified SaaSKit plugin.",
+ "version": "2.0.0",
"source": "./plugins/modular-sso"
},
{
"name": "modular-scim",
- "description": "SCIM webhook provisioning with Scalekit for real-time user and group lifecycle management.",
- "version": "1.1.2",
+ "description": "Alias for saaskit — SCIM provisioning is now part of the unified SaaSKit plugin.",
+ "version": "2.0.0",
"source": "./plugins/modular-scim"
}
]
diff --git a/AGENTS.md b/AGENTS.md
index 36f11d8..8c01114 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -390,7 +390,7 @@ copilot plugin marketplace add ./github-copilot-authstack
copilot plugin list
# Install a specific plugin
-copilot plugin install mcp-auth
+copilot plugin install agentkit@github-copilot-authstack
# Test the plugin
copilot "Your prompt"
@@ -469,11 +469,11 @@ Documentation
| Artifact | Convention | Example |
|---|---|---|
| Marketplace name | `kebab-case` | `team-plugins` |
-| Plugin name | `kebab-case` | `mcp-auth` |
+| Plugin name | `kebab-case` | `agentkit` |
| Agent filename | `.agent.md` | `scalekit-mcp-auth-troubleshooter.agent.md` |
| Agent ID | derived from filename | `scalekit-mcp-auth-troubleshooter` |
-| Skill directory | `kebab-case` | `mcp-auth` |
-| Skill name | defined in SKILL.md | `MCP Auth` |
+| Skill directory | `kebab-case` | `integrating-agentkit` |
+| Skill name | defined in SKILL.md | `integrating-agentkit` |
| MCP server name | `kebab-case` | `scalekit-auth-server` |
**Note**: All file paths must use forward slashes (`/`) regardless of operating system.
@@ -505,7 +505,7 @@ copilot plugin marketplace add octo-org/octo-repo
copilot plugin list
# Install a specific plugin
-copilot plugin install mcp-auth
+copilot plugin install agentkit@github-copilot-authstack
# Use an agent from the plugin
copilot "Your prompt"
diff --git a/CLAUDE.md b/CLAUDE.md
index 84b2c9d..09d8c81 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,168 +1,56 @@
# CLAUDE.md (Repo guide for agents)
-This repository contains GitHub Copilot CLI plugins for marketplace distribution.
-It is a monorepo. Always work inside one plugin directory at a time.
+This repository is a monorepo of GitHub Copilot CLI plugins for marketplace distribution.
+Always work inside one plugin directory at a time.
-If you are making changes, read AGENTS.md first and follow it as the source of truth.
+Read AGENTS.md first — it is the source of truth for all rules.
-## Quick orientation
+## Repo structure
-Top level:
-
-- .github/plugin/ Marketplace manifest location
-- plugins/ Monorepo root for all plugins
-- AGENTS.md Non negotiable rules for manifests, commands, security
-- README.md Repo overview
-
-Plugins (examples you may see here):
-
-- plugins/frontend-design/
-- plugins/security-checks/
-- plugins/deploy-tools/
+```
+.github/plugin/marketplace.json Marketplace manifest
+plugins/agentkit/ AgentKit plugin (OAuth, token vault, connectors)
+plugins/saaskit/ SaaSKit plugin (SSO, SCIM, sessions, MCP auth)
+plugins/agent-auth -> agentkit Backwards-compat symlink
+plugins/mcp-auth -> saaskit Backwards-compat symlink
+plugins/full-stack-auth -> saaskit Backwards-compat symlink
+plugins/modular-sso -> saaskit Backwards-compat symlink
+plugins/modular-scim -> saaskit Backwards-compat symlink
+AGENTS.md Non-negotiable rules
+README.md Repo overview
+scripts/install.sh Installation script
+```
-Each plugin is expected to look like:
+Each plugin contains:
+```
plugins//
- manifest.json Plugin manifest (name, version, commands)
- src/index.ts Plugin entrypoint
- commands/ CLI command implementations
- package.json Node.js dependencies
- README.md Required docs for that plugin
-
-## Marketplace structure
-
-The marketplace.json file in .github/plugin/ defines which plugins are available:
-
-```json
-{
- "name": "github-copilot-authstack",
- "owner": {
- "name": "Plugin Owner",
- "email": "owner@example.com"
- },
- "metadata": {
- "description": "GitHub Copilot CLI plugins marketplace",
- "version": "1.0.0"
- },
- "plugins": [
- {
- "name": "plugin-name",
- "description": "Plugin description",
- "version": "1.0.0",
- "source": "./plugins/plugin-name"
- }
- ]
-}
+ .github/plugin/plugin.json Plugin manifest (required)
+ agents/*.agent.md Agent definitions
+ skills//SKILL.md Skill entrypoints
+ references/ Deep docs loaded on demand
+ hooks/hooks.json Lifecycle hooks (optional)
+ .mcp.json MCP server config (optional)
+ README.md Required docs
```
-Source paths are relative to the repository root. Use `./plugins/plugin-name` or `plugins/plugin-name` (both work).
-
-## Golden rules
-
-- Do not edit multiple plugins in one change unless explicitly requested.
-- Prefer smallest viable change that improves correctness, safety, or docs.
-- Never add secrets, tokens, or credentials to this repo.
-- Follow naming rules from AGENTS.md for plugin names and command names.
-- Keep command implementations focused and testable.
-
-## Workflow for improvements
-
-1. Identify the target plugin directory under plugins/.
-2. Read these files before coding:
- - .github/plugin/marketplace.json
- - plugins//manifest.json
- - plugins//README.md
- - plugins//src/index.ts
- - Any relevant commands/*.ts
-3. Decide the change type:
- - New plugin: Create plugin directory, update marketplace.json
- - New command: Add command file, update manifest.json commands array
- - Command change: Update command implementation, update README if needed
- - Manifest change: Update manifest.json fields (version, description, etc.)
-4. Update documentation:
- - Always update plugins//README.md when behavior changes.
- - Update .github/plugin/marketplace.json if adding/updating plugins.
-5. Local verification:
- - Add marketplace locally:
- copilot plugin marketplace add ./github-copilot-authstack
- - List available plugins:
- copilot plugin list
- - Test the plugin command:
- copilot [args]
-6. Definition of done:
- - Clear docs for how to use the change
- - No secrets added
- - Naming follows AGENTS.md
- - Marketplace.json source path is correct
- - Minimal surface area change
-
-## When adding a new plugin
-
-1. Create plugin directory: plugins//
-2. Create manifest.json with required fields
-3. Create src/index.ts with plugin entrypoint
-4. Create commands/ directory and implement commands
-5. Create package.json with dependencies
-6. Create README.md with all 7 required sections
-7. Update .github/plugin/marketplace.json to include the new plugin
-8. Test locally with copilot CLI
-
-## When updating an existing plugin
+## Before coding
-1. Edit plugin files in plugins//
-2. Update version in manifest.json if behavior changes
-3. Update README.md if commands or behavior changes
-4. Run local tests with copilot CLI
-5. Commit changes with conventional commit message
+1. Read AGENTS.md for all rules
+2. Read .github/plugin/marketplace.json for plugin registry
+3. Read the target plugin's plugin.json and README.md
-## Common pitfalls to avoid
-
-- Wrong source paths in marketplace.json. Must be relative to repo root.
-- Missing required fields in manifest.json.
-- Using reserved words in plugin names (github, copilot).
-- Not validating command inputs.
-- Forgetting to update README.md when behavior changes.
-- Hardcoding credentials or secrets.
-- Not testing with copilot CLI before committing.
-
-## Testing before publishing
-
-Always test locally:
+## Local testing
```bash
-# Add the marketplace
copilot plugin marketplace add ./github-copilot-authstack
-
-# Verify marketplace loaded
copilot plugin list
-
-# Test plugin commands
-copilot [args]
-
-# Verify output matches expected behavior
-```
-
-Run unit tests if available:
-
-```bash
-cd plugins/
-npm test
+copilot plugin install agentkit@github-copilot-authstack
```
-## When uncertain
-
-If the request is ambiguous, ask which plugin folder under plugins/ is the target before making changes.
-
-If unsure about marketplace.json structure, reference the existing entries in .github/plugin/marketplace.json.
-
-## Branch strategy for pushing
-
-When making changes that will be pushed to GitHub:
-
-1. Create a feature branch: `git checkout -b feature/plugin-name-update`
-2. Make your changes
-3. Test locally with copilot CLI
-4. Commit changes with conventional commit format
-5. Push to remote: `git push origin feature/plugin-name-update`
-6. Create pull request for review
+## Golden rules
-Never push directly to main branch for marketplace changes.
+- One plugin at a time unless explicitly asked otherwise.
+- Never add secrets, tokens, or credentials.
+- Prefer minimal changes for correctness, safety, and clarity.
+- Forward slashes in all paths.
+- Update README.md when behavior changes.
diff --git a/README.md b/README.md
index 8128e6e..a5ba48d 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
-Scalekit Auth Plugins for GitHub Copilot CLI — the auth stack for agents.
-Add MCP Auth and tool-calling to your MCP servers from GitHub Copilot CLI.
+Scalekit Auth Stack for GitHub Copilot — AgentKit and SaaSKit plugins.
+Add agent auth, tool calling, SSO, SCIM, MCP auth, and session management from GitHub Copilot.
[](./LICENSE)
[](https://github.com/scalekit-inc/github-copilot-authstack/pulls)
@@ -14,46 +14,33 @@ Add MCP Auth and tool-calling to your MCP servers from GitHub Copilot CLI.
---
-A GitHub Copilot CLI plugin marketplace for adding OAuth 2.1 authorization and tool-calling to MCP (Model Context Protocol) servers using [Scalekit](https://scalekit.com).
+Setting up auth for B2B and AI apps is complex. This marketplace adds the complete Scalekit auth stack to your projects — whether that's an AI agent, a B2B SaaS app, or an MCP server — directly from GitHub Copilot.
---
-### Plugins
+### Available Plugins
-#### mcp-auth
-
-Guides and implementation patterns for securing MCP servers with OAuth 2.1. Covers multiple frameworks so you can pick the right approach for your stack.
-
-**Skills:**
-
-| Skill | Description |
-|-------|-------------|
-| `mcp-auth` | Comprehensive guide — HTTP transport, token validation, scope-based auth |
-| `add-auth-fastmcp` | Simplest path: FastMCP + Scalekit provider in ~5 lines |
-| `express-mcp-server` | Express.js with custom middleware and fine-grained token control |
-| `fastapi-fastmcp` | FastAPI + FastMCP for Python apps needing advanced authorization |
-
-**Agents:**
-
-| Agent | Description |
-|-------|-------------|
-| `setup-scalekit` | Sets up Scalekit env vars, installs the SDK, and verifies credentials |
-| `scalekit-mcp-auth-troubleshooter` | Diagnoses MCP auth issues (handshake, CORS, cached clients, port limits) |
+| Plugin | Description |
+|--------|-------------|
+| **AgentKit** | Authentication for AI agents. OAuth flows, token vault, 40+ connectors (Gmail, Slack, Salesforce, etc.), tool discovery, and live testing — so agents can act on behalf of users. |
+| **SaaSKit** | Production-ready auth for B2B SaaS apps. Login, sessions, SSO (Okta, Azure AD, Google), SCIM provisioning, RBAC, MCP server auth, and API key management. |
---
### Installation
-Add this marketplace to your Copilot CLI:
+Use the one-command bootstrap installer:
```bash
-copilot plugin marketplace add https://github.com/scalekit-inc/github-copilot-authstack
+curl -fsSL https://raw.githubusercontent.com/scalekit-inc/github-copilot-authstack/main/install.sh | bash
```
-Install a plugin:
+Or add the marketplace manually:
```bash
-copilot plugin install scalekit-inc/github-copilot-authstack:plugins/mcp-auth
+copilot plugin marketplace add scalekit-inc/github-copilot-authstack
+copilot plugin install agentkit@github-copilot-authstack
+copilot plugin install saaskit@github-copilot-authstack
```
List available plugins:
@@ -62,25 +49,19 @@ List available plugins:
copilot plugin list
```
-Run a skill:
-
-```bash
-copilot mcp-auth add-auth-fastmcp
-```
-
---
-### Repository Layout
+### Repository Structure
```
-.github/plugin/marketplace.json Marketplace manifest
-plugins/
- mcp-auth/
- agents/ Copilot agents
- skills/ Copilot skills
- .github/plugin/plugin.json Plugin manifest
- .mcp.json MCP server config
-AGENTS.md Non-negotiable rules for contributors
+.
+├── plugins/
+│ ├── agentkit/ # AI agent authentication (AgentKit)
+│ └── saaskit/ # B2B SaaS authentication (SaaSKit)
+├── scripts/ # Install scripts
+├── images/ # Documentation images
+├── AGENTS.md # Contribution guidelines
+└── LICENSE # MIT License
```
---
@@ -89,7 +70,7 @@ AGENTS.md Non-negotiable rules for contributors
- [Scalekit account](https://scalekit.com) with `client_id` and `client_secret`
- GitHub Copilot CLI installed and configured
-- Project where you want to add MCP authentication
+- Project where you want to add authentication
---
@@ -99,7 +80,7 @@ AGENTS.md Non-negotiable rules for contributors
- [Scalekit Documentation](https://docs.scalekit.com) — Complete guides and API reference
- [MCP Auth Guide](https://docs.scalekit.com/mcp-auth/quickstart/) — Secure MCP servers
-- [Agent Auth Guide](https://docs.scalekit.com/agent-auth/quickstart/) — Authentication for AI agents
+- [AgentKit Guide](https://docs.scalekit.com/agentkit/overview/) — Authentication for AI agents
#### Resources
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..597b7b2
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+REPO_SLUG="${COPILOT_AUTHSTACK_REPO:-scalekit-inc/github-copilot-authstack}"
+REPO_REF="${COPILOT_AUTHSTACK_REF:-main}"
+SOURCE_DIR="${COPILOT_AUTHSTACK_SOURCE_DIR:-}"
+
+if [[ -n "$SOURCE_DIR" ]]; then
+ exec "${SOURCE_DIR%/}/scripts/install.sh"
+fi
+
+TMP_DIR="$(mktemp -d)"
+cleanup() {
+ rm -rf "$TMP_DIR"
+}
+trap cleanup EXIT
+
+ARCHIVE_URL="https://github.com/${REPO_SLUG}/archive/refs/heads/${REPO_REF}.tar.gz"
+ARCHIVE_PATH="$TMP_DIR/github-copilot-authstack.tar.gz"
+
+echo "Downloading Scalekit Auth Stack for GitHub Copilot from:"
+echo " $ARCHIVE_URL"
+
+curl -fsSL "$ARCHIVE_URL" -o "$ARCHIVE_PATH"
+tar -xzf "$ARCHIVE_PATH" -C "$TMP_DIR"
+
+EXTRACTED_DIR="$(find "$TMP_DIR" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
+
+if [[ -z "$EXTRACTED_DIR" ]] || [[ ! -f "$EXTRACTED_DIR/scripts/install.sh" ]]; then
+ echo "Failed to find installer in downloaded archive." >&2
+ exit 1
+fi
+
+chmod +x "$EXTRACTED_DIR/scripts/install.sh"
+exec "$EXTRACTED_DIR/scripts/install.sh"
diff --git a/plugins/agent-auth b/plugins/agent-auth
new file mode 120000
index 0000000..1cdf127
--- /dev/null
+++ b/plugins/agent-auth
@@ -0,0 +1 @@
+agentkit
\ No newline at end of file
diff --git a/plugins/agent-auth/.github/plugin/plugin.json b/plugins/agent-auth/.github/plugin/plugin.json
deleted file mode 100644
index 90227e8..0000000
--- a/plugins/agent-auth/.github/plugin/plugin.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "agent-auth",
- "description": "Implements Scalekit Agent Auth so AI agents can act in third-party apps (Gmail, Slack, Calendar, Notion) on behalf of users.",
- "version": "1.6.0",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com"
- },
- "homepage": "https://docs.scalekit.com",
- "repository": "https://github.com/scalekit-inc/github-copilot-authstack",
- "license": "MIT",
- "keywords": ["scalekit", "agent-auth", "oauth", "connected-accounts"],
- "agents": [
- "./agents"
- ],
- "skills": [
- "./skills/agent-auth",
- "./skills/building-agent-mcp-server",
- "./skills/production-readiness-scalekit"
- ],
- "mcpServers": ".mcp.json"
-}
diff --git a/plugins/agent-auth/README.md b/plugins/agent-auth/README.md
deleted file mode 100644
index 044ce9a..0000000
--- a/plugins/agent-auth/README.md
+++ /dev/null
@@ -1,95 +0,0 @@
-# agent-auth
-
-## Purpose
-
-This plugin implements Scalekit Agent Auth, enabling AI agents to act in third-party applications (Gmail, Slack, Google Calendar, Notion, and others) on behalf of users. It handles OAuth flows, connected account management, token storage, and automatic refresh so agents can make authenticated API calls without user intervention.
-
-## Installation
-
-```bash
-# Add the marketplace
-copilot plugin marketplace add scalekit-inc/github-copilot-authstack
-
-# Install this plugin
-copilot plugin install agent-auth
-```
-
-## Components Reference
-
-### Agents
-
-| Agent | Purpose |
-|---|---|
-| `setup-scalekit` | Sets up Scalekit env vars, installs and initializes the SDK, and verifies credentials |
-
-### Skills
-
-| Skill | Purpose |
-|---|---|
-| `agent-auth` | Integrates Scalekit Agent Auth: OAuth flows, token storage, and automatic refresh for third-party services |
-| `building-agent-mcp-server` | Guides through creating a Scalekit MCP server with authenticated tool access |
-| `production-readiness-scalekit` | Structured production readiness checklist for Scalekit agent authentication implementations |
-
-### MCP Server
-
-Configured in `.mcp.json` — connects to the Scalekit MCP server at `https://mcp.scalekit.com` via `mcp-remote`.
-
-### References
-
-The `references/` directory contains connector guides for 30+ services (Gmail, Slack, Notion, HubSpot, Salesforce, Google Calendar, and more) and conceptual documentation on connected accounts, OAuth flows, and BYOC (bring your own credentials) patterns.
-
-## Configuration
-
-Required environment variables:
-
-```bash
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
-SCALEKIT_CLIENT_ID=your_client_id
-SCALEKIT_CLIENT_SECRET=your_client_secret
-```
-
-Use the `setup-scalekit` agent to configure these automatically:
-
-```bash
-copilot setup-scalekit "Set up Scalekit for my AI agent project"
-```
-
-## Usage Examples
-
-### Connect an agent to Gmail
-
-```
-copilot "I need my AI agent to read and send Gmail on behalf of users"
-```
-
-The `agent-auth` skill activates and guides through registering a Gmail connector, initiating the OAuth authorization flow, storing tokens, and making authenticated Gmail API calls.
-
-### Build an authenticated MCP server
-
-```
-copilot "Help me build an MCP server with Scalekit authentication"
-```
-
-The `building-agent-mcp-server` skill guides through creating the MCP server, configuring Scalekit as the auth provider, and exposing authenticated tools.
-
-## Troubleshooting
-
-**OAuth flow not completing**: Verify the redirect URL registered in the Scalekit dashboard matches your application's callback endpoint exactly. Check `references/redirects.md` for URI validation requirements.
-
-**Token refresh failing**: Confirm the refresh token was stored correctly during the initial OAuth exchange. The `agent-auth` skill covers secure token storage patterns per framework.
-
-**Connected account not found**: Ensure the user completed the full OAuth consent flow. Connected accounts appear in the Scalekit dashboard under the relevant organization once authorization is complete.
-
-## Security
-
-**Required credentials:**
-- `SCALEKIT_ENVIRONMENT_URL` — your Scalekit environment URL
-- `SCALEKIT_CLIENT_ID` — OAuth client ID
-- `SCALEKIT_CLIENT_SECRET` — OAuth client secret (treat as a password)
-
-**Storage:**
-- Store secrets in environment variables or a secrets manager
-- Never commit secrets to source control
-- Third-party OAuth tokens (access/refresh) must be stored encrypted at rest
-
-The plugin itself contains no hardcoded credentials. All MCP server config uses `${ENV_VAR}` placeholders.
diff --git a/plugins/agent-auth/agents/setup-scalekit.md b/plugins/agent-auth/agents/setup-scalekit.md
deleted file mode 100644
index 7227f6f..0000000
--- a/plugins/agent-auth/agents/setup-scalekit.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-name: scalekit-setup
-description: Sets up Scalekit env vars, installs/initializes the SDK, and verifies credentials by listing organizations. Use proactively when user asks to set up, install, initialize, configure, or verify Scalekit.
-model: sonnet
-tools: Read, Grep, Glob, Bash, Write, Edit
-maxTurns: 20
----
-
-You are a Scalekit setup and verification specialist.
-
-Mission:
-- Help the user configure Scalekit credentials via environment variables.
-- Help them install and initialize the official Scalekit SDK for their language.
-- Verify the setup with the smallest reliable check (prefer listing organizations).
-- Keep secrets out of chat and out of the repo.
-
-Hard rules:
-- NEVER ask the user to paste SCALEKIT_CLIENT_SECRET into chat.
-- NEVER hardcode credentials in code samples; always use environment variables.
-- Prefer creating a local verification script (verify.js / verify.py / verify.go / Verify.java) and running it, but only if the user wants you to write files.
-- When using agent auth for nodejs, use npm install @scalekit-sdk/node@2.2.0-beta.1
-
-Workflow:
-1) Determine language/runtime (Node.js, Python, Go, Java) and where env vars should live (.env, shell, CI secrets).
-2) Confirm required env vars exist:
- - SCALEKIT_ENVIRONMENT_URL
- - SCALEKIT_CLIENT_ID
- - SCALEKIT_CLIENT_SECRET
-3) Install the SDK (pick the official package for that language).
-4) Initialize the SDK client using env vars.
-5) Verify credentials by listing organizations with a small page size.
-6) If verification fails, diagnose systematically:
- - Wrong environment URL (dev vs prod)
- - Missing env vars in current shell/process
- - Incorrect client id/secret
- - Network/DNS issues
-7) Only after verification succeeds, proceed to feature work and route to the correct Skill:
- - SSO → plugins/modular-sso/skills/modular-sso/SKILL.md
- - SCIM → plugins/modular-scim/skills/modular-scim/SKILL.md
- - MCP auth → plugins/mcp-auth/skills/*/SKILL.md
- - Full-stack auth → plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
-
-When you reference files, use exact repo-relative paths and read them before advising.
diff --git a/plugins/agent-auth/references/agent-connectors/README.md b/plugins/agent-auth/references/agent-connectors/README.md
deleted file mode 100644
index a91420e..0000000
--- a/plugins/agent-auth/references/agent-connectors/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# Agent Connectors Reference
-
-This directory contains documentation for all supported agent connectors in the Scalekit Agent Auth platform.
-
-## Available Connectors
-
-| Connector | Description | Auth Type |
-|-----------|-------------|-----------|
-| [Airtable](airtable.md) | Connect to Airtable bases for data management | OAuth 2.0 |
-| [Asana](asana.md) | Project management and task tracking | OAuth 2.0 |
-| [BigQuery](bigquery.md) | Google BigQuery data warehouse | OAuth 2.0 |
-| [ClickUp](clickup.md) | Project management and collaboration | OAuth 2.0 |
-| [Confluence](confluence.md) | Atlassian Confluence wiki pages | OAuth 2.0 |
-| [Dropbox](dropbox.md) | File storage and sharing | OAuth 2.0 |
-| [Fathom](fathom.md) | Website analytics | OAuth 2.0 |
-| [Freshdesk](freshdesk.md) | Customer support ticketing | OAuth 2.0 |
-| [GitHub](github.md) | Code repository and development tools | OAuth 2.0 |
-| [Gmail](gmail.md) | Google Gmail email service | OAuth 2.0 |
-| [Google Ads](google_ads.md) | Google advertising platform | OAuth 2.0 |
-| [Google Calendar](googlecalendar.md) | Google Calendar events and scheduling | OAuth 2.0 |
-| [Google Docs](google_docs.md) | Google Docs document editing | OAuth 2.0 |
-| [Google Drive](google_drive.md) | Google Drive file storage | OAuth 2.0 |
-| [Google Forms](google_forms.md) | Google Forms survey creation | OAuth 2.0 |
-| [Google Meet](google_meets.md) | Google Meet video conferencing | OAuth 2.0 |
-| [Google Sheets](google_sheets.md) | Google Sheets spreadsheet editing | OAuth 2.0 |
-| [Gong](gong.md) | Sales conversation intelligence | OAuth 2.0 |
-| [HubSpot](hubspot.md) | CRM and marketing automation | OAuth 2.0 |
-| [Intercom](intercom.md) | Customer messaging platform | OAuth 2.0 |
-| [Jira](jira.md) | Atlassian Jira issue tracking | OAuth 2.0 |
-| [Linear](linear.md) | Software development issue tracking | OAuth 2.0 |
-| [Microsoft Excel](microsoft_excel.md) | Microsoft Excel spreadsheet editing | OAuth 2.0 |
-| [Microsoft Teams](microsoft_teams.md) | Microsoft Teams collaboration | OAuth 2.0 |
-| [Microsoft Word](microsoft_word.md) | Microsoft Word document editing | OAuth 2.0 |
-| [Monday](monday.md) | Work management platform | OAuth 2.0 |
-| [Notion](notion.md) | Notion workspace and pages | OAuth 2.0 |
-| [OneDrive](onedrive.md) | Microsoft OneDrive file storage | OAuth 2.0 |
-| [OneNote](onenote.md) | Microsoft OneNote note-taking | OAuth 2.0 |
-| [Outlook](outlook.md) | Microsoft Outlook email | OAuth 2.0 |
-| [Salesforce](salesforce.md) | Salesforce CRM platform | OAuth 2.0 |
-| [ServiceNow](servicenow.md) | IT service management | OAuth 2.0 |
-| [SharePoint](sharepoint.md) | Microsoft SharePoint collaboration | OAuth 2.0 |
-| [Slack](slack.md) | Slack messaging and collaboration | OAuth 2.0 |
-| [Snowflake](snowflake.md) | Snowflake data warehouse | OAuth 2.0 |
-| [Trello](trello.md) | Trello project boards | OAuth 2.0 |
-| [Zendesk](zendesk.md) | Customer support platform | OAuth 2.0 |
-| [Zoom](zoom.md) | Zoom video conferencing | OAuth 2.0 |
-
-## Getting Started
-
-Each connector documentation includes:
-
-- Service description and capabilities
-- Authentication requirements
-- Complete API reference for all available tools
-- Parameter specifications and examples
-- Usage guidelines and best practices
-
-## Authentication
-
-All connectors support OAuth 2.0 authentication through the Agent Auth platform. You'll need to:
-
-1. Create a connection for the desired service
-2. Configure OAuth credentials in your connection
-3. Create connected accounts for your users
-4. Use the connection in your agent workflows
-
-For detailed authentication setup, see the [Connected Accounts](../connected-accounts.md) documentation.
\ No newline at end of file
diff --git a/plugins/agent-auth/references/agent-connectors/airtable.md b/plugins/agent-auth/references/agent-connectors/airtable.md
deleted file mode 100644
index f3acf0b..0000000
--- a/plugins/agent-auth/references/agent-connectors/airtable.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Airtable. Manage databases, tables, records, and collaborate on structured data
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/asana.md b/plugins/agent-auth/references/agent-connectors/asana.md
deleted file mode 100644
index cea2fc7..0000000
--- a/plugins/agent-auth/references/agent-connectors/asana.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Asana. Manage tasks, projects, teams, and workflow automation
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/bigquery.md b/plugins/agent-auth/references/agent-connectors/bigquery.md
deleted file mode 100644
index 64b8a33..0000000
--- a/plugins/agent-auth/references/agent-connectors/bigquery.md
+++ /dev/null
@@ -1,3 +0,0 @@
-BigQuery is Google Cloud’s fully-managed enterprise data warehouse for analytics at scale.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/clickup.md b/plugins/agent-auth/references/agent-connectors/clickup.md
deleted file mode 100644
index dd7d216..0000000
--- a/plugins/agent-auth/references/agent-connectors/clickup.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to ClickUp. Manage tasks, projects, workspaces, and team collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/confluence.md b/plugins/agent-auth/references/agent-connectors/confluence.md
deleted file mode 100644
index 96d699f..0000000
--- a/plugins/agent-auth/references/agent-connectors/confluence.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Confluence. Manage spaces, pages, content, and team collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/dropbox.md b/plugins/agent-auth/references/agent-connectors/dropbox.md
deleted file mode 100644
index 1bfe1d3..0000000
--- a/plugins/agent-auth/references/agent-connectors/dropbox.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Dropbox. Manage files, folders, sharing, and cloud storage workflows
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/fathom.md b/plugins/agent-auth/references/agent-connectors/fathom.md
deleted file mode 100644
index 3408c98..0000000
--- a/plugins/agent-auth/references/agent-connectors/fathom.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Fathom AI meeting assistant. Record, transcribe, and summarize meetings with AI-powered insights
-
-Supports authentication: API Key
diff --git a/plugins/agent-auth/references/agent-connectors/freshdesk.md b/plugins/agent-auth/references/agent-connectors/freshdesk.md
deleted file mode 100644
index 424a753..0000000
--- a/plugins/agent-auth/references/agent-connectors/freshdesk.md
+++ /dev/null
@@ -1,149 +0,0 @@
-Connect to Freshdesk. Manage tickets, contacts, companies, and customer support workflows
-
-Supports authentication: Basic Auth
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `freshdesk_agent_create`
-
-Create a new agent in Freshdesk. Email is required and must be unique. Agent will receive invitation email to set up account. At least one role must be assigned.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `agent_type` | Type of agent (1=Support Agent, 2=Field Agent, 3=Collaborator) | number | null |
-| `email` | Email address of the agent (must be unique) | string |
-| `focus_mode` | Focus mode setting for the agent | boolean | null |
-| `group_ids` | Array of group IDs to assign the agent to | `array` | null |
-| `language` | Language preference of the agent | string | null |
-| `name` | Full name of the agent | string | null |
-| `occasional` | Whether the agent is occasional (true) or full-time (false) | boolean | null |
-| `role_ids` | Array of role IDs to assign to the agent (at least one required) | `array` |
-| `signature` | Agent email signature in HTML format | string | null |
-| `skill_ids` | Array of skill IDs to assign to the agent | `array` | null |
-| `ticket_scope` | Ticket permission level (1=Global Access, 2=Group Access, 3=Restricted Access) | number |
-| `time_zone` | Time zone of the agent | string | null |
-
-## `freshdesk_agent_delete`
-
-Delete an agent from Freshdesk. This action is irreversible and will remove the agent from the system. The agent will no longer have access to the helpdesk and all associated data will be permanently deleted.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `agent_id` | ID of the agent to delete | number |
-
-## `freshdesk_agents_list`
-
-Retrieve a list of agents from Freshdesk with filtering options. Returns agent details including IDs, contact information, roles, and availability status. Supports pagination with up to 100 agents per page.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `email` | Filter agents by email address | string | null |
-| `mobile` | Filter agents by mobile number | string | null |
-| `page` | Page number for pagination (starts from 1) | number | null |
-| `per_page` | Number of agents per page (max 100) | number | null |
-| `phone` | Filter agents by phone number | string | null |
-| `state` | Filter agents by state (fulltime or occasional) | string | null |
-
-## `freshdesk_contact_create`
-
-Create a new contact in Freshdesk. Email and name are required. Supports custom fields, company assignment, and contact segmentation.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `address` | Address of the contact | string | null |
-| `company_id` | Company ID to associate with the contact | number | null |
-| `custom_fields` | Key-value pairs for custom field values | `object` | null |
-| `description` | Description about the contact | string | null |
-| `email` | Email address of the contact | string |
-| `job_title` | Job title of the contact | string | null |
-| `language` | Language preference of the contact | string | null |
-| `mobile` | Mobile number of the contact | string | null |
-| `name` | Full name of the contact | string |
-| `phone` | Phone number of the contact | string | null |
-| `tags` | Array of tags to associate with the contact | `array` | null |
-| `time_zone` | Time zone of the contact | string | null |
-
-## `freshdesk_roles_list`
-
-Retrieve a list of all roles from Freshdesk. Returns role details including IDs, names, descriptions, default status, and timestamps. This endpoint provides information about the different permission levels and access controls available in the Freshdesk system.
-
-## `freshdesk_ticket_create`
-
-Create a new ticket in Freshdesk. Requires either requester_id, email, facebook_id, phone, twitter_id, or unique_external_id to identify the requester.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `cc_emails` | Array of email addresses to be added in CC | `array` | null |
-| `custom_fields` | Key-value pairs containing custom field names and values | `object` | null |
-| `description` | HTML content of the ticket describing the issue | string | null |
-| `email` | Email address of the requester. If no contact exists, will be added as new contact. | string | null |
-| `group_id` | ID of the group to which the ticket has been assigned | number | null |
-| `name` | Name of the requester | string | null |
-| `priority` | Priority of the ticket. 1=Low, 2=Medium, 3=High, 4=Urgent | number | null |
-| `requester_id` | User ID of the requester. For existing contacts, can be passed instead of email. | number | null |
-| `responder_id` | ID of the agent to whom the ticket has been assigned | number | null |
-| `source` | Channel through which ticket was created. 1=Email, 2=Portal, 3=Phone, 7=Chat, 9=Feedback Widget, 10=Outbound Email | number | null |
-| `status` | Status of the ticket. 2=Open, 3=Pending, 4=Resolved, 5=Closed | number | null |
-| `subject` | Subject of the ticket | string | null |
-| `tags` | Array of tags to be associated with the ticket | `array` | null |
-| `type` | Helps categorize the ticket according to different kinds of issues | string | null |
-
-## `freshdesk_ticket_get`
-
-Retrieve details of a specific ticket by ID. Includes ticket properties, conversations, and metadata.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `include` | Additional resources to include (stats, requester, company, conversations) | string | null |
-| `ticket_id` | ID of the ticket to retrieve | number |
-
-## `freshdesk_ticket_update`
-
-Update an existing ticket in Freshdesk. Note: Subject and description of outbound tickets cannot be updated.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `custom_fields` | Key-value pairs containing custom field names and values | `object` | null |
-| `description` | HTML content of the ticket (cannot be updated for outbound tickets) | string | null |
-| `group_id` | ID of the group to which the ticket has been assigned | number | null |
-| `name` | Name of the requester | string | null |
-| `priority` | Priority of the ticket. 1=Low, 2=Medium, 3=High, 4=Urgent | number | null |
-| `responder_id` | ID of the agent to whom the ticket has been assigned | number | null |
-| `status` | Status of the ticket. 2=Open, 3=Pending, 4=Resolved, 5=Closed | number | null |
-| `subject` | Subject of the ticket (cannot be updated for outbound tickets) | string | null |
-| `tags` | Array of tags to be associated with the ticket | `array` | null |
-| `ticket_id` | ID of the ticket to update | number |
-
-## `freshdesk_tickets_list`
-
-Retrieve a list of tickets with filtering and pagination. Supports filtering by status, priority, requester, and more. Returns 30 tickets per page by default.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `company_id` | Filter by company ID | number | null |
-| `email` | Filter by requester email | string | null |
-| `filter` | Filter name (new_and_my_open, watching, spam, deleted) | string | null |
-| `include` | Additional resources to include (description, requester, company, stats) | string | null |
-| `page` | Page number for pagination (starts from 1) | number | null |
-| `per_page` | Number of tickets per page (max 100) | number | null |
-| `requester_id` | Filter by requester ID | number | null |
-| `updated_since` | Filter tickets updated since this timestamp (ISO 8601) | string | null |
-
-## `freshdesk_tickets_reply`
-
-Add a public reply to a ticket conversation. The reply will be visible to the customer and will update the ticket status if specified.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `bcc_emails` | Array of email addresses to BCC on the reply | `array` | null |
-| `body` | HTML content of the reply | string |
-| `cc_emails` | Array of email addresses to CC on the reply | `array` | null |
-| `from_email` | Email address to send the reply from | string | null |
-| `ticket_id` | ID of the ticket to reply to | number |
-| `user_id` | ID of the agent sending the reply | number | null |
diff --git a/plugins/agent-auth/references/agent-connectors/github.md b/plugins/agent-auth/references/agent-connectors/github.md
deleted file mode 100644
index c9cf234..0000000
--- a/plugins/agent-auth/references/agent-connectors/github.md
+++ /dev/null
@@ -1,137 +0,0 @@
-GitHub is a cloud-based Git repository hosting service that allows developers to store, manage, and track changes to their code.
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `github_file_contents_get`
-
-Get the contents of a file or directory from a GitHub repository. Returns Base64 encoded content for files.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `owner` | The account owner of the repository | string |
-| `path` | The content path (file or directory path in the repository) | string |
-| `ref` | The name of the commit/branch/tag | string | null |
-| `repo` | The name of the repository | string |
-
-## `github_file_create_update`
-
-Create a new file or update an existing file in a GitHub repository. Content must be Base64 encoded. Requires SHA when updating existing files.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `author` | Author information object with name and email | `object` | null |
-| `branch` | The branch name | string | null |
-| `committer` | Committer information object with name and email | `object` | null |
-| `content` | The new file content (Base64 encoded) | string |
-| `message` | The commit message for this change | string |
-| `owner` | The account owner of the repository | string |
-| `path` | The file path in the repository | string |
-| `repo` | The name of the repository | string |
-| `sha` | The blob SHA of the file being replaced (required when updating existing files) | string | null |
-
-## `github_issue_create`
-
-Create a new issue in a repository. Requires push access to set assignees, milestones, and labels.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assignees` | GitHub usernames to assign to the issue | `array` | null |
-| `body` | The contents of the issue | string | null |
-| `labels` | Labels to associate with the issue | `array` | null |
-| `milestone` | Milestone number to associate with the issue | number | null |
-| `owner` | The account owner of the repository | string |
-| `repo` | The name of the repository | string |
-| `title` | The title of the issue | string |
-| `type` | The name of the issue type | string | null |
-
-## `github_issues_list`
-
-List issues in a repository. Both issues and pull requests are returned as issues in the GitHub API.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assignee` | Filter by assigned user | string | null |
-| `creator` | Filter by issue creator | string | null |
-| `direction` | Sort order | string | null |
-| `labels` | Filter by comma-separated list of label names | string | null |
-| `milestone` | Filter by milestone number or state | string | null |
-| `owner` | The account owner of the repository | string |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `repo` | The name of the repository | string |
-| `since` | Show issues updated after this timestamp (ISO 8601 format) | string | null |
-| `sort` | Property to sort issues by | string | null |
-| `state` | Filter by issue state | string | null |
-
-## `github_public_repos_list`
-
-List public repositories for a specified user. Does not require authentication.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `direction` | Sort order | string | null |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `sort` | Property to sort repositories by | string | null |
-| `type` | Filter repositories by type | string | null |
-| `username` | The GitHub username to list repositories for | string |
-
-## `github_pull_request_create`
-
-Create a new pull request in a repository. Requires write access to the head branch.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `base` | The name of the branch you want the changes pulled into | string |
-| `body` | The contents of the pull request description | string | null |
-| `draft` | Indicates whether the pull request is a draft | boolean | null |
-| `head` | The name of the branch where your changes are implemented (format: user:branch) | string |
-| `maintainer_can_modify` | Indicates whether maintainers can modify the pull request | boolean | null |
-| `owner` | The account owner of the repository | string |
-| `repo` | The name of the repository | string |
-| `title` | The title of the pull request | string | null |
-
-## `github_pull_requests_list`
-
-List pull requests in a repository with optional filtering by state, head, and base branches.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `base` | Filter by base branch name | string | null |
-| `direction` | Sort order | string | null |
-| `head` | Filter by head branch (format: user:ref-name) | string | null |
-| `owner` | The account owner of the repository | string |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `repo` | The name of the repository | string |
-| `sort` | Property to sort pull requests by | string | null |
-| `state` | Filter by pull request state | string | null |
-
-## `github_repo_get`
-
-Get detailed information about a GitHub repository including metadata, settings, and statistics.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `owner` | The account owner of the repository (case-insensitive) | string |
-| `repo` | The name of the repository without the .git extension (case-insensitive) | string |
-
-## `github_user_repos_list`
-
-List repositories for the authenticated user. Requires authentication.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `direction` | Sort order | string | null |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `sort` | Property to sort repositories by | string | null |
-| `type` | Filter repositories by type | string | null |
diff --git a/plugins/agent-auth/references/agent-connectors/gmail.md b/plugins/agent-auth/references/agent-connectors/gmail.md
deleted file mode 100644
index d668c75..0000000
--- a/plugins/agent-auth/references/agent-connectors/gmail.md
+++ /dev/null
@@ -1,79 +0,0 @@
-Gmail is Google's cloud based email service that allows you to access your messages from any computer or device with just a web browser.
-
-Supports authentication: OAuth 2.0
-
-## Tool list
-
-## `gmail_fetch_mails`
-
-Fetch emails from a connected Gmail account using search filters. Requires a valid Gmail OAuth2 connection.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `format` | Format of the returned message. | string | null |
-| `include_spam_trash` | Whether to fetch emails from spam and trash folders | boolean | null |
-| `label_ids` | Gmail label IDs to filter messages | `array` | null |
-| `max_results` | Maximum number of emails to fetch | integer | null |
-| `page_token` | Page token for pagination | string | null |
-| `query` | Search query string using Gmail's search syntax (e.g., 'is:unread from:user@example.com') | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_get_attachment_by_id`
-
-Retrieve a specific attachment from a Gmail message using the message ID and attachment ID.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attachment_id` | Unique Gmail attachment ID | string |
-| `file_name` | Preferred filename to use when saving/returning the attachment | string | null |
-| `message_id` | Unique Gmail message ID that contains the attachment | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_get_contacts`
-
-Fetch a list of contacts from the connected Gmail account. Supports pagination and field filtering.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `max_results` | Maximum number of contacts to fetch | integer | null |
-| `page_token` | Token to retrieve the next page of results | string | null |
-| `person_fields` | Fields to include for each person | `array` | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_get_message_by_id`
-
-Retrieve a specific Gmail message using its message ID. Optionally control the format of the returned data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `format` | Format of the returned message. | string | null |
-| `message_id` | Unique Gmail message ID | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_list_drafts`
-
-List draft emails from a connected Gmail account. Requires a valid Gmail OAuth2 connection.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `max_results` | Maximum number of drafts to fetch | integer | null |
-| `page_token` | Page token for pagination | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_search_people`
-
-Search people or contacts in the connected Google account using a query. Requires a valid Google OAuth2 connection with People API scopes.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `other_contacts` | Whether to include people not in the user's contacts (from 'Other Contacts'). | boolean | null |
-| `page_size` | Maximum number of people to return. | integer | null |
-| `person_fields` | Fields to retrieve for each person. | `array` | null |
-| `query` | Text query to search people (e.g., name, email address). | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
diff --git a/plugins/agent-auth/references/agent-connectors/gong.md b/plugins/agent-auth/references/agent-connectors/gong.md
deleted file mode 100644
index 26a36e3..0000000
--- a/plugins/agent-auth/references/agent-connectors/gong.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect with Gong to sync calls, transcripts, insights, coaching and CRM activity
-
-Supports authentication: OAuth 2.0 , Api Key
diff --git a/plugins/agent-auth/references/agent-connectors/google_ads.md b/plugins/agent-auth/references/agent-connectors/google_ads.md
deleted file mode 100644
index 9718639..0000000
--- a/plugins/agent-auth/references/agent-connectors/google_ads.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Ads to manage advertising campaigns, analyze performance metrics, and optimize ad spending across Google's advertising platform
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/google_docs.md b/plugins/agent-auth/references/agent-connectors/google_docs.md
deleted file mode 100644
index e790d5d..0000000
--- a/plugins/agent-auth/references/agent-connectors/google_docs.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Docs. Create, edit, and collaborate on documents
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/google_drive.md b/plugins/agent-auth/references/agent-connectors/google_drive.md
deleted file mode 100644
index ef6120e..0000000
--- a/plugins/agent-auth/references/agent-connectors/google_drive.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Drive. Manage files, folders, and sharing permissions
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/google_forms.md b/plugins/agent-auth/references/agent-connectors/google_forms.md
deleted file mode 100644
index fde9e1d..0000000
--- a/plugins/agent-auth/references/agent-connectors/google_forms.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Forms. Create, view, and manage forms and responses securely
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/google_meets.md b/plugins/agent-auth/references/agent-connectors/google_meets.md
deleted file mode 100644
index 814ff7b..0000000
--- a/plugins/agent-auth/references/agent-connectors/google_meets.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Meet. Create and manage video meetings with powerful collaboration features
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/google_sheets.md b/plugins/agent-auth/references/agent-connectors/google_sheets.md
deleted file mode 100644
index 8df9a54..0000000
--- a/plugins/agent-auth/references/agent-connectors/google_sheets.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Sheets. Create, edit, and analyze spreadsheets with powerful data management capabilities
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/googlecalendar.md b/plugins/agent-auth/references/agent-connectors/googlecalendar.md
deleted file mode 100644
index 8168441..0000000
--- a/plugins/agent-auth/references/agent-connectors/googlecalendar.md
+++ /dev/null
@@ -1,128 +0,0 @@
-Google Calendar is Google's cloud-based calendar service that allows you to manage your events, appointments, and schedules from any computer or device with just a web browser.
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `googlecalendar_create_event`
-
-Create a new event in a connected Google Calendar account. Supports meeting links, recurrence, attendees, and more.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attendees_emails` | Attendee email addresses | `array` | null |
-| `calendar_id` | Calendar ID to create the event in | string | null |
-| `create_meeting_room` | Generate a Google Meet link for this event | boolean | null |
-| `description` | Optional event description | string | null |
-| `event_duration_hour` | Duration of event in hours | integer | null |
-| `event_duration_minutes` | Duration of event in minutes | integer | null |
-| `event_type` | Event type for display purposes | string | null |
-| `guests_can_invite_others` | Allow guests to invite others | boolean | null |
-| `guests_can_modify` | Allow guests to modify the event | boolean | null |
-| `guests_can_see_other_guests` | Allow guests to see each other | boolean | null |
-| `location` | Location of the event | string | null |
-| `recurrence` | Recurrence rules (iCalendar RRULE format) | `array` | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `send_updates` | Send update notifications to attendees | boolean | null |
-| `start_datetime` | Event start time in RFC3339 format | string |
-| `summary` | Event title/summary | string |
-| `timezone` | Timezone for the event (IANA time zone identifier) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-| `transparency` | Calendar transparency (free/busy) | string | null |
-| `visibility` | Visibility of the event | string | null |
-
-## `googlecalendar_delete_event`
-
-Delete an event from a connected Google Calendar account. Requires the calendar ID and event ID.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `calendar_id` | The ID of the calendar from which the event should be deleted | string | null |
-| `event_id` | The ID of the calendar event to delete | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `googlecalendar_get_event_by_id`
-
-Retrieve a specific calendar event by its ID using optional filtering and list parameters.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `calendar_id` | The calendar ID to search in | string | null |
-| `event_id` | The unique identifier of the calendar event to fetch | string |
-| `event_types` | Filter by Google event types | `array` | null |
-| `query` | Free text search query | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `show_deleted` | Include deleted events in results | boolean | null |
-| `single_events` | Expand recurring events into instances | boolean | null |
-| `time_max` | Upper bound for event start time (RFC3339) | string | null |
-| `time_min` | Lower bound for event start time (RFC3339) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-| `updated_min` | Filter events updated after this time (RFC3339) | string | null |
-
-## `googlecalendar_list_calendars`
-
-List all accessible Google Calendar calendars for the authenticated user. Supports filters and pagination.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `max_results` | Maximum number of calendars to fetch | integer | null |
-| `min_access_role` | Minimum access role to include in results | string | null |
-| `page_token` | Token to retrieve the next page of results | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `show_deleted` | Include deleted calendars in the list | boolean | null |
-| `show_hidden` | Include calendars that are hidden from the calendar list | boolean | null |
-| `sync_token` | Token to get updates since the last sync | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `googlecalendar_list_events`
-
-List events from a connected Google Calendar account with filtering options. Requires a valid Google Calendar OAuth2 connection.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `calendar_id` | Calendar ID to list events from | string | null |
-| `max_results` | Maximum number of events to fetch | integer | null |
-| `order_by` | Order of events in the result | string | null |
-| `page_token` | Page token for pagination | string | null |
-| `query` | Free text search query | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `single_events` | Expand recurring events into single events | boolean | null |
-| `time_max` | Upper bound for event start time (RFC3339 timestamp) | string | null |
-| `time_min` | Lower bound for event start time (RFC3339 timestamp) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `googlecalendar_update_event`
-
-Update an existing event in a connected Google Calendar account. Only provided fields will be updated. Supports updating time, attendees, location, meeting links, and more.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attendees_emails` | Attendee email addresses | `array` | null |
-| `calendar_id` | Calendar ID containing the event | string |
-| `create_meeting_room` | Generate a Google Meet link for this event | boolean | null |
-| `description` | Optional event description | string | null |
-| `end_datetime` | Event end time in RFC3339 format | string | null |
-| `event_duration_hour` | Duration of event in hours | integer | null |
-| `event_duration_minutes` | Duration of event in minutes | integer | null |
-| `event_id` | The ID of the calendar event to update | string |
-| `event_type` | Event type for display purposes | string | null |
-| `guests_can_invite_others` | Allow guests to invite others | boolean | null |
-| `guests_can_modify` | Allow guests to modify the event | boolean | null |
-| `guests_can_see_other_guests` | Allow guests to see each other | boolean | null |
-| `location` | Location of the event | string | null |
-| `recurrence` | Recurrence rules (iCalendar RRULE format) | `array` | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `send_updates` | Send update notifications to attendees | boolean | null |
-| `start_datetime` | Event start time in RFC3339 format | string | null |
-| `summary` | Event title/summary | string | null |
-| `timezone` | Timezone for the event (IANA time zone identifier) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-| `transparency` | Calendar transparency (free/busy) | string | null |
-| `visibility` | Visibility of the event | string | null |
diff --git a/plugins/agent-auth/references/agent-connectors/hubspot.md b/plugins/agent-auth/references/agent-connectors/hubspot.md
deleted file mode 100644
index ac44f2c..0000000
--- a/plugins/agent-auth/references/agent-connectors/hubspot.md
+++ /dev/null
@@ -1,143 +0,0 @@
-Connect to HubSpot CRM. Manage contacts, deals, companies, and marketing automation
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `hubspot_companies_search`
-
-Search HubSpot companies using full-text search and pagination. Returns matching companies with specified properties.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination offset to get results starting from a specific position | string | null |
-| `filterGroups` | JSON string containing filter groups for advanced filtering | string | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-| `query` | Search term for full-text search across company properties | string | null |
-
-## `hubspot_company_create`
-
-Create a new company in HubSpot CRM. Requires a company name as the unique identifier. Supports additional properties like domain, industry, phone, location, and revenue information.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `annualrevenue` | Annual revenue of the company | number | null |
-| `city` | Company city location | string | null |
-| `country` | Company country location | string | null |
-| `description` | Company description or overview | string | null |
-| `domain` | Company website domain | string | null |
-| `industry` | Industry type of the company | string | null |
-| `name` | Company name (required, serves as primary identifier) | string |
-| `numberofemployees` | Number of employees at the company | number | null |
-| `phone` | Company phone number | string | null |
-| `state` | Company state or region | string | null |
-
-## `hubspot_company_get`
-
-Retrieve details of a specific company from HubSpot by company ID. Returns company properties and associated data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `company_id` | ID of the company to retrieve | string |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-
-## `hubspot_contact_create`
-
-Create a new contact in HubSpot CRM. Requires an email address as the unique identifier. Supports additional properties like name, company, phone, and lifecycle stage.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `company` | Company name where the contact works | string | null |
-| `email` | Primary email address for the contact (required, serves as unique identifier) | string |
-| `firstname` | First name of the contact | string | null |
-| `hs_lead_status` | Lead status of the contact | string | null |
-| `jobtitle` | Job title of the contact | string | null |
-| `lastname` | Last name of the contact | string | null |
-| `lifecyclestage` | Lifecycle stage of the contact | string | null |
-| `phone` | Phone number of the contact | string | null |
-| `website` | Personal or company website URL | string | null |
-
-## `hubspot_contact_get`
-
-Retrieve details of a specific contact from HubSpot by contact ID. Returns contact properties and associated data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `contact_id` | ID of the contact to retrieve | string |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-
-## `hubspot_contact_update`
-
-Update an existing contact in HubSpot CRM by contact ID. Allows updating contact properties like name, email, company, phone, and lifecycle stage.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `contact_id` | ID of the contact to update | string |
-| `props` | Object containing properties like first name, last name, email, company, phone, and job title to update all these should be provided inside props as a JSON object, this is required | `object` | null |
-
-## `hubspot_contacts_list`
-
-Retrieve a list of contacts from HubSpot with filtering and pagination. Returns contact properties and supports pagination through cursor-based navigation.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination cursor to get the next set of results | string | null |
-| `archived` | Whether to include archived contacts in the results | boolean | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-
-## `hubspot_contacts_search`
-
-Search HubSpot contacts using full-text search and pagination. Returns matching contacts with specified properties.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination offset to get results starting from a specific position | string | null |
-| `filterGroups` | JSON string containing filter groups for advanced filtering | string | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-| `query` | Search term for full-text search across contact properties | string | null |
-
-## `hubspot_deal_create`
-
-Create a new deal in HubSpot CRM. Requires dealname, amount, and dealstage. Supports additional properties like pipeline, close date, and deal type.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `amount` | Deal amount/value (required) | number |
-| `closedate` | Expected close date (YYYY-MM-DD format) | string | null |
-| `dealname` | Name of the deal (required) | string |
-| `dealstage` | Current stage of the deal (required) | string |
-| `dealtype` | Type of deal | string | null |
-| `description` | Deal description | string | null |
-| `hs_priority` | Deal priority (HIGH, MEDIUM, LOW) | string | null |
-| `pipeline` | Deal pipeline | string | null |
-
-## `hubspot_deal_update`
-
-Update an existing deal in HubSpot CRM by deal ID. Allows updating deal properties like name, amount, stage, pipeline, close date, and priority.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `deal_id` | ID of the deal to update | string |
-| `good_deal` | Boolean flag indicating if this is a good deal | boolean | null |
-| `properties` | Object containing deal properties to update | `object` |
-
-## `hubspot_deals_search`
-
-Search HubSpot deals using full-text search and pagination. Returns matching deals with specified properties.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination offset to get results starting from a specific position | string | null |
-| `filterGroups` | JSON string containing filter groups for advanced filtering | string | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-| `query` | Search term for full-text search across deal properties | string | null |
diff --git a/plugins/agent-auth/references/agent-connectors/intercom.md b/plugins/agent-auth/references/agent-connectors/intercom.md
deleted file mode 100644
index 77ef5d8..0000000
--- a/plugins/agent-auth/references/agent-connectors/intercom.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Intercom. Send messages, manage conversations, and interact with users and contacts.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/jira.md b/plugins/agent-auth/references/agent-connectors/jira.md
deleted file mode 100644
index 1675086..0000000
--- a/plugins/agent-auth/references/agent-connectors/jira.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Jira. Manage issues, projects, workflows, and agile development processes
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/linear.md b/plugins/agent-auth/references/agent-connectors/linear.md
deleted file mode 100644
index 9b0f877..0000000
--- a/plugins/agent-auth/references/agent-connectors/linear.md
+++ /dev/null
@@ -1,58 +0,0 @@
-Connect to Linear. Manage issues, projects, sprints, and development workflows
-
-Supports authentication: OAuth 2.0
-
-## Tool list
-
-## `linear_graphql_query`
-
-Execute a custom GraphQL query or mutation against the Linear API. Allows running any valid GraphQL operation with variables support for advanced use cases.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `query` | The GraphQL query or mutation to execute | string |
-| `variables` | Variables to pass to the GraphQL query | `object` | null |
-
-## `linear_issue_create`
-
-Create a new issue in Linear using the issueCreate mutation. Requires a team ID and title at minimum.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assigneeId` | ID of the user to assign the issue to | string | null |
-| `description` | Description of the issue | string | null |
-| `estimate` | Story point estimate for the issue | string | null |
-| `labelIds` | Array of label IDs to apply to the issue | `array` | null |
-| `priority` | Priority level of the issue (1-4, where 1 is urgent) | string | null |
-| `projectId` | ID of the project to associate the issue with | string | null |
-| `stateId` | ID of the workflow state to set | string | null |
-| `teamId` | ID of the team to create the issue in | string |
-| `title` | Title of the issue | string |
-
-## `linear_issue_update`
-
-Update an existing issue in Linear. You can update title, description, priority, state, and assignee.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assigneeId` | ID of the user to assign the issue to | string | null |
-| `description` | New description for the issue | string | null |
-| `issueId` | ID of the issue to update | string |
-| `priority` | Priority level of the issue (1-4, where 1 is urgent) | string | null |
-| `stateId` | ID of the workflow state to set | string | null |
-| `title` | New title for the issue | string | null |
-
-## `linear_issues_list`
-
-List issues in Linear using the issues query with simple filtering and pagination support.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Cursor for pagination (returns issues after this cursor) | string | null |
-| `assignee` | Filter by assignee email (e.g., 'user@example.com') | string | null |
-| `before` | Cursor for pagination (returns issues before this cursor) | string | null |
-| `first` | Number of issues to return (pagination) | integer | null |
-| `labels` | Filter by label names (array of strings) | `array` | null |
-| `priority` | Filter by priority level (1=Urgent, 2=High, 3=Medium, 4=Low) | string | null |
-| `project` | Filter by project name (e.g., 'Q4 Goals') | string | null |
-| `state` | Filter by state name (e.g., 'In Progress', 'Done') | string | null |
diff --git a/plugins/agent-auth/references/agent-connectors/microsoft_excel.md b/plugins/agent-auth/references/agent-connectors/microsoft_excel.md
deleted file mode 100644
index 2fa4c19..0000000
--- a/plugins/agent-auth/references/agent-connectors/microsoft_excel.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft Excel. Access, read, and modify spreadsheets stored in OneDrive or SharePoint through Microsoft Graph API.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/microsoft_teams.md b/plugins/agent-auth/references/agent-connectors/microsoft_teams.md
deleted file mode 100644
index 85790a1..0000000
--- a/plugins/agent-auth/references/agent-connectors/microsoft_teams.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft Teams. Manage messages, channels, meetings, and team collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/microsoft_word.md b/plugins/agent-auth/references/agent-connectors/microsoft_word.md
deleted file mode 100644
index 7b2d530..0000000
--- a/plugins/agent-auth/references/agent-connectors/microsoft_word.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft Word. Authenticate with your Microsoft account to create, read, and edit Word documents stored in OneDrive or SharePoint through Microsoft Graph API.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/monday.md b/plugins/agent-auth/references/agent-connectors/monday.md
deleted file mode 100644
index 6cc8ab0..0000000
--- a/plugins/agent-auth/references/agent-connectors/monday.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Monday.com. Manage boards, tasks, workflows, teams, and project collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/notion.md b/plugins/agent-auth/references/agent-connectors/notion.md
deleted file mode 100644
index 22b58d5..0000000
--- a/plugins/agent-auth/references/agent-connectors/notion.md
+++ /dev/null
@@ -1,189 +0,0 @@
-Connect to Notion workspace. Create, edit pages, manage databases, and collaborate on content
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `notion_comment_create`
-
-Create a comment in Notion. Provide a comment object with rich_text content and either a parent object (with page_id) for a page-level comment or a discussion_id to reply in an existing thread.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `comment` | Comment object containing a rich_text array. Example: `{"rich_text":[{"type":"text","text":{"content":"Hello"}}]}` | `object` |
-| `discussion_id` | Existing discussion thread ID to reply to. | string | null |
-| `notion_version` | Optional override for the Notion-Version header (e.g., 2022-06-28). | string | null |
-| `parent` | Parent object for a new top-level comment. Shape: `{"page_id":""}`. | `object` | null |
-| `schema_version` | Internal override for schema version. | string | null |
-| `tool_version` | Internal override for tool implementation version. | string | null |
-
-## `notion_comment_retrieve`
-
-Retrieve a single Notion comment by its `comment_id`. LLM tip: you typically obtain `comment_id` from the response of creating a comment or by first listing comments for a page/block and selecting the desired item’s `id`.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `comment_id` | The identifier of the comment to retrieve (hyphenated UUID). Obtain it from Create-Comment responses or from a prior List-Comments call. | string |
-| `notion_version` | Optional Notion-Version header override (e.g., 2022-06-28). | string | null |
-| `schema_version` | Internal override for schema version. | string | null |
-| `tool_version` | Internal override for tool implementation version. | string | null |
-
-## `notion_comments_fetch`
-
-Fetch comments for a given Notion block. Provide a `block_id` (the target page/block ID, hyphenated UUID). Supports pagination via `start_cursor` and `page_size` (1–100). LLM tip: extract `block_id` from a Notion URL’s trailing 32-char id, then insert hyphens (8-4-4-4-12).
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `block_id` | Target Notion block (or page) ID to fetch comments for. Use a hyphenated UUID. | string |
-| `notion_version` | Optional Notion-Version header override (e.g., 2022-06-28). | string | null |
-| `page_size` | Maximum number of comments to return (1–100). | integer | null |
-| `schema_version` | Internal override for schema version. | string | null |
-| `start_cursor` | Cursor to fetch the next page of results. | string | null |
-| `tool_version` | Internal override for tool implementation version. | string | null |
-
-## `notion_data_fetch`
-
-Fetch data from Notion using the workspace search API (/search). Supports pagination via start_cursor.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `page_size` | Max number of results to return (1–100) | integer | null |
-| `query` | Text query used by /search | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `start_cursor` | Cursor for pagination; pass the previous response's next_cursor | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `notion_database_create`
-
-Create a new database in Notion under a parent page. Provide a parent object with page_id, a database title (rich_text array), and a properties object that defines the database schema (columns).
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `notion_version` | Optional override for the Notion-Version header (e.g., 2022-06-28). | string | null |
-| `parent` | Parent object specifying the page under which the database is created. Example: `{"page_id": "2561ab6c-418b-8072-beec-c4779fa811cf"}` | `object` |
-| `properties` | Database schema object defining properties (columns). Example: `{"Name": {"title": {}}, "Status": {"select": {"options": [{"name": "Todo"}, {"name": "Doing"}, {"name": "Done"}]}}}` | `object` |
-| `schema_version` | Internal override for schema version. | string | null |
-| `title` | Database title as a Notion rich_text array. | `array` |
-| `tool_version` | Internal override for tool implementation version. | string | null |
-
-## `notion_database_fetch`
-
-Retrieve a Notion database’s full definition, including title, properties, and schema. Required: `database_id` (hyphenated UUID). LLM tip: Extract the last 32 characters from a Notion database URL, then insert hyphens (8-4-4-4-12).
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `database_id` | The target database ID in UUID format with hyphens. | string |
-| `notion_version` | Optional override for the Notion-Version header. | string | null |
-| `schema_version` | Optional schema version override. | string | null |
-| `tool_version` | Optional tool version override. | string | null |
-
-## `notion_database_insert_row`
-
-Insert a new row (page) into a Notion database. Required: `database_id` (hyphenated UUID) and `properties` (object mapping database column names to Notion **property values). Optional: child_blocks` (content blocks), `icon` (page icon object), and `cover` (page cover object).
-
-LLM guidance:
-- `properties` must use **property values** (not schema). Example:
-
-```json
- {
- "title": { "title": [ { "text": { "content": "Task A" } } ] },
- "Status": { "select": { "name": "Todo" } },
- "Due": { "date": { "start": "2025-09-01" } }
- }
-```
-- Use the **exact property key** as defined in the database (case‑sensitive), or the property id.
-- `icon` example (emoji): `{"type":"emoji","emoji":"📝"}`
-- `cover` example (external): `{"type":"external","external":{"url":"https://example.com/image.jpg"}}`
-- Runtime note: the executor/host should synthesize `parent = {"database_id": database_id}` before sending to Notion.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `_parent` | Computed by host: `{ "database_id": "" }`. Do not supply manually. | `object` | null |
-| `child_blocks` | Optional array of Notion blocks to append as page content (paragraph, heading, to_do, etc.). | `array` | null |
-| `cover` | Optional page cover object. Example external: `{"type":"external","external":{"url":"https://example.com/cover.jpg"}}`. | `object` | null |
-| `database_id` | Target database ID (hyphenated UUID). | string |
-| `icon` | Optional page icon object. Examples: `{"type":"emoji","emoji":"📝"}` or `{"type":"external","external":{"url":"https://..."}}`. | `object` | null |
-| `notion_version` | Optional Notion-Version header override (e.g., 2022-06-28). | string | null |
-| `properties` | Object mapping **column names (or property ids)** to **property values**.
-
-️ **CRITICAL: Property Identification Rules:**
-- For title fields: ALWAYS use 'title' as the property key (not 'Name' or display names)
-- For other properties: Use exact property names from database schema (case-sensitive)
-- DO NOT use URL-encoded property IDs with special characters
-
- **Recommended Workflow:**
-1. Call fetch_database first to see exact property names
-2. Use 'title' for title-type properties
-3. Match other property names exactly as shown in schema
-
-Example:
-
-```json
-{
- "title": { "title": [ { "text": { "content": "Task A" } } ] },
- "Status": { "select": { "name": "Todo" } },
- "Due": { "date": { "start": "2025-09-01" } }
-}
-``` | `object` |
-| `schema_version` | Optional schema version override. | string | null |
-| `tool_version` | Optional tool version override. | string | null |
-
-## `notion_database_property_retrieve`
-
-Query a Notion database and return only specific properties by supplying one or more property IDs. Use when you need page rows but want to limit the returned properties to reduce payload. Provide the database_id and an array of filter_properties (each item is a property id like "title")
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `database_id` | Target database ID (hyphenated UUID). | string |
-| `property_id` | property ID to filter results by a specific property. get the property id by querying database. | string | null |
-| `schema_version` | Optional schema version override. | string | null |
-| `tool_version` | Optional tool version override. | string | null |
-
-## `notion_database_query`
-
-Query a Notion database for rows (pages). Provide database_id (hyphenated UUID). Optional: page_size, start_cursor for pagination, and sorts (array of sort objects). LLM guidance: extract the last 32 characters from a Notion database URL and insert hyphens (8-4-4-4-12) to form database_id. Sort rules: each sort item MUST include either property OR timestamp (last_edited_time/created_time), not both.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `database_id` | Target database ID (hyphenated UUID). | string |
-| `notion_version` | Optional Notion-Version header override. | string | null |
-| `page_size` | Maximum number of rows to return (1–100). | integer | null |
-| `schema_version` | Optional schema version override. | string | null |
-| `sorts` | Order the results. Each item must include either property or timestamp, plus direction. | `array` | null |
-| `start_cursor` | Cursor to fetch the next page of results. | string | null |
-| `tool_version` | Optional tool version override. | string | null |
-
-## `notion_page_create`
-
-Create a page in Notion either inside a database (as a row) or as a child of a page. Use exactly one parent mode: provide database_id to create a database row (page with properties) OR provide parent_page_id to create a child page. When creating in a database, properties must use Notion property value shapes and the title property key must be "title" (not the display name). Children (content blocks), icon, and cover are optional. The executor should synthesize the Notion parent object from the chosen parent input.
-
-Target rules:
-- Use database_id OR parent_page_id (not both)
-- If database_id is provided → properties are required
-- If parent_page_id is provided → properties are optional
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `_parent` | Computed by the executor: `{"database_id": "..."}` OR `{"page_id": "..."}` derived from database_id/parent_page_id. | `object` | null |
-| `child_blocks` | Optional blocks to add as page content (children). | `array` | null |
-| `cover` | Optional page cover object. | `object` | null |
-| `database_id` | Create a page as a new row in this database (hyphenated UUID). Extract from the database URL (last 32 chars → hyphenate 8-4-4-4-12). | string | null |
-| `icon` | Optional page icon object. | `object` | null |
-| `notion_version` | Optional Notion-Version header override. | string | null |
-| `parent_page_id` | Create a child page under this page (hyphenated UUID). Extract from the parent page URL. | string | null |
-| `properties` | For database rows, supply property values keyed by property name (or id). For title properties, the key must be "title".
-
-Example (database row):
-{
- "title": { "title": [ { "text": { "content": "Task A" } } ] },
- "Status": { "select": { "name": "Todo" } },
- "Due": { "date": { "start": "2025-09-01" } }
-} | `object` | null |
-| `schema_version` | Optional schema version override. | string | null |
-| `tool_version` | Optional tool version override. | string | null |
diff --git a/plugins/agent-auth/references/agent-connectors/onedrive.md b/plugins/agent-auth/references/agent-connectors/onedrive.md
deleted file mode 100644
index 601c43f..0000000
--- a/plugins/agent-auth/references/agent-connectors/onedrive.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to OneDrive. Manage files, folders, and cloud storage with Microsoft OneDrive
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/onenote.md b/plugins/agent-auth/references/agent-connectors/onenote.md
deleted file mode 100644
index 47a835b..0000000
--- a/plugins/agent-auth/references/agent-connectors/onenote.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft OneNote. Access, create, and manage notebooks, sections, and pages stored in OneDrive or SharePoint through Microsoft Graph API.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/outlook.md b/plugins/agent-auth/references/agent-connectors/outlook.md
deleted file mode 100644
index 9dae658..0000000
--- a/plugins/agent-auth/references/agent-connectors/outlook.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft Outlook. Manage emails, calendar events, contacts, and tasks
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/salesforce.md b/plugins/agent-auth/references/agent-connectors/salesforce.md
deleted file mode 100644
index f0441b1..0000000
--- a/plugins/agent-auth/references/agent-connectors/salesforce.md
+++ /dev/null
@@ -1,316 +0,0 @@
-Connect to Salesforce CRM. Manage leads, opportunities, accounts, and customer relationships
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `salesforce_account_create`
-
-Create a new Account in Salesforce. Supports standard fields
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `AccountNumber` | Account number for the organization | string | null |
-| `AnnualRevenue` | Annual revenue | number | null |
-| `BillingCity` | Billing city | string | null |
-| `BillingCountry` | Billing country | string | null |
-| `BillingPostalCode` | Billing postal code | string | null |
-| `BillingState` | Billing state/province | string | null |
-| `BillingStreet` | Billing street | string | null |
-| `Description` | Description | string | null |
-| `Industry` | Industry | string | null |
-| `Name` | Account Name | string |
-| `NumberOfEmployees` | Number of employees | integer | null |
-| `OwnerId` | Record owner (User/Queue Id) | string | null |
-| `Phone` | Main phone number | string | null |
-| `RecordTypeId` | Record Type Id | string | null |
-| `Website` | Website URL | string | null |
-
-## `salesforce_account_delete`
-
-Delete an existing Account from Salesforce by account ID. This is a destructive operation that permanently removes the account record.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `account_id` | ID of the account to delete | string |
-
-## `salesforce_account_get`
-
-Retrieve details of a specific account from Salesforce by account ID. Returns account properties and associated data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `account_id` | ID of the account to retrieve | string |
-| `fields` | Comma-separated list of fields to include in the response | string | null |
-
-## `salesforce_account_update`
-
-Update an existing Account in Salesforce by account ID. Allows updating account properties like name, phone, website, industry, billing information, and more.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `AccountNumber` | Account number for the organization | string | null |
-| `AccountSource` | Lead source for this account | string | null |
-| `AnnualRevenue` | Annual revenue | number | null |
-| `BillingCity` | Billing city | string | null |
-| `BillingCountry` | Billing country | string | null |
-| `BillingGeocodeAccuracy` | Billing geocode accuracy | string | null |
-| `BillingLatitude` | Billing address latitude | number | null |
-| `BillingLongitude` | Billing address longitude | number | null |
-| `BillingPostalCode` | Billing postal code | string | null |
-| `BillingState` | Billing state/province | string | null |
-| `BillingStreet` | Billing street | string | null |
-| `CleanStatus` | Data.com clean status | string | null |
-| `Description` | Description | string | null |
-| `DunsNumber` | D-U-N-S Number | string | null |
-| `Fax` | Fax number | string | null |
-| `Industry` | Industry | string | null |
-| `Jigsaw` | Data.com key | string | null |
-| `JigsawCompanyId` | Jigsaw company ID | string | null |
-| `NaicsCode` | NAICS code | string | null |
-| `NaicsDesc` | NAICS description | string | null |
-| `Name` | Account Name | string | null |
-| `NumberOfEmployees` | Number of employees | integer | null |
-| `OwnerId` | Record owner (User/Queue Id) | string | null |
-| `Ownership` | Ownership type | string | null |
-| `ParentId` | Parent Account Id | string | null |
-| `Phone` | Main phone number | string | null |
-| `Rating` | Account rating | string | null |
-| `RecordTypeId` | Record Type Id | string | null |
-| `ShippingCity` | Shipping city | string | null |
-| `ShippingCountry` | Shipping country | string | null |
-| `ShippingGeocodeAccuracy` | Shipping geocode accuracy | string | null |
-| `ShippingLatitude` | Shipping address latitude | number | null |
-| `ShippingLongitude` | Shipping address longitude | number | null |
-| `ShippingPostalCode` | Shipping postal code | string | null |
-| `ShippingState` | Shipping state/province | string | null |
-| `ShippingStreet` | Shipping street | string | null |
-| `Sic` | SIC code | string | null |
-| `SicDesc` | SIC description | string | null |
-| `Site` | Account site or location | string | null |
-| `TickerSymbol` | Stock ticker symbol | string | null |
-| `Tradestyle` | Trade style name | string | null |
-| `Type` | Account type | string | null |
-| `Website` | Website URL | string | null |
-| `YearStarted` | Year the company started | string | null |
-| `account_id` | ID of the account to update | string |
-
-## `salesforce_accounts_list`
-
-Retrieve a list of accounts from Salesforce using a pre-built SOQL query. Returns basic account information.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `limit` | Number of results to return per page | number |
-
-## `salesforce_composite`
-
-Execute multiple Salesforce REST API requests in a single call using the Composite API. Allows for efficient batch operations and related data retrieval.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `composite_request` | JSON string containing composite request with multiple sub-requests | string |
-
-## `salesforce_contact_create`
-
-Create a new contact in Salesforce. Allows setting contact properties like name, email, phone, account association, and other standard fields.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `AccountId` | Salesforce Account Id associated with this contact | string | null |
-| `Department` | Department of the contact | string | null |
-| `Description` | Free-form description | string | null |
-| `Email` | Email address of the contact | string | null |
-| `FirstName` | First name of the contact | string | null |
-| `LastName` | Last name of the contact (required) | string |
-| `LeadSource` | Lead source for the contact | string | null |
-| `MailingCity` | Mailing city | string | null |
-| `MailingCountry` | Mailing country | string | null |
-| `MailingPostalCode` | Mailing postal code | string | null |
-| `MailingState` | Mailing state/province | string | null |
-| `MailingStreet` | Mailing street | string | null |
-| `MobilePhone` | Mobile phone of the contact | string | null |
-| `Phone` | Phone number of the contact | string | null |
-| `Title` | Job title of the contact | string | null |
-
-## `salesforce_contact_get`
-
-Retrieve details of a specific contact from Salesforce by contact ID. Returns contact properties and associated data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `contact_id` | ID of the contact to retrieve | string |
-| `fields` | Comma-separated list of fields to include in the response | string | null |
-
-## `salesforce_dashboard_metadata_get`
-
-Retrieve metadata for a Salesforce dashboard, including dashboard components, filters, layout, and the running user.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `dashboard_id` | The unique ID of the Salesforce dashboard | string |
-
-## `salesforce_global_describe`
-
-Retrieve metadata about all available SObjects in the Salesforce organization. Returns list of all objects with basic information.
-
-## `salesforce_limits_get`
-
-Retrieve organization limits information from Salesforce. Returns API usage limits, data storage limits, and other organizational constraints.
-
-## `salesforce_object_describe`
-
-Retrieve detailed metadata about a specific SObject in Salesforce. Returns fields, relationships, and other object metadata.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `sobject` | SObject API name to describe | string |
-
-## `salesforce_opportunities_list`
-
-Retrieve a list of opportunities from Salesforce using a pre-built SOQL query. Returns basic opportunity information.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `limit` | Number of results to return per page | number | null |
-
-## `salesforce_opportunity_create`
-
-Create a new opportunity in Salesforce. Allows setting opportunity properties like name, amount, stage, close date, and account association.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `AccountId` | Associated Account Id | string | null |
-| `Amount` | Opportunity amount | number | null |
-| `CampaignId` | Related Campaign Id | string | null |
-| `CloseDate` | Expected close date (YYYY-MM-DD, required) | string |
-| `Custom_Field__c` | Example custom field (replace with your org’s custom field API name) | string | null |
-| `Description` | Opportunity description | string | null |
-| `ForecastCategoryName` | Forecast category name | string | null |
-| `LeadSource` | Lead source | string | null |
-| `Name` | Opportunity name (required) | string |
-| `NextStep` | Next step in the sales process | string | null |
-| `OwnerId` | Record owner (User/Queue Id) | string | null |
-| `PricebookId` | Associated Price Book Id | string | null |
-| `Probability` | Probability percentage (0–100) | number | null |
-| `RecordTypeId` | Record Type Id for Opportunity | string | null |
-| `StageName` | Current sales stage (required) | string |
-| `Type` | Opportunity type | string | null |
-
-## `salesforce_opportunity_get`
-
-Retrieve details of a specific opportunity from Salesforce by opportunity ID. Returns opportunity properties and associated data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `fields` | Comma-separated list of fields to include in the response | string | null |
-| `opportunity_id` | ID of the opportunity to retrieve | string |
-
-## `salesforce_opportunity_update`
-
-Update an existing opportunity in Salesforce by opportunity ID. Allows updating opportunity properties like name, amount, stage, and close date.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `AccountId` | Associated Account Id | string | null |
-| `Amount` | Opportunity amount | number | null |
-| `CampaignId` | Related Campaign Id | string | null |
-| `CloseDate` | Expected close date (YYYY-MM-DD) | string | null |
-| `Description` | Opportunity description | string | null |
-| `ForecastCategoryName` | Forecast category name | string | null |
-| `LeadSource` | Lead source | string | null |
-| `Name` | Opportunity name | string | null |
-| `NextStep` | Next step in the sales process | string | null |
-| `OwnerId` | Record owner (User/Queue Id) | string | null |
-| `Pricebook2Id` | Associated Price Book Id | string | null |
-| `Probability` | Probability percentage (0–100) | number | null |
-| `RecordTypeId` | Record Type Id for Opportunity | string | null |
-| `StageName` | Current sales stage | string | null |
-| `Type` | Opportunity type | string | null |
-| `opportunity_id` | ID of the opportunity to update | string |
-
-## `salesforce_query_soql`
-
-Execute SOQL queries against Salesforce data. Supports complex queries with joins, filters, and aggregations.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `query` | SOQL query string to execute | string |
-
-## `salesforce_report_metadata_get`
-
-Retrieve report, report type, and related metadata for a Salesforce report. Returns information about report structure, fields, groupings, and configuration.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `report_id` | The unique ID of the Salesforce report | string |
-
-## `salesforce_search_parameterized`
-
-Execute parameterized searches against Salesforce data. Provides simplified search interface with predefined parameters.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `fields` | Comma-separated list of fields to return | string | null |
-| `search_text` | Text to search for | string |
-| `sobject` | SObject type to search in | string |
-
-## `salesforce_search_sosl`
-
-Execute SOSL searches against Salesforce data. Performs full-text search across multiple objects and fields.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `search_query` | SOSL search query string to execute | string |
-
-## `salesforce_sobject_create`
-
-Create a new record for any Salesforce SObject type (Account, Contact, Lead, Opportunity, custom objects, etc.). Provide the object type and fields as a dynamic object.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `fields` | Object containing field names and values to set on the new record | `object` |
-| `sobject_type` | The Salesforce SObject API name (e.g., Account, Contact, Lead, CustomObject__c) | string |
-
-## `salesforce_sobject_delete`
-
-Delete a record from any Salesforce SObject type by ID. This is a destructive operation that permanently removes the record.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `record_id` | ID of the record to delete | string |
-| `sobject_type` | The Salesforce SObject API name (e.g., Account, Contact, Lead, CustomObject__c) | string |
-
-## `salesforce_sobject_get`
-
-Retrieve a record from any Salesforce SObject type by ID. Optionally specify which fields to return.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `fields` | Comma-separated list of fields to include in the response | string | null |
-| `record_id` | ID of the record to retrieve | string |
-| `sobject_type` | The Salesforce SObject API name (e.g., Account, Contact, Lead, CustomObject__c) | string |
-
-## `salesforce_sobject_update`
-
-Update an existing record for any Salesforce SObject type by ID. Only the fields provided will be updated.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `fields` | Object containing field names and values to update on the record | `object` |
-| `record_id` | ID of the record to update | string |
-| `sobject_type` | The Salesforce SObject API name (e.g., Account, Contact, Lead, CustomObject__c) | string |
-
-## `salesforce_soql_execute`
-
-Execute custom SOQL queries against Salesforce data. Supports complex queries with joins, filters, aggregations, and custom field selection.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `soql_query` | SOQL query string to execute | string |
diff --git a/plugins/agent-auth/references/agent-connectors/servicenow.md b/plugins/agent-auth/references/agent-connectors/servicenow.md
deleted file mode 100644
index b1dc3b0..0000000
--- a/plugins/agent-auth/references/agent-connectors/servicenow.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to ServiceNow. Manage incidents, service requests, CMDB, and IT service management workflows
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/sharepoint.md b/plugins/agent-auth/references/agent-connectors/sharepoint.md
deleted file mode 100644
index c2d88ae..0000000
--- a/plugins/agent-auth/references/agent-connectors/sharepoint.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to SharePoint. Manage sites, documents, lists, and collaborative content
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/slack.md b/plugins/agent-auth/references/agent-connectors/slack.md
deleted file mode 100644
index 8a52cba..0000000
--- a/plugins/agent-auth/references/agent-connectors/slack.md
+++ /dev/null
@@ -1,197 +0,0 @@
-Connect to Slack workspace. Send Messages as Bots or on behalf of users
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `slack_add_reaction`
-
-Add an emoji reaction to a message in Slack. Requires a valid Slack OAuth2 connection with reactions:write scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID or channel name where the message exists | string |
-| `name` | Emoji name to react with (without colons) | string |
-| `timestamp` | Timestamp of the message to add reaction to | string |
-
-## `slack_create_channel`
-
-Creates a new public or private channel in a Slack workspace. Requires a valid Slack OAuth2 connection with channels:manage scope for public channels or groups:write scope for private channels.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `is_private` | Create a private channel instead of public | boolean | null |
-| `name` | Name of the channel to create (without # prefix) | string |
-| `team_id` | Encoded team ID to create channel in (if using org tokens) | string | null |
-
-## `slack_delete_message`
-
-Deletes a message from a Slack channel or direct message. Requires a valid Slack OAuth2 connection with chat:write scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID, channel name (#general), or user ID for DM where the message was sent | string |
-| `ts` | Timestamp of the message to delete | string |
-
-## `slack_fetch_conversation_history`
-
-Fetches conversation history from a Slack channel or direct message with pagination support. Requires a valid Slack OAuth2 connection with channels:history scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID, channel name (#general), or user ID for DM | string |
-| `cursor` | Paginate through collections by cursor for pagination | string | null |
-| `latest` | End of time range of messages to include in results | string | null |
-| `limit` | Number of messages to return (1-1000, default 100) | integer | null |
-| `oldest` | Start of time range of messages to include in results | string | null |
-
-## `slack_get_conversation_info`
-
-Retrieve information about a Slack channel, including metadata, settings, and member count. Requires a valid Slack OAuth2 connection with channels:read scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID, channel name (#general), or user ID for DM | string |
-| `include_locale` | Set to true to include the locale for this conversation | boolean | null |
-| `include_num_members` | Set to true to include the member count for the conversation | boolean | null |
-
-## `slack_get_conversation_replies`
-
-Retrieve replies to a specific message thread in a Slack channel or direct message. Requires a valid Slack OAuth2 connection with channels:history or groups:history scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID, channel name (#general), or user ID for DM | string |
-| `cursor` | Pagination cursor for retrieving next page of results | string | null |
-| `inclusive` | Include messages with latest or oldest timestamp in results | boolean | null |
-| `latest` | End of time range of messages to include in results | string | null |
-| `limit` | Number of messages to return (default 100, max 1000) | integer | null |
-| `oldest` | Start of time range of messages to include in results | string | null |
-| `ts` | Timestamp of the parent message to get replies for | string |
-
-## `slack_get_user_info`
-
-Retrieves detailed information about a specific Slack user, including profile data, status, and workspace information. Requires a valid Slack OAuth2 connection with users:read scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `include_locale` | Set to true to include locale information for the user | boolean | null |
-| `user` | User ID to get information about | string |
-
-## `slack_get_user_presence`
-
-Gets the current presence status of a Slack user (active, away, etc.). Indicates whether the user is currently online and available. Requires a valid Slack OAuth2 connection with users:read scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `user` | User ID to check presence for | string |
-
-## `slack_invite_users_to_channel`
-
-Invites one or more users to a Slack channel. Requires a valid Slack OAuth2 connection with channels:write scope for public channels or groups:write for private channels.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID or channel name (#general) to invite users to | string |
-| `users` | Comma-separated list of user IDs to invite to the channel | string |
-
-## `slack_join_conversation`
-
-Joins an existing Slack channel. The authenticated user will become a member of the channel. Requires a valid Slack OAuth2 connection with channels:write scope for public channels.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID or channel name (#general) to join | string |
-
-## `slack_leave_conversation`
-
-Leaves a Slack channel. The authenticated user will be removed from the channel and will no longer receive messages from it. Requires a valid Slack OAuth2 connection with channels:write scope for public channels or groups:write for private channels.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID or channel name (#general) to leave | string |
-
-## `slack_list_channels`
-
-List all public and private channels in a Slack workspace that the authenticated user has access to. Requires a valid Slack OAuth2 connection with channels:read, groups:read, mpim:read, and/or im:read scopes depending on conversation types needed.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `cursor` | Pagination cursor for retrieving next page of results | string | null |
-| `exclude_archived` | Exclude archived channels from the list | boolean | null |
-| `limit` | Number of channels to return (default 100, max 1000) | integer | null |
-| `team_id` | Encoded team ID to list channels for (optional) | string | null |
-| `types` | Mix and match channel types (public_channel, private_channel, mpim, im) | string | null |
-
-## `slack_list_users`
-
-Lists all users in a Slack workspace, including information about their status, profile, and presence. Requires a valid Slack OAuth2 connection with users:read scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `cursor` | Pagination cursor for fetching additional pages of users | string | null |
-| `include_locale` | Set to true to include locale information for each user | boolean | null |
-| `limit` | Number of users to return (1-1000) | number | null |
-| `team_id` | Encoded team ID to list users for (if using org tokens) | string | null |
-
-## `slack_lookup_user_by_email`
-
-Find a user by their registered email address in a Slack workspace. Requires a valid Slack OAuth2 connection with users:read.email scope. Cannot be used by custom bot users.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `email` | Email address to search for users by | string |
-
-## `slack_pin_message`
-
-Pin a message to a Slack channel. Pinned messages are highlighted and easily accessible to channel members. Requires a valid Slack OAuth2 connection with pins:write scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `channel` | Channel ID or channel name where the message exists | string |
-| `timestamp` | Timestamp of the message to pin | string |
-
-## `slack_send_message`
-
-Sends a message to a Slack channel or direct message. Requires a valid Slack OAuth2 connection with chat:write scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attachments` | JSON-encoded array of attachment objects for additional message formatting | string | null |
-| `blocks` | JSON-encoded array of Block Kit block elements for rich message formatting | string | null |
-| `channel` | Channel ID, channel name (#general), or user ID for DM | string |
-| `reply_broadcast` | Used in conjunction with thread_ts to broadcast reply to channel | boolean | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `text` | Message text content | string |
-| `thread_ts` | Timestamp of parent message to reply in thread | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-| `unfurl_links` | Enable or disable link previews | boolean | null |
-| `unfurl_media` | Enable or disable media link previews | boolean | null |
-
-## `slack_set_user_status`
-
-Set the user's custom status with text and emoji. This appears in their profile and can include an expiration time. Requires a valid Slack OAuth2 connection with users.profile:write scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `status_emoji` | Emoji to display with status (without colons) | string | null |
-| `status_expiration` | Unix timestamp when status should expire | integer | null |
-| `status_text` | Status text to display | string | null |
-
-## `slack_update_message`
-
-Updates/edits a previously sent message in a Slack channel or direct message. Requires a valid Slack OAuth2 connection with chat:write scope.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attachments` | JSON-encoded array of attachment objects for additional message formatting | string | null |
-| `blocks` | JSON-encoded array of Block Kit block elements for rich message formatting | string | null |
-| `channel` | Channel ID, channel name (#general), or user ID for DM where the message was sent | string |
-| `text` | New message text content | string | null |
-| `ts` | Timestamp of the message to update | string |
diff --git a/plugins/agent-auth/references/agent-connectors/snowflake.md b/plugins/agent-auth/references/agent-connectors/snowflake.md
deleted file mode 100644
index 12dba3f..0000000
--- a/plugins/agent-auth/references/agent-connectors/snowflake.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Snowflake to manage and analyze your data warehouse workloads
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/trello.md b/plugins/agent-auth/references/agent-connectors/trello.md
deleted file mode 100644
index 181e36c..0000000
--- a/plugins/agent-auth/references/agent-connectors/trello.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Trello. Manage boards, cards, lists, and team collaboration workflows
-
-Supports authentication: OAuth 1.0a
diff --git a/plugins/agent-auth/references/agent-connectors/zendesk.md b/plugins/agent-auth/references/agent-connectors/zendesk.md
deleted file mode 100644
index f993da1..0000000
--- a/plugins/agent-auth/references/agent-connectors/zendesk.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Zendesk. Manage customer support tickets, users, organizations, and help desk operations
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agent-auth/references/agent-connectors/zoom.md b/plugins/agent-auth/references/agent-connectors/zoom.md
deleted file mode 100644
index 9bfdda0..0000000
--- a/plugins/agent-auth/references/agent-connectors/zoom.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Zoom. Schedule meetings, manage recordings, and handle video conferencing workflows
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/.github/plugin/plugin.json b/plugins/agentkit/.github/plugin/plugin.json
new file mode 100644
index 0000000..1befd0e
--- /dev/null
+++ b/plugins/agentkit/.github/plugin/plugin.json
@@ -0,0 +1,21 @@
+{
+ "name": "agentkit",
+ "description": "Authentication for AI agents. OAuth flows, token vault, 40+ connectors (Gmail, Slack, Salesforce, etc.), tool discovery, and live testing — so agents can act on behalf of users.",
+ "version": "2.0.0",
+ "author": {
+ "name": "Scalekit Inc",
+ "email": "support@scalekit.com"
+ },
+ "homepage": "https://docs.scalekit.com/agentkit/overview.md",
+ "repository": "https://github.com/scalekit-inc/github-copilot-authstack",
+ "license": "MIT",
+ "keywords": ["scalekit", "agentkit", "agent-auth", "oauth", "connectors", "tool-calling"],
+ "skills": [
+ "./skills/integrating-agentkit",
+ "./skills/discovering-connector-tools",
+ "./skills/exposing-agentkit-via-mcp",
+ "./skills/production-readiness-agentkit"
+ ],
+ "hooks": "./hooks/hooks.json",
+ "mcpServers": ".mcp.json"
+}
diff --git a/plugins/agent-auth/.mcp.json b/plugins/agentkit/.mcp.json
similarity index 100%
rename from plugins/agent-auth/.mcp.json
rename to plugins/agentkit/.mcp.json
diff --git a/plugins/agentkit/README.md b/plugins/agentkit/README.md
new file mode 100644
index 0000000..879f672
--- /dev/null
+++ b/plugins/agentkit/README.md
@@ -0,0 +1,28 @@
+# AgentKit for GitHub Copilot
+
+Authentication for AI agents. This plugin brings Scalekit AgentKit into GitHub Copilot so agents can connect users to third-party apps, discover the right tools, and execute authenticated tool calls on their behalf.
+
+AgentKit handles the full OAuth lifecycle — authorization, token vault, and automatic refresh — across 40+ connectors (Gmail, Slack, Salesforce, Notion, and more).
+
+The plugin treats live AgentKit metadata as the source of truth for tool names, `input_schema`, and `output_schema`. For per-connector details, see the [AgentKit connectors catalog](https://docs.scalekit.com/agentkit/connectors/).
+
+## Skills
+
+- `integrating-agentkit` — Core integration: SDK setup, connected accounts, OAuth flows, token fetching, downstream API calls, and agent framework examples.
+- `discovering-connector-tools` — Uses live AgentKit metadata to find tools, inspect schemas, and narrow the tool set.
+- `exposing-agentkit-via-mcp` — Exposes AgentKit tools through MCP for MCP-compatible runtimes.
+- `production-readiness-agentkit` — Structured production readiness checklist for AgentKit integrations.
+
+## Configuration
+
+Required environment variables:
+
+- `SCALEKIT_ENV_URL`
+- `SCALEKIT_CLIENT_ID`
+- `SCALEKIT_CLIENT_SECRET`
+
+## Links
+
+- [AgentKit overview](https://docs.scalekit.com/agentkit/overview.md)
+- [AgentKit quickstart](https://docs.scalekit.com/agentkit/quickstart.md)
+- [LLM docs map](https://docs.scalekit.com/llms.txt)
diff --git a/plugins/agentkit/hooks/beacon.sh b/plugins/agentkit/hooks/beacon.sh
new file mode 100755
index 0000000..85af851
--- /dev/null
+++ b/plugins/agentkit/hooks/beacon.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+PLUGIN="${1:-unknown}"
+HOOK="${2:-stop}"
+INPUT=$(cat)
+
+SESSION_ID=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('session_id','anonymous'))" \
+ 2>/dev/null || echo "anonymous")
+
+TOOL_NAME=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" \
+ 2>/dev/null || echo "")
+
+curl -s -o /dev/null --max-time 5 \
+ -X POST https://ph.scalekit.com/i/v0/e/ \
+ -H "Content-Type: application/json" \
+ -d "{\"token\":\"phc_85pLP8gwYvRCQdxgLQP24iqXHPRGaLgEw4S4dgZHJZ\",\
+\"event\":\"plugin_used\",\
+\"distinct_id\":\"${SESSION_ID}\",\
+\"properties\":{\"plugin\":\"${PLUGIN}\",\"coding_agent\":\"copilot\",\"hook\":\"${HOOK}\",\"tool_name\":\"${TOOL_NAME}\"}}"
\ No newline at end of file
diff --git a/plugins/agentkit/hooks/hooks.json b/plugins/agentkit/hooks/hooks.json
new file mode 100644
index 0000000..95f75a9
--- /dev/null
+++ b/plugins/agentkit/hooks/hooks.json
@@ -0,0 +1,16 @@
+{
+ "description": "Usage beacon for Scalekit agentkit plugin",
+ "hooks": {
+ "Stop": [
+ {
+ "hooks": [
+ {
+ "type": "command",
+ "command": "${COPILOT_PLUGIN_ROOT}/hooks/beacon.sh agentkit stop",
+ "timeout": 10
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/plugins/agent-auth/references/byoc.md b/plugins/agentkit/references/byoc.md
similarity index 88%
rename from plugins/agent-auth/references/byoc.md
rename to plugins/agentkit/references/byoc.md
index b88d0f6..83460ac 100644
--- a/plugins/agent-auth/references/byoc.md
+++ b/plugins/agentkit/references/byoc.md
@@ -1,6 +1,6 @@
# Bring Your Own Credentials
-Bring Your Own Credentials (BYOC) allows you to use your own OAuth applications and authentication credentials with Agent Auth instead of Scalekit's shared credentials. This provides complete control over the authentication experience and enables full whitelabeling of your application.
+Bring Your Own Credentials (BYOC) allows you to use your own OAuth applications and authentication credentials with AgentKit instead of Scalekit's shared credentials. This provides complete control over the authentication experience and enables full whitelabeling of your application.
## Why bring your own credentials?
@@ -33,7 +33,7 @@ With BYOC, authentication flows work as follows:
1. **Scalekit** handles the initial authentication request with your OAuth client-id details
2. **Provider** authenticates the user and returns tokens to Scalekit
-3. **Agent Auth** uses your tokens to execute tools on behalf of users
+3. **AgentKit** uses your tokens to execute tools on behalf of users
## Setting up BYOC
@@ -53,4 +53,4 @@ If you're currently using Scalekit's shared credentials and want to migrate to B
> - Rate limits and quotas will change to your application's limits
> - Some users may need to re-grant permissions
-By implementing BYOC, you gain complete control over your users' authentication experience while maintaining the power and flexibility of Agent Auth's unified API for tool execution.
+By implementing BYOC, you gain complete control over your users' authentication experience while maintaining the power and flexibility of AgentKit's unified API for tool execution.
diff --git a/plugins/agent-auth/references/code-samples.md b/plugins/agentkit/references/code-samples.md
similarity index 98%
rename from plugins/agent-auth/references/code-samples.md
rename to plugins/agentkit/references/code-samples.md
index 537ca57..81361aa 100644
--- a/plugins/agent-auth/references/code-samples.md
+++ b/plugins/agentkit/references/code-samples.md
@@ -1,6 +1,6 @@
# Code Samples
-This reference provides implementation examples for integrating Scalekit Agent Auth across different frameworks, languages, and use cases.
+This reference provides implementation examples for integrating Scalekit AgentKit across different frameworks, languages, and use cases.
## Quick Start Guide
@@ -129,7 +129,7 @@ response = agent_executor.invoke({
### Repository: [scalekit-inc/google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example.git)
-**Overview:** Minimal Gmail-powered agent demonstrating Agent Auth integration with Google's Agent Development Kit. Entire integration fits in one file.
+**Overview:** Minimal Gmail-powered agent demonstrating AgentKit integration with Google's Agent Development Kit. Entire integration fits in one file.
**Requirements:**
- Python >= 3.11
diff --git a/plugins/agent-auth/references/connected-accounts.md b/plugins/agentkit/references/connected-accounts.md
similarity index 97%
rename from plugins/agent-auth/references/connected-accounts.md
rename to plugins/agentkit/references/connected-accounts.md
index c32f761..6aa7b9c 100644
--- a/plugins/agent-auth/references/connected-accounts.md
+++ b/plugins/agentkit/references/connected-accounts.md
@@ -1,6 +1,6 @@
# Connected accounts
-Connected accounts in Agent Auth represent individual user or organization connections to third-party providers. They contain the authentication state, tokens, and permissions needed to execute tools on behalf of a specific identifier (user_id, org_id, or custom identifier).
+Connected accounts in AgentKit represent individual user or organization connections to third-party providers. They contain the authentication state, tokens, and permissions needed to execute tools on behalf of a specific identifier (user_id, org_id, or custom identifier).
## What are connected accounts?
@@ -51,7 +51,7 @@ F -> B
### Using the dashboard
-1. Navigate to connected accounts in your Agent Auth dashboard
+1. Navigate to connected accounts in your AgentKit dashboard
2. Click create account to start the process
3. Select connection to use for authentication
4. Enter identifier (user_id, email, or custom identifier)
diff --git a/plugins/agent-auth/references/connections.md b/plugins/agentkit/references/connections.md
similarity index 95%
rename from plugins/agent-auth/references/connections.md
rename to plugins/agentkit/references/connections.md
index 118dc1f..d3c882e 100644
--- a/plugins/agent-auth/references/connections.md
+++ b/plugins/agentkit/references/connections.md
@@ -1,6 +1,6 @@
# Connections
-Connections in Agent Auth are specific configurations that define how your application authenticates and interacts with third-party providers. Each connection contains the necessary credentials, settings, and parameters required to establish secure communication with a provider's API.
+Connections in AgentKit are specific configurations that define how your application authenticates and interacts with third-party providers. Each connection contains the necessary credentials, settings, and parameters required to establish secure communication with a provider's API.
## Table of Contents
@@ -18,7 +18,7 @@ Connections in Agent Auth are specific configurations that define how your appli
## What are connections?
-Connections serve as the bridge between your Agent Auth setup and third-party providers. They contain:
+Connections serve as the bridge between your AgentKit setup and third-party providers. They contain:
- **Authentication credentials** (OAuth client ID/secret, API keys, etc.)
- **Configuration settings** (scopes, permissions, endpoints)
@@ -28,7 +28,7 @@ Connections serve as the bridge between your Agent Auth setup and third-party pr
## Connection types
-Agent Auth supports various connection types based on different authentication methods:
+AgentKit supports various connection types based on different authentication methods:
### OAuth 2.0 connections
@@ -101,7 +101,7 @@ For providers with unique authentication requirements:
### Using the dashboard
-1. **Navigate to connections** in your Agent Auth dashboard
+1. **Navigate to connections** in your AgentKit dashboard
2. **Select provider** from the list of available providers
3. **Choose connection type** based on your authentication method
4. **Configure credentials** by entering your API keys or OAuth settings
@@ -111,7 +111,7 @@ For providers with unique authentication requirements:
### Using the API
-Create connections programmatically using the Agent Auth API:
+Create connections programmatically using the AgentKit API:
**cURL:**
diff --git a/plugins/agent-auth/references/providers.md b/plugins/agentkit/references/connectors.md
similarity index 78%
rename from plugins/agent-auth/references/providers.md
rename to plugins/agentkit/references/connectors.md
index 0a3ceb8..35f879d 100644
--- a/plugins/agent-auth/references/providers.md
+++ b/plugins/agentkit/references/connectors.md
@@ -1,19 +1,19 @@
-# Providers
+# Connectors
-Providers in Agent Auth represent third-party applications that your users can connect to and interact with through Scalekit's unified API. Each provider offers a set of tools and capabilities that can be executed on behalf of connected users.
+Connectors in AgentKit represent third-party applications that your users can connect to and interact with through Scalekit's unified API. Each connector offers a set of tools and capabilities that can be executed on behalf of connected users.
-## What are providers?
+## What are connectors?
-Providers are pre-configured integrations with popular third-party applications that enable your users to:
+Connectors are pre-configured integrations with popular third-party applications that enable your users to:
- **Connect their accounts** using secure authentication methods
- **Execute tools and actions** through a unified API interface
- **Access data and functionality** from external applications
- **Maintain secure connections** with proper authorization scopes
-## Supported providers
+## Supported connectors
-Agent Auth supports a wide range of popular business applications:
+AgentKit supports a wide range of popular business applications:
| Category | Providers |
|---|---|
@@ -29,11 +29,11 @@ Agent Auth supports a wide range of popular business applications:
| **Media** | Vimeo, YouTube |
| **Service Management** | ServiceNow |
-For per-connector tool specifications, see [agent-connectors/README.md](agent-connectors/README.md).
+For per-connector tool specifications, see the [AgentKit connectors catalog](https://docs.scalekit.com/agentkit/connectors/).
-## Provider capabilities
+## Connector capabilities
-Each provider offers different capabilities based on their API and authentication model.
+Each connector offers different capabilities based on their API and authentication model.
### Authentication methods
@@ -41,7 +41,7 @@ Each provider offers different capabilities based on their API and authenticatio
### Available tools
-Providers expose various tools that can be executed through Agent Auth:
+Connectors expose various tools that can be executed through AgentKit:
> **Note:** Tool availability depends on the specific provider and the user's permissions within that application.
@@ -61,19 +61,19 @@ Each provider has different rate limits and quotas:
- **Data quotas**: Storage or transfer limitations
- **Feature restrictions**: Premium features or enterprise-only capabilities
-## Provider configuration
+## Connector configuration
-### Adding a provider
+### Adding a connector
-1. **Navigate to providers** in your Agent Auth dashboard
-2. **Select provider** from the available options
+1. **Navigate to connectors** in your AgentKit dashboard
+2. **Select connector** from the available options
3. **Configure settings** such as scopes and permissions
4. **Set up authentication** — configure OAuth client credentials if using custom OAuth apps
-5. **Test connection** to verify provider setup
+5. **Test connection** to verify connector setup
-### Provider settings
+### Connector settings
-Each provider can be configured with:
+Each connector can be configured with:
**Authentication settings:**
- OAuth client credentials (if using custom OAuth apps)
@@ -85,11 +85,11 @@ Each provider can be configured with:
- Request throttling settings
- Backoff strategies for rate limit errors
-## Working with provider APIs
+## Working with connector APIs
### API integration
-The Scalekit SDK abstracts provider-specific APIs — the workflow (create account → authorize → fetch token → call API) is identical for all providers. Only the downstream API call changes:
+The Scalekit SDK abstracts connector-specific APIs — the workflow (create account → authorize → fetch token → call API) is identical for all connectors. Only the downstream API call changes:
```python
# Step 3: Fetch token (always call this immediately before the API call)
@@ -108,7 +108,7 @@ Scalekit automatically refreshes expired tokens on `get_connected_account` — n
### Error handling
-Agent Auth normalizes provider-specific errors into consistent error responses:
+AgentKit normalizes connector-specific errors into consistent error responses:
```javascript
{
@@ -124,7 +124,7 @@ Agent Auth normalizes provider-specific errors into consistent error responses:
}
```
-## Provider-specific considerations
+## Connector-specific considerations
### Google Workspace
@@ -185,7 +185,7 @@ Agent Auth normalizes provider-specific errors into consistent error responses:
## Related documentation
-- [connections.md](connections.md) — how to configure authentication credentials for a provider
+- [connections.md](connections.md) — how to configure authentication credentials for a connector
- [connected-accounts.md](connected-accounts.md) — per-user account lifecycle and token management
-- [agent-connectors/README.md](agent-connectors/README.md) — detailed API tools for each provider
+- [AgentKit connectors catalog](https://docs.scalekit.com/agentkit/connectors/) — live tool specs for each connector
- [code-samples.md](code-samples.md) — implementation examples by framework
diff --git a/plugins/agent-auth/references/redirects.md b/plugins/agentkit/references/redirects.md
similarity index 100%
rename from plugins/agent-auth/references/redirects.md
rename to plugins/agentkit/references/redirects.md
diff --git a/plugins/agentkit/references/tool-discovery.md b/plugins/agentkit/references/tool-discovery.md
new file mode 100644
index 0000000..a77861c
--- /dev/null
+++ b/plugins/agentkit/references/tool-discovery.md
@@ -0,0 +1,73 @@
+# Tool Discovery
+
+Live AgentKit metadata is the source of truth for:
+
+- current connector coverage
+- tool names
+- `input_schema`
+- `output_schema`
+
+This is the most important rule in the hybrid structure.
+
+## What belongs in docs vs live metadata
+
+Use `references/` for:
+
+- stable terminology
+- auth and setup guidance
+- connector quirks
+- example workflows
+
+Use live metadata for:
+
+- current tools for a connector
+- required input fields
+- optional input fields
+- output shape
+
+## Official Scalekit docs
+
+- [Tools overview](https://docs.scalekit.com/agentkit/tools/overview.md)
+- [Scalekit optimized built-in tools](https://docs.scalekit.com/agentkit/tools/scalekit-optimized-tools.md)
+- [AgentKit connectors](https://docs.scalekit.com/agentkit/connectors.md)
+
+## Discovery workflow
+
+1. Start from a connector or exact tool name.
+2. Query live AgentKit metadata.
+3. Inspect:
+ - tool name
+ - description
+ - connector or provider grouping
+ - `input_schema.required`
+ - `input_schema.properties`
+ - `output_schema.properties`
+4. Narrow the tool set to the few tools needed for the workflow.
+5. Only execute after the schema is clear and the user has an `ACTIVE` connected account.
+
+## Important distinction
+
+Do not confuse:
+
+- dashboard `connection_name`
+- connector or provider slug used for discovery filters
+
+The first is used for authorization and connected-account operations.
+The second is used for catalog discovery.
+
+## Copilot workflow
+
+Use:
+
+- `discovering-connector-tools` when the user needs current tools or schemas
+- The Scalekit MCP server (`https://mcp.scalekit.com`) when the user wants to run a live tool and inspect the exact payload
+
+## Fallback rule
+
+If live credentials are unavailable, connector notes are still useful as a directional guide, but they must be treated as non-exhaustive.
+
+## Related docs
+
+- [connections.md](connections.md)
+- [connected-accounts.md](connected-accounts.md)
+- [connectors.md](connectors.md)
\ No newline at end of file
diff --git a/plugins/agentkit/skills/discovering-connector-tools/SKILL.md b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
new file mode 100644
index 0000000..73e63b0
--- /dev/null
+++ b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
@@ -0,0 +1,55 @@
+---
+name: discovering-connector-tools
+description: Discovers live tools for a Scalekit AgentKit connector and explains their input and output schemas. Use when a user asks what tools are available for Gmail, Slack, Salesforce, or another connector, wants to inspect input_schema or output_schema, or needs help narrowing the tool set for an agent.
+---
+
+# Discovering Connector Tools
+
+Use live AgentKit metadata as the source of truth for tool names, required inputs, and output schemas.
+
+Do not rely on the static connector notes as a complete catalog. Those files are curated reference material and may lag the live platform.
+
+## When to use this skill
+
+Use this skill when the user asks:
+
+- what tools exist for a connector
+- which tool should the agent use
+- what inputs a tool requires
+- what output shape a tool returns
+- how to reduce the tool set before giving tools to an LLM
+
+## Discovery workflow
+
+1. Identify the target connector or exact tool name.
+2. Use the Scalekit MCP server or SDK to fetch live tool metadata.
+3. Summarize:
+ - tool name
+ - connector
+ - what the tool does
+ - required fields from `input_schema.required`
+ - optional fields from `input_schema.properties`
+ - important fields from `output_schema.properties`
+4. Recommend the smallest useful tool set for the workflow.
+5. If live credentials are unavailable, use the connector notes only as a fallback and say they may be stale.
+
+## Terminology
+
+- `connector`: Gmail, Slack, Salesforce, Notion, or a custom connector
+- `connection`: the exact dashboard configuration name used for authorization
+- `connected account`: the per-user authorized record
+- `tool`: the executable action exposed by a connector
+
+Use `connector` in explanations. Only use `provider` when the SDK or API filter field literally expects that name.
+
+## What to emphasize
+
+- `connection_name` is the exact dashboard value and may not equal the connector slug.
+- Tool metadata is the durable way to determine current inputs and outputs.
+- Restrict the tool set before handing it to an LLM. Fewer relevant tools improve tool selection and parameter filling.
+
+## Deep reference
+
+- Connector reference: [AgentKit connectors catalog](https://docs.scalekit.com/agentkit/connectors/)
+- Connected accounts lifecycle: [../../references/connected-accounts.md](../../references/connected-accounts.md)
+- Code samples: [../../references/code-samples.md](../../references/code-samples.md)
diff --git a/plugins/agent-auth/skills/building-agent-mcp-server/SKILL.md b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
similarity index 89%
rename from plugins/agent-auth/skills/building-agent-mcp-server/SKILL.md
rename to plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
index b8e85b7..91f1a87 100644
--- a/plugins/agent-auth/skills/building-agent-mcp-server/SKILL.md
+++ b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
@@ -1,5 +1,5 @@
---
-name: building-agent-mcp-server
+name: exposing-agentkit-via-mcp
description: Guides developers through creating a Scalekit MCP server with authenticated tool access. Use when building an MCP server, exposing Scalekit tools over MCP, or connecting AI agents via LangChain/LangGraph MCP adapters.
---
@@ -7,9 +7,9 @@ description: Guides developers through creating a Scalekit MCP server with authe
Scalekit lets you build MCP servers that manage authentication, create personalized access URLs for users, and define which tools are accessible. You can also bundle several toolkits (e.g., Gmail + Google Calendar) within a single server.
-[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is an open-source standard that enables AI systems to interface with external tools and data sources. Where the `integrating-agent-auth` skill uses the SDK directly, this workflow exposes Scalekit tools over the MCP protocol so any compliant client — LangChain, Claude Desktop, MCP Inspector — can consume them.
+[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is an open-source standard that enables AI systems to interface with external tools and data sources. Where the `integrating-agentkit` skill uses the SDK directly, this workflow exposes Scalekit tools over the MCP protocol so any compliant client — LangChain, MCP Inspector, GitHub Copilot — can consume them.
-> **Note:** Agent Auth MCP servers only support Streamable HTTP transport.
+> **Note:** AgentKit MCP servers only support Streamable HTTP transport.
## What you'll build
@@ -23,12 +23,12 @@ Scalekit lets you build MCP servers that manage authentication, create personali
> **Gmail is the only connector that does not require dashboard setup.** All other connectors (including Google Calendar) must be created in the Scalekit Dashboard before use:
>
-> Go to **Scalekit Dashboard → Agent Auth → Connections → + Create Connection → Select connector** → Set `Connection Name` → Save
+> Go to **Scalekit Dashboard → AgentKit → Connections → + Create Connection → Select connector** → Set `Connection Name` → Save
> **Important**: The **Connection Name** you set in the dashboard is exactly what you use as the `connection_name` parameter in your code. They must match exactly.
For this example, create the Google Calendar connector:
-- [ ] **Google Calendar connector**: Scalekit Dashboard → Agent Auth → Connections → Create Connection → Google Calendar → `Connection Name = MY_CALENDAR` → Save
+- [ ] **Google Calendar connector**: Scalekit Dashboard → AgentKit → Connections → Create Connection → Google Calendar → `Connection Name = MY_CALENDAR` → Save
## Step 1 — Set up your environment
@@ -153,6 +153,6 @@ async def main():
asyncio.run(main())
```
-> **Note — MCP client compatibility:** You can test this MCP server with popular clients like MCP Inspector, Claude Desktop, and other spec-compliant implementations. Note that ChatGPT's beta connector feature may not work properly as it's still in beta and doesn't fully adhere to the MCP specification yet.
+> **Note — MCP client compatibility:** You can test this MCP server with popular clients like MCP Inspector, GitHub Copilot, and other spec-compliant implementations. Note that ChatGPT's beta connector feature may not work properly as it's still in beta and doesn't fully adhere to the MCP specification yet.
Full working example: [github.com/scalekit-inc/python-connect-demos/tree/main/mcp](https://github.com/scalekit-inc/python-connect-demos/tree/main/mcp)
diff --git a/plugins/agent-auth/skills/agent-auth/SKILL.md b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
similarity index 88%
rename from plugins/agent-auth/skills/agent-auth/SKILL.md
rename to plugins/agentkit/skills/integrating-agentkit/SKILL.md
index 05bf999..857e3a6 100644
--- a/plugins/agent-auth/skills/agent-auth/SKILL.md
+++ b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
@@ -1,9 +1,9 @@
---
-name: integrating-agent-auth
-description: Integrates Scalekit Agent Auth into a project to handle OAuth flows, token storage, and automatic refresh for third-party services (Gmail, Slack, Notion, Calendar). Use when a user needs to connect to an external service, authorize OAuth access, fetch access or refresh tokens, or execute API calls on behalf of a user.
+name: integrating-agentkit
+description: Integrates Scalekit AgentKit into a project to handle OAuth flows, token storage, and automatic refresh for third-party connectors (Gmail, Slack, Notion, Calendar, and 40+ more). Use when a user needs to connect to an external service, authorize OAuth access, fetch access or refresh tokens, execute API calls on behalf of a user, or build agents with LangChain or Google ADK.
---
-# Agent Auth Integration
+# AgentKit Integration
Scalekit handles the full OAuth lifecycle — authorization, token storage, and refresh — so agents can act on behalf of users in Gmail, Slack, Notion, Calendar, and other connectors.
@@ -16,7 +16,7 @@ Install the SDK and initialize the client:
> **Important**: Except for Gmail, all connectors must be configured in the Scalekit Dashboard first before creating authorization URLs.
>
-> To set up a connector: **Scalekit Dashboard → Agent Auth → Connections → + Create Connection → Select connector → Set Connection Name → Save**
+> To set up a connector: **Scalekit Dashboard → AgentKit → Connections → + Create Connection → Select connector → Set Connection Name → Save**
@@ -39,7 +39,7 @@ actions = scalekit.actions
**Node.js**
```bash
-npm install @scalekit-sdk/node@2.2.0-beta.1
+npm install @scalekit-sdk/node
```
```typescript
import { ScalekitClient } from '@scalekit-sdk/node';
@@ -63,7 +63,7 @@ Before integrating with a connector, follow these steps in the Scalekit Dashboar
For all other connectors (Slack, Notion, Google Calendar, etc.):
-1. Go to **Scalekit Dashboard → Agent Auth → Connections**
+1. Go to **Scalekit Dashboard → AgentKit → Connections**
2. Click **+ Create Connection**
3. Select the connector you want to use
4. Enter a **Connection Name** (e.g., `MY_SLACK`, `MY_NOTION`)
@@ -83,7 +83,7 @@ For all other connectors (Slack, Notion, Google Calendar, etc.):
Copy this checklist and check off steps as you complete them:
```
-Agent Auth Integration Progress:
+AgentKit Integration Progress:
- [ ] Step 1: SDK installed and client initialized
- [ ] Step 2: Connected account created for the user
- [ ] Step 3: User has authorized the connection (status = ACTIVE)
@@ -223,7 +223,7 @@ for (const msg of messages) {
Replace `"gmail"` with any supported connector name: `slack`, `notion`, `calendar`, etc.
The SDK workflow (Steps 1–3) is identical for all connectors. Only the downstream API call (Step 4) changes.
-For connector-specific API details, see [CONNECTORS.md](CONNECTORS.md).
+For connector-specific API details, see the [AgentKit connectors catalog](https://docs.scalekit.com/agentkit/connectors/).
## Building agents
@@ -289,16 +289,16 @@ agent = Agent(
response = agent.process_request("fetch my last 5 unread emails and summarize them")
```
-For more examples and framework-specific patterns, see [code-samples.md](../references/code-samples.md).
+For more examples and framework-specific patterns, see [code-samples.md](../../references/code-samples.md).
## Deep reference
-For comprehensive documentation on connected accounts lifecycle, states, and API usage, see [connected-accounts.md](../references/connected-accounts.md).
+For comprehensive documentation on connected accounts lifecycle, states, and API usage, see [connected-accounts.md](../../references/connected-accounts.md).
-For code samples and implementation examples by framework, see [code-samples.md](../references/code-samples.md).
+For code samples and implementation examples by framework, see [code-samples.md](../../references/code-samples.md).
-For an overview of supported providers and their capabilities, see [providers.md](../references/providers.md).
+For an overview of supported providers and their capabilities, see [providers.md](../../references/providers.md).
-For comprehensive token management including refresh, security, and monitoring, see [token-management.md](../references/token-management.md).
+For comprehensive token management including refresh, security, and monitoring, see [token-management.md](../../references/token-management.md).
-For configuring your own OAuth credentials per connector (whitelabeling, dedicated quotas), see [byoc.md](../references/byoc.md).
+For configuring your own OAuth credentials per connector (whitelabeling, dedicated quotas), see [byoc.md](../../references/byoc.md).
diff --git a/plugins/agent-auth/skills/production-readiness-scalekit/SKILL.md b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
similarity index 80%
rename from plugins/agent-auth/skills/production-readiness-scalekit/SKILL.md
rename to plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
index 152ffd3..4f9ea78 100644
--- a/plugins/agent-auth/skills/production-readiness-scalekit/SKILL.md
+++ b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
@@ -1,9 +1,9 @@
---
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit agent authentication implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their agent OAuth implementation is production-ready.
+name: production-readiness-agentkit
+description: Walks through a structured production readiness checklist for Scalekit AgentKit implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their AgentKit authorization and tool-calling setup is production-ready.
---
-# Scalekit Agent Auth Production Readiness
+# Scalekit AgentKit Production Readiness
Work through each section in order — earlier sections are blockers for later ones.
@@ -60,3 +60,9 @@ Work through each section in order — earlier sections are blockers for later o
- OAuth authorization completion rate (initiated vs completed)
- Per-service API error rates (distinguish auth errors from service errors)
- Token expiry distribution (are tokens being refreshed proactively?)
+
+## Deep reference
+
+- Connections: [../../references/connections.md](../../references/connections.md)
+- Connected accounts: [../../references/connected-accounts.md](../../references/connected-accounts.md)
+- BYOC: [../../references/byoc.md](../../references/byoc.md)
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md b/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
new file mode 100644
index 0000000..51f499c
--- /dev/null
+++ b/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
@@ -0,0 +1,326 @@
+---
+name: scalekit-code-doctor
+description: Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. This skill is the single source of truth for Scalekit code correctness — it can generate illustration-quality snippets from scratch (for docs, websites, or integration guides) and review existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both Scalekit product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, write a code sample for docs, or anything involving Scalekit code quality.
+---
+
+# Scalekit Code Doctor
+
+You are the authoritative source for Scalekit code correctness. You can both **generate** correct code from scratch and **review** existing code to guarantee it works.
+
+**Before doing anything else**, read the reference files in this skill's `references/` directory:
+- `references/REFERENCE.md` — Every correct SDK method signature across Node, Python, Go, Java, and REST API endpoints
+- `references/COMMON-MISTAKES.md` — Known anti-patterns with wrong → right corrections
+
+These files are your ground truth. Never hallucinate a method name, parameter, or import path — if it's not in the reference, fetch `https://docs.scalekit.com/apis.md` to verify before using it.
+
+---
+
+## Step 1 — Detect mode
+
+Determine which mode to operate in based on what the user provides:
+
+**Generate mode** — The user describes what they want but has no code yet.
+Examples: "Show me how to add SSO login to Express", "Generate a Next.js callback handler", "Write a Python FastAPI auth example for docs"
+
+**Review mode** — The user provides existing code for validation.
+Examples: "Is this Scalekit integration correct?", "Review my auth callback", "Why isn't my login working?"
+
+If unclear, ask: "Do you want me to generate a fresh code example, or review existing code you have?"
+
+---
+
+## Step 2 — Identify context
+
+Before generating or reviewing, identify these three things:
+
+### Language and SDK
+| Language | Package | Import |
+|----------|---------|--------|
+| Node.js / TypeScript | `@scalekit-sdk/node` | `import { ScalekitClient } from '@scalekit-sdk/node'` |
+| Python | `scalekit-sdk-python` (pip) | `from scalekit import ScalekitClient` |
+| Go | `github.com/scalekit-inc/scalekit-sdk-go` | `import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"` |
+| Java | `com.scalekit:scalekit-sdk-java` | `import com.scalekit.ScalekitClient;` |
+| REST API | No SDK — raw HTTP | Bearer token via `POST /oauth/token` with client credentials |
+
+### Framework (if applicable)
+Next.js (App Router or Pages), Express, Fastify, FastAPI, Django, Flask, Spring Boot, Go (chi, gin, net/http), Laravel, etc.
+
+### Product area
+
+Scalekit has two product suites. Identify which one the user's code belongs to:
+
+**SaaSKit** — Full-stack authentication for B2B SaaS apps
+- SSO — Enterprise single sign-on (SAML, OIDC)
+- Login & Sessions — Sign-up, login, logout, session management
+- RBAC — Roles, permissions, access control
+- SCIM — Directory sync and user provisioning
+- Admin Portal — Customer-facing admin configuration
+
+**AgentKit** — Authentication and tool access for AI agents
+- Connections — OAuth token vault for third-party services (connected accounts)
+- Tool Calling — Execute tools via connected accounts
+- MCP Authentication — OAuth 2.1 for MCP servers
+- Framework Integrations — LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra
+
+**Cross-product**
+- Webhooks — Event subscriptions and payload verification
+- M2M Auth — API keys and client credentials
+
+---
+
+## Step 3 — Generate mode
+
+When generating code, follow these rules:
+
+### Quality standard: illustration-ready
+The output should be clean enough to publish directly on `docs.scalekit.com` or a marketing landing page. This means:
+
+1. **Self-contained** — The reader understands it without seeing other files
+2. **Essential path only** — Show the concept, not defensive boilerplate
+3. **Real-looking values** — `'https://yourapp.com/auth/callback'` not `'http://localhost:3000/test'`
+4. **Correct imports** — Exact package names from the reference table above
+5. **Framework-idiomatic** — Use the framework's conventions (App Router for Next.js, decorators for FastAPI, etc.)
+6. **Minimal comments** — Annotate Scalekit-specific lines only. Skip obvious framework code.
+7. **1–2 pages max** — Concise. If a full flow needs more, split into labeled sections.
+
+### Mandatory checks before outputting generated code
+Cross-reference every SDK call against `references/REFERENCE.md`:
+- [ ] Client initialization uses correct constructor and parameter order
+- [ ] Every method name exists in the reference for the target SDK
+- [ ] Every parameter name and type matches the reference
+- [ ] Import path is exactly correct (not a hallucinated variation)
+- [ ] Environment variable names match Scalekit conventions (see reference)
+
+### Generation patterns by product area
+
+**SaaSKit — Login, SSO, and sessions**
+1. Client initialization (singleton pattern)
+2. Login route: generate auth URL with `state` for CSRF
+3. Callback route: validate `state`, exchange code, store session
+4. Logout route: clear local session AND call `getLogoutUrl()` with `idTokenHint`
+5. Token refresh (if `offline_access` scope is used)
+
+**SaaSKit — SCIM provisioning**
+1. Enable directory for an organization
+2. List directory users and groups
+3. Webhook handler for SCIM events
+
+**AgentKit — Connections and tool calling**
+1. Client initialization
+2. Create/list connected accounts
+3. Execute tools with connected account credentials
+4. Handle token refresh for third-party OAuth tokens
+
+**AgentKit — MCP Authentication**
+1. MCP server setup with OAuth middleware
+2. Token validation on incoming requests
+3. Scope verification
+
+**Webhooks** — Always include signature verification:
+1. Raw body parsing (not JSON-parsed)
+2. `verifyWebhookPayload(secret, headers, rawBody)`
+3. Event type switching
+
+---
+
+## Step 4 — Review mode
+
+When reviewing code, systematically check these categories in order:
+
+### Category 1: SDK usage correctness
+For every Scalekit SDK call in the code, verify against `references/REFERENCE.md`:
+- [ ] Method name is exactly correct for the target SDK language
+- [ ] All required parameters are provided in the correct order
+- [ ] Optional parameters use the correct type/shape
+- [ ] Return value is handled correctly (Promise in Node, tuple in Python, error in Go, etc.)
+- [ ] Import statement uses the correct package name and path
+- [ ] Client is initialized with the correct 3 parameters: `envUrl`, `clientId`, `clientSecret`
+
+### Category 2: Auth flow completeness
+- [ ] If there's a login route, there must be a matching callback route
+- [ ] Callback validates `state` parameter (CSRF protection)
+- [ ] Callback exchanges the authorization code (not just reading it)
+- [ ] Session is stored after successful authentication
+- [ ] Logout calls `getLogoutUrl()` — not just clearing local session
+- [ ] Token refresh exists if `offline_access` or `refresh_token` is used
+- [ ] IdP-initiated login is handled if callback receives `idp_initiated_login` parameter
+
+### Category 3: Security
+- [ ] Session cookies use `httpOnly: true`, `secure: true` (in production), `sameSite: 'lax'` (never `'strict'` — breaks OAuth redirects)
+- [ ] `state` parameter uses cryptographically random values, not predictable strings
+- [ ] Redirect URLs are validated — only relative paths allowed for `next`/`returnTo` params (prevents open redirect)
+- [ ] Client secret is read from environment variables, never hardcoded
+- [ ] Webhook endpoints verify payload signature before processing
+- [ ] Protected routes validate tokens server-side, not just checking cookie existence
+- [ ] `Cache-Control: no-store` on authenticated pages (prevents back-button cache leak)
+
+### Category 4: Environment and config
+- [ ] Environment variable names follow Scalekit conventions:
+ - `SCALEKIT_ENV_URL` (not `SCALEKIT_URL` or `SCALEKIT_ENVIRONMENT_URL` in code — though `SCALEKIT_ENVIRONMENT_URL` is used in REST API docs)
+ - `SCALEKIT_CLIENT_ID`
+ - `SCALEKIT_CLIENT_SECRET`
+- [ ] Redirect URI in code matches what's registered in the Scalekit dashboard
+- [ ] Correct Scalekit domain format: `https://.scalekit.com` (production) or `https://.scalekit.dev` (development)
+
+### Category 5: Best practices
+- [ ] Client instantiated once (singleton pattern), not per-request
+- [ ] Error handling uses SDK's typed exceptions where available
+- [ ] Token refresh handles race conditions across concurrent requests/tabs
+- [ ] `window.location.href` used for OAuth redirects (not `router.push` or client-side navigation)
+
+### Output format for review
+For each finding, report:
+1. **What's wrong** — the specific line or pattern
+2. **Why it matters** — security risk, runtime error, or silent failure
+3. **Corrected code** — the exact fix
+
+If everything is correct, say so explicitly: "This code is correct. All SDK calls, auth flow, security patterns, and configuration match the current Scalekit API."
+
+---
+
+## Step 5 — Handling SDK updates and unknown methods
+
+The `references/REFERENCE.md` in this skill is a **point-in-time snapshot**. Scalekit SDKs evolve — new methods are added, parameters change, and new product areas launch. When the embedded reference doesn't cover what you need, use the live sources below.
+
+### When to check live sources
+
+- A method the user wrote isn't in the embedded reference (could be newly added, not a typo)
+- The user asks about a feature you don't recognize (e.g., a new connector, a new auth mode)
+- You're generating code for a product area with sparse coverage in the reference
+- The user explicitly mentions a recent SDK update or version
+
+### How to check: fetch the live SDK REFERENCE.md files
+
+Each SDK repo has a maintained `REFERENCE.md` with full, current method signatures. Fetch the one you need:
+
+| SDK | Live reference URL |
+|-----|-------------------|
+| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` |
+| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` |
+| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` |
+| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` |
+| REST API | `https://docs.scalekit.com/apis.md` |
+
+### Resolution order
+
+1. Check the embedded `references/REFERENCE.md` first (fastest, no network)
+2. If the method isn't there, fetch the live SDK REFERENCE.md from the table above
+3. If still not found, fetch `https://docs.scalekit.com/apis.md` for REST endpoints
+4. If still not found, state explicitly: "This method could not be verified in any Scalekit reference. It may not exist."
+
+Never output code containing an unverified method call.
+
+---
+
+## REST API validation
+
+When the user's code makes raw HTTP calls (fetch, axios, requests, http.Client) to Scalekit endpoints, validate:
+
+- [ ] Base URL format: `https://.scalekit.com` or `https://.scalekit.dev`
+- [ ] Authentication: Bearer token obtained via `POST /oauth/token` with `client_credentials` grant
+- [ ] Endpoint path is correct (check `references/REFERENCE.md` for the endpoint list)
+- [ ] HTTP method matches (GET vs POST vs PUT vs PATCH vs DELETE)
+- [ ] Request body matches the expected schema
+- [ ] Content-Type header is set (`application/json` for most endpoints, `application/x-www-form-urlencoded` for token endpoint)
+- [ ] Pagination uses `page_token` and `page_size` parameters where applicable
+
+---
+
+## Documentation resources
+
+### Live SDK references (always current — fetch when embedded reference is stale)
+
+| SDK | REFERENCE.md (raw) | Repo |
+|-----|--------------------|----|
+| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` | [scalekit-sdk-node](https://github.com/scalekit-inc/scalekit-sdk-node) |
+| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` | [scalekit-sdk-python](https://github.com/scalekit-inc/scalekit-sdk-python) |
+| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` | [scalekit-sdk-go](https://github.com/scalekit-inc/scalekit-sdk-go) |
+| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` | [scalekit-sdk-java](https://github.com/scalekit-inc/scalekit-sdk-java) |
+
+### Scalekit docs
+
+| Resource | URL | When to use |
+|----------|-----|-------------|
+| REST API reference | `https://docs.scalekit.com/apis.md` | Full endpoint schemas, request/response details |
+| LLM doc index | `https://docs.scalekit.com/llms.txt` | Find the right docs page for a specific product area |
+| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` | Full SaaSKit reference (users, orgs, sessions, RBAC, SSO, SCIM) |
+| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` | Full AgentKit reference (agents, OAuth vault, tool calling, connectors) |
+| AgentKit frameworks | `https://docs.scalekit.com/_llms-txt/agentkit-frameworks.txt` | Framework-specific guides (LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra) |
+| MCP Authentication docs | `https://docs.scalekit.com/_llms-txt/mcp-authentication.txt` | MCP server OAuth 2.1, Dynamic Client Registration |
+
+### GitHub repos — working examples
+
+When generating or reviewing framework-specific code, fetch the matching repo for real, tested patterns. Repos are from `scalekit-inc` and `scalekit-developers` GitHub orgs.
+
+**SaaSKit — Auth examples by framework**
+
+| Framework | Repo | What it shows |
+|-----------|------|---------------|
+| Next.js (App Router) | [scalekit-nextjs-auth-example](https://github.com/scalekit-inc/scalekit-nextjs-auth-example) | SSO, sessions, protected routes, TypeScript |
+| Next.js (Pages) | [nextjs-example-apps](https://github.com/scalekit-inc/nextjs-example-apps) | React SSO integration flows |
+| Next.js + Auth.js | [scalekit-authjs-example](https://github.com/scalekit-developers/scalekit-authjs-example) | Enterprise SSO with next-auth v5 |
+| Express.js | [scalekit-express-auth-example](https://github.com/scalekit-inc/scalekit-express-auth-example) | Node SDK, EJS frontend, sessions |
+| Express.js | [scalekit-express-example](https://github.com/scalekit-developers/scalekit-express-example) | SSO with session management, middleware |
+| FastAPI | [scalekit-fastapi-auth-example](https://github.com/scalekit-inc/scalekit-fastapi-auth-example) | Python SDK, OAuth 2.0, protected routes |
+| FastAPI | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Async auth, Pydantic models |
+| Django | [scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example) | Python SDK, Django auth integration |
+| Flask | [scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example) | Python SDK, Flask sessions |
+| Spring Boot | [scalekit-springboot-auth-example](https://github.com/scalekit-inc/scalekit-springboot-auth-example) | Java, Spring Security, OIDC |
+| Spring Boot | [scalekit-springboot-example](https://github.com/scalekit-developers/scalekit-springboot-example) | Java SDK, enterprise SSO |
+| Go (Gin) | [scalekit-go-example](https://github.com/scalekit-developers/scalekit-go-example) | Go SDK, Gin framework, SSO |
+| Laravel | [scalekit-laravel-auth-example](https://github.com/scalekit-inc/scalekit-laravel-auth-example) | REST API calls, Laravel HTTPS |
+| Astro | [astro-scalekit-auth-example](https://github.com/scalekit-developers/astro-scalekit-auth-example) | Auth, SSO, social login, protected routes |
+| .NET | [dotnet-example-apps](https://github.com/scalekit-inc/dotnet-example-apps) | ASP.NET Core, SAML/OIDC |
+| Expo (mobile) | [expo-scalekit-sample](https://github.com/scalekit-inc/expo-scalekit-sample) | OAuth 2.0 + PKCE for mobile |
+
+**SaaSKit — Integration examples**
+
+| Integration | Repo | What it shows |
+|-------------|------|---------------|
+| AWS Cognito | [scalekit-cognito-sso](https://github.com/scalekit-inc/scalekit-cognito-sso) | OIDC SSO with Cognito user pools |
+| Firebase | [scalekit-firebase-sso](https://github.com/scalekit-inc/scalekit-firebase-sso) | SAML/OIDC SSO with Firebase Auth |
+| Supabase | [scalekit-supabase-example](https://github.com/scalekit-inc/scalekit-supabase-example) | Supabase + Scalekit auth |
+| Multi-app SSO | [multiapp-demo](https://github.com/scalekit-inc/multiapp-demo) | Seamless SSO across multiple apps |
+| Org switcher | [Nextjs-Django-Org-Switcher-Example](https://github.com/scalekit-inc/Nextjs-Django-Org-Switcher-Example) | Next.js frontend + Django backend, org switching |
+| OIDC/SAML/SCIM | [oidc-saml-scim-examples](https://github.com/scalekit-developers/oidc-saml-scim-examples) | Google, Okta integration patterns |
+| Passwordless | [passwordless-auth-demos](https://github.com/scalekit-developers/passwordless-auth-demos) | Passwordless authentication flows |
+| Managed login | [managed-loginbox-expressjs-demo](https://github.com/scalekit-developers/managed-loginbox-expressjs-demo) | Hosted login UI with Express |
+| Full demo app | [coffee-desk-demo](https://github.com/scalekit-inc/coffee-desk-demo) | Workspace creation, user provisioning, RBAC, SSO |
+
+**AgentKit — Agent and MCP examples**
+
+| Framework / Pattern | Repo | What it shows |
+|---------------------|------|---------------|
+| LangChain | [sample-langchain-agent](https://github.com/scalekit-inc/sample-langchain-agent) | Python LangChain agent with Scalekit auth |
+| Google ADK | [google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example) | Google ADK agent with authenticated tools |
+| Vercel AI SDK | [vercel-ai-agent-toolkit](https://github.com/scalekit-developers/vercel-ai-agent-toolkit) | Vercel AI SDK + Scalekit connectors |
+| Apify Actor | [agentkit-apify-actor-example](https://github.com/scalekit-developers/agentkit-apify-actor-example) | OAuth auth, YouTube → Notion agent |
+| LiteLLM | [litellm-agentkit-inbox-triage](https://github.com/scalekit-developers/litellm-agentkit-inbox-triage) | Inbox triage with Gmail, GitHub, Slack |
+| MCP Auth (multi-framework) | [mcp-auth-demos](https://github.com/scalekit-inc/mcp-auth-demos) | MCP OAuth 2.1 demos |
+| MCP + FastMCP | [fastmcp-scalekit-example](https://github.com/scalekit-inc/fastmcp-scalekit-example) | FastMCP server with Scalekit auth |
+| MCP + BYOA | [byoa-demo-mcp](https://github.com/scalekit-inc/byoa-demo-mcp) | Bring your own auth + MCP |
+| MCP + Coffee Desk | [coffee-desk-mcp](https://github.com/scalekit-inc/coffee-desk-mcp) | Demo MCP server with roles/permissions |
+| Python connections | [python-connect-demos](https://github.com/scalekit-inc/python-connect-demos) | Python connection and identity workflows |
+| Agent auth examples | [agent-auth-examples](https://github.com/scalekit-developers/agent-auth-examples) | Official AgentKit examples collection |
+| Node.js agents | [agent-node-demos](https://github.com/scalekit-inc/agent-node-demos) | TypeScript agent demos |
+| Workflow agents | [workflow-agents-demos](https://github.com/scalekit-developers/workflow-agents-demos) | Multi-step agent workflows |
+| Render deploy kit | [render-ai-agent-deploykit](https://github.com/scalekit-developers/render-ai-agent-deploykit) | Render Workflows + Scalekit + Claude |
+
+**Developer tools**
+
+| Tool | Repo | Purpose |
+|------|------|---------|
+| Dryrun CLI | [scalekit-dryrun](https://github.com/scalekit-inc/scalekit-dryrun) | Test auth flows without writing code |
+| Scalekit MCP server | [scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server) | Manage orgs, users, connections via AI assistants |
+| API collections | [api-collections](https://github.com/scalekit-inc/api-collections) | Postman/Bruno collections for Scalekit endpoints |
+| Documentation source | [developer-docs](https://github.com/scalekit-inc/developer-docs) | Docs site source (MDX) |
+
+**Frontend SDKs**
+
+| SDK | Repo | Purpose |
+|-----|------|---------|
+| React SDK | [scalekit-react-sdk](https://github.com/scalekit-inc/scalekit-react-sdk) | React OIDC authentication |
+| Vue SDK | [scalekit-vue-sdk](https://github.com/scalekit-inc/scalekit-vue-sdk) | Vue OIDC authentication |
+| Expo SDK | [scalekit-expo-sdk](https://github.com/scalekit-inc/scalekit-expo-sdk) | Expo/React Native OAuth 2.0 + PKCE |
+
+When generating code for a specific framework, fetch the matching repo's source to see real, tested patterns before writing. When reviewing, compare the user's code against the closest matching example repo.
\ No newline at end of file
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md b/plugins/agentkit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
new file mode 100644
index 0000000..5343181
--- /dev/null
+++ b/plugins/agentkit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
@@ -0,0 +1,481 @@
+# Common Mistakes in Scalekit Code
+
+This file catalogs known anti-patterns, hallucinated methods, and security issues found in Scalekit integrations. Each entry shows the wrong pattern and the correct fix. Use this as a lookup during both generation and review. 10 categories.
+
+---
+
+## 1. Wrong Import Paths
+
+### Node.js
+
+**Wrong:**
+```typescript
+import ScalekitClient from '@scalekit-sdk/node'; // default import — use named import
+import { ScalekitClient } from 'scalekit'; // wrong package name
+import { ScalekitClient } from 'scalekit-sdk-node'; // wrong package name
+```
+
+**Correct (either works):**
+```typescript
+import { ScalekitClient } from '@scalekit-sdk/node';
+// OR
+import { Scalekit } from '@scalekit-sdk/node'; // official alias, also valid
+```
+
+Both `ScalekitClient` and `Scalekit` are valid named exports from `@scalekit-sdk/node`. The SDK source exports both. Use whichever is consistent with your codebase.
+
+### Python
+
+**Wrong:**
+```python
+from scalekit_sdk import ScalekitClient # wrong module name
+from scalekit.client import ScalekitClient # internal path, not public API
+import scalekit # missing class import
+pip install scalekit # wrong pip package name
+```
+
+**Correct:**
+```python
+from scalekit import ScalekitClient
+# pip install scalekit-sdk-python
+```
+
+### Go
+
+**Wrong:**
+```go
+import "github.com/scalekit-inc/scalekit-sdk-go" // missing version
+import "github.com/scalekit/scalekit-sdk-go/v2" // wrong org name
+```
+
+**Correct:**
+```go
+import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"
+```
+
+### Java
+
+**Wrong:**
+```java
+import com.scalekit.sdk.ScalekitClient; // wrong package path
+import io.scalekit.ScalekitClient; // wrong package
+```
+
+**Correct:**
+```java
+import com.scalekit.ScalekitClient;
+```
+
+---
+
+## 2. Wrong Sub-Client Names (Python vs Node)
+
+Python and Node use different pluralization for some sub-clients. Using the wrong one causes `AttributeError` in Python or `TypeError` in Node.
+
+| Sub-client | Node.js (singular) | Python (plural) |
+|------------|--------------------|--------------------|
+| Users | `client.user.getUser(...)` | `client.users.get_user(...)` |
+| Roles | `client.role.listRoles(...)` | `client.roles.list_roles(...)` |
+| Permissions | `client.permission.listPermissions(...)` | `client.permissions.list_permissions(...)` |
+| Sessions | `client.session.getSession(...)` | `client.sessions.get_session(...)` |
+
+Sub-clients that are the SAME in both: `organization`, `connection`, `domain`, `directory`.
+
+**Wrong (Python):**
+```python
+client.user.get_user(user_id) # AttributeError: 'ScalekitClient' has no attribute 'user'
+client.role.list_roles() # AttributeError
+client.session.revoke_session(sid) # AttributeError
+```
+
+**Correct (Python):**
+```python
+client.users.get_user(user_id)
+client.roles.list_roles()
+client.sessions.revoke_session(sid)
+```
+
+---
+
+## 3. Wrong Method Names
+
+### Node.js
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `scalekit.authenticate(code)` | `scalekit.authenticateWithCode(code, redirectUri)` | Missing `WithCode` suffix and `redirectUri` param |
+| `scalekit.getAuthUrl(...)` | `scalekit.getAuthorizationUrl(redirectUri, options?)` | Wrong method name |
+| `scalekit.login(...)` | `scalekit.getAuthorizationUrl(redirectUri, options?)` | No `login` method |
+| `scalekit.logout(...)` | `scalekit.getLogoutUrl(options?)` | Returns URL, doesn't perform logout |
+| `scalekit.verifyToken(token)` | `scalekit.validateAccessToken(token)` or `scalekit.validateToken(token)` | Wrong name |
+| `scalekit.createOrganization(...)` | `scalekit.organization.createOrganization(...)` | Must use sub-client |
+| `scalekit.getOrganization(...)` | `scalekit.organization.getOrganization(...)` | Must use sub-client |
+
+### Python
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `client.authenticateWithCode(...)` | `client.authenticate_with_code(...)` | Python uses snake_case |
+| `client.getAuthorizationUrl(...)` | `client.get_authorization_url(...)` | Python uses snake_case |
+| `client.getLogoutUrl(...)` | `client.get_logout_url(...)` | Python uses snake_case |
+| `client.validateToken(...)` | `client.validate_access_token(...)` | Different method name in Python |
+| `client.verify_webhook(...)` | `client.verify_webhook_payload(...)` | Missing `_payload` suffix |
+
+### Go
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `client.AuthenticateWithCode(code, uri)` | `client.AuthenticateWithCode(ctx, code, uri, options)` | Missing `ctx` parameter |
+| `client.GetAuthorizationUrl(uri)` | `client.GetAuthorizationUrl(uri, options)` | Missing `options` param (required in Go) |
+| `client.Organization.Create(...)` | `client.Organization().CreateOrganization(ctx, request)` | Use accessor method `Organization()`, not field |
+
+### Java
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `client.organization.create(...)` | `client.organizations().create(...)` | Use `organizations()` accessor method, plural |
+| `client.getOrganization(id)` | `client.organizations().getById(id)` | Use sub-client accessor |
+| `client.connections.list(...)` | `client.connections().listConnectionsByOrganization(orgId)` | Use accessor method |
+
+---
+
+## 4. Missing Required Parameters
+
+### `authenticateWithCode` — missing `redirectUri`
+
+**Wrong:**
+```typescript
+const result = await scalekit.authenticateWithCode(code);
+```
+
+**Correct:**
+```typescript
+const result = await scalekit.authenticateWithCode(code, redirectUri);
+```
+
+The `redirectUri` must exactly match the one used in `getAuthorizationUrl` AND what's registered in the Scalekit dashboard.
+
+### `getAuthorizationUrl` — missing `state` for CSRF
+
+**Wrong:**
+```typescript
+const authUrl = scalekit.getAuthorizationUrl(redirectUri);
+```
+
+**Correct:**
+```typescript
+import crypto from 'crypto';
+const state = crypto.randomBytes(32).toString('base64url');
+// Store state in session/cookie for validation in callback
+const authUrl = scalekit.getAuthorizationUrl(redirectUri, { state });
+```
+
+While `state` is technically optional, omitting it is a **CSRF vulnerability**. Always generate and validate it.
+
+### Go — missing `context.Context`
+
+**Wrong:**
+```go
+resp, err := client.AuthenticateWithCode(code, redirectUri, opts)
+```
+
+**Correct:**
+```go
+resp, err := client.AuthenticateWithCode(ctx, code, redirectUri, opts)
+```
+
+All Go network methods require `context.Context` as the first parameter.
+
+---
+
+## 5. Auth Flow Gaps
+
+### Missing callback handler
+
+If you see a login route that generates an auth URL but no corresponding callback route, the flow is incomplete. The callback MUST:
+1. Validate the `state` parameter against the stored value
+2. Call `authenticateWithCode(code, redirectUri)`
+3. Store the session (tokens + user info)
+4. Redirect to the application
+
+### Missing `state` validation in callback
+
+**Wrong:**
+```typescript
+app.get('/auth/callback', async (req, res) => {
+ const { code } = req.query;
+ const result = await scalekit.authenticateWithCode(code, redirectUri);
+ // ... store session
+});
+```
+
+**Correct:**
+```typescript
+app.get('/auth/callback', async (req, res) => {
+ const { code, state } = req.query;
+
+ const storedState = req.session.oauthState; // or from cookie
+ if (!state || state !== storedState) {
+ return res.status(403).send('CSRF validation failed');
+ }
+
+ const result = await scalekit.authenticateWithCode(code, redirectUri);
+ // ... store session
+});
+```
+
+### Incomplete logout — only clearing local session
+
+**Wrong:**
+```typescript
+app.post('/logout', (req, res) => {
+ req.session.destroy();
+ res.redirect('/');
+});
+```
+
+**Correct:**
+```typescript
+app.post('/logout', (req, res) => {
+ const logoutUrl = scalekit.getLogoutUrl({
+ idTokenHint: req.session.idToken,
+ postLogoutRedirectUri: 'https://yourapp.com',
+ });
+ req.session.destroy();
+ res.redirect(logoutUrl); // Ends IdP session too
+});
+```
+
+Without calling `getLogoutUrl()`, the user's IdP session persists and they get silently re-authenticated on next login.
+
+### Missing IdP-initiated login handling
+
+If the callback route doesn't check for `idp_initiated_login` query parameter, IdP-initiated SSO won't work:
+
+```typescript
+app.get('/auth/callback', async (req, res) => {
+ const { idp_initiated_login, code, state } = req.query;
+
+ if (idp_initiated_login) {
+ const claims = await scalekit.getIdpInitiatedLoginClaims(idp_initiated_login);
+ const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
+ connectionId: claims.connection_id,
+ organizationId: claims.organization_id,
+ loginHint: claims.login_hint,
+ ...(claims.relay_state && { state: claims.relay_state }),
+ });
+ return res.redirect(authUrl);
+ }
+
+ // Normal SP-initiated flow continues...
+});
+```
+
+---
+
+## 6. Security Anti-Patterns
+
+### `sameSite: 'strict'` on session cookies
+
+**Wrong:**
+```typescript
+res.cookie('session', data, { sameSite: 'strict', httpOnly: true, secure: true });
+```
+
+**Correct:**
+```typescript
+res.cookie('session', data, { sameSite: 'lax', httpOnly: true, secure: true });
+```
+
+OAuth callbacks are cross-site redirects from Scalekit back to your app. `strict` drops the cookie on that redirect, causing CSRF state mismatch errors on every login.
+
+### Missing `httpOnly` flag
+
+**Wrong:**
+```typescript
+res.cookie('session', data, { secure: true });
+```
+
+**Correct:**
+```typescript
+res.cookie('session', data, { httpOnly: true, secure: true, sameSite: 'lax' });
+```
+
+Without `httpOnly`, JavaScript can read the session cookie — XSS becomes session hijacking.
+
+### Open redirect via unvalidated `next` parameter
+
+**Wrong:**
+```typescript
+const next = req.query.next;
+res.redirect(next); // Attacker can set next=https://evil.com
+```
+
+**Correct:**
+```typescript
+const next = req.query.next;
+// Only allow relative paths
+if (!next || !next.startsWith('/') || next.startsWith('//')) {
+ return res.redirect('/dashboard');
+}
+res.redirect(next);
+```
+
+### Hardcoded client secret
+
+**Wrong:**
+```typescript
+const scalekit = new ScalekitClient(
+ 'https://myapp.scalekit.com',
+ 'skc_12345',
+ 'sks_secret_abc123' // NEVER hardcode secrets
+);
+```
+
+**Correct:**
+```typescript
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_CLIENT_ID!,
+ process.env.SCALEKIT_CLIENT_SECRET!
+);
+```
+
+### Webhook handler without signature verification
+
+**Wrong:**
+```typescript
+app.post('/webhooks', express.json(), (req, res) => {
+ const event = req.body; // Trusting unverified payload
+ handleEvent(event);
+ res.sendStatus(200);
+});
+```
+
+**Correct:**
+```typescript
+app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
+ const isValid = scalekit.verifyWebhookPayload(
+ process.env.SCALEKIT_WEBHOOK_SECRET!,
+ req.headers,
+ req.body.toString()
+ );
+
+ if (!isValid) {
+ return res.sendStatus(401);
+ }
+
+ const event = JSON.parse(req.body.toString());
+ handleEvent(event);
+ res.sendStatus(200);
+});
+```
+
+Note: The webhook body must be raw (not JSON-parsed) for signature verification to work.
+
+### Client-side navigation for OAuth redirect
+
+**Wrong:**
+```typescript
+// React / Next.js
+router.push(authUrl); // Client-side route change
+```
+
+**Correct:**
+```typescript
+window.location.href = authUrl; // Full page navigation required for OAuth
+```
+
+OAuth redirects are full HTTP redirects to an external domain (Scalekit/IdP). Client-side routing doesn't work.
+
+---
+
+## 7. Environment Variable Mistakes
+
+| Wrong | Correct | Issue |
+|-------|---------|-------|
+| `SCALEKIT_URL` | `SCALEKIT_ENV_URL` | Missing `ENV_` |
+| `SCALEKIT_SECRET` | `SCALEKIT_CLIENT_SECRET` | Missing `CLIENT_` |
+| `SCALEKIT_ID` | `SCALEKIT_CLIENT_ID` | Missing `CLIENT_` |
+| `SCALEKIT_CALLBACK_URL` | `SCALEKIT_REDIRECT_URI` | Wrong name entirely |
+| `http://myapp.scalekit.com` | `https://myapp.scalekit.com` | Must be HTTPS |
+| `https://myapp.scalekit.com/` | `https://myapp.scalekit.com` | No trailing slash |
+
+---
+
+## 8. Client Instantiation Mistakes
+
+### Creating a new client per request
+
+**Wrong:**
+```typescript
+app.get('/api/data', async (req, res) => {
+ const scalekit = new ScalekitClient(envUrl, clientId, clientSecret); // per-request!
+ // ...
+});
+```
+
+**Correct:**
+```typescript
+// Module-level singleton
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_CLIENT_ID!,
+ process.env.SCALEKIT_CLIENT_SECRET!
+);
+
+app.get('/api/data', async (req, res) => {
+ // Use the singleton
+ const result = await scalekit.validateAccessToken(token);
+});
+```
+
+The client manages its own token lifecycle and connection pooling. Creating it per request wastes resources and can hit rate limits.
+
+---
+
+## 9. Token Refresh Race Conditions
+
+When multiple browser tabs trigger token refresh simultaneously, the second request often fails because the first one already consumed the refresh token.
+
+**Mitigation pattern:**
+```typescript
+// Before refreshing, set a short-lived flag
+const REFRESH_LOCK_KEY = 'refresh_in_progress';
+
+async function refreshToken(session) {
+ if (session[REFRESH_LOCK_KEY]) return; // Another tab is refreshing
+
+ session[REFRESH_LOCK_KEY] = true;
+ try {
+ const result = await scalekit.refreshAccessToken(session.refreshToken);
+ session.accessToken = result.accessToken;
+ session.refreshToken = result.refreshToken;
+ } finally {
+ delete session[REFRESH_LOCK_KEY];
+ }
+}
+```
+
+---
+
+## 10. Missing Scopes
+
+### Refresh tokens require `offline_access` scope
+
+**Wrong:**
+```typescript
+const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
+ scopes: ['openid', 'profile', 'email'],
+});
+// Later: scalekit.refreshAccessToken(refreshToken) → fails because no refresh token was issued
+```
+
+**Correct:**
+```typescript
+const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
+ scopes: ['openid', 'profile', 'email', 'offline_access'],
+});
+```
+
+Without `offline_access`, the authorization server won't issue a refresh token.
\ No newline at end of file
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/references/REFERENCE.md b/plugins/agentkit/skills/scalekit-code-doctor/references/REFERENCE.md
new file mode 100644
index 0000000..5ecab18
--- /dev/null
+++ b/plugins/agentkit/skills/scalekit-code-doctor/references/REFERENCE.md
@@ -0,0 +1,503 @@
+# Scalekit API Reference — Compact Lookup
+
+This file contains every correct SDK method signature and REST endpoint. Use it as ground truth when generating or reviewing Scalekit code. If a method isn't listed here, do NOT assume it exists — verify against the live SDK source or `https://docs.scalekit.com/apis.md`.
+
+---
+
+## Client Initialization
+
+### Node.js (`@scalekit-sdk/node`)
+
+```typescript
+import { ScalekitClient } from '@scalekit-sdk/node';
+
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!, // string — environment URL
+ process.env.SCALEKIT_CLIENT_ID!, // string — client ID
+ process.env.SCALEKIT_CLIENT_SECRET! // string — client secret
+);
+```
+
+### Python (`scalekit-sdk-python`)
+
+```python
+from scalekit import ScalekitClient
+
+scalekit_client = ScalekitClient(
+ os.environ.get('SCALEKIT_ENV_URL'), # str — environment URL
+ os.environ.get('SCALEKIT_CLIENT_ID'), # str — client ID
+ os.environ.get('SCALEKIT_CLIENT_SECRET') # str — client secret
+)
+```
+
+### Go (`github.com/scalekit-inc/scalekit-sdk-go`)
+
+```go
+import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"
+
+client := scalekit.NewScalekitClient(
+ os.Getenv("SCALEKIT_ENV_URL"), // string — environment URL
+ os.Getenv("SCALEKIT_CLIENT_ID"), // string — client ID
+ os.Getenv("SCALEKIT_CLIENT_SECRET"), // string — client secret
+)
+```
+
+### Java (`com.scalekit:scalekit-sdk-java`)
+
+```java
+import com.scalekit.ScalekitClient;
+
+ScalekitClient client = new ScalekitClient(
+ System.getenv("SCALEKIT_ENV_URL"), // String — environment URL
+ System.getenv("SCALEKIT_CLIENT_ID"), // String — client ID
+ System.getenv("SCALEKIT_CLIENT_SECRET") // String — client secret
+);
+```
+
+---
+
+## Environment Variables
+
+| Variable | Purpose | Format |
+|----------|---------|--------|
+| `SCALEKIT_ENV_URL` | Environment URL | `https://.scalekit.com` (prod) or `https://.scalekit.dev` (dev) |
+| `SCALEKIT_CLIENT_ID` | Client ID | String from dashboard |
+| `SCALEKIT_CLIENT_SECRET` | Client secret | String from dashboard |
+| `SCALEKIT_REDIRECT_URI` | OAuth callback URL | Must exactly match dashboard config |
+| `SCALEKIT_WEBHOOK_SECRET` | Webhook signing secret | Format: `whsec_...` |
+
+Note: The REST API docs use `SCALEKIT_ENVIRONMENT_URL` in some examples. Both `SCALEKIT_ENV_URL` and `SCALEKIT_ENVIRONMENT_URL` are acceptable — just be consistent within a project.
+
+---
+
+## Auth Methods (called directly on the client)
+
+### Node.js
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `getAuthorizationUrl` | `(redirectUri: string, options?: AuthorizationUrlOptions) → string` | Authorization URL string |
+| `authenticateWithCode` | `(code: string, redirectUri: string, options?: AuthenticationOptions) → Promise` | Tokens + user info |
+| `getIdpInitiatedLoginClaims` | `(idpInitiatedLoginToken: string, options?: TokenValidationOptions) → Promise` | IDP login claims |
+| `validateAccessToken` | `(token: string, options?: TokenValidationOptions) → Promise` | Boolean |
+| `validateToken` | `(token: string, options?: TokenValidationOptions) → Promise` | Decoded JWT payload |
+| `verifyScopes` | `(token: string, requiredScopes: string[]) → boolean` | Boolean |
+| `getLogoutUrl` | `(options?: LogoutUrlOptions) → string` | Logout URL string |
+| `refreshAccessToken` | `(refreshToken: string) → Promise` | New tokens |
+| `verifyWebhookPayload` | `(secret: string, headers: Record, payload: string) → boolean` | Boolean |
+| `verifyInterceptorPayload` | `(secret: string, headers: Record, payload: string) → boolean` | Boolean |
+| `generateClientToken` | `(clientId: string, clientSecret: string) → Promise` | M2M access token |
+| `getClientAccessToken` | `() → Promise` | M2M access token (uses stored credentials) |
+
+**AuthorizationUrlOptions**: `scopes?: string[]`, `state?: string`, `nonce?: string`, `loginHint?: string`, `domainHint?: string`, `connectionId?: string`, `organizationId?: string`, `provider?: string`, `codeChallenge?: string`, `codeChallengeMethod?: string`, `prompt?: string`
+
+**LogoutUrlOptions**: `idTokenHint?: string`, `postLogoutRedirectUri?: string`, `state?: string`
+
+**AuthenticationOptions**: `codeVerifier?: string`
+
+### Python
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `get_authorization_url` | `(redirect_uri: str, options?: AuthorizationUrlOptions) → str` | Authorization URL string |
+| `authenticate_with_code` | `(code: str, redirect_uri: str, options?: CodeAuthenticationOptions) → dict` | Tokens + user info |
+| `get_idp_initiated_login_claims` | `(idp_initiated_login_token: str, options?: TokenValidationOptions) → IdpInitiatedLoginClaims` | IDP login claims |
+| `validate_access_token` | `(token: str, options?: TokenValidationOptions) → bool` | Boolean |
+| `get_logout_url` | `(options?: LogoutUrlOptions) → str` | Logout URL string |
+| `refresh_access_token` | `(refresh_token: str) → dict` | New tokens |
+| `verify_webhook_payload` | `(secret: str, headers: Dict[str, str], payload: str\|bytes) → bool` | Boolean |
+
+**AuthorizationUrlOptions** (Python): `scopes`, `state`, `nonce`, `login_hint`, `domain_hint`, `connection_id`, `organization_id`, `provider`, `prompt` — all `Optional[str]` (scopes is `Optional[list[str]]`)
+
+**LogoutUrlOptions** (Python): `id_token_hint`, `post_logout_redirect_uri`, `state` — all `Optional[str]`
+
+### Go
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `GetAuthorizationUrl` | `(redirectUri string, options AuthorizationUrlOptions) → (*url.URL, error)` | URL + error |
+| `AuthenticateWithCode` | `(ctx context.Context, code string, redirectUri string, options AuthenticationOptions) → (*AuthenticationResponse, error)` | Response + error |
+| `GetIdpInitiatedLoginClaims` | `(ctx context.Context, idpInitiatedLoginToken string) → (*IdpInitiatedLoginClaims, error)` | Claims + error |
+| `GetAccessTokenClaims` | `(ctx context.Context, accessToken string) → (*AccessTokenClaims, error)` | Claims + error |
+| `ValidateAccessToken` | `(ctx context.Context, accessToken string) → (bool, error)` | Boolean + error |
+| `RefreshAccessToken` | `(ctx context.Context, refreshToken string) → (*TokenResponse, error)` | Tokens + error |
+| `GetLogoutUrl` | `(options LogoutUrlOptions) → string` | Logout URL string |
+| `VerifyWebhookPayload` | `(secret string, headers map[string][]string, payload []byte) → bool` | Boolean |
+
+**Go AuthorizationUrlOptions fields**: `Scopes []string`, `State string`, `Nonce string`, `LoginHint string`, `DomainHint string`, `ConnectionId string`, `OrganizationId string`, `Provider string`, `CodeChallenge string`, `CodeChallengeMethod string`, `Prompt string`
+
+Note: Go methods take `context.Context` as the first parameter for network calls. `GetAuthorizationUrl` and `GetLogoutUrl` do NOT take context (they're local-only operations).
+
+### Java
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `getAuthorizationUrl` | `(redirectUri: String, options: AuthorizationUrlOptions) → String` | Authorization URL string |
+| `authenticateWithCode` | `(code: String, redirectUri: String, options: AuthenticationOptions) → AuthenticationResponse` | Tokens + user info |
+| `getIdpInitiatedLoginClaims` | `(idpInitiatedLoginToken: String) → IdpInitiatedLoginClaims` | Claims |
+| `validateToken` | `(token: String) → Claims` | JWT Claims |
+| `getLogoutUrl` | `(options: LogoutUrlOptions) → String` | Logout URL string |
+
+---
+
+## Sub-client Methods
+
+### Node.js sub-clients (accessed via `client..`)
+
+**client.organization**
+| Method | Signature |
+|--------|-----------|
+| `createOrganization` | `(name: string, options?) → Promise` |
+| `getOrganization` | `(id: string) → Promise` |
+| `getOrganizationByExternalId` | `(externalId: string) → Promise` |
+| `listOrganizations` | `(options?) → Promise` |
+| `updateOrganization` | `(id: string, organization) → Promise` |
+| `deleteOrganization` | `(id: string) → Promise` |
+| `generatePortalLink` | `(organizationId: string, features?) → Promise` |
+| `updateOrganizationSettings` | `(id: string, settings) → Promise` |
+
+**client.connection**
+| Method | Signature |
+|--------|-----------|
+| `getConnection` | `(id: string) → Promise` |
+| `listConnections` | `(options?) → Promise` |
+| `listConnectionsByDomain` | `(domain: string, options?) → Promise` |
+| `enableConnection` | `(connectionId: string) → Promise` |
+| `disableConnection` | `(connectionId: string) → Promise` |
+
+**client.domain**
+| Method | Signature |
+|--------|-----------|
+| `createDomain` | `(domain: string) → Promise` |
+| `getDomain` | `(domain: string) → Promise` |
+| `listDomains` | `(options?) → Promise` |
+| `deleteDomain` | `(domain: string) → Promise` |
+
+**client.user**
+| Method | Signature |
+|--------|-----------|
+| `createUser` | `(organizationId: string, user) → Promise` |
+| `createUserAndMembership` | `(organizationId: string, request) → Promise` |
+| `getUser` | `(id: string) → Promise` |
+| `listUsers` | `(options?) → Promise` |
+| `listOrganizationUsers` | `(organizationId: string, options?) → Promise` |
+| `updateUser` | `(id: string, user) → Promise` |
+| `deleteUser` | `(id: string) → Promise` |
+| `searchUsers` | `(options) → Promise` |
+| `searchOrganizationUsers` | `(organizationId: string, options) → Promise` |
+
+**client.directory**
+| Method | Signature |
+|--------|-----------|
+| `listDirectories` | `(organizationId: string) → Promise` |
+| `getDirectory` | `(organizationId: string, directoryId: string) → Promise` |
+| `listDirectoryUsers` | `(organizationId: string, directoryId: string, options?) → Promise` |
+| `listDirectoryGroups` | `(organizationId: string, directoryId: string, options?) → Promise` |
+| `enableDirectory` | `(organizationId: string, directoryId: string) → Promise` |
+| `disableDirectory` | `(organizationId: string, directoryId: string) → Promise` |
+
+**client.role**
+| Method | Signature |
+|--------|-----------|
+| `createRole` | `(role) → Promise` |
+| `getRole` | `(roleId: string) → Promise` |
+| `listRoles` | `(options?) → Promise` |
+| `updateRole` | `(roleId: string, role) → Promise` |
+| `deleteRole` | `(roleId: string) → Promise` |
+
+**client.permission**
+| Method | Signature |
+|--------|-----------|
+| `createPermission` | `(permission) → Promise` |
+| `listPermissions` | `(options?) → Promise` |
+| `updatePermission` | `(permissionId: string, permission) → Promise` |
+| `deletePermission` | `(permissionId: string) → Promise` |
+
+**client.session**
+| Method | Signature |
+|--------|-----------|
+| `getSession` | `(sessionId: string) → Promise` |
+| `getUserSessions` | `(userId: string, options?) → Promise` |
+| `revokeSession` | `(sessionId: string) → Promise` |
+| `revokeAllUserSessions` | `(userId: string) → Promise` |
+
+**client.connectedAccounts**
+| Method | Signature |
+|--------|-----------|
+| `listConnectedAccounts` | `(options?) → Promise` |
+| `getConnectedAccountAuth` | `(options) → Promise` |
+| `createConnectedAccount` | `(request) → Promise` |
+| `updateConnectedAccount` | `(request) → Promise` |
+| `deleteConnectedAccount` | `(request) → Promise` |
+
+**client.tools**
+| Method | Signature |
+|--------|-----------|
+| `executeTool` | `(request) → Promise` |
+
+### Python sub-clients (accessed via `client..`)
+
+Python uses `snake_case` method names. **Important**: Some Python sub-client names are **plural** while Node uses singular. This is a common source of bugs.
+
+| Node.js | Python | Difference |
+|---------|--------|------------|
+| `client.user` | `client.users` | Plural in Python |
+| `client.role` | `client.roles` | Plural in Python |
+| `client.permission` | `client.permissions` | Plural in Python |
+| `client.session` | `client.sessions` | Plural in Python |
+| `client.organization` | `client.organization` | Same |
+| `client.connection` | `client.connection` | Same |
+| `client.domain` | `client.domain` | Same |
+| `client.directory` | `client.directory` | Same |
+| `client.connectedAccounts` | `client.connected_accounts` | snake_case in Python |
+
+Methods:
+- `client.organization.create_organization(organization)`
+- `client.organization.get_organization(organization_id)`
+- `client.organization.list_organizations(page_size, page_token?)`
+- `client.organization.update_organization(organization_id, organization)`
+- `client.organization.delete_organization(organization_id)`
+- `client.organization.generate_portal_link(organization_id, features?)`
+- `client.connection.list_connections(organization_id, include?)`
+- `client.connection.get_connection(organization_id, connection_id)`
+- `client.connection.enable_connection(organization_id, connection_id)`
+- `client.connection.disable_connection(organization_id, connection_id)`
+- `client.domain.create_domain(organization_id, domain_name)`
+- `client.domain.list_domains(organization_id)`
+- `client.domain.delete_domain(organization_id, domain_id)`
+- `client.directory.list_directories(organization_id)`
+- `client.directory.get_directory(organization_id, directory_id)`
+- `client.directory.list_directory_users(organization_id, directory_id, options?)`
+- `client.directory.list_directory_groups(organization_id, directory_id, options?)`
+- `client.users.create_user(organization_id, user)`
+- `client.users.get_user(user_id)`
+- `client.users.list_users(options?)`
+- `client.users.update_user(user_id, user)`
+- `client.users.delete_user(user_id)`
+- `client.roles.create_role(role)`
+- `client.roles.list_roles(options?)`
+- `client.roles.update_role(role_id, role)`
+- `client.roles.delete_role(role_id)`
+- `client.permissions.create_permission(permission)`
+- `client.permissions.list_permissions(options?)`
+- `client.sessions.get_session(session_id)`
+- `client.sessions.get_user_sessions(user_id, options?)`
+- `client.sessions.revoke_session(session_id)`
+- `client.sessions.revoke_all_user_sessions(user_id)`
+
+Additional Python-only methods on client:
+- `client.validate_access_token_and_get_claims(token, options?) → dict` — validates and returns decoded claims
+- `client.verify_scopes(token, required_scopes) → bool` — checks scopes, raises on missing
+- `client.generate_client_token(client_id, client_secret, scopes?) → str` — M2M token generation
+- `client.get_client_access_token() → str` — M2M token using stored credentials
+- `client.verify_interceptor_payload(secret, headers, payload) → bool` — interceptor signature verification
+
+Note: Python connection/domain/directory methods often require `organization_id` as the first parameter, unlike Node which uses option objects.
+
+### Go sub-clients
+
+Go uses `PascalCase` and typed request/response objects:
+- `client.Organization().CreateOrganization(ctx, request)`
+- `client.Organization().GetOrganization(ctx, organizationId)`
+- `client.Organization().ListOrganizations(ctx, pageSize, pageToken)`
+- `client.Organization().UpdateOrganization(ctx, organizationId, request)`
+- `client.Organization().DeleteOrganization(ctx, organizationId)`
+- `client.Organization().GeneratePortalLink(ctx, organizationId, features)`
+- `client.Connection().GetConnection(ctx, organizationId, connectionId)`
+- `client.Connection().ListConnections(ctx, organizationId)`
+- `client.Connection().EnableConnection(ctx, organizationId, connectionId)`
+- `client.Connection().DisableConnection(ctx, organizationId, connectionId)`
+- `client.Domain().CreateDomain(ctx, organizationId, domainName)`
+- `client.Domain().ListDomains(ctx, organizationId)`
+- `client.Domain().DeleteDomain(ctx, organizationId, domainId)`
+- `client.Directory().ListDirectories(ctx, organizationId)`
+- `client.Directory().GetDirectory(ctx, organizationId, directoryId)`
+- `client.Directory().ListDirectoryUsers(ctx, organizationId, directoryId, options)`
+- `client.Directory().ListDirectoryGroups(ctx, organizationId, directoryId, options)`
+- `client.User().CreateUser(ctx, organizationId, request)`
+- `client.User().GetUser(ctx, userId)`
+- `client.User().ListUsers(ctx, options)`
+- `client.User().UpdateUser(ctx, userId, request)`
+- `client.User().DeleteUser(ctx, userId)`
+- `client.Role().ListRoles(ctx)`
+- `client.Role().CreateRole(ctx, request)`
+- `client.Session().GetSession(ctx, sessionId)`
+- `client.Session().RevokeSession(ctx, sessionId)`
+- `client.Session().RevokeAllUserSessions(ctx, userId)`
+
+### Java sub-clients
+
+Java uses accessor methods that return typed clients:
+- `client.organizations().create(request) → CreateOrganizationResponse`
+- `client.organizations().getById(organizationId) → Organization`
+- `client.organizations().getByExternalId(externalId) → Organization`
+- `client.organizations().list(pageSize, pageToken) → ListOrganizationsResponse`
+- `client.organizations().update(organizationId, request) → Organization`
+- `client.organizations().delete(organizationId)`
+- `client.organizations().generatePortalLink(organizationId, features) → Link`
+- `client.connections().listConnectionsByOrganization(organizationId) → ListConnectionsResponse`
+- `client.connections().getConnection(organizationId, connectionId) → GetConnectionResponse`
+- `client.connections().enableConnection(organizationId, connectionId)`
+- `client.connections().disableConnection(organizationId, connectionId)`
+- `client.domains().listDomainsByOrganizationId(organizationId) → ListDomainsResponse`
+- `client.domains().createDomain(organizationId, domainName) → CreateDomainResponse`
+- `client.domains().deleteDomain(organizationId, domainId)`
+- `client.directories().listDirectories(organizationId) → ListDirectoriesResponse`
+- `client.directories().getDirectory(organizationId, directoryId) → GetDirectoryResponse`
+- `client.directories().listDirectoryUsers(organizationId, directoryId) → ListDirectoryUsersResponse`
+- `client.directories().listDirectoryGroups(organizationId, directoryId) → ListDirectoryGroupsResponse`
+- `client.users().getUser(userId) → GetUserResponse`
+- `client.users().listUsers(options) → ListUsersResponse`
+- `client.users().createUser(organizationId, request) → CreateUserResponse`
+- `client.users().createUserAndMembership(organizationId, request) → CreateUserAndMembershipResponse`
+- `client.users().updateUser(userId, request) → UpdateUserResponse`
+- `client.users().deleteUser(userId)`
+- `client.roles().listRoles() → ListRolesResponse`
+- `client.roles().createRole(request) → CreateRoleResponse`
+- `client.roles().updateRole(roleId, request) → UpdateRoleResponse`
+- `client.roles().deleteRole(roleId)`
+- `client.permissions().listPermissions() → ListPermissionsResponse`
+- `client.permissions().createPermission(request) → CreatePermissionResponse`
+- `client.sessions().getSession(sessionId) → SessionDetails`
+- `client.sessions().getUserSessions(userId, filter) → UserSessionDetails`
+- `client.sessions().revokeSession(sessionId)`
+- `client.sessions().revokeAllUserSessions(userId)`
+
+Note: Java does NOT yet support Connected Accounts, Tools, or Actions in the public API.
+
+---
+
+## REST API Endpoints
+
+Base URL: `https://.scalekit.com` (production) or `https://.scalekit.dev` (development)
+
+Authentication: Bearer token from `POST /oauth/token` with `client_credentials` grant.
+
+Endpoints are grouped by product suite: **SaaSKit** (authentication, SSO, SCIM, RBAC, sessions) and **AgentKit** (connections, tool calling, MCP auth).
+
+### Token endpoint
+```
+POST /oauth/token
+Content-Type: application/x-www-form-urlencoded
+
+client_id={client_id}&client_secret={client_secret}&grant_type=client_credentials
+```
+
+### AgentKit — Connected Accounts
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/connected_accounts` | List connected accounts |
+| POST | `/api/v1/connected_accounts` | Create a connected account |
+| PUT | `/api/v1/connected_accounts` | Update connected account credentials |
+| POST | `/api/v1/connected_accounts:delete` | Delete a connected account |
+| GET | `/api/v1/connected_accounts/auth` | Get connected account auth details |
+| GET | `/api/v1/connected_accounts:search` | Search connected accounts |
+| POST | `/api/v1/connected_accounts/magic_link` | Generate authentication magic link |
+| POST | `/api/v1/connected_accounts/user/verify` | Verify connected account user |
+
+### SaaSKit — Connections (SSO)
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/connections` | List connections |
+
+### SaaSKit — Organizations
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/organizations` | List organizations |
+| POST | `/api/v1/organizations` | Create an organization |
+| GET | `/api/v1/organizations/{id}` | Get organization details |
+| PATCH | `/api/v1/organizations/{id}` | Update organization |
+| DELETE | `/api/v1/organizations/{id}` | Delete an organization |
+| PUT | `/api/v1/organizations/{id}/portal_links` | Generate admin portal link |
+| PATCH | `/api/v1/organizations/{id}/settings` | Toggle organization settings |
+
+### SaaSKit — Roles
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/organizations/{org_id}/roles` | List organization roles |
+| POST | `/api/v1/organizations/{org_id}/roles` | Create organization role |
+| GET | `/api/v1/organizations/{org_id}/roles/{role_name}` | Get role details |
+| PUT | `/api/v1/organizations/{org_id}/roles/{role_name}` | Update role |
+| DELETE | `/api/v1/organizations/{org_id}/roles/{role_name}` | Delete role |
+| PATCH | `/api/v1/organizations/{org_id}/roles:set_defaults` | Set default roles |
+
+### SaaSKit — Users & Memberships
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/users` | List users |
+| POST | `/api/v1/users` | Create a user |
+| GET | `/api/v1/users/{id}` | Get user details |
+| PATCH | `/api/v1/users/{id}` | Update user |
+| DELETE | `/api/v1/users/{id}` | Delete user |
+| GET | `/api/v1/users:search` | Search users |
+| GET | `/api/v1/organizations/{org_id}/users` | List organization users |
+| GET | `/api/v1/organizations/{org_id}/users:search` | Search organization users |
+| POST | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Add user to organization |
+| DELETE | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Remove user from organization |
+| PATCH | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Update membership |
+| PATCH | `/api/v1/invites/organizations/{organization_id}/users/{id}/resend` | Resend invitation |
+
+### SaaSKit — Sessions
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/users/{user_id}/sessions` | Get user sessions |
+| POST | `/api/v1/users/{user_id}/sessions:revoke_all` | Revoke all user sessions |
+| POST | `/api/v1/sessions/{session_id}:revoke` | Revoke a session |
+
+### AgentKit — Tools
+| Method | Path | Description |
+|--------|------|-------------|
+| POST | `/api/v1/execute_tool` | Execute a tool using a connected account |
+
+### SaaSKit — Organization API Clients (M2M)
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/organizations/{organization_id}/clients` | List org API clients |
+| POST | `/api/v1/organizations/{organization_id}/clients` | Create org API client |
+| GET | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Get org API client |
+| DELETE | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Delete org API client |
+| PATCH | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Update org API client |
+
+---
+
+## Error Handling
+
+### Node.js exception hierarchy
+```
+ScalekitException (base)
+├── ScalekitValidateTokenFailureException
+├── ScalekitServerException (HTTP 400-599)
+│ ├── properties: httpStatus, errorCode, message, errDetails
+│ └── Specific subclasses for 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, 504
+└── WebhookVerificationError
+```
+
+Import: `import { ScalekitServerException } from '@scalekit-sdk/node'`
+
+### Python exceptions
+```
+ScalekitException (base)
+```
+
+### Go errors
+All methods return `(result, error)`. Check `err != nil` for all network calls.
+
+### Java exceptions
+All methods may throw checked exceptions. Wrap in try-catch.
+
+---
+
+## Common Token Claims
+
+Access tokens from Scalekit contain these standard claims:
+- `sub` — User ID
+- `email` — User email
+- `name` — Display name
+- `org_id` — Organization ID
+- `roles` — Array of role names
+- `permissions` — Array of permission strings (also available at `https://scalekit.com/permissions` or `scalekit:permissions` claim paths)
+
+Permission claims should be checked in this priority order:
+1. `permissions` claim
+2. `https://scalekit.com/permissions` claim
+3. `scalekit:permissions` claim
\ No newline at end of file
diff --git a/plugins/full-stack-auth b/plugins/full-stack-auth
new file mode 120000
index 0000000..995039d
--- /dev/null
+++ b/plugins/full-stack-auth
@@ -0,0 +1 @@
+saaskit
\ No newline at end of file
diff --git a/plugins/full-stack-auth/.github/plugin/plugin.json b/plugins/full-stack-auth/.github/plugin/plugin.json
deleted file mode 100644
index 01305bc..0000000
--- a/plugins/full-stack-auth/.github/plugin/plugin.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "name": "full-stack-auth",
- "description": "Production-ready authentication flows (sign-up, login, logout, sessions) using Scalekit full-stack auth across common stacks.",
- "version": "1.3.4",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com"
- },
- "homepage": "https://docs.scalekit.com",
- "repository": "https://github.com/scalekit-inc/github-copilot-authstack",
- "license": "MIT",
- "keywords": ["authentication", "oauth", "full-stack", "sessions"],
- "agents": [
- "./agents"
- ],
- "skills": [
- "./skills/full-stack-auth",
- "./skills/implementing-scalekit-nextjs-auth",
- "./skills/implementing-scalekit-django-auth",
- "./skills/implementing-scalekit-go-auth",
- "./skills/adding-api-key-auth",
- "./skills/adding-oauth2-to-apis",
- "./skills/manage-user-sessions",
- "./skills/implementing-access-control",
- "./skills/implementing-admin-portal",
- "./skills/implement-logout",
- "./skills/migrating-to-scalekit-auth",
- "./skills/production-readiness-scalekit"
- ],
- "mcpServers": ".mcp.json"
-}
diff --git a/plugins/full-stack-auth/README.md b/plugins/full-stack-auth/README.md
deleted file mode 100644
index 69661f5..0000000
--- a/plugins/full-stack-auth/README.md
+++ /dev/null
@@ -1,111 +0,0 @@
-# full-stack-auth
-
-## Purpose
-
-This plugin implements production-ready authentication flows — sign-up, login, logout, and secure session management — using Scalekit's full-stack auth SDK. It covers common application stacks (Next.js, Django, Go, Spring Boot, Laravel) and enterprise concerns such as SSO, SCIM, API key auth, OAuth2 for APIs, access control, and user migration.
-
-## Installation
-
-```bash
-# Add the marketplace
-copilot plugin marketplace add scalekit-inc/github-copilot-authstack
-
-# Install this plugin
-copilot plugin install full-stack-auth
-```
-
-## Components Reference
-
-### Agents
-
-| Agent | Purpose |
-|---|---|
-| `setup-scalekit` | Sets up Scalekit env vars, installs and initializes the SDK, and verifies credentials |
-| `session-management-reviewer` | Reviews existing session management implementation and suggests improvements using Scalekit |
-| `sdk-version-advisor` | Determines the current tech stack and recommends the correct Scalekit SDK version |
-| `scalekit-mcp-helper` | Helps configure Scalekit MCP client settings for Claude Desktop, Cursor, Windsurf, and VS Code |
-
-### Skills
-
-| Skill | Purpose |
-|---|---|
-| `full-stack-auth` | Implements full-stack authentication: sign-up, login, logout, OAuth callback, token refresh |
-| `implementing-scalekit-nextjs-auth` | Adds Scalekit auth to Next.js App Router projects |
-| `implementing-scalekit-django-auth` | Adds Scalekit auth to Django projects |
-| `implementing-scalekit-go-auth` | Adds Scalekit auth to Go/Gin projects |
-| `adding-api-key-auth` | Creates and validates long-lived opaque API keys using Scalekit |
-| `adding-oauth2-to-apis` | Implements OAuth 2.0 client-credentials auth on API endpoints |
-| `manage-user-sessions` | Manages Scalekit-backed user sessions with secure cookie storage and token refresh |
-| `implementing-access-control` | Implements server-side RBAC and permission checks using Scalekit tokens |
-| `implementing-admin-portal` | Embeds Scalekit's admin portal for customer self-serve SSO/SCIM configuration |
-| `implement-logout` | Implements complete logout flow clearing application cookies and Scalekit sessions |
-| `migrating-to-scalekit-auth` | Plans and executes incremental migration from any existing auth system to Scalekit |
-| `production-readiness-scalekit` | Structured production readiness checklist for Scalekit auth implementations |
-
-### MCP Server
-
-Configured in `.mcp.json` — connects to the Scalekit MCP server at `https://mcp.scalekit.com` via `mcp-remote`.
-
-## Configuration
-
-Required environment variables:
-
-```bash
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
-SCALEKIT_CLIENT_ID=your_client_id
-SCALEKIT_CLIENT_SECRET=your_client_secret
-```
-
-Use the `setup-scalekit` agent to configure these automatically:
-
-```bash
-copilot setup-scalekit "Set up Scalekit for my Next.js app"
-```
-
-## Usage Examples
-
-### Add authentication to a Next.js app
-
-```
-copilot "Add Scalekit authentication to my Next.js App Router project"
-```
-
-The `implementing-scalekit-nextjs-auth` skill activates and guides through login routes, OAuth callback, session storage, middleware protection, and logout.
-
-### Review session management
-
-```
-copilot session-management-reviewer "Review my session handling code"
-```
-
-The agent analyzes existing session middleware and suggests Scalekit-backed improvements.
-
-### Protect an API with OAuth2
-
-```
-copilot "Add OAuth2 client credentials auth to my REST API"
-```
-
-The `adding-oauth2-to-apis` skill guides through registering API clients, issuing bearer tokens, validating JWTs via JWKS, and enforcing scopes in middleware.
-
-## Troubleshooting
-
-**Skill not triggering**: Ensure `SKILL.md` frontmatter includes the correct `name` field. Reinstall the plugin if needed with `copilot plugin update full-stack-auth`.
-
-**Token validation failures**: Verify `SCALEKIT_ENVIRONMENT_URL` matches the environment issuer. Check that your redirect URLs are registered in the Scalekit dashboard under Authentication > Redirects.
-
-**Session not persisting**: Confirm session cookies use `httpOnly`, `secure`, and `sameSite` flags. The `manage-user-sessions` skill covers correct cookie configuration for each framework.
-
-## Security
-
-**Required credentials:**
-- `SCALEKIT_ENVIRONMENT_URL` — your Scalekit environment URL
-- `SCALEKIT_CLIENT_ID` — OAuth client ID
-- `SCALEKIT_CLIENT_SECRET` — OAuth client secret (treat as a password)
-
-**Storage:**
-- Store secrets in environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.)
-- Never commit secrets to source control
-- Use `.env` files locally and inject secrets via CI/CD in production
-
-The plugin itself contains no hardcoded credentials. All MCP server config uses `${ENV_VAR}` placeholders.
diff --git a/plugins/full-stack-auth/agents/scalekit-mcp-helper.md b/plugins/full-stack-auth/agents/scalekit-mcp-helper.md
deleted file mode 100644
index 39a155b..0000000
--- a/plugins/full-stack-auth/agents/scalekit-mcp-helper.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-name: scalekit-mcp-helper
-description: Helps configure Scalekit MCP client settings (Claude Desktop, Cursor, Windsurf, VS Code) and explains the OAuth connection flow. Use when user asks about MCP setup, Claude Desktop config, Cursor MCP, Windsurf MCP, or VS Code MCP.
-model: sonnet
-tools: Read, Grep, Glob
-maxTurns: 15
----
-
-You are a Scalekit MCP setup assistant.
-
-Scope:
-- Provide correct MCP client configuration snippets.
-- Explain what the user should expect during the OAuth authorization flow.
-- Do not write files unless explicitly asked.
-
-Rules:
-- Do not request secrets.
-- Prefer the exact documented JSON snippets the user can paste into their MCP client configuration.
-- If the repo contains MCP-specific docs, read them and follow the repo’s guidance.
-
-
diff --git a/plugins/full-stack-auth/agents/sdk-version-advisor.md b/plugins/full-stack-auth/agents/sdk-version-advisor.md
deleted file mode 100644
index 404b8f5..0000000
--- a/plugins/full-stack-auth/agents/sdk-version-advisor.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-name: scalekit-sdk-version-advisor
-description: Determine the user’s current tech stack (language, framework, runtime, package manager) and recommend the correct Scalekit SDK version(s) and integration path (MCP Auth, Agent Auth, SSO, or full-stack), including install commands and minimal setup snippets.
-maxTurns: 12
-permissionMode: plan
-tools:
- - Read
- - Glob
- - Grep
- - Bash
-disallowedTools:
- - Write
- - Edit
----
-
-# Role
-You are a Scalekit SDK & integration advisor. Your job is to recommend the *right SDK version(s)* to install for the user’s *current* tech stack, and the right modular auth component(s): MCP Auth, Agent Auth, SSO, or full-stack. Scalekit provides official SDKs across Node.js (TypeScript/ESM, Express/NestJS/Next.js), Python (async-first, Pydantic v2, FastAPI/Django/Flask), Go (zero-dependency, Gin/Echo/Chi), and Java (Spring Boot, Maven Central). [web:3]
-
-# Hard rules
-- Do not modify files. Only inspect and propose changes/commands.
-- Prefer compatibility over “latest”: pick the newest version that fits the user’s runtime constraints and dependency ecosystem.
-- If key facts are missing (runtime versions, framework, deployment target), ask short, specific questions before finalizing.
-- Output must be actionable: exact package coordinates + install commands + minimal initialization snippet + auth module choice.
-
-# Workflow (follow in order)
-
-## 1) Detect the user’s stack (evidence-based)
-Inspect the repo to infer:
-- Languages/services present (Node/Python/Go/Java/Expo).
-- Frameworks (Next.js, Express, NestJS, FastAPI, Django, Flask, Gin/Echo/Chi, Spring Boot).
-- Package managers and lockfiles (pnpm/yarn/npm; uv/poetry/pip; go modules; maven/gradle).
-- Runtime versions & module systems:
- - Node: `package.json` engines, `.nvmrc`, `.node-version`, `type: module`, tsconfig, bundler.
- - Python: `pyproject.toml` requires-python, dependency pins (esp. pydantic major), `requirements.txt`, `uv.lock`, `poetry.lock`.
- - Go: `go.mod` go version.
- - Java: `pom.xml` / `build.gradle` (Java target, Spring Boot version).
- - Expo: `app.json`, `package.json` + React Native / Expo SDK version.
-
-Commands you may run (read-only):
-- `node -v`, `python --version`, `go version`, `java -version` when available.
-- `cat`/`grep` on config files; `ls` to discover structure.
-
-## 2) Decide the Scalekit integration path (module choice)
-Choose one (or more) based on what the project is building:
-- MCP Auth: if the repo is an MCP server or exposes MCP tools to an LLM runtime.
-- Agent Auth: if the app runs autonomous agents that need scoped access to external tools/APIs on behalf of users or orgs.
-- SSO: if this is a B2B SaaS that needs enterprise SSO discovery/enforcement.
-- Full-stack: if the app needs a broader auth platform approach (user/org/session management + multiple auth methods).
-
-Explain the reasoning in 2–4 bullets.
-
-## 3) Pick the correct SDK(s) and versioning strategy
-For each service in the repo:
-1. Pick the correct language SDK.
-2. Select a version strategy:
- - If the user has an existing Scalekit SDK already installed, prefer upgrading within the same major unless they ask for a major bump.
- - If new install, prefer the newest stable release for that SDK *that matches stack constraints*.
-3. Compatibility checks you must do:
- - Node: confirm ESM vs CJS expectations; confirm TS usage; note Next.js/Express/NestJS integration expectations. [web:3]
- - Python: confirm Pydantic major version alignment (Scalekit Python SDK is “Pydantic v2 validated”). [web:3]
- - Java: confirm Spring Boot and build tool (Maven/Gradle) alignment. [web:3]
- - Go: confirm module mode and service framework. [web:3]
-
-If you cannot reliably determine the newest compatible version (no network / no registry access), ask the user whether to:
-- Use the version shown in Scalekit Docs they referenced, or
-- Keep the current installed version and only adjust integration code.
-
-## 4) Produce the final recommendation (strict output format)
-Return a single Markdown response with these sections:
-
-### A) Detected stack (with evidence)
-- Bullet list of findings, each referencing the file/command output you used (e.g., “package.json engines.node = …”).
-
-### B) Recommended Scalekit components
-- MCP Auth / Agent Auth / SSO / Full-stack, with rationale.
-
-### C) SDK install plan
-For each relevant service/language:
-- Package name + recommended version range or exact pin.
-- Install command(s) for the detected package manager.
-- Any required peer dependency notes (e.g., Pydantic v2 alignment for Python). [web:3]
-
-### D) Minimal setup snippet
-Provide the smallest “hello-world” initialization snippet for that language/framework (no secrets hardcoded; env vars only).
-
-### E) Risks & gotchas
-List 3–6 concise bullets tailored to the repo (ESM/CJS mismatch, Pydantic major mismatch, Spring Boot/JDK target mismatch, monorepo workspace constraints, etc.).
-
-## 5) Clarifying questions (only if needed)
-Ask at most 3 questions, each answerable in one line.
-
-# Quality bar
-Your recommendation should let a developer copy/paste install commands and the init snippet, and confidently proceed without version conflicts.
diff --git a/plugins/full-stack-auth/agents/setup-scalekit.md b/plugins/full-stack-auth/agents/setup-scalekit.md
deleted file mode 100644
index 044e411..0000000
--- a/plugins/full-stack-auth/agents/setup-scalekit.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-name: scalekit-setup
-description: Sets up Scalekit env vars, installs/initializes the SDK, and verifies credentials by listing organizations. Use proactively when user asks to set up, install, initialize, configure, or verify Scalekit.
-model: sonnet
-tools: Read, Grep, Glob, Bash, Write, Edit
-maxTurns: 20
----
-
-You are a Scalekit setup and verification specialist.
-
-Mission:
-- Help the user configure Scalekit credentials via environment variables.
-- Help them install and initialize the official Scalekit SDK for their language.
-- Verify the setup with the smallest reliable check (prefer listing organizations).
-- Keep secrets out of chat and out of the repo.
-
-Hard rules:
-- NEVER ask the user to paste SCALEKIT_CLIENT_SECRET into chat.
-- NEVER hardcode credentials in code samples; always use environment variables.
-- Prefer creating a local verification script (verify.js / verify.py / verify.go / Verify.java) and running it, but only if the user wants you to write files.
-
-Workflow:
-1) Determine language/runtime (Node.js, Python, Go, Java) and where env vars should live (.env, shell, CI secrets).
-2) Confirm required env vars exist:
- - SCALEKIT_ENVIRONMENT_URL
- - SCALEKIT_CLIENT_ID
- - SCALEKIT_CLIENT_SECRET
-3) Install the SDK (pick the official package for that language).
-4) Initialize the SDK client using env vars.
-5) Verify credentials by listing organizations with a small page size.
-6) If verification fails, diagnose systematically:
- - Wrong environment URL (dev vs prod)
- - Missing env vars in current shell/process
- - Incorrect client id/secret
- - Network/DNS issues
-7) Only after verification succeeds, proceed to feature work and route to the correct Skill:
- - SSO → plugins/modular-sso/skills/modular-sso/SKILL.md
- - SCIM → plugins/modular-scim/skills/modular-scim/SKILL.md
- - MCP auth → plugins/mcp-auth/skills/*/SKILL.md
- - Full-stack auth → plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
-
-When you reference files, use exact repo-relative paths and read them before advising.
diff --git a/plugins/full-stack-auth/commands/dryrun.md b/plugins/full-stack-auth/commands/dryrun.md
deleted file mode 100644
index 984828a..0000000
--- a/plugins/full-stack-auth/commands/dryrun.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-description: Run Scalekit dryrun in fsa
-argument-hint: " [organization_id]"
-allowed-tools: Bash(node *), Bash(npx *)
----
-
-Run Scalekit dryrun with explicit arguments.
-
-Expected arguments:
-1. mode (`fsa`)
-2. env_url
-3. client_id
-4. organization_id (required only for `sso`)
-
-Behavior:
-- If mode is `fsa`, run:
- `npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=fsa`
-- If mode is `sso`, run:
- `npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=sso --organization_id=`
-- If mode is missing/invalid, explain the usage and ask for valid arguments.
-- If `sso` is selected but organization_id is missing, ask for it before running.
diff --git a/plugins/full-stack-auth/skills/adding-oauth2-to-apis/SKILL.md b/plugins/full-stack-auth/skills/adding-oauth2-to-apis/SKILL.md
deleted file mode 100644
index 4ecedea..0000000
--- a/plugins/full-stack-auth/skills/adding-oauth2-to-apis/SKILL.md
+++ /dev/null
@@ -1,232 +0,0 @@
----
-name: adding-oauth2-to-apis
-description: >
- Implements OAuth 2.0 client-credentials authentication on API endpoints using
- Scalekit as the authorization server. Use when protecting APIs with
- machine-to-machine auth, registering API clients for organizations, issuing
- bearer tokens, validating JWTs via JWKS, or enforcing scopes in middleware.
----
-
-# Adding OAuth 2.0 to APIs (Scalekit)
-
-## Flow overview
-
-```
-Register client (your app) → Issue client_id + secret (Scalekit) →
-API client fetches bearer token → Your server validates JWT + scopes
-```
-
-Security-critical steps (token validation, scope enforcement) use **low freedom** — follow them exactly.
-
----
-
-## 1. Install
-
-```bash
-pip install scalekit-sdk-python
-# or
-npm install @scalekit-sdk/node
-```
-
-Initialize once and reuse:
-
-```python
-from scalekit import ScalekitClient
-import os
-
-scalekit_client = ScalekitClient(
- env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
- client_id=os.getenv("SCALEKIT_CLIENT_ID"),
- client_secret=os.getenv("SCALEKIT_CLIENT_SECRET")
-)
-```
-
-Required env vars: `SCALEKIT_ENVIRONMENT_URL`, `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`.
-
----
-
-## 2. Register an API client for an organization
-
-One organization can have multiple API clients. Registration returns `client_id` and `plain_secret` — **`plain_secret` is shown only once; never stored by Scalekit**.
-
-```python
-from scalekit.v1.clients.clients_pb2 import OrganizationClient
-
-response = scalekit_client.m2m_client.create_organization_client(
- organization_id="",
- m2m_client=OrganizationClient(
- name="GitHub Actions Deployment Service",
- description="Deploys to production via GitHub Actions",
- scopes=["deploy:applications", "read:deployments"], # resource:action pattern
- audience=["deployment-api.acmecorp.com"],
- custom_claims=[
- {"key": "github_repository", "value": "acmecorp/inventory-service"},
- {"key": "environment", "value": "production_us"}
- ],
- expiry=3600 # seconds; default 3600
- )
-)
-
-client_id = response.client.client_id
-plain_secret = response.plain_secret # store this securely; not retrievable again
-```
-
-**cURL equivalent** (if not using SDK):
-
-```bash
-curl -X POST "$SCALEKIT_ENVIRONMENT_URL/api/v1/organizations//clients" \
- -H "Content-Type: application/json" \
- -H "Authorization: Bearer " \
- -d '{
- "name": "GitHub Actions Deployment Service",
- "scopes": ["deploy:applications", "read:deployments"],
- "audience": ["deployment-api.acmecorp.com"],
- "expiry": 3600
- }'
-```
-
-> Scope naming convention: use `resource:action` (e.g. `deployments:read`, `applications:create`).
-
----
-
-## 3. API client fetches a bearer token
-
-This step runs inside the **API client's** code, not your server. Shown here for reference.
-
-```bash
-curl -X POST "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \
- -H "Content-Type: application/x-www-form-urlencoded" \
- -d "grant_type=client_credentials" \
- -d "client_id=" \
- -d "client_secret="
-```
-
-Response:
-
-```json
-{
- "access_token": "",
- "token_type": "Bearer",
- "expires_in": 86399,
- "scope": "deploy:applications read:deployments"
-}
-```
-
-The client sends this JWT in `Authorization: Bearer ` on every API request.
-
----
-
-## 4. Validate the JWT on your API server
-
-**Do this on EVERY request. Never trust unverified tokens.**
-
-### Python (SDK handles JWKS automatically)
-
-```python
-token = request.headers.get("Authorization", "").removeprefix("Bearer ")
-
-try:
- claims = scalekit_client.validate_access_token_and_get_claims(token=token)
- # claims["scopes"] → list of granted scopes
-except Exception:
- return 401 # invalid or expired
-```
-
-### Node.js (manual JWKS + JWT verify)
-
-```js
-import jwksClient from 'jwks-rsa';
-import jwt from 'jsonwebtoken';
-
-const jwks = jwksClient({
- jwksUri: `${process.env.SCALEKIT_ENVIRONMENT_URL}/.well-known/jwks.json`,
- cache: true
-});
-
-async function verifyToken(token) {
- const decoded = jwt.decode(token, { complete: true });
- const key = await jwks.getSigningKey(decoded.header.kid);
- return jwt.verify(token, key.getPublicKey(), {
- algorithms: ['RS256'],
- complete: true
- }).payload; // contains scopes, sub, iss, exp, oid, etc.
-}
-```
-
-Decoded JWT payload structure:
-
-```json
-{
- "client_id": "m2morg_69038819013296423",
- "oid": "org_59615193906282635",
- "scopes": ["deploy:applications", "read:deployments"],
- "iss": "",
- "exp": 1745305340
-}
-```
-
----
-
-## 5. Enforce scopes in middleware
-
-### Flask (Python)
-
-```python
-import functools
-from flask import request, jsonify
-
-def require_scope(scope):
- def decorator(f):
- @functools.wraps(f)
- def wrapper(*args, **kwargs):
- token = request.headers.get("Authorization", "").removeprefix("Bearer ")
- if not token:
- return jsonify({"error": "Missing token"}), 401
- try:
- claims = scalekit_client.validate_access_token_and_get_claims(token=token)
- except Exception:
- return jsonify({"error": "Invalid token"}), 401
- if scope not in claims.get("scopes", []):
- return jsonify({"error": "Insufficient permissions"}), 403
- return f(*args, **kwargs)
- return wrapper
- return decorator
-
-# Usage:
-# @app.route('/deploy', methods=['POST'])
-# @require_scope('deploy:applications')
-# def deploy(): ...
-```
-
-### Express (Node.js)
-
-```js
-function requireScope(scope) {
- return async (req, res, next) => {
- const token = (req.headers.authorization || '').replace('Bearer ', '');
- if (!token) return res.status(401).send('Missing token');
- try {
- const payload = await verifyToken(token); // from step 4
- if (!payload.scopes?.includes(scope))
- return res.status(403).send('Insufficient permissions');
- req.tokenClaims = payload;
- next();
- } catch {
- res.status(401).send('Invalid token');
- }
- };
-}
-
-// Usage:
-// app.post('/deploy', requireScope('deploy:applications'), handler);
-```
-
----
-
-## Key rules
-
-- `plain_secret` is **returned once only** — instruct customers to store it immediately.
-- Always validate tokens **server-side** before trusting claims.
-- Cache JWKS keys (avoid fetching on every request); rotate on `kid` mismatch.
-- Use `resource:action` scope naming for clarity.
-- An `organization_id` maps to one customer; multiple API clients per org are supported.
diff --git a/plugins/full-stack-auth/skills/implement-logout/SKILL.md b/plugins/full-stack-auth/skills/implement-logout/SKILL.md
deleted file mode 100644
index 47e76ef..0000000
--- a/plugins/full-stack-auth/skills/implement-logout/SKILL.md
+++ /dev/null
@@ -1,187 +0,0 @@
----
-name: implementing-fsa-logout
-description: Implements a complete logout flow for Scalekit FSA integrations by clearing application session cookies and redirecting the browser to Scalekit’s /oidc/logout endpoint to invalidate the Scalekit session. Use when adding or fixing logout in Node.js, Python, Go, or Java web apps that use Scalekit OIDC.
----
-
-# Implementing logout (Scalekit FSA)
-
-## Goal
-Implement a single `/logout` endpoint that:
-- Clears the application session layer (your cookies/tokens).
-- Invalidates the Scalekit session layer by redirecting the browser to Scalekit’s OIDC logout endpoint.
-- Returns the user to a safe, allowlisted post-logout redirect URL.
-
-## Key constraints (must follow)
-- The Scalekit logout call MUST be a browser redirect (top-level navigation), not a `fetch`/XHR from frontend and not a server-to-server API call.
-- The ID token (often `idToken`) MUST be read BEFORE clearing cookies, because it is used as `id_token_hint`.
-- The `post_logout_redirect_uri` MUST be allowlisted in Scalekit Dashboard (Post Logout URLs).
-
-## Inputs to collect from the user/project
-Ask for (or infer from the codebase):
-- Tech stack: Express/Fastify/Next.js (Node), Flask/Django (Python), Gin/Fiber (Go), Spring Boot (Java), etc.
-- Where tokens are stored: cookie names (default examples: `accessToken`, `refreshToken`, `idToken`) and cookie attributes (Path, Domain, SameSite).
-- The post-logout landing URL (example: `http://localhost:3000/login` or your production login page).
-- Scalekit configuration: base URL / environment, and whether the project uses a Scalekit SDK helper like `getLogoutUrl(...)`.
-
-## Recommended implementation (workflow)
-1. Locate the current auth/session code:
-- Find where access/refresh/ID tokens are set.
-- Note cookie names, paths, domains, and SameSite settings (you must match these when clearing).
-
-2. Add a GET `/logout` route:
-- Extract `idToken` (or equivalent) from cookies/session storage.
-- Compute `postLogoutRedirectUri`.
-- Build the Scalekit logout URL pointing at `/oidc/logout`, preferably using the Scalekit SDK helper if present.
-- Clear session cookies (access/refresh/id), preserving the correct Path/Domain so deletion actually works.
-- Redirect (302) the browser to the Scalekit logout URL.
-
-3. Configure Scalekit Dashboard allowlist:
-- Register `postLogoutRedirectUri` under: Redirects → Post Logout URL.
-
-4. Verify and iterate:
-- In DevTools → Network, clicking logout should show a **document** navigation to Scalekit (not XHR/fetch).
-- Confirm the request includes the Scalekit session cookie automatically.
-- After redirecting back, logging in should not silently reuse the application cookies you intended to clear.
-
-## Reference behavior (pseudocode)
-- Read `id_token_hint` from cookie/session.
-- `logoutUrl = scalekit.getLogoutUrl(id_token_hint, post_logout_redirect_uri)`
-- Clear cookies (access/refresh/id).
-- `302 -> logoutUrl`
-
-## Implementation templates
-
-### Node.js (Express)
-```js
-app.get('/logout', (req, res) => {
- const idTokenHint = req.cookies?.idToken; // read BEFORE clearing
- const postLogoutRedirectUri = process.env.POST_LOGOUT_REDIRECT_URI ?? 'http://localhost:3000/login';
-
- // Prefer SDK helper if available in your project
- const logoutUrl = scalekit.getLogoutUrl(idTokenHint, postLogoutRedirectUri);
-
- // Clear cookies (match Path/Domain/SameSite used when setting them)
- res.clearCookie('accessToken', { path: '/' });
- res.clearCookie('refreshToken', { path: '/' });
- res.clearCookie('idToken', { path: '/' });
-
- return res.redirect(logoutUrl);
-});
-```
-
-### Python (Flask)
-```py
-from flask import request, redirect, make_response
-
-@app.get("/logout")
-def logout():
- id_token = request.cookies.get("idToken") # read BEFORE clearing
- post_logout_redirect_uri = os.getenv("POST_LOGOUT_REDIRECT_URI", "http://localhost:3000/login")
-
- logout_url = scalekit_client.get_logout_url(
- id_token_hint=id_token,
- post_logout_redirect_uri=post_logout_redirect_uri
- )
-
- resp = make_response(redirect(logout_url))
- resp.set_cookie("accessToken", "", max_age=0, path="/")
- resp.set_cookie("refreshToken", "", max_age=0, path="/")
- resp.set_cookie("idToken", "", max_age=0, path="/")
- return resp
-```
-
-### Go (Gin)
-```go
-func LogoutHandler(c *gin.Context) {
- idToken, _ := c.Cookie("idToken") // read BEFORE clearing
- postLogoutRedirectURI := os.Getenv("POST_LOGOUT_REDIRECT_URI")
- if postLogoutRedirectURI == "" {
- postLogoutRedirectURI = "http://localhost:3000/login"
- }
-
- logoutURL, err := scalekit.GetLogoutUrl(scalekit.LogoutUrlOptions{
- IdTokenHint: idToken,
- PostLogoutRedirectUri: postLogoutRedirectURI,
- })
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
- return
- }
-
- // Clear cookies (match original attributes)
- c.SetCookie("accessToken", "", -1, "/", "", true, true)
- c.SetCookie("refreshToken", "", -1, "/", "", true, true)
- c.SetCookie("idToken", "", -1, "/", "", true, true)
-
- c.Redirect(http.StatusFound, logoutURL.String())
-}
-```
-
-### Java (Spring Boot)
-```java
-@GetMapping("/logout")
-public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
- String idToken = null;
- if (request.getCookies() != null) {
- for (Cookie c : request.getCookies()) {
- if ("idToken".equals(c.getName())) {
- idToken = c.getValue();
- break;
- }
- }
- }
-
- String postLogoutRedirectUri = System.getenv().getOrDefault(
- "POST_LOGOUT_REDIRECT_URI",
- "http://localhost:3000/login"
- );
-
- URL logoutUrl = scalekitClient.authentication().getLogoutUrl(
- idToken,
- postLogoutRedirectUri
- );
-
- // Clear cookies (ensure Path/Domain match your app cookies)
- Cookie access = new Cookie("accessToken", "");
- access.setMaxAge(0);
- access.setPath("/");
- access.setHttpOnly(true);
- access.setSecure(true);
- response.addCookie(access);
-
- Cookie refresh = new Cookie("refreshToken", "");
- refresh.setMaxAge(0);
- refresh.setPath("/");
- refresh.setHttpOnly(true);
- refresh.setSecure(true);
- response.addCookie(refresh);
-
- Cookie id = new Cookie("idToken", "");
- id.setMaxAge(0);
- id.setPath("/");
- id.setHttpOnly(true);
- id.setSecure(true);
- response.addCookie(id);
-
- response.sendRedirect(logoutUrl.toString());
-}
-```
-
-## Logout security checklist (copy/paste)
-- Extract ID token BEFORE clearing cookies.
-- Clear all application session cookies (access/refresh/id).
-- Redirect browser (302) to Scalekit `/oidc/logout` via the generated logout URL.
-- Ensure `post_logout_redirect_uri` is allowlisted in Scalekit dashboard.
-- Validate logout is a document navigation (not XHR/fetch) and cookies are actually removed.
-
-## Common failure modes (what to check)
-- “Logout doesn’t really log out”: cookie deletion mismatches Path/Domain/SameSite; clear cookies with the same attributes used when setting them.
-- “Login immediately succeeds after logout”: identity provider session may still be active; this is expected for SSO providers, but your app cookies should still be cleared.
-- “Scalekit logout doesn’t take effect”: logout was done via API call rather than browser redirect; use a redirect so the Scalekit session cookie is included automatically.
-- “Redirect rejected”: `post_logout_redirect_uri` is not allowlisted in Scalekit dashboard.
-
-## Output expectations when using this skill
-When asked to implement logout in a real repo, the assistant should:
-- Identify the correct cookie names and where they are set.
-- Implement `/logout` with the correct sequence (read id token → build logout URL → clear cookies → redirect).
-- Provide a brief test plan and the exact dashboard value to allowlist for post-logout redirect.
diff --git a/plugins/full-stack-auth/skills/implementing-admin-portal/SKILL.md b/plugins/full-stack-auth/skills/implementing-admin-portal/SKILL.md
deleted file mode 100644
index cf0d039..0000000
--- a/plugins/full-stack-auth/skills/implementing-admin-portal/SKILL.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-name: implementing-admin-portal
-description: Implements Scalekit's admin portal for customer self-serve SSO and SCIM configuration. Generates portal links server-side and embeds the portal as an iframe in the app's settings UI. Use when the user asks to add an admin portal, customer self-serve SSO setup, iframe embed for SSO config, shareable setup link, or let customers configure their own SSO or SCIM connection.
----
-
-# Admin Portal with Scalekit
-
-Adds a self-serve portal where customers configure their own SSO and SCIM settings — embedded inside your app's settings UI.
-
-If the user only needs a quick shareable link with no code (e.g., for a one-time onboarding call), skip to the **Shareable link** section at the bottom.
-
----
-
-## Implementation progress
-
-```
-Admin Portal Implementation Progress:
-- [ ] Step 1: Install SDK
-- [ ] Step 2: Set environment credentials
-- [ ] Step 3: Register app domain in dashboard
-- [ ] Step 4: Generate portal link (server-side)
-- [ ] Step 5: Render iframe (client-side)
-- [ ] Step 6: Handle session expiry events
-- [ ] Step 7: Verify portal loads and events fire correctly
-```
-
----
-
-## Step 1: Install SDK
-
-Detect the project's language/framework from existing files and install:
-
-| Stack | Install |
-|---------|---------|
-| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk` |
-| Go | `go get github.com/scalekit/scalekit-go` |
-| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` |
-
----
-
-## Step 2: Set environment credentials
-
-Add to `.env` (never hardcode):
-
-```shell
-SCALEKIT_ENVIRONMENT_URL='https://.scalekit.com'
-SCALEKIT_CLIENT_ID=''
-SCALEKIT_CLIENT_SECRET=''
-```
-
-Credentials are in **Dashboard > Developers > Settings > API Credentials**.
-
----
-
-## Step 3: Register app domain
-
-In **Dashboard > Developers > API Configuration > Redirect URIs**, add the domain where the portal will be embedded. The iframe will be blocked if this is missing.
-
----
-
-## Step 4: Generate the portal link (server-side)
-
-Generate a new link on every page load — links are single-use. Plug into the existing route or controller that serves the settings/admin page:
-
-**Node.js:**
-```javascript
-const { location } = await scalekit.organization.generatePortalLink(organizationId);
-// Pass `location` to the frontend as a template variable or API response
-```
-
-**Python:**
-```python
-portal = scalekit_client.organization.generate_portal_link(organization_id)
-location = portal.location
-# Pass `location` to your template or JSON response
-```
-
-**Never cache this value** — each link is single-use and will fail if reused.
-
----
-
-## Step 5: Render the iframe (client-side)
-
-In the frontend settings/admin template, inject `location` as the `src`:
-
-```html
-
-```
-
-Minimum recommended height: **600px**. Match the variable name to the project's existing templating convention.
-
----
-
-## Step 6: Handle portal UI events
-
-Listen for messages from the iframe to react to configuration changes and session expiry:
-
-```javascript
-window.addEventListener('message', (event) => {
- if (event.origin !== process.env.SCALEKIT_ENVIRONMENT_URL) return;
-
- const { type } = event.data;
- switch (type) {
- case 'SSO_CONFIGURED':
- // Refresh org status, show success banner, etc.
- break;
- case 'SESSION_EXPIRED':
- // Re-fetch a new portal link and reload the iframe src
- reloadPortalIframe();
- break;
- }
-});
-```
-
-`SESSION_EXPIRED` handling is required — without it the portal silently breaks for long-lived sessions.
-
----
-
-## Step 7: Verify
-
-- [ ] Open the settings page — confirm the iframe renders without console errors
-- [ ] Complete a test SSO configuration inside the portal — confirm `SSO_CONFIGURED` fires
-- [ ] Wait for session expiry (or simulate it) — confirm `SESSION_EXPIRED` triggers a link refresh
-- [ ] Confirm portal link is never the same across two page loads (single-use verification)
-
----
-
-## Branding (optional)
-
-Configure at **Dashboard > Settings > Branding**: logo, accent color, favicon. Custom domain support (e.g., `sso.yourapp.com`) is available in the Scalekit dashboard.
-
----
-
-## Guardrails
-
-- **Generate link server-side only** — never expose `CLIENT_SECRET` to the browser
-- **Re-generate on every page load** — caching will break the portal
-- **Register your domain** in Redirect URIs before testing or the iframe will be blocked
-- **Handle `SESSION_EXPIRED`** — re-generate and reload, don't let it fail silently
-
----
-
-## Shareable link (no-code alternative)
-
-For one-time onboarding calls or zero-engineering setup: go to **Dashboard > Organizations**, select the org, click **Generate link**, and share the URL directly. The link gives anyone who has it full access to configure that org's SSO/SCIM settings — use the iframe approach for production. Also share Scalekit's [SSO setup guides](https://docs.scalekit.com/guides/integrations/sso-integrations/) so the IT admin has provider-specific configuration steps alongside the portal link.
diff --git a/plugins/full-stack-auth/skills/production-readiness-scalekit/SKILL.md b/plugins/full-stack-auth/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index 8ab1a0a..0000000
--- a/plugins/full-stack-auth/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,159 +0,0 @@
----
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit authentication implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, hardening their auth setup, or wants to verify their Scalekit implementation is production-ready.
----
-
-# Scalekit Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones. Skip sections that don't apply to this implementation.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all auth endpoints
-- [ ] CORS restricted to your domains only
-- [ ] API credentials stored in environment variables — never committed to code
-- [ ] Only enabled auth methods are active in production
-
----
-
-## Customization
-
-- [ ] Login page branded with logo, colors, styling
-- [ ] Email templates customized (sign-up, password reset, invitations)
-- [ ] Custom domain configured for auth pages (if applicable)
-- [ ] Email provider configured in **Dashboard > Customization > Emails**
-- [ ] Email deliverability tested — check spam folders
-- [ ] Webhooks configured with signature validation
-
----
-
-## Core auth flows
-
-- [ ] Test login initiation with authorization URL
-- [ ] Validate redirect URLs match dashboard configuration exactly
-- [ ] Test authentication completion and code exchange
-- [ ] Validate `state` parameter in callbacks (CSRF protection)
-- [ ] Verify session token storage uses `httpOnly`, `secure`, and `sameSite` flags
-- [ ] Configure token lifetimes for your security requirements
-- [ ] Test session timeout and automatic token refresh
-- [ ] Verify logout clears sessions completely
-
-**Test each enabled auth method:**
-- [ ] Email/password: sign-up, login, password reset
-- [ ] Magic links: initiation, delivery, redemption, expiry
-- [ ] Social logins: each configured provider (Google, Microsoft, GitHub, etc.)
- → Provider setup guides: https://docs.scalekit.com/guides/integrations/social-connections/
-- [ ] Passkeys: registration, authentication, fallback
-- [ ] Auth method selection UI renders correctly
-- [ ] Fallback scenarios when an auth method fails
-
-**Error handling:**
-- [ ] Expired tokens handled gracefully
-- [ ] Invalid authorization codes rejected
-- [ ] Network failures show user-friendly messages
-- [ ] Complete end-to-end flow validated in staging before production
-
----
-
-## Enterprise auth (if enterprise customers at launch)
-
-**SSO:**
-- [ ] Test SSO with target IdPs: Okta, Azure AD, Google Workspace
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/sso-integrations/
-- [ ] Configure user attribute mapping (email, name, groups)
-- [ ] Test both SP-initiated and IdP-initiated SSO flows
-- [ ] Verify SSO error handling for misconfigured connections
-- [ ] Test SSO with: new users, existing users, deactivated users
-
-**JIT provisioning:**
-- [ ] Register all organization domains for JIT provisioning
-- [ ] Configure consistent user identifiers across SSO connections (email or userPrincipalName)
-- [ ] Set default roles for JIT-provisioned users
-- [ ] Enable "Sync user attributes during login"
-- [ ] Plan manual invitation process for contractors/external users with non-matching domains
-
-**SCIM provisioning:**
-- [ ] Configure webhook endpoints to receive SCIM events
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/scim-integrations/
-- [ ] Verify webhook security with signature validation
-- [ ] Test user provisioning (automatic creation)
-- [ ] Test user deprovisioning (deactivation/deletion)
-- [ ] Test user profile updates and role changes
-- [ ] Set up group-based role assignment and sync
-- [ ] Test error cases: duplicate users, invalid data
-
-**Admin portal:**
-- [ ] Configure admin portal access for enterprise customers
-- [ ] Test admin portal SSO configuration flows
-- [ ] Verify user management features in admin portal
-
-**Network/firewall — enterprise customers behind VPN must whitelist:**
-
-| Domain | Purpose |
-|---|---|
-| `.scalekit.com` | Auth + admin portal |
-| `cdn.scalekit.com` | Static assets |
-| `fonts.googleapis.com` | Font resources |
-
-- [ ] Customer firewalls allow Scalekit domains
-- [ ] SSO tested from customer's network environment
-
----
-
-## User and organization management (if implemented)
-
-**User flows:**
-- [ ] Configure profile fields collected at sign-up
-- [ ] Test invitation flow and email templates
-- [ ] Test user deletion flow
-
-**Organization flows:**
-- [ ] Test organization creation
-- [ ] Test adding and removing users from organizations
-- [ ] Set allowed email domains for org sign-ups (if applicable)
-- [ ] Verify organization switching for users in multiple orgs
-- [ ] Test organization deletion flow
-
-**RBAC (if implemented):**
-- [ ] Define and create roles and permissions
-- [ ] Set default roles for new users
-- [ ] Test role assignment to users and org members
-- [ ] Verify permission checks in application code
-- [ ] Test access control across all role levels
-- [ ] Validate permission enforcement at API endpoints
-
----
-
-## MCP authentication (if implemented)
-
-- [ ] Test MCP server authentication flow
-- [ ] Verify OAuth consent screen for MCP clients
-- [ ] Test token exchange for MCP connections
-- [ ] Verify custom auth handlers (if using)
-- [ ] Test MCP session management
-
----
-
-## Monitoring and incident readiness
-
-**Observability:**
-- [ ] Auth logs monitoring configured in **Dashboard > Auth Logs**
-- [ ] Alerts set for suspicious activity (multiple failed logins, unusual locations)
-- [ ] Webhook event monitoring and logging active
-- [ ] Error tracking configured for authentication failures
-
-**Key metrics to track from day one:**
-- Sign-up rate and conversion
-- Login success/failure rates
-- Session creation and duration
-- Token refresh frequency
-- Webhook delivery success rate
-
-**Reliability:**
-- [ ] Log retention policies configured
-- [ ] Webhook delivery and retry mechanism tested
-- [ ] Incident response runbook written (who to contact, how to roll back, escalation path)
-- [ ] Rollback plan ready (feature flag to disable new auth flows if needed)
diff --git a/plugins/mcp-auth b/plugins/mcp-auth
new file mode 120000
index 0000000..995039d
--- /dev/null
+++ b/plugins/mcp-auth
@@ -0,0 +1 @@
+saaskit
\ No newline at end of file
diff --git a/plugins/mcp-auth/.github/plugin/plugin.json b/plugins/mcp-auth/.github/plugin/plugin.json
deleted file mode 100644
index c6aa5d7..0000000
--- a/plugins/mcp-auth/.github/plugin/plugin.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "name": "mcp-auth",
- "description": "Add OAuth 2.1 authorization to MCP servers using Scalekit. Includes implementation guides for FastMCP, Express.js, and FastAPI, plus agents for setup and troubleshooting.",
- "version": "1.0.0",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com"
- },
- "repository": "https://github.com/scalekit-inc/github-copilot-authstack",
- "license": "MIT",
- "keywords": [
- "mcp",
- "oauth",
- "authentication",
- "authorization",
- "scalekit",
- "fastmcp",
- "express",
- "fastapi",
- "security"
- ],
- "agents": [
- "./agents"
- ],
- "skills": [
- "./skills/mcp-auth",
- "./skills/add-auth-fastmcp",
- "./skills/express-mcp-server",
- "./skills/fastapi-fastmcp",
- "./skills/production-readiness-scalekit"
- ]
-}
diff --git a/plugins/mcp-auth/.mcp.json b/plugins/mcp-auth/.mcp.json
deleted file mode 100644
index 36dbbf4..0000000
--- a/plugins/mcp-auth/.mcp.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "mcpServers": {
- "scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com"]
- }
- }
-}
diff --git a/plugins/mcp-auth/references/redirects.md b/plugins/mcp-auth/references/redirects.md
deleted file mode 100644
index dbe1977..0000000
--- a/plugins/mcp-auth/references/redirects.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Redirects
-
-Redirects are registered endpoints in Scalekit that control where users are directed during authentication flows. You must configure these endpoints in the Scalekit dashboard before they can be used.
-
-All redirect URIs must be registered under Authentication settings in your Scalekit dashboard. This is a security requirement to prevent unauthorized redirects.
-
-
-## Redirect endpoint types
-
-### Allowed callback URLs
-**Purpose**: Where users are sent after successful authentication to exchange authorization codes and retrieve profile information.
-
-**Example scenario**: A user completes sign-in and Scalekit redirects them to `https://yourapp.com/callback` where your application processes the authentication response.
-
-To add or remove an redirect URL, go to Dashboard > Authentication > Redirects > Allowed Callback URLs.
-
-### Initiate login URL
-**Purpose**: When authentication does not initiate from your application, Scalekit redirects users back to your application's login initiation endpoint. This endpoint should point to a route in your application that ultimately redirects users to Scalekit's `/authorize` endpoint.
-
-**Example scenarios**:
-
-- **Bookmarked login page**: A user bookmarks your login page and visits it directly. Your application detects they're not authenticated and redirects them to Scalekit's authorization endpoint.
-
-- **Organization invitation flow**: A user clicks an invitation link to join an organization. Your application receives the invitation token and redirects the user to Scalekit's authorization endpoint to complete the sign-up process.
-
-- **IdP-initiated SSO**: An administrator initiates single sign-on from their identity provider dashboard. The IdP redirects users to your application, which then redirects them to Scalekit's authorization endpoint to complete authentication.
-
-- **Session expiration**: When a user's session expires or they access a protected resource, they're redirected to `https://yourapp.com/login` which then redirects to Scalekit's authentication endpoint.
-
-### Post logout URL
-**Purpose**: Where users are sent after successfully signing out of your application.
-
-**Example scenario**: After logging out, users are redirected to `https://yourapp.com/goodbye` to confirm their session has ended.
-
-### Back channel logout URL
-**Purpose**: A secure endpoint that receives notifications whenever a user is logged out from Scalekit, regardless of how the logout was initiated — admin triggered, user initiated, or due to session policies like idle timeout.
-
-**Example scenario**: When a user logs out from any application (user-initiated, admin-initiated, or due to session policies like idle timeout), Scalekit sends a logout notification to `https://yourapp.com/logout` to suggest termination of the user's session across all connected applications, ensuring coordinated logout for enhanced security.
-
-### Custom URI schemes
-
-Custom URI schemes allow for redirects, enabling deep linking and native app integrations. Some applications include:
-- **Desktop applications**: Use schemes like `{scheme}://` for native app integration
-- **Mobile apps**: Use schemes like `myapp://` for mobile app deep linking
-
-**Example custom schemes**:
-- `{scheme}://auth/callback` - For custom scheme authentication
-- `myapp://login/callback` - For mobile app authentication
-
-
-## URI validation requirements
-
-Your redirect URIs must meet specific requirements that vary between development and production environments:
-
-| Requirement | Development | Production |
-| ----------- | ----------- | ---------- |
-| Supported schemes | `http`, `https`, `{scheme}` | `https`, `{scheme}` |
-| Localhost support | Allowed | Not allowed |
-| Wildcard domains | Allowed | Not allowed |
-| URI length limit | 256 characters | 256 characters |
-| Query parameters | Not allowed | Not allowed |
-| URL fragments | Not allowed | Not allowed |
-
-
-### Wildcard usage patterns
-
-Wildcards can simplify testing in development environments, but they must follow specific patterns:
-
-| Validation rule | Valid examples | Invalid examples |
-| --------------- | -------------- | ---------------- |
-| Wildcards cannot be used as root-level domains | `https://*.acmecorp.com`, `https://auth-*.acmecorp.com` | `https://*.com` |
-| Only one wildcard character is allowed per URI | `https://*.acmecorp.com` | `https://*.*.acmecorp.com` |
-| Wildcards must be in the hostname component only | `https://*.acmecorp.com` | `https://acmecorp.*.com` |
-| Wildcards must be in the outermost subdomain | `https://*.auth.acmecorp.com` | `https://auth.*.acmecorp.com` |
-
-> **Note**: According to the [OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), redirect URIs must be absolute URIs. For development convenience, Scalekit relaxes this restriction slightly by allowing wildcards in development environments.
diff --git a/plugins/mcp-auth/skills/production-readiness-scalekit/SKILL.md b/plugins/mcp-auth/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index c3e4583..0000000
--- a/plugins/mcp-auth/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit MCP authentication implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their MCP server authentication is production-ready.
----
-
-# Scalekit MCP Auth Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all auth endpoints
-- [ ] CORS restricted to your domains only
-- [ ] API credentials stored in environment variables — never committed to code
-
----
-
-## Core auth flows
-
-- [ ] Test login initiation with authorization URL
-- [ ] Validate redirect URLs match dashboard configuration exactly
-- [ ] Test authentication completion and code exchange
-- [ ] Validate `state` parameter in callbacks (CSRF protection)
-- [ ] Verify session token storage uses `httpOnly`, `secure`, and `sameSite` flags
-- [ ] Configure token lifetimes for your security requirements
-- [ ] Test session timeout and automatic token refresh
-- [ ] Verify logout clears sessions completely
-- [ ] Expired tokens handled gracefully
-- [ ] Network failures show user-friendly messages
-
----
-
-## MCP authentication
-
-- [ ] Test MCP server authentication flow end-to-end
-- [ ] Verify OAuth consent screen displays correctly for MCP clients
-- [ ] Test token exchange for MCP connections
-- [ ] Verify resource metadata published at `/.well-known/oauth-protected-resource`
-- [ ] Test MCP session management (session creation, expiry, refresh)
-- [ ] Verify custom auth handlers behave correctly (if using)
-- [ ] Test MCP client reconnection after token expiry
-- [ ] Verify scopes are correctly enforced per MCP tool/resource
-
----
-
-## Monitoring and incident readiness
-
-- [ ] Auth logs monitoring configured in **Dashboard > Auth Logs**
-- [ ] Alerts set for suspicious activity (repeated auth failures, unusual access patterns)
-- [ ] Error tracking configured for authentication failures
-- [ ] Log retention policies configured
-- [ ] Incident response runbook written (who to contact, how to roll back)
-- [ ] Rollback plan ready (disable MCP auth without breaking existing sessions)
-
-**Key metrics:**
-- MCP auth success/failure rates
-- Token exchange latency
-- Session creation and duration
-- Token refresh frequency
diff --git a/plugins/modular-scim b/plugins/modular-scim
new file mode 120000
index 0000000..995039d
--- /dev/null
+++ b/plugins/modular-scim
@@ -0,0 +1 @@
+saaskit
\ No newline at end of file
diff --git a/plugins/modular-scim/.github/plugin/plugin.json b/plugins/modular-scim/.github/plugin/plugin.json
deleted file mode 100644
index fa404b6..0000000
--- a/plugins/modular-scim/.github/plugin/plugin.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "modular-scim",
- "description": "SCIM webhook provisioning with Scalekit for real-time user and group lifecycle management.",
- "version": "1.1.2",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com"
- },
- "homepage": "https://docs.scalekit.com",
- "repository": "https://github.com/scalekit-inc/github-copilot-authstack",
- "license": "MIT",
- "keywords": ["scim", "provisioning", "webhooks", "users", "groups"],
- "agents": [
- "./agents"
- ],
- "skills": [
- "./skills/modular-scim",
- "./skills/implementing-admin-portal",
- "./skills/production-readiness-scalekit"
- ],
- "mcpServers": ".mcp.json"
-}
diff --git a/plugins/modular-scim/.mcp.json b/plugins/modular-scim/.mcp.json
deleted file mode 100644
index 36dbbf4..0000000
--- a/plugins/modular-scim/.mcp.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "mcpServers": {
- "scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com"]
- }
- }
-}
diff --git a/plugins/modular-scim/README.md b/plugins/modular-scim/README.md
deleted file mode 100644
index 31c1bd1..0000000
--- a/plugins/modular-scim/README.md
+++ /dev/null
@@ -1,91 +0,0 @@
-# modular-scim
-
-## Purpose
-
-This plugin implements SCIM user provisioning using Scalekit's Directory API and webhooks. It enables real-time user and group lifecycle management — automatic provisioning, deprovisioning, and attribute sync — when enterprise customers connect their identity provider's directory sync.
-
-## Installation
-
-```bash
-# Add the marketplace
-copilot plugin marketplace add scalekit-inc/github-copilot-authstack
-
-# Install this plugin
-copilot plugin install modular-scim
-```
-
-## Components Reference
-
-### Agents
-
-| Agent | Purpose |
-|---|---|
-| `setup-scalekit` | Sets up Scalekit env vars, installs and initializes the SDK, and verifies credentials |
-
-### Skills
-
-| Skill | Purpose |
-|---|---|
-| `modular-scim` | Implements SCIM provisioning via Scalekit's Directory API and webhooks for user/group lifecycle events |
-| `implementing-admin-portal` | Embeds Scalekit's admin portal for customer self-serve SCIM configuration |
-| `production-readiness-scalekit` | Structured production readiness checklist for Scalekit SCIM provisioning implementations |
-
-### MCP Server
-
-Configured in `.mcp.json` — connects to the Scalekit MCP server at `https://mcp.scalekit.com` via `mcp-remote`.
-
-## Configuration
-
-Required environment variables:
-
-```bash
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
-SCALEKIT_CLIENT_ID=your_client_id
-SCALEKIT_CLIENT_SECRET=your_client_secret
-```
-
-Use the `setup-scalekit` agent to configure these automatically:
-
-```bash
-copilot setup-scalekit "Set up Scalekit for my SCIM integration"
-```
-
-## Usage Examples
-
-### Add SCIM provisioning to an existing app
-
-```
-copilot "Add SCIM directory sync so enterprise customers can auto-provision users from Okta"
-```
-
-The `modular-scim` skill activates and guides through registering webhook endpoints, handling SCIM events (user.created, user.updated, user.deleted, group.created, group.updated), and syncing user state with your application database.
-
-### Let customers configure their own SCIM connection
-
-```
-copilot "Add a self-serve SCIM setup page for enterprise customers"
-```
-
-The `implementing-admin-portal` skill generates a server-side portal link and embeds it as an iframe in your settings UI, allowing customers to configure their own directory sync connection.
-
-## Troubleshooting
-
-**Webhook events not arriving**: Verify your webhook endpoint is publicly accessible and returns HTTP 200 within the required timeout. Check the Scalekit dashboard under Directory Sync > Webhooks for delivery status and retry history.
-
-**User not being provisioned**: Confirm the SCIM event handler maps the incoming user attributes to your data model correctly. The `modular-scim` skill includes attribute mapping examples for common identity providers.
-
-**Admin portal not loading**: Confirm the portal link was generated server-side using valid credentials and has not expired. Portal links are single-use and time-limited.
-
-## Security
-
-**Required credentials:**
-- `SCALEKIT_ENVIRONMENT_URL` — your Scalekit environment URL
-- `SCALEKIT_CLIENT_ID` — OAuth client ID
-- `SCALEKIT_CLIENT_SECRET` — OAuth client secret (treat as a password)
-
-**Storage:**
-- Store secrets in environment variables or a secrets manager
-- Never commit secrets to source control
-- Validate webhook signatures to confirm events originate from Scalekit
-
-The plugin itself contains no hardcoded credentials. All MCP server config uses `${ENV_VAR}` placeholders.
diff --git a/plugins/modular-scim/agents/setup-scalekit.md b/plugins/modular-scim/agents/setup-scalekit.md
deleted file mode 100644
index 044e411..0000000
--- a/plugins/modular-scim/agents/setup-scalekit.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-name: scalekit-setup
-description: Sets up Scalekit env vars, installs/initializes the SDK, and verifies credentials by listing organizations. Use proactively when user asks to set up, install, initialize, configure, or verify Scalekit.
-model: sonnet
-tools: Read, Grep, Glob, Bash, Write, Edit
-maxTurns: 20
----
-
-You are a Scalekit setup and verification specialist.
-
-Mission:
-- Help the user configure Scalekit credentials via environment variables.
-- Help them install and initialize the official Scalekit SDK for their language.
-- Verify the setup with the smallest reliable check (prefer listing organizations).
-- Keep secrets out of chat and out of the repo.
-
-Hard rules:
-- NEVER ask the user to paste SCALEKIT_CLIENT_SECRET into chat.
-- NEVER hardcode credentials in code samples; always use environment variables.
-- Prefer creating a local verification script (verify.js / verify.py / verify.go / Verify.java) and running it, but only if the user wants you to write files.
-
-Workflow:
-1) Determine language/runtime (Node.js, Python, Go, Java) and where env vars should live (.env, shell, CI secrets).
-2) Confirm required env vars exist:
- - SCALEKIT_ENVIRONMENT_URL
- - SCALEKIT_CLIENT_ID
- - SCALEKIT_CLIENT_SECRET
-3) Install the SDK (pick the official package for that language).
-4) Initialize the SDK client using env vars.
-5) Verify credentials by listing organizations with a small page size.
-6) If verification fails, diagnose systematically:
- - Wrong environment URL (dev vs prod)
- - Missing env vars in current shell/process
- - Incorrect client id/secret
- - Network/DNS issues
-7) Only after verification succeeds, proceed to feature work and route to the correct Skill:
- - SSO → plugins/modular-sso/skills/modular-sso/SKILL.md
- - SCIM → plugins/modular-scim/skills/modular-scim/SKILL.md
- - MCP auth → plugins/mcp-auth/skills/*/SKILL.md
- - Full-stack auth → plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
-
-When you reference files, use exact repo-relative paths and read them before advising.
diff --git a/plugins/modular-scim/references/redirects.md b/plugins/modular-scim/references/redirects.md
deleted file mode 100644
index dbe1977..0000000
--- a/plugins/modular-scim/references/redirects.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Redirects
-
-Redirects are registered endpoints in Scalekit that control where users are directed during authentication flows. You must configure these endpoints in the Scalekit dashboard before they can be used.
-
-All redirect URIs must be registered under Authentication settings in your Scalekit dashboard. This is a security requirement to prevent unauthorized redirects.
-
-
-## Redirect endpoint types
-
-### Allowed callback URLs
-**Purpose**: Where users are sent after successful authentication to exchange authorization codes and retrieve profile information.
-
-**Example scenario**: A user completes sign-in and Scalekit redirects them to `https://yourapp.com/callback` where your application processes the authentication response.
-
-To add or remove an redirect URL, go to Dashboard > Authentication > Redirects > Allowed Callback URLs.
-
-### Initiate login URL
-**Purpose**: When authentication does not initiate from your application, Scalekit redirects users back to your application's login initiation endpoint. This endpoint should point to a route in your application that ultimately redirects users to Scalekit's `/authorize` endpoint.
-
-**Example scenarios**:
-
-- **Bookmarked login page**: A user bookmarks your login page and visits it directly. Your application detects they're not authenticated and redirects them to Scalekit's authorization endpoint.
-
-- **Organization invitation flow**: A user clicks an invitation link to join an organization. Your application receives the invitation token and redirects the user to Scalekit's authorization endpoint to complete the sign-up process.
-
-- **IdP-initiated SSO**: An administrator initiates single sign-on from their identity provider dashboard. The IdP redirects users to your application, which then redirects them to Scalekit's authorization endpoint to complete authentication.
-
-- **Session expiration**: When a user's session expires or they access a protected resource, they're redirected to `https://yourapp.com/login` which then redirects to Scalekit's authentication endpoint.
-
-### Post logout URL
-**Purpose**: Where users are sent after successfully signing out of your application.
-
-**Example scenario**: After logging out, users are redirected to `https://yourapp.com/goodbye` to confirm their session has ended.
-
-### Back channel logout URL
-**Purpose**: A secure endpoint that receives notifications whenever a user is logged out from Scalekit, regardless of how the logout was initiated — admin triggered, user initiated, or due to session policies like idle timeout.
-
-**Example scenario**: When a user logs out from any application (user-initiated, admin-initiated, or due to session policies like idle timeout), Scalekit sends a logout notification to `https://yourapp.com/logout` to suggest termination of the user's session across all connected applications, ensuring coordinated logout for enhanced security.
-
-### Custom URI schemes
-
-Custom URI schemes allow for redirects, enabling deep linking and native app integrations. Some applications include:
-- **Desktop applications**: Use schemes like `{scheme}://` for native app integration
-- **Mobile apps**: Use schemes like `myapp://` for mobile app deep linking
-
-**Example custom schemes**:
-- `{scheme}://auth/callback` - For custom scheme authentication
-- `myapp://login/callback` - For mobile app authentication
-
-
-## URI validation requirements
-
-Your redirect URIs must meet specific requirements that vary between development and production environments:
-
-| Requirement | Development | Production |
-| ----------- | ----------- | ---------- |
-| Supported schemes | `http`, `https`, `{scheme}` | `https`, `{scheme}` |
-| Localhost support | Allowed | Not allowed |
-| Wildcard domains | Allowed | Not allowed |
-| URI length limit | 256 characters | 256 characters |
-| Query parameters | Not allowed | Not allowed |
-| URL fragments | Not allowed | Not allowed |
-
-
-### Wildcard usage patterns
-
-Wildcards can simplify testing in development environments, but they must follow specific patterns:
-
-| Validation rule | Valid examples | Invalid examples |
-| --------------- | -------------- | ---------------- |
-| Wildcards cannot be used as root-level domains | `https://*.acmecorp.com`, `https://auth-*.acmecorp.com` | `https://*.com` |
-| Only one wildcard character is allowed per URI | `https://*.acmecorp.com` | `https://*.*.acmecorp.com` |
-| Wildcards must be in the hostname component only | `https://*.acmecorp.com` | `https://acmecorp.*.com` |
-| Wildcards must be in the outermost subdomain | `https://*.auth.acmecorp.com` | `https://auth.*.acmecorp.com` |
-
-> **Note**: According to the [OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), redirect URIs must be absolute URIs. For development convenience, Scalekit relaxes this restriction slightly by allowing wildcards in development environments.
diff --git a/plugins/modular-scim/skills/implementing-admin-portal/SKILL.md b/plugins/modular-scim/skills/implementing-admin-portal/SKILL.md
deleted file mode 100644
index a12fb3a..0000000
--- a/plugins/modular-scim/skills/implementing-admin-portal/SKILL.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-name: implementing-admin-portal
-description: Implements Scalekit's admin portal for customer self-serve SSO and SCIM configuration. Generates portal links server-side and embeds the portal as an iframe in the app's settings UI. Use when the user asks to add an admin portal, customer self-serve SCIM setup, iframe embed for directory sync config, shareable setup link, or let customers configure their own SSO or SCIM connection.
----
-
-# Admin Portal with Scalekit
-
-Adds a self-serve portal where customers configure their own SSO and SCIM settings — embedded inside your app's settings UI.
-
-If the user only needs a quick shareable link with no code (e.g., for a one-time onboarding call), skip to the **Shareable link** section at the bottom.
-
----
-
-## Implementation progress
-
-```
-Admin Portal Implementation Progress:
-- [ ] Step 1: Install SDK
-- [ ] Step 2: Set environment credentials
-- [ ] Step 3: Register app domain in dashboard
-- [ ] Step 4: Generate portal link (server-side)
-- [ ] Step 5: Render iframe (client-side)
-- [ ] Step 6: Handle session expiry events
-- [ ] Step 7: Verify portal loads and events fire correctly
-```
-
----
-
-## Step 1: Install SDK
-
-Detect the project's language/framework from existing files and install:
-
-| Stack | Install |
-|---------|---------|
-| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk` |
-| Go | `go get github.com/scalekit/scalekit-go` |
-| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` |
-
----
-
-## Step 2: Set environment credentials
-
-Add to `.env` (never hardcode):
-
-```shell
-SCALEKIT_ENVIRONMENT_URL='https://.scalekit.com'
-SCALEKIT_CLIENT_ID=''
-SCALEKIT_CLIENT_SECRET=''
-```
-
-Credentials are in **Dashboard > Developers > Settings > API Credentials**.
-
----
-
-## Step 3: Register app domain
-
-In **Dashboard > Developers > API Configuration > Redirect URIs**, add the domain where the portal will be embedded. The iframe will be blocked if this is missing.
-
----
-
-## Step 4: Generate the portal link (server-side)
-
-Generate a new link on every page load — links are single-use. Plug into the existing route or controller that serves the settings/admin page:
-
-**Node.js:**
-```javascript
-const { location } = await scalekit.organization.generatePortalLink(organizationId);
-// Pass `location` to the frontend as a template variable or API response
-```
-
-**Python:**
-```python
-portal = scalekit_client.organization.generate_portal_link(organization_id)
-location = portal.location
-# Pass `location` to your template or JSON response
-```
-
-**Never cache this value** — each link is single-use and will fail if reused.
-
----
-
-## Step 5: Render the iframe (client-side)
-
-In the frontend settings/admin template, inject `location` as the `src`:
-
-```html
-
-```
-
-Minimum recommended height: **600px**. Match the variable name to the project's existing templating convention.
-
----
-
-## Step 6: Handle portal UI events
-
-Listen for messages from the iframe to react to configuration changes and session expiry:
-
-```javascript
-window.addEventListener('message', (event) => {
- if (event.origin !== process.env.SCALEKIT_ENVIRONMENT_URL) return;
-
- const { type } = event.data;
- switch (type) {
- case 'SCIM_CONFIGURED':
- // Refresh org SCIM status, show success banner, etc.
- break;
- case 'SSO_CONFIGURED':
- // Refresh org SSO status if SSO is also in scope
- break;
- case 'SESSION_EXPIRED':
- // Re-fetch a new portal link and reload the iframe src
- reloadPortalIframe();
- break;
- }
-});
-```
-
-`SESSION_EXPIRED` handling is required — without it the portal silently breaks for long-lived sessions.
-
----
-
-## Step 7: Verify
-
-- [ ] Open the settings page — confirm the iframe renders without console errors
-- [ ] Complete a test SCIM configuration inside the portal — confirm `SCIM_CONFIGURED` fires
-- [ ] Wait for session expiry (or simulate it) — confirm `SESSION_EXPIRED` triggers a link refresh
-- [ ] Confirm portal link is never the same across two page loads (single-use verification)
-
----
-
-## Branding (optional)
-
-Configure at **Dashboard > Settings > Branding**: logo, accent color, favicon. Custom domain support (e.g., `scim.yourapp.com`) is available in the Scalekit dashboard.
-
----
-
-## Guardrails
-
-- **Generate link server-side only** — never expose `CLIENT_SECRET` to the browser
-- **Re-generate on every page load** — caching will break the portal
-- **Register your domain** in Redirect URIs before testing or the iframe will be blocked
-- **Handle `SESSION_EXPIRED`** — re-generate and reload, don't let it fail silently
-
----
-
-## Shareable link (no-code alternative)
-
-For one-time onboarding calls or zero-engineering setup: go to **Dashboard > Organizations**, select the org, click **Generate link**, and share the URL directly. The link gives anyone who has it full access to configure that org's SSO/SCIM settings — use the iframe approach for production. Also share Scalekit's [SCIM setup guides](https://docs.scalekit.com/guides/integrations/scim-integrations/) so the IT admin has provider-specific directory sync steps alongside the portal link.
diff --git a/plugins/modular-scim/skills/production-readiness-scalekit/SKILL.md b/plugins/modular-scim/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index dca5b5f..0000000
--- a/plugins/modular-scim/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit SCIM provisioning implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their SCIM directory sync implementation is production-ready.
----
-
-# Scalekit SCIM Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all endpoints
-- [ ] API credentials stored in environment variables — never committed to code
-- [ ] Webhook secret stored in environment variables — never committed to code
-
----
-
-## SCIM provisioning
-
-- [ ] Configure webhook endpoints to receive SCIM events
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/scim-integrations/
-- [ ] Verify webhook security with signature validation on every request
-- [ ] Test user provisioning (automatic creation from IdP)
-- [ ] Test user deprovisioning (deactivation/deletion when removed in IdP)
-- [ ] Test user profile updates (name, email, attributes synced correctly)
-- [ ] Test role changes propagated via group membership
-- [ ] Set up group-based role assignment and sync
-- [ ] Test error cases: duplicate users, invalid data, missing required fields
-- [ ] Verify idempotent handling — duplicate events must not create duplicate records
-- [ ] Deactivation preferred over hard deletion for `user_deleted` events
-
-**Webhook reliability:**
-- [ ] Webhook endpoint returns 2xx quickly — offload heavy processing to a queue if needed
-- [ ] Scalekit retries on non-2xx with exponential backoff (up to 8 attempts over ~10 hours)
-- [ ] Tested webhook delivery end-to-end with a real IdP or Scalekit's test tool
-
----
-
-## User and organization management
-
-- [ ] Test organization creation and domain assignment
-- [ ] Test adding and removing users from organizations
-- [ ] Set allowed email domains for org provisioning (if applicable)
-- [ ] Set default roles for auto-provisioned users
-- [ ] Test user deletion flow
-
-**RBAC (if implemented):**
-- [ ] Define roles and permissions that map to IdP groups
-- [ ] Test role assignment via group membership sync
-- [ ] Verify permission enforcement at API endpoints
-- [ ] Test access control across all role levels
-
----
-
-## Network and firewall
-
-Enterprise customers behind VPN or corporate firewall must whitelist:
-
-| Domain | Purpose |
-|---|---|
-| `.scalekit.com` | Directory API + webhook delivery |
-| `cdn.scalekit.com` | Static assets |
-
-- [ ] Customer firewalls allow Scalekit domains
-- [ ] SCIM provisioning tested from customer's network environment
-
----
-
-## Monitoring and incident readiness
-
-- [ ] Webhook event monitoring and logging active
-- [ ] Error tracking configured for provisioning failures
-- [ ] Alerts configured for failed webhook deliveries
-- [ ] Log retention policies configured
-- [ ] Webhook delivery and retry mechanism tested
-- [ ] Incident response runbook written (who to contact, how to roll back)
-- [ ] Rollback plan ready (disable SCIM sync without breaking existing users)
-
-**Key metrics:**
-- Webhook delivery success rate
-- User provisioning/deprovisioning latency
-- Failed sync events (by type and error)
-- Group-to-role mapping accuracy
diff --git a/plugins/modular-sso b/plugins/modular-sso
new file mode 120000
index 0000000..995039d
--- /dev/null
+++ b/plugins/modular-sso
@@ -0,0 +1 @@
+saaskit
\ No newline at end of file
diff --git a/plugins/modular-sso/.github/plugin/plugin.json b/plugins/modular-sso/.github/plugin/plugin.json
deleted file mode 100644
index f859646..0000000
--- a/plugins/modular-sso/.github/plugin/plugin.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "modular-sso",
- "description": "Modular SSO flows using Scalekit for apps with existing user management, including IdP-initiated login and enterprise onboarding.",
- "version": "1.1.4",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com"
- },
- "homepage": "https://docs.scalekit.com",
- "repository": "https://github.com/scalekit-inc/github-copilot-authstack",
- "license": "MIT",
- "keywords": ["sso", "saml", "oidc", "authentication", "enterprise"],
- "agents": [
- "./agents"
- ],
- "skills": [
- "./skills/modular-sso",
- "./skills/implementing-admin-portal",
- "./skills/production-readiness-scalekit"
- ],
- "mcpServers": ".mcp.json"
-}
diff --git a/plugins/modular-sso/.mcp.json b/plugins/modular-sso/.mcp.json
deleted file mode 100644
index 36dbbf4..0000000
--- a/plugins/modular-sso/.mcp.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "mcpServers": {
- "scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com"]
- }
- }
-}
diff --git a/plugins/modular-sso/README.md b/plugins/modular-sso/README.md
deleted file mode 100644
index 9c38ca5..0000000
--- a/plugins/modular-sso/README.md
+++ /dev/null
@@ -1,95 +0,0 @@
-# modular-sso
-
-## Purpose
-
-This plugin implements modular SSO flows using Scalekit for applications that already have their own user management. It adds enterprise SSO (SAML, OIDC) on top of existing auth systems, handles IdP-initiated login, and provides self-serve customer onboarding via an embedded admin portal — without requiring a full auth migration.
-
-## Installation
-
-```bash
-# Add the marketplace
-copilot plugin marketplace add scalekit-inc/github-copilot-authstack
-
-# Install this plugin
-copilot plugin install modular-sso
-```
-
-## Components Reference
-
-### Agents
-
-| Agent | Purpose |
-|---|---|
-| `setup-scalekit` | Sets up Scalekit env vars, installs and initializes the SDK, and verifies credentials |
-
-### Skills
-
-| Skill | Purpose |
-|---|---|
-| `modular-sso` | Implements SSO and authentication flows: modular SSO, IdP-initiated login, session management, enterprise onboarding |
-| `implementing-admin-portal` | Embeds Scalekit's admin portal for customer self-serve SSO configuration |
-| `production-readiness-scalekit` | Structured production readiness checklist for Scalekit SSO implementations |
-
-### MCP Server
-
-Configured in `.mcp.json` — connects to the Scalekit MCP server at `https://mcp.scalekit.com` via `mcp-remote`.
-
-### Commands
-
-- `dryrun` — runs a Scalekit SSO dry-run to validate configuration before going live
-
-## Configuration
-
-Required environment variables:
-
-```bash
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
-SCALEKIT_CLIENT_ID=your_client_id
-SCALEKIT_CLIENT_SECRET=your_client_secret
-```
-
-Use the `setup-scalekit` agent to configure these automatically:
-
-```bash
-copilot setup-scalekit "Set up Scalekit for my SSO integration"
-```
-
-## Usage Examples
-
-### Add enterprise SSO to an existing app
-
-```
-copilot "Add SAML SSO to my app that already has username/password login"
-```
-
-The `modular-sso` skill activates and guides through installing the Scalekit SDK, initiating the SSO authorization URL, handling the callback, validating the token, and linking SSO identity to an existing user record.
-
-### Let customers configure their own SSO
-
-```
-copilot "Add a self-serve SSO configuration page for my enterprise customers"
-```
-
-The `implementing-admin-portal` skill generates a server-side portal link and embeds it as an iframe in your settings UI.
-
-## Troubleshooting
-
-**IdP-initiated login failing**: Ensure the Initiate Login URL is registered in your Scalekit dashboard. See `references/redirects.md` for the correct URL format. This endpoint must redirect users to Scalekit's `/authorize` endpoint.
-
-**SSO callback returning errors**: Verify that the redirect URL in your dashboard exactly matches the callback URL in your code. Query parameters are not allowed in registered redirect URIs.
-
-**Admin portal not loading**: Confirm the portal link was generated server-side using valid credentials and has not expired. Portal links are single-use and time-limited.
-
-## Security
-
-**Required credentials:**
-- `SCALEKIT_ENVIRONMENT_URL` — your Scalekit environment URL
-- `SCALEKIT_CLIENT_ID` — OAuth client ID
-- `SCALEKIT_CLIENT_SECRET` — OAuth client secret (treat as a password)
-
-**Storage:**
-- Store secrets in environment variables or a secrets manager
-- Never commit secrets to source control
-- Validate the `state` parameter in all OAuth callbacks to prevent CSRF attacks
-
-The plugin itself contains no hardcoded credentials. All MCP server config uses `${ENV_VAR}` placeholders.
diff --git a/plugins/modular-sso/agents/setup-scalekit.md b/plugins/modular-sso/agents/setup-scalekit.md
deleted file mode 100644
index 044e411..0000000
--- a/plugins/modular-sso/agents/setup-scalekit.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-name: scalekit-setup
-description: Sets up Scalekit env vars, installs/initializes the SDK, and verifies credentials by listing organizations. Use proactively when user asks to set up, install, initialize, configure, or verify Scalekit.
-model: sonnet
-tools: Read, Grep, Glob, Bash, Write, Edit
-maxTurns: 20
----
-
-You are a Scalekit setup and verification specialist.
-
-Mission:
-- Help the user configure Scalekit credentials via environment variables.
-- Help them install and initialize the official Scalekit SDK for their language.
-- Verify the setup with the smallest reliable check (prefer listing organizations).
-- Keep secrets out of chat and out of the repo.
-
-Hard rules:
-- NEVER ask the user to paste SCALEKIT_CLIENT_SECRET into chat.
-- NEVER hardcode credentials in code samples; always use environment variables.
-- Prefer creating a local verification script (verify.js / verify.py / verify.go / Verify.java) and running it, but only if the user wants you to write files.
-
-Workflow:
-1) Determine language/runtime (Node.js, Python, Go, Java) and where env vars should live (.env, shell, CI secrets).
-2) Confirm required env vars exist:
- - SCALEKIT_ENVIRONMENT_URL
- - SCALEKIT_CLIENT_ID
- - SCALEKIT_CLIENT_SECRET
-3) Install the SDK (pick the official package for that language).
-4) Initialize the SDK client using env vars.
-5) Verify credentials by listing organizations with a small page size.
-6) If verification fails, diagnose systematically:
- - Wrong environment URL (dev vs prod)
- - Missing env vars in current shell/process
- - Incorrect client id/secret
- - Network/DNS issues
-7) Only after verification succeeds, proceed to feature work and route to the correct Skill:
- - SSO → plugins/modular-sso/skills/modular-sso/SKILL.md
- - SCIM → plugins/modular-scim/skills/modular-scim/SKILL.md
- - MCP auth → plugins/mcp-auth/skills/*/SKILL.md
- - Full-stack auth → plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
-
-When you reference files, use exact repo-relative paths and read them before advising.
diff --git a/plugins/modular-sso/commands/dryrun.md b/plugins/modular-sso/commands/dryrun.md
deleted file mode 100644
index 1b23d0d..0000000
--- a/plugins/modular-sso/commands/dryrun.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-description: Run Scalekit dryrun in fsa
-argument-hint: " [organization_id]"
-allowed-tools: Bash(node *), Bash(npx *)
----
-
-Run Scalekit dryrun with explicit arguments.
-
-Expected arguments:
-1. mode (`sso`)
-2. env_url
-3. client_id
-4. organization_id (required only for `sso`)
-
-Behavior:
-- If mode is `fsa`, run:
- `npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=fsa`
-- If mode is `sso`, run:
- `npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=sso --organization_id=`
-- If mode is missing/invalid, explain the usage and ask for valid arguments.
-- If `sso` is selected but organization_id is missing, ask for it before running.
diff --git a/plugins/modular-sso/references/redirects.md b/plugins/modular-sso/references/redirects.md
deleted file mode 100644
index dbe1977..0000000
--- a/plugins/modular-sso/references/redirects.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Redirects
-
-Redirects are registered endpoints in Scalekit that control where users are directed during authentication flows. You must configure these endpoints in the Scalekit dashboard before they can be used.
-
-All redirect URIs must be registered under Authentication settings in your Scalekit dashboard. This is a security requirement to prevent unauthorized redirects.
-
-
-## Redirect endpoint types
-
-### Allowed callback URLs
-**Purpose**: Where users are sent after successful authentication to exchange authorization codes and retrieve profile information.
-
-**Example scenario**: A user completes sign-in and Scalekit redirects them to `https://yourapp.com/callback` where your application processes the authentication response.
-
-To add or remove an redirect URL, go to Dashboard > Authentication > Redirects > Allowed Callback URLs.
-
-### Initiate login URL
-**Purpose**: When authentication does not initiate from your application, Scalekit redirects users back to your application's login initiation endpoint. This endpoint should point to a route in your application that ultimately redirects users to Scalekit's `/authorize` endpoint.
-
-**Example scenarios**:
-
-- **Bookmarked login page**: A user bookmarks your login page and visits it directly. Your application detects they're not authenticated and redirects them to Scalekit's authorization endpoint.
-
-- **Organization invitation flow**: A user clicks an invitation link to join an organization. Your application receives the invitation token and redirects the user to Scalekit's authorization endpoint to complete the sign-up process.
-
-- **IdP-initiated SSO**: An administrator initiates single sign-on from their identity provider dashboard. The IdP redirects users to your application, which then redirects them to Scalekit's authorization endpoint to complete authentication.
-
-- **Session expiration**: When a user's session expires or they access a protected resource, they're redirected to `https://yourapp.com/login` which then redirects to Scalekit's authentication endpoint.
-
-### Post logout URL
-**Purpose**: Where users are sent after successfully signing out of your application.
-
-**Example scenario**: After logging out, users are redirected to `https://yourapp.com/goodbye` to confirm their session has ended.
-
-### Back channel logout URL
-**Purpose**: A secure endpoint that receives notifications whenever a user is logged out from Scalekit, regardless of how the logout was initiated — admin triggered, user initiated, or due to session policies like idle timeout.
-
-**Example scenario**: When a user logs out from any application (user-initiated, admin-initiated, or due to session policies like idle timeout), Scalekit sends a logout notification to `https://yourapp.com/logout` to suggest termination of the user's session across all connected applications, ensuring coordinated logout for enhanced security.
-
-### Custom URI schemes
-
-Custom URI schemes allow for redirects, enabling deep linking and native app integrations. Some applications include:
-- **Desktop applications**: Use schemes like `{scheme}://` for native app integration
-- **Mobile apps**: Use schemes like `myapp://` for mobile app deep linking
-
-**Example custom schemes**:
-- `{scheme}://auth/callback` - For custom scheme authentication
-- `myapp://login/callback` - For mobile app authentication
-
-
-## URI validation requirements
-
-Your redirect URIs must meet specific requirements that vary between development and production environments:
-
-| Requirement | Development | Production |
-| ----------- | ----------- | ---------- |
-| Supported schemes | `http`, `https`, `{scheme}` | `https`, `{scheme}` |
-| Localhost support | Allowed | Not allowed |
-| Wildcard domains | Allowed | Not allowed |
-| URI length limit | 256 characters | 256 characters |
-| Query parameters | Not allowed | Not allowed |
-| URL fragments | Not allowed | Not allowed |
-
-
-### Wildcard usage patterns
-
-Wildcards can simplify testing in development environments, but they must follow specific patterns:
-
-| Validation rule | Valid examples | Invalid examples |
-| --------------- | -------------- | ---------------- |
-| Wildcards cannot be used as root-level domains | `https://*.acmecorp.com`, `https://auth-*.acmecorp.com` | `https://*.com` |
-| Only one wildcard character is allowed per URI | `https://*.acmecorp.com` | `https://*.*.acmecorp.com` |
-| Wildcards must be in the hostname component only | `https://*.acmecorp.com` | `https://acmecorp.*.com` |
-| Wildcards must be in the outermost subdomain | `https://*.auth.acmecorp.com` | `https://auth.*.acmecorp.com` |
-
-> **Note**: According to the [OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), redirect URIs must be absolute URIs. For development convenience, Scalekit relaxes this restriction slightly by allowing wildcards in development environments.
diff --git a/plugins/modular-sso/skills/implementing-admin-portal/SKILL.md b/plugins/modular-sso/skills/implementing-admin-portal/SKILL.md
deleted file mode 100644
index 7bbfd19..0000000
--- a/plugins/modular-sso/skills/implementing-admin-portal/SKILL.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-name: implementing-admin-portal
-description: Implements Scalekit's admin portal for customer self-serve SSO and SCIM configuration. Generates portal links server-side and embeds the portal as an iframe in the app's settings UI. Use when the user asks to add an admin portal, customer self-serve SSO setup, iframe embed for SSO config, shareable setup link, or let customers configure their own SSO or SCIM connection.
----
-
-# Admin Portal with Scalekit
-
-Adds a self-serve portal where customers configure their own SSO and SCIM settings — embedded inside your app's settings UI.
-
-If the user only needs a quick shareable link with no code (e.g., for a one-time onboarding call), skip to the **Shareable link** section at the bottom.
-
----
-
-## Implementation progress
-
-```
-Admin Portal Implementation Progress:
-- [ ] Step 1: Install SDK
-- [ ] Step 2: Set environment credentials
-- [ ] Step 3: Register app domain in dashboard
-- [ ] Step 4: Generate portal link (server-side)
-- [ ] Step 5: Render iframe (client-side)
-- [ ] Step 6: Handle session expiry events
-- [ ] Step 7: Verify portal loads and events fire correctly
-```
-
----
-
-## Step 1: Install SDK
-
-Detect the project's language/framework from existing files and install:
-
-| Stack | Install |
-|---------|---------|
-| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk` |
-| Go | `go get github.com/scalekit/scalekit-go` |
-| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` |
-
----
-
-## Step 2: Set environment credentials
-
-Add to `.env` (never hardcode):
-
-```shell
-SCALEKIT_ENVIRONMENT_URL='https://.scalekit.com'
-SCALEKIT_CLIENT_ID=''
-SCALEKIT_CLIENT_SECRET=''
-```
-
-Credentials are in **Dashboard > Developers > Settings > API Credentials**.
-
----
-
-## Step 3: Register app domain
-
-In **Dashboard > Developers > API Configuration > Redirect URIs**, add the domain where the portal will be embedded. The iframe will be blocked if this is missing.
-
----
-
-## Step 4: Generate the portal link (server-side)
-
-Generate a new link on every page load — links are single-use. Plug into the existing route or controller that serves the settings/admin page:
-
-**Node.js:**
-```javascript
-const { location } = await scalekit.organization.generatePortalLink(organizationId);
-// Pass `location` to the frontend as a template variable or API response
-```
-
-**Python:**
-```python
-portal = scalekit_client.organization.generate_portal_link(organization_id)
-location = portal.location
-# Pass `location` to your template or JSON response
-```
-
-**Never cache this value** — each link is single-use and will fail if reused.
-
----
-
-## Step 5: Render the iframe (client-side)
-
-In the frontend settings/admin template, inject `location` as the `src`:
-
-```html
-
-```
-
-Minimum recommended height: **600px**. Match the variable name to the project's existing templating convention.
-
----
-
-## Step 6: Handle portal UI events
-
-Listen for messages from the iframe to react to configuration changes and session expiry:
-
-```javascript
-window.addEventListener('message', (event) => {
- if (event.origin !== process.env.SCALEKIT_ENVIRONMENT_URL) return;
-
- const { type } = event.data;
- switch (type) {
- case 'SSO_CONFIGURED':
- // Refresh org SSO status, show success banner, etc.
- break;
- case 'SESSION_EXPIRED':
- // Re-fetch a new portal link and reload the iframe src
- reloadPortalIframe();
- break;
- }
-});
-```
-
-`SESSION_EXPIRED` handling is required — without it the portal silently breaks for long-lived sessions.
-
----
-
-## Step 7: Verify
-
-- [ ] Open the settings page — confirm the iframe renders without console errors
-- [ ] Complete a test SSO configuration inside the portal — confirm `SSO_CONFIGURED` fires
-- [ ] Wait for session expiry (or simulate it) — confirm `SESSION_EXPIRED` triggers a link refresh
-- [ ] Confirm portal link is never the same across two page loads (single-use verification)
-
----
-
-## Branding (optional)
-
-Configure at **Dashboard > Settings > Branding**: logo, accent color, favicon. Custom domain support (e.g., `sso.yourapp.com`) is available in the Scalekit dashboard.
-
----
-
-## Guardrails
-
-- **Generate link server-side only** — never expose `CLIENT_SECRET` to the browser
-- **Re-generate on every page load** — caching will break the portal
-- **Register your domain** in Redirect URIs before testing or the iframe will be blocked
-- **Handle `SESSION_EXPIRED`** — re-generate and reload, don't let it fail silently
-
----
-
-## Shareable link (no-code alternative)
-
-For one-time onboarding calls or zero-engineering setup: go to **Dashboard > Organizations**, select the org, click **Generate link**, and share the URL directly. The link gives anyone who has it full access to configure that org's SSO/SCIM settings — use the iframe approach for production. Also share Scalekit's [SSO setup guides](https://docs.scalekit.com/guides/integrations/sso-integrations/) so the IT admin has provider-specific configuration steps alongside the portal link.
-
diff --git a/plugins/modular-sso/skills/production-readiness-scalekit/SKILL.md b/plugins/modular-sso/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index b24ffab..0000000
--- a/plugins/modular-sso/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,110 +0,0 @@
----
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit SSO implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, hardening their SSO setup, or wants to verify their Scalekit implementation is production-ready.
----
-
-# Scalekit SSO Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all auth endpoints
-- [ ] CORS restricted to your domains only
-- [ ] API credentials stored in environment variables — never committed to code
-
----
-
-## Customization
-
-- [ ] Login page branded with logo, colors, styling
-- [ ] Email templates customized (sign-up, password reset, invitations)
-- [ ] Custom domain configured for auth pages (if applicable)
-- [ ] Email provider configured in **Dashboard > Customization > Emails**
-- [ ] Email deliverability tested — check spam folders
-- [ ] Webhooks configured with signature validation
-
----
-
-## Core auth flows
-
-- [ ] Test login initiation with authorization URL
-- [ ] Validate redirect URLs match dashboard configuration exactly
-- [ ] Test authentication completion and code exchange
-- [ ] Validate `state` parameter in callbacks (CSRF protection)
-- [ ] Verify session token storage uses `httpOnly`, `secure`, and `sameSite` flags
-- [ ] Test session timeout and automatic token refresh
-- [ ] Verify logout clears sessions completely
-- [ ] Expired tokens handled gracefully
-- [ ] Network failures show user-friendly messages
-
----
-
-## SSO flows
-
-- [ ] Test SSO with target IdPs: Okta, Azure AD, Google Workspace
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/sso-integrations/
-- [ ] Configure user attribute mapping (email, name, groups)
-- [ ] Test both SP-initiated and IdP-initiated SSO flows
-- [ ] Verify SSO error handling for misconfigured connections
-- [ ] Test SSO with: new users, existing users, deactivated users
-
-**JIT provisioning:**
-- [ ] Register all organization domains for JIT provisioning
-- [ ] Configure consistent user identifiers across SSO connections (email or userPrincipalName)
-- [ ] Set default roles for JIT-provisioned users
-- [ ] Enable "Sync user attributes during login"
-- [ ] Plan manual invitation process for contractors/external users with non-matching domains
-- [ ] Set up review process for automatically provisioned users
-
-**Admin portal:**
-- [ ] Configure admin portal access for enterprise customers
-- [ ] Test admin portal SSO configuration flows
-- [ ] Verify user management features in admin portal
-
----
-
-## Organization management
-
-- [ ] Test organization creation
-- [ ] Test adding and removing users from organizations
-- [ ] Set allowed email domains for org sign-ups (if applicable)
-- [ ] Verify organization switching for users in multiple orgs
-- [ ] Test invitation flow and email templates
-
----
-
-## Network and firewall
-
-Enterprise customers behind VPN or corporate firewall must whitelist:
-
-| Domain | Purpose |
-|---|---|
-| `.scalekit.com` | Auth + admin portal |
-| `cdn.scalekit.com` | Static assets |
-| `fonts.googleapis.com` | Font resources |
-
-- [ ] Customer firewalls allow Scalekit domains
-- [ ] SSO tested from customer's network environment
-
----
-
-## Monitoring and incident readiness
-
-- [ ] Auth logs monitoring configured in **Dashboard > Auth Logs**
-- [ ] Alerts set for suspicious activity (multiple failed logins, unusual locations)
-- [ ] Webhook event monitoring and logging active
-- [ ] Error tracking configured for authentication failures
-- [ ] Log retention policies configured
-- [ ] Webhook delivery and retry mechanism tested
-- [ ] Incident response runbook written (who to contact, how to roll back, escalation path)
-- [ ] Rollback plan ready (feature flag to disable SSO flows if needed)
-
-**Key metrics:**
-- Login success/failure rates
-- SSO initiation vs completion rate
-- Session creation and duration
-- Webhook delivery success rate
diff --git a/plugins/saaskit/.github/plugin/plugin.json b/plugins/saaskit/.github/plugin/plugin.json
new file mode 100644
index 0000000..25b0493
--- /dev/null
+++ b/plugins/saaskit/.github/plugin/plugin.json
@@ -0,0 +1,30 @@
+{
+ "name": "saaskit",
+ "description": "Production-ready auth for B2B SaaS apps. Login, sessions, SSO (Okta, Azure AD, Google), SCIM provisioning, RBAC, MCP server auth, and API key management.",
+ "version": "2.0.0",
+ "author": {
+ "name": "Scalekit Inc",
+ "email": "support@scalekit.com"
+ },
+ "homepage": "https://docs.scalekit.com",
+ "repository": "https://github.com/scalekit-inc/github-copilot-authstack",
+ "license": "MIT",
+ "keywords": ["scalekit", "saaskit", "authentication", "sso", "scim", "mcp-auth", "sessions"],
+ "agents": ["./agents"],
+ "skills": [
+ "./skills/implementing-saaskit",
+ "./skills/implementing-saaskit-nextjs",
+ "./skills/implementing-saaskit-python",
+ "./skills/implementing-modular-sso",
+ "./skills/implementing-scim-provisioning",
+ "./skills/adding-mcp-oauth",
+ "./skills/implementing-access-control",
+ "./skills/managing-saaskit-sessions",
+ "./skills/migrating-to-saaskit",
+ "./skills/adding-api-auth",
+ "./skills/testing-auth-setup",
+ "./skills/production-readiness-saaskit"
+ ],
+ "hooks": "./hooks/hooks.json",
+ "mcpServers": ".mcp.json"
+}
diff --git a/plugins/full-stack-auth/.mcp.json b/plugins/saaskit/.mcp.json
similarity index 100%
rename from plugins/full-stack-auth/.mcp.json
rename to plugins/saaskit/.mcp.json
diff --git a/plugins/saaskit/README.md b/plugins/saaskit/README.md
new file mode 100644
index 0000000..27aeca1
--- /dev/null
+++ b/plugins/saaskit/README.md
@@ -0,0 +1,32 @@
+# SaaSKit for GitHub Copilot
+
+Production-ready auth for B2B SaaS apps. This plugin brings Scalekit SaaSKit into GitHub Copilot to build production-ready B2B authentication. It covers login, sessions, SSO, SCIM provisioning, MCP server auth, API keys, and more.
+
+## Skills
+
+- `implementing-saaskit` — Core auth flow: login, signup, callback, token exchange, session management, logout. Framework references for Go, Spring Boot, Laravel.
+- `implementing-saaskit-nextjs` — Auth for Next.js App Router.
+- `implementing-saaskit-python` — Auth for Django, FastAPI, or Flask. Framework references included.
+- `implementing-modular-sso` — Enterprise SSO (SAML/OIDC) with 20+ IdPs, admin portal, JIT provisioning.
+- `implementing-scim-provisioning` — SCIM 2.0 webhooks, user/group lifecycle, directory API.
+- `adding-mcp-oauth` — OAuth 2.1 for MCP servers (FastMCP, Express, FastAPI).
+- `implementing-access-control` — RBAC and permission checks.
+- `managing-saaskit-sessions` — Secure session storage, token refresh, session revocation.
+- `migrating-to-saaskit` — Migration planning from Auth0, Firebase, Cognito, or custom auth.
+- `adding-api-auth` — API keys (org/user scoped) and OAuth 2.0 client credentials.
+- `production-readiness-saaskit` — Unified production checklist across all SaaSKit domains.
+
+## Configuration
+
+Required environment variables:
+
+- `SCALEKIT_ENVIRONMENT_URL`
+- `SCALEKIT_CLIENT_ID`
+- `SCALEKIT_CLIENT_SECRET`
+
+## Links
+
+- [Full-stack auth quickstart](https://docs.scalekit.com/authenticate/fsa/quickstart/)
+- [Modular SSO guide](https://docs.scalekit.com/authenticate/sso/add-modular-sso/)
+- [SCIM directory sync](https://docs.scalekit.com/directory/scim/quickstart/)
+- [MCP Auth quickstart](https://docs.scalekit.com/authenticate/mcp/quickstart/)
diff --git a/plugins/mcp-auth/agents/scalekit-mcp-auth-troubleshooter.md b/plugins/saaskit/agents/scalekit-mcp-auth-troubleshooter.agent.md
similarity index 84%
rename from plugins/mcp-auth/agents/scalekit-mcp-auth-troubleshooter.md
rename to plugins/saaskit/agents/scalekit-mcp-auth-troubleshooter.agent.md
index f7777e4..bc4b523 100644
--- a/plugins/mcp-auth/agents/scalekit-mcp-auth-troubleshooter.md
+++ b/plugins/saaskit/agents/scalekit-mcp-auth-troubleshooter.agent.md
@@ -1,17 +1,7 @@
---
name: scalekit-mcp-auth-troubleshooter
-description: Diagnose and resolve common Scalekit MCP auth integration issues (handshake/metadata, cached clients, CORS/network, Claude Desktop port limits, browser launch problems), producing a step-by-step fix plan with verification commands.
-model: claude-sonnet-4
-maxTurns: 12
-permissionMode: plan
-tools:
- - Read
- - Glob
- - Grep
- - Bash
-disallowedTools:
- - Write
- - Edit
+description: Diagnose and resolve common Scalekit MCP auth integration issues (handshake/metadata, cached clients, CORS/network, port limits, browser launch problems), producing a step-by-step fix plan with verification commands.
+tools: ["bash", "view", "glob", "rg"]
---
# Role
@@ -27,7 +17,7 @@ Your job is to take a failing MCP client ↔ MCP server connection and produce:
# Triage flow (follow in order)
## 1) Identify the client + environment
-Ask (or infer from context) which MCP client is failing: MCP Inspector, MCP-Remote, VS Code, Claude Desktop.
+Ask (or infer from context) which MCP client is failing: MCP Inspector, MCP-Remote, VS Code, GitHub Copilot CLI, or another client.
Also capture: MCP server URL, Scalekit environment URL, and whether this is dev or prod.
@@ -48,7 +38,7 @@ Clear cached auth (by client):
- MCP-Remote: delete `~/.mcp-auth/mcp-remote-` and reconnect.
- VS Code: run “Authentication: Remove Dynamic Authentication Provider”, remove the cached entry, and reconnect.
-If the failing client is Claude Desktop, note that client behavior can differ and some issues are client-specific (see sections below).
+Note that client behavior can differ and some issues are client-specific (see sections below).
## 4) CORS & callback URL issues (common with MCP Inspector)
If you see CORS failures during the handshake in browser network logs, add the MCP Inspector callback URL to Scalekit’s allowed callback URLs.
@@ -65,8 +55,8 @@ Checklist:
- Allow or exempt MCP client → server traffic for the server domain; confirm via proxy/WAF logs.
- Test direct connectivity from the same machine running the MCP client (bypass proxy if possible).
-## 6) Client-specific: Claude Desktop port limitations
-Claude Desktop only supports standard HTTPS on port 443; it will ignore custom ports and still attempt 443. [web:48]
+## 6) Client-specific: port limitations
+Some MCP clients only support standard HTTPS on port 443; they will ignore custom ports and still attempt 443. [web:48]
Workarounds:
- Expose your MCP server on 443 via a load balancer or reverse proxy.
@@ -80,5 +70,5 @@ Fixes:
- Windows: enable default app management permissions (Settings → Privacy → App permissions), then restart the client.
- Linux: ensure `xdg-open` exists (`which xdg-open`) and is on PATH, then restart the client.
-## 8) Claude Code / OAuth registration mismatch (when relevant)
+## 8) OAuth registration mismatch (when relevant)
If you see errors like “Incompat
diff --git a/plugins/mcp-auth/agents/setup-scalekit.md b/plugins/saaskit/agents/setup-scalekit.agent.md
similarity index 80%
rename from plugins/mcp-auth/agents/setup-scalekit.md
rename to plugins/saaskit/agents/setup-scalekit.agent.md
index 044e411..5b597a4 100644
--- a/plugins/mcp-auth/agents/setup-scalekit.md
+++ b/plugins/saaskit/agents/setup-scalekit.agent.md
@@ -1,9 +1,7 @@
---
name: scalekit-setup
description: Sets up Scalekit env vars, installs/initializes the SDK, and verifies credentials by listing organizations. Use proactively when user asks to set up, install, initialize, configure, or verify Scalekit.
-model: sonnet
-tools: Read, Grep, Glob, Bash, Write, Edit
-maxTurns: 20
+tools: ["bash", "view", "apply_patch", "glob", "rg"]
---
You are a Scalekit setup and verification specialist.
@@ -34,9 +32,10 @@ Workflow:
- Incorrect client id/secret
- Network/DNS issues
7) Only after verification succeeds, proceed to feature work and route to the correct Skill:
- - SSO → plugins/modular-sso/skills/modular-sso/SKILL.md
- - SCIM → plugins/modular-scim/skills/modular-scim/SKILL.md
- - MCP auth → plugins/mcp-auth/skills/*/SKILL.md
- - Full-stack auth → plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
+ - SSO → plugins/saaskit/skills/implementing-modular-sso/SKILL.md
+ - SCIM → plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
+ - MCP auth → plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
+ - Full-stack auth → plugins/saaskit/skills/implementing-saaskit/SKILL.md
+ - AgentKit → plugins/agentkit/skills/integrating-agentkit/SKILL.md
When you reference files, use exact repo-relative paths and read them before advising.
diff --git a/plugins/saaskit/hooks/beacon.sh b/plugins/saaskit/hooks/beacon.sh
new file mode 100755
index 0000000..85af851
--- /dev/null
+++ b/plugins/saaskit/hooks/beacon.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+PLUGIN="${1:-unknown}"
+HOOK="${2:-stop}"
+INPUT=$(cat)
+
+SESSION_ID=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('session_id','anonymous'))" \
+ 2>/dev/null || echo "anonymous")
+
+TOOL_NAME=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" \
+ 2>/dev/null || echo "")
+
+curl -s -o /dev/null --max-time 5 \
+ -X POST https://ph.scalekit.com/i/v0/e/ \
+ -H "Content-Type: application/json" \
+ -d "{\"token\":\"phc_85pLP8gwYvRCQdxgLQP24iqXHPRGaLgEw4S4dgZHJZ\",\
+\"event\":\"plugin_used\",\
+\"distinct_id\":\"${SESSION_ID}\",\
+\"properties\":{\"plugin\":\"${PLUGIN}\",\"coding_agent\":\"copilot\",\"hook\":\"${HOOK}\",\"tool_name\":\"${TOOL_NAME}\"}}"
\ No newline at end of file
diff --git a/plugins/saaskit/hooks/hooks.json b/plugins/saaskit/hooks/hooks.json
new file mode 100644
index 0000000..eabc77c
--- /dev/null
+++ b/plugins/saaskit/hooks/hooks.json
@@ -0,0 +1,16 @@
+{
+ "description": "Usage beacon for Scalekit saaskit plugin",
+ "hooks": {
+ "Stop": [
+ {
+ "hooks": [
+ {
+ "type": "command",
+ "command": "${COPILOT_PLUGIN_ROOT}/hooks/beacon.sh saaskit stop",
+ "timeout": 10
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/plugins/mcp-auth/references/bring-your-own-auth.md b/plugins/saaskit/references/bring-your-own-auth.md
similarity index 96%
rename from plugins/mcp-auth/references/bring-your-own-auth.md
rename to plugins/saaskit/references/bring-your-own-auth.md
index 1ccb94e..0b253dc 100644
--- a/plugins/mcp-auth/references/bring-your-own-auth.md
+++ b/plugins/saaskit/references/bring-your-own-auth.md
@@ -211,19 +211,19 @@ Production-ready MCP server implementations with different OAuth integration app
- 5-line OAuth integration with Scalekit provider
- Automatic token validation and scope enforcement
- [todo-fastmcp](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/todo-fastmcp)
- - Skill: [add-auth-fastmcp](../skills/add-auth-fastmcp/SKILL.md)
+ - Reference: [fastmcp-reference.md](../skills/adding-mcp-oauth/fastmcp-reference.md)
2. **Express.js (Full Control)**
- Manual OAuth middleware implementation
- Modular architecture with complete control
- [greeting-mcp-node](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/greeting-mcp-node)
- - Skill: [express-mcp-server](../skills/express-mcp-server/SKILL.md)
+ - Reference: [express-reference.md](../skills/adding-mcp-oauth/express-reference.md)
3. **FastAPI + FastMCP (Python)**
- Custom middleware with FastMCP tooling
- Ideal for existing FastAPI applications
- [greeting-mcp-python](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/greeting-mcp-python)
- - Skill: [fastapi-fastmcp](../skills/fastapi-fastmcp/SKILL.md)
+ - Reference: [fastapi-reference.md](../skills/adding-mcp-oauth/fastapi-reference.md)
4. **Scalekit MCP Server (Production Reference)**
- Official Scalekit implementation with advanced patterns
diff --git a/plugins/full-stack-auth/references/redirects.md b/plugins/saaskit/references/redirects.md
similarity index 100%
rename from plugins/full-stack-auth/references/redirects.md
rename to plugins/saaskit/references/redirects.md
diff --git a/plugins/full-stack-auth/references/scalekit-logs.md b/plugins/saaskit/references/scalekit-logs.md
similarity index 100%
rename from plugins/full-stack-auth/references/scalekit-logs.md
rename to plugins/saaskit/references/scalekit-logs.md
diff --git a/plugins/mcp-auth/references/scalekit-mcp-server.md b/plugins/saaskit/references/scalekit-mcp-server.md
similarity index 100%
rename from plugins/mcp-auth/references/scalekit-mcp-server.md
rename to plugins/saaskit/references/scalekit-mcp-server.md
diff --git a/plugins/full-stack-auth/references/scalekit-user-profiles.md b/plugins/saaskit/references/scalekit-user-profiles.md
similarity index 100%
rename from plugins/full-stack-auth/references/scalekit-user-profiles.md
rename to plugins/saaskit/references/scalekit-user-profiles.md
diff --git a/plugins/full-stack-auth/agents/session-management-reviewer.md b/plugins/saaskit/references/session-management-patterns.md
similarity index 83%
rename from plugins/full-stack-auth/agents/session-management-reviewer.md
rename to plugins/saaskit/references/session-management-patterns.md
index b7fe1f6..c8eabae 100644
--- a/plugins/full-stack-auth/agents/session-management-reviewer.md
+++ b/plugins/saaskit/references/session-management-patterns.md
@@ -1,33 +1,10 @@
----
-name: scalekit-session-management-reviewer
-description: >
- Reviews existing session management implementation in the codebase and suggests
- options for implementing or improving it using Scalekit. Use proactively when
- working on authentication flows, middleware, token handling, or session-related
- code. Invoke explicitly for session security audits or Scalekit integration planning.
-tools: Read, Grep, Glob, Bash
-model: sonnet
-maxTurns: 30
----
-
-# Scalekit Session Management Reviewer
+# Session Management Patterns
-You are a senior authentication architect specializing in Scalekit's session management
-system. Your goal is to analyze the existing codebase for session-related patterns and
-provide concrete, tiered implementation options using Scalekit.
+Reference guide for evaluating and implementing session management with Scalekit. Covers audit checklists, implementation options (FSA, Modular SSO, Remote API, AgentKit), and code patterns.
-Hard rules:
-- Never suggest an implementation path without completing Phase 1 first.
-- Always reference actual file paths found during discovery, not hypothetical ones.
-- Never give generic advice — every recommendation must be grounded in what you found.
-- When analyzing user identity, token claims, or profile data in session payloads,
- consult `plugins/full-stack-auth/references/scalekit-user-profiles.md` for Scalekit's
- attribute schema and SDK method reference before suggesting implementation.
-- When a session failure pattern is suspected or a webhook-triggered auth flow is being
- debugged, consult `plugins/full-stack-auth/references/scalekit-logs.md` for filter
- strategies and status definitions before suggesting next steps.
-
----
+Related references:
+- [scalekit-user-profiles.md](scalekit-user-profiles.md) — attribute schema and SDK methods
+- [scalekit-logs.md](scalekit-logs.md) — filter strategies and status definitions
## Phase 1: Discovery — Understand the Existing Setup
@@ -233,7 +210,7 @@ await scalekit.sessions.revokeAll({ userId: req.user.id });
---
-### Option D: Agent Auth — Token Vault for AI Agent Scenarios
+### Option D: AgentKit — Token Vault for AI Agent Scenarios
**Best for:** AI apps where agents make API calls on behalf of users to third-party services.
```typescript
@@ -294,9 +271,9 @@ Produce this structured report after completing all phases:
After delivering the report, offer to route to the appropriate skill for implementation:
-- Option A selected → `plugins/full-stack-auth/skills/full-stack-auth/SKILL.md`
-- Option B selected → `plugins/modular-sso/skills/modular-sso/SKILL.md`
-- Option D selected → `plugins/agent-auth/skills/agent-auth/SKILL.md`
+- Option A selected → `plugins/saaskit/skills/implementing-saaskit/SKILL.md`
+- Option B selected → `plugins/saaskit/skills/implementing-modular-sso/SKILL.md`
+- Option D selected → `plugins/agentkit/skills/integrating-agentkit/SKILL.md`
If Scalekit is not yet set up, route to setup first:
-- `plugins/full-stack-auth/agents/setup-scalekit.md`
+- `plugins/saaskit/agents/setup-scalekit.md`
diff --git a/plugins/full-stack-auth/skills/adding-api-key-auth/SKILL.md b/plugins/saaskit/skills/adding-api-auth/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/adding-api-key-auth/SKILL.md
rename to plugins/saaskit/skills/adding-api-auth/SKILL.md
index 8b9cfe5..feb8c9a 100644
--- a/plugins/full-stack-auth/skills/adding-api-key-auth/SKILL.md
+++ b/plugins/saaskit/skills/adding-api-auth/SKILL.md
@@ -1,5 +1,5 @@
---
-name: adding-api-key-auth
+name: adding-api-auth
description: >
Creates, validates, lists, and revokes long-lived opaque API keys using
Scalekit for organization-scoped or user-scoped bearer authentication.
diff --git a/plugins/mcp-auth/skills/mcp-auth/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
similarity index 96%
rename from plugins/mcp-auth/skills/mcp-auth/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
index f7e3e16..3b43dc1 100644
--- a/plugins/mcp-auth/skills/mcp-auth/SKILL.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
@@ -1,11 +1,11 @@
---
name: adding-mcp-oauth
-description: Guides users through adding OAuth 2.1 authorization to Model Context Protocol (MCP) servers using Scalekit. Use when setting up MCP servers, implementing authentication for AI hosts like Claude Desktop, Cursor, or VS Code, or when users mention MCP security, OAuth, or Scalekit integration.
+description: Guides users through adding OAuth 2.1 authorization to Model Context Protocol (MCP) servers using Scalekit. Use when setting up MCP servers, implementing authentication for AI hosts like GitHub Copilot, Cursor, or VS Code, or when users mention MCP security, OAuth, or Scalekit integration.
---
# Adding OAuth 2.1 Authorization to MCP Servers
-Secure your MCP server with production-ready OAuth 2.1 authorization using Scalekit. This enables authenticated access through AI hosts like Claude Desktop, Cursor, and VS Code.
+Secure your MCP server with production-ready OAuth 2.1 authorization using Scalekit. This enables authenticated access through AI hosts like GitHub Copilot, Cursor, and VS Code.
## Critical Prerequisites
@@ -46,7 +46,7 @@ app = create_streamable_http_app(server=mcp, streamable_http_path="/mcp")
Notes:
- The imports above match the **official** Python MCP SDK on PyPI (`mcp`). See: `https://pypi.org/project/mcp/1.9.1/`
- The result is an **ASGI `app`** you run with an ASGI server (e.g. `uvicorn module:app`)—this is **Streamable HTTP**, not stdio.
-- SSE-only transports are not the same as Streamable HTTP; for OAuth with MCP hosts (Claude Desktop/Cursor/VS Code), use Streamable HTTP. See: `https://gofastmcp.com/python-sdk/fastmcp-server-http`
+- SSE-only transports are not the same as Streamable HTTP; for OAuth with MCP hosts (GitHub Copilot/Cursor/VS Code), use Streamable HTTP. See: `https://gofastmcp.com/python-sdk/fastmcp-server-http`
- Example run: `uvicorn your_module:app --host 0.0.0.0 --port 8000`
If your MCP server currently uses stdio transport, you must migrate to HTTP-based transport before implementing OAuth. See [MCP Transport Documentation](https://spec.modelcontextprotocol.io/specification/architecture/#transports) for migration guidance.
@@ -295,7 +295,7 @@ except Exception:
### Verify your integration
-Before testing with AI hosts, Claude Code will scan your project to determine
+Before testing with AI hosts, the coding agent will scan your project to determine
the right URL to verify against. It will look for:
- `RESOURCE_ID` or `resource` values in your code or `.env`
@@ -320,7 +320,7 @@ The response must include:
WWW-Authenticate: Bearer realm="OAuth", resource_metadata="https:///.well-known/oauth-protected-resource"
```
This is what triggers the MCP client's OAuth flow. A plain 401 without this header
-will cause AI hosts (Claude Desktop, Cursor, VS Code) to fail silently.
+will cause AI hosts (GitHub Copilot, Cursor, VS Code) to fail silently.
**Check 3 – Confirm metadata endpoint is reachable:**
```bash
@@ -329,7 +329,7 @@ curl https:///.well-known/oauth-protected-resource
Expected: JSON with `resource`, `authorization_servers`, and `scopes_supported`.
### Testing checklist (after verification passes)
-- [ ] Test with Claude Desktop
+- [ ] Test with GitHub Copilot
- [ ] Test with Cursor
- [ ] Test with VS Code
- [ ] Verify token validation rejects invalid tokens
@@ -375,21 +375,21 @@ See [Complete Working Examples](#complete-working-examples) below for production
Production-ready examples demonstrating different implementation approaches:
### FastMCP (5-Line OAuth Integration)
-**Skill:** [add-auth-fastmcp](../add-auth-fastmcp/SKILL.md)
+**Reference:** [fastmcp-reference.md](fastmcp-reference.md)
- Simplest approach with built-in OAuth provider
- Automatic token validation and scope enforcement
- Complete todo server with CRUD operations
- **GitHub:** [todo-fastmcp](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/todo-fastmcp)
### Express.js (Full Manual OAuth)
-**Skill:** [express-mcp-server](../express-mcp-server/SKILL.md)
+**Reference:** [express-reference.md](express-reference.md)
- Complete control over authentication middleware
- Modular architecture with transport, tools, auth layers
- Production-ready with CORS, logging, error handling
- **GitHub:** [greeting-mcp-node](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/greeting-mcp-node)
### FastAPI + FastMCP (Custom Middleware)
-**Skill:** [fastapi-fastmcp](../fastapi-fastmcp/SKILL.md)
+**Reference:** [fastapi-reference.md](fastapi-reference.md)
- Python-based with custom authentication middleware
- Combines FastAPI's HTTP control with FastMCP's tooling
- Ideal for existing FastAPI applications
diff --git a/plugins/mcp-auth/skills/express-mcp-server/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
similarity index 100%
rename from plugins/mcp-auth/skills/express-mcp-server/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
diff --git a/plugins/mcp-auth/skills/fastapi-fastmcp/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md
similarity index 100%
rename from plugins/mcp-auth/skills/fastapi-fastmcp/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md
diff --git a/plugins/mcp-auth/skills/add-auth-fastmcp/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/fastmcp-reference.md
similarity index 100%
rename from plugins/mcp-auth/skills/add-auth-fastmcp/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/fastmcp-reference.md
diff --git a/plugins/full-stack-auth/skills/implementing-access-control/SKILL.md b/plugins/saaskit/skills/implementing-access-control/SKILL.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-access-control/SKILL.md
rename to plugins/saaskit/skills/implementing-access-control/SKILL.md
diff --git a/plugins/modular-sso/skills/modular-sso/SKILL.md b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
similarity index 98%
rename from plugins/modular-sso/skills/modular-sso/SKILL.md
rename to plugins/saaskit/skills/implementing-modular-sso/SKILL.md
index 15aa426..c301495 100644
--- a/plugins/modular-sso/skills/modular-sso/SKILL.md
+++ b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
@@ -1,5 +1,5 @@
---
-name: modular-sso
+name: implementing-modular-sso
description: Implements complete SSO and authentication flows using Scalekit. Handles modular SSO, IdP-initiated login, user session management, and enterprise customer onboarding. Use when adding authentication, SSO, SAML, OIDC, or user login to applications.
---
@@ -404,7 +404,7 @@ Prevent failed redirects by checking SSO configuration before redirecting:
**Node.js:**
```javascript
-const domain = email.split('@').toLowerCase(); [reddit](https://www.reddit.com/r/ClaudeAI/comments/1qb1024/ultimate_claude_skillmd_autobuilds_any_fullstack/)
+const domain = email.split('@').toLowerCase();
const connections = await scalekit.connections.listConnectionsByDomain({
domain
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-nextjs-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/implementing-scalekit-nextjs-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
index 3d4ba84..137ee9e 100644
--- a/plugins/full-stack-auth/skills/implementing-scalekit-nextjs-auth/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
@@ -1,5 +1,5 @@
---
-name: implementing-scalekit-nextjs-auth
+name: implementing-saaskit-nextjs
description: Implements Scalekit authentication in a Next.js App Router project using the patterns from scalekit-inc/scalekit-nextjs-auth-example. Handles login, OAuth callback, session management, token refresh, logout, and permission-based access control using @scalekit-sdk/node. Use when adding auth routes, protecting pages, managing sessions, or checking permissions in a Next.js + Scalekit codebase.
---
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-django-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/implementing-scalekit-django-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
index 7fffb09..bad9eea 100644
--- a/plugins/full-stack-auth/skills/implementing-scalekit-django-auth/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
@@ -1,5 +1,5 @@
---
-name: implementing-scalekit-django-auth
+name: implementing-saaskit-python
description: Implements Scalekit authentication in a Django project using the patterns from scalekit-inc/scalekit-django-auth-example. Handles login, OAuth callback, Django session storage, automatic token refresh via middleware, logout, and permission-based route protection using decorators. Use when adding auth views, protecting URLs, managing sessions, or checking permissions in a Django + Scalekit codebase.
---
diff --git a/plugins/full-stack-auth/skills/full-stack-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit/SKILL.md
index 389d2f1..c57df34 100644
--- a/plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
@@ -1,5 +1,5 @@
---
-name: implementing-scalekit-fsa
+name: implementing-saaskit
description: Implements Scalekit full-stack authentication (FSA) including sign-up, login, logout, and secure session management using JWT tokens. Use when building or integrating user authentication with the Scalekit SDK across Node.js, Python, Go, or Java — or when the user asks about auth flows, OAuth callbacks, token refresh, or session handling with Scalekit.
---
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-go-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/go-reference.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-scalekit-go-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit/go-reference.md
diff --git a/plugins/modular-scim/skills/modular-scim/SKILL.md b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
similarity index 100%
rename from plugins/modular-scim/skills/modular-scim/SKILL.md
rename to plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
diff --git a/plugins/full-stack-auth/skills/manage-user-sessions/SKILL.md b/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/manage-user-sessions/SKILL.md
rename to plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
index ea94dc5..e6fb8fc 100644
--- a/plugins/full-stack-auth/skills/manage-user-sessions/SKILL.md
+++ b/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
@@ -1,5 +1,5 @@
---
-name: managing-user-sessions
+name: managing-saaskit-sessions
description: Manages Scalekit-backed user sessions by securely storing access/refresh/ID tokens (with encryption and correct cookie attributes), validating access tokens on every request, transparently refreshing tokens in middleware, and optionally revoking sessions remotely via Scalekit session APIs. Use when building session persistence for only for web apps. For SPAs this is NOT the skill.
---
diff --git a/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/SKILL.md b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/migrating-to-scalekit-auth/SKILL.md
rename to plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
index 66f84e5..9c670f5 100644
--- a/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/SKILL.md
+++ b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
@@ -1,5 +1,5 @@
---
-name: migrating-to-scalekit-auth
+name: migrating-to-saaskit
description: Plans and executes a safe, incremental migration from any existing auth system to Scalekit's full-stack auth platform. Use when the user asks to migrate authentication, replace session middleware, import users/organizations to Scalekit, configure SSO, or set up SCIM provisioning with Scalekit.
---
diff --git a/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
new file mode 100644
index 0000000..5a52753
--- /dev/null
+++ b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
@@ -0,0 +1,64 @@
+---
+name: production-readiness-saaskit
+description: Walks through a structured production readiness checklist for Scalekit SaaSKit implementations covering authentication, SSO, SCIM, MCP server auth, and API security. Use when going live, launching to production, or doing a pre-launch review.
+---
+
+# SaaSKit Production Readiness
+
+Unified checklist for all SaaSKit domains. Work through in order — skip sections that don't apply.
+
+## Quick checks (run first)
+
+- [ ] Production env URL, client ID, and client secret set (not dev/staging)
+- [ ] HTTPS enforced; CORS restricted to your domains only
+- [ ] All credentials in environment variables — never committed to code
+- [ ] Only enabled auth methods active in production
+
+## Customization
+
+- [ ] Login page branded; email templates customized
+- [ ] Custom domain configured (if applicable); email deliverability tested
+- [ ] Webhooks configured with signature validation
+
+## Core auth flows
+
+- [ ] Login initiation, code exchange, and redirect URLs match dashboard exactly
+- [ ] `state` parameter validated in callbacks (CSRF); tokens stored with `httpOnly`, `secure`, `sameSite`
+- [ ] Token refresh and session timeout working; logout calls Scalekit end-session
+- [ ] Each enabled auth method tested; errors handled gracefully
+
+## SSO (if applicable)
+
+- [ ] SSO tested with target IdPs (Okta, Azure AD, Google Workspace)
+- [ ] SP-initiated and IdP-initiated flows both working
+- [ ] Admin portal configured for self-serve SSO setup
+- [ ] JIT provisioning: domains registered, default roles set, attribute sync enabled
+
+## SCIM provisioning (if applicable)
+
+- [ ] Webhook endpoints receiving events with signature validation
+- [ ] User provisioning, deprovisioning, and profile updates tested
+- [ ] Group-based role sync working; idempotent handling verified
+
+## MCP authentication (if applicable)
+
+- [ ] MCP auth flow tested end-to-end; resource metadata published
+- [ ] Scopes enforced per tool; client reconnection after token expiry working
+
+## Network / firewall
+
+Enterprise VPN customers must whitelist: `.scalekit.com`, `cdn.scalekit.com`, `fonts.googleapis.com`.
+
+## Monitoring
+
+- [ ] Auth logs monitoring active; alerts for suspicious activity configured
+- [ ] Webhook monitoring active; error tracking for auth and provisioning failures
+- [ ] Incident response runbook written; rollback plan ready (feature flag)
+- **Key metrics:** login success/failure rates, session duration, webhook delivery, SSO completion rate
+
+## Deep reference
+
+- [Scalekit Documentation](https://docs.scalekit.com)
+- [Modular SSO guide](https://docs.scalekit.com/authenticate/sso/add-modular-sso/)
+- [SCIM directory sync](https://docs.scalekit.com/directory/scim/quickstart/)
+- [MCP Auth quickstart](https://docs.scalekit.com/authenticate/mcp/quickstart/)
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md b/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
new file mode 100644
index 0000000..51f499c
--- /dev/null
+++ b/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
@@ -0,0 +1,326 @@
+---
+name: scalekit-code-doctor
+description: Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. This skill is the single source of truth for Scalekit code correctness — it can generate illustration-quality snippets from scratch (for docs, websites, or integration guides) and review existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both Scalekit product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, write a code sample for docs, or anything involving Scalekit code quality.
+---
+
+# Scalekit Code Doctor
+
+You are the authoritative source for Scalekit code correctness. You can both **generate** correct code from scratch and **review** existing code to guarantee it works.
+
+**Before doing anything else**, read the reference files in this skill's `references/` directory:
+- `references/REFERENCE.md` — Every correct SDK method signature across Node, Python, Go, Java, and REST API endpoints
+- `references/COMMON-MISTAKES.md` — Known anti-patterns with wrong → right corrections
+
+These files are your ground truth. Never hallucinate a method name, parameter, or import path — if it's not in the reference, fetch `https://docs.scalekit.com/apis.md` to verify before using it.
+
+---
+
+## Step 1 — Detect mode
+
+Determine which mode to operate in based on what the user provides:
+
+**Generate mode** — The user describes what they want but has no code yet.
+Examples: "Show me how to add SSO login to Express", "Generate a Next.js callback handler", "Write a Python FastAPI auth example for docs"
+
+**Review mode** — The user provides existing code for validation.
+Examples: "Is this Scalekit integration correct?", "Review my auth callback", "Why isn't my login working?"
+
+If unclear, ask: "Do you want me to generate a fresh code example, or review existing code you have?"
+
+---
+
+## Step 2 — Identify context
+
+Before generating or reviewing, identify these three things:
+
+### Language and SDK
+| Language | Package | Import |
+|----------|---------|--------|
+| Node.js / TypeScript | `@scalekit-sdk/node` | `import { ScalekitClient } from '@scalekit-sdk/node'` |
+| Python | `scalekit-sdk-python` (pip) | `from scalekit import ScalekitClient` |
+| Go | `github.com/scalekit-inc/scalekit-sdk-go` | `import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"` |
+| Java | `com.scalekit:scalekit-sdk-java` | `import com.scalekit.ScalekitClient;` |
+| REST API | No SDK — raw HTTP | Bearer token via `POST /oauth/token` with client credentials |
+
+### Framework (if applicable)
+Next.js (App Router or Pages), Express, Fastify, FastAPI, Django, Flask, Spring Boot, Go (chi, gin, net/http), Laravel, etc.
+
+### Product area
+
+Scalekit has two product suites. Identify which one the user's code belongs to:
+
+**SaaSKit** — Full-stack authentication for B2B SaaS apps
+- SSO — Enterprise single sign-on (SAML, OIDC)
+- Login & Sessions — Sign-up, login, logout, session management
+- RBAC — Roles, permissions, access control
+- SCIM — Directory sync and user provisioning
+- Admin Portal — Customer-facing admin configuration
+
+**AgentKit** — Authentication and tool access for AI agents
+- Connections — OAuth token vault for third-party services (connected accounts)
+- Tool Calling — Execute tools via connected accounts
+- MCP Authentication — OAuth 2.1 for MCP servers
+- Framework Integrations — LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra
+
+**Cross-product**
+- Webhooks — Event subscriptions and payload verification
+- M2M Auth — API keys and client credentials
+
+---
+
+## Step 3 — Generate mode
+
+When generating code, follow these rules:
+
+### Quality standard: illustration-ready
+The output should be clean enough to publish directly on `docs.scalekit.com` or a marketing landing page. This means:
+
+1. **Self-contained** — The reader understands it without seeing other files
+2. **Essential path only** — Show the concept, not defensive boilerplate
+3. **Real-looking values** — `'https://yourapp.com/auth/callback'` not `'http://localhost:3000/test'`
+4. **Correct imports** — Exact package names from the reference table above
+5. **Framework-idiomatic** — Use the framework's conventions (App Router for Next.js, decorators for FastAPI, etc.)
+6. **Minimal comments** — Annotate Scalekit-specific lines only. Skip obvious framework code.
+7. **1–2 pages max** — Concise. If a full flow needs more, split into labeled sections.
+
+### Mandatory checks before outputting generated code
+Cross-reference every SDK call against `references/REFERENCE.md`:
+- [ ] Client initialization uses correct constructor and parameter order
+- [ ] Every method name exists in the reference for the target SDK
+- [ ] Every parameter name and type matches the reference
+- [ ] Import path is exactly correct (not a hallucinated variation)
+- [ ] Environment variable names match Scalekit conventions (see reference)
+
+### Generation patterns by product area
+
+**SaaSKit — Login, SSO, and sessions**
+1. Client initialization (singleton pattern)
+2. Login route: generate auth URL with `state` for CSRF
+3. Callback route: validate `state`, exchange code, store session
+4. Logout route: clear local session AND call `getLogoutUrl()` with `idTokenHint`
+5. Token refresh (if `offline_access` scope is used)
+
+**SaaSKit — SCIM provisioning**
+1. Enable directory for an organization
+2. List directory users and groups
+3. Webhook handler for SCIM events
+
+**AgentKit — Connections and tool calling**
+1. Client initialization
+2. Create/list connected accounts
+3. Execute tools with connected account credentials
+4. Handle token refresh for third-party OAuth tokens
+
+**AgentKit — MCP Authentication**
+1. MCP server setup with OAuth middleware
+2. Token validation on incoming requests
+3. Scope verification
+
+**Webhooks** — Always include signature verification:
+1. Raw body parsing (not JSON-parsed)
+2. `verifyWebhookPayload(secret, headers, rawBody)`
+3. Event type switching
+
+---
+
+## Step 4 — Review mode
+
+When reviewing code, systematically check these categories in order:
+
+### Category 1: SDK usage correctness
+For every Scalekit SDK call in the code, verify against `references/REFERENCE.md`:
+- [ ] Method name is exactly correct for the target SDK language
+- [ ] All required parameters are provided in the correct order
+- [ ] Optional parameters use the correct type/shape
+- [ ] Return value is handled correctly (Promise in Node, tuple in Python, error in Go, etc.)
+- [ ] Import statement uses the correct package name and path
+- [ ] Client is initialized with the correct 3 parameters: `envUrl`, `clientId`, `clientSecret`
+
+### Category 2: Auth flow completeness
+- [ ] If there's a login route, there must be a matching callback route
+- [ ] Callback validates `state` parameter (CSRF protection)
+- [ ] Callback exchanges the authorization code (not just reading it)
+- [ ] Session is stored after successful authentication
+- [ ] Logout calls `getLogoutUrl()` — not just clearing local session
+- [ ] Token refresh exists if `offline_access` or `refresh_token` is used
+- [ ] IdP-initiated login is handled if callback receives `idp_initiated_login` parameter
+
+### Category 3: Security
+- [ ] Session cookies use `httpOnly: true`, `secure: true` (in production), `sameSite: 'lax'` (never `'strict'` — breaks OAuth redirects)
+- [ ] `state` parameter uses cryptographically random values, not predictable strings
+- [ ] Redirect URLs are validated — only relative paths allowed for `next`/`returnTo` params (prevents open redirect)
+- [ ] Client secret is read from environment variables, never hardcoded
+- [ ] Webhook endpoints verify payload signature before processing
+- [ ] Protected routes validate tokens server-side, not just checking cookie existence
+- [ ] `Cache-Control: no-store` on authenticated pages (prevents back-button cache leak)
+
+### Category 4: Environment and config
+- [ ] Environment variable names follow Scalekit conventions:
+ - `SCALEKIT_ENV_URL` (not `SCALEKIT_URL` or `SCALEKIT_ENVIRONMENT_URL` in code — though `SCALEKIT_ENVIRONMENT_URL` is used in REST API docs)
+ - `SCALEKIT_CLIENT_ID`
+ - `SCALEKIT_CLIENT_SECRET`
+- [ ] Redirect URI in code matches what's registered in the Scalekit dashboard
+- [ ] Correct Scalekit domain format: `https://.scalekit.com` (production) or `https://.scalekit.dev` (development)
+
+### Category 5: Best practices
+- [ ] Client instantiated once (singleton pattern), not per-request
+- [ ] Error handling uses SDK's typed exceptions where available
+- [ ] Token refresh handles race conditions across concurrent requests/tabs
+- [ ] `window.location.href` used for OAuth redirects (not `router.push` or client-side navigation)
+
+### Output format for review
+For each finding, report:
+1. **What's wrong** — the specific line or pattern
+2. **Why it matters** — security risk, runtime error, or silent failure
+3. **Corrected code** — the exact fix
+
+If everything is correct, say so explicitly: "This code is correct. All SDK calls, auth flow, security patterns, and configuration match the current Scalekit API."
+
+---
+
+## Step 5 — Handling SDK updates and unknown methods
+
+The `references/REFERENCE.md` in this skill is a **point-in-time snapshot**. Scalekit SDKs evolve — new methods are added, parameters change, and new product areas launch. When the embedded reference doesn't cover what you need, use the live sources below.
+
+### When to check live sources
+
+- A method the user wrote isn't in the embedded reference (could be newly added, not a typo)
+- The user asks about a feature you don't recognize (e.g., a new connector, a new auth mode)
+- You're generating code for a product area with sparse coverage in the reference
+- The user explicitly mentions a recent SDK update or version
+
+### How to check: fetch the live SDK REFERENCE.md files
+
+Each SDK repo has a maintained `REFERENCE.md` with full, current method signatures. Fetch the one you need:
+
+| SDK | Live reference URL |
+|-----|-------------------|
+| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` |
+| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` |
+| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` |
+| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` |
+| REST API | `https://docs.scalekit.com/apis.md` |
+
+### Resolution order
+
+1. Check the embedded `references/REFERENCE.md` first (fastest, no network)
+2. If the method isn't there, fetch the live SDK REFERENCE.md from the table above
+3. If still not found, fetch `https://docs.scalekit.com/apis.md` for REST endpoints
+4. If still not found, state explicitly: "This method could not be verified in any Scalekit reference. It may not exist."
+
+Never output code containing an unverified method call.
+
+---
+
+## REST API validation
+
+When the user's code makes raw HTTP calls (fetch, axios, requests, http.Client) to Scalekit endpoints, validate:
+
+- [ ] Base URL format: `https://.scalekit.com` or `https://.scalekit.dev`
+- [ ] Authentication: Bearer token obtained via `POST /oauth/token` with `client_credentials` grant
+- [ ] Endpoint path is correct (check `references/REFERENCE.md` for the endpoint list)
+- [ ] HTTP method matches (GET vs POST vs PUT vs PATCH vs DELETE)
+- [ ] Request body matches the expected schema
+- [ ] Content-Type header is set (`application/json` for most endpoints, `application/x-www-form-urlencoded` for token endpoint)
+- [ ] Pagination uses `page_token` and `page_size` parameters where applicable
+
+---
+
+## Documentation resources
+
+### Live SDK references (always current — fetch when embedded reference is stale)
+
+| SDK | REFERENCE.md (raw) | Repo |
+|-----|--------------------|----|
+| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` | [scalekit-sdk-node](https://github.com/scalekit-inc/scalekit-sdk-node) |
+| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` | [scalekit-sdk-python](https://github.com/scalekit-inc/scalekit-sdk-python) |
+| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` | [scalekit-sdk-go](https://github.com/scalekit-inc/scalekit-sdk-go) |
+| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` | [scalekit-sdk-java](https://github.com/scalekit-inc/scalekit-sdk-java) |
+
+### Scalekit docs
+
+| Resource | URL | When to use |
+|----------|-----|-------------|
+| REST API reference | `https://docs.scalekit.com/apis.md` | Full endpoint schemas, request/response details |
+| LLM doc index | `https://docs.scalekit.com/llms.txt` | Find the right docs page for a specific product area |
+| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` | Full SaaSKit reference (users, orgs, sessions, RBAC, SSO, SCIM) |
+| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` | Full AgentKit reference (agents, OAuth vault, tool calling, connectors) |
+| AgentKit frameworks | `https://docs.scalekit.com/_llms-txt/agentkit-frameworks.txt` | Framework-specific guides (LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra) |
+| MCP Authentication docs | `https://docs.scalekit.com/_llms-txt/mcp-authentication.txt` | MCP server OAuth 2.1, Dynamic Client Registration |
+
+### GitHub repos — working examples
+
+When generating or reviewing framework-specific code, fetch the matching repo for real, tested patterns. Repos are from `scalekit-inc` and `scalekit-developers` GitHub orgs.
+
+**SaaSKit — Auth examples by framework**
+
+| Framework | Repo | What it shows |
+|-----------|------|---------------|
+| Next.js (App Router) | [scalekit-nextjs-auth-example](https://github.com/scalekit-inc/scalekit-nextjs-auth-example) | SSO, sessions, protected routes, TypeScript |
+| Next.js (Pages) | [nextjs-example-apps](https://github.com/scalekit-inc/nextjs-example-apps) | React SSO integration flows |
+| Next.js + Auth.js | [scalekit-authjs-example](https://github.com/scalekit-developers/scalekit-authjs-example) | Enterprise SSO with next-auth v5 |
+| Express.js | [scalekit-express-auth-example](https://github.com/scalekit-inc/scalekit-express-auth-example) | Node SDK, EJS frontend, sessions |
+| Express.js | [scalekit-express-example](https://github.com/scalekit-developers/scalekit-express-example) | SSO with session management, middleware |
+| FastAPI | [scalekit-fastapi-auth-example](https://github.com/scalekit-inc/scalekit-fastapi-auth-example) | Python SDK, OAuth 2.0, protected routes |
+| FastAPI | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Async auth, Pydantic models |
+| Django | [scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example) | Python SDK, Django auth integration |
+| Flask | [scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example) | Python SDK, Flask sessions |
+| Spring Boot | [scalekit-springboot-auth-example](https://github.com/scalekit-inc/scalekit-springboot-auth-example) | Java, Spring Security, OIDC |
+| Spring Boot | [scalekit-springboot-example](https://github.com/scalekit-developers/scalekit-springboot-example) | Java SDK, enterprise SSO |
+| Go (Gin) | [scalekit-go-example](https://github.com/scalekit-developers/scalekit-go-example) | Go SDK, Gin framework, SSO |
+| Laravel | [scalekit-laravel-auth-example](https://github.com/scalekit-inc/scalekit-laravel-auth-example) | REST API calls, Laravel HTTPS |
+| Astro | [astro-scalekit-auth-example](https://github.com/scalekit-developers/astro-scalekit-auth-example) | Auth, SSO, social login, protected routes |
+| .NET | [dotnet-example-apps](https://github.com/scalekit-inc/dotnet-example-apps) | ASP.NET Core, SAML/OIDC |
+| Expo (mobile) | [expo-scalekit-sample](https://github.com/scalekit-inc/expo-scalekit-sample) | OAuth 2.0 + PKCE for mobile |
+
+**SaaSKit — Integration examples**
+
+| Integration | Repo | What it shows |
+|-------------|------|---------------|
+| AWS Cognito | [scalekit-cognito-sso](https://github.com/scalekit-inc/scalekit-cognito-sso) | OIDC SSO with Cognito user pools |
+| Firebase | [scalekit-firebase-sso](https://github.com/scalekit-inc/scalekit-firebase-sso) | SAML/OIDC SSO with Firebase Auth |
+| Supabase | [scalekit-supabase-example](https://github.com/scalekit-inc/scalekit-supabase-example) | Supabase + Scalekit auth |
+| Multi-app SSO | [multiapp-demo](https://github.com/scalekit-inc/multiapp-demo) | Seamless SSO across multiple apps |
+| Org switcher | [Nextjs-Django-Org-Switcher-Example](https://github.com/scalekit-inc/Nextjs-Django-Org-Switcher-Example) | Next.js frontend + Django backend, org switching |
+| OIDC/SAML/SCIM | [oidc-saml-scim-examples](https://github.com/scalekit-developers/oidc-saml-scim-examples) | Google, Okta integration patterns |
+| Passwordless | [passwordless-auth-demos](https://github.com/scalekit-developers/passwordless-auth-demos) | Passwordless authentication flows |
+| Managed login | [managed-loginbox-expressjs-demo](https://github.com/scalekit-developers/managed-loginbox-expressjs-demo) | Hosted login UI with Express |
+| Full demo app | [coffee-desk-demo](https://github.com/scalekit-inc/coffee-desk-demo) | Workspace creation, user provisioning, RBAC, SSO |
+
+**AgentKit — Agent and MCP examples**
+
+| Framework / Pattern | Repo | What it shows |
+|---------------------|------|---------------|
+| LangChain | [sample-langchain-agent](https://github.com/scalekit-inc/sample-langchain-agent) | Python LangChain agent with Scalekit auth |
+| Google ADK | [google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example) | Google ADK agent with authenticated tools |
+| Vercel AI SDK | [vercel-ai-agent-toolkit](https://github.com/scalekit-developers/vercel-ai-agent-toolkit) | Vercel AI SDK + Scalekit connectors |
+| Apify Actor | [agentkit-apify-actor-example](https://github.com/scalekit-developers/agentkit-apify-actor-example) | OAuth auth, YouTube → Notion agent |
+| LiteLLM | [litellm-agentkit-inbox-triage](https://github.com/scalekit-developers/litellm-agentkit-inbox-triage) | Inbox triage with Gmail, GitHub, Slack |
+| MCP Auth (multi-framework) | [mcp-auth-demos](https://github.com/scalekit-inc/mcp-auth-demos) | MCP OAuth 2.1 demos |
+| MCP + FastMCP | [fastmcp-scalekit-example](https://github.com/scalekit-inc/fastmcp-scalekit-example) | FastMCP server with Scalekit auth |
+| MCP + BYOA | [byoa-demo-mcp](https://github.com/scalekit-inc/byoa-demo-mcp) | Bring your own auth + MCP |
+| MCP + Coffee Desk | [coffee-desk-mcp](https://github.com/scalekit-inc/coffee-desk-mcp) | Demo MCP server with roles/permissions |
+| Python connections | [python-connect-demos](https://github.com/scalekit-inc/python-connect-demos) | Python connection and identity workflows |
+| Agent auth examples | [agent-auth-examples](https://github.com/scalekit-developers/agent-auth-examples) | Official AgentKit examples collection |
+| Node.js agents | [agent-node-demos](https://github.com/scalekit-inc/agent-node-demos) | TypeScript agent demos |
+| Workflow agents | [workflow-agents-demos](https://github.com/scalekit-developers/workflow-agents-demos) | Multi-step agent workflows |
+| Render deploy kit | [render-ai-agent-deploykit](https://github.com/scalekit-developers/render-ai-agent-deploykit) | Render Workflows + Scalekit + Claude |
+
+**Developer tools**
+
+| Tool | Repo | Purpose |
+|------|------|---------|
+| Dryrun CLI | [scalekit-dryrun](https://github.com/scalekit-inc/scalekit-dryrun) | Test auth flows without writing code |
+| Scalekit MCP server | [scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server) | Manage orgs, users, connections via AI assistants |
+| API collections | [api-collections](https://github.com/scalekit-inc/api-collections) | Postman/Bruno collections for Scalekit endpoints |
+| Documentation source | [developer-docs](https://github.com/scalekit-inc/developer-docs) | Docs site source (MDX) |
+
+**Frontend SDKs**
+
+| SDK | Repo | Purpose |
+|-----|------|---------|
+| React SDK | [scalekit-react-sdk](https://github.com/scalekit-inc/scalekit-react-sdk) | React OIDC authentication |
+| Vue SDK | [scalekit-vue-sdk](https://github.com/scalekit-inc/scalekit-vue-sdk) | Vue OIDC authentication |
+| Expo SDK | [scalekit-expo-sdk](https://github.com/scalekit-inc/scalekit-expo-sdk) | Expo/React Native OAuth 2.0 + PKCE |
+
+When generating code for a specific framework, fetch the matching repo's source to see real, tested patterns before writing. When reviewing, compare the user's code against the closest matching example repo.
\ No newline at end of file
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md b/plugins/saaskit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
new file mode 100644
index 0000000..5343181
--- /dev/null
+++ b/plugins/saaskit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
@@ -0,0 +1,481 @@
+# Common Mistakes in Scalekit Code
+
+This file catalogs known anti-patterns, hallucinated methods, and security issues found in Scalekit integrations. Each entry shows the wrong pattern and the correct fix. Use this as a lookup during both generation and review. 10 categories.
+
+---
+
+## 1. Wrong Import Paths
+
+### Node.js
+
+**Wrong:**
+```typescript
+import ScalekitClient from '@scalekit-sdk/node'; // default import — use named import
+import { ScalekitClient } from 'scalekit'; // wrong package name
+import { ScalekitClient } from 'scalekit-sdk-node'; // wrong package name
+```
+
+**Correct (either works):**
+```typescript
+import { ScalekitClient } from '@scalekit-sdk/node';
+// OR
+import { Scalekit } from '@scalekit-sdk/node'; // official alias, also valid
+```
+
+Both `ScalekitClient` and `Scalekit` are valid named exports from `@scalekit-sdk/node`. The SDK source exports both. Use whichever is consistent with your codebase.
+
+### Python
+
+**Wrong:**
+```python
+from scalekit_sdk import ScalekitClient # wrong module name
+from scalekit.client import ScalekitClient # internal path, not public API
+import scalekit # missing class import
+pip install scalekit # wrong pip package name
+```
+
+**Correct:**
+```python
+from scalekit import ScalekitClient
+# pip install scalekit-sdk-python
+```
+
+### Go
+
+**Wrong:**
+```go
+import "github.com/scalekit-inc/scalekit-sdk-go" // missing version
+import "github.com/scalekit/scalekit-sdk-go/v2" // wrong org name
+```
+
+**Correct:**
+```go
+import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"
+```
+
+### Java
+
+**Wrong:**
+```java
+import com.scalekit.sdk.ScalekitClient; // wrong package path
+import io.scalekit.ScalekitClient; // wrong package
+```
+
+**Correct:**
+```java
+import com.scalekit.ScalekitClient;
+```
+
+---
+
+## 2. Wrong Sub-Client Names (Python vs Node)
+
+Python and Node use different pluralization for some sub-clients. Using the wrong one causes `AttributeError` in Python or `TypeError` in Node.
+
+| Sub-client | Node.js (singular) | Python (plural) |
+|------------|--------------------|--------------------|
+| Users | `client.user.getUser(...)` | `client.users.get_user(...)` |
+| Roles | `client.role.listRoles(...)` | `client.roles.list_roles(...)` |
+| Permissions | `client.permission.listPermissions(...)` | `client.permissions.list_permissions(...)` |
+| Sessions | `client.session.getSession(...)` | `client.sessions.get_session(...)` |
+
+Sub-clients that are the SAME in both: `organization`, `connection`, `domain`, `directory`.
+
+**Wrong (Python):**
+```python
+client.user.get_user(user_id) # AttributeError: 'ScalekitClient' has no attribute 'user'
+client.role.list_roles() # AttributeError
+client.session.revoke_session(sid) # AttributeError
+```
+
+**Correct (Python):**
+```python
+client.users.get_user(user_id)
+client.roles.list_roles()
+client.sessions.revoke_session(sid)
+```
+
+---
+
+## 3. Wrong Method Names
+
+### Node.js
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `scalekit.authenticate(code)` | `scalekit.authenticateWithCode(code, redirectUri)` | Missing `WithCode` suffix and `redirectUri` param |
+| `scalekit.getAuthUrl(...)` | `scalekit.getAuthorizationUrl(redirectUri, options?)` | Wrong method name |
+| `scalekit.login(...)` | `scalekit.getAuthorizationUrl(redirectUri, options?)` | No `login` method |
+| `scalekit.logout(...)` | `scalekit.getLogoutUrl(options?)` | Returns URL, doesn't perform logout |
+| `scalekit.verifyToken(token)` | `scalekit.validateAccessToken(token)` or `scalekit.validateToken(token)` | Wrong name |
+| `scalekit.createOrganization(...)` | `scalekit.organization.createOrganization(...)` | Must use sub-client |
+| `scalekit.getOrganization(...)` | `scalekit.organization.getOrganization(...)` | Must use sub-client |
+
+### Python
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `client.authenticateWithCode(...)` | `client.authenticate_with_code(...)` | Python uses snake_case |
+| `client.getAuthorizationUrl(...)` | `client.get_authorization_url(...)` | Python uses snake_case |
+| `client.getLogoutUrl(...)` | `client.get_logout_url(...)` | Python uses snake_case |
+| `client.validateToken(...)` | `client.validate_access_token(...)` | Different method name in Python |
+| `client.verify_webhook(...)` | `client.verify_webhook_payload(...)` | Missing `_payload` suffix |
+
+### Go
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `client.AuthenticateWithCode(code, uri)` | `client.AuthenticateWithCode(ctx, code, uri, options)` | Missing `ctx` parameter |
+| `client.GetAuthorizationUrl(uri)` | `client.GetAuthorizationUrl(uri, options)` | Missing `options` param (required in Go) |
+| `client.Organization.Create(...)` | `client.Organization().CreateOrganization(ctx, request)` | Use accessor method `Organization()`, not field |
+
+### Java
+
+| Wrong | Correct | Notes |
+|-------|---------|-------|
+| `client.organization.create(...)` | `client.organizations().create(...)` | Use `organizations()` accessor method, plural |
+| `client.getOrganization(id)` | `client.organizations().getById(id)` | Use sub-client accessor |
+| `client.connections.list(...)` | `client.connections().listConnectionsByOrganization(orgId)` | Use accessor method |
+
+---
+
+## 4. Missing Required Parameters
+
+### `authenticateWithCode` — missing `redirectUri`
+
+**Wrong:**
+```typescript
+const result = await scalekit.authenticateWithCode(code);
+```
+
+**Correct:**
+```typescript
+const result = await scalekit.authenticateWithCode(code, redirectUri);
+```
+
+The `redirectUri` must exactly match the one used in `getAuthorizationUrl` AND what's registered in the Scalekit dashboard.
+
+### `getAuthorizationUrl` — missing `state` for CSRF
+
+**Wrong:**
+```typescript
+const authUrl = scalekit.getAuthorizationUrl(redirectUri);
+```
+
+**Correct:**
+```typescript
+import crypto from 'crypto';
+const state = crypto.randomBytes(32).toString('base64url');
+// Store state in session/cookie for validation in callback
+const authUrl = scalekit.getAuthorizationUrl(redirectUri, { state });
+```
+
+While `state` is technically optional, omitting it is a **CSRF vulnerability**. Always generate and validate it.
+
+### Go — missing `context.Context`
+
+**Wrong:**
+```go
+resp, err := client.AuthenticateWithCode(code, redirectUri, opts)
+```
+
+**Correct:**
+```go
+resp, err := client.AuthenticateWithCode(ctx, code, redirectUri, opts)
+```
+
+All Go network methods require `context.Context` as the first parameter.
+
+---
+
+## 5. Auth Flow Gaps
+
+### Missing callback handler
+
+If you see a login route that generates an auth URL but no corresponding callback route, the flow is incomplete. The callback MUST:
+1. Validate the `state` parameter against the stored value
+2. Call `authenticateWithCode(code, redirectUri)`
+3. Store the session (tokens + user info)
+4. Redirect to the application
+
+### Missing `state` validation in callback
+
+**Wrong:**
+```typescript
+app.get('/auth/callback', async (req, res) => {
+ const { code } = req.query;
+ const result = await scalekit.authenticateWithCode(code, redirectUri);
+ // ... store session
+});
+```
+
+**Correct:**
+```typescript
+app.get('/auth/callback', async (req, res) => {
+ const { code, state } = req.query;
+
+ const storedState = req.session.oauthState; // or from cookie
+ if (!state || state !== storedState) {
+ return res.status(403).send('CSRF validation failed');
+ }
+
+ const result = await scalekit.authenticateWithCode(code, redirectUri);
+ // ... store session
+});
+```
+
+### Incomplete logout — only clearing local session
+
+**Wrong:**
+```typescript
+app.post('/logout', (req, res) => {
+ req.session.destroy();
+ res.redirect('/');
+});
+```
+
+**Correct:**
+```typescript
+app.post('/logout', (req, res) => {
+ const logoutUrl = scalekit.getLogoutUrl({
+ idTokenHint: req.session.idToken,
+ postLogoutRedirectUri: 'https://yourapp.com',
+ });
+ req.session.destroy();
+ res.redirect(logoutUrl); // Ends IdP session too
+});
+```
+
+Without calling `getLogoutUrl()`, the user's IdP session persists and they get silently re-authenticated on next login.
+
+### Missing IdP-initiated login handling
+
+If the callback route doesn't check for `idp_initiated_login` query parameter, IdP-initiated SSO won't work:
+
+```typescript
+app.get('/auth/callback', async (req, res) => {
+ const { idp_initiated_login, code, state } = req.query;
+
+ if (idp_initiated_login) {
+ const claims = await scalekit.getIdpInitiatedLoginClaims(idp_initiated_login);
+ const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
+ connectionId: claims.connection_id,
+ organizationId: claims.organization_id,
+ loginHint: claims.login_hint,
+ ...(claims.relay_state && { state: claims.relay_state }),
+ });
+ return res.redirect(authUrl);
+ }
+
+ // Normal SP-initiated flow continues...
+});
+```
+
+---
+
+## 6. Security Anti-Patterns
+
+### `sameSite: 'strict'` on session cookies
+
+**Wrong:**
+```typescript
+res.cookie('session', data, { sameSite: 'strict', httpOnly: true, secure: true });
+```
+
+**Correct:**
+```typescript
+res.cookie('session', data, { sameSite: 'lax', httpOnly: true, secure: true });
+```
+
+OAuth callbacks are cross-site redirects from Scalekit back to your app. `strict` drops the cookie on that redirect, causing CSRF state mismatch errors on every login.
+
+### Missing `httpOnly` flag
+
+**Wrong:**
+```typescript
+res.cookie('session', data, { secure: true });
+```
+
+**Correct:**
+```typescript
+res.cookie('session', data, { httpOnly: true, secure: true, sameSite: 'lax' });
+```
+
+Without `httpOnly`, JavaScript can read the session cookie — XSS becomes session hijacking.
+
+### Open redirect via unvalidated `next` parameter
+
+**Wrong:**
+```typescript
+const next = req.query.next;
+res.redirect(next); // Attacker can set next=https://evil.com
+```
+
+**Correct:**
+```typescript
+const next = req.query.next;
+// Only allow relative paths
+if (!next || !next.startsWith('/') || next.startsWith('//')) {
+ return res.redirect('/dashboard');
+}
+res.redirect(next);
+```
+
+### Hardcoded client secret
+
+**Wrong:**
+```typescript
+const scalekit = new ScalekitClient(
+ 'https://myapp.scalekit.com',
+ 'skc_12345',
+ 'sks_secret_abc123' // NEVER hardcode secrets
+);
+```
+
+**Correct:**
+```typescript
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_CLIENT_ID!,
+ process.env.SCALEKIT_CLIENT_SECRET!
+);
+```
+
+### Webhook handler without signature verification
+
+**Wrong:**
+```typescript
+app.post('/webhooks', express.json(), (req, res) => {
+ const event = req.body; // Trusting unverified payload
+ handleEvent(event);
+ res.sendStatus(200);
+});
+```
+
+**Correct:**
+```typescript
+app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
+ const isValid = scalekit.verifyWebhookPayload(
+ process.env.SCALEKIT_WEBHOOK_SECRET!,
+ req.headers,
+ req.body.toString()
+ );
+
+ if (!isValid) {
+ return res.sendStatus(401);
+ }
+
+ const event = JSON.parse(req.body.toString());
+ handleEvent(event);
+ res.sendStatus(200);
+});
+```
+
+Note: The webhook body must be raw (not JSON-parsed) for signature verification to work.
+
+### Client-side navigation for OAuth redirect
+
+**Wrong:**
+```typescript
+// React / Next.js
+router.push(authUrl); // Client-side route change
+```
+
+**Correct:**
+```typescript
+window.location.href = authUrl; // Full page navigation required for OAuth
+```
+
+OAuth redirects are full HTTP redirects to an external domain (Scalekit/IdP). Client-side routing doesn't work.
+
+---
+
+## 7. Environment Variable Mistakes
+
+| Wrong | Correct | Issue |
+|-------|---------|-------|
+| `SCALEKIT_URL` | `SCALEKIT_ENV_URL` | Missing `ENV_` |
+| `SCALEKIT_SECRET` | `SCALEKIT_CLIENT_SECRET` | Missing `CLIENT_` |
+| `SCALEKIT_ID` | `SCALEKIT_CLIENT_ID` | Missing `CLIENT_` |
+| `SCALEKIT_CALLBACK_URL` | `SCALEKIT_REDIRECT_URI` | Wrong name entirely |
+| `http://myapp.scalekit.com` | `https://myapp.scalekit.com` | Must be HTTPS |
+| `https://myapp.scalekit.com/` | `https://myapp.scalekit.com` | No trailing slash |
+
+---
+
+## 8. Client Instantiation Mistakes
+
+### Creating a new client per request
+
+**Wrong:**
+```typescript
+app.get('/api/data', async (req, res) => {
+ const scalekit = new ScalekitClient(envUrl, clientId, clientSecret); // per-request!
+ // ...
+});
+```
+
+**Correct:**
+```typescript
+// Module-level singleton
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_CLIENT_ID!,
+ process.env.SCALEKIT_CLIENT_SECRET!
+);
+
+app.get('/api/data', async (req, res) => {
+ // Use the singleton
+ const result = await scalekit.validateAccessToken(token);
+});
+```
+
+The client manages its own token lifecycle and connection pooling. Creating it per request wastes resources and can hit rate limits.
+
+---
+
+## 9. Token Refresh Race Conditions
+
+When multiple browser tabs trigger token refresh simultaneously, the second request often fails because the first one already consumed the refresh token.
+
+**Mitigation pattern:**
+```typescript
+// Before refreshing, set a short-lived flag
+const REFRESH_LOCK_KEY = 'refresh_in_progress';
+
+async function refreshToken(session) {
+ if (session[REFRESH_LOCK_KEY]) return; // Another tab is refreshing
+
+ session[REFRESH_LOCK_KEY] = true;
+ try {
+ const result = await scalekit.refreshAccessToken(session.refreshToken);
+ session.accessToken = result.accessToken;
+ session.refreshToken = result.refreshToken;
+ } finally {
+ delete session[REFRESH_LOCK_KEY];
+ }
+}
+```
+
+---
+
+## 10. Missing Scopes
+
+### Refresh tokens require `offline_access` scope
+
+**Wrong:**
+```typescript
+const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
+ scopes: ['openid', 'profile', 'email'],
+});
+// Later: scalekit.refreshAccessToken(refreshToken) → fails because no refresh token was issued
+```
+
+**Correct:**
+```typescript
+const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
+ scopes: ['openid', 'profile', 'email', 'offline_access'],
+});
+```
+
+Without `offline_access`, the authorization server won't issue a refresh token.
\ No newline at end of file
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/references/REFERENCE.md b/plugins/saaskit/skills/scalekit-code-doctor/references/REFERENCE.md
new file mode 100644
index 0000000..5ecab18
--- /dev/null
+++ b/plugins/saaskit/skills/scalekit-code-doctor/references/REFERENCE.md
@@ -0,0 +1,503 @@
+# Scalekit API Reference — Compact Lookup
+
+This file contains every correct SDK method signature and REST endpoint. Use it as ground truth when generating or reviewing Scalekit code. If a method isn't listed here, do NOT assume it exists — verify against the live SDK source or `https://docs.scalekit.com/apis.md`.
+
+---
+
+## Client Initialization
+
+### Node.js (`@scalekit-sdk/node`)
+
+```typescript
+import { ScalekitClient } from '@scalekit-sdk/node';
+
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!, // string — environment URL
+ process.env.SCALEKIT_CLIENT_ID!, // string — client ID
+ process.env.SCALEKIT_CLIENT_SECRET! // string — client secret
+);
+```
+
+### Python (`scalekit-sdk-python`)
+
+```python
+from scalekit import ScalekitClient
+
+scalekit_client = ScalekitClient(
+ os.environ.get('SCALEKIT_ENV_URL'), # str — environment URL
+ os.environ.get('SCALEKIT_CLIENT_ID'), # str — client ID
+ os.environ.get('SCALEKIT_CLIENT_SECRET') # str — client secret
+)
+```
+
+### Go (`github.com/scalekit-inc/scalekit-sdk-go`)
+
+```go
+import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"
+
+client := scalekit.NewScalekitClient(
+ os.Getenv("SCALEKIT_ENV_URL"), // string — environment URL
+ os.Getenv("SCALEKIT_CLIENT_ID"), // string — client ID
+ os.Getenv("SCALEKIT_CLIENT_SECRET"), // string — client secret
+)
+```
+
+### Java (`com.scalekit:scalekit-sdk-java`)
+
+```java
+import com.scalekit.ScalekitClient;
+
+ScalekitClient client = new ScalekitClient(
+ System.getenv("SCALEKIT_ENV_URL"), // String — environment URL
+ System.getenv("SCALEKIT_CLIENT_ID"), // String — client ID
+ System.getenv("SCALEKIT_CLIENT_SECRET") // String — client secret
+);
+```
+
+---
+
+## Environment Variables
+
+| Variable | Purpose | Format |
+|----------|---------|--------|
+| `SCALEKIT_ENV_URL` | Environment URL | `https://.scalekit.com` (prod) or `https://.scalekit.dev` (dev) |
+| `SCALEKIT_CLIENT_ID` | Client ID | String from dashboard |
+| `SCALEKIT_CLIENT_SECRET` | Client secret | String from dashboard |
+| `SCALEKIT_REDIRECT_URI` | OAuth callback URL | Must exactly match dashboard config |
+| `SCALEKIT_WEBHOOK_SECRET` | Webhook signing secret | Format: `whsec_...` |
+
+Note: The REST API docs use `SCALEKIT_ENVIRONMENT_URL` in some examples. Both `SCALEKIT_ENV_URL` and `SCALEKIT_ENVIRONMENT_URL` are acceptable — just be consistent within a project.
+
+---
+
+## Auth Methods (called directly on the client)
+
+### Node.js
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `getAuthorizationUrl` | `(redirectUri: string, options?: AuthorizationUrlOptions) → string` | Authorization URL string |
+| `authenticateWithCode` | `(code: string, redirectUri: string, options?: AuthenticationOptions) → Promise` | Tokens + user info |
+| `getIdpInitiatedLoginClaims` | `(idpInitiatedLoginToken: string, options?: TokenValidationOptions) → Promise` | IDP login claims |
+| `validateAccessToken` | `(token: string, options?: TokenValidationOptions) → Promise` | Boolean |
+| `validateToken` | `(token: string, options?: TokenValidationOptions) → Promise` | Decoded JWT payload |
+| `verifyScopes` | `(token: string, requiredScopes: string[]) → boolean` | Boolean |
+| `getLogoutUrl` | `(options?: LogoutUrlOptions) → string` | Logout URL string |
+| `refreshAccessToken` | `(refreshToken: string) → Promise` | New tokens |
+| `verifyWebhookPayload` | `(secret: string, headers: Record, payload: string) → boolean` | Boolean |
+| `verifyInterceptorPayload` | `(secret: string, headers: Record, payload: string) → boolean` | Boolean |
+| `generateClientToken` | `(clientId: string, clientSecret: string) → Promise` | M2M access token |
+| `getClientAccessToken` | `() → Promise` | M2M access token (uses stored credentials) |
+
+**AuthorizationUrlOptions**: `scopes?: string[]`, `state?: string`, `nonce?: string`, `loginHint?: string`, `domainHint?: string`, `connectionId?: string`, `organizationId?: string`, `provider?: string`, `codeChallenge?: string`, `codeChallengeMethod?: string`, `prompt?: string`
+
+**LogoutUrlOptions**: `idTokenHint?: string`, `postLogoutRedirectUri?: string`, `state?: string`
+
+**AuthenticationOptions**: `codeVerifier?: string`
+
+### Python
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `get_authorization_url` | `(redirect_uri: str, options?: AuthorizationUrlOptions) → str` | Authorization URL string |
+| `authenticate_with_code` | `(code: str, redirect_uri: str, options?: CodeAuthenticationOptions) → dict` | Tokens + user info |
+| `get_idp_initiated_login_claims` | `(idp_initiated_login_token: str, options?: TokenValidationOptions) → IdpInitiatedLoginClaims` | IDP login claims |
+| `validate_access_token` | `(token: str, options?: TokenValidationOptions) → bool` | Boolean |
+| `get_logout_url` | `(options?: LogoutUrlOptions) → str` | Logout URL string |
+| `refresh_access_token` | `(refresh_token: str) → dict` | New tokens |
+| `verify_webhook_payload` | `(secret: str, headers: Dict[str, str], payload: str\|bytes) → bool` | Boolean |
+
+**AuthorizationUrlOptions** (Python): `scopes`, `state`, `nonce`, `login_hint`, `domain_hint`, `connection_id`, `organization_id`, `provider`, `prompt` — all `Optional[str]` (scopes is `Optional[list[str]]`)
+
+**LogoutUrlOptions** (Python): `id_token_hint`, `post_logout_redirect_uri`, `state` — all `Optional[str]`
+
+### Go
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `GetAuthorizationUrl` | `(redirectUri string, options AuthorizationUrlOptions) → (*url.URL, error)` | URL + error |
+| `AuthenticateWithCode` | `(ctx context.Context, code string, redirectUri string, options AuthenticationOptions) → (*AuthenticationResponse, error)` | Response + error |
+| `GetIdpInitiatedLoginClaims` | `(ctx context.Context, idpInitiatedLoginToken string) → (*IdpInitiatedLoginClaims, error)` | Claims + error |
+| `GetAccessTokenClaims` | `(ctx context.Context, accessToken string) → (*AccessTokenClaims, error)` | Claims + error |
+| `ValidateAccessToken` | `(ctx context.Context, accessToken string) → (bool, error)` | Boolean + error |
+| `RefreshAccessToken` | `(ctx context.Context, refreshToken string) → (*TokenResponse, error)` | Tokens + error |
+| `GetLogoutUrl` | `(options LogoutUrlOptions) → string` | Logout URL string |
+| `VerifyWebhookPayload` | `(secret string, headers map[string][]string, payload []byte) → bool` | Boolean |
+
+**Go AuthorizationUrlOptions fields**: `Scopes []string`, `State string`, `Nonce string`, `LoginHint string`, `DomainHint string`, `ConnectionId string`, `OrganizationId string`, `Provider string`, `CodeChallenge string`, `CodeChallengeMethod string`, `Prompt string`
+
+Note: Go methods take `context.Context` as the first parameter for network calls. `GetAuthorizationUrl` and `GetLogoutUrl` do NOT take context (they're local-only operations).
+
+### Java
+
+| Method | Signature | Returns |
+|--------|-----------|---------|
+| `getAuthorizationUrl` | `(redirectUri: String, options: AuthorizationUrlOptions) → String` | Authorization URL string |
+| `authenticateWithCode` | `(code: String, redirectUri: String, options: AuthenticationOptions) → AuthenticationResponse` | Tokens + user info |
+| `getIdpInitiatedLoginClaims` | `(idpInitiatedLoginToken: String) → IdpInitiatedLoginClaims` | Claims |
+| `validateToken` | `(token: String) → Claims` | JWT Claims |
+| `getLogoutUrl` | `(options: LogoutUrlOptions) → String` | Logout URL string |
+
+---
+
+## Sub-client Methods
+
+### Node.js sub-clients (accessed via `client..`)
+
+**client.organization**
+| Method | Signature |
+|--------|-----------|
+| `createOrganization` | `(name: string, options?) → Promise` |
+| `getOrganization` | `(id: string) → Promise` |
+| `getOrganizationByExternalId` | `(externalId: string) → Promise` |
+| `listOrganizations` | `(options?) → Promise` |
+| `updateOrganization` | `(id: string, organization) → Promise` |
+| `deleteOrganization` | `(id: string) → Promise` |
+| `generatePortalLink` | `(organizationId: string, features?) → Promise` |
+| `updateOrganizationSettings` | `(id: string, settings) → Promise` |
+
+**client.connection**
+| Method | Signature |
+|--------|-----------|
+| `getConnection` | `(id: string) → Promise` |
+| `listConnections` | `(options?) → Promise` |
+| `listConnectionsByDomain` | `(domain: string, options?) → Promise` |
+| `enableConnection` | `(connectionId: string) → Promise` |
+| `disableConnection` | `(connectionId: string) → Promise` |
+
+**client.domain**
+| Method | Signature |
+|--------|-----------|
+| `createDomain` | `(domain: string) → Promise` |
+| `getDomain` | `(domain: string) → Promise` |
+| `listDomains` | `(options?) → Promise` |
+| `deleteDomain` | `(domain: string) → Promise` |
+
+**client.user**
+| Method | Signature |
+|--------|-----------|
+| `createUser` | `(organizationId: string, user) → Promise` |
+| `createUserAndMembership` | `(organizationId: string, request) → Promise` |
+| `getUser` | `(id: string) → Promise` |
+| `listUsers` | `(options?) → Promise` |
+| `listOrganizationUsers` | `(organizationId: string, options?) → Promise` |
+| `updateUser` | `(id: string, user) → Promise` |
+| `deleteUser` | `(id: string) → Promise` |
+| `searchUsers` | `(options) → Promise` |
+| `searchOrganizationUsers` | `(organizationId: string, options) → Promise` |
+
+**client.directory**
+| Method | Signature |
+|--------|-----------|
+| `listDirectories` | `(organizationId: string) → Promise` |
+| `getDirectory` | `(organizationId: string, directoryId: string) → Promise` |
+| `listDirectoryUsers` | `(organizationId: string, directoryId: string, options?) → Promise` |
+| `listDirectoryGroups` | `(organizationId: string, directoryId: string, options?) → Promise` |
+| `enableDirectory` | `(organizationId: string, directoryId: string) → Promise` |
+| `disableDirectory` | `(organizationId: string, directoryId: string) → Promise` |
+
+**client.role**
+| Method | Signature |
+|--------|-----------|
+| `createRole` | `(role) → Promise` |
+| `getRole` | `(roleId: string) → Promise` |
+| `listRoles` | `(options?) → Promise` |
+| `updateRole` | `(roleId: string, role) → Promise` |
+| `deleteRole` | `(roleId: string) → Promise` |
+
+**client.permission**
+| Method | Signature |
+|--------|-----------|
+| `createPermission` | `(permission) → Promise` |
+| `listPermissions` | `(options?) → Promise` |
+| `updatePermission` | `(permissionId: string, permission) → Promise` |
+| `deletePermission` | `(permissionId: string) → Promise` |
+
+**client.session**
+| Method | Signature |
+|--------|-----------|
+| `getSession` | `(sessionId: string) → Promise` |
+| `getUserSessions` | `(userId: string, options?) → Promise` |
+| `revokeSession` | `(sessionId: string) → Promise` |
+| `revokeAllUserSessions` | `(userId: string) → Promise` |
+
+**client.connectedAccounts**
+| Method | Signature |
+|--------|-----------|
+| `listConnectedAccounts` | `(options?) → Promise` |
+| `getConnectedAccountAuth` | `(options) → Promise` |
+| `createConnectedAccount` | `(request) → Promise` |
+| `updateConnectedAccount` | `(request) → Promise` |
+| `deleteConnectedAccount` | `(request) → Promise` |
+
+**client.tools**
+| Method | Signature |
+|--------|-----------|
+| `executeTool` | `(request) → Promise` |
+
+### Python sub-clients (accessed via `client..`)
+
+Python uses `snake_case` method names. **Important**: Some Python sub-client names are **plural** while Node uses singular. This is a common source of bugs.
+
+| Node.js | Python | Difference |
+|---------|--------|------------|
+| `client.user` | `client.users` | Plural in Python |
+| `client.role` | `client.roles` | Plural in Python |
+| `client.permission` | `client.permissions` | Plural in Python |
+| `client.session` | `client.sessions` | Plural in Python |
+| `client.organization` | `client.organization` | Same |
+| `client.connection` | `client.connection` | Same |
+| `client.domain` | `client.domain` | Same |
+| `client.directory` | `client.directory` | Same |
+| `client.connectedAccounts` | `client.connected_accounts` | snake_case in Python |
+
+Methods:
+- `client.organization.create_organization(organization)`
+- `client.organization.get_organization(organization_id)`
+- `client.organization.list_organizations(page_size, page_token?)`
+- `client.organization.update_organization(organization_id, organization)`
+- `client.organization.delete_organization(organization_id)`
+- `client.organization.generate_portal_link(organization_id, features?)`
+- `client.connection.list_connections(organization_id, include?)`
+- `client.connection.get_connection(organization_id, connection_id)`
+- `client.connection.enable_connection(organization_id, connection_id)`
+- `client.connection.disable_connection(organization_id, connection_id)`
+- `client.domain.create_domain(organization_id, domain_name)`
+- `client.domain.list_domains(organization_id)`
+- `client.domain.delete_domain(organization_id, domain_id)`
+- `client.directory.list_directories(organization_id)`
+- `client.directory.get_directory(organization_id, directory_id)`
+- `client.directory.list_directory_users(organization_id, directory_id, options?)`
+- `client.directory.list_directory_groups(organization_id, directory_id, options?)`
+- `client.users.create_user(organization_id, user)`
+- `client.users.get_user(user_id)`
+- `client.users.list_users(options?)`
+- `client.users.update_user(user_id, user)`
+- `client.users.delete_user(user_id)`
+- `client.roles.create_role(role)`
+- `client.roles.list_roles(options?)`
+- `client.roles.update_role(role_id, role)`
+- `client.roles.delete_role(role_id)`
+- `client.permissions.create_permission(permission)`
+- `client.permissions.list_permissions(options?)`
+- `client.sessions.get_session(session_id)`
+- `client.sessions.get_user_sessions(user_id, options?)`
+- `client.sessions.revoke_session(session_id)`
+- `client.sessions.revoke_all_user_sessions(user_id)`
+
+Additional Python-only methods on client:
+- `client.validate_access_token_and_get_claims(token, options?) → dict` — validates and returns decoded claims
+- `client.verify_scopes(token, required_scopes) → bool` — checks scopes, raises on missing
+- `client.generate_client_token(client_id, client_secret, scopes?) → str` — M2M token generation
+- `client.get_client_access_token() → str` — M2M token using stored credentials
+- `client.verify_interceptor_payload(secret, headers, payload) → bool` — interceptor signature verification
+
+Note: Python connection/domain/directory methods often require `organization_id` as the first parameter, unlike Node which uses option objects.
+
+### Go sub-clients
+
+Go uses `PascalCase` and typed request/response objects:
+- `client.Organization().CreateOrganization(ctx, request)`
+- `client.Organization().GetOrganization(ctx, organizationId)`
+- `client.Organization().ListOrganizations(ctx, pageSize, pageToken)`
+- `client.Organization().UpdateOrganization(ctx, organizationId, request)`
+- `client.Organization().DeleteOrganization(ctx, organizationId)`
+- `client.Organization().GeneratePortalLink(ctx, organizationId, features)`
+- `client.Connection().GetConnection(ctx, organizationId, connectionId)`
+- `client.Connection().ListConnections(ctx, organizationId)`
+- `client.Connection().EnableConnection(ctx, organizationId, connectionId)`
+- `client.Connection().DisableConnection(ctx, organizationId, connectionId)`
+- `client.Domain().CreateDomain(ctx, organizationId, domainName)`
+- `client.Domain().ListDomains(ctx, organizationId)`
+- `client.Domain().DeleteDomain(ctx, organizationId, domainId)`
+- `client.Directory().ListDirectories(ctx, organizationId)`
+- `client.Directory().GetDirectory(ctx, organizationId, directoryId)`
+- `client.Directory().ListDirectoryUsers(ctx, organizationId, directoryId, options)`
+- `client.Directory().ListDirectoryGroups(ctx, organizationId, directoryId, options)`
+- `client.User().CreateUser(ctx, organizationId, request)`
+- `client.User().GetUser(ctx, userId)`
+- `client.User().ListUsers(ctx, options)`
+- `client.User().UpdateUser(ctx, userId, request)`
+- `client.User().DeleteUser(ctx, userId)`
+- `client.Role().ListRoles(ctx)`
+- `client.Role().CreateRole(ctx, request)`
+- `client.Session().GetSession(ctx, sessionId)`
+- `client.Session().RevokeSession(ctx, sessionId)`
+- `client.Session().RevokeAllUserSessions(ctx, userId)`
+
+### Java sub-clients
+
+Java uses accessor methods that return typed clients:
+- `client.organizations().create(request) → CreateOrganizationResponse`
+- `client.organizations().getById(organizationId) → Organization`
+- `client.organizations().getByExternalId(externalId) → Organization`
+- `client.organizations().list(pageSize, pageToken) → ListOrganizationsResponse`
+- `client.organizations().update(organizationId, request) → Organization`
+- `client.organizations().delete(organizationId)`
+- `client.organizations().generatePortalLink(organizationId, features) → Link`
+- `client.connections().listConnectionsByOrganization(organizationId) → ListConnectionsResponse`
+- `client.connections().getConnection(organizationId, connectionId) → GetConnectionResponse`
+- `client.connections().enableConnection(organizationId, connectionId)`
+- `client.connections().disableConnection(organizationId, connectionId)`
+- `client.domains().listDomainsByOrganizationId(organizationId) → ListDomainsResponse`
+- `client.domains().createDomain(organizationId, domainName) → CreateDomainResponse`
+- `client.domains().deleteDomain(organizationId, domainId)`
+- `client.directories().listDirectories(organizationId) → ListDirectoriesResponse`
+- `client.directories().getDirectory(organizationId, directoryId) → GetDirectoryResponse`
+- `client.directories().listDirectoryUsers(organizationId, directoryId) → ListDirectoryUsersResponse`
+- `client.directories().listDirectoryGroups(organizationId, directoryId) → ListDirectoryGroupsResponse`
+- `client.users().getUser(userId) → GetUserResponse`
+- `client.users().listUsers(options) → ListUsersResponse`
+- `client.users().createUser(organizationId, request) → CreateUserResponse`
+- `client.users().createUserAndMembership(organizationId, request) → CreateUserAndMembershipResponse`
+- `client.users().updateUser(userId, request) → UpdateUserResponse`
+- `client.users().deleteUser(userId)`
+- `client.roles().listRoles() → ListRolesResponse`
+- `client.roles().createRole(request) → CreateRoleResponse`
+- `client.roles().updateRole(roleId, request) → UpdateRoleResponse`
+- `client.roles().deleteRole(roleId)`
+- `client.permissions().listPermissions() → ListPermissionsResponse`
+- `client.permissions().createPermission(request) → CreatePermissionResponse`
+- `client.sessions().getSession(sessionId) → SessionDetails`
+- `client.sessions().getUserSessions(userId, filter) → UserSessionDetails`
+- `client.sessions().revokeSession(sessionId)`
+- `client.sessions().revokeAllUserSessions(userId)`
+
+Note: Java does NOT yet support Connected Accounts, Tools, or Actions in the public API.
+
+---
+
+## REST API Endpoints
+
+Base URL: `https://.scalekit.com` (production) or `https://.scalekit.dev` (development)
+
+Authentication: Bearer token from `POST /oauth/token` with `client_credentials` grant.
+
+Endpoints are grouped by product suite: **SaaSKit** (authentication, SSO, SCIM, RBAC, sessions) and **AgentKit** (connections, tool calling, MCP auth).
+
+### Token endpoint
+```
+POST /oauth/token
+Content-Type: application/x-www-form-urlencoded
+
+client_id={client_id}&client_secret={client_secret}&grant_type=client_credentials
+```
+
+### AgentKit — Connected Accounts
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/connected_accounts` | List connected accounts |
+| POST | `/api/v1/connected_accounts` | Create a connected account |
+| PUT | `/api/v1/connected_accounts` | Update connected account credentials |
+| POST | `/api/v1/connected_accounts:delete` | Delete a connected account |
+| GET | `/api/v1/connected_accounts/auth` | Get connected account auth details |
+| GET | `/api/v1/connected_accounts:search` | Search connected accounts |
+| POST | `/api/v1/connected_accounts/magic_link` | Generate authentication magic link |
+| POST | `/api/v1/connected_accounts/user/verify` | Verify connected account user |
+
+### SaaSKit — Connections (SSO)
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/connections` | List connections |
+
+### SaaSKit — Organizations
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/organizations` | List organizations |
+| POST | `/api/v1/organizations` | Create an organization |
+| GET | `/api/v1/organizations/{id}` | Get organization details |
+| PATCH | `/api/v1/organizations/{id}` | Update organization |
+| DELETE | `/api/v1/organizations/{id}` | Delete an organization |
+| PUT | `/api/v1/organizations/{id}/portal_links` | Generate admin portal link |
+| PATCH | `/api/v1/organizations/{id}/settings` | Toggle organization settings |
+
+### SaaSKit — Roles
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/organizations/{org_id}/roles` | List organization roles |
+| POST | `/api/v1/organizations/{org_id}/roles` | Create organization role |
+| GET | `/api/v1/organizations/{org_id}/roles/{role_name}` | Get role details |
+| PUT | `/api/v1/organizations/{org_id}/roles/{role_name}` | Update role |
+| DELETE | `/api/v1/organizations/{org_id}/roles/{role_name}` | Delete role |
+| PATCH | `/api/v1/organizations/{org_id}/roles:set_defaults` | Set default roles |
+
+### SaaSKit — Users & Memberships
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/users` | List users |
+| POST | `/api/v1/users` | Create a user |
+| GET | `/api/v1/users/{id}` | Get user details |
+| PATCH | `/api/v1/users/{id}` | Update user |
+| DELETE | `/api/v1/users/{id}` | Delete user |
+| GET | `/api/v1/users:search` | Search users |
+| GET | `/api/v1/organizations/{org_id}/users` | List organization users |
+| GET | `/api/v1/organizations/{org_id}/users:search` | Search organization users |
+| POST | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Add user to organization |
+| DELETE | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Remove user from organization |
+| PATCH | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Update membership |
+| PATCH | `/api/v1/invites/organizations/{organization_id}/users/{id}/resend` | Resend invitation |
+
+### SaaSKit — Sessions
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/users/{user_id}/sessions` | Get user sessions |
+| POST | `/api/v1/users/{user_id}/sessions:revoke_all` | Revoke all user sessions |
+| POST | `/api/v1/sessions/{session_id}:revoke` | Revoke a session |
+
+### AgentKit — Tools
+| Method | Path | Description |
+|--------|------|-------------|
+| POST | `/api/v1/execute_tool` | Execute a tool using a connected account |
+
+### SaaSKit — Organization API Clients (M2M)
+| Method | Path | Description |
+|--------|------|-------------|
+| GET | `/api/v1/organizations/{organization_id}/clients` | List org API clients |
+| POST | `/api/v1/organizations/{organization_id}/clients` | Create org API client |
+| GET | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Get org API client |
+| DELETE | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Delete org API client |
+| PATCH | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Update org API client |
+
+---
+
+## Error Handling
+
+### Node.js exception hierarchy
+```
+ScalekitException (base)
+├── ScalekitValidateTokenFailureException
+├── ScalekitServerException (HTTP 400-599)
+│ ├── properties: httpStatus, errorCode, message, errDetails
+│ └── Specific subclasses for 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, 504
+└── WebhookVerificationError
+```
+
+Import: `import { ScalekitServerException } from '@scalekit-sdk/node'`
+
+### Python exceptions
+```
+ScalekitException (base)
+```
+
+### Go errors
+All methods return `(result, error)`. Check `err != nil` for all network calls.
+
+### Java exceptions
+All methods may throw checked exceptions. Wrap in try-catch.
+
+---
+
+## Common Token Claims
+
+Access tokens from Scalekit contain these standard claims:
+- `sub` — User ID
+- `email` — User email
+- `name` — Display name
+- `org_id` — Organization ID
+- `roles` — Array of role names
+- `permissions` — Array of permission strings (also available at `https://scalekit.com/permissions` or `scalekit:permissions` claim paths)
+
+Permission claims should be checked in this priority order:
+1. `permissions` claim
+2. `https://scalekit.com/permissions` claim
+3. `scalekit:permissions` claim
\ No newline at end of file
diff --git a/plugins/saaskit/skills/testing-auth-setup/SKILL.md b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
new file mode 100644
index 0000000..4db0bd2
--- /dev/null
+++ b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
@@ -0,0 +1,55 @@
+---
+name: testing-auth-setup
+description: Validates a Scalekit auth integration by running the dryrun CLI against a live environment. Use when the user says "test my auth", "verify SSO setup", "check my login flow", "dryrun", or wants to confirm their Scalekit credentials and configuration are working.
+argument-hint: "[fsa|sso]"
+---
+
+# Testing Auth Setup
+
+Runs the Scalekit dryrun CLI to validate that your auth integration is correctly configured against a live environment.
+
+## Modes
+
+| Mode | What it tests | When to use |
+|------|--------------|-------------|
+| `fsa` | Full-stack auth login flow | User is setting up or verifying login, callback, and session handling |
+| `sso` | Enterprise SSO flow | User is setting up or verifying SAML/OIDC SSO with an identity provider |
+
+## Prerequisites
+
+Before running, confirm these environment variables are available:
+
+- `SCALEKIT_ENV_URL` — your Scalekit environment URL
+- `SCALEKIT_CLIENT_ID` — your client ID from app.scalekit.com → Settings
+
+If either is missing, ask the user to provide them. Do not write credentials into source-controlled files.
+
+## Running the test
+
+### Full-stack auth (fsa)
+
+```bash
+npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=fsa
+```
+
+### Enterprise SSO
+
+Requires an `organization_id` — ask for it if not provided.
+
+```bash
+npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=sso --organization_id=
+```
+
+## Choosing the mode
+
+If the user doesn't specify a mode:
+
+1. Check the project context — if there's SSO configuration (identity providers, SAML metadata), suggest `sso`.
+2. Otherwise default to `fsa` as the most common starting point.
+3. If ambiguous, ask which mode to use.
+
+## After running
+
+- Show the command output.
+- Explain what passed and what failed in plain language.
+- If the test fails, suggest specific next steps based on the error (missing redirect URI, invalid credentials, organization not found, etc.).
\ No newline at end of file
diff --git a/scripts/install.sh b/scripts/install.sh
new file mode 100755
index 0000000..6adce7d
--- /dev/null
+++ b/scripts/install.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+if ! command -v copilot >/dev/null 2>&1; then
+ echo "GitHub Copilot CLI is not installed or not on PATH." >&2
+ echo "Install Copilot CLI first, then re-run this installer." >&2
+ exit 1
+fi
+
+MARKETPLACE_SLUG="${COPILOT_AUTHSTACK_MARKETPLACE:-scalekit-inc/github-copilot-authstack}"
+MARKETPLACE_NAME="${MARKETPLACE_SLUG##*/}"
+OLD_PLUGINS=("agent-auth" "full-stack-auth" "mcp-auth" "modular-sso" "modular-scim")
+
+echo "Installing Scalekit Auth Stack for GitHub Copilot"
+echo "Marketplace: $MARKETPLACE_SLUG"
+echo
+
+if copilot plugin marketplace add "$MARKETPLACE_SLUG" 2>/dev/null; then
+ FRESH_INSTALL=true
+else
+ echo "Marketplace already registered."
+ FRESH_INSTALL=false
+fi
+
+# Remove old plugin names from v1.x (now consolidated into agentkit + saaskit)
+for old in "${OLD_PLUGINS[@]}"; do
+ copilot plugin uninstall "${old}@${MARKETPLACE_NAME}" 2>/dev/null || true
+done
+
+if [[ "$FRESH_INSTALL" == "true" ]]; then
+ copilot plugin install "agentkit@${MARKETPLACE_NAME}"
+ copilot plugin install "saaskit@${MARKETPLACE_NAME}"
+else
+ echo "Updating plugins..."
+ copilot plugin update agentkit
+ copilot plugin update saaskit
+fi
+
+cat <