How Slash Commands and Custom Command Directories Work in DeepSeek-Reasonix
DeepSeek-Reasonix implements slash commands as Markdown-based prompt templates stored in configurable directories, loading them at startup with priority-based overrides and exposing them to the model through a dedicated tool interface.
DeepSeek-Reasonix treats slash commands as reusable prompt templates that transform user inputs into structured instructions for the AI. These commands are defined in Markdown files scattered across multiple custom command directories, which the application scans recursively on startup according to a strict priority hierarchy. Understanding this architecture allows you to extend the tool with custom workflows by simply creating text files in the right locations.
Directory Discovery and Priority Hierarchy
The function CommandDirs() in internal/config/paths.go builds a prioritized list of directories to scan, with later directories overriding earlier ones when filenames conflict. The search order follows five distinct priority levels:
- Global legacy OS support – System-wide legacy paths like
<legacy-support>/commands - XDG config fallback – Standard XDG directories such as
<xdg-config>/commands - User home convention – Dot-directories in the home folder:
~/.reasonix/commands,~/.agents/commands, and similar variants - User config/support directories – XDG-compliant paths:
$XDG_CONFIG_HOME/reasonix/commands,$XDG_DATA_HOME/reasonix/commands - Project-relative convention – Local directories in the current working tree:
./.reasonix/commands,./.agents/commands
This hierarchy ensures that project-specific commands take precedence over user defaults, while system-wide fallbacks remain available. When two files resolve to the same command name, the higher-priority directory wins, as documented in the Load function comments in internal/command/command.go.
Loading and Parsing Command Files
The Load(dirs ...string) function in internal/command/command.go walks each directory recursively via walkCommands and processes every *.md file through parseFile. This pipeline extracts three critical components from each Markdown file:
Path-to-name mapping converts the relative filepath into a command identifier by removing the .md extension and converting subdirectory separators into colon namespaces. For example, git/commit.md becomes the command git:commit.
Front-matter parsing extracts a minimal header using frontmatter.Split (lines 45-48). The system recognizes two fields:
description– A human-readable explanation of the command's purposeargument-hint– Placeholder text showing expected arguments
Body extraction treats the remainder of the file as a template string containing substitution tokens.
The resulting data populates a Command struct defined in internal/command/command.go:
type Command struct {
Name string // e.g. "review" or "git:commit"
Description string // from front-matter
ArgHint string // from front-matter
Body string // template containing $ARGUMENTS, $1…$N, $$
Source string // original file path (for diagnostics)
}
Template Rendering and Variable Substitution
When invoked, the Command.Render(args []string) method (lines 32-48) processes the template body using the regex substRe to replace tokens:
$ARGUMENTS– Expands to all arguments joined by spaces$1,$2, etc. – Positional arguments (empty string if missing)$$– Escapes to a literal dollar sign
This simple substitution engine allows commands to accept flexible input without requiring complex scripting syntax.
Runtime Execution and Tool Integration
Custom slash commands are exposed to the AI model through slashCommandTool in internal/command/slashtool.go. The implementation follows this flow:
NewSlashCommandTool receives a slice of SlashEntry wrappers containing the loaded Command objects. When the model calls this tool, it provides JSON with command and arguments fields. The Execute method handles three scenarios:
- Empty or
"list"command – Returns a formatted list of available commands via thelistmethod - Specific command lookup – Renders the template with supplied arguments and returns the expanded text
- Management commands – Direct handling of built-ins like
/model,/provider, and/reload-cmdoccurs inmanagementNoticewithininternal/control/slash.go(lines 62-84)
For custom commands, the tool returns a message formatted as:
Expanded /review — follow these instructions now:
<rendered text>
The model treats this output as a standard user turn, effectively injecting the expanded prompt into the conversation context.
UI Completion and Autocomplete
Both the CLI and TUI interfaces share completion logic defined in internal/control/slash.go. The SlashArgItems function (lines 44-86) dispatches to command-specific helpers (e.g., mcpArgItems, skillArgItems) to generate relevant suggestions.
When typing in the CLI, internal/cli/complete.go calls SlashArgItems to provide live autocomplete. The TUI implementation in internal/cli/chat_tui.go renders these as interactive menus. The filterSlash utility hides already-completed suggestions to streamline the interface.
Creating and Using Custom Commands
To create a custom slash command, place a Markdown file in any scanned directory. For example, create ~/.reasonix/commands/review.md:
description: Summarize the provided code
argument-hint: <files...>
Review the following files:
$ARGUMENTS
Provide a concise summary.
After saving, trigger a reload by running /reload-cmd in the Reasonix interface. This calls ReloadCommands, which re-executes command.Load(CommandDirs()) to pick up the new file.
To invoke the command from the model via the tool interface:
{
"command": "review",
"arguments": "main.go utils.go"
}
The slashCommandTool expands this to:
Expanded /review — follow these instructions now:
Review the following files:
main.go utils.go
Provide a concise summary.
To list available commands, send an empty command field:
{ "command": "", "arguments": "" }
Summary
- DeepSeek-Reasonix loads slash commands from Markdown files in prioritized directories defined by
CommandDirs()ininternal/config/paths.go - Priority overrides follow a five-level hierarchy from global legacy paths to project-local directories
- Command names derive from file paths, with subdirectories becoming colon-separated namespaces (e.g.,
git/commit.md→git:commit) - Template rendering supports
$ARGUMENTS, positional$1…$N, and escaped$$tokens via theRendermethod ininternal/command/command.go - Runtime execution flows through
slashCommandToolininternal/command/slashtool.go, distinguishing management commands from custom templates - Live reload is available via the
/reload-cmdmanagement command without requiring application restart
Frequently Asked Questions
Where should I place custom slash command files?
Place Markdown files in any directory returned by CommandDirs() in internal/config/paths.go. The most common locations are ~/.reasonix/commands/ for user-global commands or ./.reasonix/commands/ for project-specific commands. The scanner recursively searches subdirectories, turning folder structures into command namespaces.
How do I reload commands without restarting the application?
Execute the /reload-cmd management command in the CLI or TUI interface. This triggers ReloadCommands in the controller, which re-executes command.Load(CommandDirs()) to refresh the command registry from disk. This only reloads custom commands; management commands are baked into the binary.
What variables can I use in command templates?
Templates support three substitution tokens processed by Command.Render(): $ARGUMENTS expands to all arguments joined by spaces, $1 through $N access specific positional arguments (returning empty strings for missing positions), and $$ produces a literal dollar sign. These are replaced via regex matching defined in internal/command/command.go.
How are conflicting command names resolved?
When identical filenames exist across multiple directories, later directories override earlier ones according to the priority order in CommandDirs(). Project-relative directories (priority 5) take precedence over user home directories (priority 3), allowing repository-specific commands to shadow global defaults. The Source field in the Command struct tracks the originating file path for debugging conflicts.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →