cd /news/developer-tools/show-hn-pleasantries · home topics developer-tools article
[ARTICLE · art-86827] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Show HN: Pleasantries

A developer released Pleasantries, an open-source pre-hook script that blocks pleasantry-only prompts like "hi" and "thank you" before they reach AI coding CLIs, saving tokens and preventing wasted model calls. The tool supports 15 CLIs including Claude Code, Codex CLI, Gemini CLI, Cursor, and Copilot Chat, with per-CLI blocking mechanisms such as exit code 2 or JSON deny responses. It normalizes input to catch greetings while allowing prompts that contain real tasks, and can be installed via a Python script that auto-detects installed CLIs.

read5 min views1 publishedAug 4, 2026
Show HN: Pleasantries
Image: source

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.py

The installer will:

  • Copy block_pleasantries.py

to~/.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 --uninstall

If 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 = true

Step 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

── more in #developer-tools 4 stories · sorted by recency
── more on @pleasantries 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-pleasantries] indexed:0 read:5min 2026-08-04 ·