AgentSkillsCN

add-autotask-child-entity

在本仓库中端到端新增一个 Autotask 子实体,包括实体元数据、资源文件、节点连线、共享执行器注册、AI 工具验证,以及 README/CHANGELOG 的更新。

SKILL.md
--- frontmatter
name: add-autotask-child-entity
description: Add a new Autotask child entity end-to-end in this repo, including entity metadata, resource files, node wiring, shared executor registration, AI tools validation, and README/CHANGELOG updates.

Add Autotask Child Entity

Use this skill when

  • Adding a new child resource under an existing parent entity in the Autotask node
  • Implementing a new query-only or CRUD child entity
  • You need the full change set, including docs updates in README.md and CHANGELOG.md

End-to-end workflow

  1. Verify API capabilities first (Swagger/docs)
  2. Add entity metadata in nodes/Autotask/constants/entities.ts
  3. Add resource definition in nodes/Autotask/resources/definitions.ts (strict alphabetical order)
  4. Create resource files under nodes/Autotask/resources/<resourceDir>/:
    • description.ts
    • execute.ts
    • index.ts
  5. Wire the resource in nodes/Autotask/Autotask.node.ts:
    • execute import
    • fields import
    • addOperationsToResource(...) in properties
    • switch case in execute()
  6. Wire the resource in nodes/Autotask/resources/tool/execute.ts (shared executor backbone):
    • execute import
    • RESOURCE_EXECUTORS map entry (key = node resource value from definitions.ts)
  7. Verify AI Tools exposure via resourceKey + operation mapping
  8. Update docs:
    • Add entry under current version in CHANGELOG.md
    • Add resource row in README supported resources table
  9. Run validation:
    • npx tsc --noEmit
    • run lint checks for changed files

Implementation details

1) Entity metadata (entities.ts)

Add an entity object in AUTOTASK_ENTITIES with:

  • name: singular PascalCase internal identifier
  • resourceKey: required when lowerCamelCase(name) does not match API path/resource identifier
  • childOf: parent entity internal name
  • subname: exact API child URL segment
  • parentIdField: parent FK field
  • operations: only operations the API supports

Example for query-only child:

typescript
{
  name: 'TicketCategoryFieldDefault',
  resourceKey: 'ticketCategoryFieldDefaults',
  childOf: 'TicketCategory',
  subname: 'FieldDefaults',
  parentIdField: 'ticketCategoryID',
  operations: {
    [OperationType.QUERY]: 'self',
    [OperationType.COUNT]: 'self',
  },
}

2) Resource definition (definitions.ts)

  • Add a new entry in strict alphabetical order by name
  • Keep value aligned with node resource key used in Autotask.node.ts

Example:

typescript
{
  name: 'Ticket Category Field Default',
  value: 'ticketCategoryFieldDefault',
  description: 'Query default field values for ticket categories, which define default settings for ticket fields based on category',
}

3) Resource files

description.ts

  • Include only supported operations (for query-only: get, getMany, count)
  • Define id for get
  • Define fieldsToMap for getMany and count
  • Export base fields (advanced/entity-info operations are injected by addOperationsToResource)

execute.ts

  • Set ENTITY_TYPE to lowerCamelCase internal entity name
  • Include switch cases for:
    • get
    • getMany
    • getManyAdvanced
    • count
    • getEntityInfo
    • getFieldInfo
  • Keep continueOnFail behaviour aligned with existing resources
  • Reuse base operations (GetOperation, GetManyOperation, CountOperation, etc.)

index.ts

typescript
export * from './description';
export * from './execute';

4) Main node wiring (Autotask.node.ts)

Add:

  • execute import from new resource execute.ts
  • fields import from new resource description.ts
  • properties entry:
    • ...addOperationsToResource(newFields, { resourceName: 'newResourceValue' })
  • switch case:
    • case 'newResourceValue': return executeNewResourceOperation.call(this);

5) Shared executor wiring (resources/tool/execute.ts)

