> ## Documentation Index
> Fetch the complete documentation index at: https://cadenya.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Assign a tool, tool set, or sub-agent

> Give a variation a capability. One call, one target: a single tool, a whole tool set, or another agent.

A [variation](/docs/api-reference/agentvariationservice/create-a-new-variation) starts with a model and a prompt and nothing to do. An assignment hands it a capability.

<CodeGroup>
  ```typescript TypeScript theme={null}
  await client.agents.variations.addAssignment(agentId, variationId, {
    workspaceId,
    type: 'toolSetId',
    toolSetId: 'toolset_01KVNB4S8WS04J4VNJRR782176',
  });
  ```

  ```go Go theme={null}
  _, err := client.Agents.Variations.AddAssignment(ctx, agentID, variationID,
  	cadenya.AgentVariationAddAssignmentParams{
  		WorkspaceID: cadenya.String(workspaceID),
  		OfToolSetID: &cadenya.AddAgentVariationAssignmentRequestToolSetIDParam{
  			ToolSetID: "toolset_01KVNB4S8WS04J4VNJRR782176",
  			Type:      cadenya.AddAgentVariationAssignmentRequestToolSetIDTypeToolSetID,
  		},
  	})
  ```

  ```ruby Ruby theme={null}
  cadenya.agents.variations.add_assignment(
    agent_id,
    variation_id,
    workspace_id: workspace_id,
    body: {type: :toolSetId, toolSetId: "toolset_01KVNB4S8WS04J4VNJRR782176"}
  )
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.cadenya.com/v1/workspaces/${WORKSPACE_ID}/agents/${AGENT_ID}/variations/${VARIATION_ID}/assignments" \
    -H "Authorization: Bearer ${CADENYA_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{ "type": "toolSetId", "toolSetId": "toolset_01KVNB4S8WS04J4VNJRR782176" }'
  ```
</CodeGroup>

## Exactly one target

The body is a discriminated union. `type` names the variant, and the matching key carries the ID.

| Key          | Gives the agent                                                                                           |
| ------------ | --------------------------------------------------------------------------------------------------------- |
| `toolId`     | One tool, from any tool set                                                                               |
| `toolSetId`  | Every tool in a [tool set](/docs/api-reference/toolservice/create-a-new-tool-set), including ones synced later |
| `subAgentId` | Another agent, callable as a tool ([delegation](/docs/guides/delegate-to-sub-agents))                          |

Set two keys and the request fails before it touches the database:

```
{ "type": "toolSetId", "toolSetId": "...", "subAgentId": "..." }
  -> 400  "oneof field 'target' is already set. Cannot set 'subAgentId'"
```

Assigning a tool set is the durable choice. It tracks the provider: tools discovered on a later sync appear to the agent without another assignment. Assigning `toolId` pins the agent to exactly the tools you name, which is what you want when a tool set is broad and the agent's job is narrow.

## Assign once

A target already on the variation is a `409`, with the reason spelled out:

```
POST .../assignments  { "type": "toolSetId", "toolSetId": "toolset_01KVNB..." }   -> 200
POST .../assignments  { "type": "toolSetId", "toolSetId": "toolset_01KVNB..." }   -> 409
  "tool set toolset_01KVNB4S8WS04J4VNJRR782176 already assigned to variation"
```

So a setup script that reruns catches `409` rather than assuming idempotency, unlike [publish](/docs/api-reference/agentservice/publish-an-agent), which is a no-op the second time.

## Nothing stops a sub-agent loop

<Warning>
  An agent can be assigned as **its own** sub-agent, and two agents can be assigned to each other. Both return `200`. There is no cycle check.

  ```
  POST /agents/{A}/variations/{V}/assignments  { "type": "subAgentId", "subAgentId": "{A}" }   -> 200
  POST /agents/{B}/variations/{V}/assignments  { "type": "subAgentId", "subAgentId": "{A}" }   -> 200   (with A -> B already set)
  ```

  An agent that delegates to itself spawns a sub-objective that delegates again. Every node in that tree is a billed model run. Check the target before you assign it. The API does not.
</Warning>

The same endpoint rejects a duplicate tool set and a two-key union, so the validation gap is specific to the shape of the sub-agent graph, not to assignments in general.

## What the agent sees

Publish the agent, and the next objective's tool list carries every assigned tool. In the event stream, `toolCalled.tool` names which kind was called. It is a discriminated union, so narrow on `type`:

```typescript theme={null}
if (event.data.type === 'toolCalled') {
  const called = event.data.toolCalled.tool;
  if (called.type === 'tool') called.tool.name;    // 'GenerateFake'   (from a tool or tool set)
  if (called.type === 'agent') called.agent.name;  // 'Research'       (a sub-agent)
                                                   // built-ins arrive as type 'cadenyaProvidedTool'
}
```

Assignments are not paged. There is no `GET .../assignments` collection (it returns `415`). Read them from the variation:

```typescript theme={null}
const variation = await client.agents.variations.retrieve(agentId, variationId, {
  workspaceId, includeInfo: true,
});

for (const assignment of variation.info?.assignments ?? []) {
  const target = assignment.type === 'toolSet' ? assignment.toolSet
    : assignment.type === 'agent' ? assignment.agent
    : assignment.tool;
  console.log(assignment.id, target.name);
}
// avt_01KX1KKP4M02H3CWHER8BFWB3Q  Faker MCP
```

Remove one by its `avt_...` id:

```typescript theme={null}
await client.agents.variations.removeAssignment(agentId, variationId, assignmentId, { workspaceId });
```

## Memory is a different call

Memory layers are not assignments. They have their own route and their own ordering, because the [cascade](/docs/guides/memory-layers) resolves keys by position:

```typescript theme={null}
await client.agents.variations.addMemoryLayer(agentId, variationId, {
  workspaceId,
  memoryLayerId: layerId,
  position: 0,
});
```

Assigning any memory layer is what gives the agent `get_memory` and `search_memory`.

## Related

<CardGroup cols={2}>
  <Card title="Search tools and tool sets" icon="magnifying-glass" href="/docs/api-reference/searchservice/search-for-tools-or-tool-sets">
    Find the ID to assign. It returns the same three kinds.
  </Card>

  <Card title="Delegate to sub-agents" icon="sitemap" href="/docs/guides/delegate-to-sub-agents">
    What `subAgentId` buys you, and how a sub-objective reports back.
  </Card>

  <Card title="Preventing tool bloat" icon="filter" href="/docs/guides/preventing-tool-bloat">
    When to assign one tool instead of a whole set.
  </Card>

  <Card title="Publish an agent" icon="rocket" href="/docs/api-reference/agentservice/publish-an-agent">
    Assignments go live on the next objective, with no republish.
  </Card>
</CardGroup>


## OpenAPI

````yaml post /v1/workspaces/{workspaceId}/agents/{agentId}/variations/{variationId}/assignments
openapi: 3.1.0
info:
  title: Cadenya API
  description: API for the Cadenya Agent Runtime platform.
  version: '1.0'
