DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Chillizu /

Chillizu/miopiik-iui

Verified

MiOpIIk IUI for DeepSeek Harness (DSH) — trusted declarative Markdown embeds and bounded iui blocks rendered as native components. Prerelease (0.1.0-rc.5).

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@f218e1d0

MiOpIIk IUI

English | 简体中文

Version 0.1.0-rc.4 — prerelease. This is a release candidate, not a stable release. It has not been published to npm, it is not a DeepSeek Harness upstream feature, and rendering inside the chat depends on an unofficial, version-coupled patch of @deepseek-ai/dsh-client-ui-chat. See Release status.

MiOpIIk IUI is a presentation-only plugin for DeepSeek Harness (DSH) Web. Models write ordinary Markdown that may contain a few trusted inline tokens and controlled iui fences; the browser turns those fragments into declarative interface components. The plugin does not require the MiOpIIk Mind/Ink/Operator agent, does not keep a ledger, and does not expose model tools.

The scope is deliberately narrow: just enough interface, in place. Everything else about the chat experience (messages, reasoning rows, images, history, streaming, copy, accessibility ownership) stays with DSH.

  • Inline tokens: {{badge:success:passed}}, {{icon:check}}, {{code:npm test}}
  • Fenced iui blocks containing miopiik-ml or a validated iui/1 JSON AST
  • A small whitelist of declarative components, local state bindings and local segmented interaction
  • Read-only replay of legacy ink-view widget JSON, so historical sessions do not lose their content
  • A native DSH plugin page with an Overview using the real renderer and a Configuration view with the one browser-local switch and diagnostics

It is not a UI builder: models cannot ship arbitrary HTML, JavaScript or CSS, and nothing in the message can issue a network request, call a tool, or start a model turn.

Release status

Version 0.1.0-rc.4 is a prerelease. The code is usable and tested, but the package cannot be called stable yet:

  1. Experimental host patch. In-chat rendering needs a local fork of @deepseek-ai/dsh-client-ui-chat, generated by tools/fork-chat-embeds.mjs from a specific DSH version. DSH upstream exposes no Markdown embed API. Without the patch, an iui fence renders as an ordinary code block; the plugin page still previews correctly and the diagnostics say so.
  2. Lossy cross-token Markdown. Trusted fragments split the Markdown text block, so formatting, selection/copy and screen-reader reading order that cross a token boundary are not identical to native Markdown.
  3. Non-incremental streaming. An unclosed iui fence is shown as plain text until the closing fence arrives; then the block materializes at once.

The full gate list for calling v1 finished lives in docs/IUI-V1-RELEASE-CANDIDATE.md, and the per-version stable blockers are recorded in docs/RELEASE-NOTES.md. Treat those documents as baselines, not as permanent health certificates.

Compared with MiOpIIk Agent

The MiOpIIk project is split into two independent repositories. They can be installed together or separately; neither depends on the other.

MiOpIIk IUI (this repository) MiOpIIk Agent
Package miopiik-iui 0.1.0-rc.4, prerelease miopiik-dsh 0.1.1, stable
Layer presentation only: trusted Markdown fragments in the browser host side: memory, governance, background execution
Main surface inline tokens, iui fences, declarative components, local state ink_* tool surface, inbox/facts/loops/branches ledger, operator dispatch
State one browser-local render preference append-only JSONL ledger under the workspace .dsh/miopiik/
Model tools none yes
Chat ownership native DSH AssistantMarkdown / ReasoningRow remain in charge session views and plugin pages; does not render IUI
Install requirement DSH Web profile; experimental chat patch for in-chat rendering DSH Web profile
Repository this one https://github.com/Chillizu/miopiik

Repository split

This repository was extracted from the former MiOpIIk monorepo with git subtree split -P miopiik-iui, so the IUI commit history is real history. The agent part moved to its own repository, https://github.com/Chillizu/miopiik. Pre-split release tags in the old repository used the miopiik-iui-v... prefix; their assets and download links stay valid. Historical session data is not migrated or rewritten: legacy ink-view content is mapped read-only at render time (see Legacy replay). The full provenance record is in docs/MIGRATION.md.

