Skip to content

claudish-to-english

A Claude Code plugin that shows a plain rewrite of every assistant message underneath the original — produced by a local ollama model by default, or by the codex CLI, the Anthropic API or any OpenAI-compatible endpoint, with a /claudish command that switches it on and off and changes the display mode, the style, the output language and the model mid-session. It is display-only: the transcript and Claude’s own reasoning always keep the original text.

Screenshot of claudish-to-english
Editor screenshot, 1 Oct 2026claudish-to-english ↗

What it is

A Claude Code plugin that shows a plain-language rewrite of every assistant message directly under the original. The rewriter is a model you choose with one environment variable: a local ollama model by default, or the codex CLI, the Anthropic API or any OpenAI-compatible endpoint. It is display-only — the saved transcript and what Claude itself sees keep the original text, only what is rendered on screen changes — so the hook cannot alter or swallow an answer, and a failure of any kind leaves the original on screen. An optional second hook rewrites Markdown files as an agent writes them, either in place or to a NAME.plain.md sibling. The /claudish command switches rewrites on and off and changes the display mode, the style preset, the output language and the model mid-session, and a dashboard prints each setting with the place its value came from, flagging every override that will outlive the session.

Who built itThirty-seven commits and nine contributors, but this is one person’s project: 21 commits carry his own GitHub account and six more are his name from two different Macs. He signs his review comments “Human Mike”, and 24 of the 37 commits carry a co-author trailer — 21 of those name a Claude model, with Opus 5 on a one-million-token context appearing eleven times. The rest of the history is other people’s: the provider layer, an oauth login path, a caveman style preset and a slash command all arrived as pull requests.

How it is put together

The parts · 6

A Claude Code plugin with no build step, no test suite and no dependencies beyond bash, jq and curl. Every hook is a short-lived process that reads JSON on stdin and writes JSON on stdout, and the whole thing is organised around the assumption that it will fail. Three hooks are wired in a 719-byte hooks.json — a SessionStart notice, the MessageDisplay rewrite with a 60-second ceiling, and the opt-in PostToolUse Markdown rewrite with 180 seconds — and each one emits nothing and exits 0 on any problem, leaving the original text in place. Both rewrite hooks source the same two libraries, so the provider choice and the language resolver behave identically for the screen and for files on disk. Configuration precedence is the same everywhere: a flag file under ~/.claude/ beats an environment variable, which beats the language key in the project’s settings, which beats the built-in default. The flag files exist because environment variables are captured when the session launches and cannot be changed in a running one; the slash command writes them and the hooks re-read them on every message.

rewrite.sh
The MessageDisplay hook and the largest script in the repository at 22,877 bytes: it buffers each streamed delta to a temp file, reconstructs the message on the final chunk, chooses the prompt and the on-screen label, applies the prose-length gate, and prints the rewrite or nothing.
providers.sh
The 23,678-byte provider layer that both hooks source: one request shape each for ollama, the codex CLI, the Anthropic Messages API and OpenAI chat completions, with per-provider key lookup, base URL and timeout, and the rule that a rewrite cut off by a token cap is thrown away rather than displayed.
rewrite-md.sh
The 14,205-byte optional PostToolUse hook that rewrites Markdown files. It does nothing at all unless a directory is named, splits YAML frontmatter off and re-attaches it verbatim, writes atomically, and defaults to a NAME.plain.md sibling instead of editing the file it was given.
claudish-ctl.sh, commands/claudish.md, session-notice.sh
At 13,800, 1,751 and 3,367 bytes: the script that writes the flag files and prints the dashboard with each value’s provenance, the slash-command definition that hands it the user’s arguments through a quoted here-doc, and the SessionStart hook that announces overrides left active by an earlier session.
lang.sh
The 4,771-byte language resolver plus the sanitiser every untrusted configuration value passes through: it reads CLAUDISH_LANG, then the Claude Code language key from four settings files in precedence order, and folds control characters and caps the value at three words or thirty codepoints before it can reach a prompt or the screen.
README, CHANGELOG, CONTRIBUTING, CLAUDE.md and the manifests
Documentation weighing more than the code: README at 34,435 bytes, CHANGELOG at 15,261, CONTRIBUTING at 9,530, CLAUDE.md at 5,501, the pull-request template at 2,418 and the release skill at 5,638, alongside an 825-byte plugin manifest and a 530-byte marketplace manifest. Eighteen files in all.

