Overview
Agent Skills are reusable, file-based “playbooks” that you can share across projects or keep workspace-local. Xum follows the Agent Skills specification and exposes skills to models in two steps:- Index in the system prompt: Xum lists available skills (name + description).
- Tool-based loading: the agent calls tools to load a full skill when needed.
/<skill-name> slash command. For example:
/xum-docs suggest tool hooks for this project.
You can find a list of community-maintained, curated skills at skills.sh.
You can easily add those skills to your Xum instance with:
Where skills live
Xum discovers skills from these locations:- Project:
.xum/skills/<skill-name>/SKILL.md - Project (cross-tool):
.agents/skills/<skill-name>/SKILL.md - Global (Xum-specific):
~/.xum/skills/<skill-name>/SKILL.md - Universal (cross-tool):
~/.agents/skills/<skill-name>/SKILL.md - Built-in: shipped with Xum
.xum/skills wins over .agents/skills.
Legacy .mux/skills directories remain readable after .xum/skills at the same directory level. New and updated project skills are written only to .xum/skills.
After project skills, the remaining precedence order is global (~/.xum/skills) > universal (~/.agents/skills) > built-in. Built-in skills behave like any other skill for precedence purposes, so any project or global skill with the same name overrides them.
Xum reads skills using the active workspace runtime. For SSH workspaces, skills are read from the
remote host.
Claude Code compatibility (experiment)
Many repositories already ship skills in Claude Code’s directories. Enable the Claude compatibility experiment (Settings → Experiments) to also discover skills from:- Workspace-local:
.claude/skills/<skill-name>/SKILL.md - Global:
~/.claude/skills/<skill-name>/SKILL.md
.xum/skills > .agents/skills > .claude/skills); a nearer directory still wins over a farther one. The global roots use the same convention order. Compat roots are read-only: Xum never writes or deletes skills in .claude directories. Skills that package Xum workflow scripts are not discovered from .claude roots.
Agent Plugins
Xum also discovers skills packaged in Agent Plugins 1.0.0 directories. A plugin is a directory with aplugin.json manifest plus an optional skills/ folder. Plugins are discovered from:
- Workspace-local:
.xum/plugins/<plugin>/and.agents/plugins/<plugin>/ - Global:
~/.xum/plugins/<plugin>/and~/.agents/plugins/<plugin>/
owner/repo[/path/to/plugin][@ref]). For a plugin inside a monorepo, add its folder after owner/repo, for example cursor/plugins/pstack. Xum then downloads only that folder’s files (a sparse, partial clone) and installs it as the plugin, and the consent preview and update reviews cover only that folder. For a full git URL (https://, SSH, non-GitHub hosts), enter the folder in the Plugin folder field instead. The preview lists the full package before anything is written. Select which skills and MCP servers to import; both groups start with all current items selected and support Select all and Clear. You can install with neither group selected. Agents, workflows, slash commands, and hooks are unaffected by this choice; review their disclosures too. Imported MCP servers remain disabled until you enable them per workspace.
Installed rows show imported-of-available counts. For a managed, present plugin, choose Manage components (or Manage Plugin Components… in the command palette) to change which skills and MCP servers are imported from its locked installed version without fetching the remote. Deselect imported components, select new ones, or use Select all and Clear for a whole group. Review the add/remove counts and choose Save changes, or Cancel to discard your draft. Saving an empty selection keeps the plugin installed with no skills or MCP servers imported; uninstall is a separate action. If the installed files or saved selection change during review, the inventory refreshes and you must review and save again.
Removing imports does not delete source files, plugin data, or workspace MCP settings (including enablement and tool allowlists). New MCP imports remain disabled until enabled per workspace; re-adding a server honors its saved workspace enablement. Agents, hooks, workflows, and slash commands are not changed by this selection. Legacy installs continue to import all components until you save a different selection. Once a selection is explicit, updates preserve it and do not automatically import newly added components.
Updates preserve explicit selections: newly available skills and MCP servers stay unimported until you add them. Updates still require consent for full-package capability changes, including unimported components. Older managed installs without a saved selection continue importing everything, including new components on update. Unmanaged and project-local plugins are unchanged.
Component review
Xum loads a skill, MCP server, agent or slash command from a managed plugin, or runs one of its workflow scripts, only after you review that exact version of it. Xum records what you approved at install, at each update, and in a component review. If its reviewed definition changes later, or if a newer Xum reads more of the plugin than you saw, it stops loading until you review it again. For a skill, the definition is its folder in the plugin and itsSKILL.md frontmatter. A change to the skill’s instructions (the SKILL.md body) does not need a new review. For an MCP server, the definition is everything Xum starts or connects with, such as the command, arguments, environment, URL and OAuth settings. For a workflow script, the definition is the whole script file, because Xum runs it. Any change to the file needs a new review. This includes a skill’s workflow.js in a managed plugin. Other scripts in a managed plugin’s skill folder do not run as workflows. For an agent, the definition is its ID and its frontmatter, such as its name, description, tools and base agent. A change to the agent’s instructions (the body) does not need a new review. If two files in a plugin’s agents folder claim the same agent ID, such as Reviewer.md and reviewer.md, Xum loads neither of them and shows a warning in the review. For a slash command, the definition is its name, description and the full text it inserts.
A changed skill or workflow script is an exception: Xum keeps using the version you approved. At each approval, Xum saves a copy of each approved skill’s SKILL.md and of each approved workflow script. When the file in the plugin no longer matches your approval, Xum uses the saved copy instead, and the plugin shows needs review for the new version. When you approve the new version, Xum uses it and saves it as the new copy. Before Xum uses a saved copy, it checks the copy against your approval the same way, so a copy whose reviewed definition was changed does not load. Other files in a skill folder are not saved. If the file is removed from the plugin, moved to another folder, or can no longer be loaded (for example a SKILL.md that does not parse, or an empty script), Xum does not use the copy. MCP servers, agents and slash commands have no saved copy: they stop loading until you review them.
The saved copy does not help in two cases. When a newer Xum reads more of a skill or script than you approved, the copy does not match your approval either. When a component has no approval on this install (you never reviewed it), there is nothing to fall back to. In both cases the component does not load until you review it.
After you upgrade to a Xum version with component review, every managed plugin needs one review. Its skills and MCP servers do not load until then. Xum does not approve them for you, because your earlier approval did not record what you saw. The same applies to workflow scripts, agents and slash commands: after you upgrade to a Xum version that reviews them, each managed plugin with any of them needs one more review before they load.
To review a plugin:
- Open Settings → Plugins. Each plugin that needs a review shows needs review, and a notice at the top explains what does not load until you review it.
- Select Review on the plugin. The review lists each skill, MCP server, workflow script, agent and slash command with the fields you approve.
- Select Approve components to load them. You can also run Review Plugin Components… from the command palette.
~/.agents/plugins and project plugins are not managed installs. They load as before.
Plugin skill namespaces
A plugin skill has two names: its bare name (tdd) and a qualified name <plugin>:<skill> (pstack:tdd), the same convention Claude Code uses for plugin components.
- A bare name keeps the precedence above. If you have a global
tddskill,tddloads your skill andpstack:tddloads the skill from thepstackplugin. - A qualified name only loads a skill from the named plugin. It never falls back to a project, global, or built-in skill. If a project plugin and a global plugin have the same plugin name, the project plugin wins.
- If two plugins ship the same skill name, the bare name loads the first one, and each stays reachable as
alpha:tddandbeta:tdd. - When a plugin skill loses its bare name to another skill, the model’s skill index lists it under its qualified name. Plugin skills that win their bare name are listed only once, under the bare name.
- A qualified name with no match (for example
nope:tddorpstack:missing) fails withAgent skill not found: <name>.
/pstack:tdd in the composer, or mention $pstack:tdd in a message. The slash menu and $ suggestions list a shadowed plugin skill under its qualified name, and typing tdd also matches pstack:tdd. If no plugin named tdd is installed, $tdd:notes loads the bare tdd skill and leaves :notes as text. If a tdd plugin is installed, $tdd:notes names one of its skills, and no skill attaches when that skill does not exist.
Plugin skills often refer to their sibling skills by bare name. For example, a pstack skill can say “see the tdd skill”. If a higher-precedence skill takes that bare name, Xum tells the model which skill the plugin means:
agent_skill_read,/skill, and$skillput a one-line note at the top of the plugin skill. The note maps each shadowed sibling to its qualified name, for exampletdd->pstack:tdd.agent_skill_read_fileadds the same note in apluginSkillNotefield when it reads a file of a plugin skill. The file content does not change.- The note lists only skills of the same plugin, at most 30. Xum adds no note when no sibling is shadowed.
- Bare-name lookups keep the precedence above. The note does not change which skill a name loads.
SKILL.md frontmatter and directory names stay bare. The qualified form applies only to lookups such as agent_skill_read, agent_skill_read_file, /skill, and $skill.
Skill layout
A skill is a directory named after the skill:^[a-z0-9]+(?:-[a-z0-9]+)*$ (1–64 chars).
The directory name is the skill ID. A directory name that does not match is an error, and Xum does not load the skill.
Bundled files and the skill directory
A skill can ship scripts and other files next toSKILL.md. The skill does not need to know where it is installed: Xum tells the agent.
- The
agent_skill_readresult includesskillDir, the absolute path of the skill’s directory. Plugin skills also getpluginRoot, the absolute path of the plugin. Both paths are valid where the workspace’sbashruns, so the agent can run a bundled script or pass the path to a sub-agent. - Xum replaces these placeholders in the skill body. They use the same names as Claude Code, so skills written for Claude Code work unchanged:
${CLAUDE_SKILL_DIR}: the skill’s directory.${CLAUDE_PLUGIN_ROOT}: the plugin’s directory. Xum replaces it only in plugin skills.
agent_skill_read and when you invoke it (/{skill-name} or $skill-name). For invoked skills, the order is: arguments, then placeholders (except on directive lines), then dynamic context. A directive such as !`sh "${CLAUDE_SKILL_DIR}/scripts/status.sh"` therefore runs the bundled script. In directives, Xum does not insert the path into the command: it sets CLAUDE_SKILL_DIR and CLAUDE_PLUGIN_ROOT as environment variables, and the shell expands them. Quote them, because a path can contain spaces.
/{skill-name} or $skill-name), the first line of the skill text the agent gets names the skill’s directory (and the plugin root for plugin skills). The agent can then open bundled files without searching for them. If the path contains a backtick, a < or >, or a control character, that line tells the agent to call agent_skill_read for the path instead. Skill text in older messages does not change.
Xum reports a directory only when the path is valid where bash runs. Otherwise skillDir is absent and skillDirUnavailable tells the agent why. For an invoked skill whose files are on the Xum host while bash runs elsewhere, the first line says so instead. The agent can still read every bundled file with agent_skill_read_file. The copy of a skill that Xum re-injects after compaction keeps this first line, also for a skill the agent read with agent_skill_read.
When you invoke a project skill in the first message of a new worktree workspace, Xum reads the skill from the project’s main checkout, because the new worktree can lack it. That copy is not the worktree’s, so the placeholders stay literal. If the worktree has the skill, the agent gets its path from
agent_skill_read.
When there is no directory, the placeholders stay as literal text. Xum does not run a dynamic context directive that names one of these variables when it has no value (a shell would expand it to an empty path). The directive’s line then says why it did not run. Xum does not expand ${PLUGIN_ROOT} in skill bodies: Agent Plugins defines it only for MCP server configuration.
SKILL.md format
SKILL.md must start with YAML frontmatter delimited by --- on its own line.
Xum enforces a 1MB maximum file size for SKILL.md.
Required fields:
name: must match the directory name (see Display names)description: short summary shown in Xum’s skills index
licensecompatibilitymetadata(string key/value map)disable-model-invocation(boolean) — set totrueto omit a skill from the system prompt index (see Unadvertised skills below). This spelling is shared with other agent tools such as Claude Code, so portable skills work unchanged.advertise(boolean) — Xum-specific equivalent:advertise: falsebehaves likedisable-model-invocation: true. If both are set, the opt-out wins.user-invocable(boolean) — set tofalseto hide a skill from user-facing invocation surfaces (see Controlling who invokes a skill).argument-hint(string) — short hint describing the arguments a skill expects (for example[issue-number]), shown next to the skill in invocation UIs (see Skill arguments).when_to_use(string) — extra model-facing guidance appended to the skill’s entry in the skills index. The kebab-case spellingwhen-to-useis also accepted; the underscore spelling wins if both are set.paths(list or comma-separated string) — globs that limit the skill to matching files (see Path-scoped skills).
allowed-tools).
Display names
Some skills from other tools set aname that is not kebab-case or is not the directory name, for example name: Poteto Mode in poteto-mode/.
Xum loads such a skill from a project, global or plugin skills root under its directory name.
Xum shows the name as a display name in the slash menu and the skills list, with a warning.
The display name must be a single line of at most 64 characters, with no control or invisible formatting characters.
The skill ID stays the directory name:
- Invoke the skill as
/poteto-mode. - The agent loads it with
agent_skill_read({ name: "poteto-mode" }). - A plugin skill is also reachable as
<plugin>:poteto-mode.
name to the directory name to remove the warning. A missing name is still an error.
Controlling who invokes a skill
Two frontmatter fields control a skill’s visibility in opposite directions:
Combining them makes a reference-only skill: it is neither indexed for the model nor user-invocable, and only loads when something explicitly calls
agent_skill_read({ name: "skill-name" }) — useful for shared fragments referenced by other skills or workflows.
Unadvertised skills
By default, Xum advertises skills by listing them in the system prompt’s<agent-skills> index.
Set disable-model-invocation: true (or the Xum-specific advertise: false) in the frontmatter to exclude a skill from that index. Unadvertised skills:
- Are not listed in the system prompt (reducing token overhead)
- Can still be invoked via
/{skill-name}slash command oragent_skill_read({ name: "skill-name" }) - Still appear in Xum’s UI lists (for example
/slash suggestions) and in ACP clients’ command lists - Are useful for: skills meant only for sub-agents, advanced users, or internal orchestration
Path-scoped skills
Setpaths to make a skill apply only to some files. Cursor and Claude Code use the same key, so portable skills work unchanged.
- Syntax: a YAML list, or one comma-separated string (
paths: "src/**/*.ts, *.{ts,tsx}"). In the string form, a comma inside{}belongs to the glob, and patterns with[or((character classes, extglobs) need the list form. - Matching: each glob is relative to the workspace root.
**/*.tsmatchesfoo.tsandsrc/foo.ts. Files in dot folders (for example.github/) match too. Files outside the workspace never match. - Trigger: a successful
file_readorfile_edit_*call on a matching file. Calls made from insidecode_executiondo not trigger it. - What the model gets: the tool result gets a
path_skillsfield with the skill name and description, and asks the model to read the skill withagent_skill_read. Xum does not insert the skill body. Each skill surfaces at most once per context window. Xum skips it if the model already read the skill in that window. - Limits: at most 3 skills surface per tool call, and only the first 100 model-invocable path-scoped skills can activate.
- Index: path-scoped skills are not in the model-facing skills index. They stay readable by name and invocable with
/{skill-name}. disable-model-invocation: truewins: a skill with both keys never surfaces on its own. It loads only when invoked explicitly.- Invalid patterns: an empty list, an unclosed bracket, an empty entry, a negated pattern (
!…), a backslash (use/), an absolute path, or a..segment makes the whole skill invalid. Xum shows it with the error in the skills indicator and loads the other skills.
Example: deep-review skill
The Xum repository includes an unadvertised deep-review skill that encourages aggressive use of sub-agents to produce excellent code reviews (correctness, tests, consistency, UX, performance). Invoke it with /deep-review when you want a thorough, parallelized review. This skill is defined in .xum/skills/deep-review/SKILL.md.
Skill arguments
Slash invocations can carry arguments after the skill name, for example/fix-issue 123 high. If the skill body contains placeholders, Xum substitutes them before the model sees the skill:
$ARGUMENTS— the full argument text (123 high)$1…$9— whitespace-tokenized positional arguments ($1is123); absent positions become empty strings
- Tokenization is simple whitespace splitting; there are no shell quoting rules.
- Placeholders are substituted everywhere in the body, including code blocks.
- Only a single digit is consumed:
$10means$1followed by a literal0. - If the body contains no placeholders, nothing changes: the arguments simply remain visible in your message (for example “Using skill deploy: 123”).
- Substitution applies only to slash invocations. Inline
$skill-namereferences and model-initiatedagent_skill_readloads receive the body without argument substitution (Xum still replaces the skill directory placeholders).
argument-hint frontmatter field to document the expected arguments in invocation UIs.
Dynamic context injection (experiment)
Enable the Skill dynamic context injection experiment (Settings → Experiments) to let skills pull live command output into their instructions. When you invoke a skill, any line whose entire content is!`command` runs in the workspace, and the line is replaced with a fenced block containing the command’s output before the model sees the skill:
- Directives must occupy the whole line; mid-line
!`...`is ignored. - Directives run after argument substitution, so
!`git log $1`sees resolved arguments. - Commands run sequentially in the workspace directory, with a 10-second timeout and a 16KB output cap per command, and at most 10 directives per skill. A failing command injects its output plus an
[exit code N]note instead of aborting the invocation. - Directives run only when you invoke a skill (
/{skill-name}or a$skill-namereference). Skills the model loads viaagent_skill_readnever run directives — the model cannot trigger command execution this way. - Enabling the experiment requires flipping the toggle in Settings yourself; remote experiment rollout can never switch it on.
Current limitations
- Slash command invocation supports only a single skill as the first token (for example
/{skill-name}or/{skill-name} ...). - Skill bodies may be truncated when injected to avoid accidental mega-prompts.
allowed-toolsis not enforced by Xum (it is tolerated in frontmatter, but ignored).
Further reading
- Agent Skills overview
- What are skills? (progressive disclosure)
- Agent Skills specification
- Integrate skills into your agent (tool-based vs filesystem-based)
- Example skills (GitHub)
- skills-ref validation library (GitHub)