This is part 2 of an ongoing series where I keep exploring what Claude Code can do in real-world codebases — just actionable feedback that works! Part 1 here!
As discussed in the previous post, AI coding agents, and in particular Claude Code, have taken the programming world by storm (minus the skeptics yet) and it’s probably the hottest topic right now, so, it’s worthwhile to dive deep into it and explore what these agents can actually do in practice.
A disclaimer before I go on: My experiences are based on working on backend systems for web development, so, Rest APIs and web applications, using very modern frameworks in well-architectured codebases: Springboot, Java 21, Python 3.13 and codebases that have very high test coverage (>= 80%). This is important because codebase context matters a lot on how efficient these models can be for your particular context.
YMMV if: you are working on different tech stacks, giant codebases or have little to no test coverage, although the principles will be very much the same.
What actually are Slash Commands?
Slash commands are a particular feature of Claude Code specifically, but, with a little engineering and imagination, you can replicate it in our own agentic workflows using either open-source models (you have to do a bit more plumbing yourself) or editor built-in agents like Junie inside IntelliJ. Or Github Copilot in your preferred editor, etc.
The reasons these will work so well in different contexts is that essentially they encapsulate flows that:
You are already used to and use often;
Can benefit a wide range of tasks that essentially become very repetitive;
It’s all context engineering under the hood;
Let’s see how it works!
Essentially in Claude Code, a custom slash command is an encapsulation of a fixed set of instructions that can be parametrized in a markdown file, so that the underlying LLM knows exactly what to do for your own workflow.
Think of it as “an alias” for a more contextual prompt you find yourself writing over and over.
What this looks like for you will look very different from user to user: it will be affected by the baseline quality of your codebase, your writing skill and, obviously, how you like to work yourself.
Crafting a Slash command
Let’s look at a practical example.
One of the ways I really like to use Claude is by letting it take the role of a planner or architect for any work I need to do.
I don’t ask it directly to “write me all the code for A, B, C”, but, instead, a more nuanced request, such as: “Let’s plan feature A together, taking into account service B and C, and let’s work in a TDD-like fashion.”
I find that this “extends” the agency of the model because it frees it from the constraints of actually having to output working code. So it’s given “free-rein” to plan, which I find (empirically) that leads to better planning and carefully outlined steps that I can then work through myself.
Again, the most important thing to stress is: you need to find what works for you and if you find yourself repeating certain patterns, you can automate them with a slash command that essentially makes your “workflows” reusable within your context.
Obviously, these can all be version-controlled and shared across teams and/or projects so that everyone can benefit from common workflows to reap the benefits.
These are the same benefits that you already have when you enforce rules like linters, unit test coverage, architecture decisions: by creating a shared vocabulary to interact with agents, the results become more predictable and consistent if people are working across the same codebase.
It’s about scaling knowledge and context engineering practices to level up everyone in your team to benefit from agentic workflows.
To create a custom slash command, we start by defining a folder called `commands
` inside the (potentially already existing) `.claude
` folder.
Then, depending on the organization of your codebase and slash commands, you can: create a command directly inside the top-level `commands
` folder, or create subfolders depending on how you structure your agentic interactions.
As an example, let’s define a custom command to plan a feature, that receives a file as an argument.
The idea is that the user will define a high-level specification for a given feature (this can be for example a ticket from JIRA, Gitlab, etc, directly embedded in the codebase) and then our custom command will guide the model to craft a high-level plan, using a TDD approach where tasks are supplied in stages that can be worked through independently and gradually improve quality.
The best part? Frontier LLMs are amazing as teachers: they can provide great architectural approaches to conduct refactorings and green field implementations.
It won’t be 100% perfect, but, it will do a great job to kickstart your work and if you have a well-structured and documented codebase, you can even one-shot these architectural designs that are so important to get right.
Here’s the full command, called, `plan-feature.md
`. As stated earlier, the full path will be `/.claude/commands/plan-feature.md`
.
Claude will take the file name as the command name, which can be invoked as `/plan-feature <ARGUMENT>`:
You are an expert software architect who excels at feature implementation planning.
Your goal is to read both the @CLAUDE.md file and the $#ARGUMENTS files.
Based on the context inferred from both files, you should plan the feature.
If you can not find the file $#ARGUMENTS, ask the user to provide it. Tell the user to describe the context of the feature.
## Guidelines
Provide a detailed plan in the form of a TODO list. The tasks should be well-defined and well-scoped.
You can suggest small code snippets to guide the implementation. You must follow existing patterns and conventions.
Always think in small steps and using TDD.
Do NOT write the code, only the plan.
As you can see, the command itself is straightforward and self-contained, guiding the model to act as a guide instead of writing code. By calling this command with a reference to a file that contains our “feature details” this would be:/plan-feature @CONTEXT.md
Then, the output will be a detailed, high-level plan that is contextual to your codebase, your best practices and can serve as a great “brainstorming buddy”. Here’s some example output from asking to refactor a simple MCP server that exposes a couple of tools (simplified):
⏺ Refactoring Plan
Project Context
A server application with analysis capabilities that follows a layered architecture. The codebase has tools, execution infrastructure, and services that need refactoring to improve maintainability while preserving performance.
Current Issues
- Classes are well-separated but internal methods have high coupling
- Large methods (85+ lines) with multiple responsibilities
- Parameter-heavy method signatures (5+ parameters)
- Duplication between executor classes
- Configuration logic mixed with execution logic
Detailed Refactoring Plan
Phase 1: Extract Configuration Management
Task 1: Extract Environment Configuration
# Create EnvironmentManager class to handle:
# - External tool environment setup
# - System argument management
# - Process environment creation
# - Reduces the 20+ line environment setup in subprocess execution
Task 2: Create Command Builder Abstraction
# Create CommandBuilder class to:
# - Handle command construction logic
# - Reduce parameter passing between methods
# - Encapsulate tool-specific command logic
# - Support method chaining for cleaner API
Task 3: Extract Timeout Management
# Create TimeoutManager class to:
# - Centralize timeout logic
# - Support different timeout strategies
# - Handle timeout error reporting
Phase 2: Refactor Execution Logic
Task 4: Split Large Methods
- Break down _execute_external_process (85 lines) into:
- _setup_process_environment()
- _execute_process()
- _handle_process_result()
- _log_execution_details()
Task 5: Refactor Subprocess Execution
- Create ProcessExecutor class
- Move subprocess logic from global functions to focused class methods
- Separate concerns: environment setup, execution, result handling
Task 6: Remove Executor Duplication
- Create shared BaseExecutor class
- Move common logic to base class
- Implement template method pattern for execution strategies
Phase 3: Package Restructuring
New Package Structure:
src/core/
├── tools/
├── execution/ # New package
│ ├── __init__.py
│ ├── base_executor.py # Base execution logic
│ ├── command_builder.py # Command construction
│ ├── env_manager.py # Environment management
│ └── timeout_manager.py # Timeout handling
├── analysis_base.py # Existing - interfaces and paths
└── executors.py # Deprecated - will be removed
Phase 4: Test Updates
Phase 1 Tests: Focus on new environment configuration and command builder classes
Phase 2 Tests: Update executor tests to work with new structure
Phase 5: Verification
- Comprehensive test suite execution
- Performance benchmarking
- Behavior validation
Implementation Guidelines
TDD Approach:
1. Red: Write failing tests for new structure
2. Green: Implement minimal code to pass tests
3. Refactor: Improve implementation while keeping tests green
4. Repeat: Work in small increments
Key Principles:
- Single Responsibility: Each class handles one concern
- Dependency Injection: Inject dependencies rather than creating them
- Interface Segregation: Small, focused interfaces
- Method Length: Target < 20 lines per method
- Parameter Count: Target < 4 parameters per method
Example Refactoring (Command Builder):
# Before (high coupling, many parameters)
def build_command(binary_path: str, config: Settings, filename: str) -> List[str]
# After (low coupling, fluent interface)
CommandBuilder(config)\
.with_binary(binary_path)\
.with_filename(filename)\
.build()
Benefits Achieved:
- ✅ Reduce coupling: Extract configurations and builders
- ✅ Fewer parameters: Command builder pattern
- ✅ Smaller methods: Split large method into several focused methods
- ✅ Reduce complexity: Separate execution concerns
- ✅ Reduce nesting: Flatten conditional logic
- ✅ Reduce duplication: Shared base executor class
- ✅ Dedicated packages: New execution/ package structure
Notice how: the model didn’t write any code, and how it focused on offering high level refactoring suggestions to improve the architecture and also proposed a path to start.
Essentially, using this custom slash command effectively “eliminates” writer’s block and can be a great driver for engineers of any level.
The idea is that this structure can guide everyone on a team to adopt a “TDD-mindset” which is super valuable and people will slowly start improving their “architecture taste” which creates a positive feedback loop where writing better code improves the LLMs benefits and the more benefits the better the code, etc.
What’s next?
As with most agentic tools, the idea is to experiment and see what works for you and doesn’t work. You will keep sharpening your sense of what works and doesn’t work the more you use it, and, slash commands are a powerful tool to have in our agentic workflows arsenal!
Ive been working on my own custom slash commands aswell !
Ive made a novel framwork on how to think about working with Claude, and helping Claude account for the weaknesses inherit to its nature as a LLM.
ive turned these into slash commands check out it out
https://typhren.substack.com/p/exploration-of-anthropics-claude?r=6cw5jw