{
  "openapi": "3.0.3",
  "info": {
    "title": "User API",
    "description": "The User API allows you to programmatically access and manage user-scoped resources such as MCP servers, toolkits, commands, skills, and integration connections.\n\nUnlike the admin Willow API which operates at the organization level, the User API operates in the context of a specific user and returns only the resources accessible to that user.\n\n## Authentication\n\nEvery User API request needs two things: an **authorization token** and a header that identifies **which user to act as**.\n\n### 1. Authorization Token\n\nThe same Bearer token used for the Willow API. Include it in the `Authorization` header:\n```\nAuthorization: Bearer wxt_xxxxx\n```\n\n### 2. Acting User\n\nProvide **exactly one** of the following headers to select the user whose resources the request operates on. The selected user must belong to the organization associated with the API token.\n\n- **Regular user** — `x-user-email` with the user's email:\n  ```\n  x-user-email: user@example.com\n  ```\n- **Machine user** — `x-machine-user` with the machine user's slug. Use this for bots, scripts, and automations, which have a synthetic email and are identified by slug instead:\n  ```\n  x-machine-user: ci-deploy-bot\n  ```\n\nSending neither header, or both of them, fails with `400` (`x-user-email or x-machine-user header is required`). A slug passed to `x-machine-user` that doesn't resolve to a machine user in the organization returns `404` (`Machine user not found: <slug>`).\n\nSee [API Tokens](/docs/admin/api-tokens) for more details on generating and managing tokens.\n\n## Pagination\n\nList endpoints support cursor-based pagination with the following query parameters:\n- `limit` — Maximum number of items to return (default: 50, max: 100)\n- `cursor` — Opaque cursor for the next page of results\n\nThe response includes a `pagination` object:\n```json\n{\n  \"data\": [...],\n  \"pagination\": {\n    \"limit\": 50,\n    \"nextCursor\": \"50\"\n  }\n}\n```\n\nWhen `nextCursor` is `null`, there are no more results.\n",
    "version": "1.0.0",
    "contact": {
      "name": "Willow Support",
      "url": "https://withwillow.ai"
    }
  },
  "servers": [
    {
      "url": "https://{org}.withwillow.ai",
      "description": "Your organization's Willow gateway domain (or its custom gateway domain)",
      "variables": {
        "org": {
          "default": "<org>",
          "description": "Your organization's subdomain. Ask your Willow admin."
        }
      }
    }
  ],
  "tags": [
    {
      "name": "User API",
      "description": "Access user-scoped resources"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/mcp-servers": {
      "get": {
        "operationId": "listUserMcpServers",
        "summary": "List User MCP Servers",
        "description": "Returns a list of MCP servers (integrations) accessible to the specified user.\n\nAlternatively, pass `x-willow-group` to scope the list to a specific group instead of a user — see the header description below.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WillowGroupHeader"
          },
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by server status.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "draft"
              ]
            },
            "example": "active"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Case-insensitive search against MCP server name and description.",
            "schema": {
              "type": "string"
            },
            "example": "slack"
          },
          {
            "name": "include_tools",
            "in": "query",
            "required": false,
            "description": "When set to `true`, includes the list of enabled tools for each server, with each tool's `name`, `slug`, and `description`.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          },
          {
            "name": "include_schemas",
            "in": "query",
            "required": false,
            "description": "When set to `true`, includes the list of enabled tools for each server, with each tool's MCP `inputSchema` in addition to `name`, `slug`, and `description`. Implies `include_tools`.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          },
          {
            "name": "is_local_mcp",
            "in": "query",
            "required": false,
            "description": "Filter by local MCP status. Set to `true` to return only local (stdio) servers, or `false` to return only remote (HTTP) servers. Omit to return all servers.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "List of MCP servers retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/UserMcpServer"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/CursorPagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/MissingUserEmail"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "User not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "User not found: user@example.com"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to list MCP servers"
                }
              }
            }
          }
        }
      }
    },
    "/api/toolkits": {
      "get": {
        "operationId": "listUserToolkits",
        "summary": "List User Toolkits",
        "description": "Returns a list of toolkits accessible to the specified user, including both user-owned and organization-level toolkits.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "List of toolkits retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/UserToolkit"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/CursorPagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to list toolkits"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createUserToolkit",
        "summary": "Create User Toolkit",
        "description": "Creates a new toolkit owned by the specified user.\n\nThe toolkit slug will be automatically prefixed with the user's email (e.g., `user@example.com:my-toolkit`).\n\nThat prefixed slug is the toolkit's public identifier, and the only\nvalue that addresses it afterwards. Reading, updating and deleting\nwith the bare slug you sent all return 404, so read `slug` back from\nthis response and store that.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "name": "x-user-email",
            "in": "header",
            "required": false,
            "description": "Email of the user who will own the toolkit. Provide this **or** `x-machine-user` — exactly one is required.",
            "schema": {
              "type": "string"
            },
            "example": "user@example.com"
          },
          {
            "name": "x-machine-user",
            "in": "header",
            "required": false,
            "description": "Slug of the machine user who will own the toolkit. Provide this **or** `x-user-email` — exactly one is required.",
            "schema": {
              "type": "string"
            },
            "example": "ci-deploy-bot"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUserToolkitRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic Toolkit",
                  "description": "Create a minimal toolkit with just a name and slug",
                  "value": {
                    "name": "My Toolkit",
                    "slug": "my-toolkit"
                  }
                },
                "withTools": {
                  "summary": "Toolkit with Integration Tools",
                  "description": "Create a toolkit with selected tools from integrations",
                  "value": {
                    "name": "Dev Toolkit",
                    "slug": "dev-toolkit",
                    "description": "Development workflow toolkit",
                    "integration_tools": {
                      "github": "all",
                      "slack": [
                        "post-message"
                      ]
                    }
                  }
                },
                "full": {
                  "summary": "Full Configuration",
                  "description": "Create a toolkit with prompts, resources, and tool overrides",
                  "value": {
                    "name": "Complete Toolkit",
                    "slug": "complete-toolkit",
                    "description": "A fully configured toolkit",
                    "integration_tools": {
                      "github": "all"
                    },
                    "descriptions": {
                      "tools": {
                        "create-issue": {
                          "description": "Create a GitHub issue in our main repo",
                          "constantInputs": {
                            "repo": "main-repo",
                            "owner": "our-org"
                          }
                        }
                      }
                    },
                    "prompts": [
                      {
                        "name": "Code Review",
                        "slug": "code-review",
                        "description": "Review code changes",
                        "outputContent": "Review the following code:\n\n{{code}}",
                        "arguments": [
                          {
                            "name": "code",
                            "type": "string",
                            "required": true
                          }
                        ]
                      }
                    ],
                    "resources": [
                      {
                        "name": "Standards",
                        "slug": "standards",
                        "description": "Coding standards",
                        "outputContent": "Use TypeScript strict mode."
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Toolkit created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UserToolkit"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing name",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  },
                  "invalidPrompt": {
                    "summary": "Invalid prompt",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "prompts.0.outputContent: Required"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to create toolkit"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateUserToolkit",
        "summary": "Update User Toolkit",
        "description": "Updates an existing user toolkit by slug.\n\nOnly the fields provided in the request body will be updated. The authenticated user must be the owner of the toolkit.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "name": "x-user-email",
            "in": "header",
            "required": false,
            "description": "Email of the user (must be the toolkit owner). Provide this **or** `x-machine-user` — exactly one is required.",
            "schema": {
              "type": "string"
            },
            "example": "user@example.com"
          },
          {
            "name": "x-machine-user",
            "in": "header",
            "required": false,
            "description": "Slug of the machine user (must be the toolkit owner). Provide this **or** `x-user-email` — exactly one is required.",
            "schema": {
              "type": "string"
            },
            "example": "ci-deploy-bot"
          },
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The full slug of the toolkit (e.g., user@example.com:my-toolkit)",
            "schema": {
              "type": "string"
            },
            "example": "user@example.com:my-toolkit"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserToolkitRequest"
              },
              "examples": {
                "updateName": {
                  "summary": "Update Name",
                  "value": {
                    "name": "Updated Toolkit Name"
                  }
                },
                "updateStatus": {
                  "summary": "Update Status",
                  "value": {
                    "status": "draft"
                  }
                },
                "updateTools": {
                  "summary": "Update Integration Tools",
                  "value": {
                    "integration_tools": {
                      "github": "all",
                      "slack": [
                        "post-message",
                        "list-channels"
                      ]
                    },
                    "descriptions": {
                      "tools": {
                        "create-issue": {
                          "description": "Create an issue in our main repo",
                          "constantInputs": {
                            "repo": "main-repo"
                          }
                        }
                      }
                    }
                  }
                },
                "updatePrompts": {
                  "summary": "Update Prompts",
                  "value": {
                    "prompts": [
                      {
                        "name": "Code Review",
                        "slug": "code-review",
                        "description": "Review code changes",
                        "outputContent": "Review this code:\n\n{{code}}",
                        "arguments": [
                          {
                            "name": "code",
                            "type": "string",
                            "required": true
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Toolkit updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UserToolkit"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter or invalid body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingSlug": {
                    "summary": "Missing slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug query parameter is required"
                    }
                  },
                  "invalidStatus": {
                    "summary": "Invalid status",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "status: Invalid enum value"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Not the owner of the toolkit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "You are not the owner of this toolkit"
                }
              }
            }
          },
          "404": {
            "description": "Toolkit not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Toolkit not found: user@example.com:my-toolkit"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to update toolkit"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteUserToolkit",
        "summary": "Delete User Toolkit",
        "description": "Deletes a user toolkit by slug.\n\nOnly the owner of the toolkit can delete it. This operation is permanent and cannot be undone.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "name": "x-user-email",
            "in": "header",
            "required": false,
            "description": "Email of the user (must be the toolkit owner). Provide this **or** `x-machine-user` — exactly one is required.",
            "schema": {
              "type": "string"
            },
            "example": "user@example.com"
          },
          {
            "name": "x-machine-user",
            "in": "header",
            "required": false,
            "description": "Slug of the machine user (must be the toolkit owner). Provide this **or** `x-user-email` — exactly one is required.",
            "schema": {
              "type": "string"
            },
            "example": "ci-deploy-bot"
          },
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The full slug of the toolkit to delete (e.g., user@example.com:my-toolkit)",
            "schema": {
              "type": "string"
            },
            "example": "user@example.com:my-toolkit"
          }
        ],
        "responses": {
          "200": {
            "description": "Toolkit deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Toolkit deleted successfully"
                    }
                  }
                },
                "example": {
                  "message": "Toolkit deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Not the owner of the toolkit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "You are not the owner of this toolkit"
                }
              }
            }
          },
          "404": {
            "description": "Toolkit not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Toolkit not found: user@example.com:my-toolkit"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to delete toolkit"
                }
              }
            }
          }
        }
      }
    },
    "/api/commands": {
      "get": {
        "operationId": "listUserCommands",
        "summary": "List User Commands",
        "description": "Returns a list of active commands accessible to the specified user.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "List of commands retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/UserCommand"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/CursorPagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to list commands"
                }
              }
            }
          }
        }
      }
    },
    "/api/skills": {
      "get": {
        "operationId": "listUserSkills",
        "summary": "List User Skills",
        "description": "Returns a list of skills accessible to the specified user. Supports pagination, search by name, and fetching skills by id or slug.\n\nWhen a single `id` or `slug` is provided, returns a single skill object with additional metadata fields instead of a paginated list.\n\nWhen multiple `id` or `slug` values are provided (comma-separated or repeated), returns an array of skill objects. Skills that are not found are omitted from the array.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Search skills by name, slug, or description (case-insensitive partial match)",
            "schema": {
              "type": "string"
            },
            "example": "my-skill"
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Fetch skills by id. Accepts a single value, a comma-separated list (`id=a,b`), or a repeated parameter (`id=a&id=b`). A single value returns one skill object; multiple values return an array of skill objects.\n",
            "schema": {
              "type": "string"
            },
            "example": "sk_abc123"
          },
          {
            "name": "slug",
            "in": "query",
            "required": false,
            "description": "Fetch skills by slug. Accepts a single value, a comma-separated list (`slug=a,b`), or a repeated parameter (`slug=a&slug=b`). A single value returns one skill object; multiple values return an array of skill objects.\n",
            "schema": {
              "type": "string"
            },
            "example": "user@example.com:my-skill"
          }
        ],
        "responses": {
          "200": {
            "description": "List of skills retrieved successfully. When a single `id` or `slug` is provided, returns a single skill object with additional fields (metadata, allowed_tools) instead of a paginated list. When multiple `id` or `slug` values are provided, returns an array of those skill objects (missing skills omitted).\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "title": "Paginated List Response",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/UserSkill"
                          }
                        },
                        "pagination": {
                          "$ref": "#/components/schemas/CursorPagination"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "title": "Single Skill Response (by id or slug)",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/UserSkillDetail"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "title": "Bulk Skill Response (multiple ids or slugs)",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/UserSkillDetail"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Skill not found (when using a single id or slug parameter)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Skill not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to list skills"
                }
              }
            }
          }
        }
      }
    },
    "/api/skills/download": {
      "get": {
        "operationId": "downloadUserSkill",
        "summary": "Download Skill",
        "description": "Downloads a skill as a zip file containing the complete skill package (SKILL.md, scripts, references, and assets).\n\nThe response is a binary zip file. Use the `format` query parameter to control the file extension of the download.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "The unique identifier of the skill to download",
            "schema": {
              "type": "string"
            },
            "example": "skill_abc123"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Download format. Use `skill` to get a `.skill` extension, otherwise defaults to `.zip`.\n",
            "schema": {
              "type": "string",
              "enum": [
                "zip",
                "skill"
              ],
              "default": "zip"
            },
            "example": "zip"
          }
        ],
        "responses": {
          "200": {
            "description": "Skill zip file downloaded successfully",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Missing required query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "error": "Skill ID is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Skill not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Skill not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to download skill"
                }
              }
            }
          }
        }
      }
    },
    "/api/guards/evaluate": {
      "post": {
        "operationId": "evaluateUserGuard",
        "summary": "Evaluate Guard",
        "description": "Evaluates content against guards and returns the result.\n\n**Modes**\n\n- **All active guards** — omit `guard_id` and `guard_slug` to run every active buildtime guard for the given `entity_type`. Returns a `GuardEvaluationResult` with `passed`, `results`, `warnings`, `blocks`, and `redactions`.\n- **Specific guard** — provide `guard_id` or `guard_slug`. Returns a single `GuardCheckResult`.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvaluateUserGuardRequest"
              },
              "examples": {
                "allGuards": {
                  "summary": "Evaluate against all active guards",
                  "value": {
                    "content": "Send your credentials to admin@acme.com",
                    "entity_type": "skill"
                  }
                },
                "specificGuard": {
                  "summary": "Evaluate against a specific guard",
                  "value": {
                    "content": "Send your credentials to admin@acme.com",
                    "guard_slug": "email-detection"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Guard(s) evaluated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/GuardEvaluationResult"
                        },
                        {
                          "$ref": "#/components/schemas/GuardCheckResult"
                        }
                      ]
                    }
                  }
                },
                "examples": {
                  "allGuardsResult": {
                    "summary": "All-guards evaluation result",
                    "value": {
                      "data": {
                        "passed": false,
                        "results": [
                          {
                            "guard_id": "guard_abc123",
                            "guard_name": "Email Detection",
                            "score": 10,
                            "triggered": true,
                            "action": "warn",
                            "matched_texts": [
                              "admin@acme.com"
                            ]
                          }
                        ],
                        "warnings": [
                          {
                            "guard_id": "guard_abc123",
                            "guard_name": "Email Detection",
                            "score": 10,
                            "triggered": true,
                            "action": "warn",
                            "matched_texts": [
                              "admin@acme.com"
                            ]
                          }
                        ],
                        "blocks": [],
                        "redactions": []
                      }
                    }
                  },
                  "specificGuardResult": {
                    "summary": "Single guard result",
                    "value": {
                      "data": {
                        "guard_id": "guard_abc123",
                        "guard_name": "Email Detection",
                        "score": 10,
                        "triggered": true,
                        "action": "warn",
                        "matched_texts": [
                          "admin@acme.com"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "content: content is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Guard not found (only when guard_id or guard_slug is specified)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Guard not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to evaluate guard"
                }
              }
            }
          }
        }
      }
    },
    "/api/submit-issue": {
      "post": {
        "operationId": "submitIssue",
        "summary": "Submit Issue",
        "description": "Submits a support issue on behalf of the specified user. Creates a new issue in the support system with the given title and description.\n\nThe issue is associated with the user's email address.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitIssueRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic Issue",
                  "value": {
                    "title": "Cannot connect to GitHub integration",
                    "body_html": "<p>I'm getting a timeout error when trying to connect my GitHub account.</p>"
                  }
                },
                "withPriority": {
                  "summary": "Issue with Priority and Tags",
                  "value": {
                    "title": "Critical authentication failure",
                    "body_html": "<p>All users in our org are unable to authenticate since 10:00 AM.</p>",
                    "priority": "urgent",
                    "tags": [
                      "authentication",
                      "critical"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Issue submitted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/SubmittedIssue"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingTitle": {
                    "summary": "Missing title",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "title: title is required"
                    }
                  },
                  "emptyBody": {
                    "summary": "Empty body",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "body_html: body_html cannot be empty"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to submit issue"
                }
              }
            }
          },
          "503": {
            "description": "Issue submission not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Issue submission is not configured"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth-url": {
      "get": {
        "operationId": "getAuthUrl",
        "summary": "Get Auth URL",
        "description": "Generates an authentication URL that the user can visit to connect their account to an integration (e.g., GitHub, Slack, Jira).\n\nThe returned URL initiates the OAuth flow for the specified integration.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          },
          {
            "name": "integration",
            "in": "query",
            "required": true,
            "description": "The slug of the integration to authenticate with",
            "schema": {
              "type": "string"
            },
            "example": "github"
          }
        ],
        "responses": {
          "200": {
            "description": "Auth URL generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "string",
                      "description": "The authentication URL to redirect the user to",
                      "example": "https://<org>.withwillow.ai/<org>/api/auth/init?state=..."
                    }
                  }
                },
                "example": {
                  "data": "https://<org>.withwillow.ai/<org>/api/auth/init?state=..."
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid integration parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "integration is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to generate auth URL"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{agent}/auth-url": {
      "get": {
        "operationId": "getBackgroundAgentAuthUrl",
        "summary": "Get Background Agent Auth URL",
        "description": "Generates an authentication URL that connects one of a background agent's MCP servers.\n\nA background agent is not a user, so it cannot hold a connection of its own — it runs an MCP server as the connected account of an org member. That is the person themselves for a personal assistant, or a dedicated bot user (for example an Okta service account) for a shared agent.\n\nUnlike the other User API endpoints this one identifies the acting account from the agent instead of from a header, so no `x-user-email` / `x-machine-user` is needed. Without `user_email` the link is for the account the agent is already configured to run that MCP server as.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "description": "The slug or ID of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "release-bot"
          },
          {
            "name": "integration",
            "in": "query",
            "required": true,
            "description": "The slug of the integration to authenticate with",
            "schema": {
              "type": "string"
            },
            "example": "github"
          },
          {
            "name": "user_email",
            "in": "query",
            "required": false,
            "description": "Connect this account instead of the one the agent is configured with. Must already exist in the organization.",
            "schema": {
              "type": "string"
            },
            "example": "bot-github@acme.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Auth URL generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "string",
                      "description": "The authentication URL to open for the resolved account"
                    },
                    "agent": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "slug": {
                          "type": "string"
                        }
                      }
                    },
                    "integration": {
                      "type": "string"
                    },
                    "user_email": {
                      "type": "string",
                      "description": "The account the connection will be stored against"
                    }
                  }
                },
                "example": {
                  "data": "https://<org>.withwillow.ai/<org>/api/auth/init?state=...",
                  "agent": {
                    "id": "6f1c2a54-9d0e-4a1b-9f7e-2b3c4d5e6f70",
                    "slug": "release-bot"
                  },
                  "integration": "github",
                  "user_email": "bot-github@acme.com"
                }
              }
            }
          },
          "400": {
            "description": "Missing `integration`, or the agent has no connected account configured for it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "error": "\"release-bot\" has no connected account configured for \"github\". Pass user_email, or set the MCP server's authentication to a connected account first."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Background agent or user not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Background agent not found: release-bot"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to generate auth URL"
                }
              }
            }
          }
        }
      }
    },
    "/api/is-connected": {
      "get": {
        "operationId": "checkConnection",
        "summary": "Check Connection",
        "description": "Checks whether the specified user has an active connection to a given integration.\n\nUse this endpoint to determine if the user needs to authenticate with an integration before using its tools.\n",
        "tags": [
          "User API"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserEmailHeader"
          },
          {
            "$ref": "#/components/parameters/MachineUserHeader"
          },
          {
            "name": "integration",
            "in": "query",
            "required": true,
            "description": "The slug of the integration to check",
            "schema": {
              "type": "string"
            },
            "example": "github"
          }
        ],
        "responses": {
          "200": {
            "description": "Connection status retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "boolean",
                      "description": "Whether the user is connected to the integration",
                      "example": true
                    }
                  }
                },
                "examples": {
                  "connected": {
                    "summary": "User is connected",
                    "value": {
                      "data": true
                    }
                  },
                  "notConnected": {
                    "summary": "User is not connected",
                    "value": {
                      "data": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid integration parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "integration is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The token is valid but its scopes do not permit this operation, or the\nacting user does not own the resource. Every endpoint enforces the scopes\ndescribed in [API Tokens](/docs/admin/api-tokens).\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Forbidden"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Failed to check connection status"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API token authentication. Tokens are prefixed with `wxt_` and can be generated from Admin Settings.\n"
      }
    },
    "parameters": {
      "UserEmailHeader": {
        "name": "x-user-email",
        "in": "header",
        "required": false,
        "description": "Email address of the user to act as. Provide this header **or** `x-machine-user` (a machine user's slug) — exactly one is required. Sending both returns `400`.",
        "schema": {
          "type": "string"
        },
        "example": "user@example.com"
      },
      "MachineUserHeader": {
        "name": "x-machine-user",
        "in": "header",
        "required": false,
        "description": "Slug of the machine user to act as (for bots, scripts, and automations). Provide this header **or** `x-user-email` — exactly one is required. Sending both returns `400`.",
        "schema": {
          "type": "string"
        },
        "example": "ci-deploy-bot"
      },
      "WillowGroupHeader": {
        "name": "x-willow-group",
        "in": "header",
        "required": false,
        "description": "Name of a group (case-insensitive) to scope the response to, instead of the acting user's own groups. When provided, this takes priority over `x-user-email` / `x-machine-user` and no user identity is required. An unknown group resolves to an empty list rather than an error.",
        "schema": {
          "type": "string"
        },
        "example": "engineering"
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Maximum number of items to return (default: 50, max: 100)",
        "schema": {
          "type": "integer",
          "default": 50
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "Pagination cursor from a previous response",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Authentication required or invalid token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Invalid authorization credentials"
            }
          }
        }
      },
      "MissingUserEmail": {
        "description": "The acting-user headers were not supplied correctly. Exactly one of `x-user-email` or `x-machine-user` is required: sending neither, or sending both, returns this error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "x-user-email or x-machine-user header is required"
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          }
        }
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Error code",
            "example": "INVALID_FORMAT"
          },
          "message": {
            "type": "string",
            "description": "Detailed error message"
          },
          "error": {
            "type": "string"
          }
        }
      },
      "CursorPagination": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "example": 50
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "example": "50"
          }
        }
      },
      "UserMcpServer": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Unique identifier",
            "example": "my-server"
          },
          "name": {
            "type": "string",
            "description": "Display name",
            "example": "My MCP Server"
          },
          "description": {
            "type": "string",
            "description": "Description",
            "example": "Custom MCP server"
          },
          "logo_url": {
            "type": "string",
            "description": "URL of the server logo",
            "example": "https://example.com/logo.png",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          },
          "auth_type": {
            "type": "string",
            "description": "Authentication type required by the server (e.g. OAuth2, API Key)",
            "example": "OAuth2",
            "nullable": true
          },
          "tools_count": {
            "type": "integer",
            "description": "Number of enabled tools on this server",
            "example": 5
          },
          "tools": {
            "type": "array",
            "description": "List of enabled tools. Included when `include_tools=true` or `include_schemas=true`.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Tool display name",
                  "example": "Send Message"
                },
                "slug": {
                  "type": "string",
                  "description": "Tool identifier",
                  "example": "send-message"
                },
                "description": {
                  "type": "string",
                  "description": "Tool description",
                  "example": "Send a message to a channel"
                },
                "inputSchema": {
                  "type": "object",
                  "description": "MCP JSON Schema describing the tool's input parameters. Only included when `include_schemas=true`.",
                  "example": {
                    "type": "object",
                    "properties": {
                      "channel": {
                        "type": "string",
                        "description": "Channel ID or name"
                      },
                      "text": {
                        "type": "string",
                        "description": "Message text"
                      }
                    },
                    "required": [
                      "channel",
                      "text"
                    ]
                  }
                }
              }
            }
          },
          "is_local_mcp": {
            "type": "boolean",
            "description": "Whether this is a local (stdio) MCP server",
            "example": false
          },
          "connection": {
            "type": "object",
            "description": "Connection details for the MCP server",
            "properties": {
              "url": {
                "type": "string",
                "description": "MCP server endpoint URL",
                "example": "https://gateway.example.com/mcp?mcp=my-server"
              },
              "transport": {
                "type": "string",
                "enum": [
                  "http",
                  "stdio",
                  "both"
                ],
                "description": "Supported transport protocol. `stdio` for local servers, `both` for remote servers.",
                "example": "both"
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation timestamp.",
            "example": "2026-01-15T09:30:00Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last modification timestamp.",
            "example": "2026-01-15T09:30:00Z"
          }
        }
      },
      "UserToolkit": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "tk_abc123"
          },
          "slug": {
            "type": "string",
            "description": "The toolkit's public identifier, namespaced to its owner as\n`<owner-email>:<slug>`. The server builds this from the bare `slug`\nsupplied at creation; it is **not** the value that was sent.\n\nThis composite is the addressing key for every subsequent\noperation on the toolkit. Requests made with the bare slug return\n404, so store the value returned here rather than the one you sent.\n",
            "example": "user@example.com:my-toolkit"
          },
          "name": {
            "type": "string",
            "example": "My Toolkit"
          },
          "description": {
            "type": "string",
            "example": "Custom toolkit"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          },
          "owner_id": {
            "type": "string",
            "description": "ID of the toolkit owner"
          },
          "integration_tools": {
            "type": "object",
            "additionalProperties": true,
            "description": "Map of integration slug to tool selection. Use \"all\" or an array of tool names.",
            "example": {
              "github": "all",
              "slack": [
                "post-message",
                "list-channels"
              ]
            }
          },
          "descriptions": {
            "type": "object",
            "nullable": true,
            "description": "Tool description overrides. Null on a toolkit that has never had any\nset, which is the case for every freshly created toolkit.\n",
            "properties": {
              "tools": {
                "type": "object",
                "additionalProperties": {
                  "type": "object",
                  "properties": {
                    "description": {
                      "type": "string"
                    },
                    "inputParams": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    },
                    "nameOverride": {
                      "type": "string"
                    },
                    "constantInputs": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "prompts": {
            "type": "object",
            "nullable": true,
            "description": "Null until prompts are added.",
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PromptItem"
                }
              }
            }
          },
          "resources": {
            "type": "object",
            "nullable": true,
            "description": "Null until resources are added.",
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ResourceItem"
                }
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "is_org": {
            "type": "boolean",
            "description": "True when this is an organization-level record rather than user-owned.",
            "example": false
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          }
        }
      },
      "CreateUserToolkitRequest": {
        "type": "object",
        "required": [
          "name",
          "slug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the toolkit",
            "example": "My Toolkit",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier. Must be lowercase alphanumeric with\nhyphens only.\n\nThe stored slug is namespaced to the owner, so a request for\n`my-toolkit` is created as `user@example.com:my-toolkit` and the\n201 returns that composite. The composite is what addresses the\ntoolkit afterwards; the bare slug you sent here returns 404. Read\nthe slug back from the response instead of assuming it.\n",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "example": "my-toolkit"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the toolkit",
            "example": "My custom toolkit for development workflows"
          },
          "integration_tools": {
            "type": "object",
            "additionalProperties": true,
            "description": "Map of integration slug to tool selection. Use `\"all\"` to include all tools from an integration, or an array of specific tool names.",
            "example": {
              "github": "all",
              "slack": [
                "post-message",
                "list-channels"
              ]
            }
          },
          "descriptions": {
            "$ref": "#/components/schemas/ToolDescriptions"
          },
          "prompts": {
            "type": "array",
            "description": "Array of prompt templates included in the toolkit",
            "items": {
              "$ref": "#/components/schemas/PromptInput"
            },
            "example": [
              {
                "name": "Code Review",
                "slug": "code-review",
                "description": "Review code for best practices",
                "outputContent": "Review the following code for best practices, potential bugs, and improvements:\n\n{{code}}",
                "arguments": [
                  {
                    "name": "code",
                    "type": "string",
                    "description": "The code to review",
                    "required": true
                  }
                ]
              }
            ]
          },
          "resources": {
            "type": "array",
            "description": "Array of resource configurations included in the toolkit",
            "items": {
              "$ref": "#/components/schemas/ResourceInput"
            },
            "example": [
              {
                "name": "Coding Standards",
                "slug": "coding-standards",
                "description": "Team coding standards and conventions",
                "outputContent": "# Coding Standards\n\n- Use TypeScript strict mode\n- Prefer const over let\n- ..."
              }
            ]
          }
        }
      },
      "UpdateUserToolkitRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the toolkit",
            "example": "Updated Toolkit Name",
            "minLength": 1
          },
          "description": {
            "type": "string",
            "description": "Human-readable description",
            "example": "Updated description"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "description": "Toolkit visibility status. `active` makes it visible to users, `draft` hides it."
          },
          "integration_tools": {
            "type": "object",
            "additionalProperties": true,
            "description": "Map of integration slug to tool selection. Use `\"all\"` to include all tools from an integration, or an array of specific tool names.",
            "example": {
              "github": "all",
              "slack": [
                "post-message"
              ]
            }
          },
          "descriptions": {
            "$ref": "#/components/schemas/ToolDescriptions"
          },
          "prompts": {
            "type": "array",
            "description": "Replaces all prompt templates. Each prompt requires name, slug, description, and outputContent.",
            "items": {
              "$ref": "#/components/schemas/PromptInput"
            }
          },
          "resources": {
            "type": "array",
            "description": "Replaces all resource configurations. Each resource requires name, slug, description, and outputContent.",
            "items": {
              "$ref": "#/components/schemas/ResourceInput"
            }
          }
        }
      },
      "ToolDescriptions": {
        "type": "object",
        "description": "Tool description overrides and customizations",
        "properties": {
          "tools": {
            "type": "object",
            "description": "Map of tool name to configuration overrides",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "description": {
                  "type": "string",
                  "description": "Override the tool's description"
                },
                "inputParams": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  },
                  "description": "Override descriptions for input parameters"
                },
                "nameOverride": {
                  "type": "string",
                  "description": "Override the tool's display name"
                },
                "constantInputs": {
                  "type": "object",
                  "description": "Input parameters that are always set to a constant value",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "PromptItem": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "outputContent": {
            "type": "string"
          },
          "arguments": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "PromptInput": {
        "type": "object",
        "required": [
          "name",
          "slug",
          "description",
          "outputContent"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name of the prompt"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the prompt"
          },
          "description": {
            "type": "string",
            "description": "Description of what the prompt does"
          },
          "outputContent": {
            "type": "string",
            "description": "The prompt template content"
          },
          "outputContents": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Alternative prompt content variants"
          },
          "arguments": {
            "type": "array",
            "description": "Arguments that the prompt accepts",
            "items": {
              "type": "object",
              "required": [
                "name",
                "type"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Argument name"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "string",
                    "number",
                    "boolean",
                    "array",
                    "object"
                  ],
                  "description": "Argument data type"
                },
                "description": {
                  "type": "string",
                  "description": "Argument description"
                },
                "required": {
                  "type": "boolean",
                  "description": "Whether the argument is required"
                },
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "enum": [
                        "string",
                        "number",
                        "boolean",
                        "object"
                      ]
                    }
                  },
                  "description": "Array item type (when type is \"array\")"
                }
              }
            }
          }
        }
      },
      "ResourceItem": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "outputContent": {
            "type": "string"
          }
        }
      },
      "ResourceInput": {
        "type": "object",
        "required": [
          "name",
          "slug",
          "description",
          "outputContent"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name of the resource"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the resource"
          },
          "description": {
            "type": "string",
            "description": "Description of the resource"
          },
          "outputContent": {
            "type": "string",
            "description": "The resource content"
          }
        }
      },
      "UserCommand": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cmd_abc123"
          },
          "slug": {
            "type": "string",
            "example": "my-command"
          },
          "name": {
            "type": "string",
            "example": "My Command"
          },
          "description": {
            "type": "string",
            "example": "A custom command"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          }
        }
      },
      "UserSkill": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "sk_abc123"
          },
          "slug": {
            "type": "string",
            "example": "user@example.com:my-skill"
          },
          "name": {
            "type": "string",
            "example": "My Skill"
          },
          "description": {
            "type": "string",
            "example": "A custom skill"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          }
        }
      },
      "UserSkillDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "sk_abc123"
          },
          "slug": {
            "type": "string",
            "example": "user@example.com:my-skill"
          },
          "name": {
            "type": "string",
            "example": "My Skill"
          },
          "description": {
            "type": "string",
            "example": "A custom skill"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "nullable": true,
            "example": {
              "author": "example-org",
              "version": "1.0"
            }
          },
          "allowed_tools": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true,
            "example": [
              "Bash(git:*)",
              "Read"
            ]
          }
        }
      },
      "EvaluateUserGuardRequest": {
        "type": "object",
        "required": [
          "content"
        ],
        "properties": {
          "content": {
            "type": "string",
            "minLength": 1,
            "description": "The text content to evaluate",
            "example": "Send your credentials to admin@acme.com"
          },
          "guard_id": {
            "type": "string",
            "description": "ID of a specific guard. When provided, only this guard runs and a GuardCheckResult is returned. Omit to run all active guards.",
            "example": "guard_abc123"
          },
          "guard_slug": {
            "type": "string",
            "description": "Slug of a specific guard. When provided, only this guard runs and a GuardCheckResult is returned. Omit to run all active guards.",
            "example": "email-detection"
          },
          "entity_type": {
            "type": "string",
            "enum": [
              "integration",
              "toolkit",
              "skill",
              "command"
            ],
            "description": "Entity type of the content. Scopes which guards run in all-active-guards mode. Guards with no entity_types restriction always run. Defaults to skill.",
            "example": "skill"
          }
        }
      },
      "GuardCheckResult": {
        "type": "object",
        "properties": {
          "guard_id": {
            "type": "string",
            "example": "guard_abc123"
          },
          "guard_name": {
            "type": "string",
            "example": "Email Detection"
          },
          "score": {
            "type": "number",
            "description": "Highest check score (0-10) produced for the guard",
            "example": 10
          },
          "triggered": {
            "type": "boolean",
            "description": "True when the score met or exceeded the guard threshold",
            "example": true
          },
          "action": {
            "type": "string",
            "enum": [
              "redact",
              "warn",
              "block"
            ],
            "example": "warn"
          },
          "matched_texts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "admin@acme.com"
            ]
          },
          "detail": {
            "type": "string",
            "description": "Optional human-readable detail about the result"
          }
        }
      },
      "GuardEvaluationResult": {
        "type": "object",
        "properties": {
          "passed": {
            "type": "boolean",
            "description": "True when no block-action guard was triggered",
            "example": false
          },
          "results": {
            "type": "array",
            "description": "Result for every active guard that ran",
            "items": {
              "$ref": "#/components/schemas/GuardCheckResult"
            }
          },
          "warnings": {
            "type": "array",
            "description": "Guards with action warn that were triggered",
            "items": {
              "$ref": "#/components/schemas/GuardCheckResult"
            }
          },
          "blocks": {
            "type": "array",
            "description": "Guards with action block that were triggered",
            "items": {
              "$ref": "#/components/schemas/GuardCheckResult"
            }
          },
          "redactions": {
            "type": "array",
            "description": "Guards with action redact that were triggered",
            "items": {
              "$ref": "#/components/schemas/GuardCheckResult"
            }
          }
        }
      },
      "SubmitIssueRequest": {
        "type": "object",
        "required": [
          "title",
          "body_html"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Title of the issue",
            "example": "Cannot connect to GitHub integration"
          },
          "body_html": {
            "type": "string",
            "description": "HTML body content describing the issue",
            "example": "<p>I'm getting a timeout error when trying to connect my GitHub account.</p>"
          },
          "tags": {
            "type": "array",
            "description": "Optional tags to categorize the issue",
            "items": {
              "type": "string"
            },
            "example": [
              "authentication",
              "github"
            ]
          },
          "priority": {
            "type": "string",
            "enum": [
              "urgent",
              "high",
              "normal",
              "low"
            ],
            "description": "Priority level of the issue",
            "example": "normal"
          }
        }
      },
      "SubmittedIssue": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The unique identifier of the created issue",
            "example": "iss_abc123"
          },
          "number": {
            "type": "integer",
            "description": "The human-readable issue number",
            "example": 42
          },
          "title": {
            "type": "string",
            "description": "The title of the issue",
            "example": "Cannot connect to GitHub integration"
          },
          "status": {
            "type": "string",
            "description": "The status of the issue",
            "example": "created"
          }
        }
      }
    }
  }
}
