A Claude Code plugin that shows a plain-English rewrite of each assistant message, produced by a local LLM via ollama. It is display-only: Claude's own reasoning and the saved transcript keep the original text β only what you read on screen changes.
An optional second hook rewrites Markdown files into plain English when they are written or edited (opt-in, off by default).
Status: working prototype. Every hook fails
openβ if anything goes wrong (ollama down, timeout, missing dependency), you simply see Claude's original text. The plugin can never swallow or corrupt an answer.
This plugin shells out to a local model. Nothing works until these are in place:
| Requirement | Why | Install |
|---|---|---|
| ollama, running | ||
| Does the rewriting, locally | brew install ollama then ollama serve |
|
| A pulled model | The actual rewriter | ollama pull gemma4:26b-mlx (~17 GB; choose the model that fits into your memory) |
jq |
||
| Parses hook JSON | ships with macOS; else brew install jq |
|
curl |
||
| Talks to ollama | ships with macOS |
Warm the model once after ollama serve
(the first call is a slow cold load):
ollama run gemma4:26b-mlx "hi"
If the local model isn't ready, the plugin does nothing to your text β
Claude's output shows normally, unchanged. That is by design, not a bug. It skips
(fails open) when ollama is down, the request times out, or the model isn't
pulled. The first time that happens in a session it tells you why: the display
hook appends a one-line notice on screen, and the Markdown hook shows a
systemMessage
. So a silent skip is never a mystery (once per session; set
CLAUDISH_NOTICE=0
to silence it).
Pick a model you actually have. The default is gemma4:26b-mlx
. Pull it (as
above), or pull a smaller/faster model and point the plugin at it by setting
CLAUDISH_MODEL
to that model's exact ollama tag in your env
(see
Configuring the plugin). If CLAUDISH_MODEL
names a model you have not pulled, every rewrite is skipped β with the one-time notice above.
Directly from this repository (also serves its own marketplace):
/plugin marketplace add gvzdv/claudish-to-english
/plugin install claudish-to-english@gvzdv-plugins
After review by the Anthropic team, the plugin will be available to install from the community marketplace:
/plugin marketplace add anthropics/claude-plugins-community
/plugin install claudish-to-english@claude-community
If the install summary says Run /reload-plugins to activate.
, run that command.
Try before installing (loads it for one session, no install):
claude --plugin-dir /path/to/claudish-to-english
Run /reload-plugins
after edits; if it doesn't load, check the /plugin
Errors tab.
All behavior is controlled by CLAUDISH_*
environment variables (full list in Configuration below). When you install from a marketplace, set them in Claude Code's ** env block in settings.json** β do
not edit the plugin's own
hooks/hooks.json
, which lives in the read-only
plugin cache (~/.claude/plugins/cache/β¦
) and is overwritten on every update.For a personal, all-projects setup, use ~/.claude/settings.json
:
{
"env": {
"CLAUDISH_MODEL": "gemma4:26b-mlx",
"CLAUDISH_MODE": "append"
}
}
The hooks are subprocesses Claude Code spawns, so they inherit these. A few things to know:
Restart Claude Code after editing The value is captured at launch, so a running session keeps the old one.env
.The highest-precedence settings file that definesenv
does not merge across scopes.env
supplies theentireblock β it isn't combined with lower scopes. Precedence: managed β local β project β user. Keep all yourCLAUDISH_*
vars in whichever file wins.Scopes:~/.claude/settings.json
(all your projects) Β·.claude/settings.json
(shared with a repo, checked in) Β·.claude/settings.local.json
(just you, just this repo).
Quick one-off without editing a file β hooks inherit the launching shell:
CLAUDISH_MODEL=llama3.2:3b claude
To confirm the hook is firing, set CLAUDISH_DEBUG=1
and watch
"$TMPDIR"/claudish-to-english/debug.log
.
Claude Code fires the MessageDisplay
event once per streamed chunk, not
once per message. Each fire is a separate process carrying message_id
,
index
, a final
flag, and this chunk's delta
(a text fragment, not the
whole message). So the hook buffers every delta to a temp file (keyed by
message_id
) and only calls the model on the final chunk, once the whole message is known:
chunk 0 (final:false) ββ
chunk 1 (final:false) ββ€ append each delta to $TMPDIR/claudish-to-english/<session>/<message>/<index>.part
chunk 2 (final:false) ββ β emit nothing (append) or "" (replace)
chunk 3 (final:true) βββΊ reconstruct full message β call ollama once β show the rewrite
β delete the buffer
On that final chunk it also reads the original user question from the transcript and passes it to the model as context only β to keep the rewrite on-topic. The model is told never to answer or repeat the question; it only rewrites the assistant's message.
CLAUDISH_MODE |
On screen | Notes |
|---|---|---|
append (default) |
Original streams normally, then a π¬ In plain English: block is appended. |
Safest. No streaming loss; if the LLM fails you just don't get the extra block. |
replace |
Only the simplified version (original chunks suppressed while streaming). | Experimental. Appears all at once after LLM latency; on failure it re-shows the full original. |
A PostToolUse
hook (rewrite-md.sh
) rewrites Markdown files into plain English when they are written or edited. Unlike the display hook, this changes bytes on disk.
Opt-in by directory. It does nothing unless CLAUDISH_MD_DIR
is set, and it
only touches *.md
files whose resolved path is inside that directory. Every
other README
, CLAUDE.md
, or doc you edit is left alone.
CLAUDISH_MD_MODE |
Result | Notes |
|---|---|---|
sibling (default) |
Writes NAME.plain.md next to NAME.md . |
Non-destructive; the original is never touched. |
overwrite |
Replaces NAME.md in place. |
Adds a <!-- claudish-to-english:rewritten --> marker so a re-write is skipped (idempotent). A weak model can degrade real docs β use with care. |
In both modes: YAML frontmatter is split off and re-attached verbatim, fenced code is left to the model instruction, short files are skipped, and the write is atomic. Fail-open here means the file is left exactly as the agent wrote it.
Large files are slow. gemma4:26b-mlx
(the default) rewrites at roughly 60
tokens/s, so a long plan or spec can take 30β120s. This hook allows up to
CLAUDISH_MD_TIMEOUT
(150s) inside a 180s PostToolUse
hook budget; if a rewrite
still times out you get the one-time notice above β raise those limits, or set
CLAUDISH_MODEL
to a smaller model.
Enable it for one directory, in sibling mode (the safe default), the same way
as every other setting β the env
block of your settings.json
:
{
"env": {
"CLAUDISH_MD_DIR": "/ABS/PATH/docs/plain",
"CLAUDISH_MD_MODE": "sibling"
}
}
In overwrite
mode the marker comment is written after any YAML frontmatter, so the frontmatter stays on line 1 where parsers expect it.
| Var | Default | Meaning |
|---|---|---|
CLAUDISH_ENABLED |
||
1 |
||
Master switch. 0 = pass everything through. Read once at session start. |
||
CLAUDISH_OFF_FILE |
||
~/.claude/claudish-off |
||
| Runtime kill switch. While this file exists, rewrites β re-checked every message, so unlike env vars it works mid-session. See | ||
CLAUDISH_MODE
append
append
or replace
(display hook).CLAUDISH_MODEL
gemma4:26b-mlx
CLAUDISH_OLLAMA
http://localhost:11434
CLAUDISH_MIN_CHARS
200
CLAUDISH_STUB
0
1
= deterministic stub instead of the model (for testing display mechanics).CLAUDISH_TIMEOUT
45
display hook (seconds). Keep it below that hook'stimeout
(60s).CLAUDISH_MD_TIMEOUT
150
Markdown file hook (seconds). Higher on purpose β a large model rewriting a long doc is slow. Keep it below thePostToolUse
hook timeout
(180s).CLAUDISH_DEBUG
0
1
= write a debug log to $TMPDIR/claudish-to-english/
.CLAUDISH_NOTICE
1
1
= show a one-time, once-per-session notice when a rewrite is skipped because ollama is unreachable, the call timed out, or the model isn't pulled (display hook appends it on screen; Markdown hook uses a systemMessage
). 0
= stay fully silent (pure fail-open).CLAUDISH_MD_DIR
*(unset)*Markdown hook opt-in. Only*.md
under this directory is rewritten. Unset = the Markdown hook does nothing.CLAUDISH_MD_MODE
sibling
sibling
(NAME.plain.md
) or overwrite
(in place).CLAUDISH_MD_SUFFIX
plain
NAME.<suffix>.md
.In hooks/hooks.json
the display hook (MessageDisplay
) has a 60s timeout
and
the Markdown hook (PostToolUse
) has a 180s timeout
β the file hook is higher
because a large model rewriting a long document can take a couple of minutes.
CLAUDISH_TIMEOUT
and CLAUDISH_MD_TIMEOUT
keep the LLM call itself bounded below those ceilings, so it fails open cleanly instead of being killed mid-write.
Quick kill switch: set CLAUDISH_ENABLED=0
or disable the plugin (both apply
only from the next session start), or touch ~/.claude/claudish-off
to a session that's already running β see Toggling mid-session below.
CLAUDISH_ENABLED
and the other env vars are read once, when a session launches, so they can't rewrites in a session that's already running. For that, both hooks also check a flag file on every invocation β each fire is a fresh process, so the check is always live:
touch ~/.claude/claudish-off # rewrites, effective on the next message
rm ~/.claude/claudish-off # resume
You create and remove this file yourself; nothing creates it on install, and its
absence is the normal "on" state. While it exists, ENABLED
is forced to 0
and
the fail-open path leaves Claude's original text untouched. Point a hotkey at a
two-line toggle script to flip rewrites from the keyboard across all running
sessions at once. Override the path with CLAUDISH_OFF_FILE
.
The request sends "think": false
. Models with a hidden reasoning phase otherwise spend most of their time generating reasoning tokens you never see β much slower for identical output quality on this simple task. Keep it off.
The rewriter runs entirely locally against ollama, so no conversation
content leaves your machine. If you ever point CLAUDISH_OLLAMA
at a remote/hosted endpoint, that context (which can include file contents from tool results) would be sent off-box β don't do that unless you understand and accept it.
claudish-to-english/
βββ .claude-plugin/
β βββ plugin.json # plugin manifest
β βββ marketplace.json # so the repo can be added as a marketplace directly
βββ hooks/
β βββ hooks.json # MessageDisplay -> rewrite.sh ; PostToolUse -> rewrite-md.sh
βββ rewrite.sh # display-rewrite hook
βββ rewrite-md.sh # markdown-file rewrite hook (opt-in)
βββ LICENSE
βββ README.md
MIT β see LICENSE.