This step is critical and separate from the main node wiring.

tool/execute.ts contains the RESOURCE_EXECUTORS map — the shared execution backbone used by:

  • AutotaskAiTools node (AutotaskAiTools.node.ts) — the new structured AI tools node, which calls executeToolOperation via ai-tools/tool-executor.ts
  • Legacy Tool resource (the tool resource within Autotask.node.ts) — being decommissioned in a future release

Without an entry in RESOURCE_EXECUTORS, the new resource will be invisible to the AI tools node even though the main Autotask node works fine.

Decommissioning note: The tool resource and aiHelper resource within Autotask.node.ts are legacy and will be removed in a future release. The AutotaskAiTools.node.ts is the replacement. However, tool/execute.ts itself is not legacy — it is the shared executor that the new AI tools node depends on.

Add:

  • Import the execute function from the new resource module
  • Entry in the RESOURCE_EXECUTORS map using the node resource value (from definitions.ts) as the key

Example:

typescript
// Import (add near other ticket-related imports)
import { executeTicketSecondaryResourceOperation } from '../ticketSecondaryResources/execute';

// RESOURCE_EXECUTORS entry (add in alphabetical position among ticket-related entries)
ticketSecondaryResource: executeTicketSecondaryResourceOperation,

The map key must match the value field from definitions.ts (the node resource key), not the entity resourceKey from entities.ts. These can differ when resourceKey is explicitly set (e.g. entity resourceKey: 'ticketSecondaryResources' plural vs node value ticketSecondaryResource singular).

6) AI Tools mapping check

The AI tools architecture auto-derives available resources and operations from entity metadata. The flow is:

code
AUTOTASK_ENTITIES (entities.ts)
        ↓
buildResourceOperationsMap() in resource-operations.ts
        ↓
RESOURCE_OPERATIONS_MAP
        ↓
AutotaskAiTools.node.ts (loadOptions + tool generation)
        ↓
ai-tools/tool-executor.ts → executeToolOperation() → RESOURCE_EXECUTORS

nodes/Autotask/constants/resource-operations.ts resolves key as:

typescript
const resourceKey = entity.resourceKey ?? lowerCamelCase(entity.name);

Validation checklist:

  • Entity is not excluded by isAttachment / excluded name patterns
  • resourceKey resolves to expected map key
  • Operation mapping is correct for supported operation types
  • Alias generation handles default key vs explicit key mismatch
  • tool-surface.ts calls getResourceOperations(entity.name) which normalises via aliases — confirm the alias chain resolves to the correct RESOURCE_OPERATIONS_MAP key

Adding special/custom operations? Standard CRUD operations (get, getMany, create, update, delete, count) are auto-derived and need no manual AI tools wiring. But if you're adding a custom operation (e.g. slaHealthCheck, searchByDomain) to a resource, there are 10+ additional mandatory touchpoints in the AI tools layer. Use the add-autotask-special-operation skill and follow the full checklist at .docs/autotask/change-guidelines/ai-tools-special-operation-checklist.md. The most critical step is adding a normaliseOperation() case in ai-tools/tool-executor.ts — without it, the operation silently fails at runtime.

7) README and CHANGELOG updates

CHANGELOG.md

  • Under the current version, add an Added bullet for the new resource
  • Mention operation scope clearly (for query-only: Get/Get Many/Count)
  • Mention parent/child context where useful

README.md

  • Add the resource in the supported resources table
  • Keep resource table ordering consistent (alphabetical within the section)
  • Use concise, user-facing description

8) RESOURCE_ALIASES entry (when needed)

When the entity name in entities.ts is plural (e.g. ServiceLevelAgreementResults) but the node resource value in definitions.ts is singular (e.g. serviceLevelAgreementResult), the AI Tools mapping cannot resolve the resource automatically. Add a manual alias in constants/resource-operations.ts:

typescript
// In RESOURCE_ALIASES initialiser object
servicelevelagreementresult: 'serviceLevelAgreementResults',

