Skip to main content

Claude Code: Moving from Slash Commands to Agents

· 8 min read
Craig P. Motlin
Software Engineer

When agents were released, the documentation was too vague for me to understand what they were for. One effective way to use them is as a more powerful form of slash commands.

Agents Seemed Vague

When Claude Code released agents, the documentation described them as "specialized AI assistants that can be invoked to handle specific types of tasks." Each agent:

  • Has a specific purpose and expertise area
  • Uses its own context window separate from the main conversation
  • Can be configured with specific tools it's allowed to use
  • Includes a custom system prompt that guides its behavior

This definition was so generic I couldn't figure out what they were actually for. The examples showed personas like "code-reviewer," "debugger," and "data-scientist." I've never understood the pattern of personifying AI with "you are a senior code reviewer" type prompts. The LLM's expertise comes from its training data, not from prompts written in second person.

Porting Slash Commands to Agents

I already had custom slash commands that worked well. So I started experimenting by converting commands into agents.

I used the /agents slash command to set up the markdown file structure, then copied my existing prompt content in.

At this point I noticed a mechanical benefit - I could tell Claude to run multiple agents in sequence. It's not possible to execute multiple slash commands in one go. A prompt like Please /commit and then /rebase doesn't work - presumably because they are a special syntax.

With slash commands, I had felt like I was babysitting the agents. At the end of each task, I ran /comments, then just precommit (pasting failures if it broke), then /commit, then git rebase (running /conflicts if it failed). With subagents, I can say "run comment-cleaner, precommit-runner, git-commit-handler, and git-rebaser" and it works great.

I kept my slash commands. I still use them occasionally, but I use the subagent versions more.

Why Agents Are Better Than Alternatives

Agents share features with several existing tools but combine their benefits:

What Agents Have in Common With Other Tools

  • Slash Commands: Both let you invoke complex behavior with a simple trigger, keeping detailed prompts out of context until needed
  • Task Tool: Both run in isolated context windows to avoid polluting your main conversation
  • MCP Tools: Both can run automatically when Claude recognizes they're needed, or can be invoked explicitly

How Agents Improve on Each

  1. Context Isolation (vs Slash Commands): Slash command prompts don't load into context on startup, but they do load when you invoke them. Subagents are more like MCP tools; only their description loads into main context on startup, and the full prompt loads in the agent's isolated context. Subagents are also like the Task tool; all the output from their work stays in the agent's context as well.

  2. Model Switching (vs Slash Commands and Task Tool): With slash commands and Tasks, everything runs using the same model. With subagents, I can use a more powerful and expensive model for my main work but run agents on a cheaper model. This is not always a huge benefit - it depends on the models and pricing of the day.

  3. Detailed Instructions (vs Task Tool): Before subagents, I had tried prompts like "Run /commit using the Task tool" but this simply didn't work. Subagents fill this gap.

Practical Benefits

After using agents for a few weeks, here's what I've found:

  • Longer Sessions: By offloading repetitive tasks to agents, my main context stays clean. I can work much longer without hitting context limits or needing to compact.

  • Better Task Decomposition: LLMs perform better with several short, focused prompts rather than a single long prompt with multiple steps. Since agents can call other agents (like git-rebaser calling git-rebase-conflict-resolver), they naturally decompose complex tasks into manageable pieces.

  • Cost Savings: On personal projects where I pay per token or have usage caps, running simpler tasks on Sonnet instead of Opus saves money and stays under limits. This is less relevant with Sonnet 4.5.

My Four Main Agents

In my ~/.claude/CLAUDE.md, I specify four agents that should run when code changes are ready:

- When a code change is ready, and we are about to return control to the user, do these things in order:
- Remove obvious comments using the `comment-cleaner` agent
- Verify the build passes using the `precommit-runner` agent
- Commit to git using the `git-commit-handler` agent
- Rebase on top of the upstream branch with the `git-rebaser` agent

comment-cleaner

This agent removes the redundant comments that LLMs inevitably write. It's based on my /comments command.

