# How to Create Slash Commands with Argument Placeholders and @file References in Claudian

> Learn to build Claudian slash commands using Markdown files with argument placeholders like $ARGUMENTS and @file references for dynamic prompts. Simplify your command creation workflow.

- Repository: [YishenTu/claudian](https://github.com/YishenTu/claudian)
- Tags: how-to-guide
- Published: 2026-03-17

---

**Claudian lets you define slash commands as Markdown files with YAML front-matter, supporting `$ARGUMENTS`, `$1`, `$2` placeholders for dynamic input and `@file` references that automatically attach file contents to your prompts.**

The Claudian SDK is an open-source Obsidian plugin that integrates Claude directly into your vault. Creating parameterized slash commands allows you to build reusable prompts that dynamically pull in arguments and file contents before sending requests to the agent.

## Understanding the Three Token Types

Claudian expands three distinct token types when processing slash commands. According to the source code in [`src/features/settings/ui/SlashCommandSettings.ts`](https://github.com/YishenTu/claudian/blob/main/src/features/settings/ui/SlashCommandSettings.ts) at line 185, these placeholders are officially documented as:

- **Argument placeholders**: Use `$ARGUMENTS` for the entire input string, or `$1`, `$2`, etc., for positional arguments. The runtime substitutes these with user-supplied values at invocation time.
- **File references**: The `@<path>` syntax triggers the `FileContextManager` to resolve the path, read the file, and attach its contents to the query. This happens in [`src/features/chat/controllers/InputController.ts`](https://github.com/YishenTu/claudian/blob/main/src/features/chat/controllers/InputController.ts) via `fileContextManager.transformContextMentions`.
- **Shell snippets**: The `!` followed by a back-ticked command (e.g., ``!`bash git status` ``) executes in the agent's sandboxed runtime, injecting the command output directly into the prompt.

## Creating Your First Slash Command

Slash commands live as Markdown files in your vault with a YAML front-matter block followed by the prompt body. The parsing logic resides in [`src/utils/slashCommand.ts`](https://github.com/YishenTu/claudian/blob/main/src/utils/slashCommand.ts), which normalizes the `argument-hint` field and serializes commands back to Markdown.

Here is a minimal command file that uses both positional arguments and file references:

```markdown
---
name: summarize-file
description: Summarise a file with optional extra notes
argument-hint: "[file] [notes]"
allowed-tools:
  - Read
---
Summarise @{{ $1 }}.
Additional notes: $2

```

When invoked as `/summarize-file docs/api.md "Focus on auth methods"`, the following expansion occurs:

1. `$1` resolves to [`docs/api.md`](https://github.com/YishenTu/claudian/blob/main/docs/api.md).
2. `@{{ $1 }}` triggers file resolution—the referenced file is read and attached to the query context.
3. `$2` resolves to `Focus on auth methods`.

## Using `$ARGUMENTS` for Free-Form Input

For commands that accept unstructured text, use the `$ARGUMENTS` placeholder to capture everything after the command name. This pattern is processed in [`src/features/chat/controllers/InputController.ts`](https://github.com/YishenTu/claudian/blob/main/src/features/chat/controllers/InputController.ts) around lines 200-207, where the controller prepares the `promptToSend` string.

```markdown
---
name: review-code
description: Review code and suggest improvements
argument-hint: "[code]"
allowed-tools:
  - Read
---
Please review the following code:
$ARGUMENTS

```

Invoking `/review-code console.log('test');` replaces `$ARGUMENTS` with the complete argument string `console.log('test');`.

## Combining Placeholders with Shell Snippets

Advanced commands can mix all three token types. The `!` syntax delegates execution to the agent's runtime, while `@file` references ensure the agent receives the file context.

```markdown
---
name: lint-and-run
description: Lint a file then run a test command
argument-hint: "[file] [test-cmd]"
allowed-tools:
  - Bash
---
!`bash eslint @{{ $1 }}`

Run test: $2

```

In this example:
- `@{{ $1 }}` expands to the file path provided as the first argument.
- The ``!`bash ...` `` snippet executes `eslint` on that file path within the sandbox.
- `$2` receives the test command string.

## Where the Magic Happens: Core Implementation Files

The lifecycle of slash command expansion spans several key files in the `YishenTu/claudian` repository:

**[`src/utils/slashCommand.ts`](https://github.com/YishenTu/claudian/blob/main/src/utils/slashCommand.ts)** – Handles front-matter parsing and serialization. The `serializeSlashCommandMarkdown` function ensures kebab-case output for fields like `argument-hint` and `allowed-tools`, which the parser expects.

**[`src/features/chat/controllers/InputController.ts`](https://github.com/YishenTu/claudian/blob/main/src/features/chat/controllers/InputController.ts)** – Orchestrates the expansion pipeline. At lines 200-207, the controller:
1. Appends editor context and selections.
2. Calls `fileContextManager.transformContextMentions(promptToSend)` to expand `@file` references into absolute paths and attach contents.
3. Sends the expanded string to the agent runtime, which then substitutes `$ARGUMENTS` and positional placeholders.

**[`src/core/prompts/mainAgent.ts`](https://github.com/YishenTu/claudian/blob/main/src/core/prompts/mainAgent.ts)** – Documents the `@filename.md` syntax at line 131, establishing the convention used throughout the prompt language.

## Programmatic Command Creation

You can generate command files dynamically using the SDK's utility functions:

```typescript
import {
  serializeSlashCommandMarkdown,
  validateCommandName,
} from '@/utils/slashCommand';

const cmd = {
  name: 'summarize-file',
  description: 'Summarise a file with optional notes',
  argumentHint: '[file] [notes]',
  allowedTools: ['Read'],
};

const body = `Summarise @{{ $1 }}.\nAdditional notes: $2`;
const markdown = serializeSlashCommandMarkdown(cmd, body);

// Write `markdown` to your vault's commands directory

```

The `validateCommandName` function ensures your command name follows SDK constraints before serialization.

## Summary

- **Slash commands** in Claudian are Markdown files with YAML front-matter defining `name`, `description`, `argument-hint`, and `allowed-tools`.
- **Argument placeholders** (`$ARGUMENTS`, `$1`, `$2`) are substituted at runtime by the agent after `@file` expansion occurs.
- **@file references** are resolved by `FileContextManager.transformContextMentions` in [`InputController.ts`](https://github.com/YishenTu/claudian/blob/main/InputController.ts), automatically attaching file contents to queries.
- **Shell snippets** (``!`bash ...` ``) execute in the agent's sandboxed environment and inject output into prompts.
- Use [`src/utils/slashCommand.ts`](https://github.com/YishenTu/claudian/blob/main/src/utils/slashCommand.ts) functions like `serializeSlashCommandMarkdown` to programmatically generate valid command files.

## Frequently Asked Questions

### What happens if I use `$1` but don't provide any arguments when invoking the command?

If no arguments are provided, `$1` resolves to an empty string. The `@{{ $1 }}` reference would then attempt to resolve `@` with no path, which typically fails silently or resolves to an invalid path depending on your `FileContextManager` configuration. Always validate inputs or provide default logic in your prompt body.

### Can I use `@file` references outside of slash commands?

Yes. The `@filename.md` syntax is part of the broader prompt language documented in [`src/core/prompts/mainAgent.ts`](https://github.com/YishenTu/claudian/blob/main/src/core/prompts/mainAgent.ts). The `InputController` processes these mentions for any chat input, not just slash command invocations, allowing you to reference files in regular chat messages.

### How are shell snippets (`!`) different from regular commands?

Shell snippets marked with ``!` `` are executed by the **agent's runtime** in a sandboxed environment, not by your local system. This means they have access to the agent's file system view and tools, whereas local shell commands would run on your host machine. According to the implementation, these snippets are processed after file references but before the final prompt is sent to Claude.

### Where should I store my slash command Markdown files?

Store them in your Obsidian vault's designated commands directory (typically configured in Claudian's settings). The SDK scans these locations and parses them using the logic in [`src/utils/slashCommand.ts`](https://github.com/YishenTu/claudian/blob/main/src/utils/slashCommand.ts) to populate the command palette. Ensure each file has valid YAML front-matter separated from the body by `---` delimiters.