Architecture

model output (plain Markdown from the model)
  |
  |  shared/markdown-segments.js   split fenced iui / ink-view and inline tokens;
  |                                other code fences and inline code are left untouched
  v
  L-- shared/miopiik-ml.js         iui fence in miopiik-ml -> raw AST document
  |   (or iui/1 JSON fence)        JSON AST is kept for debugging/compatibility
  v
  shared/iui-ast.js                validateAst(): component whitelist, props,
  |                                binding paths, budgets, safe links, local degrade
  v
  renderer.js                      React component registry; theme tokens, inline SVG
  |
  v
browser                            local React state only; no network, no model round-trip

Files and responsibilities:

File Role
index.js Host half. Injects one system-prompt section (miopiik-iui:render-contract, order 670, interpolation off) with the short output convention. Registers no tools.
shared/markdown-segments.js Stateless splitter for fenced blocks and inline tokens. A bare top-level <ui>...</ui> at line start is also recognized when a model forgets the fence.
shared/miopiik-ml.js Parser for the model-facing miopiik-ml tag grammar; produces an unvalidated AST document.
shared/iui-ast.js The single validator for iui/1: REGISTRY whitelist, LIMITS, binding parser, table/chart normalization, local degradation.
shared/legacy-widgets.js Read-only adapter mapping the retired seven-widget ink-view JSON into iui/1.
renderer.js React renderer for the validated AST, plus inline primitives. Bundled verbatim into client.js.
settings.js The DSH plugin page (plugins.bundle.config, key miopiik-iui): Overview and Configuration views.
client.js Generated browser bundle. Do not edit by hand; regenerate with node tools/build.mjs.
cordis.patch.yml Bundle patch used by the DSH profile to load the plugin.

Host-side patch

DSH has no official Markdown embed API at this version. The client needs one hook inside the chat message renderer, so the repository ships a patch generator instead of a private fork that silently drifts:

  1. tools/fork-chat-embeds.mjs copies the installed @deepseek-ai/dsh-client-ui-chat package into upstream/dsh-client-ui-chat-embeds/ (generated output, gitignored) and inserts exactly one controlled hook in the case "text" branch of AssistantMarkdown.
  2. It writes the exact difference to patches/chat-markdown-embeds.patch, runs node --check on the result, and links the fork's node_modules to the DSH dependency tree so imports resolve.
  3. Native AssistantMarkdown, ReasoningRow (fold, summary, streaming, accessibility), images, attachments, copy and replay stay in charge; only text fragments matched by trusted markers are handed to the plugin.
  4. The hook is fail-closed: if the plugin registry is absent, the browser preference is off, or rendering throws, the fragment goes back to native Markdown or a plain fallback. The hook also sets globalThis.__miopiikMarkdownEmbedsHost = true, which the plugin page uses to report whether the patch is loaded.

This is not a DSH upstream API. The generator locates anchors in the installed package and fails loudly instead of producing a wrong patch, so the fork is coupled to a DSH version. Regenerate it after a DSH upgrade and point only the target profile at it; never edit the global DSH installation.

What you can write

Inline tokens

Anywhere in a normal paragraph:

Token Meaning
{{badge:success:passed}} Badge with tone neutral, success, warning or danger, followed by text. Tone may be omitted ({{badge:draft}} becomes neutral).
{{icon:check}} Icon by name. Allowed names: check, alert, dot, arrow-right, spark, chart, layers, shield, clock, inbox, info. Unknown names degrade to dot.
{{code:npm test}} Inline monospace text; the payload is shown literally.

Payloads are limited to 120 characters and must not contain braces or newlines. Other fenced code blocks are left untouched; a token written inside inline code is still recognized, which is a known limitation (see Limitations).

Fenced iui blocks

The fence info string is exactly iui. Two formats are accepted:

  • miopiik-ml (preferred): a small XML-like tag language. It is compiled to an AST, then validated.
  • iui/1 JSON AST: a JSON object with a root tree. Kept as a debugging and compatibility entry point; it goes through the same validator.

