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

> Explore how Roo Code's skill and slash command systems interact for seamless workflow automation. Discover flexible development with shared logic and approval workflows.

- Repository: [Roo Code/Roo-Code](https://github.com/RooCodeInc/Roo-Code)
- Tags: how-to-guide
- Published: 2026-04-26

---

**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`](https://github.com/RooCodeInc/Roo-Code/blob/main/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`](https://github.com/RooCodeInc/Roo-Code/blob/main/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`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/RunSlashCommandTool.ts)** (lines 19-71), which attempts to resolve the command via `getCommand()` from **[`src/services/command/commands.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/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:

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

```

This function, defined in **[`src/services/skills/skillInvocation.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/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`](https://github.com/RooCodeInc/Roo-Code/blob/main/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:

```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:

```json
{
  "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`](https://github.com/RooCodeInc/Roo-Code/blob/main/.roo/skills/pdf-processing/SKILL.md)**

```yaml
---
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`](https://github.com/RooCodeInc/Roo-Code/blob/main/.roo/commands/deploy.md)**

```yaml
---
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`](https://github.com/RooCodeInc/Roo-Code/blob/main/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`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/command/commands.ts). If no file exists, `RunSlashCommandTool.execute()` automatically falls back to `resolveSkillContentForMode()` in [`src/services/skills/skillInvocation.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/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`](https://github.com/RooCodeInc/Roo-Code/blob/main/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`](https://github.com/RooCodeInc/Roo-Code/blob/main/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`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/services/skills/skillInvocation.ts). This shared function is also used by `SkillTool` in [`src/core/tools/SkillTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/SkillTool.ts), ensuring consistent behavior across both invocation paths.