Compare commits

..

3 Commits

Author SHA1 Message Date
Daisy Hollman
95380b3cd5 Add caffeinate plugin to prevent blocking sleep commands
This plugin intercepts sleep commands in Bash and prompts Claude to use
background execution (run_in_background: true) instead. This keeps the
session responsive during long-running operations.

Features:
- Blocks sleep commands with helpful retry message
- Allows sleep in quoted strings (false positive prevention)
- Catches sleep in compound commands (&&, ||, ;) and loops
- Allows background commands through (run_in_background: true)

🏠 Remote-Dev: homespace

Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%)
Claude-Steers: 6
Claude-Permission-Prompts: 0
Claude-Escapes: 0
2026-01-09 22:48:26 +00:00
Boris Cherny
f1be96f0fb Merge pull request #183 from anthropics/boris/code-simplifier-plugin
Add code-simplifier plugin
2026-01-08 17:59:29 -08:00
Noah Zweben
48c6726985 Add huggingface-skills plugin to marketplace (#174)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-08 16:52:00 -08:00
5 changed files with 167 additions and 0 deletions

View File

@@ -328,6 +328,17 @@
"category": "productivity",
"homepage": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/code-simplifier"
},
{
"name": "caffeinate",
"description": "Prevents blocking sleep commands by intercepting them and prompting Claude to use background execution instead. Keeps your session responsive during long-running operations.",
"author": {
"name": "Anthropic",
"email": "support@anthropic.com"
},
"source": "./plugins/caffeinate",
"category": "productivity",
"homepage": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/caffeinate"
},
{
"name": "explanatory-output-style",
"description": "Adds educational insights about implementation choices and codebase patterns (mimics the deprecated Explanatory output style)",
@@ -546,6 +557,16 @@
"url": "https://github.com/pinecone-io/pinecone-claude-code-plugin.git"
},
"homepage": "https://github.com/pinecone-io/pinecone-claude-code-plugin"
},
{
"name": "huggingface-skills",
"description": "Build, train, evaluate, and use open source AI models, datasets, and spaces.",
"category": "development",
"source": {
"source": "url",
"url": "https://github.com/huggingface/skills.git"
},
"homepage": "https://github.com/huggingface/skills.git"
}
]
}

View File

@@ -0,0 +1,10 @@
{
"name": "caffeinate",
"version": "0.1.0",
"description": "Blocks sleep commands and reminds Claude to use background tasks instead",
"author": {
"name": "Anthropic",
"email": "support@anthropic.com"
},
"keywords": ["productivity", "hooks", "bash", "background-tasks"]
}

View File

@@ -0,0 +1,58 @@
# Caffeinate
A Claude Code plugin that blocks `sleep` commands and reminds Claude to use background tasks instead.
## Purpose
When Claude uses `sleep` commands in Bash, it blocks the session unnecessarily. This plugin intercepts these commands and suggests using proper async patterns like:
- `run_in_background: true` parameter for long-running commands
- Polling for conditions instead of sleeping
- Proper async/background task patterns
## Installation
```bash
# From the plugin directory
claude --plugin-dir /path/to/caffeinate
```
Or copy to your project's `.claude-plugin/` directory.
## What Gets Blocked
| Command | Blocked? | Reason |
|---------|----------|--------|
| `sleep 5` | Yes | Direct sleep command |
| `sleep $TIMEOUT` | Yes | Sleep with variable |
| `echo "test" && sleep 5` | Yes | Sleep after separator, outside quotes |
| `cmd; sleep 10` | Yes | Sleep after semicolon |
| `echo "sleep 8 hours"` | No | Sleep is inside quotes (not a command) |
| `echo "foo && sleep 5"` | No | Entire sleep pattern is in a string |
## How It Works
The plugin uses a `PreToolUse` hook on the `Bash` tool to:
1. Check if commands start with `sleep`
2. Detect `sleep` after command separators (`&&`, `||`, `;`, `|`)
3. Use quote-counting to avoid false positives when `sleep` appears inside strings
## Alternatives to Sleep
Instead of:
```bash
sleep 5 && check_status
```
Use background execution:
```bash
# Run in background with run_in_background: true
long_running_command
```
Or poll for conditions:
```bash
# Poll for a file to exist
while [ ! -f /tmp/ready ]; do :; done
```

View File

@@ -0,0 +1,17 @@
{
"description": "Blocks sleep commands and reminds Claude to use background tasks",
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-sleep.sh",
"timeout": 5
}
]
}
]
}
}

View File

@@ -0,0 +1,61 @@
#!/bin/bash
# Caffeinate hook: Blocks sleep commands and suggests background tasks
set -euo pipefail
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')
if [[ -z "$command" ]]; then
exit 0
fi
# Allow sleep if run_in_background is true - that's the whole point!
run_in_bg=$(echo "$input" | jq -r '.tool_input.run_in_background // false')
if [[ "$run_in_bg" == "true" ]]; then
exit 0
fi
block_message='ACTION REQUIRED: Your sleep command was blocked. You MUST now call Bash again with the SAME command but add the parameter run_in_background: true. Do this immediately in your next tool call. Do not explain or apologize - just retry with run_in_background: true.'
output_block() {
# Output JSON to stdout for blocking decision
# Output message to stderr to feed back to Claude
cat << EOF
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "$block_message"
}
}
EOF
exit 0
}
# Remove all quoted strings to avoid false positives
# Replace single and double quoted strings with placeholder
cmd_no_quotes=$(echo "$command" | sed -E "s/\"[^\"]*\"//g; s/'[^']*'//g")
# Check for sleep command patterns in the de-quoted command
# Pattern 1: Command starts with sleep
if [[ "$cmd_no_quotes" =~ (^|[[:space:]])sleep[[:space:]]+[0-9] ]]; then
output_block
fi
# Pattern 2: sleep after any common separator (&&, ||, ;, |, do, then)
if [[ "$cmd_no_quotes" =~ (\&\&|;\||[[:space:]]do[[:space:]]|[[:space:]]then[[:space:]])[[:space:]]*sleep[[:space:]] ]]; then
output_block
fi
# Pattern 3: Simple contains check - if "sleep " followed by number appears anywhere
if [[ "$cmd_no_quotes" =~ sleep[[:space:]]+[0-9] ]]; then
output_block
fi
# Pattern 4: sleep with variable like $TIMEOUT or ${DELAY}
if [[ "$cmd_no_quotes" =~ sleep[[:space:]]+\$ ]]; then
output_block
fi
# No sleep command detected - allow
exit 0