This is separate from the auto-generated aliases derived from resourceKey mismatches. Check whether normaliseResourceName(nodeResourceValue) resolves to the correct RESOURCE_OPERATIONS_MAP key; if not, add the alias.

Dual-scope entities (root + child endpoints)

Some entities can be accessed via both root endpoints and child endpoints (e.g. ServiceLevelAgreementResults has both /ServiceLevelAgreementResults/* and /ServiceLevelAgreements/{id}/Results/*).

When to use

  • The Autotask API exposes both root and child endpoints for the same entity
  • The parent entity may or may not be registered in entities.ts

Rules

  1. Never add an "Endpoint Scope" selector to the UI. Make the parent ID field optional and detect scope automatically.
  2. If the parent entity is not in entities.ts, do NOT use childOf. Register the entity standalone and handle child routing in execute.ts.
  3. In execute.ts, determine scope with:
    typescript
    const parentId = getParentId(this, i);
    const isChildScope = parentId !== undefined;
    
  4. Root scope → use base operation classes. Child scope → build URLs manually with buildChildBasePath().
  5. Add manual executeChildEntityInfoOperation and executeChildFieldInfoOperation helpers for child-scoped entity/field info.

Reference implementations

  • Without childOf: nodes/Autotask/resources/serviceLevelAgreementResults/
  • With childOf: nodes/Autotask/resources/ticketChangeRequestApprovals/

Quality gates

  • API operations match Swagger/docs (no unsupported operations)
  • resourceKey set when required
  • RESOURCE_ALIASES entry added if entity name plural/singular mismatch exists
  • definitions.ts ordering remains correct
  • Autotask.node.ts imports/properties/switch all wired
  • tool/execute.ts import and RESOURCE_EXECUTORS entry added
  • AI Tools mapping produces expected operations (verify RESOURCE_OPERATIONS_MAP key resolves)
  • No "Endpoint Scope" selector in description.ts — scope is auto-detected from parent ID
  • README.md and CHANGELOG.md updated
  • npx tsc --noEmit passes

Known hazards

normaliseOperation() in ai-tools/tool-executor.ts

When adding any special/custom operation with a camelCase name, it must have an explicit case in normaliseOperation(). This function lowercases all input and selectively restores casing for known operations. If a new operation is not handled, it stays lowercase and silently fails every downstream comparison — no compiler or linter catches it.

See .docs/autotask/change-guidelines/ai-tools-special-operation-checklist.md for the full AI tools wiring checklist.

filtersFromTool parameter and getNodeParameter throws

The shared buildFiltersFromResourceMapper() helper in helpers/filter.ts accesses a filtersFromTool parameter that is only injected at runtime by the AI tool executor (tool/execute.ts). It does not exist in the node's property schema.

In newer n8n versions, getNodeParameter(name, index, fallback) throws "Could not get parameter" even when a fallback is supplied, if the parameter name is absent from the node schema. This was fixed by wrapping the access in try/catch in filter.ts.

Rule: Any shared helper code that reads parameters only available in the AI tool execution context must use try/catch, not rely on a fallback value. This affects all resources globally, not just new ones.

Notes

  • Prefer exact API naming for endpoint segments (subname and endpoint-specific keys)
  • Keep changes minimal and aligned with established patterns in existing resources
  • Follow existing indentation style in this repo for touched files
  • The tool/execute.ts wiring is a separate concern from Autotask.node.ts — both must be updated independently. Missing the executor entry means the main node works but the AI tools node silently fails to route to the resource.
  • tool/execute.ts is the shared executor backbone, not a legacy file. Do not confuse it with the legacy tool resource (which routes through it) or the legacy aiHelper resource — both of those resources are being decommissioned, but tool/execute.ts itself persists as the execution layer for AutotaskAiTools.node.ts.
  • When implementing dual-scope entities, the ServiceLevelAgreementResults resource is the canonical reference for the pattern without childOf, and TicketChangeRequestApprovals is the reference for dual-scope with childOf.