Prompt pre-flight: rewrite rough prompts into clearer ones with Claude Haiku before they reach a stronger model.
Project description
prompt-preflight
Type a rough prompt; your strong model sees a clear one.
prompt-preflight runs a fast pre-flight pass with Claude Haiku that sharpens your vague input into a clear, well-structured prompt — without inventing requirements — before it reaches a stronger model. You write the way you always do; Opus/Sonnet spends its budget on a good prompt instead of a messy one.
you type: "make my api faster"
│
┌───────▼────────┐
│ prompt-preflight│ ~1s, a fraction of a cent (Haiku)
└───────┬────────┘
│
model sees: "Profile and optimize my REST API for latency. Identify the slowest
endpoints, reduce N+1 queries, add caching where safe, and measure
before/after. Keep the existing public routes unchanged."
If anything goes wrong, it fails open to your original text — the worst case is a one-second delay, never a blocked or mangled prompt.
Unofficial, community tool. Not affiliated with or endorsed by Anthropic; "Claude" and "Claude Code" are trademarks of Anthropic. It reuses your own Claude auth and adds no telemetry — see Privacy.
📖 Full docs: https://anothersamwithadream.github.io/prompt-preflight/
Contents
- Quick start
- Which path is right for you?
- Backends
- 1.
enhance— interactive Claude Code (true replacement) - 2. The hook — zero-setup fallback
- 3.
enhance-cli— any desktop / web app - Configuration
- Command cheat-sheet
- Troubleshooting & FAQ
- Privacy & data handling
- Safety
- How it works against Claude Code
- Develop & test
Quick start
Requirements: Python 3.9+. For the default zero-config path, a working claude CLI
(claude --version; Claude Code ≥ 2.1). No API key needed — it reuses your Claude login.
pip install prompt-preflight # or: pipx install prompt-preflight (isolated)
Try it in one line — rewrite a prompt and copy the result to your clipboard:
enhance-cli "make my code faster and add tests"
Or, for interactive Claude Code, enhance your prompt and open a session with it:
enhance "make my code faster and add tests"
Not sure it's wired up correctly? Run the self-check:
enhance-cli doctor
Other install options (uvx, pipx run, from source, the api extra)
# one-shot, no install:
uvx prompt-preflight --help # via uv
pipx run prompt-preflight --help # via pipx
# from a clone, for development:
pip install -e . # commands: enhance, enhance-cli, enhance-hook
pip install -e ".[api]" # also installs the Anthropic SDK for the api backend
Which path is right for you?
There are three ways to use prompt-preflight. Pick by where you type your prompts:
| If you… | Use | What the strong model sees | Setup |
|---|---|---|---|
| use interactive Claude Code | enhance (proxy) |
only the enhanced prompt ✅ | enhance "your prompt" |
| want zero setup inside Claude Code | hook (enhance-hook) |
your original + a clarified restatement | one settings.json line |
| use the desktop/web app (or any tool) | enhance-cli |
only what you paste | run it, paste the result |
Most people want enhance. It's the only path that achieves true replacement in an
interactive session (the proxy rewrites the actual API request). The hook is the
no-install fallback; enhance-cli is for everything outside Claude Code.
Why can't the hook just replace the prompt? Claude Code's
UserPromptSubmithook can only append context or block — it has no "replace my prompt" output (see How it works). The proxy is what makes true replacement possible.
Backends
One engine, several interchangeable backends. Set backend in config (or
PROMPT_ENHANCER_BACKEND). The default, auto, is right for most people.
| Backend | How it works | Needs | Good for |
|---|---|---|---|
auto (default) |
API key → api; else claude CLI → cli; else heuristic |
nothing | just works |
cli |
claude -p with Haiku, prompt on stdin |
Claude Code CLI | no API key — reuses your login |
api |
Anthropic SDK, system-prompt caching | prompt-preflight[api] + key |
speed; servers |
openai |
OpenAI-compatible chat completions | openai SDK + key |
non-Anthropic models |
ollama |
local Ollama chat endpoint | a running Ollama | fully offline, free |
heuristic |
rule-based cleanup, no model | nothing | air-gapped; last resort |
- Offline / private:
ollama(a real local model) orheuristic(no model at all — it only tidies whitespace, casing, and punctuation, so it can never change your meaning). - Enterprise: set
api_providertobedrockorvertexto use AWS/GCP credentials instead of anANTHROPIC_API_KEY. - Plugins: register your own backend via the
prompt_preflight.backendsentry-point group — no need to fork. A misbehaving plugin fails open. (See the Backends docs.)
Profiles tune the rewrite for a task. Pass --profile or set profile in config:
enhance-cli --profile coding "speed up the parser" # preserves code/paths/identifiers
enhance-cli --profile concise "..." # shortest faithful rewrite
Choices: default, concise, detailed, coding, research.
1. enhance — interactive Claude Code (true replacement)
enhance "make my code faster and add tests" # enhance this prompt, then open claude with it
enhance # no prompt: open claude, enhance as you type
enhance "fix the login bug" --model opus # leading words = prompt; trailing flags go to claude
enhance "fix the bug" -- --model opus --add-dir ./src # everything after `--` -> claude, verbatim
enhance --serve-only # run just the proxy (point your own claude at it)
Passing claude parameters. Anything that isn't the prompt is forwarded to claude. Put
flags after the prompt, or — to be unambiguous (e.g. for flags that might collide with
enhance's own options) — put them after a -- separator, which passes everything after it
to claude verbatim. The launcher prints exactly what it forwards. For persistent
defaults, set claude_args (or PROMPT_ENHANCER_CLAUDE_ARGS="--model,opus"); CLI flags are
appended after them, so they win:
enhance-cli config set claude_args "--model,opus" # always launch claude with --model opus
enhance "review this module" -- --permission-mode plan # plus per-run flags
(config set/the env var take a comma-separated list; for args containing commas, edit the
config file directly: "claude_args": ["--model", "opus"].)
enhance "..." rewrites your prompt with Haiku and starts an interactive claude
whose first message is the enhanced prompt. A local proxy runs alongside it, so the
follow-up prompts you type in the session are enhanced too (your already-enhanced first
prompt is skipped, so it's never enhanced twice). When claude exits, the proxy stops; if
the configured port is busy, a free one is chosen automatically.
The proxy is conservative — a single Claude Code turn makes several API calls, and it rewrites only your main prompt:
- Skips background/title calls (Haiku, in
proxy_skip_models) and utility turns without a tool list (proxy_require_tools). - Rewrites the one human text block, leaving
<system-reminder>context untouched; tool-loop turns (tool_result) are left alone. - Honors
//raw, the word threshold, and slash commands; fails open on any error (the request is forwarded unchanged). Responses relay raw, so streaming is preserved.
The proxy and hook never double-enhance: the hook auto-disables whenever
ANTHROPIC_BASE_URL points at the proxy.
Cost & latency: enhancement runs before the strong model starts, adding the rewrite time to your first token (~5 s with
cli, ~1–3 s withapi). SetPROMPT_ENHANCER_PROXY_DEBUG=1to log per-request structural decisions (never prompt text).
2. The hook — zero-setup fallback
The fastest way to install the hook:
enhance-cli init # adds enhance-hook to ~/.claude/settings.json (with a backup)
Or merge this into ~/.claude/settings.json (global) or a project's .claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [ { "type": "command", "command": "enhance-hook", "timeout": 20 } ] }
]
}
}
It injects the rewrite as additionalContext — a labelled "Clarified restatement"
that the model follows while honouring your original on any conflict. It skips slash
commands, short prompts (< word_threshold words), and //raw, and fails open (emits
nothing → your prompt proceeds unchanged). Prefer a terser one-line framing? Set
hook_output_style to minimal.
No
pip install? Use"command": "python \"<abs path>/prompt_enhancer/hook.py\"".
3. enhance-cli — any desktop / web app
enhance-cli "make my code faster and add some tests" # or pipe text via stdin
It rewrites your prompt, prints a short "Changes made" summary, and asks [A]ccept /
[E]dit / [R]eject before copying the result to your clipboard (pbcopy / clip /
wl-copy / xclip / xsel). Edit opens $EDITOR on a temp file (deleted immediately
after); Reject copies your original instead.
Handy flags:
| Flag | Effect |
|---|---|
-y, --yes |
accept without prompting |
-f, --file FILE |
read the prompt from a file |
--profile NAME |
use a rewrite profile (see Backends) |
--diff |
also show a unified diff of the changes |
--json |
print a structured result (for scripting) and exit |
--explain |
print why it did or didn't enhance (backend, error, timing) |
--repl |
interactive loop: type a prompt, get the rewrite, repeat |
--watch |
rewrite whatever you copy to the clipboard, in place |
--no-clipboard |
don't touch the clipboard; just print to stdout |
//raw … |
bypass enhancement and copy your text verbatim (token stripped) |
When a rewrite raises "Open questions", the CLI offers to let you answer them and folds your answers back into the prompt in one pass.
Configuration
Everything is configurable via one JSON file plus PROMPT_ENHANCER_* env overrides.
You rarely need to touch it — auto is sensible out of the box.
enhance-cli config show # effective config + where it's loaded from + active env overrides
enhance-cli config path # the config file path
enhance-cli config init # write a default config you can edit
enhance-cli config edit # open it in $EDITOR
enhance-cli config set backend api # set one key without hand-editing JSON
enhance-cli config unset backend # remove one key
enhance-cli config reset # delete the config file
Lookup order: $PROMPT_ENHANCER_CONFIG → ./.prompt-enhancer.json →
%APPDATA%\prompt-enhancer\config.json (Windows) / ~/.config/prompt-enhancer/config.json.
The file is plain JSON (no comments). Common fields, with defaults:
{
"backend": "auto",
"profile": "default",
"timeout": 15.0,
"word_threshold": 12,
"bypass_prefix": "//raw",
"api_model": "claude-haiku-4-5",
"api_key_env": "ANTHROPIC_API_KEY",
"proxy_port": 8788,
"proxy_skip_models": ["haiku"],
"proxy_require_tools": true
}
| Field | Meaning |
|---|---|
backend |
auto | cli | api | openai | ollama | heuristic (or a plugin name) |
profile |
rewrite style: default | concise | detailed | coding | research |
timeout |
seconds before fail-open |
word_threshold |
prompts shorter than this pass through unchanged |
bypass_prefix |
the skip token (default //raw) |
proxy_skip_models |
request models that are never enhanced (Claude Code's background calls) |
proxy_require_tools |
only enhance the main agentic turn (which carries tools) |
api_provider |
anthropic | bedrock | vertex |
hook_output_style |
context (labelled block) | minimal (one line) |
Every field has a PROMPT_ENHANCER_<FIELD> env override (e.g.
PROMPT_ENHANCER_BACKEND=api, PROMPT_ENHANCER_PROFILE=coding,
PROMPT_ENHANCER_PROXY_PORT=9000). Run enhance-cli config show to see which are active.
The full field list is in the docs.
Command cheat-sheet
# Interactive Claude Code (proxy + launcher)
enhance "prompt" enhance the prompt, then open claude with it
enhance open claude; the proxy enhances what you type
enhance -m "prompt" --quiet enhance a prompt without echoing the rewrite
enhance --serve-only run only the proxy
enhance "fix bug" --model opus pass flags through to claude (prompt = leading words)
enhance "fix bug" -- ARGS... pass everything after -- to claude verbatim
# Rewrite to clipboard / scripting
enhance-cli "prompt" rewrite → Accept/Edit/Reject → clipboard
enhance-cli -y --diff "..." auto-accept and show a diff
enhance-cli --json "..." structured output for scripts
enhance-cli --repl interactive rewrite loop
enhance-cli --watch rewrite clipboard text as you copy it
enhance-cli //raw "..." bypass enhancement (copy verbatim)
# Setup, diagnostics, ops
enhance-cli init install the hook into ~/.claude/settings.json
enhance-cli doctor verify binary, flags, auth, and backend
enhance-cli config show view effective config
enhance-cli stats pretty-print a running proxy's /stats
Troubleshooting & FAQ
"It doesn't seem to do anything."
Run enhance-cli doctor — it checks the claude binary, flags, auth, and runs one live
enhancement. A silent fail-open (e.g. missing binary) looks like a no-op; --explain on
enhance-cli prints the exact reason.
"My prompt got enhanced twice."
It shouldn't — the hook auto-disables when the proxy is active. If you see it, you likely
have both the hook installed and ANTHROPIC_BASE_URL set to something non-loopback.
Use one path at a time.
"It's slow."
The cli backend adds ~5 s (it launches claude). The api backend is ~1–3 s — set
PROMPT_ENHANCER_BACKEND=api with an ANTHROPIC_API_KEY. You can also try cli_bare
(--bare) to skip hook/skill/MCP discovery — it's off by default because on some Claude
Code versions it bypasses the interactive login; if you enable it and a call fails, the
engine automatically retries without it.
"I want to skip enhancement for one prompt."
Prefix it with //raw (or use a /slash-command, which is always skipped).
"Turn it off entirely."
Set PROMPT_ENHANCER_DISABLE=1 — honored by the engine, hook, proxy, and launcher.
"The proxy port is busy."
enhance picks a free port automatically. For --serve-only, set proxy_port or
PROMPT_ENHANCER_PROXY_PORT.
"I'm on Windows and claude isn't found."
When Claude Code is installed via npm, claude is a .cmd/.ps1 shim that Python can't
launch directly (and routing through cmd.exe would re-parse your prompt — an injection
risk). The engine auto-resolves it to the bundled
…\node_modules\@anthropic-ai\claude-code\bin\claude.exe. Override with
PROMPT_ENHANCER_CLAUDE_BIN if needed.
"Does it work with my Claude subscription (no API key)?"
Yes. The cli backend reuses your Claude Code login. The proxy also works under claude.ai
auth — Claude Code forwards its Authorization header to the local proxy, which relays it
upstream unchanged.
Privacy & data handling
What leaves your machine: only your prompt, sent to be rewritten — through your own
claude CLI auth (cli), your ANTHROPIC_API_KEY (api), your chosen provider
(openai), your local Ollama (ollama), or nothing at all (heuristic) — and
then your enhanced prompt to your model. Nothing else. No telemetry.
- Nothing on disk by default. Diagnostics are opt-in and local-only:
PROMPT_ENHANCER_LOG=<path>logs metadata only (timings, sizes, fail-open reasons); addPROMPT_ENHANCER_LOG_CONTENT=1to also record prompt text. Proxy debug (PROMPT_ENHANCER_PROXY_DEBUG=1) and--log-levellog only request structure, never prompt text. - Credentials never reach the enhancer. Before rewriting, prompts are scanned for
secrets (API keys,
Bearer …, AWS keys); if one is found the prompt is not sent to the enhancer — your original still proceeds to the strong model. - Prompt never on the command line. The
clibackend sends the prompt on stdin, so it isn't visible inps//proc, and parses a JSON envelope rather than scraping stdout. - The tool never handles your credentials.
claudemanages its own auth; the proxy passes yourAuthorizationheader upstream unchanged and never logs it.
See SECURITY.md for the threat model and how to report issues.
Safety
- Fail open (~15 s, configurable): timeout, non-zero exit, missing binary/key, bad/empty output, dropped specifics, implausible length, a crashing plugin, a tripped circuit breaker → your original text, unchanged.
- Faithful or nothing. A programmatic check verifies your hard tokens (file paths, URLs, code spans, numbers) survive the rewrite; if any are dropped, it fails open.
- No shell / no injection.
clauderuns via an argv list (and on Windows the resolved.exe, never the.cmdshim); the prompt goes on stdin or in a JSON body, never on a command line. - Recursion-safe. The engine sets
PROMPT_ENHANCER_ACTIVE=1for its child; the hook bails the moment it sees that (or any loopbackANTHROPIC_BASE_URL). - Proxy bind-safety. The proxy binds to
127.0.0.1and refuses a non-loopback host unless you setallow_public_bind/PROMPT_ENHANCER_ALLOW_PUBLIC_BIND=1. It caps request body size and concurrent enhancements.
Cost note (changes 2026-06-15): every enhancement is a
claude -p/ API call. From June 15 2026,claude -pand Agent SDK usage on subscription plans draws from a new monthly Agent SDK credit pool, separate from interactive limits. Budget accordingly, or use theapibackend with your own key.
How it works against Claude Code
The technical details that make true replacement possible (verified against Claude Code 2.1.x):
- The
UserPromptSubmithook cannot replace the prompt. Its only outputs aredecision:"block",reason,hookSpecificOutput.additionalContext(append),sessionTitle,suppressOriginalPrompt— noupdatedPrompt(hooks ref, feature requests #53330, #46761). So the hook appends a labelled restatement; the proxy does true replacement. claude -pflags:--model haiku✓,--system-prompt(replace — not--append-system-prompt, which makes Haiku answer instead of rewrite) ✓,--max-turns 1✓,--tools ""to disable all tools ✓.- The proxy works with subscription auth. Under
claude.aiauth, Claude Code forwards itsAuthorizationheader to a localANTHROPIC_BASE_URLproxy, which relays it upstream unchanged — so the strong model receives only the rewritten prompt.
Other published tools (prompt-improver, prompt-enhancer, prompt-optimizer) all use the append-only hook — none achieve true replacement.
The enhancer system prompt lives in
prompt_enhancer/system_prompt.py: rewrite (don't
answer), faithfulness first, improve clarity/structure, return already-clear prompts
~unchanged, and append a short "Open questions" list only when genuinely ambiguous.
Develop & test
pip install -e ".[dev]"
pytest # fast, deterministic; never calls claude (mocked)
ruff check . && mypy prompt_enhancer
Opt-in live tests (real model):
set PROMPT_ENHANCER_LIVE_TESTS=1 # Windows; export ... on POSIX
pytest -m live
CI runs ruff, mypy, and the suite (with a coverage gate) across
ubuntu/macOS/windows × Python 3.9–3.13. Deploying the proxy as a shared service? See the
Deploy docs and the
templates in deploy/.
Project layout
prompt_enhancer/
engine.py # backend dispatch, safety pipeline, fail-open, caching, breaker
safety.py # secret/PII detection, token & length guards, output cleanup
config.py # JSON config + PROMPT_ENHANCER_* overrides + validation
system_prompt.py # the enhancer prompt + per-profile variants
policy.py # classify a prompt: enhance / passthrough / raw
proxy.py # local replacing proxy (ANTHROPIC_BASE_URL); stats/metrics/tracing
hook.py # UserPromptSubmit hook (append)
launcher.py # `enhance` — rewrite first prompt, start proxy, launch claude
cli.py # `enhance-cli` — rewrite to clipboard, REPL, watch, config/doctor/init/stats
tests/ docs/ packaging/ deploy/ examples/settings.json
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file prompt_preflight-0.2.1.tar.gz.
File metadata
- Download URL: prompt_preflight-0.2.1.tar.gz
- Upload date:
- Size: 86.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a057458cf5f3a6a426d853a26e2f6630d904f15591abb9b7897c605bf2b71679
|
|
| MD5 |
6a15f55343a8d17e782b39cd1ad44b5f
|
|
| BLAKE2b-256 |
452dcf5772f1e084e15d451228008811b5a1e3091a1924e258dd91f0c803cb58
|
Provenance
The following attestation bundles were made for prompt_preflight-0.2.1.tar.gz:
Publisher:
publish.yml on AnotherSamWithADream/prompt-preflight
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prompt_preflight-0.2.1.tar.gz -
Subject digest:
a057458cf5f3a6a426d853a26e2f6630d904f15591abb9b7897c605bf2b71679 - Sigstore transparency entry: 1710885429
- Sigstore integration time:
-
Permalink:
AnotherSamWithADream/prompt-preflight@d0735f7db5186936e807a110c1280c78aaa06030 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/AnotherSamWithADream
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d0735f7db5186936e807a110c1280c78aaa06030 -
Trigger Event:
release
-
Statement type:
File details
Details for the file prompt_preflight-0.2.1-py3-none-any.whl.
File metadata
- Download URL: prompt_preflight-0.2.1-py3-none-any.whl
- Upload date:
- Size: 55.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
489d07b4eb6ea927be4fa3f787a06b48b1cdd07a80649e94cdb3e01d6b35cb2d
|
|
| MD5 |
528982401bd5b0fa1e0c47e7f68f26fc
|
|
| BLAKE2b-256 |
4bed06d3eb4da5d26638c84d777962dca81cc3ecdf6d95a9dc46ad7b4dd1c11c
|
Provenance
The following attestation bundles were made for prompt_preflight-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on AnotherSamWithADream/prompt-preflight
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prompt_preflight-0.2.1-py3-none-any.whl -
Subject digest:
489d07b4eb6ea927be4fa3f787a06b48b1cdd07a80649e94cdb3e01d6b35cb2d - Sigstore transparency entry: 1710885439
- Sigstore integration time:
-
Permalink:
AnotherSamWithADream/prompt-preflight@d0735f7db5186936e807a110c1280c78aaa06030 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/AnotherSamWithADream
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d0735f7db5186936e807a110c1280c78aaa06030 -
Trigger Event:
release
-
Statement type: