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

Write a Skill

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 → New Skill.
  2. Fill the structured form:
    • Name — lowercase, kebab-case slug (e.g. email-triage). Lower-case + dashes are enforced by the input.
    • 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. The frontmatter is reconstructed server-side from the structured fields.

Step 2: Or create it via the API

The same operation as a single REST call. Versions are auto-incremented server-side, so the payload never contains a version field.

curl -s -X POST http://localhost:4000/api/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

Note: scripts is not accepted by POST /api/skills or PUT /api/skills/:name. It is a catalog-import-only field — skills imported via POST /api/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/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/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: Attach the skill to an instance

A skill in the library does nothing until you attach it to an instance. From the admin panel, open the instance → Skills tab → toggle email-triage on. The API equivalent is:

curl -s -X POST http://localhost:4000/api/instances/my-bot/skills/email-triage \ -H "Authorization: Bearer $TOKEN"

Step 4: 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 instance Skills tab — email-triage should be toggled on and show no red “missing env” badge.
  • Go to Playground, send a message that matches the skill’s trigger (“can you triage this email…”). The skill content is now part of the supervisor prompt.
  • In the conversation trace, the active skills list is logged on every turn — check the engine logs for discoverSkills entries naming email-triage.

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/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