Choices, and what they beat

  • Display-only, with the transcript left alone over rewriting what Claude itself sees

    The README states it as the plugin’s defining property: only what is rendered on screen changes, while Claude’s own reasoning and the saved transcript keep the original text. The contributor guide repeats it as a ground rule — nothing added should change what Claude actually said. It is also what makes /claudish last possible: the command reprints an original that was never overwritten, behind a marker that tells the hook to pass that reply through.

  • Fail open, always over showing an error on screen

    The rule is stated first in CLAUDE.md and marked as outranking every other consideration: on any problem a hook emits nothing and exits 0, so the worst case is that the reader sees exactly what Claude wrote. The contributor guide says a display hook that can swallow or corrupt an answer is worse than no plugin at all, and the failure this guard is aimed at — a half-finished rewrite on screen, or written over a real document in overwrite mode — is why token-capped rewrites are discarded.

  • Call the model once, on the final chunk over rewriting every streamed chunk as it arrives

    The hook is fired once per chunk carrying only a fragment of the message, so rewriting on arrival would mean rewriting a sentence at a time. Instead every delta is buffered to a temp file and the model is called once, when the chunk flagged final holds the whole message — which is also the point at which the original user question can be read from the transcript and passed in as context.

  • Local ollama by default, cloud only by explicit choice over a hosted model that works without setup

    The default is inherited unchanged: a local model, nothing leaving the machine. The README treats selecting a cloud provider as the consent switch itself, warning that an ambient OPENAI_API_KEY in the environment is enough for a single variable to start sending every assistant message to OpenAI, and the provider pull request was reviewed against the guarantee that the default path stays byte-identical to what it replaced.

  • An emoji and a bold word, not colour over the coloured separator labels a contributor had already tested

    The coloured version rendered correctly in a live session and was replaced anyway, with three reasons given: the 16-colour codes are palette indices a terminal theme may remap onto grey or onto the background, the escapes leak as literal bytes into claude -p output piped to a file, and the hook has no terminal on any descriptor, so it can detect neither case and degrade.

  • The voice-framing line applies even to a custom prompt over placing it with the other preference lines, before the prompt-file override

    The output-language line sits before the prompt-file override so that a custom prompt can replace it. The line added in 0.9.0 — that “I” is the assistant and “you” is the user — is appended after the override instead, because it is a fact about the input rather than a preference, and one insertion point also avoids the failure mode in which a new preset touches four files and misses one.

Read fromREADME.md (34,139 characters), CHANGELOG.md (15,195 characters), CONTRIBUTING.md (9,494 characters), CLAUDE.md, and the complete eighteen-file tree with sizes.

Build log

