Skills System Overview
Applies to: ChengOS v0.1.0+ | Last verified: 2026-08-12 | Source:
chengflow/skills/,crates/cheng-core/src/domain/skill.rs,crates/cheng-core/src/domain/active_skill.rs,crates/cheng-nodes/src/nodes/builtin/tools/skills_hub,crates/cheng-api/src/rest/handlers/skill/mod.rs
A skill packages a capability so an agent can find it and use it correctly. Where a tool is one callable function, a skill is a named unit with instructions, input and output schemas, and often reference documentation — the difference between handing a model a button and handing it a manual.
What a skill is
Skill
├── name ← slug: 2+ chars, alphanumerics, - and _ only
├── display_name, description
├── instructions ← what the model reads to use it
├── workflow_id? ← the workflow that implements it, when backed by one
├── input_schema / output_schema
├── category, tags
├── enabled, is_user_invocable
├── version ← defaults to "1.0.0"
└── workspace_id? ← None means global
Skills are workspace-scoped, or global when workspace_id is None. is_user_invocable
separates skills a person can trigger from ones only an agent uses.
On disk a skill is a directory under skills/<name>/ with a SKILL.md carrying YAML
front-matter:
---
name: workflow-helper
description: Use this skill when the user has questions about building, debugging,
or understanding ChengOS workflows — including node selection, port wiring,
field configuration, error troubleshooting, and pattern recommendations.
---
The description is a trigger condition, not a summary. It is what the agent matches
against to decide whether this skill applies, so write it as "use this when…" rather than as a
blurb. Larger skills add a references/ directory the instructions link into.
The skills that ship
| Skill | Purpose |
|---|---|
workflow-helper | Answers "how do I build / wire / configure / debug this workflow", querying live node schemas |
workflow-json-builder | Guides a user through generating importable workflow JSON — read-only APIs only |
http-tool-guide | How to fill in tools/http correctly |
browser-tool-guide | How to choose tools/browser actions correctly |
skill-importer | The pipeline for importing external skills |
Two of these are worth studying as patterns.
workflow-helper queries the running API for live schemas rather than embedding a snapshot,
because a node's schema changes with every build. An embedded copy would be wrong within a week.
workflow-json-builder is explicitly restricted to read-only endpoints — templates, node types,
node schemas, models — and is forbidden from calling create, update, execute, or save. A
skill can constrain what the agent may do, not only tell it what to do.
SKILLS_INDEX.md is the registry. Consulting it before creating a new skill is how you avoid
five near-duplicate capabilities.
The Skills Hub
tools/skills_hub is the unified gateway. Connect it to an agent and the agent can:
| Operation | Returns |
|---|---|
list | Discoverable skills in the current workspace |
search | Skills matching a capability, name, description, or tag |
describe | A skill's full descriptor: required inputs, execution requirements, declared Tool Hub tools |
credential_status | Whether the required credentials are available |
approval_status | Whether execution needs human approval |
execute | Runs the skill with input_data |
The node's own description tells the model the rule that matters: the catalog is dynamic.
Use list or search to discover skills instead of assuming which exist, and call describe
before invoking any tool a skill declares — then use the returned tool identifiers, allowed
operations, and argument schemas. Do not guess skill or tool contracts.
credential_status and approval_status exist so an agent can find out before executing that
it lacks an API key or will hit an approval gate, instead of discovering it halfway through.
The older tools/skill node ("Execute Skill") finds and runs a skill by name. Prefer the hub
for anything new.
Active skill bindings
When Skills Hub successfully resolves a skill through describe, it records an active skill
binding. If the model later omits skill_name on a Tool Hub execute command, that binding
supplies the lookup key.
Three properties make this safe, and they are worth spelling out because "remember which skill we were using" is the kind of convenience that usually becomes a vulnerability:
- Bindings are established only by trusted runtime code — the Skills Hub resolution path. They are never derived from model text, chat memory, or ordinary workflow input.
- A binding is only a lookup key. Tool Hub re-resolves the skill against the current workspace, visibility, and canonical spec before every execution. A stale or revoked binding can never authorise a command on its own.
- The shortcut requires exactly one. Uniqueness is judged by distinct canonical name plus workspace: the same skill resolved repeatedly collapses to one binding and stays unambiguous, while two different skills make the omission shortcut ambiguous and unavailable.
Note that the binding stores the resolved canonical name, not the lookup key the model supplied.
Importing external skills
skill-importer covers the pipeline for bringing in a skill from a URL, a Git repository, or
pasted text:
fetch → LLM parse & generate → tools/validate_skill_spec → approval
→ tools/write_skill_package writes skills/<name>/
→ SkillFileWatcher syncs it into the database
The safety property is in the last step: an imported skill lands as needs_review with
enabled = false. It does not become available to agents because it was written to disk. A
human enables it, and until then it is not added to the tool catalog.
skills/<name>/ is watched, so editing a SKILL.md on disk syncs into the database without a
restart. The lock / unlock endpoints control whether the watcher may overwrite a skill.
REST surface
GET|POST /skills list, create
POST /skills/export-workflow turn a workflow into a skill
GET /skills/uncompleted drafts
GET /skills/by-name/:name
POST /skills/validate validate skill YAML
POST /skills/preview-tools preview the tools a skill would expose
POST /skills/:id/execute
POST /skills/:id/enable | /disable
GET /skills/:id/credential-status
GET /skills/:id/runtime-policy
POST /skills/:id/review
POST /skills/:id/lock | /unlock
POST /skills/:id/normalize
…plus skill categories and CLI tool endpoints
export-workflow is the shortest path to your first skill: build a workflow, export it, and you
have a named capability with schemas an agent can discover.
Writing a good skill
- Write
descriptionas a trigger condition. "Use this skill when the user asks X" beats "This skill does X". - Query live data instead of embedding snapshots where the underlying thing changes.
- State what is forbidden. The most useful line in
workflow-json-builderis the list of APIs it must not call. - Check
SKILLS_INDEX.mdfirst and extend an existing skill rather than adding a fifth near-duplicate. - Keep instructions short and put detail in
references/, linked from the instructions — the agent loads what it needs rather than the whole manual every turn.
Next steps
- Tool Discovery & Tool Hub — how skills and tools meet.
- ReAct Agent Guide — the agent that uses them.
- Connecting MCP Servers — external capability instead of packaged.