# Packs & skills

**A skill is a written standard an agent reads before it writes code, and a pack is a curated set of them for one kind of stack.** They are how a house convention — "our API errors always carry a code", "migrations are reversible" — becomes something every agent on every task already knows, instead of something a person has to say again on each review.

Three things can put a skill in front of an agent, and they arrive by different routes.

| Source | Scope | How it reaches a task |
| --- | --- | --- |
| A pack | One project | Copied into the checkout's `.claude/skills/` from hlix's skill library |
| A workspace custom skill | The Workspace, optionally narrowed to named projects | Written into the checkout as a file |
| An imported skill | One project | Written into the checkout as a file, through that project's Environment |

## Prerequisites

- A project in your Workspace.
- `manage` access on the project to change its packs; `owner` or `admin` to write a Workspace custom skill.

## Packs

A pack bundles skill slugs and agent briefs for a technology. hlix matches packs to a project automatically from the stack it detected at import, and you can change the selection afterwards.

```bash
curl -sS "$HLIX_BASE_URL/v1/api/packs?projectId=$PROJECT_ID" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID"
```

Expected result: `200` and every available pack, each with its name, version, description, category, and the skill and agent slugs it carries.

```bash
curl -sS -X POST "$HLIX_BASE_URL/v1/api/packs/project/$PROJECT_ID" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -H 'content-type: application/json' \
  -d '{"packName":"typescript-api"}'
```

Expected result: `201` and the activated attachment.

`GET /v1/api/packs/project/{projectId}` lists what a project has. `PATCH /v1/api/packs/{id}` takes `{"isActive": false}` to switch one off without detaching it, and `DELETE /v1/api/packs/{id}` removes the attachment.

## Workspace custom skills

A custom skill is yours, written once and applied across the Workspace.

```bash
curl -sS -X POST "$HLIX_BASE_URL/v1/api/packs/custom-skills" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -H 'content-type: application/json' \
  -d '{
    "slug": "error-envelope",
    "name": "API error envelope",
    "description": "Every error response carries a stable machine code.",
    "content": "# API error envelope\n\nEvery error…"
  }'
```

Expected result: `201` and the stored skill.

| Field | Rule |
| --- | --- |
| `slug` | Lowercase letters, digits and hyphens; up to 100 characters. It is the identity |
| `name` | Up to 200 characters |
| `description` | Up to 1,000 characters — this is what an agent scans to decide the skill is relevant |
| `content` | The skill itself, in Markdown. No length cap |
| `enabled` | Omit to keep the default, which is enabled |
| `projectIds` | Omit for every project. Send a list to narrow it; sending it at all **replaces** the whole scope set, and an empty list means no project |

`GET /v1/api/packs/custom-skills` lists them, `GET`, `PATCH` and `DELETE` on `/v1/api/packs/custom-skills/{slug}` handle one.

**Sending an empty projectIds list narrows to nothing:** `projectIds` replaces the whole set; it does not merge. `{"projectIds": []}` scopes the skill to no project, which switches it off everywhere while it stays enabled. Omit the key to leave the scope unchanged.

### Draft one from a description

```bash
curl -sS -X POST "$HLIX_BASE_URL/v1/api/packs/custom-skills/generate" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -H 'content-type: application/json' \
  -d '{"description":"Our API errors always carry a stable machine-readable code."}'
```

Expected result: `200` and a draft skill — a suggested slug, name, description and content. It is a **draft**: nothing is stored until you post it as a custom skill.

The dashboard offers the same thing under **Settings → Custom Skills**.

## How a skill reaches a task

hlix's skill library is available in every sandbox, so when a task starts, the skills of the project's active packs are copied into `.claude/skills/<slug>/` in the task's checkout. A skill your [Environment](/configure/environments/) lists by slug is copied from the same library.

A slug that is not in the library is **skipped**, never written as an empty placeholder that could hide a real skill of that name.

An imported skill takes a different route: it is stored as a file in the project's Environment at `.claude/skills/<slug>/SKILL.md` and written into the checkout from there. That is why an imported skill appears in your Environment's `files` and `managedPaths` rather than in its `skills` list. See [Import skills, agents & MCP](/cli/resources/).

**Every coder receives them:** Every route on this page delivers a skill to every coder, Hlix Code and every external coder alike. Agent briefs and hlix's own identity are composed for every coder too; see [Context, memory & DNA](/concepts/context-memory/).

## If a skill does not reach an agent

- **`{"error":"Pack not found"}` with `404`.** The pack id is not one of this Workspace's attachments, or the pack name is not in the library.
- **`{"error":"Custom skill not found"}` with `404`.** No skill with that slug in this Workspace.
- **`{"error":"Skill generation failed. Please try again."}` with `502`.** The drafting call did not return a usable skill. Retry, or write it by hand — nothing was stored.
- **A `400` on the slug.** Slugs are lowercase letters, digits and hyphens only. No spaces, no capitals, no underscores.
- **The skill exists but no agent used it.** Check the scope: a custom skill with a `projectIds` list only applies to those projects, and a `PATCH` that sent `projectIds` replaced the whole set.
- **A pack is attached and its skills are not in the checkout.** Check `isActive` on the attachment — an inactive pack stays attached and contributes nothing.
- **An Environment lists a skill slug and nothing appears.** The slug did not resolve in the library and was skipped. Use a custom skill (delivered as a file) for a standard the library does not carry.
- **A `403` on a custom-skill write.** Workspace-wide skills need the `owner` or `admin` role, because they change what every project's agents read.

## Where to go next

| If you want to… | Read |
| --- | --- |
| Deliver a skill to one project only | [Environments](/configure/environments/) |
| Import a skill from an existing repository | [Import skills, agents & MCP](/cli/resources/) |
| Understand what an agent reads before a turn | [Context, memory & DNA](/concepts/context-memory/) |
| See the trust boundary on imported resources | [Import trust model](/security/import-trust-model/) |

## Next steps

[Context, memory & DNA](/concepts/context-memory/)
  [Environments](/configure/environments/)
  [Memories](/configure/memories/)
  [Import trust model](/security/import-trust-model/)