Skip to main content

dsh-file-mount

11Stars0Forks0Issues0Watchers

Provides incremental file mounting for DeepSeek Harness: automatically tracks which lines of read files enter the model context, re-reads only supply missing or changed portions, and presents a billable "mounted files" dashboard on the web.

Evidence5/5methodologySourceInstallMaintenanceDSH versionSecurity scan
Machine-auditedInstall commandRepo verifieddsh-plugin topicLicenseREADMEAI wiki
Language
TypeScript
License
MIT
Branch
main
contextcordisdeepseek-harnessdsh-plugin

Install

cmdweb profile
$ dsh plugin --profile web add github:acefun29/dsh-file-mount

Run the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial

Install via your agent

Install the DeepSeek Harness plugin acefun29/dsh-file-mount for me: review the repository at https://github.com/acefun29/dsh-file-mount first, then run the install command and verify the plugin loads successfully.

Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.

One-Line Description

dsh-file-mount recaptures the context window wasted when "AI repeatedly reads the same file" — it maintains a ledger for DSH's read/write/edit tools tracking which lines of each file have already entered the model context, so repeated reads only supplement missing lines or lines changed on disk, plus includes a browser-side "Mounted Files" dashboard that displays the ledger and savings in real time.

Core Capabilities

  • Intercept read tool results, replacing mounted line ranges with a single "mounted" marker instead of stuffing entire content blocks into context repeatedly
  • When file disk content changes, use line-level diff to only supplement modified lines (append-only logs only add new tails; when middle sections are too large, split by unique line anchors using LCS)
  • Files the model just writes are automatically marked as "known" — subsequent reads are fee-exempt; edit marks expire but retain line fingerprint drafts for incremental comparison
  • Provides file_mount_forget tool, allowing the model to actively drop a file's mount and force the next read to resend the entire file
  • Register a "Mounted Files" tab on the web side: list each file, expand into line segments, show coverage maps (position of mounted lines in the full file), mark freshness with color ribbons, and display net savings with rough RMB conversion
  • Support compressed sensing: when DSH's standard compression checkpoint appears, old mount messages it shadows are no longer counted in the ledger, avoiding incorrect deduplication based on removed content

Technical Implementation

  • Language: TypeScript (build outputs lib/index.js + lib/client.js, dual-side release)
  • Key Dependencies: @deepseek-ai/cordis (Service/Context container), @deepseek-ai/schemastery (Config schema), @deepseek-ai/dsh-tools (defineTool to register file_mount_forget, tools/post-execute interception hook), @deepseek-ai/dsh-llm (createUserMessage to inject mount hints)
  • Architecture Pattern: Dual-sided Cordis plugin — cordis.patch.yml injects a plugin named file-mount into the host via bundle.patch (host side runs tools/post-execute hook for incremental deduplication), package.json#dsh.client registers file-mount-ui tab via conversation.view slot of dsh-client-ui-conversation (browser side renders dashboard); the ledger attaches structured source fields to standard user/message events, with host compaction/session recovery/browser folding sharing the same merge rules (mount-source.ts)
  • Entry Files: src/index.ts (host side FileMountService, exports name = 'file-mount'), src/client/index.ts (browser side apply(ctx), exports name = 'file-mount-ui')

Use Cases

During daily DSH and AI collaboration modifying a mid-scale project, the model frequently revisits package.json, config files, utility scripts, and UI component source files — most lines in these files have already entered context, and pasting them again just wastes the window. dsh-file-mount makes "reading the same book a second time" become just pasting bookmarks, only supplementing lines when the model truly needs new content; it's also suitable for having the AI confirm what it wrote after completing a file — the write action automatically makes the file "known," so reading it again incurs no token cost.

Prerequisites & Compatibility

