/jrpolish <rough prompt>: a small fast model rewrites it into a clear, structured prompt in the same language and puts it in your prompt box to edit and send.

Turn a rough, dictated or rushed request into a clear prompt before you send it.
/jrpolish euh so fix the login thing in auth ts it breaks when the token expires and dont touch the api
jr polish · put in the prompt box, edit it and press Enter
before:
euh so fix the login thing in auth ts it breaks when the token expires and dont touch the api
after:
Fix the login bug in auth.ts that breaks when the token expires.
- Keep the API unchanged.
| Command | |
|---|---|
/jrpolish <rough prompt> | Rewrite it and put it in the prompt box |
/config)| Option | Default | |
|---|---|---|
| Model | haiku | Any alias (haiku, sonnet) or full model id |
One small-model call per /jrpolish, roughly the length of your prompt in and out.
/plugin install jr-polish --marketplace jrlprost/claude-code-mods
Sends the text you pass to /jrpolish to the model through your own Claude Code session, and fills the prompt box. Reads no files, runs nothing.
hooks/register.ts 44 lines1import type { EngineInterface, Register } from 'claude-code'
2
3import { beforeAfter, cleanReply, SYSTEM } from './polish'
4
5const commands = { isRegistered: false }
6
7async function ensureCommand($: EngineInterface) {
8 if (commands.isRegistered) return
9 commands.isRegistered = true
10 await $.command.register({ name: 'jrpolish', description: 'Rewrite a rough prompt into a clear one and put it in the prompt box: /jrpolish <rough prompt>' })
11}
12
13async function polish($: EngineInterface, rough: string, model: string) {
14 if (!rough.trim()) return 'jr polish · usage: /jrpolish <your rough prompt>'
15 const reply = await $.model.complete({ model, system: SYSTEM, prompt: rough, maxTokens: 1200 })
16 if (!reply.isAnswered) return `jr polish · no rewrite (${reply.reason}); your prompt is unchanged`
17 const polished = cleanReply(reply.text)
18 const filled = await $.prompt.fill({ text: polished, mode: 'replace' })
19 if (!filled.isFilled) return `jr polish · rewritten, but the prompt box was not available. Copy it from here:\n\n${polished}`
20 return beforeAfter(rough, polished)
21}
22
23export const register: Register = (on, options) => {
24 const model = String(options.model ?? 'haiku')
25
26 on('session.start', async ($, e, next) => {
27 const started = await next(e)
28 await ensureCommand($)
29 return started
30 })
31
32 // Installed mid-session: no session.start, so register on the first draw above the prompt.
33 on('ui.render', { component: 'AbovePrompt' }, ($, e, next) => {
34 if (!commands.isRegistered) {
35 $.clock.after(0, () => {
36 void ensureCommand($)
37 })
38 }
39 return next(e)
40 })
41
42 on('command.run', { command: 'jrpolish' }, async ($, e) => ({ text: await polish($, e.args, model) }))
43}
44hooks/polish.ts 21 lines1export const SYSTEM = `You rewrite a rough, often dictated, request to a coding assistant into a clear prompt.
2
3Rules:
4- Keep the language of the request (French stays French, English stays English).
5- Keep every fact, file name, constraint and intent; add none, invent none.
6- Fix transcription noise, filler words and run-on sentences.
7- Structure: one line for the goal, then short bullet points for details or constraints when there is more than one. No headings, no preamble.
8- Reply with the rewritten prompt only.`
9
10/** The rewritten prompt, trimmed of quotes or fences a model sometimes wraps it in. */
11export const cleanReply = (text: string) =>
12 text
13 .trim()
14 .replace(/^```[a-z]*\n?|\n?```$/g, '')
15 .replace(/^"([\s\S]*)"$/, '$1')
16 .trim()
17
18/** The command's output row: before, then after. */
19export const beforeAfter = (rough: string, polished: string) =>
20 `jr polish · put in the prompt box, edit it and press Enter\n\nbefore:\n${rough}\n\nafter:\n${polished}`
21