---
title: Plain Speak (a plain-English summary beside every reply)
---

# Plain Speak

## What it is

### What it is

**Plain Speak** rewrites the latest agent message into a five-section markdown card so a non-programmer can understand what just happened in five seconds. The five sections are **Latest** (a 6–14-word past-tense recap of what the operator is actually trying to get done — mining the compaction summary if the session was compacted, never echoing procedural acknowledgments like "continue"), **TLDR** (a single 6–14-word unformatted headline of what the agent did and what is pending), **Recommended Action** (a short phrase telling you the most useful next step — Unblock the agent, View original, Answer questions, Make a decision, Commit locally, Push to remote, Update documentation, Understand then archive, Archive, or Wait — with the highest-priority one chosen when several apply; the two closing rungs differ by whether the card is worth reading — bare **Archive** is a safety claim that you can close it unread and lose nothing, while **Understand then archive** means there is nothing to _do_ but something worth taking in first (a finding, a root cause, a cost, a behaviour change), and a torn call goes to **Understand then archive**; both closing rungs are a claim that the whole conversation is finished, so neither appears mid-thread — while you and the agent are still going back and forth, while it still owes you a result it promised, or while it is waiting on work that reports back to it, the action is **None** (the section simply hides) or **Wait**, never Archive, and **None** is likewise the answer whenever no rung genuinely fits; destructive / shared-state approval gates like "OK to push?" route through **Answer questions** with a synthesized Yes/No question naming the specific action, e.g. "Approve pushing `feat/auth` into master?" — there is no separate "Approve or deny" rung), **Response** (the bulleted body, sized to the source message; important links from the agent's reply are surfaced inline so you can click straight from the summary), and **Questions** (an optional numbered list of any **real** questions the agent is asking, with lettered options for multiple-choice; throwaway closers like "anything else?", catch-all "type your own answer" options, and self-generated scheduling offers are dropped, and an option the agent explicitly recommends is tagged with `(recommended)`). The original message is still available behind a **Show Original** disclosure underneath the rewrite.

**Emojis on action labels (default on).** With the **Emojis on action labels** toggle (Settings → Plain Speak) on, the **Recommended Action** line shows a fixed emoji before each standard action — 📦 Archive, 🧐 Understand then archive, ⏳ Wait, 🔀 Merge to local master, 🚀 Push to remote, 📝 Update documentation, 📖 Review the doc, 🆘 Unblock the agent, 👀 View original, ❓ Answer questions, ⚖️ Make a decision, 💾 Commit locally — so you can spot the next step at a glance. A custom, non-standard action phrase shows no emoji. The emoji is applied when the card renders (session bubble, inbox, and mobile alike), so flipping the toggle updates cards you're already looking at; it's a top-level render setting delivered to mobile, decorated in [`PlainEnglishOverlay.tsx`](../../src/renderer/src/features/sessions/PlainEnglishOverlay.tsx) from the shared verb→emoji table in [`plain-speak-action-emoji.ts`](../../src/shared/plain-speak-action-emoji.ts).

The rewrite is written **by the agent itself, inline** (as of 2026-07-20). Whenever Plain Speak is on, each AMC-managed session appends its own five-section card at the end of its message, below a `[[OMNISCIO_PLAIN_SPEAK]]` marker; Omniscio strips that card off the shown / stored / exported reply and routes it into the overlay + ⇄ toggle. Two wins: **higher quality** (the smart in-app model that wrote the message, with full context, writes the card — instead of a small model re-reading a truncated transcript) and **free** (no separate paid pass; the agent you already pay for produced it). The full mechanics — the marker, the strip, the gating — live in [plain-speak-inline-generation-contract.md](../../.claude/memory/contracts/plain-speak-inline-generation-contract.md).

A message with **no valid inline card** — an older session that predates the feature, a malformed card, or a pure terminal signal that never gets one (a waiting / background / nothing-to-do reply) — simply renders **plain, with no overlay** (recorded in the decisions log as `skipped`). There is no fallback rewrite.

**Dev-pipeline gate reports carry the card too (2026-07-23).** A gate report (`## 🔨 🟢 Build Complete`, `## 🚀 🟢 Ready to Merge`, …) renders natively — its header + pipeline stepper — by default, but the agent writes its own Plain Speak card for it just like any other message (placed after the `[DEV-PIPELINE | …]` marker). Omniscio applies that card **free** as a toggle-able overlay: the pill appears, and flipping to Plain Speak shows the card while the original view keeps the native gate report. Omniscio never runs a paid rewrite on a gate report, and it never machine-synthesizes the card — only the agent's own card is shown. **The one deterministic touch (2026-08-04):** the app guarantees the card's **TLDR leads with the gate's phase emoji + status circle** (e.g. `🔨 🟢`), mirrored from the report's own header whenever the agent's TLDR left them out — it prepends only those two glyphs (idempotent, never a rewrite), so the phase is unmistakable in the card even when the model forgets to write them. A strengthened prompt asks the agent to write them itself; this backstop is the guarantee underneath. Mechanics: `gateHeaderGlyphs` + `ensureGatePhaseGlyphsInTldr`, applied at `applyGateReportInlineCard`; invariant `a-dev-pipeline-gate-report` in [plain-speak-overlay-gating-contract.md](../../.claude/memory/contracts/plain-speak-overlay-gating-contract.md).

**The old cheap-model cascade is archived (2026-07-20).** Plain Speak used to offer four swappable **pipelines** — a 5-stage Qwen 3 32B → critic → Haiku → gpt-oss cascade (plus a reduced-context variant), a single Claude Sonnet call, and a single Qwen call — picked from a dropdown in Settings. Those pipelines made **outside model calls** and were the default engine. They are **no longer a live route and the picker was removed**: the code is preserved in-tree but runs only behind the default-off `AMC_ENABLE_OVERLAY_CASCADE` env switch (kept for rollback / internal testing). Their mechanics are documented in [plain-speak-cascade-contract.md](../../.claude/memory/contracts/plain-speak-cascade-contract.md).

**Every pipeline ends with a deterministic jargon scrub** ([`src/main/services/ai-manager/cascade/jargon-scrub.ts`](../../src/main/services/ai-manager/cascade/jargon-scrub.ts), `scrubJargon`) — a final post-process pass that strips the RULEBOOK-forbidden engineering identifiers the LLM stages intermittently leak (branch names → "that change", test counts → "all of them" / "the checks passed", version/migration numbers → "the latest version", file paths → "that file", CLI commands → "that command", and the "the agent" voice slip → "the session"). It preserves link URLs, keyboard shortcuts (`` `Ctrl+Shift+Q` ``), and benign backticked labels, closes the one gap the jargon scanner leaves (a bare ID _inside_ backticks, e.g. `` `bd9ef03db` ``), and is idempotent + a no-op on already-clean output. The scrub is **grammar-safe** — de-jargoning never leaves broken English: it consumes the _whole_ jargon phrase (so `17/17 tests OK` → `the tests OK`, never the orphan `all of them tests OK`), collapses the leftover apposition/survivor words an identifier strands (so ``(`fix/x-200002` recent change-200002)`` → the paren is dropped, not the garbled `(that change recent change-200002)`), and re-capitalizes a replacement that lands at a sentence or bullet start (`- 84 tests passed` → `- The checks passed`); when it cannot clean a seam it leaves the model's already-fluent text rather than emit nonsense. This grammar-safety is what fixed the 2026-06-23 "Ready to Merge" cards that were rendering as broken English (orphan words, lowercase bullets, branch-name survivors, a shredded session ID). V8 already strips commit SHAs; this closes the rest of the gap and runs across **all** pipelines (cascade, cascade-reduced, Sonnet single, Qwen single) so no engine choice ships jargon. Ported from the offline bake-off harness where it was validated to take the held-out set to 100% jargon-clean; its grammar invariants are pinned by `jargon-scrub-grammar-safe` in [plain-speak-cascade-contract.md](../../.claude/memory/contracts/plain-speak-cascade-contract.md).

Plain Speak is **on by default** as of 2026-08-25 — turn it off in Settings → Plain Speak. It was opt-in while the rewrite ran through a paid model cascade; since 2026-07-20 the agent writes the card itself for **$0**, so the cost reason for opt-in is gone and a fresh install now gets the readable summary out of the box. A one-time **ship-on migration** (`migrateOverlayShipOnV1`, 2026-08-25) carries the new default to EXISTING installs too: any install still switched off is turned **on**, but pinned **original-first** — those messages keep opening on the real content and you switch to the card yourself with the ⇄ pill. (Fresh installs, and anyone who already had Plain Speak on, get the card first.) It runs exactly once per install; turn Plain Speak off after it and it stays off. History: Plain Speak was off by default from 2026-05-23, the 2026-05-16 default-on migration was retired the same day, and on 2026-05-25 a one-time **force-off reset** flipped it back off for every install the retired migration had switched on. That force-off migration was **retired on 2026-08-25** with the default flip — left wired, it would have reset every brand-new install on its first boot. On 2026-05-26 a second one-time migration collapsed the two-flag model (`overlay.enabled` + `overlayPaused`) into a **single** master toggle: `overlay.enabled` is now the only flag the runtime gate reads, and the retirement migration reconciles any install whose legacy `overlayPaused: true` left the master stale-on. Installs that were reset get a one-time dismissible banner explaining the 2026-05-25 force-off (see _What you see_ below); anyone who re-enables Plain Speak after either migration keeps it on. DB migration v126 (2026-04-30) still flipped every pre-existing session's per-session enable to on, and every newly-created session still defaults its per-session flag to on — the per-session opt-out toggle was removed from the three-dot menu on 2026-05-14 to reduce menu clutter, so Plain Speak applies uniformly to every session whenever the global master toggle is on and the daily cap allows it. Every rewrite Plain Speak makes is audited in a decisions log so you can see exactly what it did, why, what it cost, and which model it used.

## Where to find it

In the conversation — the rewrite arrives attached to the message rather than on a screen of its own, with a toggle to flip between it and the original.

## How it behaves

### How the card is delivered

Each AMC-managed session is nudged (via an injected, relay-safe system-prompt directive) to append its OWN five-section card after its final answer, on a line delimited by `[[OMNISCIO_PLAIN_SPEAK]]`; Omniscio strips that card off the shown / stored / exported reply and routes it into the overlay + ⇄ toggle. The nudge is injected whenever the master Plain Speak toggle is on — there is no separate inline sub-toggle any more (`overlayInlineAgentGenerated` defaults ON and a one-time migration ported existing users, but the gate now keys on the master toggle alone). The `## Questions` section reproduces the questions the agent actually asked **word-for-word** (stem + lettered options, exactly as written) and preserves the ` (recommended)` tag on any option the agent recommended, rather than paraphrasing them. Beyond questions the agent literally asked, any **decision** the turn leaves you — a choice, an approval, an either-or — is surfaced in the same widget (a stem plus lettered options) so you can decide in one click; a decision that genuinely needs a long free-form answer instead states the question plainly and says what it needs. And any important **link or URL** the agent produced or points to is always included in the card as a clickable link (in TLDR when the link is the answer, otherwise in Response), so you never have to open the original just to copy it. The directive is a **default, not a mandate**: if you tell the agent in-conversation to skip, reshape, or otherwise change its Plain Speak card, it defers to you — your direct instruction wins over the built-in nudge.

**The one deterministic link touch (2026-08-15).** The app guarantees this even when the model forgets: if the agent shows a web/app link in its answer but leaves it out of its card, Omniscio automatically adds that link to the card's **Response** section — up to three, each a single-line bullet, replacing a "None" body so it can't be dropped — so a link you saw in the reply never vanishes from the summary. Like the TLDR-glyph touch on gate reports above, it is a backstop under a prompt that already asks the agent to include the link itself: it is idempotent, only ever adds a link that is genuinely missing (a URL already anywhere in the card is left alone, never duplicated), scopes to real `http(s)`/`omniscio` links (never a bare file path, a `javascript:` link, or a URL that only appeared in the agent's tool-activity or a code sample), and can never forge a card section (injected bullets are always single-line). It runs at the same free, inline chokepoint that saves the card, so desktop, mobile, copy, and the inbox all carry the link, and the desktop first-paint applies the identical transform so nothing flickers. Mechanics: `backfillResponseLinks` applied at `applyInlineCard`; invariant `apply-inline-card-deterministically-back` in [plain-speak-overlay-gating-contract.md](../../.claude/memory/contracts/plain-speak-overlay-gating-contract.md).

**Decision cards always get their widget — the auto-repair re-drive (2026-08-15).** When an agent's card tells you to **Make a Decision** or **Answer questions** but ships **no clickable question widget** — so you'd be told to choose with nothing to click — Omniscio quietly sends the agent back to re-send that reply _with_ the widget, keeping its actual decision unchanged, then **hides the broken reply and that nudge** so you see only the corrected card. It happens at most **once per broken card** (a corrected reply is never re-driven, so it can't loop) and the session **never reaches your inbox or Needs You until the fix lands** — while the repair is running the session is held back exactly the way it is while a card is still being written, and the corrected turn is what finally surfaces. If the agent's corrected reply still lacks a widget, that attempt is shown as-is (we tried once); if the re-drive can't run or never comes back (a dead session, an app restart), the original simply surfaces normally — a session is never stranded invisible. The hidden reply is not deleted (it reappears under Show System Messages). This is a real extra agent turn, so it only fires on the rare turn where an agent forgets the widget. Mechanics: `decisionCardNeedsWidget` + `tryDecisionRedrive` / `handleDecisionRedriveArrival` in [`decision-redrive.ts`](../../src/main/services/ai-manager/decision-redrive.ts), reusing the overlay-pending gate for suppression; invariant `decision-widget-repair-re-drive` in [plain-speak-overlay-gating-contract.md](../../.claude/memory/contracts/plain-speak-overlay-gating-contract.md).

**The widget repair has a floor under it — a card is never left asking for an answer it cannot take (2026-09-21).** The re-drive above is prompt-shaped, and it reaches only the turns that come through the normal reply path. Two other paths save a card without ever consulting it — a **dev-pipeline gate report** and the **missed-turn catch-up sweep** — so a card telling you to answer something could still reach you with nothing to click, and did: measured over the three days to 2026-09-21, **47 of 6,565 cards** shipped that way (~16/day), and the one the owner reported was a green gate card whose `## Questions` section read "None. Reply approved to build the revised plan." A Questions area that opens on a nothing-word is hidden, so the card on screen read "Answer questions" with no Questions area at all. The guarantee now lives in the **one place every card passes through on its way to being saved** rather than in one of the three callers: a card whose action asks for an answer it cannot deliver has that action dropped to `None`. "It cannot deliver" is deliberately three questions, because a dev-pipeline gate puts its real question in the **report body** rather than the card — so a gate card with no widget of its own is often *correct* and keeps its rung. The test is on the Questions section's **first sentence**, not a prefix, so "None. Everything is done." is filler while "None of these fit — which do you prefer?" is a real question and is left alone. Verified against the live database, the repair changes exactly those 47 cards and not one other card's output. Mechanics: `clearAnswerRungWhenNothingToAnswer` applied inside `finalizeInlineOverlayCard`; invariant `answer-rung-never-without-something-to-answer` in [plain-speak-overlay-gating-contract.md](../../.claude/memory/contracts/plain-speak-overlay-gating-contract.md).

**A stopped gate card gets one round-trip for the real question (2026-09-26).** On a dev-pipeline gate that has **stopped and is waiting for you** — a 🟡 or 🔴 gate, never a green one that already advanced — dropping the rung is not the whole answer, because the gate card is the one place you are actually being asked to respond. So the app also asks the agent **once**, invisibly, to send that card again with the question as a real clickable widget, and the corrected card replaces the one on that same message. You see **one message**, the gate report and its own approve / feedback / abort controls are left exactly as they were, and the session never sits holding a card that asks something it cannot take. A **green** gate is deliberately excluded: it advances by itself and the app strips that card's question widget on the way in, so asking for one would be a round-trip whose only possible outcome is nothing. Mechanics: `tryGateWidgetRedrive` in [card-redrive.ts](../../src/main/services/ai-manager/card-redrive.ts), fired fire-and-forget from `applyGateReportInlineCard`; its arrival **corrects** the overlay row the gate path already wrote rather than adding a second one, because those rows are unique per message and a duplicate insert throws — after the agent's answer had already been hidden, which is how this would have failed silently and permanently. Invariant `gate-card-widget-repair` in [plain-speak-overlay-gating-contract.md](../../.claude/memory/contracts/plain-speak-overlay-gating-contract.md).

**Every engine gets the directive — not just Claude (2026-07-31).** How the "write your own card" instruction reaches the agent depends on the engine, but the result is the same card + toggle on all of them. A **Claude** session (and the anthropic-compat vendors that run the Claude CLI — DeepSeek / Kimi / GLM / MiniMax / Meta) receives it through the CLI's `--append-system-prompt` flag. A **non-Claude** engine — **Codex, Gemini, OpenCode, Cursor, Kimi Code, Hermes, Devin** — has no such flag, so Omniscio delivers the SAME directive **invisibly through the first-message context** (the identical hidden channel that already carries your project docs + coaching profile to those engines), plus a short one-line reminder on every later turn so a long conversation keeps producing the card. The instruction never appears in the chat bubble or the stored message — only the resulting card lands in the ⇄ toggle. Because the card-detection/overlay machinery is **engine-agnostic** (it reads the finished agent message, not the engine), nothing else differs: a Codex card renders exactly like a Claude one. Delivery is gated by the same master Plain Speak toggle and is skipped for silent/background recipe sessions (no reader). Mechanics: `buildExternalNudgeContext` + `resolveExternalNudgeReminder` in [`session-auto-context.ts`](../../src/main/services/session/session-auto-context.ts) and the injected `PLAIN_SPEAK_MARKER_NUDGE` / `PLAIN_SPEAK_TURN_REMINDER` in [`spawn-system-prompts.ts`](../../src/main/process/spawn-system-prompts.ts); see [launch-auto-context-contract.md](../../.claude/memory/contracts/launch-auto-context-contract.md). **The same generalized channel also delivers the Spoken Narration and Final-Message-marker nudges to those engines (2026-07-31), each behind its own toggle — see [spoken-narration.md](spoken-narration.md).** **Codex update (2026-08-11):** on a recent Codex version the STANDING directive now rides Codex's own `developerInstructions` system-prompt slot (a real system prompt, like Claude's `--append-system-prompt`) instead of the first message; its per-turn reminder still uses the first-message channel, and an older Codex falls back to first-message entirely — see [custom-model-instructions.md](custom-model-instructions.md) → "How the text reaches the model" and [launch-auto-context-contract.md](../../.claude/memory/contracts/launch-auto-context-contract.md) `codex-developer-instructions-divert`.

**Marker-optional — a card missing its `[[OMNISCIO_PLAIN_SPEAK]]` marker is still recognized by its shape.** The marker is the primary delimiter, but an agent occasionally writes the whole card and omits the marker line — the card's `##` sections blend into the answer's own headings, so the model drops the delimiter. Omniscio still recognizes such a card by its canonical sections — `## Latest` has to be there, at least three of the card's sections have to form the trailing block of the message, and no other heading may follow them — and strips + routes it exactly as a marked card, so a missing marker no longer leaks the card into the visible message (and the card still lands in the ⇄ toggle instead of getting no overlay at all). **The sections do not have to be in card order**: a card written out of sequence is recognized too, and displayed in the canonical order. The structural match is deliberately **precision-first**: it is fence-aware, a repeated section breaks the match, and a card that would be the _whole_ message is only accepted when it is complete — biased to MISS over a false positive, because a false positive would hide real agent output. So an ordinary answer that merely uses a `## Latest` heading, one carrying only two card headings, or a card an agent is _discussing_ inside a code fence is never mistaken for a card. Mechanics: `detectStructuralPlainSpeakCardStart` in [`agent-content-markers.ts`](../../src/shared/agent-content-markers.ts), and `tail-cut-plus-misplaced-order`/`invisible-every-content-interpreter` in [plain-speak-inline-generation-contract.md](../../.claude/memory/contracts/plain-speak-inline-generation-contract.md).

A one-time config migration `migrateOverlayInlineDefaultForExistingUsers` (sentinel `overlayInlineDefaultMigrated`) ported EXISTING users to inline mode, **preserving each user's `overlay.enabled` on/off state** — it only changed the generation mode, never whether Plain Speak is on.

**A forgotten card is asked for once, invisibly (2026-09-06).** When Plain Speak is on but an agent finishes a turn with **no card at all**, Omniscio quietly sends that agent a single message asking for the card it left off. The agent answers one of two ways: it sends the card — which Omniscio attaches to **the message it already sent**, so you still see one message with a ⇄ pill, not two — or it says the omission was **deliberate** (the turn was a hand-off or a terminal signal a glance card would only add noise to), and Omniscio leaves the message exactly as written and **never asks again about it**. Either way you see none of it: the request and the agent's answer are both hidden, the session doesn't ping you twice, and while the exchange runs the session is held back from your inbox exactly the way it is while a card is still being written. It happens **at most once per message** — a message that's been asked is marked, so it can't loop, and that mark is written the moment the request is sent, so even an app restart can't cause a second ask. If the agent replies with real new content instead of a card, that reply is **never** hidden: it shows normally and gets its own card. Turns that are meant to be card-less are never asked at all — a waiting or background reply, a nothing-to-do wake-up, a dev-pipeline gate report, an error or interrupted turn, a turn that was **cut off mid-flight** (Omniscio resumes that one on its own — asking it for a card first used to cancel the resume, leaving the session idle until you noticed; fixed 2026-09-21), a phrase you configured to skip, or a background session. Hidden messages are not deleted (they reappear under Show System Messages). This is a real extra agent turn, so it only fires on the rare turn where an agent forgets. Mechanics: `tryCardRedrive` / `handleCardRedriveArrival` in [`card-redrive.ts`](../../src/main/services/ai-manager/card-redrive.ts); [plain-speak-card-redrive-contract.md](../../.claude/memory/contracts/plain-speak-card-redrive-contract.md).

When an agent still does **not** produce a card after that — it declined as strategic, it was one of the never-asked turns above, or the request couldn't be delivered — **no overlay renders** (the message shows plain, recorded `skipped`); the old cascade fallback is archived behind the `AMC_ENABLE_OVERLAY_CASCADE` switch (default off). (Dev-pipeline gate reports never get a PAID rewrite or a machine-synthesized card — but the agent's OWN inline card, when it wrote one, IS applied free, so the pill DOES appear and flipping to Plain Speak shows that card; see _Dev-pipeline gate reports_ below.) The full mechanics — the marker, the strip, the gating — live in [plain-speak-inline-generation-contract.md](../../.claude/memory/contracts/plain-speak-inline-generation-contract.md).

## Related

- [Plain Speak part 2](plain-speak-part-2.md) — what you actually see, and what happens while the rewrite is being computed.
- [Plain Speak part 3](plain-speak-part-3.md) — the gate reports, what the rewrite can see, the cost controls, the decisions log and the privacy rules.
- [Plain Speak part 4](plain-speak-part-4.md) — the internals, for anyone working on the code.
- [plain-speak-feedback.md](plain-speak-feedback.md) — flagging a rewrite that got it wrong.

### Related

- [inbox-pilot.md](inbox-pilot.md) — the sibling feature that classifies each agent end-of-turn into a routing outcome; same backend, separate cap / pause / api-key permission
- [catch-up-card.md](catch-up-card.md) — the pinned 4-line summary at the top of a Needs You session (**currently disabled** as of 2026-04-30 — code preserved, Settings UI unwired)
- [coaching-engine.md](coaching-engine.md) — the other AI-driven nudge system in Omniscio, but for teaching you the app rather than rewriting agent output
- [inbox-overview.md](inbox-overview.md) — the unified inbox that Plain Speak's per-session opt-in lives next to
- [ai-providers.md](ai-providers.md) — how Omniscio routes AI features between Anthropic, Groq, Together, and OpenRouter; Plain Speak runs on Qwen 3 32B via OpenRouter, the rest of Omniscio's AI features default to Haiku

