# Create skills

URL: https://docs.hanzo.ai/docs/openapi/tool/post-tool-skills

> Adds or revises one of the caller org's own skills, and answers 201 with the stored record.

`POST /v1/tool/skills`

> [Tool →](https://docs.hanzo.ai/docs/openapi/tool) · [All API references →](https://docs.hanzo.ai/docs/openapi) · [Get started →](https://docs.hanzo.ai/docs/guides)

|               |                                        |
| ------------- | -------------------------------------- |
| **Address**   | `https://api.hanzo.ai/v1/tool/skills`  |
| **Method**    | `POST`                                 |
| **Operation** | `post_tool_skills`                     |
| **Auth**      | `Authorization: Bearer $HANZO_API_KEY` |

Adds or revises one of the caller org's own skills, and answers 201
with the stored record. The id is derived from the name, so writing the same
name again REVISES that skill rather than accumulating near-duplicates that
would then collide in the registry. An org's skills are private to it by
construction — they live in a different store from the brand's embedded
catalogue and have no path into the public gallery — and a brand skill always
wins a name collision against an org's.

An activated skill is carried into every agent run in the org, so writing one
takes an admin of the org or a SuperAdmin; a member is refused 403. The write is
on the org's audit trail before it is made, and one the trail cannot record is
refused 503.

## Request

3 fields, body `application/json` (required).

| Field         | In   | Type   | Required | Description                                                                          |
| ------------- | ---- | ------ | -------- | ------------------------------------------------------------------------------------ |
| `content`     | body | string | —        | Content is the SKILL.md body.                                                        |
| `description` | body | string | —        | Description is the one-line summary discovery shows for the skill.                   |
| `name`        | body | string | —        | Name is the skill's id within the org: one lowercase path segment (a-z0-9, \_ or -). |

## Response

| Status    | Body              | Meaning |
| --------- | ----------------- | ------- |
| `201`     | tool.skillWritten | created |
| `default` | problem-details   | refused |

`201` body — 9 fields.

| Field               | In   | Type            | Always | Description                                                                                                                     |
| ------------------- | ---- | --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `skill`             | body | tool.Skill      | —      |                                                                                                                                 |
| `skill.admitted`    | body | boolean         | —      | Admitted is whether an admin of the org, or a SuperAdmin, wrote this content.                                                   |
| `skill.content`     | body | string          | —      | Content is the SKILL.md body, markdown.                                                                                         |
| `skill.createdAt`   | body | integer (int64) | —      | CreatedAt is when the skill was last written, Unix seconds.                                                                     |
| `skill.description` | body | string          | —      | Description is the one-line summary discovery shows for the skill.                                                              |
| `skill.id`          | body | string          | —      | ID is the skill's id within the org.                                                                                            |
| `skill.name`        | body | string          | —      | Name is the skill's name: one lowercase path segment (a-z0-9, \_ or -).                                                         |
| `skill.org`         | body | string          | —      | Org is the org that authored the skill — the validated caller's, never a value the body supplied.                               |
| `skill.source`      | body | string          | —      | Source is the repository the skill was read from, "\<project>/\<name>" or "\<name>"; empty for a skill written through the API. |

Failure carries the platform error shape — see [Errors](https://docs.hanzo.ai/docs/errors).

## Examples

**CLI**

```bash
hanzo tool skills create
```

**SDK**

**.ts**

```ts
import { Configuration, ToolApi } from 'hanzoai';

const api = new ToolApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postToolSkills({ content: "<content>", description: "<description>" });
```

**.py**

```python
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import ToolApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = ToolApi(client).post_tool_skills(content="<content>", description="<description>")
```

**.go**

```go
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.ToolAPI.PostToolSkills(context.Background()).Execute()
if err != nil {
	return err
}
```

**.rs**

```rust
use hanzo_client::apis::{configuration::Configuration, tool_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = tool_api::post_tool_skills(&cfg, Default::default()).await?;
```

**.java**

```java
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.ToolApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new ToolApi(client).postToolSkills();
```

**HTTP**

```bash
curl -X POST https://api.hanzo.ai/v1/tool/skills \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "content": "<content>",
       "description": "<description>"
     }'
```

**MCP**

MCP reaches **tool** through the `tool` tool, which names its 17 operations with its own verbs — this one among them, under a name only MCP declares. `describe` explains any of them:

```bash
curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "describe",
         "arguments": {
           "op": "list_tools"
         }
       }
     }'
```

---

[Tool API](https://docs.hanzo.ai/docs/openapi/tool) · [All Hanzo APIs](https://docs.hanzo.ai/docs/openapi) · [Interactive reference](https://docs.hanzo.ai/docs/openapi/reference)