.claude/agents/comment-cleaner.md
---
name: comment-cleaner
description: This agent should be invoked after making code changes and before running the build or committing. It removes redundant, obvious, or outdated comments while preserving important ones like TODOs and linter directives.\n\n<example>\nContext: The user has fixed a bug and the code contains old commented-out debugging code.\nuser: "I've fixed the null pointer exception in the payment processor"\nassistant: "Good work fixing that bug. Now let me clean up the comments before we commit."\n<commentary>\nAfter bug fixes, there are often commented-out debug statements or old code. Use the comment-cleaner agent to clean these up.\n</commentary>\nassistant: "I'll run the comment-cleaner agent to remove any commented-out code and redundant comments"\n</example>\n\n<example>\nContext: The user has refactored code and there are comments describing old behavior.\nuser: "I've refactored the data processing pipeline to use the new async pattern"\nassistant: "The refactoring looks complete. Let me clean up the comments next."\n<commentary>\nRefactoring often leaves behind comments about old implementations. Use the comment-cleaner agent to remove these outdated comments.\n</commentary>\nassistant: "I'll use the comment-cleaner agent to remove any comments that describe the old synchronous implementation"\n</example>
model: haiku
color: cyan
---

🧹 Remove redundant and unnecessary comments from code.

Your role is to review code that is about to be committed and remove reundant and unnecessary comments that the LLM added while making changes.

## Comments to Remove:
- Delete any code that has been commented out
- Edit history comments - Remove comments containing past-tense verbs like "added", "removed", "changed", "updated", "modified"
- Delete comments that merely restate what the code clearly does (e.g., `// increment counter` above `counter++`)
- Remove comments that just repeat the method name in different words

## Comments to Preserve:
- Never remove comments starting with TODO, FIXME, or similar markers
- Keep comments like `// eslint-disable`, `// prettier-ignore`, `// @ts-ignore`, etc.
- Preserve comments that explain non-obvious logic or business rules
- Don't remove comments if doing so would leave empty scopes (empty catch blocks, else blocks, etc.)
- Comments that already existed before our work

## Comments to move
- End-of-line comments - These should be moved to their own line above the code they describe
- Place the comment on its own line immediately above the code it describes
- Maintain the same indentation level as the code below it

## Workflow
- Look at all comments in the uncommitted changes
- It's not enough to consider all changed files because we don't want to remove old comments
- Consider the whole diff/patch to make sure we're only removing new comments
- Remove redundant comments without hesitation
- Move end-of-line comments to their own lines

Focus only on comment cleanup - do not modify the actual code logic, only comments. After your cleanup, the code should be ready for a clean commit without clutter from development artifacts or obvious explanations.

View on GitHub

precommit-runner

This agent runs just precommit. I intend for this recipe to exist in every project and to run appropriate builds, tests, and formatters. If it fails because just or the precommit recipe aren't set up yet, I go ahead and set them up.

.claude/agents/precommit-runner.md
---
name: precommit-runner
description: Use this agent after making code changes to run pre-commit checks (formatting, builds, tests) before returning control to the user. Should be invoked automatically after any code modifications.\n\n<example>\nuser: "Fix the null pointer exception in the user service"\nassistant: "I've fixed the null pointer exception by adding proper null checks. Let me run the pre-commit checks."\n<commentary>\nAfter making code changes, use the precommit-runner agent to ensure everything passes.\n</commentary>\nassistant: "Now I'll use the precommit-runner agent to verify all checks pass"\n</example>
tools: Task, Bash, Glob, Grep, LS, ExitPlanMode, Read, Edit, MultiEdit, Write, NotebookRead, NotebookEdit, WebFetch, TodoWrite, WebSearch, mcp__context7__resolve-library-id, mcp__context7__get-library-docs
model: haiku
color: pink
---

✅ Run quality checks on code changes.

You run quality checks on code changes before they are finalized. Your task is to execute pre-commit checks and handle any failures that occur.

## Initial Execution

Run `[ "$(pmset -g batt | head -n1 | cut -d "'" -f2)" != "Battery Power" ] && just precommit || echo "⚡ Skipping precommit on battery power"`. Don't check if the justfile or recipe exists. This command typically runs autoformatting, builds, tests, and other quality checks.

