-
Notifications
You must be signed in to change notification settings - Fork 11
Plugin #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Plugin #22
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
e2faba6
feat: add stackone-connector-builder plugin with full OAS schema refe…
CameronCarlin 15fae39
feat: add import-schema skill and wire into choose-schema workflow
CameronCarlin 6c8d0ae
fix: collapse redundant schema path C into import-schema (B)
CameronCarlin 7e5359a
fix: Making plugins for new users.
CameronCarlin 2e0bc10
feat: update claude.md
CameronCarlin e69c367
Merge branch 'main' of https://github.com/StackOneHQ/connectors-template
CameronCarlin 7a3a3b2
fix: restoring some changes in line with new skills. Fixing plugins.
CameronCarlin 01f81a0
fix: Addressing all comments.
CameronCarlin 623fbc6
Delete docs/plans/2026-03-20-connector-builder-plugins-implementation.md
CameronCarlin 1fb069e
Delete docs/plans directory
CameronCarlin c73a92e
fix: Splitting examples to be accurate
CameronCarlin c58d6ef
Merge branch 'plugin' of https://github.com/StackOneHQ/connectors-tem…
CameronCarlin 27c4f04
fix: plugin fixes
CameronCarlin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
.claude/plugins/stackone-connector-builder/.claude-plugin/plugin.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "name": "stackone-connector-builder", | ||
| "version": "1.0.0", | ||
| "description": "Interactive wizard for building generic Falcon connectors. Guides builders through provider setup, authentication, action discovery (scoped or maximal), config generation, validation, and testing with full cleanup.", | ||
| "author": { | ||
| "name": "StackOne", | ||
| "email": "engineering@stackone.com" | ||
| }, | ||
| "license": "MIT", | ||
| "keywords": ["connector", "falcon", "generic", "stackone", "builder", "discovery"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # stackone-connector-builder | ||
|
|
||
| Claude Code plugin for building generic Falcon connectors that return raw provider API responses. | ||
|
|
||
| ## When to use this plugin | ||
|
|
||
| Use **this plugin** when you want direct API access — actions use `actionType: custom` and return the provider's response as-is, with no schema normalisation. | ||
|
|
||
| Use **`stackone-unified-builder`** (via `/build-unified-connector`) when your connector needs to map provider data to a StackOne unified schema (HRIS, ATS, CRM, etc.). | ||
|
|
||
| ## Workflow | ||
|
|
||
| | Step | Command | What it does | | ||
| |------|---------|--------------| | ||
| | 1 | `/setup-connector` | Provider setup, checks StackOne index, CLI pull or scaffold | | ||
| | 2 | `/configure-auth` | Auth configuration (API key, OAuth2, Basic Auth, custom) | | ||
| | 3 | `/discover-actions` | Choose scoped or maximal discovery (MCP-powered) | | ||
| | 4 | `/build-config` | Generate YAML with `actionType: custom` for all actions | | ||
| | 5 | `/validate-connector` | Validate YAML structure | | ||
| | 6 | `/test-connector` | Live test + automatic cleanup of test records | | ||
|
|
||
| ## Quick start | ||
|
|
||
| ``` | ||
| /build-connector | ||
| ``` | ||
|
|
||
| This runs the full workflow from start to finish, guiding you through each step. | ||
|
|
||
| ## Key features | ||
|
|
||
| - **Session persistence** — progress is saved to `.connector-build-session.json` so you can pause and resume at any step | ||
| - **Two discovery modes**: | ||
| - *Scoped* — describe your use case and relevant endpoints are found via vector search | ||
| - *Maximal* — discovers all provider endpoints via MCP (async, 5–15 min); use when you want full coverage | ||
| - **Test cleanup** — every record created during testing is tracked and deleted afterwards; any records that cannot be deleted are reported | ||
| - **Credential security** — `scramble_credentials` is always called after testing to invalidate live credentials | ||
|
|
||
| ## MCP tools used | ||
|
|
||
| | Tool | Purpose | | ||
| |------|---------| | ||
| | `map_provider_key`, `get_provider_actions` | Check StackOne connector index | | ||
| | `discover_actions`, `get_discover_actions_task_status` | Maximal endpoint discovery (async) | | ||
| | `analyze_versioning` | Detect API versioning patterns | | ||
| | `vector_search` | Scoped discovery — find relevant endpoints by description | | ||
| | `test_actions`, `get_test_actions_task_status` | Automated live testing (async) | | ||
| | `scramble_credentials` | Invalidate credentials after testing | | ||
|
|
||
| --- | ||
|
|
||
| For unified connectors (HRIS/ATS/CRM/etc), see the `stackone-unified-builder` plugin and `/build-unified-connector`. |
301 changes: 301 additions & 0 deletions
301
.claude/plugins/stackone-connector-builder/references/actions-and-steps.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,301 @@ | ||
| # Actions and Steps Reference | ||
|
|
||
| Technical reference for writing action YAML files — covering action structure, inputs, step functions, expressions, and result mapping. | ||
|
|
||
| ## Action Structure | ||
|
|
||
| ### Required Fields | ||
| - `actionId`: Unique identifier | ||
| - `categories`: List of categories for StackOne UI | ||
| - `actionType`: `custom` (default for non-unified) or `list|get|create|update|delete` (unified only) | ||
| - `label`: Human-readable name | ||
| - `description`: Short description (shown in UI) | ||
| - `steps`: List of step functions | ||
| - `result`: Final output | ||
|
|
||
| ### Optional Fields | ||
| - `details`: Longer description (tool description, rate limits, required permissions) | ||
| - `resources`: Action-specific documentation URLs | ||
| - `examples`: Input/output demonstration pairs | ||
| - `inputs`: Request parameters | ||
| - `requiredScopes`: Space-separated OAuth scopes (must be defined in `scopeDefinitions`). Use most restrictive scope. | ||
| - `entrypointUrl` / `entrypointHttpMethod`: **Unified actions ONLY** (DO NOT USE for non-unified) | ||
|
|
||
| ## Inputs | ||
|
|
||
| For non-unified actions: inputs must match EXACTLY the provider's request parameters. DO NOT create inputs that don't exist in the provider API. Ignore deprecated fields. | ||
|
|
||
| ### Supported Types | ||
| `string`, `number`, `boolean`, `datetime_string`, `object`, `enum` | ||
|
|
||
| **Never use `type: array`** — always use `array: true` with element type. | ||
|
|
||
| ### Input Examples | ||
|
|
||
| **Basic string/number:** | ||
| ```yaml | ||
| inputs: | ||
| - name: userId | ||
| description: User identifier | ||
| type: string | ||
| in: path | ||
| required: true | ||
| ``` | ||
|
|
||
| **Object:** | ||
| ```yaml | ||
| inputs: | ||
| - name: filter | ||
| description: Filter object | ||
| type: object | ||
| in: body | ||
| required: true | ||
| properties: | ||
| - name: name | ||
| description: Filter by name | ||
| type: string | ||
| required: false | ||
| ``` | ||
|
|
||
| **Array:** | ||
| ```yaml | ||
| inputs: | ||
| - name: userIds | ||
| description: Array of user IDs | ||
| type: string | ||
| array: true | ||
| in: body | ||
| required: true | ||
| ``` | ||
|
|
||
| **Enum:** | ||
| ```yaml | ||
| inputs: | ||
| - name: status | ||
| description: Employment status | ||
| type: enum | ||
| required: true | ||
| in: query | ||
| oneOf: | ||
| values: | ||
| - active | ||
| - inactive | ||
| - terminated | ||
| ``` | ||
|
|
||
| ### Input locations (`in` field) | ||
| - `query` — URL query parameter | ||
| - `body` — request body | ||
| - `path` — URL path parameter (referenced via `${inputs.fieldName}` in URL) | ||
| - `headers` — request header | ||
|
|
||
| ## Expression Formats | ||
|
|
||
| ### 1. JSONPath (`$.path.to.field`) — PREFERRED | ||
| For direct references without string construction: | ||
| - Credentials: `$.credentials.apiKey` | ||
| - Inputs: `$.inputs.userId` | ||
| - Step output: `$.steps.fetch_users.output.data` | ||
|
|
||
| ### 2. String Interpolation (`${...}`) | ||
| For embedding dynamic values in strings: | ||
| - URLs: `/users/${inputs.userId}/posts/${inputs.postId}` | ||
| - Domains: `https://${credentials.domain}.api.com` | ||
|
|
||
| ### 3. JEXL Expressions (`'{{...}}'`) | ||
| For conditional logic, transformations. **Wrap in single quotes.** | ||
| - Conditionals: `'{{present(inputs.includeInactive)}}'` | ||
| - Ternary: `'{{$.status == "active" ? "enabled" : "disabled"}}'` | ||
| - String manipulation: `'{{inputs.name.toUpperCase()}}'` | ||
|
|
||
| **IMPORTANT:** | ||
| - For `value` fields: prefer JSONPath `$.inputs.fieldName` for simple references. JEXL `'{{...}}'` is also supported in `value` fields when you need transformations, conditionals, or string manipulation. | ||
| - For `condition` fields: use JEXL `'{{present(inputs.fieldName)}}'` | ||
|
|
||
| ## Step Functions | ||
|
|
||
| Every step MUST have a `description` field. | ||
|
|
||
| ### `request` — Standard HTTP request | ||
|
|
||
| ```yaml | ||
| steps: | ||
| - stepId: fetch_users | ||
| description: List users from the API | ||
| stepFunction: | ||
| functionName: request | ||
| parameters: | ||
| url: '/users' | ||
| method: get | ||
| args: | ||
| - name: showInactive | ||
| value: $.inputs.showInactive | ||
| in: query | ||
| condition: '{{present(inputs.showInactive)}}' | ||
| ``` | ||
|
|
||
| Always use `args` for parameters (never direct `body` field). | ||
|
|
||
| **Custom headers for `authorization.type: none`:** | ||
| ```yaml | ||
| args: | ||
| - name: X-API-Key | ||
| value: $.credentials.customKey | ||
| in: headers | ||
| ``` | ||
|
|
||
| **Raw array bodies** — when API requires `[...]` instead of `{...}`: | ||
| ```yaml | ||
| args: | ||
| - name: events | ||
| value: $.inputs.events | ||
| in: body | ||
| spread: true | ||
| ``` | ||
|
|
||
| **Custom error mapping:** | ||
| ```yaml | ||
| customErrors: | ||
| - receivedStatus: 404 | ||
| targetStatus: 400 | ||
| message: 'Custom error message' | ||
| ``` | ||
|
|
||
| ### `paginated_request` — Cursor-based pagination | ||
|
|
||
| Only use if provider supports cursor/offset pagination. Otherwise use `request`. | ||
|
|
||
| ```yaml | ||
| steps: | ||
| - stepId: list_records | ||
| description: Fetch records with pagination | ||
| stepFunction: | ||
| functionName: paginated_request | ||
| parameters: | ||
| url: "/records" | ||
| method: get | ||
| response: | ||
| dataKey: results | ||
| nextKey: nextCursor | ||
| iterator: | ||
| key: cursor | ||
| in: query | ||
| ``` | ||
|
|
||
| ### `soap_request` — SOAP API calls | ||
|
|
||
| ```yaml | ||
| steps: | ||
| - stepId: get_employee | ||
| description: Fetch employee via SOAP | ||
| stepFunction: | ||
| functionName: soap_request | ||
| parameters: | ||
| url: /EmployeeService | ||
| method: post | ||
| soapOperation: GetEmployee | ||
| soapAction: http://example.com/soap/GetEmployee | ||
| useSoapContext: false | ||
| namespaces: | ||
| - namespaceIdentifier: emp | ||
| namespace: http://example.com/employees | ||
| args: | ||
| - name: EmployeeId | ||
| value: ${inputs.employee_id} | ||
| in: body | ||
| ``` | ||
|
|
||
| Key parameters: | ||
| - `soapOperation`: SOAP operation name | ||
| - `soapAction`: SOAP action URI | ||
| - `namespaces`: XML namespace definitions | ||
| - `useSoapContext`: Set to `false` when provider expects payload as-is | ||
| - Prefix XML attributes with `@_` (e.g., `@_xsi:type`) | ||
|
|
||
| ### Other Step Functions | ||
| - `group_data`: Groups data from multiple steps | ||
| - `map_fields`: Maps using `fieldConfigs` (unified actions only) | ||
| - `typecast`: Applies types from `fieldConfigs` (unified actions only) | ||
|
|
||
| ## Field Configs (Unified Actions Only) | ||
|
|
||
| NOT required for non-unified connectors. Maps provider response to StackOne unified schema: | ||
|
|
||
| ```yaml | ||
| fieldConfigs: | ||
| - targetFieldKey: id | ||
| expression: $.accountId | ||
| type: string | ||
| - targetFieldKey: type | ||
| expression: $.accountType | ||
| type: enum | ||
| enumMapper: | ||
| matcher: | ||
| - matchExpression: '{{$.accountType == "atlassian"}}' | ||
| value: agent | ||
| - matchExpression: '{{$.accountType == "app"}}' | ||
| value: bot | ||
| - targetFieldKey: active | ||
| expression: $.active | ||
| type: boolean | ||
| ``` | ||
|
|
||
| ## Result Mapping | ||
|
|
||
| ```yaml | ||
| # Read response | ||
| result: | ||
| data: $.steps.fetch_users.output.data | ||
|
|
||
| # Write response | ||
| result: | ||
| message: Resource updated successfully | ||
| data: | ||
| id: $.inputs.id | ||
| ``` | ||
|
|
||
| ## GraphQL Patterns | ||
|
|
||
| Reference: `linear` connector | ||
|
|
||
| **Input structure — always use nested `variables` object:** | ||
| ```yaml | ||
| inputs: | ||
| - name: variables | ||
| description: Variables for the query | ||
| type: object | ||
| in: body | ||
| properties: | ||
| - name: first | ||
| description: Number of items | ||
| type: number | ||
| required: false | ||
| - name: filter | ||
| description: Filter object | ||
| type: object | ||
| required: false | ||
| ``` | ||
|
|
||
| **Request:** | ||
| ```yaml | ||
| args: | ||
| - name: Content-Type | ||
| value: application/json | ||
| in: headers | ||
| - name: query | ||
| value: "query($first: Int) { resources(first: $first) { nodes { id name } } }" | ||
| in: body | ||
| - name: variables | ||
| in: body | ||
| condition: "{{present(inputs.variables)}}" | ||
| value: | ||
| { first: $.inputs.variables.first } | ||
| ``` | ||
|
|
||
| **IMPORTANT for nested objects:** When querying nested objects, ONLY return the `id` field if a separate action exists to fetch the full object. Don't return full nested objects. | ||
|
|
||
| **Query patterns:** | ||
| - List: `query($first: Int, $after: String) { resources(first: $first, after: $after) { nodes { id name } pageInfo { hasNextPage endCursor } } }` | ||
| - Get: `query($id: String!) { resource(id: $id) { id name description } }` | ||
| - Create: `mutation($input: CreateInput!) { create(input: $input) { success resource { id } } }` | ||
| - Update: `mutation($id: String!, $input: UpdateInput!) { update(id: $id, input: $input) { success } }` | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1:
entrypointUrlandentrypointHttpMethodare required for generic connectors in this plugin, so telling authors not to use them will produce invalid configs that fail validation.Prompt for AI agents