Pre-hook scripts for AI coding CLIs that block pleasantry-only prompts like "hi", "hello", "ok", "thank you", etc. Send a real task, not a greeting.
AI coding assistants are task tools, not chat buddies. Every "hello" wastes a model call, burns tokens, and breaks your flow. This hook intercepts the prompt before it reaches the model and rejects it with a nudge.
You type "hi" --> Hook reads prompt --> Regex fullmatch --> Blocked
You type "fix auth bug" --> Hook reads prompt --> No match --> Prompt proceeds
Each CLI has its own blocking mechanism:
| Block method | CLIs |
|---|---|
| stderr + exit code 2 | Claude, Kiro, Copilot Chat, Copilot CLI, Cursor, Factory Droid, Kimi Code, Devin |
JSON {"decision": "block"} + exit 0 |
Codex |
JSON {"decision": "deny"} + exit 0 |
Gemini |
The matcher normalizes input (lowercase, strip punctuation, collapse whitespace) and checks if the entire prompt is a pleasantry. Prompts that contain pleasantry words but include a real task pass through fine:
| Prompt | Result |
|---|---|
hi |
Blocked |
Hello!! |
Blocked |
thank you so much |
Blocked |
ok |
Blocked |
see ya later |
Blocked |
fix the login bug |
Allowed |
hello world program in python |
Allowed |
please refactor auth.py |
Allowed |
| CLI | Hook Event | Config Location | Blocking |
|---|---|---|---|
| Claude Code | UserPromptSubmit |
~/.claude/settings.json |
exit 2 |
| Codex CLI | UserPromptSubmit |
~/.codex/hooks.json |
JSON block |
| Gemini CLI | BeforeAgent |
~/.gemini/settings.json |
JSON deny |
| Cursor | beforeSubmitPrompt |
~/.cursor/hooks.json |
exit 2 |
| Copilot Chat | UserPromptSubmit |
~/.copilot/hooks/ |
exit 2 |
| Copilot CLI | userPromptSubmitted |
~/.copilot/hooks/ |
exit 2 |
| Qwen Code | UserPromptSubmit |
~/.qwen/settings.json |
exit 2 |
| Junie CLI | UserPromptSubmit |
~/.junie/config.json |
exit 2 |
| Factory Droid | UserPromptSubmit |
~/.factory/hooks.json |
exit 2 |
| Kimi Code | UserPromptSubmit |
~/.kimi-code/config.toml |
exit 2 |
| grok-cli | UserPromptSubmit |
~/.grok/user-settings.json |
exit 2 |
| Kun | UserPromptSubmit |
~/.kun/data/config.json |
exit 2 |
| Open Interpreter | UserPromptSubmit |
~/.openinterpreter/hooks.json |
exit 2 |
| Kiro | UserPromptSubmit |
.kiro/hooks/*.json (workspace) |
exit 2 |
| Devin CLI | UserPromptSubmit |
.devin/hooks.v1.json (workspace) |
exit 2 |
CodeBuddy, OpenCode (archived), Aider, Kilo Code, Trae, Trae CN (unreleased), Hermes, Pi, OpenClaw, Amp (docs private), Google Antigravity (no prompt access), Cline (SDK-only), oh-my-pi (SDK-only), Freebuff (no config), Command Code (no pre-prompt hook).
python install.pyThe installer will:
- Copy
block_pleasantries.pyto~/.pleasantries/ - Detect which AI coding CLIs are installed on your machine
- Let you select which ones to hook
- Merge the hook into each CLI's config (skips if already installed)
To remove all hooks:
python install.py --uninstallIf you prefer to configure each CLI by hand:
~/.claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command",
"command": "python3 /path/to/block_pleasantries.py claude",
"timeout": 5 }] }
]
}
}Step 1: Enable hooks in ~/.codex/config.toml:
[features]
hooks = trueStep 2: Add to ~/.codex/hooks.json:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command",
"command": "python3 /path/to/block_pleasantries.py codex",
"timeout": 5, "statusMessage": "Checking prompt" }] }
]
}
}~/.gemini/settings.json:
{
"hooks": {
"BeforeAgent": [
{ "matcher": "*", "hooks": [{ "type": "command",
"command": "python3 /path/to/block_pleasantries.py gemini",
"timeout": 5000 }] }
]
}
}.kiro/hooks/block-pleasantries.json (workspace-level):
{
"version": "v1",
"hooks": [{
"name": "block-pleasantries",
"trigger": "UserPromptSubmit",
"action": { "type": "command",
"command": "python3 /path/to/block_pleasantries.py kiro" },
"timeout": 30, "enabled": true
}]
}.cursor/hooks.json or ~/.cursor/hooks.json:
{
"version": 1,
"hooks": {
"beforeSubmitPrompt": [{
"command": "python3 /path/to/block_pleasantries.py cursor",
"timeout": 5
}]
}
}.github/hooks/pleasantries.json or ~/.copilot/hooks/:
{
"version": 1,
"hooks": {
"UserPromptSubmit": [{
"type": "command",
"command": "python3 /path/to/block_pleasantries.py copilot-chat",
"timeout": 5
}]
}
}~/.factory/hooks.json or .factory/hooks.json:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command",
"command": "python3 /path/to/block_pleasantries.py factory-droid",
"timeout": 5 }] }
]
}
}~/.kimi-code/config.toml:
[[hooks]]
event = "UserPromptSubmit"
command = "python3 /path/to/block_pleasantries.py kimi-code"
timeout = 5.devin/hooks.v1.json:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command",
"command": "python3 /path/to/block_pleasantries.py devin",
"timeout": 5 }] }
]
}
}Replace /path/to/ with the actual path to this repo. Use python instead of python3 on Windows.
- Python 3.10+
- No external dependencies (stdlib only:
json,re,sys) - Works on macOS, Linux, and Windows
block_pleasantries.py
+-- Core matcher (CLI-agnostic)
| +-- PLEASANTRY_PATTERNS - compiled regex
| +-- normalize() - lowercase, strip punctuation
| +-- is_pleasantry() - fullmatch check
|
+-- CLI adapters
| +-- _json_prompt_extract() - shared JSON stdin parser
| +-- _exit2_block() - stderr + exit code 2 (8 CLIs)
| +-- _codex_block() - JSON stdout "block" + exit 0
| +-- _gemini_block() - JSON stdout "deny" + exit 0
| +-- ADAPTERS dict - {name: {extract, block}}
|
+-- main() - dispatch via argv[1]
Adding a new CLI:
def _newcli_block(msg: str) -> None:
print(msg, file=sys.stderr)
sys.exit(2)
ADAPTERS["newcli"] = {"extract": _json_prompt_extract, "block": _newcli_block}Then: python3 block_pleasantries.py newcli
Edit the PLEASANTRY_PATTERNS regex in block_pleasantries.py. Patterns are grouped by category:
- Greetings: hi, hello, hey, howdy, good morning, ...
- Acknowledgments: ok, sure, yeah, got it, ...
- Thanks: thank you, thanks, thx, ty, ...
- Please: please, pls, plz
- Farewells: bye, goodbye, see ya, later, ...
MIT