How Skill and Slash Command Systems Interact for Workflow Automation in Roo Code

Roo Code's slash command system automatically falls back to the skill system when a command file is not found, allowing both tools to share the same approval workflow and mode-specific discovery logic while providing developers flexibility to expose automation as either explicit commands or reusable skills.

The Roo Code extension provides two native tools—skill and run_slash_command—that enable LLM-driven workflow automation through reusable markdown definitions. Understanding how these systems interact helps developers architect efficient automation pipelines that leverage mode-specific filtering and unified approval flows. This article examines the source code implementation to reveal exactly how skills and slash commands work together in the Roo Code ecosystem.

The Two Native Automation Tools

Roo Code exposes automation through two complementary tools that share underlying infrastructure but serve slightly different purposes.

The skill tool executes reusable automation logic defined in markdown files located under .roo/skills/. When an LLM invokes this tool, it passes a JSON block containing the skill name and arguments. The implementation lives in src/core/tools/SkillTool.ts (lines 19-78), which validates the skill name, obtains the SkillsManager instance, and resolves the appropriate content for the current mode.

The slash command tool executes commands defined in markdown files under .roo/commands/. When a user types a leading / in the chat, the UI parser in src/webview-ui/src/utils/context-mentions.ts detects the pattern and creates a run_slash_command tool block. The execution logic resides in src/core/tools/RunSlashCommandTool.ts (lines 19-71), which attempts to resolve the command via getCommand() from src/services/command/commands.ts.

How Slash Commands Fall Back to Skills

The interaction between these systems centers on a graceful fallback mechanism that unifies the two automation layers.

When RunSlashCommandTool.execute() runs, it first attempts to locate a command file matching the user input. If getCommand(task.cwd, commandName) returns no result, the tool automatically falls back to the skill system at lines 57-73:

const skillContent = await resolveSkillContentForMode(
    skillsManager,
    commandName,          // same identifier the user typed
    currentMode,
);

This function, defined in src/services/skills/skillInvocation.ts (lines 21-35), searches for a matching skill using the same identifier originally intended for the command. If found, the tool uses buildSkillApprovalMessage to construct the user approval prompt and buildSkillResult to format the final output—identical to the workflow used by direct skill invocations.

This design ensures that developers can expose automation simply by creating a skill file, without needing to create a separate command definition, while still maintaining the ability to override behavior with explicit command files when necessary.

Mode-Aware Discovery and Filtering

Both tools respect mode-specific visibility through the centralized SkillsManager defined in src/services/skills/SkillsManager.ts.

At startup, the manager scans both global and project skill directories, follows symlinks, and builds an index keyed by skill name, source, and primary mode (lines 43-65). The getSkillsForMode(mode) method (lines 84-95) filters this index to return only skills whose modeSlugs include the current mode or are unrestricted.

When slash commands fall back to skills, this filtering ensures that only context-appropriate skills are available to the LLM, preventing automation meant for architect mode from appearing during code mode sessions.

Shared Approval Workflow

Both invocation paths leverage the same approval infrastructure to maintain consistent user experience.

When executing either tool, Roo Code uses:

  • buildSkillApprovalMessage() to construct the JSON approval request presented to the user
  • buildSkillResult() to format the final displayed result after approval
  • The same user consent flow before executing any automation logic

This shared workflow means that whether a user invokes automation via /command-name or through an explicit skill tool call, the security and approval mechanisms remain identical.

Practical Implementation Examples

Direct Skill Invocation

When an LLM explicitly calls the skill tool, it generates this JSON:

{
  "tool": "skill",
  "skill": "pdf-processing",
  "args": "report.pdf"
}

The SkillTool.execute() method processes this block, validates the skill exists, obtains approval, and returns the formatted result.

Slash Command Fallback to Skill

When a user types in the chat:


/pdf-processing report.pdf

The system creates this tool block:

{
  "tool": "run_slash_command",
  "command": "pdf-processing",
  "args": "report.pdf"
}

RunSlashCommandTool.execute() fails to find a command file named pdf-processing, falls back to resolveSkillContentForMode(), locates the skill, and produces the same output as a direct skill call.

Skill Definition Structure

File: .roo/skills/pdf-processing/SKILL.md

---
name: pdf-processing
description: Extract text and tables from a PDF file
modeSlugs: [code, architect]
---

# PDF Processing Skill

Do the following:
1. Read the PDF at the path supplied in `args`.
2. Extract text and tables.
3. Return the extracted data as JSON.

Slash Command Definition Structure

File: .roo/commands/deploy.md

---
name: deploy
description: Deploy the current project to the selected environment
argumentHint: <environment>
mode: code
---

# Deploy Command

Run the project's deployment script with the provided environment.

If this file exists, RunSlashCommandTool will execute it directly and never consult the skill manager, even if a skill named deploy exists.

Summary

  • Roo Code maintains a unified automation layer where slash commands and skills share discovery and approval logic through SkillsManager and skillInvocation.ts.
  • RunSlashCommandTool automatically falls back to skills when command files are missing, enabling seamless hybrid workflows without duplicate definitions.
  • Mode-specific filtering via SkillsManager.getSkillsForMode() ensures that fallback resolution respects context-appropriate visibility rules.
  • Both tools use identical approval messaging through buildSkillApprovalMessage() and buildSkillResult(), creating a consistent security model across all automation invocations.

Frequently Asked Questions

How does Roo Code decide whether to use a slash command or a skill?

When a user types a / command, the system first attempts to locate a matching command file via getCommand() in src/services/command/commands.ts. If no file exists, RunSlashCommandTool.execute() automatically falls back to resolveSkillContentForMode() in src/services/skills/skillInvocation.ts to search for a skill with the same identifier, creating a seamless priority system where explicit commands take precedence over skills.

Can a skill be restricted to specific operating modes?

Yes. Skills define modeSlugs in their frontmatter (e.g., modeSlugs: [code, architect]), and SkillsManager.getSkillsForMode() filters the available automation options based on the current mode. This ensures that when slash commands fall back to skills, only mode-appropriate skills are surfaced to the LLM according to the logic in src/services/skills/SkillsManager.ts lines 84-95.

What happens if both a command and skill exist with the same name?

The slash command takes priority. Since RunSlashCommandTool checks for command files before falling back to the skill system, any file in .roo/commands/ will shadow a skill of the same name. This allows developers to override skill behavior with command-specific metadata or logic when needed.

Where is the skill fallback logic implemented in the source code?

The fallback mechanism resides in src/core/tools/RunSlashCommandTool.ts at lines 57-73, where the tool catches command resolution failures and invokes resolveSkillContentForMode() from src/services/skills/skillInvocation.ts. This shared function is also used by SkillTool in src/core/tools/SkillTool.ts, ensuring consistent behavior across both invocation paths.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →