AgentSkillsCN

command-authoring

通过动态内容注入(@path与!command),打造单文件命令。适用于需要访问文件系统、获取Git状态、调用运行时上下文,或使用$1占位符处理参数的命令构建。涵盖@file注入、!shell执行、<injected_content>包装器,以及单文件结构模式。不适用于技能开发或审计工作流程。

SKILL.md
--- frontmatter
name: command-authoring
description: "Create single-file commands with dynamic content injection (@path and !command). Use when building commands that need filesystem access, git state, runtime context, or argument handling with $1 placeholders. Includes @file injection, !shell execution, <injected_content> wrappers, and single-file structure patterns. Not for skills (use skill-development) or audit workflows."

<mission_control> <objective>Create single-file commands with @path and !command injection for dynamic content and runtime state</objective> <success_criteria>Command has valid frontmatter, proper @/! injection patterns, and graceful error handling</success_criteria> </mission_control>

Quick Start

If you need to inject file content: Use @path pattern at invocation time.

If you need to execute shell commands: Use !`command` for dynamic state.

If you need graceful file handling: Wrap @path in <injected_content> with fallback text.

If you need argument handling: Use $1 for unique identifiers (IDs, hashes, slugs) only.

Navigation

If you need...Read this section...
File injection## PATTERN: @ Path Injection
Command execution## PATTERN: ! Command Injection
Structure## PATTERN: Command Structure
Namespacing## PATTERN: Namespacing
Thin interface## PATTERN: Thin Interface
Engine separation## PATTERN: Engine Separation
Argument handling## PATTERN: Argument Patterns
Anti-patterns## ANTI-PATTERN: Common Mistakes

PATTERN: @ Path Injection

Basic @ Syntax

markdown
<injected_content>
@.claude/workspace/handoffs/diagnostic.yaml
</injected_content>

Or inline:

markdown
Current handoff: @.claude/workspace/handoffs/latest.yaml

What @ Does

At invocation time, the file content replaces the @path pattern. This captures the current state of files that change between sessions.

@ Rules

RuleExample
Wrap in <injected_content>Semantic grouping
Use absolute or relative paths@/path/file or @./path/file
Content replaces patternFile content inlines at invocation

@ Use Cases