DependencyMinimum VersionNotes
DeepSeek Harness0.1.0-rc.5 (tested)peerDependencies all declare ^0.1.0-rc.5; plugin injects into host via cordis.patch.yml, into Web client via dsh.client
Node.js^22.19.0 or >=24.0.0enforced by package.json#engines; dsh plugin installation chain also calls pnpm
PlatformmacOS / Windows / LinuxNo native modules; paths.ts only decides whether to fold case and drive letters based on process.platform === 'win32' during path normalization
Native ModulesNoneOnly depends on Node built-ins node:fs/promises, node:path, and the npm dependencies above

Installation

dsh plugin --profile web add github:acefun29/dsh-file-mount

This is the installation command users see on the landing page. The README notes that github: format currently only installs source (repo has no lib/ and no prepare script), the actual production path recommends pnpm dsh:install (the repo's built-in installation script builds a tarball then installs via file:E:/...tgz into web profile) or using pre-built dsh-file-mount.tgz from GitHub Releases. After installation, you must restart harness — just refreshing the web page won't activate it.

Configuration Options

ConfigTypeDescriptionDefault
enabledbooleanMaster switch; when off, all reads pass through natively, ledger stops writing entirelytrue
capacityintegerCapacity limit for file identity cache (mtime+size+sha256); mounted files are pinned by reference count and not subject to eviction32
ttlMsintegerCache safety valve: fallback re-read interval (ms) when mtime+size unchanged but content actually changed300000 (5 minutes)
maxPinnedFilesintegerMaximum number of mounted files to pin in a single session (LRU evicts least recently used when exceeded)256
minSavedTokensintegerIf net savings fall below this token count, skip this deduplication/increment; pass through natively, don't write to ledger, and don't count toward safety valve16
maxFingerprintBytesintegerFiles exceeding this byte size don't retain line-level drafts; can only remount entire file on changes1000000
maxManagedBytesintegerFiles exceeding this byte size are not managed at all, passed through as-is16777216 (16 MiB)
excludeGlobsstring[]These paths always pass through as-is, no ledger or dashboard[] (typical: ['**/node_modules/**'])
statsFilestringOptional: JSON file path for cross-session total ledger; host can read via ctx.fileMount.stats()Not set
freshnessEnabledbooleanWhether to enable "freshness" heuristic: when context nears window limit, mark earlier segments as expired and resend on next readtrue
freshnessThresholdnumberSegment position below this threshold (0..1) is marked as expired0.6
safeRationumberWhen current context / window is below this ratio, pressure is considered 0, no expiration0.95
safeTokensnumberOptional: absolute safe token ceiling; if set, overrides safeRatioNot set
pinAfterintegerAfter a segment is marked expired this many times, pin it — only resend at most once1
contextWindowintegerDefault context window token count used when session doesn't report window size128000
resendBudgetnumberOptional: segments estimated larger than this token count won't be removed from ledger even if expired, to avoid stuffing large segments back into contextNot set
valveReadsintegerAfter N consecutive full-coverage deduplications, the next read passes through native result and refreshes related segments (failsafe; 0=off)2

Configuration is written under the config node at the same level as cordis.patch.yml; schema validation and defaults are at src/index.ts:103-121.

FAQ

Q: What's the relationship between this plugin and DSH's built-in session compaction/context truncation?

A: They don't conflict and don't replace each other. Session compaction solves "how much original history fits in the current window," while dsh-file-mount solves "the same file content repeatedly stuffed into the window" — the former looks at context, the latter looks at file ledger; the two directions are orthogonal and can be enabled simultaneously. When compaction occurs, old mount messages shadowed by it are automatically removed from the ledger and re-anchored on next read.

Q: Why did the Web UI's read card become a generic card when reading files, losing the original file highlight/code block?

A: This is expected behavior. The plugin replaces the model-visible result text in tools/post-execute (deduplication marker or incremental body), and the UI's read card is rendered based on the result text, so it degrades to a generic version; the canonical value remains intact, unaffected downstream audit logs.

Q: After uninstalling or disabling the plugin, is my mount ledger still there?

A: The in-memory ledger is released when the session ends; no ledger files are stored on disk (unless statsFile is actively configured). When re-enabled, the ledger replays from the current session's injected message source fields — so if closed and reopened quickly, data is continuous; if you want to preserve cross-session cumulative stats before closing, you must first configure statsFile.

Q: The "Line Range" list for a file in the dashboard is too granular, hard to view — what can I do?

A: Click the collapse arrow on the left of the file lines to collapse all line segments for that file; the top bar provides search (fuzzy path matching) and sorting (by net savings or by path). Color ribbons only distinguish tiers and can't adjust thresholds — all freshness thresholds (freshnessThreshold / safeRatio / safeTokens / pinAfter) are adjusted in host configuration, not the dashboard.

Q: What if line-level diff misses changes during incremental line supplementation?

A: Silent misses don't happen. The plugin uses stat validation (mtime+size fast path + sha256) to confirm file identity; whenever file content changes, it branches on hash inconsistency; when line-level drafts are lost or changes are too large, it automatically falls back to "full remount" rather than abandoning the file. So misses can only happen in ① files exceeding maxFingerprintBytes without draft retention, or ② extreme cases where mtime+size unchanged but content actually changed — the latter is covered by the ttlMs safety valve.

Q: Can case sensitivity, soft links, or relative paths cause misidentification?

A: The ledger internally uses "absolute path + realpath + case folding (based on actual filesystem, Windows/default macOS fold, Linux doesn't)" as the unique key, which won't be circumvented by soft links or relative paths; the slip the model sees uses working-directory-relative paths (forward slashes), with working directory preferring session header.cwd, falling back to dsh-fs-local's cwd if none.

Learning Curve

Advanced — the default configuration works out of the box; ordinary users can benefit without understanding ledger, hash, or line-level diff; but to make dashboard metrics match expectations (like valveReads, pinAfter, safeRatio thresholds), you need to first understand DSH's "tool result → model context" chain and Cordis configuration mechanism.

Known Issues & Limitations

  • After compaction, "mounted" guarantees become invalid: mount content shadowed by checkpoint has left the model context, the plugin identifies and removes it via sourceEventSeqs, and re-anchors on next read; the browser UI's shadow list has no channel to sync, so old rows remain until the file's next remount
  • Incremental/dedup/remount all replace tool result text, so web-side read cards degrade to generic cards (canonical value intact, audit unaffected)
  • Depends on read/write/edit tool canonical value structure; if DSH changes these shapes, the plugin guard degrades to native passthrough and injects a warning into the session on first trigger (src/index.ts:872-885). Shape changes are pinned by integration tests
  • Files exceeding maxManagedBytes (default 16 MiB) and paths matching excludeGlobs are not managed, passed through as-is; the plugin doesn't do sampling fingerprints — sampling has "changed but not detected" risk
  • rc.6's custom session event types can't be safely persisted (persistence read path hard-rejects unknown types), so the ledger carrier uses structured source fields on standard user/message events instead of new custom event types
  • "Freshness" is heuristic: segment expiration doesn't mean content actually left context (only compaction does), but rather "attention has decayed, model basically can't see it" — so expired resend is intentional token overhead; sessions without usage data (like some adapters) show gray "unknown" and don't expire
  • Browser-side conversation view is paginated history window (default tail page 50 messages, loads earlier pages on scroll up), dashboard folding accumulates across snapshots, mount messages scrolling out of window still retain that file's rows in the list until the next remount
  • Dashboard features "click line to jump back to chat," cross-session total ledger display, and "file changed" real-time badge not yet implemented (no corresponding channel on browser side) — see config or logs for details
  • Installation note: On Windows, dsh plugin add . includes the drive letter in the profile path causing the plugin to install but not activate; must use pnpm dsh:install or pre-built tarball; npx @deepseek-ai/dsh may have long no-output on first run (it's pulling the full CLI package)

Read the usage guide →

Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.

Listing badge

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/acefun29/dsh-file-mount)

Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.

← Back to plugin directory