# Use skills

Sync skill content into the workspace and attach it to a PromptPack so the model can activate skills on demand.

You create a `SkillSource`, publish a PromptPack version that lists it in `spec.skills`, then check that the agent pod loads the manifest.

## Prerequisites

- Workspace content storage. The chart enables it, and the operator receives `--workspace-content-path` (default `/workspace-content`).
- A PromptPack from a ConfigMap, already running on an AgentRuntime.
- A `kubectl` that can reach the workspace namespace (`dev-agents` below).

## Step 1: create a SkillSource

Save as `skills.yaml`. The repository URL, tag and skill names are illustrative; use your own.

```yaml
apiVersion: omnia.altairalabs.ai/v1alpha1
kind: SkillSource
metadata:
  name: support-skills
  namespace: dev-agents
spec:
  type: git
  git:
    url: https://github.com/anthropic/skills
    ref: { tag: v1.4.0 }
  interval: 1h
  targetPath: skills/anthropic
  filter:
    include: ["ai-safety", "pdf-processing"]
```

Apply it and wait for the first fetch:

```bash
kubectl apply -f skills.yaml
kubectl get skillsource support-skills -n dev-agents -w
```

The source is synced when `PHASE` is `Ready` and `SKILLS` matches the filtered set. Then check that every retained `SKILL.md` parsed:

```bash
kubectl get skillsource support-skills -n dev-agents \
  -o jsonpath='{.status.conditions[?(@.type=="ContentValid")]}'
```

`status: "True"` means every `SKILL.md` parsed and no two skills in the source share a name.

See [SkillSource](/reference/core/skillsource/) for the `oci` and `configmap` source types and every filter field.

## Step 2: attach to a PromptPack

A published PromptPack version is immutable, so `kubectl patch` on `spec.skills` is rejected. Publish a new version that lists the source. Save as `pack-v2.yaml`:

```yaml
apiVersion: omnia.altairalabs.ai/v1alpha1
kind: PromptPack
metadata:
  name: support-pack-1-1-0
  namespace: dev-agents
spec:
  packName: support-pack
  version: "1.1.0"
  source:
    type: configmap
    configMapRef:
      name: support-pack-prompts   # the ConfigMap your current version uses
  skills:
    - source: support-skills
      include: ["ai-safety"]
      mountAs: compliance
  skillsConfig:
    maxActive: 5
```

To offer the model only some skills, add `selector: tag` and a `tags` list under `skillsConfig`. A skill is offered when its `SKILL.md` metadata `tags` shares an entry with that list.

```bash
kubectl apply -f pack-v2.yaml
```

An AgentRuntime that pins `promptPackRef.version` keeps serving the old version until you change the pin.

The PromptPack controller resolves the references, writes a JSON manifest into the workspace content volume, and sets three conditions:

```bash
kubectl get promptpack support-pack-1-1-0 -n dev-agents \
  -o jsonpath='{range .status.conditions[*]}{.type} {.status} {.reason}{"\n"}{end}'
```

| Condition | Reason when `True` | Meaning |
|---|---|---|
| `SkillsResolved` | `AllSkillsResolved` | Every `spec.skills[].source` exists and has synced |
| `SkillsValid` | `NoCollisions` | No two referenced sources publish a skill with the same name |
| `SkillToolsResolved` | `AllToolsResolved` | Every skill's `allowed-tools` is a tool the pack declares |

If `SkillToolsResolved` is `False`, add the tool to the pack's `tools` or remove it from the skill's `allowed-tools`.

See [PromptPack](/reference/core/promptpack/#skills) for every `skills` and `skillsConfig` field.

## Step 3: verify the runtime loads the manifest

The operator rebuilds the pod of each AgentRuntime that serves the pack. The runtime container gets:

- Your workspace's part of the content volume, mounted read-only at `/workspace-content`. The pod sees no other workspace's content.
- The env var `OMNIA_PROMPTPACK_MANIFEST_PATH=/workspace-content/manifests/<promptpack-name>.json`, where `<promptpack-name>` is the PromptPack's `metadata.name` (`support-pack-1-1-0` above).

Inspect the pod:

```bash
kubectl exec <agent-pod> -n dev-agents -c runtime -- env | grep OMNIA_PROMPTPACK
kubectl exec <agent-pod> -n dev-agents -c runtime -- cat /workspace-content/manifests/support-pack-1-1-0.json
kubectl logs <agent-pod> -n dev-agents -c runtime | grep "skill manifest loaded"
```

The log line lists `skillNames`, `skillMounts`, `maxActive` and `selector`.

## Step 4: test from a session

Open a session and ask about something a skill covers (for `ai-safety`, handling sensitive content). The runtime gives the model an index of the available skills, and the model calls the `skill__activate` tool to load the one it needs before answering.

Confirm the activation in the session's tool calls:

```bash
curl -s <session-api-url>/api/v1/sessions/<session-id>/tool-calls \
  | jq '.[] | select(.name=="skill__activate")'
```

`skill__activate` is a server-side tool, so it appears here and in the runtime logs, not as a `tool_call` message on the WebSocket.

## Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| `SkillsResolved=False`, reason `LookupFailed`, message `SkillSource ... not found` | The `SkillSource` is not in the PromptPack's namespace. Lookup does not cross namespaces | `kubectl get skillsource -n <pack-ns>` |
| `SkillsResolved=False`, reason `LookupFailed`, message `... has no synced artifact yet` | The `SkillSource` has not finished its first fetch | Wait for `status.phase` to reach `Ready` |
| `SkillsResolved=False`, reason `ContentStorageUnavailable` | The operator started with an empty `--workspace-content-path` | Set `--workspace-content-path` on the operator and restart it. The Helm chart always sets it. |
| `SkillsValid=False`, reason `NameCollision` | Two referenced sources publish skills with the same `name` | Add `include` to one of the `skills` entries |
| `SkillToolsResolved=False`, reason `UnknownTool` | A `SKILL.md` `allowed-tools` entry is not declared in the pack | Declare the tool in the pack or drop it from the skill |
| `kubectl patch` on the PromptPack is rejected | Published versions are immutable | Apply a new version, as in step 2 |
| The runtime pod has no `workspace-content` volume | The pack declares no `spec.skills`, or the operator has no content storage | Check step 2 and the operator's `--workspace-content-path` |

## Related

- [SkillSource reference](/reference/core/skillsource/)
- [PromptPack reference](/reference/core/promptpack/)
- [PromptKit skills concepts](https://promptkit.altairalabs.ai/concepts/skills/)