## Handle Missing Recipe

If the command fails because the justfile doesn't exist or the 'precommit' recipe is not defined, clearly explain this situation. Your response should indicate whether the justfile file is missing or whether just the `precommit` recipe is missing.

## Handle Check Failures

When precommit fails (due to: type checking errors, test failures, linting issues, build errors) you must:
- Analyze the error output to understand what failed
- Use the 'general-purpose' agent to fix the specific failures
- After fixes are applied, run the precommit command again
- Continue the fix-and-retry cycle until precommit completes successfully with exit code 0.

View on GitHub

git-commit-handler

This agent stages and commits changes. It's based on my /commit command.

.claude/agents/git-commit-handler.md
---
name: git-commit-handler
description: Use this agent when you need to commit local changes to git. <example>\nContext: The user has just finished implementing a new feature and wants to commit the changes.\nuser: "I've finished implementing the user authentication feature, please commit these changes"\nassistant: "I'll use the git-commit-handler agent to commit your changes"\n<commentary>\nSince the user wants to commit changes after implementing a feature, use the git-commit-handler agent to ensure proper staging and commit message formatting.\n</commentary>\n</example>\n<example>\nContext: The user has fixed a bug and needs to commit the fix.\nuser: "Fixed the null pointer exception in the payment processor, commit this"\nassistant: "Let me use the git-commit-handler agent to commit your bug fix"\n<commentary>\nThe user has fixed a bug and wants to commit it, so the git-commit-handler agent will stage the relevant files and create a proper commit message.\n</commentary>\n</example>\n<example>\nContext: The assistant has just made code changes and needs to commit them.\nassistant: "I've updated the database schema as requested. Now I'll use the git-commit-handler agent to commit these changes"\n<commentary>\nAfter making code changes, the assistant proactively uses the git-commit-handler agent to commit the work.\n</commentary>\n</example>
model: haiku
color: red
---

📝 Commit the local changes to git.

## Core Responsibilities

1. **File Staging**
- 📦 Stage files individually using `git add <file1> <file2> ...`
- NEVER use commands like `git add .`, `git add -A`, or `git commit -am` which stage all changes
- Only stage files that were explicitly modified for the current task
- Use single quotes for filenames containing `$` characters (e.g., `git add 'app/routes/_protected.foo.$bar.tsx'`)

2. **Commit Message Creation**
- If the original task was fixing a compiler/linter error, create fixup commit using `git commit --fixup <sha>`.
- Otherwise:
- Start with a present-tense verb (Fix, Add, Implement, Update, Remove, etc.)
- Keep messages concise (60-120 characters)
- Single line only - no multi-line messages
- End with a period
- Focus on the intent/purpose, not implementation details
- Avoid praise adjectives (comprehensive, robust, essential, best practices, etc.)
- NEVER include attribution footers or co-author tags

3. **Pre-commit hooks**
- When pre-commit hooks fail:
- Stage the files modified by the hooks individually
- Retry the commit
- NEVER use `--no-verify`

## Workflow

- Identify changed files which files are relevant to the current task
- Stage files individually with `git add`
- Craft an appropriate commit message based on the task
- Echo: Ready to commit: `git commit --message "<message>"`
- Execute the commit without asking for confirmation
- If pre-commit hooks fail, stage the hook-modified files and retry

## Examples of Good Commit Messages
- "Add user authentication endpoint."
- "Fix null pointer exception in payment processor."
- "Update database schema for user profiles."
- "Remove deprecated API endpoints."
- "Implement password reset functionality."

## Examples of Bad Commit Messages
- "Fixed bug" (not specific enough)
- "Comprehensive refactoring of authentication system" (praise adjective)
- "Add feature\n\nThis adds a new feature that..." (multi-line)

Remember: You are responsible for creating clean, atomic commits that clearly communicate the purpose of each change. Focus on precision in both file staging and message crafting.

View on GitHub

git-rebaser

This agent rebases the current branch on top of the upstream branch to ensure changes are up to date before handing control back. This agent can itself call another agent - if it encounters merge conflicts, it delegates to the git-rebase-conflict-resolver agent.

