Preface

The design philosophy of DeepSeek Harness (DSH) is “everything is a plugin.” When developing with or using DSH for multi-turn conversations, session titles often become cluttered and lack a unified context identifier.

Attempting to periodically rename sessions with external scripts does not work. At any given moment, only one writer can exist for a DSH session log (cross-process kernel lock), and the process holding the write handle is precisely the process currently running the conversation. External scripts will encounter SessionAlreadyOwnedError: 会话正被运行中的 Harness 独占.

Therefore, only the ctx.sessionTitle channel inside the session-running process can safely modify the title. This plugin is based on this principle: it registers a provider rather than a script, enabling dynamic renaming during the conversation.

What It Is

cn-scuo-oo/dsh-session-auto-title is a DSH plugin. After each conversation turn, it rewrites the session title into the fixed format MMDD|类型|主题 via one auxiliary model call.

The plugin is ready to use once mounted, and all fields have default values. To override the defaults, specify them in the profile’s loader configuration.

Behavior and Conventions

The plugin enforces a unified naming convention to ensure readability and consistency of session titles.

1. Format
The title format is MMDD|类型|主题, with the full-width vertical bar | (U+FF5C) as the separator.

2. Field Description
* Type: The date in the Shanghai timezone, taken from the timestamp of the session’s first human message, and not invented by the model.
* Category: Exactly one choice must be made from the following list: 功能|设计|修复|优化|发布|探索|文档|研究.
* Topic: Simplified Chinese, with a maximum length of 20 characters. It must not include workspace, project, directory, or file names, and must not repeat the category word.

3. Security and Validation
* Injection defense: Source messages are framed as a JSON array before being passed in, to prevent user content from breaking separators or forging fields.
* Output validation: Model output is first normalized and then reconstructed according to the convention. If the output is non-compliant, the plugin throws an error and logs a warn; it never writes a partial result, and the title remains the original title.
* Length guardrail: The entire string is normalized to 78 bytes, ensuring the prefix is never truncated.

Installation and Enablement

The installation process requires a local file dependency and configuration changes.

  1. Add the Local Dependency
    Place the plugin directory in any location and use it as a local dependency for the profile. Use the same package manager as the profile (pnpm or npm):
    cd ~/.dsh/profiles/<profile>
    pnpm add file:/absolute/path/to/dsh-session-auto-title
> Note: `file:` dependencies are **copied** into `node_modules` (not symlinked). After modifying the source code, rerun the installation command above.
  1. Configure the Bundle
    In the same profile’s package.json, add the plugin to the bundles list:
    { "dsh": { "profile": { "bundles": ["...", "dsh-session-auto-title"] } } }
  1. Restart
    Restart the DSH client. The plugin’s bundled cordis.patch.yml automatically disables the built-in session-title-llm provider and inserts this provider (ctx.sessionTitle accepts only one provider registration).

Configuration

The plugin provides several configurable options. The defaults cover most scenarios. If overrides are needed, provide them in the profile’s loader configuration:

Field Default Purpose
provider / model Not set Explicitly specify the title model route; both fields must be provided together, otherwise the request route recorded for that turn is reused
maxSourceMessages 8 Number of trailing human messages visible to the title model
maxInputBytes 8192 Byte limit for the framed input; if exceeded, the naming attempt is abandoned
maxOutputTokens 96 Output limit for the auxiliary call
timeoutMs 60000 Timeout for a single auxiliary call
maxTopicCharacters 20 Maximum topic length (counted by code points)
unpinSessions [] Session IDs to hand back for automatic naming; automatically removed after one release
afterEveryTurn true Whether to rename after every turn ends

Design Points and Limitations

1. Cadence-driven
The plugin uses the afterEveryTurn mode and calls sessionTitle.refresh() on turn/end. This addresses the issue of the service’s built-in cadence “silently stopping updating” in long-lived sessions: the service’s own all-prompts cadence depends on request/header being persisted, but a request sequence records only one header, so new turns cannot trigger an update. The plugin drives refresh from turn boundaries.

2. Manual rename support
For a title manually renamed by the user, source.kind === "user". When the plugin detects this state, it skips it directly, keeping it “pinned.” If you need to release the pin once, place the session ID in unpinSessions, after which regular automatic naming resumes.

3. Known Limitations
* Extra calls: Each conversation turn incurs one additional model call, adding a small amount of token cost and tens of milliseconds to a few seconds of latency.
* Title drift: The title drifts as the conversation progresses; it is regenerated every turn, not finalized only on the first turn.
* Fallback behavior: If the model call fails before the session’s initial naming, the title retains the platform fallback value (usually a truncation of the first message) and does not throw an error.

Dependencies

When running as a DSH plugin, the host must provide the following packages:
@deepseek-ai/schemastery, @deepseek-ai/dsh-llm, @deepseek-ai/dsh-session-title, @deepseek-ai/dsh-util-values.

Conclusion

dsh-session-auto-title resolves the permission and synchronization problems of DSH session renaming by using an internal provider and provides strictly structured titles. For developers who value session management standards, this is a tool that can be directly mounted and used.

Plugin Catalog
GitHub Repository