Use CaseExample
Handoff files@.claude/workspace/handoffs/*.yaml
Configuration@.claude/settings.json
Diagnostic files@.claude/workspace/diagnostic.yaml

Error Handling

ScenarioBehavior
File existsInjects content
File missingEmpty result (command handles gracefully)

Graceful File Handling

markdown
<injected_content>
@.claude/workspace/handoffs/diagnostic.yaml
</injected_content>

If file doesn't exist: Create new diagnostic

Multiple File Injection

markdown
<injected_content>
@.claude/workspace/handoffs/diagnostic.yaml
@.claude/workspace/handoffs/handoff.yaml
</injected_content>

PATTERN: ! Command Injection

Basic ! Syntax

markdown
Current branch: !`git branch --show-current`
Git status: !`git status --short`

What ! Does

At invocation time, the bash command executes and its output replaces the !`command` pattern. This captures runtime state that changes between invocations.

! Rules

RuleExample
Use backticks!`command`
Standard bash syntaxgit, gh, ls, etc.
Output inlines at invocationstdout replaces pattern

! Use Cases

Use CaseExample
Git state !`git branch --show-current
CI status !`gh run list --limit 1 --json conclusion
File stats !`wc -l file.ts

Error Handling

ScenarioBehavior
Command succeedsInjects stdout
Command failsEmpty result (command handles gracefully)

Safe Commands

markdown
✅ Safe:
!`git branch --show-current`
!`gh run list --limit 1 --json conclusion`
!`pwd`
!`ls *.md`

❌ Unsafe:
!`rm file.ts`
!`git push --force`
!`chmod -R 777 .`

Graceful Patterns

markdown
<injected_content>
@.claude/workspace/handoff.yaml
</injected_content>

If no handoff exists: Create new session

Current branch: !`git branch --show-current 2>/dev/null || echo "detached"`

PATTERN: Command Structure

Single-File Structure

Commands are single markdown files:

code
.claude/commands/folder-name.md

Or flat structure:

code
.claude/commands/command-name.md

Flat Structure

code
.claude/commands/analyze.md
.claude/commands/create.md
.claude/commands/verify.md

Nested Structure

code
.claude/commands/analysis/
├── diagnose.md
├── explore.md
└── reason.md

Command Scope

ScopeLocationDescription
Project.claude/commands/Command available in this project only
Personal~/.claude/commands/Command available in all projects

Command Components

ComponentRequired?Notes
FrontmatterYesYAML with description
## Quick StartYesScenario-based
ContentYesWith @/! injection
<critical_constraint>YesAt bottom

What Commands Contain

ContentTypeNotes
FrontmatterRequiredFirst content
Quick StartRequiredScenario-based
@ injectionOptionalDynamic file content
! injectionOptionalDynamic command output
<critical_constraint>RequiredAt file bottom

What Commands Don't Contain

ExcludedReason
references/ folderCommands are single-file
SKILL.mdSkills use this format
Progressive disclosureCommands load full content

Frontmatter Fields

Commands use minimal frontmatter - no name field (auto-derived from path):

yaml
---
description: "Brief description, non spoiling of the content. Use when {trigger condition + keywords + key sentences user might say that should lead the command to be triggered}. Not for {exclusions}."
argument-hint: "<identifier>"  # Optional: hint for positional args
context: fork  # Optional: for orchestration, see ## PATTERN: Thin Interface
---

All Frontmatter Fields

FieldRequired?Purpose
descriptionYesAuto-discovery, shown in slash menu
argument-hintNoPlaceholder for $1 arguments
contextNofork for orchestration with result return
hooksNoEvent hooks configuration
disable-model-invocationNotrue for liaison commands (requires AskUserQuestion)

Example Frontmatter

yaml
---
description: "Refine skill content for quality and portability. Use when improving existing skills, fixing quality issues, or updating documentation. Includes pattern validation and anti-pattern detection. Not for creating new skills from scratch."
argument-hint: "<skill-name>"
hooks:
  PreToolUse:
    - matcher: "tool == \"Bash\" && tool_input.command matches \"rm\""
      type: prompt
      prompt: "About to run rm - confirm this is intentional."
---

Argument Handling

SyntaxDescriptionExample
$ARGUMENTSEverything after command/test authRun tests matching: auth
$1, $2Positional arguments/fix 123 high → Issue #123, priority high

String Substitutions

VariableReplaces With
$ARGUMENTSAll passed args (appended if missing)
$ARGUMENTS[N]Nth arg (0-based)
$NShorthand for $ARGUMENTS[N]
${CLAUDE_SESSION_ID}Current session ID

Best Practices

  1. Discovery: Commands available via slash command menu
  2. Security: Limit allowed-tools to essentials when needed
  3. Organization: Use subdirectories for namespacing complex projects

Command Frontmatter

yaml
---
description: "Verb + object. Use when [condition]. Includes [features]. Not for [exclusions]."
---

Command Body

markdown
## Quick Start

**If you need X:** Do Y

## Core Content

[Content with @ and ! injection patterns]

<injected_content>
@path/to/file.yaml
</injected_content>

Commands vs Skills

AspectCommandsSkills
StructureSingle fileSKILL.md + references/
Injection@, ! supportedNot supported
FrontmatterRequiredRequired
ReferencesOptional references/Extensive references/

PATTERN: Engine Separation

Commands SHOULD NOT contain complex logic. They should:

  1. Gather context (via @/!)
  2. Ask clarifying questions (if Liaison)
  3. Invoke the appropriate Skill

Anti-Pattern: Command with Logic

markdown
❌ Wrong: A 200-line "how-to" guide in a command
✅ Correct: 5-line context gatherer → invoke Skill

Command Responsibilities

ResponsibilityDescription
Context InjectionUse @/! to capture current state
Human NegotiationUse AskUserQuestion to clarify intent
Skill InvocationDelegate to Engine with compiled context

When to Move to Skill

Use a Skill instead of a Command when:

  • You need references/ for documentation
  • Logic exceeds 50 lines of content
  • Multiple patterns and anti-patterns needed
  • Complex decision trees required

Rule: If you need references/, you are building a Skill, not a Command.


PATTERN: Namespacing

Commands use folder hierarchy for namespacing. Path maps to colon syntax:

Folder PathCommand Invocation
.claude/commands/meta/refine/rules.md/meta:refine:rules
.claude/commands/strategy/architect.md/strategy:architect
.claude/commands/meta/audit/all.md/meta:audit:all

Namespacing Rules

RuleExample
No name field in frontmatterAuto-derived from path
Only description is mandatoryFrontmatter is minimal
argument-hint optional"<skill-name>"
Folders create namespace hierarchymeta/refine//meta:refine:

Flat vs Namespaced

TypeUse WhenExample
FlatCore, high-frequency commands/continue, /handoff
NamespacedRelated commands, complex domains/meta:refine:rules

Namespace Categories

NamespacePurposeExample Commands
meta/*Toolkit self-improvementrefine, audit, reflect, capture
strategy/*Planning and executionarchitect, execute
handoff/*Session continuityresume, diagnostic
learning/*Knowledge capturearchive, refine-rules

PATTERN: Thin Interface

Commands are "Skin" - thin interfaces that bind Reality to Knowledge Skills ("Brain").

Three Command Use-Cases

Use-CasePatternExample
Context Gathering@ and ! injectionGather git state, file content
Liaison WorkAskUserQuestionClarify ambiguous intent
DelegationSkill(tool) invocationCall Knowledge Skill for logic

Thin Interface Rules

  1. Commands MUST provide at least one "Reality" source (@ or !)
  2. Commands SHOULD NOT contain complex logic - delegate to Skills
  3. Commands MUST NOT delegate to other commands (only to Skills)
  4. Skill chaining IS allowed when using context:forked in frontmatter

Context Forking (Orchestration)

When a command/skill must orchestrate subprocesses and receive their results:

Without context:forked:

markdown
---
description: "Call skill B."
---
1. Invoke `skill-b` skill.
2. [Skill A ends here - unreliable return]

Skill B runs but results don't reliably return to Skill A.

With context:forked:

yaml
---
description: "Call skill B with result return."
context: forked
---
markdown
1. Invoke `skill-b` skill.
2. [Skill B completes, result returns to Skill A]
3. Process skill B results...

How it works:

  • context: forked in frontmatter makes the component behave like a subagent
  • Results reliably return to the parent for analysis
  • Essential for: multi-step workflows, result aggregation, orchestration

Delegation Pattern

markdown
## Execution
1. Read the provided skill content.
2. Invoke `skill-development` skill.
3. Compare content against standards.
4. Apply refinements autonomously.

Reality Source Requirement

DoDon't
Use @ for current file stateAssume static content
Use ! for runtime stateHardcode git status, etc.
Provide at least one injectionCreate pure logic commands

PATTERN: Argument Patterns

Dual-Mode Pattern

Commands can operate in two modes:

ModeBehaviorExample
ImplicitInfer from context/handoff:resume → scans handoffs
ExplicitUse provided argument/handoff:resume session-x → loads specific

Argument Rules

RuleExample
$1 for unique identifiers onlysession-x, abc123
Not for flags/options$1 cannot be --verbose
Positional onlyNo --flag value syntax

Example

markdown
$IF($1, Use the provided argument, Scan conversation for context and infer intent)

Argument Use Cases

Use CaseExample
Session ID/handoff:resume session-x
File hash/ops:extract abc123
Project slug/strategy:create my-project

Valid Arguments

markdown
✅ Valid (identifiers only):
session-abc123  # session ID
hash-xyz789     # file hash
my-project      # project slug

Invalid Arguments

markdown
❌ Invalid (flags not allowed):
--verbose               # flag
output-format json      # flag with value
--max-results 10        # flag with value

PATTERN: Error Handling

@ Error Behavior

ScenarioResult
File existsContent injected
File missingEmpty string

! Error Behavior

ScenarioResult
Command succeedsstdout injected
Command failsEmpty string

ANTI-PATTERN: Common Mistakes

Anti-Pattern: Using @ in Skills

markdown
❌ Wrong (skill):
@injected_content>
@.claude/workspace/file.yaml
</injected_content>

✅ Correct (skill):
Read `references/configuration.md` to understand the schema.

Fix: Skills use semantic instructions, not @ injection.

Anti-Pattern: @ for Static Content

markdown
❌ Wrong:
@.claude/commands/static-template.md

✅ Correct:
[inline the template directly]

Fix: Use @ for dynamic content (changes between invocations), not static templates.

Anti-Pattern: No Error Handling

markdown
❌ Wrong:
Current branch: !`git branch --show-current`
[no fallback]

✅ Correct:
Current branch: !`git branch --show-current` (or detached HEAD)

Fix: Consider edge cases and provide context.

Anti-Pattern: $1 for Options

markdown
❌ Wrong:
--verbose               # using flags
output-format           # option names

✅ Correct:
session-abc123          # identifier only

Fix: $1 is for IDs, slugs, hashes only—not flags or options.

Anti-Pattern: Command with References/

code
❌ Wrong:
.claude/commands/example/
├── command.md
└── references/
    └── detail.md

✅ Correct:
.claude/commands/example.md  # Single file

Or if needed:
.claude/skills/example/
├── SKILL.md
└── references/

Anti-Pattern: Wrong Extension

code
❌ Wrong:
.claude/commands/command.txt
.claude/commands/command

✅ Correct:
.claude/commands/command.md

Anti-Pattern: Inconsistent Naming

code
❌ Wrong:
.claude/commands/create-prompt.md
.claude/commands/run_prompt.md
.claude/commands/runprompt.md

✅ Correct:
.claude/commands/create-prompt.md
.claude/commands/run-prompt.md
.claude/commands/run-prompt.md  # Consistent kebab-case

Anti-Pattern: Complex Logic in !

code
❌ Wrong:
!`for f in *.ts; do echo $f; done`

✅ Correct:
Use bash with proper escaping or inline differently

EDGE: Special Cases

Edge Case: No @ or !

Commands that don't need dynamic content:

code
✅ Valid:
.claude/commands/simple.md
[no @ or ! injection]

Content is static, no dynamic state needed.

Edge Case: Multiple Injections

Commands with complex injection:

markdown
<injected_content>
@.claude/workspace/handoff.yaml
</injected_content>

Current branch: !`git branch --show-current`
Modified files: !`git status --porcelain`

Edge Case: Nested Wrappers

markdown
<injected_content>
@main-file.yaml

<details>

<injected_content>
@supporting.yaml
</injected_content>

</details>
</injected_content>

Edge Case: Conditional Injection

markdown
$IF($1, Use explicit: $1, Infer from context)

Edge Case: Command Grouping

Related commands in folder:

code
.claude/commands/handoff/
├── create.md
├── diagnostic.md
├── resume.md
└── create-full.md

Edge Case: Single Command

No folder needed for single command:

code
.claude/commands/simple.md

Edge Case: Many Commands

Use folders for organization:

code
.claude/commands/
├── analysis/
├── build/
├── handoff/
├── learning/
├── ops/
├── planning/
├── qa/
├── strategy/
└── sync/

Edge Case: Optional Injection

Commands with optional @/!:

code
✅ Valid:
!`git branch --show-current` (or detached)

<injected_content>
@optional-file.yaml
</injected_content>
(if exists)

Edge Case: Multiple Commands

Commands with multiple ! patterns:

markdown
Branch: !`git branch --show-current`
Status: !`git status --short`
Last commit: !`git log -1 --oneline`

Edge Case: Conditional Arguments

markdown
$IF($1, Use: $1, Infer from context)

Validation Checklist

Before claiming command authoring complete:

Structure:

  • Single markdown file in .claude/commands/
  • File has .md extension
  • Valid YAML frontmatter with description

Injection Patterns:

  • @path for dynamic file content (not in skills)
  • !command for runtime state capture
  • Wrapped in <injected_content> for semantic grouping
  • Paths are absolute or relative to workspace root

Error Handling:

  • Missing files handled gracefully (empty result)
  • Command failures handled gracefully

Argument Handling:

  • $1 used only for identifiers (IDs, slugs, hashes)
  • No flags or modes as $1 arguments

Content:

  • Follows What-When-Not-Includes format in description
  • Imperative/infinitive voice throughout
  • No references/ folder (commands are single-file)

Common Mistakes to Avoid

Mistake 1: Using @ or ! in Skills

Wrong:

markdown
# My Skill
Current branch: !`git branch --show-current`

Correct: Skills use semantic instructions:

markdown
# My Skill
Determine the current Git branch using standard git commands.

Mistake 2: Using $1 for Flags

Wrong:

yaml
$1: --verbose

Correct:

yaml
$1: session-id  # Only for identifiers

Mistake 3: Missing Frontmatter

Wrong:

markdown
# My Command
description: Does something useful

Correct:

yaml
---
name: my-command
description: "Verb + object. Use when [condition]. Includes [features]. Not for [exclusions]."
---

Mistake 4: Complex Bash in !

Wrong:

markdown
!`for f in $(ls *.json); do cat $f | jq '.name'; done`

Correct:

markdown
!`find . -name "*.json" -exec jq -r '.name' {} \;`

Mistake 5: Missing Error Handling

Wrong:

markdown
@/path/to/mandatory/file.yaml

(If file doesn't exist, command fails)

Correct:

markdown
@/path/to/file.yaml

(gracefully handles missing files)

code

---

## Best Practices Summary

✅ **DO:**
- Use @path for dynamic file content that changes between sessions
- Use !command for runtime state (git status, CI results)
- Wrap injections in `<injected_content>` for semantic grouping
- Handle missing files gracefully
- Use $1 only for unique identifiers (IDs, slugs)
- Follow single-file structure (no references/ folder)
- Provide at least one "Reality" source (@ or !)
- Delegate complex logic to Skills

❌ **DON'T:**
- Use @ or ! in skills (skills use semantic instructions)
- Use $1 for flags, modes, or non-identifier values
- Create multi-file commands (use skills instead)
- Skip .md extension
- Skip frontmatter description
- Use complex bash in ! without proper escaping
- Delegate from command to another command (delegate to Skills only)

---

## Recognition Questions

| Question                                | Recognition |
| :-------------------------------------- | :---------- |
| Does @ inject dynamic file content?     | Yes, content changes between sessions |
| Does ! execute for runtime state?       | Yes, captures git status, CI, etc.    |
| Does command use single-file structure? | Yes, no references/ folder            |
| Does $1 use identifier-only pattern?    | Yes, IDs/slugs, not flags             |
| Is XML minimal?                         | Only injected_content wrapper         |
| Does command delegate to Skill?         | Yes, if logic exceeds ~50 lines       |

---

## Validation Checklist

Before claiming command authoring complete:

- [ ] @ injections provide dynamic content
- [ ] ! executions capture runtime state
- [ ] Single-file structure, no references/ folder
- [ ] $1 uses identifier-only pattern
- [ ] XML minimal (only injected_content wrapper)
- [ ] Complex logic delegated to skills

---

<critical_constraint>
**Command-Only Injection:**

1. Skills MUST NEVER use `@` or `!` syntax
2. Commands MAY use `@` and `!` freely
3. Use `<injected_content>` wrapper for semantic grouping
4. All paths MUST be absolute or relative to workspace root

**Namespacing:**

- Commands use folder hierarchy for namespacing
- Path `.claude/commands/meta/refine/rules.md` → `/meta:refine:rules`
- No `name` field in frontmatter (auto-derived from path)
- Only `description` is mandatory in frontmatter

**Thin Interface:**

- Commands are "Skin" that bind Reality to Knowledge Skills ("Brain")
- Commands MUST provide at least one "Reality" source (`@` or `!`)
- Commands MUST NOT delegate to other commands (only to Skills)
- Skill chaining requires `context: forked` in frontmatter for result return
- Without `context: forked`, subprocess results don't reliably return
- Commands SHOULD NOT contain complex logic (delegate to Skills)

**Engine vs Interface:**

- Commands are Interfaces that bind Skills to Reality
- Commands SHOULD NOT contain complex logic (delegate to Skills)
- If you need references/, you are building a Skill, not a Command

@ and ! are command-only features.

Skills MUST use semantic instructions, not injection.

Commands MUST handle missing files gracefully.

Commands MUST be single markdown files.

Commands MUST use .md extension.

Commands MUST have frontmatter with description.
</critical_constraint>