The miopiik-ml grammar uses tags for components, attributes for properties, JSON for structured values, and $state.* for bindings:

<ui title="Weekly activity" fallback="Mon 12, Tue 19">
  <state name="range" value='{"total":"31"}'/>
  <column gap="md">
    <metric label="Total" value="$state.range.total" unit="visits"/>
    <chart kind="line" series='[["Mon",12],["Tue",19]]' source="demo data"/>
  </column>
</ui>

Notes on the dialect:

  • Root element is <ui>; title and fallback are optional. fallback is used when the block cannot be rendered at all.
  • <state> either uses <state name="range" value='{"...":...}'/> or carries a JSON object body: <state>{"range":{...}}</state>.
  • Attributes may be quoted strings, JSON literals (options='[...]', rows='[...]'), numbers, booleans, or $state.* strings.
  • gap accepts none, xs, sm, md, lg, xl or a number. chart accepts kind="bar" or kind="line"; legacy type/data spellings are normalized to kind/series.
  • If a model forgets the fence, a line-start top-level <ui>...</ui> is still parsed as miopiik-ml; this is a tolerance path, not the documented format.

Component catalog

Component ML tag Notes
Root ui Wraps one block; title, fallback.
State declaration state Declares local initial values; not a rendered node.
Text text Plain text node.
Paragraph p, paragraph Holds inline primitives only: text, badge, icon, emphasis, code, link.
Badge badge text, tone. Tones: neutral, success, warning, danger, info, accent. Works inline and as a block.
Icon icon Inline primitive inside p/paragraph, or empty.icon. name, label; names come from a fixed list.
Emphasis b, emphasis Inline primitive inside p/paragraph. text, strong.
Code code Inline primitive inside p/paragraph. text; inline monospace.
Link a, link Inline primitive inside p/paragraph. text, href; only https://..., root-relative /... or #anchor.
Row / Column row, column Layout containers; gap, align.
Grid grid columns 1-6, gap, align.
Card card title, subtitle, gap, span, align; container.
Divider divider label optional.
Metric metric label, value, unit, delta, caption/note, tone. Values may bind to $state.
Table table columns (1-12 strings or {key,label} descriptors), rows (up to 200 arrays or objects), caption.
Chart chart kind = bar or line; series = point array or $state binding; source. Rendered as inline SVG.
Progress progress value >= 0, max positive, label, tone.
Callout callout tone, title, text; can contain children.
Empty empty text/title/description, icon.
Segmented segmented Local control; bind must be $state.*, 1-6 options, label.

The catalog is enforced by REGISTRY in shared/iui-ast.js. Unknown component types are not rendered.

Local state and bindings

Bindings are path reads only, never expressions: $state.a.b and $data.a.b. There is no evaluation, no function call and no eval. A segmented control may only bind to $state.*; pressing an option replaces that local value and re-evaluates dependent nodes in the same message. It does not send a message, call a tool or start a model turn. The current client provides no external data channel, so the data scope is empty and $data.* resolves to an absent value; it exists for a future read-only channel.

Legacy ink-view replay

