Boot-time guard that repairs corrupt session logs, preflights plugin composition, vm-checks client artifacts, smoke-tests host apply() and quarantines crash-causing bundles, so a broken plugin can never brick startup.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-startup-guard
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:aokamoaki/dsh-startup-guard
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
Boot-time guard for DeepSeek Harness — repairs session logs, preflights the plugin composition, smoke-tests host
apply(), and quarantines crash sources before boot, so a broken plugin or corrupt log can never brick startup.
Overview
DSH is assembled from many third-party plugins: a missing package, a malformed patch, an unbuilt client artifact, or even a runtime exception thrown from a host apply() can crash the whole app at startup. dsh-startup-guard runs seven checks early in boot and can auto-repair / roll back / quarantine the source of the problem — it is a four-layer defense: parse → compose → execute → crash-containment, not just a set of file checks.
Zero configuration needed; typical overhead < 0.5s per boot.
Core capabilities
| # | Check | Behavior |
|---|---|---|
| 1 | Session log repair | Fixes session.jsonl[.zstd] seq corruption (drop duplicate row or truncate to the last committed row); frame-level detection and truncation of permanent zstd torn tails; prunes stale cache entries for deleted sessions. Originals are backed up to repair-backups/ |
| 2 | Manifest snapshot + fingerprints | Snapshots each profile's package.json / cordis.patch.yml / pnpm manifests plus link: plugin sources into plugin-snapshots/, recording per-bundle host/client/patch content fingerprints (keeps the latest N) |
| 3 | Bundle preflight + rollback | Verifies third-party bundle dirs resolve; rolls back to the newest fully-resolvable snapshot when missing (24h grace against rollback loops); broken manifests kept as package.json.broken |
| 4 | Composition preflight + repair | Detects duplicate entry ids, unresolvable name: rows, and fatal YAML shapes; rows whose name: no longer resolves are auto-disabled (with backup); fatal shapes write a block marker in strict mode that the launcher refuses to boot past |
| 5 | Client bundle validity | Verifies exports["./client"] exists, registers via __ModuleLoader__.load, and actually executes at load time in a vm sandbox; detects duplicate client ids across bundles; broken artifacts are auto-disabled |
| 6 | Host apply() smoke |
Runs every third-party plugin's apply() in a throwaway child process against a mock Cordis context, catching "crashes at startup" runtime errors (e.g. ReferenceError); results cached by content fingerprint |
| 7 | Crash quarantine | The launcher / desktop app writes a crash marker on an observed crash, and the host plugin also maintains its own boot marker (dsh-boot-state.json: written at apply, cleared on clean shutdown, left behind by abnormal exits). Either piece of evidence forces a full smoke sweep on the next boot and auto-disables failing plugins — closing the "crash → auto-disable → boot recovers" loop. Works for a bare dsh web with no launcher/shell too |
Quick start
dsh plugin --profile web add dsh-startup-guard # npm (prebuilt, skips build approval)
# or from source:
dsh plugin --profile web add github:aokamoaki/dsh-startup-guard
Published on npm:
dsh-startup-guard@1.0.0(npm page).
Restart dsh web. On first boot it scans/repairs sessions, snapshots the plugin manifests, smokes every third-party host entry, and writes the summary to ~/.dsh/dsh-preflight-report.json.
Modes & configuration
File: ~/.dsh/dsh-startup-guard.json (defaults when absent).
| Mode | Behavior |
|---|---|
report |
Detect and report only; never modifies anything |
fix (default) |
Auto-repair / auto-disable / auto-rollback |
strict |
fix + fatal composition shapes write a block marker; the launcher refuses to start and shows a dialog |
{
"mode": "fix",
"smoke": true,
"smokeTimeoutMs": 15000,
"clientVmCheck": true,
"clientFactorySmoke": false,
"quarantineOnCrash": true,
"autoRepairComposition": true,
"tornTailGraceMs": 300000,
"keepSnapshots": 10,
"exclude": ["some-bundle-i-trust"]
}
| Option | Default | Description |
|---|---|---|
mode |
fix |
report / fix / strict |
smoke |
true |
Run the host apply() smoke |
smokeTimeoutMs |
15000 |
Per-bundle child timeout |
clientVmCheck |
true |
Execute client artifacts in a vm at load time |
clientFactorySmoke |
false |
Also invoke the client factory (stub require) |
quarantineOnCrash |
true |
Crash marker forces a full smoke sweep |
autoRepairComposition |
true |
Auto-disable patch rows whose name: no longer resolves |
tornTailGraceMs |
300000 |
"Permanent torn tail" write-idle threshold |
keepSnapshots |
10 |
Number of snapshots kept |
exclude |
[] |
Bundles the guard never touches |
Auto-disable safety policy
Smoke runs in a mock environment: a failure may be a real bug or an environment gap (the plugin needs real DSH services). Therefore:
- A smoke failure alone never auto-disables (only reported +
fixNeeded); - the previous boot actually crashed (crash marker present) → failing plugins are auto-disabled;
- a plugin explicitly declares
"dsh": { "smoke": true }→ auto-disabled on smoke failure; - a plugin declares
"dsh": { "smoke": false }or is inexclude→ smoke skipped; - broken client artifacts (parse-class checks) → auto-disabled as before.
Wrongly disabled? Remove the matching - id: "xxx" / disabled: true entry from the profile's cordis.patch.yml (the original patch is backed up in repair-backups/).
Data locations
~/.dsh/
├── dsh-preflight.log # run log (rotated past threshold to .old)
├── dsh-preflight-state.json # scan state + smoke fingerprint cache
├── dsh-preflight-report.json # machine-readable summary of every run
├── dsh-crash-state.json # crash marker (written by launcher/desktop, consumed by guard)
├── dsh-boot-state.json # boot marker (written by host plugin, cleared on clean shutdown; abnormal exit = crash evidence)
├── dsh-preflight-block.json # strict-mode block marker (read by launcher)
├── dsh-startup-guard.json # config (optional)
├── repair-backups/ # original files before repair/disable
└── plugin-snapshots/ # manifests + link sources + fingerprints
Integration
Three entry points, so every crash scenario has a fallback — and a bare dsh web with no shell still gets crash quarantine via the host plugin's boot marker:
- Desktop client (dsh-desktop-app): runs
guard-runner.mjsas a child process before spawning the server; writes a crash marker on server crash, clears the boot marker on clean quit - Web launcher (dsh-launcher.ps1): calls
guard-sessions.mjsin the boot loop; writes a crash marker on crash; refuses to start if a strict block marker exists; clears the boot marker on normal stop - Host plugin: runs asynchronously early in the dsh web boot; writes/clears the boot marker and triggers quarantine from it
CLI:
node guard-sessions.mjs # fix mode
node guard-sessions.mjs --dry-run # report only, change nothing
node guard-sessions.mjs --mode report # same as dry-run
node guard-sessions.mjs --mode strict # fix + strict block
Core API:
import { runGuard } from 'dsh-startup-guard/lib/guard-core.mjs';
const r = await runGuard(home, { dryRun: true });
// r: { repaired, rolledBack, autoDisabled, broken, hostBroken,
// smokeUnresolved, issues, fixNeeded, blocked, crash, lines, ... }
Development
dsh-startup-guard/
├── lib/
│ ├── index.js # host entry (fire-and-forget, dynamic import)
│ └── guard-core.mjs # core: runGuard + all checks
├── test/guard-core.test.mjs # 73 tests (node:test, mock home, zero deps)
├── cordis.patch.yml # bundle registration
└── package.json
npm run check # node --check lib/*
npm test # node --test (73 tests)
npm run pack:check # npm pack --dry-run
node guard-sessions.mjs --dry-run # safe dry-run against a real home
Design principles:
- fire-and-forget: guard failures are logged, never thrown into the boot sequence;
- atomic writes: every file modification goes through tmp+rename;
- graceful degradation: if the session decoder is missing, only session scanning is skipped;
- single-instance lock:
dsh-preflight.lockserializes the multiple entry points.
License
Independent community plugin for DeepSeek Harness. Not affiliated with DeepSeek.
Links
More in this category
yjh051108/dsh-routing-suite★ 6995
One repository, three parts: a runtime injector for DSH plugin packages (inject, hot-reload, unload, promote a dev staging tool to the front, route self-heal, plus a settings-page plugin manager that lists, unloads and drags folders in to internalize), a task-aware reasoning-mode router agent preset (router-standard / router-spec / router-react), and a graded two-level task protocol whose six tools (commit_star, lock_stage, revise_do, edit_plan, mark_task, redteam_verdict) pin task state to disk. The injector implementation ships in-tree, so the install carries its own behaviour rather than a dependency list.
strukto-ai/mirage#dsh★ 3667
Swaps the filesystem and bash providers for a mirage virtual workspace: file tools and shell commands run over mounted resources (RAM, S3, Redis, Slack, Gmail, Notion, Postgres) instead of the host disk, with per-mount read/write/exec modes, per-command sandbox routing (monty, pyodide, quickjs in process; docker, e2b, daytona remote), and installed CLIs (git, gh, slack, linear, ntn, gws, or one you register) as head words in the virtual terminal.
hust-open-atom-club/oh-dsh★ 325
Community distribution: TUI, desktop, and Web UI as one bundle with layered installation.
weijiafu14/pi2dsh★ 208
Pi Host ABI compatibility engine: after one install, unmodified Pi extensions from npm mount as native DSH plugins with `dsh plugin add <pi-package>`. Verified end to end on stock DSH with pi-mcp-adapter (full MCP manager: OAuth, resources, prompts, MCP Apps, elicitation, sampling), @tintinweb/pi-subagents, pi-code, pi-hermes-memory and pi-background-tasks; `pi2dsh inspect` reports a package's compatibility before installing.
lire1131/dsh-undo-savepoint★ 167
Undo/redo & rollback system for DSH: every config change is auto-snapshotted; undo/redo/restore to any version from the WebUI or the offline CLI/GUI tools (works even when DSH fails to boot).
Fishquito7/dsh-skill-mcp-panel★ 158
Manages DSH skills and MCP servers from the web settings: skill cards with hot enable/disable, workspace scopes, groups, batch migration and drag-and-drop import, plus stdio/HTTP MCP CRUD with connection tests, secret redaction and the unified dsh-panel CLI.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.