servers:
  - url: https://api.cadenya.com
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: AIProviderKeyService
  - name: APIKeyService
    description: |-
      Issue, rotate, disable, and revoke a workspace's API keys. Every key
       belongs to exactly one workspace; the system-managed global account key is
       managed via GlobalAPIKeyService instead.
  - name: AccountService
    description: >-
      Manage the authenticated account. Accounts are the top-level
      organizational
       unit and contain one or more workspaces.
  - name: AgentScheduleService
    description: >-
      Manage recurring schedules attached to agents. Schedules trigger
      objectives
       on a cadence defined by AgentScheduleSpec.Schedule.
  - name: AgentService
    description: >-
      Manage AI agents within a workspace. Agents define AI behavior and tool
      access.
  - name: AgentVariationService
    description: >-
      Manage variations of an agent and their tool, sub-agent, and memory layer
      assignments.
  - name: GlobalAPIKeyService
    description: |-
      Manage the account's system-provisioned global API key. The global key is
       the only key that spans every workspace; it is created by the system and
       cannot be deleted, so the surface is retrieve, rotate, and the
       disable/enable kill switch.
  - name: MemoryService
    description: >-
      Manage memory layers and their entries. Layers are named containers that
      can
       be composed into an objective's memory cascade; entries are the keyed values
       within a layer. System-managed layers (e.g., episodic layers created by the
       runtime) cannot be mutated through this API.
  - name: ModelService
    description: |-
      Manage LLM models available to a workspace. Models represent provider and
       family pairs (e.g., "anthropic/claude-sonnet-4.6"). Workspaces are seeded
       with the supported models and you can enable or disable each one.
  - name: ObjectiveEventStreamsService
  - name: ObjectiveService
  - name: ProfilesService
    description: |-
      Operations on profiles, the account-level principals (users, API keys,
       system) that authenticate against the API.
  - name: SearchService
  - name: TenantService
    description: >-
      Read and erase tenants and the subjects under them. Tenants and subjects
      are
       created by assertion — on objective creation or widget session mint — never
       directly, so this service has no create or update: it exists to enumerate what
       assertions have produced, and to destroy it on request.
  - name: ToolService
    description: >-
      Manage tool sets and the tools they contain. Tool sets group related
      tools,
       and tools define specific capabilities available to agents.

       When a tool set is managed, only API key actors can modify its tools; human
       (profile) actors cannot.
  - name: UploadService
    description: |-
      Issue short-lived presigned URLs for direct client-to-object-storage
       uploads. Created uploads can be referenced by id when creating or updating
       resources that accept binary content (e.g., MemoryEntry).
  - name: WidgetService
    description: |-
      Manage embeddable chat widgets. A widget binds an agent to a globally
       unique hostname with a per-widget origin allowlist; browsers reach it with
       session tokens minted via WidgetSessionService.
  - name: WidgetSessionService
    description: >-
      Mint and manage widget sessions. Session creation is server-to-server
      only:
       the customer's backend authenticates its visitor, asserts tenant/subject
       context, attaches any per-visitor secrets, and receives a short-lived
       bearer token the browser uses against the widget host.
  - name: WorkspaceAdminService
    description: >-
      Administer workspaces across the account: create and archive workspaces
      and
       manage their membership. These operations are account-scoped and require the
       admin role (a token whose profile holds the WorkOS admin role); they live
       under /v1/account/workspaces rather than the workspace-scoped /v1/workspaces
       tree so an admin can manage any workspace in the account, including ones they
       are not themselves a member of.
  - name: WorkspaceSecretService
  - name: WorkspaceService
    description: |-
      Manage workspaces within an account. Workspaces provide organizational
       grouping and isolation for resources such as agents, tools, and API keys.

       This is the workspace-scoped, end-user surface. Administrative operations
       (create / archive workspaces, manage members) live in WorkspaceAdminService
       under /v1/account/workspaces and require the admin role.
