DeepSeek Harness Plugin

PerryLink/dsh-output-styles

Stars ★ 13 Downloads (30d) 3,340 Category Development & Runtime Added 2026-08-15 npm dsh-output-styles

Runtime-switchable model output styles with Claude Code outputStyles parity, plus the output.render.* presentation protocol: a /style command, per-session persistence, systemPrompt injection, six built-in styles, a web picker, and a renderer registry with per-session/per-tool rules and /export.

Install

# from npm (prebuilt)

dsh plugin --profile web add dsh-output-styles

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:PerryLink/dsh-output-styles

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

dsh-output-styles

Switch the model's output style at runtime — one /style concise and every reply from now on is terse.

The Claude Code outputStyles equivalent for DeepSeek Harness: styles are Markdown files, the choice is persisted per session, and the body is injected at every prompt assembly.

Install · Configuration · FAQ · 简体中文 · English · Español · Português · हिन्दी

dsh plugin --profile <name> add dsh-output-styles

Community plugin, not affiliated with DeepSeek. Canonical repository: https://github.com/PerryLink/dsh-output-styles (Gitee is a mirror).

What it is

/style concise — and every reply from now on is terse; /style off — back to the project default. dsh-output-styles brings Claude Code's outputStyles to DeepSeek Harness: a style is a Markdown file (frontmatter for metadata, body as the model directive), six built-ins ship in the box, the choice lives in the output_style storage domain keyed by sessionId and survives restarts, and the current body is injected into the system prompt at every assembly, truncated at a configurable budget. Styles apply to the main conversation only; subagent sessions keep their own prompts (matching Claude Code).

How it works

flowchart LR
    U[You type /style concise] --> C[command registry]
    C -->|command/run logged| L[(session log)]
    C -->|put {style, source}| D[(output_style domain)]
    D --> R[OutputStyleRuntime]
    R -->|body at every assembly| S[systemPrompt section order 90]
    S --> M[Model request]
    M -->|full system prompt| H[system/message logged]

Everything the model sees is reconstructable from the session log — no new session event type, no agent-loop changes. The style name comes from command/run, the exact injected text from system/message, and the provenance marker { kind: 'dsh-output-styles' } rides in the domain record.

Demo

You > /style
      output style off
      concise — Terse, direct answers — minimal prose, no preamble. (Daily coding work, tool-heavy sessions, or when prompt length matters.)
      explanatory — Educational answers with short "Insights" that teach as you work. (Learning a codebase, onboarding, …)
      formal — Formal, precise prose with complete sentences and defined terms. (Reports, documentation, release notes, …)
      learning — Collaborative learn-by-doing mode with short "Insights" and small hands-on steps for the user. (Pairing, onboarding, …)
      proactive — Execute immediately, assume reasonable defaults, and prefer action over planning. (Routine multi-step work, …)
      step-by-step — Numbered reasoning steps with explicit intermediate results. (Debugging, design decisions, …)

You > /style concise
      switched to concise

You > 请只用一句话介绍你自己。
AI  > 我是运行在 DeepSeek Harness 插件化平台上、基于 deepseek-v4-pro 模型的 AI 编码代理。

Three-step setup

  1. Install (pick one channel):

    # git channel (latest main; the prepare script builds with production dependencies only)
    dsh plugin --profile web add github:PerryLink/dsh-output-styles
    # npm channel (published releases)
    dsh plugin --profile web add dsh-output-styles
    # tarball channel: pnpm pack in this repo, then
    dsh plugin --profile web add ./dsh-output-styles-<version>.tgz
    
  2. Minimal config (sane defaults; set the project default for new sessions as needed):

    - insert:
        - id: output-styles
          name: dsh-output-styles
          config:
            defaultStyle: concise
    
  3. Verify it works:

    dsh --profile web --dump-config | grep -A3 'id: output-styles'
    
    > /style
          output style off
          concise — Terse, direct answers — minimal prose, no preamble. (…)
    > /style concise
          switched to concise
    

Uninstall: dsh plugin --profile web remove dsh-output-styles (or remove the row from the profile patch).

Every PerryLink plugin is listed in the built-in DSH Desktop market: Market → Sources → Add source → paste https://perrylink-dsh-catalog.perrylink.workers.dev/catalog-source.json → select. Installation still requires the market's npm identity check and your confirmation.

Core capabilities

