---
title: "Create a skill"
description: "Create a custom skill for the authenticated user."
---

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

Path: AI Gateway API › Skills

`POST /skills`

Create a custom skill for the authenticated user.

## Authentication

- `HTTPBearer`, http, header `Authorization`

## Header parameters

- `X-On-Behalf-Of` (`create_skill.header.X-On-Behalf-Of`; any of, optional)
  - any of: `string`, `null`
- `X-External-User-Id` (`create_skill.header.X-External-User-Id`; any of, optional)
  - any of: `string`, `null`
- `X-App-Id` (`create_skill.header.X-App-Id`; any of, optional)
  - any of: `string`, `null`

## Request body

_Required._

- `key` (`create_skill.key`; string, required) — Stable client-facing identifier (e.g. for slash commands). Lowercase letters, digits, hyphens, underscores; must start and end with a letter or digit.
  - minLength 2; maxLength 64
- `name` (`create_skill.name`; string, required) — Display name for the skill.
  - minLength 1; maxLength 255
- `prompt` (`create_skill.prompt`; string, required) — Prompt body executed when the skill is invoked.
  - minLength 1
- `description` (`create_skill.description`; any of, optional) — Short human-readable description of what the skill does.
  - any of: `string`, `null`
- `category` (`create_skill.category`; any of, optional) — Optional grouping label (e.g. 'productivity', 'writing').
  - any of: `string`, `null`
- `app_ids` (`create_skill.app_ids`; any of, optional) — Apps this skill is assigned to. NULL (or omitted) means all apps — visible to every app. A non-empty list scopes it to those apps. The legacy scalar ``app_id`` is still accepted and folded into a one-element list.
  - any of: `array<string>`, `null`
- `icon` (`create_skill.icon`; any of, optional) — Icon identifier or URL — interpreted by the caller.
  - any of: `string`, `null`
- `argument_hint` (`create_skill.argument_hint`; any of, optional) — Hint shown to the user about expected arguments.
  - any of: `string`, `null`
- `allowed_tools` (`create_skill.allowed_tools`; array<string>, optional) — Tool names the skill is allowed to use. Empty list means no restriction at this layer.
- `metadata` (`create_skill.metadata`; object, optional) — Free-form caller-defined metadata.
- `is_active` (`create_skill.is_active`; boolean, optional) — Whether the skill is currently enabled. Off skills are still listable.
  - default `true`
- `sort_order` (`create_skill.sort_order`; integer, optional) — Caller-defined display order; lower sorts earlier.
  - default `0`
- `use_case` (`create_skill.use_case`; any of, optional) — When this skill applies, in natural language — e.g. 'Triggers when a user shares a photo of food, a menu, or ingredients.' Read by skill selection, so write it to describe the trigger, not the behaviour.
  - any of: `string`, `null`
- `detection_patterns` (`create_skill.detection_patterns`; any of, optional) — Example utterances that should invoke this skill. Matched semantically, not literally, so paraphrases count — list distinct phrasings rather than keyword variants.
  - any of: `array<string>`, `null`
- `license` (`create_skill.license`; any of, optional) — SKILL.md `license`: a license name, or the file in the skill that holds it.
  - any of: `string`, `null`
- `compatibility` (`create_skill.compatibility`; any of, optional) — SKILL.md `compatibility`: what the skill needs to run.
  - any of: `string`, `null`
- `forked_from_skill_id` (`create_skill.forked_from_skill_id`; any of, optional) — If set, the new skill is a fork of this preset skill. Only preset skills (is_preset = TRUE) may be forked.
  - any of: `string`, `null`

## Example request

```json
{
  "key": "summarize-thread",
  "name": "Summarize Thread",
  "description": "Summarize the current conversation in three bullets.",
  "prompt": "Summarize the conversation so far in 3 short bullet points.",
  "category": "productivity",
  "app_ids": [
    "vibrantly",
    "blinklife"
  ],
  "icon": "sparkles",
  "argument_hint": "[topic]",
  "allowed_tools": [
    "web_search",
    "memory_query"
  ],
  "metadata": {},
  "is_active": true,
  "sort_order": 0,
  "use_case": "Triggers when a user shares a photo of food or a menu.",
  "detection_patterns": [
    "what are the macros in this",
    "can I eat these berries"
  ],
  "license": "Apache-2.0",
  "compatibility": "string",
  "forked_from_skill_id": "string"
}
```

## Code samples

### cURL

```bash
curl --request POST \
  --url https://truememory-api.mvstg.com/skills \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "key": "summarize-thread",
  "name": "Summarize Thread",
  "description": "Summarize the current conversation in three bullets.",
  "prompt": "Summarize the conversation so far in 3 short bullet points.",
  "category": "productivity",
  "app_ids": [
    "vibrantly",
    "blinklife"
  ],
  "icon": "sparkles",
  "argument_hint": "[topic]",
  "allowed_tools": [
    "web_search",
    "memory_query"
  ],
  "metadata": {},
  "is_active": true,
  "sort_order": 0,
  "use_case": "Triggers when a user shares a photo of food or a menu.",
  "detection_patterns": [
    "what are the macros in this",
    "can I eat these berries"
  ],
  "license": "Apache-2.0",
  "compatibility": "string",
  "forked_from_skill_id": "string"
}
'
```

### TypeScript

```typescript
const url = 'https://truememory-api.mvstg.com/skills';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', Authorization: 'Bearer <token>'},
  body: JSON.stringify({
    key: 'summarize-thread',
    name: 'Summarize Thread',
    description: 'Summarize the current conversation in three bullets.',
    prompt: 'Summarize the conversation so far in 3 short bullet points.',
    category: 'productivity',
    app_ids: ['vibrantly', 'blinklife'],
    icon: 'sparkles',
    argument_hint: '[topic]',
    allowed_tools: ['web_search', 'memory_query'],
    metadata: {},
    is_active: true,
    sort_order: 0,
    use_case: 'Triggers when a user shares a photo of food or a menu.',
    detection_patterns: ['what are the macros in this', 'can I eat these berries'],
    license: 'Apache-2.0',
    compatibility: 'string',
    forked_from_skill_id: 'string'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error(err));
```

### Python

```python
import requests

url = "https://truememory-api.mvstg.com/skills"

payload = {
    "key": "summarize-thread",
    "name": "Summarize Thread",
    "description": "Summarize the current conversation in three bullets.",
    "prompt": "Summarize the conversation so far in 3 short bullet points.",
    "category": "productivity",
    "app_ids": ["vibrantly", "blinklife"],
    "icon": "sparkles",
    "argument_hint": "[topic]",
    "allowed_tools": ["web_search", "memory_query"],
    "metadata": {},
    "is_active": True,
    "sort_order": 0,
    "use_case": "Triggers when a user shares a photo of food or a menu.",
    "detection_patterns": ["what are the macros in this", "can I eat these berries"],
    "license": "Apache-2.0",
    "compatibility": "string",
    "forked_from_skill_id": "string"
}
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer <token>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
```

## Responses

### 201

Successful Response

#### Example

```json
{
  "id": "string",
  "user_id": "string",
  "app_ids": [
    "string"
  ],
  "key": "string",
  "name": "string",
  "description": "string",
  "prompt": "string",
  "category": "string",
  "categories": [
    {
      "id": "string",
      "name": "string"
    }
  ],
  "icon": "string",
  "argument_hint": "string",
  "allowed_tools": [
    "string"
  ],
  "metadata": {},
  "use_case": "string",
  "detection_patterns": [
    "string"
  ],
  "license": "string",
  "compatibility": "string",
  "is_preset": true,
  "is_active": true,
  "sort_order": 0,
  "forked_from_skill_id": "string",
  "usage_count": 0,
  "last_used_at": "2019-08-24T14:15:22Z",
  "parent_synced_at": "2019-08-24T14:15:22Z",
  "created_at": "2019-08-24T14:15:22Z",
  "updated_at": "2019-08-24T14:15:22Z",
  "app_id": "string"
}
```

- `id` (`create_skill.response.201.id`; string, required)
- `user_id` (`create_skill.response.201.user_id`; any of, required) — Owner user_id, NULL for presets.
  - any of: `string`, `null`
- `app_ids` (`create_skill.response.201.app_ids`; any of, required) — Apps this skill is assigned to. NULL means all apps (global/unscoped).
  - any of: `array<string>`, `null`
- `key` (`create_skill.response.201.key`; string, required)
- `name` (`create_skill.response.201.name`; string, required)
- `description` (`create_skill.response.201.description`; any of, required)
  - any of: `string`, `null`
- `prompt` (`create_skill.response.201.prompt`; string, required)
- `category` (`create_skill.response.201.category`; any of, required) — Freeform grouping label (legacy string). Distinct from `categories`.
  - any of: `string`, `null`
- `icon` (`create_skill.response.201.icon`; any of, required)
  - any of: `string`, `null`
- `argument_hint` (`create_skill.response.201.argument_hint`; any of, required)
  - any of: `string`, `null`
- `allowed_tools` (`create_skill.response.201.allowed_tools`; array<string>, required)
- `metadata` (`create_skill.response.201.metadata`; object, required)
- `is_preset` (`create_skill.response.201.is_preset`; boolean, required)
- `is_active` (`create_skill.response.201.is_active`; boolean, required)
- `sort_order` (`create_skill.response.201.sort_order`; integer, required)
- `forked_from_skill_id` (`create_skill.response.201.forked_from_skill_id`; any of, required)
  - any of: `string`, `null`
- `usage_count` (`create_skill.response.201.usage_count`; integer, required) — Global invocation count, bumped via POST /skills/{id}/usage.
- `last_used_at` (`create_skill.response.201.last_used_at`; any of, required) — When the skill was last invoked, NULL if never.
  - any of: `string`, `null`
- `parent_synced_at` (`create_skill.response.201.parent_synced_at`; any of, required) — For forks: the preset updated_at this fork is synced to. The fork is stale when its preset's updated_at is newer. NULL for non-forks.
  - any of: `string`, `null`
- `created_at` (`create_skill.response.201.created_at`; string, required)
  - format `date-time`
- `updated_at` (`create_skill.response.201.updated_at`; string, required)
  - format `date-time`
- `app_id` (`create_skill.response.201.app_id`; any of, required) — DEPRECATED, read app_ids instead. Legacy single-app scalar derived from app_ids for pre-multi-app consumers: the first app id, or null for all apps. Lossy for multi-app skills.
  - any of: `string`, `null`
- `categories` (`create_skill.response.201.categories`; array<object>, optional) — Category entities assigned via the registry. Returned by the list endpoints, the single-skill reads (user and admin) and PUT /admin/skills/{skill_id}/categories; omitted by writes.
  - `id` (`create_skill.response.201.categories.id`; string, required)
  - `name` (`create_skill.response.201.categories.name`; string, required)
- `use_case` (`create_skill.response.201.use_case`; any of, optional) — When this skill applies, in natural language. Read by skill selection.
  - any of: `string`, `null`
- `detection_patterns` (`create_skill.response.201.detection_patterns`; any of, optional) — Example utterances that should invoke this skill.
  - any of: `array<string>`, `null`
- `license` (`create_skill.response.201.license`; any of, optional) — SKILL.md `license`: a license name, or the file in the skill that holds it.
  - any of: `string`, `null`
- `compatibility` (`create_skill.response.201.compatibility`; any of, optional) — SKILL.md `compatibility`: what the skill needs to run (product, packages, network).
  - any of: `string`, `null`

### 422

Validation Error

#### Example

```json
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string",
      "input": null,
      "ctx": {}
    }
  ]
}
```

- `detail` (`create_skill.response.422.detail`; array<object>, optional)
  - `loc` (`create_skill.response.422.detail.loc`; array<any of>, required)
    - any of: `string`, `integer`
  - `msg` (`create_skill.response.422.detail.msg`; string, required)
  - `type` (`create_skill.response.422.detail.type`; string, required)
  - `input` (`create_skill.response.422.detail.input`; unknown, optional)
  - `ctx` (`create_skill.response.422.detail.ctx`; object, optional)


Source: https://truememory-docs.mvstg.com/api/skills/create/index.md
