Skip to main content

Module commands

Module commands 

Source
Expand description

Read-side access to Claude Code’s on-disk custom slash command definitions.

Claude Code resolves custom slash commands from *.md files at:

  • ~/.claude/commands/<name>.md – user-level
  • <project>/.claude/commands/<name>.md – project-level

Plus plugin-provided commands under ~/.claude/plugins/<plugin>/commands/, which this module does not enumerate (the plugin feature surfaces those separately).

§What’s NOT covered

Built-in slash commands like /help, /clear, /config, /init are hardcoded in the claude binary. They have no disk representation, are not listed by claude --help, and aren’t introspectable from the CLI. Consumers learn about them from Claude Code’s own UX. We deliberately do not attempt to mirror a built-in list here – doing so would silently rot every time Claude Code adds or renames one.

Skills also surface as slash commands (/recall, /draft-pr-first, etc.) but they’re a separate on-disk artifact type and are not loaded by this module. A consumer that wants “the full slash command universe at this moment” combines this list with a separate skills enumeration (and accepts that built-ins aren’t represented).

§Two levels of granularity

  • CommandsRoot::list – enumerate every *.md command at the root with summary metadata.
  • CommandsRoot::get – read one command’s full record including the prompt body and any unknown frontmatter keys.

§Frontmatter format

Real-world commands look like:

---
description: Open a PR for the current branch
argument-hint: <pr title>
allowed-tools: Bash(git *), Bash(gh *)
model: sonnet
---

Open a pull request titled "$ARGUMENTS" ...

The parser is permissive: only description, argument-hint, allowed-tools, model, and disable-model-invocation are typed. Any other key: value pairs land in Command::extra. Frontmatter is optional – a body-only file parses fine, with description left None.

Note the dashes in argument-hint / allowed-tools / disable-model-invocation: that’s how Claude Code spells the keys on disk. The typed fields use Rust-friendly snake_case names.

§Example

use claude_wrapper::commands::CommandsRoot;

let root = CommandsRoot::user()?;
for summary in root.list()? {
    println!("/{}: {}", summary.file_stem,
        summary.description.as_deref().unwrap_or(""));
}

Structs§

Command
Full command record returned by CommandsRoot::get.
CommandSummary
Lightweight metadata for one slash command, returned by CommandsRoot::list.
CommandsRoot
Root directory of one set of slash command definitions (<root>/<stem>.md). Use Self::user for the user-level root at ~/.claude/commands, Self::project for a project’s <dir>/.claude/commands, or Self::at to point at an arbitrary directory for tests.