Older sessions may contain fenced ink-view blocks with one of the retired widget specs (dataset, graph, timeline, text, choice, media, layout). The renderer maps those specs read-only into iui/1 before validation, so history keeps showing content instead of raw JSON. Mapping is best-effort: specs that cannot be mapped are left as their raw text (the current path does not display the old spec's own fallback field), choice actions are displayed as non-executable options, and nothing is written back to the session or to any ledger. The old protocol is documented as retired design history in docs/EXTRA-UI.md.

Plugin page

The native DSH plugin page lives at Plugins -> Installed -> MiOpIIk IUI and has two views:

  • Overview: a short explanation, a live preview rendered by the real renderer with fictional demo data (when rendering is enabled), inline semantic badges, and compatibility facts (version, protocol iui/1/miopiik-ml, access method, renderer state).
  • Configuration: the one real setting (show IUI in chat, browser-local), diagnostics (renderer connected, plugin version, protocol, preference key and current value, access method and patch detection), and a copyable Markdown example.

The page uses official DSH primitives when the running shell exposes them and plain theme-token elements otherwise.

Validation, budgets and error isolation

Validation is centralized in validateAst:

  • Component whitelist; props are normalized and checked per type.
  • Budgets: 120 nodes, depth 6, 60 chart points, 6 segmented options, 2000 characters per text node, 16384 bytes for state/table payloads, 200 table rows, 12 columns.
  • Unsafe keys (__proto__, constructor, prototype) are rejected in bindings, state and table keys.
  • Invalid root, depth overflow or node overflow rejects the whole block (fails closed) and shows the block's fallback text.
  • A fence that cannot be parsed into any AST at all is handed back to native Markdown as raw text, so content is never silently dropped.
  • An invalid subtree degrades only itself into a text node; its siblings and parent layout remain.
  • A renderer exception at the hook boundary falls back to a plain text span marked data-miopiik-embed-fallback.

Examples

Models produce these as ordinary answers. No tool call is needed; the model does not need to know how the renderer works. The following Markdown can be pasted into a DSH session directly.

Inline tokens mixed with normal text:

Build {{badge:success:passed}}, duration {{badge:neutral:42s}}; status {{icon:check}}.
Local check: {{code:npm test}}

A fenced block with local state, metrics, a chart, a table and a segmented control:

This release check finished {{badge:success:2/3}}:

```iui
<ui title="Release checks" fallback="3 checks this round: parse passed, validate passed, render under observation">
  <state name="range" value='{"total":"3","passed":"2","series":[["Parse",12],["Validate",9],["Render",7]]}'/>
  <column gap="md">
    <row gap="md">
      <metric label="Checks" value="$state.range.total" unit="items"/>
      <metric label="Passed" value="$state.range.passed" unit="items" tone="success" delta="+1"/>
    </row>
    <segmented label="Round" bind="$state.range" options='[{"label":"This round","value":{"total":"3","passed":"2","series":[["Parse",12],["Validate",9],["Render",7]]}},{"label":"Previous","value":{"total":"3","passed":"1","series":[["Parse",11],["Validate",8],["Render",6]]}}]'/>
    <grid columns="2">
      <chart kind="bar" series="$state.range.series" source="demo data"/>
      <table columns='["Check","Result"]' rows='[["Parse","passed"],["Validate","passed"],["Render","observing"]]'/>
    </grid>
  </column>
</ui>
```

The same content as an iui/1 JSON AST (useful for debugging and for tools that already emit JSON):

```iui
{"version":"iui/1","title":"Component usage","fallback":"Component usage: metric 2, chart 1","state":{},"root":{"id":"root","type":"column","props":{"gap":10},"children":[{"id":"m1","type":"metric","props":{"label":"Components","value":"3","unit":"items"},"children":[]},{"id":"t1","type":"table","props":{"columns":["Type","Count"],"rows":[["metric",2],["chart",1]]},"children":[]}]}}
```

The plugin's own output convention is injected by index.js. It tells the model to prefer ordinary Markdown and to use IUI only when a comparison, trend or local choice is clearer, and it warns against tool calls made just to draw a UI. The natural-output audit behind that decision is in docs/IUI-NATURAL-OUTPUT-AUDIT.md.

Compatibility

Item Requirement
DSH DSH Web only (web profile). Test baseline: DSH 0.2.1-rc.5. Other DSH versions are not verified; the chat patch is version-coupled.
Node.js >= 23.6 (declared in package.json engines).
DSH CLI dsh plugin --profile <profile> add/remove, available in the tested baseline.
Browser Chromium is used by the isolated DOM test. Other browsers are not in the verified matrix.

The fuller package, install and removal conditions are collected in docs/SUPPORT-MATRIX.md.

Install, upgrade, rollback

0.1.0-rc.4 is a prerelease and requires a local host patch. Install it only into a DSH profile you control, in an environment where you can restart DSH Web. Do not install it into a profile used by other people without their agreement.

Prerequisites

  • A DSH Web installation with a profile you can modify.
  • Node.js >= 23.6 and the dsh CLI on PATH.
  • A local checkout of this repository for the generator and verification tools.

Install

  1. Add the package to the profile:

    dsh plugin --profile <profile> add /absolute/path/to/miopiik-iui
    

    A tarball works too:

    npm pack --pack-destination .dsh/tmp/packs
    dsh plugin --profile <profile> add .dsh/tmp/packs/miopiik-iui-0.1.0-rc.4.tgz
    

    The repository also has a wrapper, tools/install-plugin.mjs, which is dry-run by default and refuses to write a running web profile unless --allow-running-profile is passed:

    node tools/install-plugin.mjs --profile <profile> --mode link            # dry-run
    node tools/install-plugin.mjs --profile <profile> --mode link --execute  # execute
    
  2. Verify that the committed browser bundle matches its sources:

    node tools/build.mjs --check
    

    client.js is generated from shared/, renderer.js, settings.js and package.json; a mismatch means the checkout is inconsistent and must not be installed.

  3. Create the chat hook once, in a controlled environment. The generator reads the installed @deepseek-ai/dsh-client-ui-chat from the DSH installation (not from the profile). It auto-detects a DSH installation in common global npm prefixes; set MIOPIIK_DSH_DIR if yours is elsewhere:

    MIOPIIK_DSH_DIR=/path/to/dsh/installation node tools/fork-chat-embeds.mjs
    MIOPIIK_DSH_DIR=/path/to/dsh/installation node tools/fork-chat-embeds.mjs --check
    

    The output directory is upstream/dsh-client-ui-chat-embeds/ (generated, gitignored), overridable with MIOPIIK_FORK_DIR; the patch file is patches/chat-markdown-embeds.patch, overridable with MIOPIIK_FORK_PATCH. --check is read-only: it compares the fork with what the generator would produce and validates the fork's dependency link, but creates nothing. On a machine without a DSH installation, or before a fork exists, it reports that and passes, because "no fork" means "no drift". Do not rebuild a fork that a running DSH service is loading. Background and the proposed upstream API are documented in docs/UPSTREAM-MARKDOWN-EMBED.md.

  4. Point only that profile's @deepseek-ai/dsh-client-ui-chat resolution at the fork. Do not overwrite the global DSH installation or shared node_modules used by other profiles:

    cd <profile>/node_modules/@deepseek-ai
    [ -e dsh-client-ui-chat ] && mv dsh-client-ui-chat dsh-client-ui-chat.bak
    ln -s /absolute/path/to/miopiik-iui/upstream/dsh-client-ui-chat-embeds dsh-client-ui-chat
    

    The fork is a separate package and resolves its own dependencies; the generator creates its node_modules link to the DSH dependency tree. Keep that link intact.

  5. Back up the profile configuration and the previous ui-chat resolution, confirm that no DSH task is running, restart DSH Web, then reload the browser. The renderer is enabled by default once both the plugin and the hook are loaded; open Plugins -> Installed -> MiOpIIk IUI to confirm.

Upgrade

  1. Replace the profile dependency with the new version (dsh plugin --profile <profile> add <new-checkout-or-tarball>).
  2. Run node tools/build.mjs --check in the new checkout.
  3. If the DSH version changed, regenerate the fork and the patch (node tools/fork-chat-embeds.mjs, then --check) and keep the profile's ui-chat resolution pointing at the regenerated fork.
  4. Restart DSH Web. Historical messages are not migrated: they are Markdown in the session log and are rendered by the new version on next view.

Uninstall

  1. Remove the plugin from the profile:

    dsh plugin --profile <profile> remove miopiik-iui
    
  2. Restore the profile's original ui-chat resolution (for example move dsh-client-ui-chat.bak back) and keep the global DSH installation untouched.

  3. Restart DSH Web. The chat returns to native Markdown rendering. The generated upstream/ directory and the browser preference may be deleted; historical sessions are unaffected.

Rollback

  • Quick rollback, no restart: turn off rendering on the plugin page, or set the browser preference directly and reload:

    localStorage.setItem("miopiik.markdownEmbeds", "0"); location.reload()
    

    This affects only the current browser and leaves session data untouched.

  • Full rollback: remove the profile dependency and restore the previous ui-chat resolution as in Uninstall, then restart DSH Web.

Without the host patch

If the plugin is installed but the ui-chat fork is not loaded:

  • iui fences in chat render as ordinary fenced code blocks; inline tokens appear as literal text.
  • The plugin page still works and its Overview preview still renders, because the renderer runs locally in the page.
  • Configuration diagnostics report that no patch was detected, instead of silently pretending rendering works.
  • The host output convention is still injected, so a model may keep producing IUI; those blocks simply stay as code blocks until the hook is installed.

Configuration

There is no server-side configuration schema. The pieces are:

Knob Where Effect
Browser preference miopiik.markdownEmbeds Browser localStorage "0" disables rendering in this browser; any other value (default: absent) enables it. Toggling reloads the page to rehydrate already-rendered messages.
Plugin page switch Plugins -> Installed -> MiOpIIk IUI -> Configuration The supported UI for the same preference: "show IUI in chat". It is browser-local and not synced across tabs, browsers or profiles.
Host patch marker globalThis.__miopiikMarkdownEmbedsHost globalThis in the browser Set to true by the ui-chat hook when it loads. The plugin page uses it to report "patch loaded" vs "no patch detected".
Embed registry globalThis.__miopiikMarkdownEmbeds globalThis in the browser Installed by the plugin bundle; the hook calls its segments, renderInline and renderBlock. If absent, the hook returns null and the native Markdown path is used.
Bundle patch cordis.patch.yml Package metadata (dsh.bundle.patch) Tells the profile how to load the plugin.

The rendering switch controls display only. Turning it off does not stop the host output convention from being injected into the model prompt, so the model may still write IUI syntax; it will be shown as Markdown code.

Security and permissions

  • No arbitrary HTML, JavaScript or CSS. Model output is parsed into a whitelisted component tree; there is no innerHTML, no eval, no dynamic style sheet and no script injection. Styles come from DSH theme tokens and fixed code.
  • No network requests. The renderer issues no fetch, XHR, WebSocket or external asset requests; charts are inline SVG and icons are built-in glyphs.
  • No model round-trips from controls. The only interactive control is the local segmented switch; it replaces local React state. It cannot call a tool, start a turn or write durable state.
  • No arbitrary event handlers. Model output cannot attach on* handlers; only the built-in control has behavior.
  • Bounded data and state. Node count, depth, chart points, options, text length, table size and state size are limited; prototype-polluting keys are rejected.
  • Safe links. Only https://..., root-relative paths and #anchors are accepted; other schemes degrade the link node.
  • Local error isolation. An invalid subtree degrades itself; an invalid document falls back to its fallback text; a renderer exception becomes a plain fallback span. The rest of the message remains native Markdown.
  • No logging. The plugin writes no logs and no files; the only value it persists is the single localStorage preference for the current browser.

Development and tests

npm test                      # node --test — offline unit tests
npm run check                 # npm pack + unpack + per-file syntax + import-graph check
npm run build:check           # client.js must match its sources
npm run icon:check            # icon asset constraints (static checks)
node tools/fork-chat-embeds.mjs --check
  • The offline suite covers the splitter, the miopiik-ml parser, iui/1 validation, table/chart normalization, legacy mapping, the settings bundle, and release readiness. It needs no DSH installation, no network and no browser.
  • The fork-generator regression is skipped when no DSH installation can be resolved (point MIOPIIK_DSH_DIR at one to run it); the read-only --check no-host path is always tested.
  • The isolated Chromium DOM test for the plugin page is skipped when no Chromium binary is available (override the path with CHROMIUM_PATH or MIOPIIK_CHROMIUM).
  • Checks that need a live DSH Web host or a real patched chat package are development scripts, not part of npm test; they read their host paths from MIOPIIK_* environment variables (see tools/dev-env.mjs) instead of hard-coded paths.
  • node tools/fork-chat-embeds.mjs --check is safe offline: without a DSH installation or a generated fork it reports that and exits successfully.
  • CI is defined in .github/workflows/ci.yml: unit tests on Node 23.6.0, 24.x and 26.x, the release check, the bundle sync check and the icon guard, plus a pack/install verification job.

The protocol sources of truth are shared/iui-ast.js and shared/miopiik-ml.js. renderer.js is the rendering source; client.js is generated and must never be edited by hand. Development-only end-to-end scripts live under tools/: e2e-gallery-replay.mjs, e2e-iui-user-sessions.mjs, e2e-playwright.mjs, e2e-dual-settings.mjs, e2e-legacy-replay.mjs, e2e-iui.mjs and e2e-iui-model.mjs. They require a running local DSH Web plus an isolated Playwright browser, must not send test messages to existing main sessions, and must not be treated as part of npm test. The script inventory and environment variables are documented in docs/DEV-TOOLS.md.

FAQ

Why is it still a release candidate?

Because in-chat rendering depends on an unofficial patch of a specific @deepseek-ai/dsh-client-ui-chat build, cross-token Markdown is not fully lossless, and streaming is not incremental. Calling it stable would hide those conditions from users. The gate list is in docs/IUI-V1-RELEASE-CANDIDATE.md.

What happens if I do not apply the chat patch?

The plugin still installs and its page preview works, but chat iui fences appear as ordinary code blocks and inline tokens remain literal text. The page reports "no patch detected" instead of failing silently. See Without the host patch.

Does it affect historical sessions?

No. Messages remain the original Markdown in the session log; rendering happens per view. Old ink-view blocks are mapped read-only and never rewritten; disabling rendering simply returns the message to its plain Markdown appearance.

Do I have to install MiOpIIk Agent too?

No. The two repositories are independent and can be installed together or separately. IUI has no dependency on the agent's tool surface, ledger or background execution.

Do messages change when I turn rendering off?

Only their appearance. The message text is unchanged; iui fences show as code blocks and inline tokens as text. Your browser preference is the only state that changes.

Limitations

  • Inline code is not protected from tokens. Inline tokens are matched in ordinary paragraph text, including text inside backticks; keep token examples in fenced code blocks.
  • Cross-token Markdown. A trusted token splits the Markdown text block. Bold/italic or other formatting that spans the token may break at the boundary; selection, copy and screen-reader order may differ from native Markdown. A real fix needs a DSH upstream Markdown AST extension point.
  • Streaming is not incremental. An unclosed or malformed fence displays as plain text until it closes, then the block materializes once.
  • Version-coupled experimental patch. The host hook is not an upstream API and is generated against anchors in a specific ui-chat package. A DSH upgrade may make the generator fail (loudly) until the patch is refreshed.
  • No upstream guarantees. The patch and the fork are local artifacts for controlled use; do not publish the fork as a replacement official package.
  • Legacy widgets are replay-only. The seven-widget protocol is retired; mapping is best-effort, choice actions do not execute, and unmappable specs keep their raw text on screen (the old spec's own fallback field is not used by the current render path).
  • Incomplete accessibility and theme matrix. Basic dark/narrow-screen checks exist; a full light/dark/high-contrast, keyboard and screen-reader matrix has not been verified.
  • Model compliance is not guaranteed. The output convention is a prompt section, so models may ignore it; the natural-output audit documents what was measured and what was not proven.

Contributing

Issues and pull requests are welcome, with the prerelease state in mind:

  • Change the protocol in shared/ and the renderer in renderer.js; then regenerate client.js with node tools/build.mjs and commit both source and generated output.
  • Do not edit client.js, patches/chat-markdown-embeds.patch or upstream/ by hand. The patch is generated; upstream/ is gitignored.
  • Keep the plugin dependency-free and offline. New components need whitelist, validation, budget and degradation behavior, plus tests.
  • Run npm test, npm run check and npm run build:check before opening a pull request. Host-dependent end-to-end verification needs a running DSH Web instance and an isolated browser; do not test against other people's sessions.
  • Keep the user's icon.svg asset byte-identical; npm run icon:check guards its constraints.

License

MIT. See LICENSE.

—/ 5

No ratings yet

Verified DSH bundle

Commit f218e1d0aa22

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout