From b680d2f91510078cf237342f4f4c8cb314af83f5 Mon Sep 17 00:00:00 2001 From: Faisal Reza Date: Mon, 28 Sep 2026 13:46:20 +0100 Subject: [PATCH 1/4] fix(SOL-422): stackone-unified-connectors - update stale docs links and description - connector-engine links -> connector-building/stackone-cli - key urls: connector building, defined output schemas, yaml reference - llms.txt fallback - description no longer names uninstallable schema skills - skill version 2.2 Co-Authored-By: Claude Opus 5.5 --- .../skills/stackone-unified-connectors/SKILL.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md index aae2a82..572c866 100644 --- a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md +++ b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md @@ -1,11 +1,11 @@ --- name: stackone-unified-connectors -description: Baseline skill for building unified/schema-based connectors that transform provider data into standardized schemas. Use alongside domain-specific schema skills (e.g., unified-hris-schema, unified-crm-schema) that define your organization's standard schemas. Use when user says "start unified build for [provider]", "build a schema-based connector", "map fields to schema", "test unified connector", or asks about field mapping, enum mapping, pagination configuration, or scope decisions. This skill provides implementation patterns; schema skills provide field definitions. Do NOT use for agentic/custom connectors (use stackone-cli), discovering existing connectors (use stackone-connectors), or building AI agents (use stackone-agents). +description: Baseline skill for building unified/schema-based connectors that transform provider data into standardized schemas. Use alongside domain-specific schema skills that you create to define your organization's standard schemas. Use when user says "start unified build for [provider]", "build a schema-based connector", "map fields to schema", "test unified connector", or asks about field mapping, enum mapping, pagination configuration, or scope decisions. This skill provides implementation patterns; schema skills provide field definitions. Do NOT use for agentic/custom connectors (use stackone-cli), discovering existing connectors (use stackone-connectors), or building AI agents (use stackone-agents). license: MIT compatibility: Requires StackOne CLI (@stackone/cli). Requires access to provider API documentation. metadata: author: stackone - version: "2.1" + version: "2.2" --- # StackOne Unified Connectors @@ -27,10 +27,14 @@ This separation allows you to maintain consistent schemas across all providers w ## Important Before building unified connectors: -1. Read the CLI documentation: https://docs.stackone.com/guides/connector-engine/cli-reference +1. Read the CLI documentation: https://docs.stackone.com/connector-building/stackone-cli.md 2. Use `stackone help ` for command-specific details 3. Always verify response structures with `--debug` before configuring mappings +When fetching any `docs.stackone.com` page, append `.md` to the URL to get it as markdown. + +**If any URL in this skill returns 404** (StackOne reorganizes its docs from time to time), fetch `https://docs.stackone.com/llms.txt`, which indexes every docs page by title and description. Search it for the page's topic (e.g. "StackOne CLI", "Defined Output Schemas", "Connector YAML Reference") and use the URL listed there. + ## Core Principles These principles apply to ALL unified connector work. Violations cause silent failures or broken mappings. @@ -406,8 +410,10 @@ Result: Working pagination with correct cursor handling. | Resource | URL | |----------|-----| | CLI Package | https://www.npmjs.com/package/@stackone/cli | -| Connector Engine Docs | https://docs.stackone.com/guides/connector-engine | -| CLI Reference | https://docs.stackone.com/guides/connector-engine/cli-reference | +| Connector Building Docs | https://docs.stackone.com/connector-building/overview.md | +| CLI Reference | https://docs.stackone.com/connector-building/stackone-cli.md | +| Defined Output Schemas | https://docs.stackone.com/connector-building/defined-output-schemas.md | +| Connector YAML Reference | https://docs.stackone.com/connector-yaml-reference/overview.md | ## Creating Domain-Specific Schema Skills From ff608297c84242c3da725a42dae76a899976ed7f Mon Sep 17 00:00:00 2001 From: Faisal Reza Date: Mon, 28 Sep 2026 14:04:21 +0100 Subject: [PATCH 2/4] fix(SOL-422): map fields with action-level fieldConfigs - fieldConfigs replaces inline map_fields fields; map_fields/typecast take dataSource only - expressions relative to each record, no step prefix - drop schema inference troubleshooting entry - lower() replaces unsupported .toLowerCase() in enum matching Co-Authored-By: Claude Opus 5.5 --- .../stackone-unified-connectors/SKILL.md | 100 +++++++---------- .../references/field-mapping-patterns.md | 106 ++++++++---------- 2 files changed, 92 insertions(+), 114 deletions(-) diff --git a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md index 572c866..75c42e8 100644 --- a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md +++ b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md @@ -72,30 +72,28 @@ stepFunction: version: '2' # REQUIRED - omitting causes empty results ``` -### 4. Use Inline Fields in map_fields Parameters +### 4. Define Fields in Action-Level fieldConfigs -Pass `fields` directly in `map_fields` step parameters rather than action-level `fieldConfigs`. This avoids schema inference issues that cause build failures. +Declare the field mapping once in the action's `fieldConfigs`. The `map_fields` and `typecast` steps then take only a `dataSource` and apply those `fieldConfigs`. ```yaml -# RECOMMENDED - Inline fields -- stepId: map_data - stepFunction: - functionName: map_fields - version: '2' - parameters: - fields: - - targetFieldKey: email - expression: $.email # Direct reference, NO step prefix - type: string - dataSource: $.steps.get_data.output.data +fieldConfigs: + - targetFieldKey: email + expression: $.email # Relative to each record, NO step prefix + type: string + +steps: + - stepId: map_data + stepFunction: + functionName: map_fields + version: '2' + parameters: + dataSource: $.steps.get_data.output.data ``` -### 5. Expression Context Depends on Location +### 5. Expressions Are Relative to Each Record -| Location | Expression Format | Example | -|----------|------------------|---------| -| Inline in `parameters.fields` | Direct field reference | `$.email`, `$.work.department` | -| Action-level `fieldConfigs` | Step ID prefix required | `$.get_employees.email` | +`fieldConfigs` expressions are evaluated against each record of the `map_fields` `dataSource`, so reference the record's fields directly: `$.email`, `$.work.department`. Do not prefix them with a step ID. ### 6. Never Suggest User-Side Mapping @@ -190,36 +188,37 @@ See `references/scope-patterns.md` for detailed patterns. ### Step 5: Map Fields to Schema -Use inline fields in map_fields parameters: +Declare the mapping in action-level `fieldConfigs`, then run `map_fields` and `typecast` over the data: ```yaml +fieldConfigs: + - targetFieldKey: id + expression: $.id + type: string + - targetFieldKey: email + expression: $.email + type: string + - targetFieldKey: department + expression: $.work.department # Nested field + type: string + - targetFieldKey: status + expression: $.status + type: enum + enumMapper: + matcher: + - matchExpression: '{{$.status == "Active"}}' + value: active + - matchExpression: '{{$.status == "Inactive"}}' + value: inactive + - matchExpression: '{{$.status == null}}' + value: unknown + steps: - stepId: map_data stepFunction: functionName: map_fields version: '2' parameters: - fields: - - targetFieldKey: id - expression: $.id - type: string - - targetFieldKey: email - expression: $.email - type: string - - targetFieldKey: department - expression: $.work.department # Nested field - type: string - - targetFieldKey: status - expression: $.status - type: enum - enumMapper: - matcher: - - matchExpression: '{{$.status == "Active"}}' - value: active - - matchExpression: '{{$.status == "Inactive"}}' - value: inactive - - matchExpression: '{{$.status == null}}' - value: unknown dataSource: $.steps.get_data.output.data - stepId: typecast_data @@ -227,15 +226,6 @@ steps: functionName: typecast version: '2' parameters: - fields: - - targetFieldKey: id - type: string - - targetFieldKey: email - type: string - - targetFieldKey: department - type: string - - targetFieldKey: status - type: enum dataSource: $.steps.map_data.output.data result: @@ -333,7 +323,7 @@ Actions: 3. **If no skill**: Ask for schema, recommend creating `unified-hris-schema` skill for consistency across HRIS providers 4. Research BambooHR endpoints: `/v1/employees`, `/v1/employees/directory`, custom reports 5. Present options with trade-offs (field coverage, scopes, deprecation) -6. After user selects, implement map_fields with inline fields using schema from skill +6. After user selects, declare `fieldConfigs` using schema from skill and add map_fields and typecast steps 7. Configure pagination with cursor support 8. Test with `--debug`, verify field names match schema 9. Document coverage @@ -360,7 +350,7 @@ User says: "My unified connector returns provider field names instead of my sche Actions: 1. Check if `targetFieldKey` uses YOUR schema names (not provider names) 2. Verify `version: '2'` is specified on map_fields and typecast -3. Check expression context - inline fields should NOT have step prefix +3. Check expression context - `fieldConfigs` expressions should NOT have a step prefix 4. Run with `--debug` to see raw response structure 5. Verify dataSource path is correct @@ -387,20 +377,16 @@ Result: Working pagination with correct cursor handling. ### Mapping produces empty results **Cause**: Missing `version: '2'` or wrong expression context. -**Fix**: Add `version: '2'` to map_fields and typecast. For inline fields, use direct references (`$.email`) without step prefix. +**Fix**: Add `version: '2'` to map_fields and typecast. In `fieldConfigs`, use direct references (`$.email`) without step prefix. ### Enum values not translating **Cause**: `matchExpression` doesn't match provider values (case-sensitive). -**Fix**: Check exact provider values with `--debug`. Use `.toLowerCase()` for case-insensitive matching. Always include null/unknown fallback. +**Fix**: Check exact provider values with `--debug`. Use the `lower()` function for case-insensitive matching (e.g. `'{{lower($.status) == "active"}}'`). Always include null/unknown fallback. ### Pagination returns same records **Cause**: Cursor not being sent or extracted correctly. **Fix**: Verify `iterator.key` matches API's expected parameter name. Check `nextKey` path against raw response. Verify `iterator.in` is correct (query/body/headers). -### Build fails with schema inference errors -**Cause**: Action-level `fieldConfigs` triggering unwanted schema inference. -**Fix**: Use inline fields in `map_fields` parameters instead of action-level `fieldConfigs`. - ### Dynamic inputs resolve to undefined **Cause**: Using `paginated_request` which doesn't handle `$.inputs.*` well. **Fix**: Use standard `request` function with dual-condition pattern for defaults. diff --git a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/references/field-mapping-patterns.md b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/references/field-mapping-patterns.md index cfe0fe4..52d1ede 100644 --- a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/references/field-mapping-patterns.md +++ b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/references/field-mapping-patterns.md @@ -13,34 +13,36 @@ | `enum` | Constrained values | status (requires enumMapper) | | `object` | Nested structure | work_location | -## Inline Fields (Recommended Approach) +## Action-Level fieldConfigs -Define fields directly in `map_fields` step parameters: +Define fields in the action's `fieldConfigs`. The `map_fields` step takes only a `dataSource` and applies them: ```yaml -- stepId: map_data - stepFunction: - functionName: map_fields - version: '2' - parameters: - fields: - - targetFieldKey: email - expression: $.email # Direct reference, NO step prefix - type: string - - targetFieldKey: department - expression: $.work.department # Nested field reference - type: string - dataSource: $.steps.get_data.output.data +fieldConfigs: + - targetFieldKey: email + expression: $.email # Relative to each record, NO step prefix + type: string + - targetFieldKey: department + expression: $.work.department # Nested field reference + type: string + +steps: + - stepId: map_data + stepFunction: + functionName: map_fields + version: '2' + parameters: + dataSource: $.steps.get_data.output.data ``` -**Why inline?** Action-level `fieldConfigs` can trigger schema inference that adds unwanted properties, causing build failures. +The field snippets below are entries in `fieldConfigs`. ## Enum Mapping ### Basic Enum ```yaml -fields: +fieldConfigs: - targetFieldKey: status expression: $.status type: enum @@ -59,7 +61,7 @@ fields: ```yaml enumMapper: matcher: - - matchExpression: '{{($.status || "").toLowerCase() == "active"}}' + - matchExpression: '{{lower($.status) == "active"}}' value: active ``` @@ -101,7 +103,7 @@ enumMapper: ### Simple Nested Field ```yaml -fields: +fieldConfigs: - targetFieldKey: city expression: $.location.city type: string @@ -119,7 +121,7 @@ Provider returns: Your schema is flat: ```yaml -fields: +fieldConfigs: - targetFieldKey: department expression: $.work.department type: string @@ -133,7 +135,7 @@ fields: ### Simple Array ```yaml -fields: +fieldConfigs: - targetFieldKey: email_addresses expression: $.emails[*] type: string @@ -143,7 +145,7 @@ fields: ### JEXL Array Operations ```yaml -fields: +fieldConfigs: - targetFieldKey: export_formats expression: '{{keys(exportLinks)}}' type: string @@ -155,7 +157,7 @@ fields: ### Fallback Values ```yaml -fields: +fieldConfigs: - targetFieldKey: file_format expression: '{{$.fullFileExtension || $.mimeType}}' type: string @@ -164,7 +166,7 @@ fields: ### Conditional Logic ```yaml -fields: +fieldConfigs: - targetFieldKey: default_format expression: '{{exportLinks ? (keys(exportLinks)[0] || "application/pdf") : $.mimeType}}' type: string @@ -173,7 +175,7 @@ fields: ### Boolean Check ```yaml -fields: +fieldConfigs: - targetFieldKey: is_exportable expression: '{{$.exportLinks != null}}' type: boolean @@ -184,6 +186,20 @@ fields: Mapping HiBob employee data: ```yaml +fieldConfigs: + - targetFieldKey: email + expression: $.email + type: string + - targetFieldKey: employee_id + expression: $.id + type: string + - targetFieldKey: department + expression: $.work.department + type: string + - targetFieldKey: job_title + expression: $.work.title + type: string + steps: - stepId: get_employees stepFunction: @@ -211,19 +227,6 @@ steps: functionName: map_fields version: '2' parameters: - fields: - - targetFieldKey: email - expression: $.email - type: string - - targetFieldKey: employee_id - expression: $.id - type: string - - targetFieldKey: department - expression: $.work.department - type: string - - targetFieldKey: job_title - expression: $.work.title - type: string dataSource: $.steps.get_employees.output.data - stepId: typecast_data @@ -231,15 +234,6 @@ steps: functionName: typecast version: '2' parameters: - fields: - - targetFieldKey: email - type: string - - targetFieldKey: employee_id - type: string - - targetFieldKey: department - type: string - - targetFieldKey: job_title - type: string dataSource: $.steps.map_data.output.data result: @@ -251,15 +245,13 @@ result: ### Wrong Expression Context ```yaml -# WRONG - Using step prefix in inline fields -parameters: - fields: - - expression: $.get_employees.email # Don't use step prefix! +# WRONG - Using step prefix in fieldConfigs +fieldConfigs: + - expression: $.get_employees.email # Don't use step prefix! # CORRECT - Direct field reference -parameters: - fields: - - expression: $.email +fieldConfigs: + - expression: $.email ``` ### Missing Version @@ -289,9 +281,9 @@ stepFunction: ## Validation Checklist -- [ ] Using inline `fields` in map_fields parameters -- [ ] Expressions use correct context (no step prefix for inline) +- [ ] All schema fields declared in action-level `fieldConfigs` +- [ ] Expressions use correct context (no step prefix in `fieldConfigs`) - [ ] `version: '2'` specified for map_fields and typecast - [ ] All `targetFieldKey` values match YOUR schema - [ ] All enum fields have `enumMapper` with null handler -- [ ] typecast step includes all mapped fields +- [ ] typecast step runs on the map_fields output From ba22f62792a086b9ee169303ef071adc78bc0a34 Mon Sep 17 00:00:00 2001 From: Faisal Reza Date: Mon, 28 Sep 2026 15:46:07 +0100 Subject: [PATCH 3/4] fix(SOL-422): scope .md rule to urls not ending in .md Co-Authored-By: Claude Opus 5.5 --- .../skills/stackone-unified-connectors/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md index 75c42e8..a622c36 100644 --- a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md +++ b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md @@ -31,7 +31,7 @@ Before building unified connectors: 2. Use `stackone help ` for command-specific details 3. Always verify response structures with `--debug` before configuring mappings -When fetching any `docs.stackone.com` page, append `.md` to the URL to get it as markdown. +When fetching a `docs.stackone.com` page whose URL doesn't already end in `.md`, append `.md` to get it as markdown. `llms.txt` is already plain text, so fetch it as is. **If any URL in this skill returns 404** (StackOne reorganizes its docs from time to time), fetch `https://docs.stackone.com/llms.txt`, which indexes every docs page by title and description. Search it for the page's topic (e.g. "StackOne CLI", "Defined Output Schemas", "Connector YAML Reference") and use the URL listed there. From f40e6db05a5e4b2c8769d0813d8cd0bbc05626d4 Mon Sep 17 00:00:00 2001 From: Faisal Reza Date: Mon, 28 Sep 2026 15:53:56 +0100 Subject: [PATCH 4/4] fix(SOL-422): align docs fallback with sibling skills - also covers pages that do not answer the question - contact support when docs do not cover it Co-Authored-By: Claude Opus 5.5 --- .../skills/stackone-unified-connectors/SKILL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md index a622c36..8dedb2d 100644 --- a/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md +++ b/plugins/integrations/stackone-unified-connectors/skills/stackone-unified-connectors/SKILL.md @@ -33,7 +33,9 @@ Before building unified connectors: When fetching a `docs.stackone.com` page whose URL doesn't already end in `.md`, append `.md` to get it as markdown. `llms.txt` is already plain text, so fetch it as is. -**If any URL in this skill returns 404** (StackOne reorganizes its docs from time to time), fetch `https://docs.stackone.com/llms.txt`, which indexes every docs page by title and description. Search it for the page's topic (e.g. "StackOne CLI", "Defined Output Schemas", "Connector YAML Reference") and use the URL listed there. +**If any URL in this skill returns 404, or a page doesn't cover what you need** (StackOne reorganizes its docs from time to time): +- Fetch `https://docs.stackone.com/llms.txt`, which indexes every docs page by title and description. Search it for the page's topic (e.g. "StackOne CLI", "Defined Output Schemas", "Connector YAML Reference") and use the URL listed there. +- If the docs don't cover the question, say so and suggest contacting StackOne support. Don't invent an answer. ## Core Principles