# Packs

Generated from contract version `1.0.0` — the same document [`/v1/api/openapi.json`](/api/openapi/) serves.

## Prerequisites

- An API key in `x-api-key`, or a browser session cookie
- `X-Organization-Id` naming the workspace to act in, unless the session already has an active one
- The base URL for your deployment, `https://server.hlix.ai` by default

## Operations

| Method | Path | Operation |
| --- | --- | --- |
| `GET` | `/v1/api/packs` | [List every pack the registry knows](#list-every-pack-the-registry-knows) |
| `DELETE` | `/v1/api/packs/{id}` | [Detach a pack from a project](#detach-a-pack-from-a-project) |
| `PATCH` | `/v1/api/packs/{id}` | [Toggle an attached pack](#toggle-an-attached-pack) |
| `GET` | `/v1/api/packs/custom-skills` | [List the workspace's own skills](#list-the-workspaces-own-skills) |
| `POST` | `/v1/api/packs/custom-skills` | [Write a custom skill](#write-a-custom-skill) |
| `DELETE` | `/v1/api/packs/custom-skills/{slug}` | [Delete a custom skill](#delete-a-custom-skill) |
| `GET` | `/v1/api/packs/custom-skills/{slug}` | [Get one custom skill](#get-one-custom-skill) |
| `PATCH` | `/v1/api/packs/custom-skills/{slug}` | [Update a custom skill](#update-a-custom-skill) |
| `POST` | `/v1/api/packs/custom-skills/generate` | [Draft a custom skill from a description (never saves)](#draft-a-custom-skill-from-a-description-never-saves) |
| `GET` | `/v1/api/packs/project/{projectId}` | [List a project's attached packs](#list-a-projects-attached-packs) |
| `POST` | `/v1/api/packs/project/{projectId}` | [Attach a pack to a project](#attach-a-pack-to-a-project) |

## List every pack the registry knows

`GET /v1/api/packs` · operation ID `listAvailablePacks`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `projectId` | query | no | string | Report attachment against THIS project. Omitted, every entry comes back `isActive: false` — which means "not asked", not "attached to nothing". |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AvailablePack[] | The whole registry, with attachment state. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Detach a pack from a project

`DELETE /v1/api/packs/{id}` · operation ID `detachProjectPack`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | DeletedAck | The attachment row is gone. The pack itself is untouched. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | The caller is a client collaborator on this pack's project; pack configuration is agency-only. |
| `404` | ApiError | No such attached pack in this workspace — or the caller is a client collaborator with no access to its project, which answers the same 404 rather than confirming it exists. |

## Toggle an attached pack

`PATCH /v1/api/packs/{id}` · operation ID `updateProjectPack`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `UpdatePack` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `isActive` | boolean | **yes** |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | ProjectPack | The updated attachment row. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | The caller is a client collaborator on this pack's project; pack configuration is agency-only. |
| `404` | ApiError | No such attached pack in this workspace — or the caller is a client collaborator with no access to its project, which answers the same 404 rather than confirming it exists. |

## List the workspace's own skills

`GET /v1/api/packs/custom-skills` · operation ID `listCustomSkills`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CustomSkill[] | Every custom skill, with its markdown. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Write a custom skill

`POST /v1/api/packs/custom-skills` · operation ID `createCustomSkill`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `CreateCustomSkill` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `content` | string | **yes** | min length 1 |
| `description` | string | **yes** | min length 1, max length 1000 |
| `enabled` | boolean | no |  |
| `name` | string | **yes** | min length 1, max length 200 |
| `projectIds` | string (uuid)[] | no |  |
| `slug` | string | **yes** | min length 1, max length 100 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | CustomSkill | The stored skill. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Delete a custom skill

`DELETE /v1/api/packs/custom-skills/{slug}` · operation ID `deleteCustomSkill`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `slug` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | DeletedAck | The skill is gone. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | No custom skill with that slug in this workspace. |

## Get one custom skill

`GET /v1/api/packs/custom-skills/{slug}` · operation ID `getCustomSkill`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `slug` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CustomSkill | The skill. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | No custom skill with that slug in this workspace. |

## Update a custom skill

`PATCH /v1/api/packs/custom-skills/{slug}` · operation ID `updateCustomSkill`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `slug` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `UpdateCustomSkill` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `content` | string | no | min length 1 |
| `description` | string | no | min length 1, max length 1000 |
| `enabled` | boolean | no |  |
| `name` | string | no | min length 1, max length 200 |
| `projectIds` | string (uuid)[] | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | CustomSkill | The updated skill. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | No custom skill with that slug in this workspace. |

## Draft a custom skill from a description (never saves)

`POST /v1/api/packs/custom-skills/generate` · operation ID `generateCustomSkill`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `GenerateCustomSkill` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `context` | string[] | no |  |
| `description` | string | **yes** | min length 1, max length 2000 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | GeneratedSkillDraft | The draft. It only prefills the review form; saving is the caller's explicit act. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |
| `502` | ApiError | The drafting model call failed or timed out. The draft was not produced and nothing was stored. |

## List a project's attached packs

`GET /v1/api/packs/project/{projectId}` · operation ID `listProjectPacks`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `projectId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | ProjectPack[] | The attachment rows, active or not. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not a member of the named organization — or a client collaborator without the required access on this project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Attach a pack to a project

`POST /v1/api/packs/project/{projectId}` · operation ID `attachProjectPack`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `projectId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `ActivatePack` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `packName` | string | **yes** | min length 1, max length 100 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | ProjectPack | The attachment row, active. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | The caller is a client collaborator WITH access to this project; pack configuration is agency-only. |
| `404` | ApiError | No such project for this caller. A client with NO grant on it gets this rather than the 403 above — the refusal must not confirm the project exists. |

## If a request fails

These apply to every operation on this page.

- `400` — the body failed schema validation, or the request named no active organization. A `ValidationError` body carries the failing fields; an `ApiError` body carries only `error`.
- `401` — no valid session or API key.
- `403` — authenticated, but not a member of the named organization, or a client collaborator without the required access.
- `404` — no such resource **in this workspace**. Absent and not-visible are deliberately the same answer; do not infer cross-tenant existence from it.
- `409` — the expected revision or state is stale, or another operation currently owns the transition.
- `500` — the operation failed server-side. Retry only where an idempotency key makes that safe.

## Next steps

[API reference](/api/reference/)
  [API & OpenAPI](/api/openapi/)
  [TypeScript SDK](/sdk/typescript/)
  [CLI reference](/reference/cli/)