Claude Code: The Perfect Development Loop
I've written two slash commands for Claude Code that form the core of my development workflow: /todo implements one task and /commit commits it.
This post is part of my Claude Code setup series.
Understanding Slash Commands
Claude Code comes with built-in slash commands like /pr-comments, which are essentially shortcuts for specific prompts. You can also create custom slash commands.
- Global commands: Place them in
$HOME/.claude/commands/example.md - Project commands: Place them in
./.claude/commands/example.md
Both are invoked with /example. If a command exists in both locations, the project-specific version takes precedence.
You can find more examples and command definitions in the claude-code-prompts repository.
The Development Loop
When building larger features, I work through a task list in .llm/todo.md:
- Run
/todoto implement the next task - Test and debug manually
- Run
/committo commit the changes - Run
/compactto clean up the conversation history - Repeat
Creating the Task List
When planning larger changes, I tend to chat with a thinking model in the browser. At the end, I ask for a task list:
Write a task list that we can work through to implement this idea, as a markdown checklist.
Each checkbox should represent a task that we can implement and commit on its own.
Arrange the tasks in the order we need to implement them, not in order of importance.
Example format:
- Add a test case for feature ABC.
- It's ok for the test to be failing at this point.
- Implement feature ABC.
- Delete DEF
- Replace usages of DEF with ABC.
I save this list to .llm/todo.md. I've configured Claude to ignore the .llm directory in version control.
/todo
This command tells Claude to implement one task from the list.
---
name: markdown-tasks
description: Work with markdown-based task lists in .llm/todo.md files. Use when managing tasks, working with todo lists, extracting incomplete tasks, marking tasks complete, or implementing tasks from a task list.
---
# Markdown Task Management
This skill enables working with the markdown task list stored in `.llm/todo.md`.
## Important: Do Not Explore Plugin Directory
The scripts referenced below are part of this plugin and are pre-verified to work correctly. Do NOT:
- Search for or read the `.py` script files
- Explore the `${CLAUDE_PLUGIN_ROOT}` directory
- Try to understand the script implementation
Simply **run the bash commands exactly as shown**. The scripts handle all the complexity internally.
## Scripts
These scripts require Python 3 with standard library only (no external packages needed).
### task_get.py - Extract Next Task
Extract the first incomplete task with its context by running this command (do NOT read the script file):
```bash
python3 ${CLAUDE_PLUGIN_ROOT}/skills/tasks/scripts/task_get.py .llm/todo.md
```
Returns the first `[ ]` checkbox line with all indented context lines below it.
**Exit codes**: 0 (success), 1 (file not found or error)
### task_add.py - Add New Task
Add a new task by running this command (do NOT read the script file):
```bash
python3 ${CLAUDE_PLUGIN_ROOT}/skills/tasks/scripts/task_add.py .llm/todo.md "Task description
Context line 1
Context line 2"
```
Creates the `.llm/` directory and `todo.md` file if they do not exist, and appends the new task with a `[ ]` checkbox. The script preserves all indentation in multi-line strings.
**Exit codes**: 0 (success), 1 (error)
### task_complete.py - Mark Task Done
Mark the first incomplete task as done by running this command (do NOT read the script file):
```bash
python3 ${CLAUDE_PLUGIN_ROOT}/skills/tasks/scripts/task_complete.py .llm/todo.md
```
Changes the first `[ ]` to `[x]`.
**Exit codes**: 0 (success), 1 (no incomplete tasks or error)
### task_archive.py - Archive Task List
Archive a completed task list by running this command (do NOT read the script file):
```bash
python3 ${CLAUDE_PLUGIN_ROOT}/skills/tasks/scripts/task_archive.py .llm/todo.md
```
Moves the file to `.llm/YYYY-MM-DD-todo.md` where YYYY-MM-DD is today's date.
**Exit codes**: 0 (success), 1 (file not found or error)
## Task Format
The task list is in `.llm/todo.md`.
NEVER use the `Read` tool on `.llm/todo.md`. Always interact with the task list exclusively through the Python scripts.
### Task States
- `[ ]` - Not started (ready to work on)
- `[x]` - Completed
- `[!]` - Blocked after failed attempt
### Task Structure
Each task includes indented context lines with full implementation details:
- Absolute file paths
- Exact function/class names
- Code analogies to existing patterns
- Dependencies and prerequisites
- Expected outcomes
### Standalone Context
Each task is extracted and executed in isolation. Every task must contain ALL context needed to implement it. Repeat shared context in every related task. Never reference other tasks.
"Think hard" is a magic word that triggers extended reasoning.
/commit
After implementing and testing a task, I use /commit to create a commit:
---
description: Commit local changes to git
---
ALWAYS use the `code:cli` skill.
## Context
- Current git status: !`git status`
- Current git diff (staged and unstaged changes): !`git diff HEAD`
- Current branch: !`git branch --show-current`
- Recent commits: !`git log --oneline -10`
## Task
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
2. **Commit Message Creation**
- ๐ If the user pasted a compiler or linter error, create a `fixup` commit using `git commit --fixup <sha>`
- Otherwise commit messages should:
- Start with a present-tense verb (Fix, Add, Implement, etc.)
- Be concise (60-120 characters)
- Be a single line
- End with a period.
- Borrow language from the original prompt
- Avoid praise adjectives (comprehensive, robust, essential, best practices)
- Echo exactly this: Running: `git commit --message "<message>"`
- ๐ Run git commit without confirming again with the user.
3. **Pre-commit hooks**
When pre-commit hooks fail:
- Stage the files modified by the hooks individually
- Retry the commit
- Never use `git commit --no-verify`
You don't need a custom command to commit - and Claude will offer to commit without being asked. But this gives me control over timing while leveraging Claude's ability to write good summaries.
Managing the Context Window with /compact
The /compact command is built in but not well documented. It's built on a markdown prompt to summarize the conversation, then replaces Claude's context with that summary.
After completing a task, I need to make room in the context window for the next task. I used to run /compact if the next task was related, and /clear if unrelated. Now I just always run /compact.
This is also a good time to restart with claude --continue if it has been running too long or if there's a new version available.
Summary
This workflow breaks large features into manageable steps.
These commands work best when combined with proper Claude Code configuration.
For more custom commands, see Claude Code Utility Commands.