paths:
  /v1/workspaces/{workspaceId}/agents/{agentId}/variations/{variationId}/assignments:
    post:
      tags:
        - AgentVariationService
        - Agent Variations
      summary: Add an assignment to a variation
      description: >-
        Assigns a tool, tool set, or sub-agent to a variation. Exactly one
        target ID must be set.
      operationId: AgentVariationService_AddAgentVariationAssignment
      parameters:
        - name: workspaceId
          in: path
          description: Workspace ID.
          required: true
          schema:
            type: string
            example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
        - name: agentId
          in: path
          description: >-
            Agent ID. Accepts the canonical `agent_…` form or the
            `external_id:<value>` form.
          required: true
          schema:
            example: agent_01HXKD2E5NQM3T9AYWCFMGWT9Y
            type: string
        - name: variationId
          in: path
          description: >-
            Variation ID. Accepts the canonical `agentvar_…` form or the
            `external_id:<value>` form.
          required: true
          schema:
            type: string
            example: agentvar_01HXKD2E5NQM3T9AYWCF32BSPP
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddAgentVariationAssignmentRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VariationAssignment'
        default:
          description: Default error response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Status'
      x-codeSamples:
        - lang: JavaScript
          source: >-
            import Cadenya from '@cadenya/cadenya';


            const client = new Cadenya({
              apiKey: process.env['CADENYA_API_KEY'], // This is the default and can be omitted
            });


            const variationAssignment = await
            client.agents.variations.addAssignment(
              'agent_01HXKD2E5NQM3T9AYWCFMGWT9Y',
              'agentvar_01HXKD2E5NQM3T9AYWCF32BSPP',
              {
                workspaceId: 'workspace_01HXKD2E5NQM3T9AYWCF133E3Q',
                toolId: 'tool_01HXKD2E5NQM3T9AYWCFWVYY9K',
                type: 'toolId',
              },
            );


            console.log(variationAssignment);
        - lang: Python
          source: |-
            import os
            from cadenya import Cadenya

            client = Cadenya(
                api_key=os.environ.get("CADENYA_API_KEY"),  # This is the default and can be omitted
            )
            variation_assignment = client.agents.variations.add_assignment(
                agent_id="agent_01HXKD2E5NQM3T9AYWCFMGWT9Y",
                variation_id="agentvar_01HXKD2E5NQM3T9AYWCF32BSPP",
                workspace_id="workspace_01HXKD2E5NQM3T9AYWCF133E3Q",
                tool_id="tool_01HXKD2E5NQM3T9AYWCFWVYY9K",
                type="toolId",
            )
            print(variation_assignment)
        - lang: Go
          source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"go.cadenya.com/cadenya-go\"\n\t\"go.cadenya.com/cadenya-go/option\"\n)\n\nfunc main() {\n\tclient := cadenya.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tvariationAssignment, err := client.Agents.Variations.AddAssignment(\n\t\tcontext.TODO(),\n\t\t\"agent_01HXKD2E5NQM3T9AYWCFMGWT9Y\",\n\t\t\"agentvar_01HXKD2E5NQM3T9AYWCF32BSPP\",\n\t\tcadenya.AgentVariationAddAssignmentParams{\n\t\t\tWorkspaceID: cadenya.String(\"workspace_01HXKD2E5NQM3T9AYWCF133E3Q\"),\n\t\t\tOfToolID: &cadenya.AddAgentVariationAssignmentRequestToolIDParam{\n\t\t\t\tToolID: \"tool_01HXKD2E5NQM3T9AYWCFWVYY9K\",\n\t\t\t\tType:   cadenya.AddAgentVariationAssignmentRequestToolIDTypeToolID,\n\t\t\t},\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", variationAssignment)\n}\n"
        - lang: Ruby
          source: |-
            require "cadenya"

            cadenya = Cadenya::Client.new(api_key: "My API Key")

            variation_assignment = cadenya.agents.variations.add_assignment(
              "agent_01HXKD2E5NQM3T9AYWCFMGWT9Y",
              "agentvar_01HXKD2E5NQM3T9AYWCF32BSPP",
              workspace_id: "workspace_01HXKD2E5NQM3T9AYWCF133E3Q",
              body: {toolId: "tool_01HXKD2E5NQM3T9AYWCFWVYY9K", type: :toolId}
            )

            puts(variation_assignment)
        - lang: CLI
          source: |-
            cadenya agents:variations add-assignment \
              --api-key 'My API Key' \
              --workspace-id workspace_01HXKD2E5NQM3T9AYWCF133E3Q \
              --agent-id agent_01HXKD2E5NQM3T9AYWCFMGWT9Y \
              --variation-id agentvar_01HXKD2E5NQM3T9AYWCF32BSPP \
              --tool-id tool_01HXKD2E5NQM3T9AYWCFWVYY9K \
              --type toolId \
              --tool-set-id toolset_01HXKD2E5NQM3T9AYWCFNRMN74 \
              --sub-agent-id agent_01HXKD2E5NQM3T9AYWCFMGWT9Y
components:
  schemas:
    AddAgentVariationAssignmentRequest:
      oneOf:
        - $ref: '#/components/schemas/AddAgentVariationAssignmentRequest_ToolId'
        - $ref: '#/components/schemas/AddAgentVariationAssignmentRequest_ToolSetId'
        - $ref: '#/components/schemas/AddAgentVariationAssignmentRequest_SubAgentId'
      discriminator:
        propertyName: type
        mapping:
          toolId:
            $ref: '#/components/schemas/AddAgentVariationAssignmentRequest_ToolId'
          toolSetId:
            $ref: '#/components/schemas/AddAgentVariationAssignmentRequest_ToolSetId'
          subAgentId:
            $ref: '#/components/schemas/AddAgentVariationAssignmentRequest_SubAgentId'
      description: |-
        Attach a single tool, tool set, or sub-agent to a variation. Exactly one
         of the target fields must be set; the assignment kind is inferred from the
         populated field.
    VariationAssignment:
      oneOf:
        - $ref: '#/components/schemas/VariationAssignment_Tool'
        - $ref: '#/components/schemas/VariationAssignment_ToolSet'
        - $ref: '#/components/schemas/VariationAssignment_Agent'
      discriminator:
        propertyName: type
        mapping:
          tool:
            $ref: '#/components/schemas/VariationAssignment_Tool'
          toolSet:
            $ref: '#/components/schemas/VariationAssignment_ToolSet'
          agent:
            $ref: '#/components/schemas/VariationAssignment_Agent'
      description: >-
        A read-only reference to a single tool, tool set, or sub-agent attached
        to
         a variation. Read the full set of assignments via `AgentVariationInfo.assignments`;
         mutations go through the dedicated add/remove assignment endpoints.

         The `id` identifies the assignment itself (not the referenced resource) and
         is the handle used to remove the assignment. It is returned by the add
         endpoint and present on every entry in `AgentVariationInfo.assignments`.
    Status:
      type: object
      properties:
        code:
          type: integer
          description: >-
            The status code, which should be an enum value of
            [google.rpc.Code][google.rpc.Code].
          format: int32
        message:
          type: string
          description: >-
            A developer-facing error message, which should be in English. Any
            user-facing error message should be localized and sent in the
            [google.rpc.Status.details][google.rpc.Status.details] field, or
            localized by the client.
        details:
          type: array
          items:
            $ref: '#/components/schemas/GoogleProtobufAny'
          description: >-
            A list of messages that carry the error details.  There is a common
            set of message types for APIs to use.
      description: >-
        The `Status` type defines a logical error model that is suitable for
        different programming environments, including REST APIs and RPC APIs. It
        is used by [gRPC](https://github.com/grpc). Each `Status` message
        contains three pieces of data: error code, error message, and error
        details. You can find out more about this error model and how to work
        with it in the [API Design
        Guide](https://cloud.google.com/apis/design/errors).
    AddAgentVariationAssignmentRequest_ToolId:
      type: object
      required:
        - type
        - toolId
      properties:
        type:
          type: string
          enum:
            - toolId
        toolId:
          example: tool_01HXKD2E5NQM3T9AYWCFWVYY9K
          type: string
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: Workspace ID.
        agentId:
          readOnly: true
          example: agent_01HXKD2E5NQM3T9AYWCFMGWT9Y
          type: string
          description: >-
            Agent ID. Accepts the canonical `agent_…` form or the
            `external_id:<value>` form.
        variationId:
          readOnly: true
          example: agentvar_01HXKD2E5NQM3T9AYWCF32BSPP
          type: string
          description: >-
            Variation ID. Accepts the canonical `agentvar_…` form or the
            `external_id:<value>` form.
    AddAgentVariationAssignmentRequest_ToolSetId:
      type: object
      required:
        - type
        - toolSetId
      properties:
        type:
          type: string
          enum:
            - toolSetId
        toolSetId:
          example: toolset_01HXKD2E5NQM3T9AYWCFNRMN74
          type: string
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: Workspace ID.
        agentId:
          readOnly: true
          example: agent_01HXKD2E5NQM3T9AYWCFMGWT9Y
          type: string
          description: >-
            Agent ID. Accepts the canonical `agent_…` form or the
            `external_id:<value>` form.
        variationId:
          readOnly: true
          example: agentvar_01HXKD2E5NQM3T9AYWCF32BSPP
          type: string
          description: >-
            Variation ID. Accepts the canonical `agentvar_…` form or the
            `external_id:<value>` form.
    AddAgentVariationAssignmentRequest_SubAgentId:
      type: object
      required:
        - type
        - subAgentId
      properties:
        type:
          type: string
          enum:
            - subAgentId
        subAgentId:
          example: agent_01HXKD2E5NQM3T9AYWCFMGWT9Y
          type: string
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: Workspace ID.
        agentId:
          readOnly: true
          example: agent_01HXKD2E5NQM3T9AYWCFMGWT9Y
          type: string
          description: >-
            Agent ID. Accepts the canonical `agent_…` form or the
            `external_id:<value>` form.
        variationId:
          readOnly: true
          example: agentvar_01HXKD2E5NQM3T9AYWCF32BSPP
          type: string
          description: >-
            Variation ID. Accepts the canonical `agentvar_…` form or the
            `external_id:<value>` form.
    VariationAssignment_Tool:
      type: object
      required:
        - type
        - tool
      properties:
        type:
          type: string
          enum:
            - tool
        tool:
          $ref: '#/components/schemas/BareMetadata'
        id:
          readOnly: true
          example: avt_01HXKD2E5NQM3T9AYWCFJE6K89
          type: string
    VariationAssignment_ToolSet:
      type: object
      required:
        - type
        - toolSet
      properties:
        type:
          type: string
          enum:
            - toolSet
        toolSet:
          $ref: '#/components/schemas/BareMetadata'
        id:
          readOnly: true
          example: avt_01HXKD2E5NQM3T9AYWCFJE6K89
          type: string
    VariationAssignment_Agent:
      type: object
      required:
        - type
        - agent
      properties:
        type:
          type: string
          enum:
            - agent
        agent:
          $ref: '#/components/schemas/BareMetadata'
        id:
          readOnly: true
          example: avt_01HXKD2E5NQM3T9AYWCFJE6K89
          type: string
    GoogleProtobufAny:
      type: object
      properties:
        '@type':
          type: string
          description: The type of the serialized message.
      additionalProperties: true
      description: >-
        Contains an arbitrary serialized message along with a @type that
        describes the type of the serialized message.
    BareMetadata:
      type: object
      properties:
        id:
          readOnly: true
          type: string
        name:
          readOnly: true
          type: string
          description: >-
            Human-readable name of the referenced resource, populated by the
            server
             on reads for convenience. Absent on references to resources that do not
             have a name (e.g., objective tasks).
      description: |-
        BareMetadata contains the minimal metadata for a resource: the ID and an
         optional human-readable name. These are used for reference fields where the
         full metadata (account scoping, timestamps, labels, external IDs) is not
         needed — e.g., the tool references inside an agent variation spec or the
         tools assigned to an objective. Both fields are server-populated; clients
         provide IDs through sibling fields rather than by constructing a
         BareMetadata themselves.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````