.claude/agents/git-rebaser.md
---
name: git-rebaser
description: Use this agent to rebase local commits on top of the upstream remote/branch after committing code to git.\n\n<example>\nContext: The user has just committed code and wants to rebase on upstream changes.\nuser: "Now rebase my changes on the upstream branch"\nassistant: "I'll use the git-rebaser agent to rebase your commits on top of the upstream branch."\n\n</example>\n\n<example>\nContext: Code has been committed using the git-commit-handler agent.\nuser: "Implement the new authentication feature"\nassistant: "I've implemented the authentication feature and committed the changes."\n<function call to git-commit-handler omitted>\nassistant: "Now I'll rebase these changes on the upstream branch to ensure they're up to date."\n<commentary>\nAfter committing, launch the git-rebaser agent to rebase on upstream.\n</commentary>\n</example>
model: haiku
color: orange
---

🌱 Rebase local git commits on upstream branch.

You rebase local git commits on top of the upstream remote/branch.

**Your Primary Responsibilities:**

1. **Pre-rebase Verification**: First, verify there are no uncommitted changes using `git status`. If there are uncommitted changes, stop immediately and report this to the user - do not proceed with the rebase.

2. **Execute Rebase**: Run the command `just --global-justfile rebase` to perform the rebase operation. This command will detect the correct upstream remote/branch to use. Do not add any arguments or environment variables to this command.

3. **Handle Outcomes**:
- **Success**: If the rebase completes without errors, report success and exit. Your work is complete.
- **Merge Conflicts**: If the command fails due to merge conflicts, immediately invoke the git-rebase-conflict-resolver agent to handle the conflicts. Do not attempt to resolve conflicts yourself.
- **Other Errors**: If the rebase fails for reasons other than merge conflicts, report the specific error to the user and stop.

**Operational Guidelines:**

- You must execute exactly one rebase attempt per invocation
- Do not modify any files or make any commits yourself
- Do not attempt to continue or abort rebases manually - the conflict resolver agent handles all conflict resolution workflows
- Trust that the `just --global-justfile rebase` command knows how to find the correct upstream
- After delegating to the git-rebase-conflict-resolver agent for conflicts, consider your task complete - that agent will handle the entire conflict resolution process

**Workflow:**
1. Check `git status` for uncommitted changes
2. Execute `just --global-justfile rebase`
3. If successful: Report success and exit
4. If conflicts: Invoke git-rebase-conflict-resolver agent and exit
5. If other error: Report error and exit

You are a focused, single-purpose agent. Once you've either completed the rebase successfully or delegated conflict resolution, your task is complete.

View on GitHub

Putting It All Together: The /todo Command

As I found myself manually running the same sequence of cleanup agents after implementing each task, I created a /todo slash command to gather the entire workflow into a single command. I started keeping a markdown task list in .llm/todo.md. I'd run /todo to get Claude to implement one task from the list. The full slash command is on GitHub. To summarize what it does:

  1. Read .llm/todo.md using todo-get
  2. Find the first incomplete task
  3. Implement it (focusing ONLY on this task, ignoring other items)
  4. Run all the cleanup agents
  5. Mark it complete using todo-complete

Step 4 is where these four agents come together. The cleanup step calls them in sequence:

/todo (slash command)
├── 1-3: Find and implement task
└── 4: Run cleanup agents
├── @comment-cleaner
├── @precommit-runner
├── @git-commit-handler
└── @git-rebaser
└── @git-rebase-conflict-resolver (if conflicts occur)

The git-rebaser agent can itself call another agent - if it encounters merge conflicts, it delegates to git-rebase-conflict-resolver.

Complex workflows naturally decompose when agents can call other agents. Instead of one long prompt trying to handle all edge cases, each agent focuses on its specific concern - cleaning comments, running tests, committing, or resolving conflicts.

Try It Yourself

You can copy my agents directly from my GitHub repo or create your own with /agents. Start with something simple - maybe just the comment cleaner - and see how it changes your workflow.

I feel like I'm just scratching the surface with agents. If you find different patterns that work well, let me know in the comments below.