dsh-output-styles is the Claude Code outputStyles equivalent for DeepSeek Harness: a /style command that switches the model's output style at runtime, persists it per session, and injects it at every prompt assembly.

  • Style library — one Markdown file per style (styles/*.md); frontmatter for metadata, body = the model directive. Six built-ins ship in the box (concise, explanatory, formal, learning, proactive, step-by-step), including Claude Code-parity proactive and learning.
  • /style command — no argument lists styles (with descriptions) plus the current selection; /style <name> switches; /style off restores the project default.
  • Session-scoped persistence — the choice lives in the output_style storage domain, keyed by sessionId, and survives restarts.
  • System-prompt injection — a systemPrompt.section() contribution (order sectionOrder) injects the current session's style body at every assembly, truncated at a configurable budget.
  • Claude Code parity — keep-coding-instructions, force-for-plugin (force alias), outputStyles JSON compatibility, layered stylesDir directories, hot reload, and a project-default fallback that is live-editable from the Web Plugins page.
  • Renderer registry (output.render.*) — ctx.outputRenderers lets any plugin register a pure presenter, applied through the output.render/before waterfall; built-in renderers concise and step-by-step.
  • Per-session/per-tool rules — rules: [{ match: { tool: 'bash' }, style: 'concise' }] name the renderer for matching requests; live-editable from the Web Plugins page.
  • /transcript — render the current session to Markdown or sanitized HTML through the render pipeline; --save <path> writes the sanitized document to that workspace path after user approval. Every render keeps the original text beside the rendered one.

Commands & tools surface

Surface Kind Notes
/style command List styles, switch, or restore the project default
/transcript command Render the current session to Markdown or sanitized HTML; --save writes with approval
output_style storage domain Session-scoped style choice, keyed by sessionId
systemPrompt.section() contribution Injects the current style body at every assembly
output.render.* renderer registry ctx.outputRenderers + the output.render/before waterfall
style projection { options, currentValue } folded from settled commands
Web picker client entry dsh-output-styles/client decorates /style with a popup picker

Command reference

Input Outcome
/style List the current selection + one line per style (name — description)
/style concise Switch (durable write), switched to concise
/style Diagrams first Multi-word names are the whole remainder
/style off Restore the project default (settings default, then defaultStyle)
/style nope error: unknown output style "nope" (available: …)
/transcript Render the current session to Markdown through the renderer pipeline
/transcript md Render to Markdown (md is the shorthand for markdown)
/transcript html Render to sanitized HTML
/transcript --renderer=concise Render with one renderer forced (rules bypassed)
/transcript md --save report.md Render, then write the sanitized document to report.md after approval

Examples

These are the plugin's real entry points; install once, then call one.

Detailed example — command /style concise, output:

switched to concise

Observed from plugins/dsh-output-styles/src/runtime.ts:474-478; asserted in tests/runtime.spec.ts:91; README §Command reference line 194

Failure branch — input /style nope, output:

unknown output style "nope" (available: concise, explanatory, formal, learning, proactive, step-by-step)

Observed from plugins/dsh-output-styles/src/runtime.ts:213-214,474-475; plugins/dsh-output-styles/tests/runtime.spec.ts:118-125

Brief examples: /transcript · output_style

Style library

One Markdown file per style; frontmatter for metadata, body = the model directive. name defaults to the file name and may contain spaces (Diagrams first).

Field Default Meaning
name file name Switch target; letters, digits, spaces, and hyphens (off is reserved)
description — (required) One sentence shown in listings and the picker
whenToUse — Optional guidance appended to listings
keep-coding-instructions false Keep the harness prompt when true; replace it when false (Claude Code semantics)
force-for-plugin false Apply unconditionally, overriding any session selection; force is an alias, at most one style may set it

With compatJson: true, Claude Code outputStyles JSON entries ({ name, description, prompt }) load beside Markdown styles; unparseable entries are skipped with a warning.

Renderer protocol

The output.render.* protocol turns presentation into an extension point. A renderer is a pure presenter — presenter(text, context) maps args to display data, never touches the DOM — matched by tool name and content type, ordered by priority.

  • Waterfall first: every render request passes through output.render/before ({ text, context }); listeners must call next().
  • Rules: rules: [{ match: { tool: 'bash' }, style: 'concise' }] names the renderer for matching requests; ties break by priority, then rule order.
  • Built-ins: concise (whitespace compaction + budget truncation) and step-by-step (consistent step numbering).
  • Auditability: every render result carries { original, rendered, rendererId, changed }; the rendered text is what surfaces, the original stays reconstructable from the session log.

Web picker

The dsh.client entry decorates the host /style command's bare invocation with a popup picker: an "off" row plus one row per library style (description · whenToUse), the active row marked. Picking submits /style <name> through the command Remote, so every switch keeps the host's durable command lifecycle. The picker follows the Web UI's shipped zh/en locale pair.

Configuration

All tunables are Schemastery Config fields (changeable from cordis.yml). Invalid values fail the load.

defaultStyle and rules are declared volatile(), so on a host that composes the settings forms seam they are live, Web-editable fields: edit them under Plugins → dsh-output-styles in the Web UI and the running plugin adopts the new value without a remount. Every other field stays composition-only and needs a reload. A committed value is validated before it is applied — an invalid one is rejected and the running values are left unchanged.

Most-used keys:

Key Default Web-editable Meaning
stylesDir [] no Style-library directories, resolved against cwd; later entries override earlier ones. [] = the bundled styles/ only
maxStyleChars 4000 no Style-body budget (≥ 1); longer bodies are truncated with a marker
defaultStyle '' yes Style for sessions that never selected one; '' = no style. A name that is not in the live library is refused rather than injected
compatJson true no Load Claude Code outputStyles JSON entries (single objects or arrays)
sectionOrder 90 no Order of the injected section (0 = persona, 100–199 = tool guidance)
includeBuiltins true no Include the package's bundled styles/ as the lowest-priority layer
watchStyles true no Reload the library when a style file changes on disk
rules [] yes Per-session/per-tool render rules: [{ match: { tool?, contentType?, session? }, style, priority? }]
Key Default Web-editable Meaning
stylesDir [] no Style-library directories, resolved against cwd; later entries override earlier ones. [] = the bundled styles/ only
maxStyleChars 4000 no Style-body budget (≥ 1); longer bodies are truncated with a marker
defaultStyle '' yes Style for sessions that never selected one; '' = no style. A name that is not in the live library is refused rather than injected
compatJson true no Load Claude Code outputStyles JSON entries (single objects or arrays)
sectionOrder 90 no Order of the injected section (0 = persona, 100–199 = tool guidance)
truncationMarker "\n\n[style truncated]" no Marker appended at the truncation point
includeBuiltins true no Include the package's bundled styles/ as the lowest-priority layer
watchStyles true no Reload the library when a style file changes on disk
rules [] yes Per-session/per-tool render rules: [{ match: { tool?, contentType?, session? }, style, priority? }]
enableExport true no Register the /transcript command (Markdown/HTML session export, renderer-aware; --save writes with approval)
respectCoreOutputStyles true no When a core outputStyles service is detected, skip this plugin's prompt injection (keep hot-switch / rules / export)

Profile patch override example:

- insert:
    - id: output-styles
      name: dsh-output-styles
      config:
        defaultStyle: concise
        rules:
          - match: { tool: bash }
            style: concise

Migrating from 0.1.6 or earlier. Those versions kept two plugin-owned settings sections, output-style (style) and output-style-rules (rules). The 0.1.7 host deleted the API they were built on, so both sections are gone. Move any value you had there into the corresponding Config field — output-style.style → defaultStyle, output-style-rules.rules → rules — in your profile patch (cordis.yml), or set it on the Plugins page. Per-session choices made with /style are unaffected: they live in the output_style storage domain.

FAQ

The choice lives in the output_style storage domain, keyed by sessionId, and survives restarts. No other state is persisted and no network requests are made. Style bodies come from the styles/ directories and stylesDir; they are re-read at every assembly (with watchStyles on, they also hot-reload).

defaultStyle and rules are volatile() fields: they are live, Web-editable fields only when the host composes the settings forms seam. Otherwise they stay composition-only and need a profile reload. A committed value is validated — an invalid name is rejected and the running values are left unchanged.

There is no silent conflict. When the plugin detects a core outputStyles service it degrades to the incremental surface (hot-switch / rules / /transcript) and leaves prompt injection to the core; every /style and /style off reply carries a degraded coexistence mode note, and the style session projection exposes promptInjection: 'enabled' | 'disabled', so no surface implies the style is in force when it is not. The full argument is in docs/COEXISTENCE.md.

No network requests, no model calls. The plugin observes system-prompt/assemble and folds the current style body (truncated at maxStyleChars, 4000 characters by default) into the system prompt; every listener delegates through next(), so the chain is never short-circuited.

No. Styles apply to the main conversation; subagent sessions keep their own prompts, matching Claude Code.

Security boundaries

  • Public services only. Contributes systemPrompt, commands, storage, and settings; no engine / agent-loop / apiproxy / official-UI changes.
  • Model-visible ⟺ logged. Everything the model sees is reconstructable from the session log — no new session event type, no agent-loop changes.
  • Original always kept. Every render (and /transcript) keeps the original text beside the rendered one; sanitized HTML is used for HTML export.
  • Disk writes gated. /transcript --save writes only after the approval service grants it, and the written content passes through the sanitizeText pure function first; without an approval or fs service it writes nothing (fail-closed).

Permissions & data

  • Permissions: declares fs:read, fs:write, fs:watch, storage:read, storage:write, and settings:read in its workshop manifest.
  • Data: the style choice lives in the output_style storage domain (keyed by sessionId); no other state is persisted, no network requests.
  • Session log: the style name comes from command/run, the exact injected text from system/message; the provenance marker { kind: 'dsh-output-styles' } rides in the domain record.

Known limitations

  • Core coexistence. If a first-party outputStyles capability lands, this plugin detects its outputStyles service and degrades to the incremental surface (hot-switch, rules, /transcript) while leaving prompt injection to the core — see docs/COEXISTENCE.md and the exported detectCoreOutputStyles / coexistenceReport functions. Degraded mode is stated where you can see it: every /style switch and /style off reply carries a degraded coexistence mode note, and the style session projection exposes promptInjection: 'enabled' | 'disabled', so no surface implies the style is in force when it is not. (Before 0.7.0 the only trace was a ctx.logger.info line, which never reaches the session transcript.)
  • Main conversation only. Styles apply to the main conversation; subagent sessions keep their own prompts (matching Claude Code).
  • Truncation. Style bodies longer than maxStyleChars are truncated with a marker.
  • Skipped style files. A bad style file is skipped with a warning and never breaks the profile.

Interoperability with other DSH plugins

Verified against DSH 0.2.0-rc.2 (the runtime this README ships for) and the high-star plugin set surveyed on 2026-10-05.

This plugin does not interfere with other plugins, including the widely installed high-star ones:

  • No tool-name collision. Every tool is namespaced; no bare name owned by a shipped tool or another plugin is registered.
  • No service-key collision. It provides outputRenderers; that key is not a built-in seam and is not provided by any surveyed high-star plugin.
  • No slot collision. It registers no client slot key, so it cannot contend for a shadows-shipped-ui seat.
  • No HTTP route collision. It registers no webServer prefix.
  • No patch-layer collision. The bundle patch only inserts its own row; it never overrides a built-in row's config.
  • No global mutation. It does not patch prototypes, rewrite process.env, or replace the global fetch dispatcher.

Shared event listeners are non-interfering by construction. It observes the ordering-sensitive event system-prompt/assemble with ctx.on() — Cordis's broadcast registration, where every listener runs and none can starve another. Every listener here delegates through next(), so the chain is never short-circuited, and a mutation is applied to the value next() produced rather than returned in its place:

  • system-prompt/assemble — also used by dsh-routing-suite (7000★, 13 listeners).

Static evidence: dsh-plugin-doctor K10–K13 report pass for every check on this repository.

Conflict screening

Screened against the DSH ecosystem before development (2026-08 snapshot): no style/output-style repository under topic:dsh-plugin, no output-style category in the four major awesome lists, and no entry in the dsh-hub catalog. The closest neighbors — dsh-soul-md (persona) and dsh-claude-marketplace (output styles explicitly deferred to v0.2+) — are adjacent, not conflicting.

Compatibility

Surface Status
Harness DeepSeek Harness dsh-v0.2.1-rc.2 (adapted 2026-09-09): the session envelope keeps its ignorable field for stored-log read compatibility only — Session.append still cannot stamp it, so audit-gate behavior is unchanged. Verified 2026-09-11 against the dsh-v0.2.1-rc.2 checkout (full gate chain + profile install smoke).
Node ^22.19.0 || >=24.9.0
Platforms All (host + web client)
Model Any (system-prompt injection)

Differences from Claude Code

Claude Code dsh-output-styles
Style files .claude/output-styles at user/project/managed levels stylesDir directories + bundled styles/, later directory wins
Custom styles Markdown, frontmatter name/description/keep-coding-instructions/force-for-plugin Same fields (force-for-plugin accepted verbatim, force as alias) + whenToUse
Legacy JSON outputStyles array in settings.json Loaded verbatim (compatJson: true)
Taking effect After /clear or a new session Immediately — the system prompt re-assembles per request
Subagents Styles do not apply Same — subagent sessions keep their own prompts
Switching /config menu or outputStyle setting (the /output-style command was removed in v2.1.91) /style command + Web picker + the defaultStyle field on the Web Plugins page

Ecosystem & quality

Development

pnpm install
pnpm run typecheck     # both tsc projects
pnpm test              # vitest — 156 tests
pnpm run verify        # typecheck + tests + self-contained (the prepublishOnly gate)
pnpm run check:readmes # five-language README consistency gate
pnpm run build         # lib/ artifacts (host + client bundles)
pnpm pack              # tarball for dsh plugin add

Releases: pushing a v* tag whose suffix matches the package.json version triggers the Publish workflow — full verification, then an npm publish with provenance.

The README images are generated programmatically by scripts/gen-readme-assets.py: the hero is a 1440×576 WebP drawn with Pillow (zh/en × light/dark) and the structure diagram is a hand-written 1100×660 SVG (light/dark). Re-running it overwrites docs/assets/dsh-output-styles-hero-* and docs/assets/dsh-output-styles-flow-v5-{light,dark}.svg. This repository carries no benchmark data, so there is no evidence chart.

Topics: deepseek-harness, dsh, dsh-plugin, output-style, output-styles, claude-code

Family & thanks

This project is part of the DeepSeek Harness plugin family from PerryLink (all Apache-2.0). If it is useful, a star helps the next person find it — nothing is gated behind it.

  • @kskazuha — the Web style picker revival on 0.1.7 (#8).
  • @Bingtang1019 — the module-table handoff report for lib/client.js (#10).
  • @PerryLink — author and maintainer: plugin architecture, style library, bundle install, Web picker, five-language docs, and CI/release tooling.
Plugin Status
dsh-aqua-input-check
dsh-archive-check
dsh-auto-review
dsh-autotier 🧊 FROZEN — see the repo README
dsh-bid-ca-precheck
dsh-bid-qual-check
dsh-cert-mcp 🧊 FROZEN — see the repo README
dsh-checkpoint-rewind
dsh-click
dsh-composer-history
dsh-contract-stance
dsh-customs-doc-check
dsh-data-quality 🧊 FROZEN — see the repo README
dsh-demurrage-ledger
dsh-doublecheck
dsh-drill-script-check
dsh-eia-guide-check
dsh-emergency-plan
dsh-essay-rubric-check
dsh-evidence-check
dsh-export-ctl-check
dsh-fast
dsh-fmea-table-check
dsh-forecast-penalty
dsh-fund-research
dsh-github
dsh-gongwen-flow-check
dsh-gongwen-word-check
dsh-guard-plan-qc
dsh-hazchem-check
dsh-hazplan-check
dsh-hidden-risk-map
dsh-hs-classify
dsh-icd-rule-check
dsh-industry-research
dsh-lawcite-adapter
dsh-laya
dsh-lc-doc-check
dsh-learning-gap-check
dsh-library
dsh-local-ai
dsh-lsp-actions
dsh-mask
dsh-mcp-panel
dsh-medrec-qc
dsh-memento 🧊 FROZEN — see the repo README
dsh-nsfc-form-check
dsh-nurse-record-check
dsh-observe
dsh-origin-rvc-check
dsh-ota-review-check
dsh-output-styles
dsh-paper-doc-adapter
dsh-permission-rules
dsh-permit-report-check
dsh-pipeline-check
dsh-pleading-draft
dsh-plugin-doctor 🚫 RETIRED (repo archived)
dsh-plugin-guide
dsh-plugin-kit 🚫 RETIRED (repo archived)
dsh-plugin-upgrade 🚫 RETIRED (repo archived)
dsh-policy-brief-draft
dsh-power-loss-split
dsh-power-ticket-check
dsh-ppap-check
dsh-protest-deadline
dsh-railway-window
dsh-repair-order-qc
dsh-research-report
dsh-review-reply-check
dsh-rulefile-check
dsh-safety-brief-check
dsh-score 🧊 FROZEN — see the repo README
dsh-session-sync
dsh-site-log-check
dsh-skill-pack-security
dsh-soe-decision-check
dsh-soilwater-check
dsh-sop-sync-check
dsh-spc-gbt-adapter
dsh-talk
dsh-tender-extract
dsh-tender-matrix
dsh-test-drive
dsh-ticktick 🚫 RETIRED (repo archived)
dsh-translate
dsh-warranty-calc
dsh-budget 🧊 FROZEN — see the repo README
dsh-claude-move 🧊 FROZEN — see the repo README
dsh-defend 🧊 FROZEN — see the repo README
dsh-draw 🧊 FROZEN — see the repo README
dsh-reach 🧊 FROZEN — see the repo README
dsh-background-agents 🚫 RETIRED (repo archived)
dsh-session-pin 🚫 RETIRED (repo archived)
dsh-team-rooms 🚫 RETIRED (repo archived)

License

LICENSE (Apache License 2.0) © 2026 dsh-output-styles contributors

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.