opencode-agentish-to-english
v1.0.0
Published
opencode plugin that rewrites verbose agent output into plain, direct, fluff-free English
Maintainers
Readme
agentish-to-english
Rewrites verbose agent answers into plain English — for you, not the model.
What it is
An opencode plugin that rewrites every assistant message into plain, direct, fluff-free English. After each answer, a fast model produces a terse rewrite that is appended below the original as a labeled block: 💬 In plain English: …. The original text is never touched, and the block is model-invisible — it renders in your TUI but never enters the model's context, so it costs you nothing at generation time.
The problem
AI agents write like corporate memos: preambles, outro summaries, filler, hedging, clichés ("delve", "leverage", "it's important to note", "not just X, but Y"). You read for information but pay for word count. Editing that out by hand is tedious; telling the model to "be concise" in a prompt is ignored.
How it looks
You: Why does the build fail?
Agent: I've taken a look into this, and it's important to note that the build is
currently failing on src/config.ts line 42 due to a TypeScript error with
the code TS2307 — ultimately, this will need to be fixed before we can
move forward with the release.
💬 In plain English:
Build fails: src/config.ts:42 → TS2307. Fix before release.Numbers, code, paths, warnings, and negation words survive verbatim. The rest gets compressed — usually to well under half the original length.
Features
- Rewrites every assistant message. Completed text is buffered and rewritten in order on the next
session.idle, one rewrite per message. - Model-invisible blocks. The rewrite is appended as an
ignoredtext part in a separate child session — it renders for you but never enters future model context or compaction. - Lossless compression. Code, file paths, URLs, numbers, error codes, warnings, and negation words (
not/never/no/only/except) are preserved verbatim; results are capped at 60% of the original word count. - Fail-open. Any failure (model down, bad model ID, timeout, provider error) is a silent no-op — your original answer always stands.
- No extra infra. No API keys, no ollama stack, no 17 GB model download. The rewrite reuses the providers you already configured.
- Toggles mid-session. A flag file pauses rewriting;
AGENTISH_ENABLED=0makes the plugin inert at launch. - Typing-friendly. A debounce window cancels rewrites that are no longer useful; a new user message never kills an in-flight rewrite.
- No telemetry. Nothing leaves your session except the rewrite itself.
Install
Requires opencode ≥ 1.18.18.
Option A — via npm. Add the plugin to your opencode.json:
{
"plugin": ["opencode-agentish-to-english"]
}Option B — plugin directory. Drop src/plugin.ts from the published package into ~/.config/opencode/plugins/ (global) or .opencode/plugins/ (project).
Either way, restart opencode — the rewrite block appears under each assistant message.
Configuration
All configuration is via AGENTISH_* environment variables, set in your shell or in opencode.json's env block:
{
"plugin": ["opencode-agentish-to-english"],
"env": {
"AGENTISH_MODEL": "openai/gpt-4o-mini",
"AGENTISH_LABEL": "TL;DR:"
}
}| Variable | Default | Description |
|---|---|---|
| AGENTISH_ENABLED | 1 | Kill switch, read at launch. 0 makes the plugin inert. |
| AGENTISH_MODEL | (unset) | Rewrite model override, format provider/model, e.g. openai/gpt-4o-mini. |
| AGENTISH_LABEL | 💬 In plain English: | Label shown above each rewrite block. |
| AGENTISH_OFF_FILE | ~/.config/opencode/agentish-off | Flag-file path. When the file exists, rewriting is paused (checked on every message). |
| AGENTISH_NOTICE | 1 | One toast per session on the first skipped rewrite. 0 silences toasts. |
| AGENTISH_DEBUG | 0 | Structured debug log via client.app.log (service agentish-to-english). |
| AGENTISH_TIMEOUT | 300 | Rewrite timeout in seconds. On timeout the child rewrite is aborted, the child session is deleted, and the original is kept. |
| AGENTISH_REASONING_EFFORT | medium | Reasoning-effort variant sent to the rewrite model on the child prompt. Empty ("") sends nothing. Only applies to models that expose a matching variant; unknown values are ignored by opencode. |
| AGENTISH_MIN_CHARS | 40 | Skip rewriting messages shorter than this many characters. Set 0 to rewrite everything. |
| AGENTISH_DEBOUNCE | 1500 | Milliseconds to wait after an assistant message completes before starting the rewrite. A new user message within this window cancels the pending rewrite. 0 rewrites immediately. |
Model selection chain
The rewrite model is resolved in this order:
AGENTISH_MODEL(explicit override)- config
small_model - config
model - the effective per-agent model (
agent.<name>.model, agent name from the last user message, defaultbuild) - none resolved → the message is kept as-is and one session toast explains that no rewriter model was configured.
Recommended: for a reasoning model like opencode-go/deepseek-v4-flash, set AGENTISH_MODEL=opencode-go/deepseek-v4-flash yourself. Its default thinking tier can burn seconds before emitting text; the plugin's AGENTISH_REASONING_EFFORT (default medium) requests the medium-effort tier so rewrites stay fast and compress hard instead of timing out.
How it works
message.part.updatedevents accumulate text deltas per message (bounded buffer, cleaned up after completion).- When an assistant message completes, it is enqueued for rewriting.
- On the next
session.idlethe pending queue drains one message at a time. For each message the plugin creates a separate child session (parentID= the current session), prompts it with the rewrite style rules plus the original text, waits for the reply (sameAGENTISH_TIMEOUTguard), and deletes the child session — always, even on timeout or error. - Only the result is appended to the parent session — a single
ignored: truetext part labeled💬 In plain English:. - The block is model-invisible:
ignored: trueparts are excluded from model-context assembly and compaction, and child-session messages are never pulled into the parent's context. The TUI renders ignored text parts normally, so you still see the rewrite under each answer.
Rewrites are lossless by construction: negations, numbers, code, paths, URLs, error codes, and warnings survive verbatim; the result is capped at 60% of the original word count.
Roadmap & known limits
- v2 — markdown-file rewriting: rewrite tool output written to files, not just chat messages.
- v2 — replace mode: true in-place replacement of the original block via an upstream part-edit API (no such endpoint exists in opencode's SDK today).
- v2 — style dial: caveman / light / ultra voices.
- Known limit: micro-messages under
AGENTISH_MIN_CHARS(default 40) are skipped. SetAGENTISH_MIN_CHARS=0to restore rewrite-everything. - Known limit: the rewrite is serialized per
session.idle— rapid-fire turns delay later rewrites behind earlier ones. - Known limit: the block renders as a user-styled message (that's what makes it model-invisible); a future part-edit API could make it a true assistant-message edit.
Troubleshooting
- No rewrite appears. Check
AGENTISH_DEBUG=1and look at the structured logs (serviceagentish-to-english). The most common cause is no resolved rewrite model — see the model selection chain above. - Want it to stop right now?
touch ~/.config/opencode/agentish-offpauses rewriting on the next message;rm ~/.config/opencode/agentish-offresumes. Path is overridable withAGENTISH_OFF_FILE. - Want it dead at launch? Set
AGENTISH_ENABLED=0. Model not foundtoast. The resolved model ID doesn't exist on your provider. SetAGENTISH_MODELto a validprovider/model, or fix yoursmall_model. The session keeps working either way.
Uninstall
- Remove the plugin entry from
opencode.json(or delete the file from~/.config/opencode/plugins/). - Restart opencode. No behavior remains.
Development
bun install # install dev deps
bun test # vitest unit tests (128 tests)
bun test --coverage # coverage report
bunx tsc --noEmit # typecheckIntegration acceptance (spec AC 1–8) runs headless against a live provider:
bun run tests/acceptance/drive-acceptance.tsThis starts opencode serve on a scratch port, drives real sessions, and asserts the acceptance criteria on server-side session state. It needs a working provider/model — it uses your configured opencode auth. Evidence is written under tests/fixtures/acceptance/.
License
MIT