5 stages
  1. 01

    Eighteen days, twelve versions, and 2,707 stars

    The repository was created on 2026-08-10T18:32:23Z and its first commit landed twelve minutes later, titled “Initial release of claudish-to-english v0.1.0”. Everything the README describes was built in the eighteen days that followed: 37 commits, all of them in August 2026, the last on 2026-08-28. The changelog records twelve versions — 0.1.0 and 0.1.1 on the first day, 0.2.0 and 0.3.0 on 2026-08-13, 0.4.0 on 2026-08-14, 0.5.0 on 2026-08-19, 0.5.1 and 0.6.0 on 2026-08-20, 0.7.0 on 2026-08-26, 0.7.1 and 0.8.0 on 2026-08-27, and 0.9.0 on 2026-08-28 — while tags number thirteen, those twelve plus one called assets, and the GitHub releases list holds only three entries: v0.9.0, v0.8.0 and the assets release carrying the README comparison image. It finished the month with 2,707 stars, 129 forks, ten open issues and thirty issues and pull requests in total. Nine people have contributed, and 24 of the 37 commits carry a co-author trailer, 21 of them naming a Claude model — Opus 5 on a one-million-token context eleven times, Opus 4.8 nine times across two context sizes, and Fable 5 once.

  2. 02

    The hook fires once per streamed chunk, not once per message

    The central fact about the display hook is that Claude Code fires MessageDisplay once per streamed chunk, not once per message, and each firing is a separate process carrying only that chunk’s delta. So the plugin appends every fragment to a temp file keyed by session and message id, emits nothing, and calls the model exactly once — on the chunk flagged final, when the whole message is known. That call also reads the original user question out of the transcript and passes it in as context only, with an instruction never to answer or repeat it. Two display modes follow: append, the default, streams the original and adds the rewrite underneath, and replace, marked experimental, suppresses the chunks and shows only the rewrite after the model answers. Being display-only is what makes the design safe, and the repository keeps a long argument about it: issue 12 opened with a report that the hook fired, emitted schema-correct output and rendered nothing; the reporter narrowed that to an interactive-terminal bug, then retracted it entirely — the cause was "verbose": true in his own settings file, because verbose mode deliberately shows the original text and bypasses the replacement.

  3. 03

    Four providers, and a default that never leaves the machine

    The first thing users asked for was not to need ollama: issue 9 is three lines — “Would love to try this if it didn’t need Ollama” — plus a reply asking for a model-agnostic version. nircoh-onyx answered with a pull request that lifted the model call out of both hooks into a shared providers.sh, keeping ollama the default and putting any OpenAI-compatible endpoint and the Anthropic Messages API behind CLAUDISH_PROVIDER. The maintainer’s review added two things the contributor had not: a rewrite cut off by an output-token cap is discarded rather than shown, because in the Markdown hook’s overwrite mode it would replace a real document with half a rewrite; and the HTTP status is captured, so a failure can be explained. A codex CLI provider followed, contributed by datvo06 and bounded by a poll-and-kill loop because stock macOS ships no timeout(1). Then JackBhanded’s oauth mode, which rides the Claude Code login instead of an API key: a tester found the token in the macOS login Keychain rather than the credentials file and contributed that read with an end-to-end http=[200] proof, after which the maintainer made the mode refuse to run when the base URL is overridden, so a subscription token cannot reach a proxy. The README still prints the warning it earned: unofficial, use at your own risk, repeated on screen at the first rewrite of each session.

  4. 04

    A slash command that arrived twice, and a pronoun bug that arrived once

    MakhBeth had built a /claudish command in a fork called claudish-tldr; the maintainer was building the same thing, replied “I was already working on the integration of your slash command into the plugin”, merged his own version as a separate pull request, credited him under the wrong handle, apologised, and ported the one piece he had missed. The command interpolated $ARGUMENTS unquoted into the shell line, and the 0.5.1 fix replaced the quoting with a quoted here-doc on stdin, because Claude Code substitutes the argument textually before the shell parses the line, so quotes inside the command could not neutralise $(…), backticks or a bare *. A second outsider contribution became the caveman style preset, and arrived with coloured labels the maintainer tested live, found working, and replaced anyway: the 16-colour codes are palette indices a terminal theme may remap onto grey, and the escapes leak as literal bytes into claude -p output piped to a file. The labels became an emoji and a bold word. The last community round is the sharpest: issue 24 shows two rewrites with the roles inverted, “Found the root cause.” coming back as “You’ve found the root cause.” The maintainer asked which model was in use; the reporter answered with the prompt paragraph he had written himself, and 0.9.0 put a version of it in every prompt.

  5. 05

    The rules were written down after they had already been broken

    The last release is documentation. 0.9.0 adds CONTRIBUTING.md, a pull-request template, a CLAUDE.md that Claude Code picks up automatically, and a /release skill that cuts a version in two phases — and it exists because the release process and the repository’s traps lived, in the maintainer’s own words, “only in review comments and in whoever happened to remember them”. What those documents record is what had already gone wrong. A new style preset is read in four places, and the caveman preset shipped with one of them — the session-start notice — missing, so a style could persist across sessions with nothing on screen to say so. The allowed-tools line in the slash command has to close its quote after the path, and it had regressed twice, once through a merge-conflict resolution, leaving /claudish unusable in every release from 0.5.0 to 0.7.0. A language value in a project’s settings file — a file that travels with a repository — could carry a terminal escape sequence onto the screen, because the sanitiser folded whitespace and an escape is not whitespace. The rule that outranks all of them is stated first and repeated in every document: every hook must fail open. There is no test suite; a change is verified by piping synthetic payloads into the hook and checking that three malformed inputs print nothing and exit 0.

Adjacent records

All records →