Skip to Content
Polyant is open source under AGPL-3.0 — star us on GitHub.
How-toWrite a Skill

Write a Skill

On this page

Skills are reusable, instance-scoped capability bundles - Markdown instructions plus structured metadata that the supervisor injects into the prompt when the skill is enabled. This guide walks through authoring a skill in the admin panel, then doing the same thing via the Management API. By the end you will have a skill in the global library, attached to an instance, with its environment variables populated.

Prerequisites

  • An authenticated session on the admin panel (or a valid Authorization: Bearer token for API calls - see Get a JWT for API calls)
  • An instance you can attach the skill to (the slug, e.g. my-bot)
  • Optional: credentials for any external service the skill will call

Step 1: Create the skill in the admin panel

  1. Navigate to Skills in the sidebar - the organization’s catalogue - then New Skill.
  2. Fill the structured form:
    • Name - the display name (e.g. email-triage, or Email triage). The slug is derived from it server-side: lowercased, with every character outside a-z0-9- turned into a dash. It is immutable afterwards and unique within the organization, so pick a name you can live with.
    • Description - one-line summary shown in the catalog.
    • Required env - click Add to declare each env var the skill needs. Each row has Name (any string is accepted; convention is UPPER_SNAKE_CASE, e.g. OPENAI_API_KEY), an optional Description, and a Sensitive switch (masked in the admin UI when on).
    • Content - the Markdown body of the skill. This is what the LLM sees when the skill is active. Write it as instructions to the agent.
  3. Click Save. The skill lands in the library at version 0.1.0. Every subsequent Save on this skill creates a new version automatically; you do not pick the version number.

The Skills form is a structured editor - you do not paste Markdown with frontmatter. Each field is stored on its own: name, description and category on the skill row, requiredEnv and requiredTools on the version’s metadata. A --- block typed into the body is not parsed; it just becomes part of the prompt.

Step 2: Or create it via the API

The same operation as a single REST call. The catalogue is per organization, so every route carries the organization slug - set ORG to yours. Versions are auto-incremented server-side, so the payload never contains a version field.

curl -s -X POST http://localhost:4000/api/organizations/$ORG/skills \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "name": "email-triage", "description": "Classify inbound email by urgency and draft a reply.", "content": "# Email triage\n\nWhen the user shares an email, classify it as URGENT, NORMAL, or LATER. Then draft a reply in the same language as the original. Never include private data in the subject line.", "requiredEnv": [ { "name": "OPENAI_API_KEY", "description": "Used for the draft", "sensitive": true } ], "requiredTools": ["httpRequest"] }'

Supported fields on create/update:

FieldTypeNotes
namestringRequired on create; immutable after that
descriptionstringRequired
contentstringRequired - the Markdown body
requiredEnv{ name, description?, sensitive }[]Per-instance env vars
requiredToolsstring[]Tool names that must be enabled for this skill to work. A plugin tool is named with its namespace (hubspot:contact); a name the organization cannot use, including a tool’s old name from before it moved into a plugin, is refused with 400

Note: scripts is not accepted by POST .../skills or PUT .../skills/:name. It is a catalog-import-only field - skills imported via POST /api/organizations/:orgSlug/skills/catalog/import can carry a scripts payload, but the standard create/update API does not.

To update an existing skill (creates a new version):

curl -s -X PUT http://localhost:4000/api/organizations/$ORG/skills/email-triage \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "description": "...", "content": "...", "requiredEnv": [...], "changelog": "tightened tone of voice" }'

To browse the version history:

curl -s http://localhost:4000/api/organizations/$ORG/skills/email-triage/versions \ -H "Authorization: Bearer $TOKEN"

The response is wrapped in an object:

{ "versions": [ { "version": "0.2.0", "changelog": "tightened tone of voice", "createdAt": "..." }, { "version": "0.1.0", "changelog": null, "createdAt": "..." } ] }

Step 3: Assign the skill to the workspace

A skill in the catalogue does nothing until the workspace the agent lives in is allowed to draw on it. A workspace created after the allow-list shipped starts empty, so this step is not optional for a new workspace - see What a workspace may draw on.

From the admin panel: Settings → Skills, in the workspace tier, and switch email-triage on. It needs workspace.assignment:manage, which Admin and above hold. The API equivalent:

curl -s -X PUT http://localhost:4000/api/organizations/$ORG/workspaces/$WS/skills/email-triage \ -H "Authorization: Bearer $TOKEN"

Step 4: Enable the skill on the agent

From the admin panel, open the agent → Skills section → toggle email-triage on. The API equivalent takes the complete set of enabled skills, not a delta - anything you leave out is turned off:

curl -s -X PATCH http://localhost:4000/api/instances/my-bot/skills \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "enabled": ["email-triage"] }'

Step 5: Populate the per-instance env vars

If the skill declares requiredEnv entries, populate them per-instance. In the admin UI this is the form that appears next to the skill toggle. Via API:

curl -s -X PUT http://localhost:4000/api/instances/my-bot/skills/email-triage/env \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "env": [ { "key": "OPENAI_API_KEY", "value": "sk-...", "sensitive": true } ] }'

Values are AES-256-GCM encrypted at rest. To remove a single var: DELETE /api/instances/my-bot/skills/email-triage/env/OPENAI_API_KEY.

Verification

  • Open the agent’s Skills section - email-triage should be toggled on, show no red “missing env” badge, and not be counted in the “not assigned to this workspace” banner.
  • Click Try and send a message that matches the skill’s trigger (“can you triage this email…”). The skill content is now part of the supervisor prompt.
  • If it does not fire, check the agent’s Status section: a skill missing its env, or one the workspace does not carry, is reported there by name or by count.

Caveats

  • The fields requiredSecrets, dependsOnTools, language, and tags are not supported. Stick to the list in Step 2.
  • A skill version is created on every save - there is no draft mode. Use the version history (GET /api/organizations/:orgSlug/skills/:name/versions) to roll back if needed.
  • Skill content is plain Markdown but it ends up in the LLM prompt - keep it short and instruction-shaped, not narrative.

See also

Last updated on