dsh-set-session-title
Manifest validModel-facing tool that renames the calling session through the harness session-title service.
dsh-set-session-title
A model-facing set_session_title tool for DeepSeek Harness (dsh) — the agent can rename its own session.
Why this exists
DSH owns session titles properly: they are log-only session/title events (zero tokens) served by @deepseek-ai/dsh-session-title, written either by a deterministic first-prompt fallback or by an optional LLM provider.
What is missing is a way for the agent to fix one. Automatic titling can produce a content-free result — observed on a real session: the provider overwrote a usable fallback with the bare phrase 会话标题 ("session title"), i.e. the instruction's own vocabulary echoed back (discussion #8289). The rename capability itself exists (SessionTitleService.rename(session, title), the GUI rename dialog, the host's own delivery path uses it), but 0.2.0-rc.2 exposes it to no model-facing surface:
- no tool;
- no
sessionCLI subcommand (pluginandduplicateonly); /apiguarded by an authority-bound signed cookie whose launch token is a per-processrandomBytes()value that is never persisted, so a local process cannot legitimately obtain it.
This plugin adds exactly that one existing service call as a tool. It does not touch authentication, storage, or the session log directly — the capability is granted by composing the row.
Behaviour
| Write | appends a session/title event with source: { kind: "user" } |
| Pinning | a user-sourced title is authoritative: in-flight automatic generation is superseded and later prompts schedule none (an explicit refresh is the deliberate unpin) |
| Scope | the calling agent's own session (exec.agent.session) |
| Normalization | trimmed, terminal control sequences removed, capped at the deployment's maxTitleBytes (dsh-base ships 80); input that normalizes to empty is rejected |
| Cost | changes no message in the conversation and adds no tokens |
Install
# recommended: git spec pinned to a release tag (reproducible, and immune to the tarball caveat below)
dsh plugin --profile <name> add github:CancerTiN/dsh-set-session-title#v0.1.1
# drop the #v0.1.1 fragment to follow the default branch instead of a pinned release
# a tarball URL works too — read the caveat below before picking one
dsh plugin --profile <name> add https://github.com/CancerTiN/dsh-set-session-title/archive/refs/tags/v0.1.1.tar.gz
The manifest declares dsh.bundle.patch, so add appends dsh-set-session-title to the profile's dsh.profile.bundles and its patch inserts the tool row into the composed tree.
Tarball-URL caveat. Under the pnpm bundled with the desktop app (11.7.0), a GitHub tarball URL installs once and then fails on every later resolve that reuses the same pnpm store —
ERR_PNPM_MISSING_TARBALL_INTEGRITY, where deleting the lockfile and--forceboth change nothing. Reproduced and reported upstream as discussion #8294. A git spec is unaffected because it resolves to a commit-addressedgitHostedentry, which pnpm does not subject to the integrity requirement; a tarball URL is still fine when the store has not seen it (or on a newer pnpm).
On 0.2.0-rc.2 the desktop app picked the tool up without a restart (the client-side tool schema updated mid-session and the call succeeded immediately). Other builds may need the profile restarted.
Requirements
Both injected services ship with dsh-base, so the default web / desktop / headless compositions satisfy them:
| service | role |
|---|---|
tools | tool registry |
sessionTitle | @deepseek-ai/dsh-session-title (row id session-title) |
A composition missing either one fails loud at load instead of registering a tool that cannot work.
Usage
Ask the agent, or call it from a skill. Argument:
{"title": "安装终端插件并核验连通性"}
Result:
{"title": "安装终端插件并核验连通性", "eventSeq": 1307}
Read back either way (both should show the new title):
# the projection cache the GUI reads; seq matches the returned eventSeq
python3 -c "import json;print(json.load(open('$DSH_HOME/storages/session_projcache/sessions/$DSH_SESSION_ID.json'))['record']['rows']['title'])"
# the durable log; the last session/title event's source.kind should be "user"
zstd -dc "$DSH_HOME"/sessions/*/"$DSH_SESSION_ID"/session.v4.jsonl.zstd | grep session/title | tail -1
Why this package has zero dependencies
This is a hard constraint, not a style choice.
Declaring an in-box package (for example @deepseek-ai/dsh-tools, the documented home of defineTool) as a dependency makes pnpm materialize a second copy inside the profile. Module identity then splits for a module-local Symbol that keys a runtime surface of the tool registry, so ctx.tools[TOOL_RUNTIME_SCHEDULER] reads back undefined inside dsh-agent-loop and every tool call in that profile fails — bash, read, and this plugin's tool alike — with a bare Cannot read properties of undefined (reading 'prepare'). Reproduced and isolated on 0.2.0-rc.2; written up in discussion #8287.
So lib/index.js imports nothing and the tool definition is hand-written JSON Schema. ctx.tools.register() requires only output: { schema, render } plus a schema inside the supported subset (type / properties / required / additionalProperties / items / enum / const and the description annotation) — which is what defineTool compiles a declaration into. The trade-off: register() does not wrap execute with schema validation, so the single argument is checked by hand.
Verified on
@deepseek-ai/dsh-desktop-runtime 0.2.0-rc.2, macOS, session format v4 — both a headless profile and the desktop app's live session:
{"type":"tool/call","seq":1306,"data":{"name":"set_session_title","arguments":"{\"title\":\"安装终端插件并核验连通性\"}"}}
{"type":"session/title","seq":1307,"data":{"title":"安装终端插件并核验连通性","messageSeqs":[],"source":{"kind":"user"}}}
messageSeqs: [] is the signature of rename(): the title is explicit, not derived from a prompt.
Limitations
- Only the calling session can be renamed; there is no cross-session rename and no target-id argument.
- A non-agent caller (plain host-side execution) is rejected.
- A deployment that does not compose
session-titlefails loudly at load — deliberate, so the tool can never appear without the capability behind it.
Uninstall
dsh plugin --profile <name> remove dsh-set-session-title
Titles already written stay in the session log: a title is a log fact, not plugin state.
License
MIT
Comments
Loading…
From the same category
DeepSeek Harness plugin for Reactive Resume: bridges your resumes and job applications into a Harness session over MCP.
★ 41.7k
↓ 143/wk
MIT
Aug 24, 2026
dsh plugin --profile web add dsh-plugin-reactive-resumeby Tencent
Let AI agents use your real, logged-in browser without interrupting your work. CLI + extension for browser automation across any shell-capable AI agent.
★ 8.5k
↓ 5.9k/wk
MIT
TypeScript
Oct 10, 2026
dsh plugin --profile terminal add @wxg-prc-cpg/browser-skill-dsh-pluginby yjh051108
dsh-routing-suite — injector + router-standard kit: install the runtime injector first, then the task-aware reasoning-mode router preset (measured P1-P23).
★ 7k
MIT
JavaScript
Sep 18, 2026
dsh plugin --profile web add @dsh-external/dsh-super-injectorby Q00
Agent OS: the agent gets smarter on its own. We just hold the line: Interview-gated, staged evaluation, budgeted evolution loop. MCP server, 14 runtimes: Claude Code, Codex CLI, Gemini CLI, OpenCode,
★ 6.2k
MIT
Python
Oct 7, 2026
by dsh-market
The plugin market inside DeepSeek Harness — browse, search, one-click install · DSH 可视化插件市场
★ 6k
↓ 95.5k/wk
MIT
TypeScript
Oct 9, 2026
dsh plugin --profile web add dshmarketby superdesigndev
OpenRouter for agent tools. Join community here: https://discord.gg/6mQYYfFMAn
★ 4.9k
NOASSERTION
Python
Oct 10, 2026
dsh plugin --profile web add treg-dsh