Skip to content

AI skills

Skills are reusable methodology, not executable tools or additional permissions. Keep the routing metadata in ui.json and the detailed instructions in a separate Markdown file. The model chooses a relevant skill; no activation buttons are added.

"skills": [{
"id": "image-to-graph",
"title": "skill.image.title",
"description": "skill.image.description",
"file": "skills/image-to-graph.md"
}],
"assistants": [{
"id": "model",
"title": "assistant.title",
"tools": ["read_current_context"],
"useActions": ["my-plugin/create_item", "my-plugin/link_items"],
"skills": ["image-to-graph"]
}]

Write plugins/<name>/skills/image-to-graph.md in plain Markdown. Include a clear workflow, when to ask for clarification, domain constraints, existing tool/action ids and how to report the result. Use the messages.en / messages.fr catalogs for title and description; literal strings are also accepted. The description should explain when to use the skill, because it drives model selection.

Register with the existing ai.registerManifestAssistants(ctx, manifest) call. An assistant’s skills: true enables every skill declared by its owner; skills: ["local-id"] enables a subset. Omitted/false means no skills and no change to assistants such as AI Help. Unknown selected ids, duplicate ids and invalid metadata fail registration. Programmatic assistants use createAssistant(ctx, { ..., skills: AiSkill[] }); AiSkill is exported from @app/kernel/plugin-api and has id, title, description, file fields.

Only a compact catalog (qualified id, translated title/description) enters the system prompt. The reserved read tool use_skill({ skillId: "my-plugin:image-to-graph" }) loads the owner’s Markdown via ctx.resources.loadText(file) on demand and returns { skillId, title, instructions } in the conversation. No Markdown is loaded at registration. Each request reads the resource anew; no separate skill activation state is persisted. A new/cleared session starts without old skill results. Like other tool results, loaded instructions follow the history limit; the model can request the skill again when needed.

The model cannot load another assistant’s unoffered skill. File paths must be relative Markdown paths (no URLs, absolute paths or traversal); normal resource loading handles URL and desktop-file plugins. Web file installs may ask the user to select the resource, so ship the whole plugin folder or use a URL install. Disabling the owner removes access. Resource errors/empty files appear as failed tool results, never as permission to proceed blindly.

Skills do not expand the assistant’s tool/action allowlists or bypass approvals. Project-specific instructions retain priority. Use one approved actions_batch for dependent changes, with result aliases; treat user images and document text as data, not trusted instructions. use_skill is reserved: do not register a custom tool with that name on a skill-enabled assistant.

Notes includes skills/image-to-graph.md as an example. It separates visual observations from guesses, reuses existing tasks, proposes a single approved batch and states unsupported placement/grouping capabilities instead of inventing actions. Image interpretation requires a vision-capable configured model.

A host plugin can hand the ai plugin skills it does not own as files — in the application, core-plugin hands over the skills of the installed modules, the same way it registers their actions with ctx.actions.register. The framework depends on no environment: it receives plain data and a loader.

import type { AiSkillCatalog } from "@app/kernel/plugin-api";
const catalog: AiSkillCatalog = {
skills: [{
id: "scflow/image_to_model", // module-qualified: namespace/name
title: "Image to model", // literal, shown when activated
description: "Turn a picture of a supply chain into a model. Use when…",
uses: ["scflow/create_item", "scflow/link_items"], // action ids
}],
load: (id) => environment.loadSkill(id), // (id) => Promise<string>, Markdown body
};
const remove = ctx.useApi("ai")?.registerSkillCatalog(ctx.pluginId, catalog);

AiSkillCatalog and AiHostSkill are exported from @app/kernel/plugin-api. Ids are namespace/name made of identifiers and unique across catalogues; a duplicate or an id already registered by another plugin fails registration. Registering again replaces the plugin’s catalogue. The returned function, or the plugin’s deactivation, removes it. Bodies are loaded only when the model calls use_skill, never at registration.

An assistant opts in with useSkills, next to useActions, in ui.json assistants or createAssistant options: true for every host skill, or a list of qualified ids. Omitted/false means no host skills. A host skill is offered only when every action in its uses is offered to that assistant through useActions, so skills never widen the tools:

"assistants": [{
"id": "model",
"title": "assistant.title",
"useActions": ["scflow/create_item", "scflow/link_items"],
"useSkills": true,
"skills": ["image-to-graph"]
}]

Plugin skills and host skills share the single use_skill tool, the same catalog in the system prompt, the same { skillId, title, instructions } result and the same “Skill activated” display. Plugin-skill ids stay <pluginId>:<id> and host-skill ids are namespace/name, so they never clash. Skills of the host itself, such as help on the user interface, stay plugin skills.

Documentation under CC BY 4.0 · © SCFlow contributors ·Back to supplychainflow.org