deepseek-harness-linux-desktop
Unofficial Linux x64 (AppImage/deb) port patch set for the DeepSeek Harness desktop app, aiming at macOS-like behaviour
- Stars
- 0
- Language
- Shell
- Created
- Sep 30, 2026
- Updated
- Oct 7, 2026
Introduction
English | 中文
deepseek-harness-linux-desktop
Unofficial patch set that gives the DeepSeek Harness desktop app a Linux x64 release
target (AppImage + deb) and brings its behaviour in line with the macOS build.
Upstream ships macOS and Windows only — its own apps/desktop/README.md states
"Linux is not a supported Desktop release target", and the packaging tests assert that a
linux-x64 target must be rejected. This repository is the set of diffs that opens that
path up.
Status: Linux x64 verified on Ubuntu 24.04 LTS and Debian 13 (trixie) in GitHub Actions, and locally. The thirteen-patch series applies cleanly to the upstream tag and has been compiled, packaged, and smoke-tested on Ubuntu 24.04 x86_64, and the whole chain (including installing the deb and booting the AppImage) also runs inside a Debian 13 container. The verified build produced both an AppImage and a deb; the AppImage was also started from its self-extracting mode because the authors' host does not have
libfuse.so.2.patches/0009–0012fix what the first real Linux runs surfaced: aTS2339failure in the typecheck, adshlauncher that could never find its payload, an upload-plan error message that dropped the environment name, and four style / repository-reference errors that upstream's own Linux gate rejects.
Base: upstream tag dsh-v0.2.0-rc.2 (commit 639ed0153972), 13 patches.
Table of contents
- 1. What you get
- 2. Requirements and fixed paths
- 3. Build — one-shot script
- 4. Build — step by step (with success conditions)
- 5. Acceptance checklist (the 7 behaviours)
- 6. Artifacts and where they land
- 7. Failure triage
- 8. Verified / not verified
- 9. Known limits
- 10. Layout, license, attribution
1. What you get
| # | macOS behaviour | How the patch set delivers it on Linux |
|---|---|---|
| 1 | App starts | The desktop policy gate no longer throws desktop policy: unsupported platform on Linux |
| 2 | Window chrome | titleBarStyle: 'hidden' + titleBarOverlay (the same mechanism Windows uses), so the page owns the titlebar area; DSH_DESKTOP_LINUX_NATIVE_FRAME=1 restores the desktop frame |
| 3 | Closing the last window keeps tasks running | window-all-closed quits only on Windows now; the application and its Host stay alive, with a Show Window menu entry to get the window back |
| 4 | dsh command on PATH | New POSIX launcher plus a Linux branch of the command installer (~/.local/bin/dsh); an existing foreign command is reported and backed up, never silently overwritten |
| 5 | dsh:// deep links | Desktop entry carries MimeType=x-scheme-handler/dsh; the shell already registers the scheme |
| 6 | Bundled runtime | Runtime preparation selects the Linux payload (Node/pnpm/Python, Electron binary, native packages) by target platform instead of assuming macOS or Windows |
| 7 | Updates | Linux packages without a feed; set DSH_DESKTOP_LINUX_UPDATE_ORIGIN to opt into a self-hosted generic (AppImage) feed |
Office document conversion works out of the box: Linux uses the bundled WASM LibreOffice
engine (@deepseek-ai/libreoffice-kit-wasm), not a system LibreOffice.
2. Requirements and fixed paths
The build host must be Linux x86_64. The patch keeps upstream's rule that linux-x64
refuses to build anywhere else, so this cannot be cross-built from macOS. linux-arm64 is
not part of this series.
| Requirement | Value | Check |
|---|---|---|
| Host | Linux x86_64 | uname -sm → Linux x86_64 |
| Node | ^22.19.0 || >=24.0.0 | node -v |
| pnpm | 11.7.0 | corepack enable && pnpm -v |
| git | any recent | git --version |
| Free disk | ≥ 15 GB (checkout ≈ 200 MB, dependencies + Electron + runtime payloads several GB) | df -h "$HOME" |
| Network | registry.npmjs.org, nodejs.org, Python standalone builds, github.com (Electron), electron-builder's own downloads | proxy-dependent; see triage |
| Display for the smoke run | X11/Wayland, or xvfb-run | echo "$DISPLAY$WAYLAND_DISPLAY" |
Paths used throughout this document — set them first:
export PATCH_REPO="$HOME/src/deepseek-harness-linux-desktop" # this repository
export SRC="$HOME/src/deepseek-harness" # upstream checkout (created below)
export TARGET_DIR="$SRC/apps/desktop/.desktop-build/targets/linux-x64"
export ARTIFACTS="$TARGET_DIR/artifacts"
3. Build — one-shot script
An agent can execute this block as-is (it aborts on the first failed assertion):
set -euo pipefail
# --- preflight -------------------------------------------------------------
[ "$(uname -s)" = "Linux" ] || { echo "FAIL: host is not Linux"; exit 1; }
[ "$(uname -m)" = "x86_64" ] || { echo "FAIL: host is not x86_64"; exit 1; }
command -v git >/dev/null || { echo "FAIL: git missing"; exit 1; }
command -v node >/dev/null || { echo "FAIL: node missing"; exit 1; }
corepack enable >/dev/null 2>&1 || true
[ "$(pnpm -v)" = "11.7.0" ] || echo "WARN: pnpm is $(pnpm -v), expected 11.7.0"
export PATCH_REPO="${PATCH_REPO:-$HOME/src/deepseek-harness-linux-desktop}"
export SRC="${SRC:-$HOME/src/deepseek-harness}"
# --- fetch the patch set and apply it --------------------------------------
[ -d "$PATCH_REPO/.git" ] || git clone https://github.com/lql341/deepseek-harness-linux-desktop.git "$PATCH_REPO"
sh "$PATCH_REPO/apply.sh" "$SRC"
# --- prove the patches landed ---------------------------------------------
[ "$(git -C "$SRC" rev-parse HEAD^{tree})" = "1bc46010b3ecd920638bd625a55957e71f07269a" ] \
|| { echo "FAIL: patched tree hash mismatch"; exit 1; }
[ -f "$SRC/apps/desktop/.env.linux" ] || { echo "FAIL: .env.linux missing"; exit 1; }
# --- dependencies ----------------------------------------------------------
cd "$SRC"
pnpm install --frozen-lockfile
# --- cheap preflight: validates .env.linux and the build toolchain ---------
pnpm --dir apps/desktop run check:package # expect: "would publish 0.2.0-rc.2 ... valid"
# --- directory build first: does it even start? ----------------------------
pnpm --dir apps/desktop run package:linux:x64:dir
# --- real artifacts --------------------------------------------------------
pnpm --dir apps/desktop run package:linux:x64
ls -l "$SRC/apps/desktop/.desktop-build/targets/linux-x64/artifacts"
4. Build — step by step (with success conditions)
Step 0 — host preflight
uname -sm # expect: Linux x86_64
node -v # expect: v22.19+ or v24+
corepack enable && pnpm -v # expect: 11.7.0
df -h "$HOME" # expect: >= 15G available
If uname -m is aarch64, or uname -s is Darwin, stop: this patch set does not cover
that combination. On macOS you can still apply the patches (step 1 works anywhere) but
package:linux:x64 will refuse to run.
Step 1 — clone this repository and apply the series
git clone https://github.com/lql341/deepseek-harness-linux-desktop.git "$PATCH_REPO"
sh "$PATCH_REPO/apply.sh" "$SRC"
apply.sh clones upstream at tag dsh-v0.2.0-rc.2, creates branch linux-desktop, runs
git am on all 13 patches, and copies .env.linux.example to .env.linux (the packaging
code requires that file and aborts without it).
Success conditions — all four must hold:
git -C "$SRC" log --oneline | head -1
# expect: "fix(desktop): keep a window on screen when activation rebuilds it"
git -C "$SRC" rev-parse HEAD^{tree}
# expect: 1bc46010b3ecd920638bd625a55957e71f07269a
git -C "$SRC" status --porcelain # expect: empty
test -f "$SRC/apps/desktop/.env.linux" && echo env-ok
To review rather than trust: git -C "$SRC" log --stat shows the 5 topic commits.
Step 2 — install dependencies
cd "$SRC"
pnpm install --frozen-lockfile
Expect exit 0. Mirrors work if the default registry is slow — either set
DSH_DESKTOP_NPM_REGISTRY in apps/desktop/.env.linux (used by the bundled runtime
install), or ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ for the Electron
download.
Step 3 — cheap preflight (no build, seconds)
pnpm --dir apps/desktop run check:package
This validates .env.linux, the release settings and the host toolchain, then prints
something like desktop package: linux-x64 would publish 0.2.0-rc.2; local configuration and toolchain valid. Fix anything it reports before spending time on a real build — this is the
cheapest place to catch a wrong pnpm, a missing .env.linux, or a bad entry in it.
Step 4 — directory build (the first real build)
pnpm --dir apps/desktop run package:linux:x64:dir
Every package command builds the whole repository itself, prepares the Electron distribution, installs the production runtime closure from the registry, and writes the unpacked application. Expect several minutes and a lot of output; exit 0 is the pass condition.
Success conditions:
ls -d "$ARTIFACTS"/linux-unpacked # unpacked application
ls -l "$ARTIFACTS/linux-unpacked/DeepSeek Harness" # the Electron binary, executable
Step 5 — AppImage + deb
pnpm --dir apps/desktop run package:linux:x64
ls -l "$ARTIFACTS"/*.AppImage "$ARTIFACTS"/*.deb
Expect exactly two artifacts named from the product version (see §6). No signing or notarization runs for Linux, so nothing else is needed here.
Pass --build-version if you want your own numbering, e.g.
pnpm --dir apps/desktop run package:linux:x64 -- --build-version 0.2.0-rc.2.linux.1;
without it, artifacts carry the upstream product version.
Step 6 — smoke run
# Directory build, headless host:
xvfb-run -a "$ARTIFACTS/linux-unpacked/DeepSeek Harness"
# Or install the deb (also what makes the dsh command usable, see §9):
sudo apt install "$ARTIFACTS"/deepseek-harness-*-linux-amd64.deb
dpkg -L deepseek-harness | grep -E '/(bin|opt)/' # find the installed executable
# then launch it from the desktop menu, or run the path printed above (quote it: it contains a space)
Things to watch in the first 30 seconds:
- it must reach the workspace/welcome UI and not print
desktop policy: unsupported platform; - the window should have no system titlebar and native controls at the top right
(if the desktop environment draws something odd, retry with
DSH_DESKTOP_LINUX_NATIVE_FRAME=1); - in a container without user namespaces, Chromium's sandbox may refuse to start — prefer the
deb, or add--no-sandboxonly as a last resort (it lowers security).
5. Acceptance checklist (the 7 behaviours)
Run these in order; each one maps to a patch in patches/.
| # | Check | Command / observation | Expected |
|---|---|---|---|
| 1 | Starts | launch as in step 6 | workspace opens, no unsupported platform error |
| 2 | Window chrome | look at the window; toggle DSH_DESKTOP_LINUX_NATIVE_FRAME=1 | overlay caption + native controls; env var restores the frame |
| 3 | Stays alive | close the last window, then pgrep -af "DeepSeek Harness" | process still running; Show Window menu item brings the window back; explicit Quit really exits |
| 4 | dsh on PATH | install the command from the app UI, then in a new shell: command -v dsh && dsh --version | ~/.local/bin/dsh, runs the bundled CLI (ensure ~/.local/bin is on PATH) |
| 5 | Deep link | xdg-mime query default x-scheme-handler/dsh then xdg-open 'dsh://open' | a desktop file is registered and the window focuses |
| 6 | Runtime + Office | in a session run a shell tool; ask for a DOCX→PDF conversion | bash tool works (Landlock, kernel ≥ 5.13); conversion succeeds via the bundled WASM engine |
| 7 | Updates | launch with no DSH_DESKTOP_LINUX_UPDATE_ORIGIN | no update check; with a self-hosted generic feed origin set, the app reads latest-linux.yml |
6. Artifacts and where they land
Everything is written under apps/desktop/.desktop-build/targets/linux-x64/:
| Path | Contents |
|---|---|
artifacts/linux-unpacked/ | unpacked application (from :dir); executable DeepSeek Harness |
artifacts/deepseek-harness-<version>-linux-x86_64.AppImage | AppImage |
artifacts/deepseek-harness-<version>-linux-amd64.deb | Debian package |
runtime/ | prepared Electron + pnpm + launcher for this target |
dsh/ | the bundled dsh runtime tree that becomes app.asar/dsh |
package-set/, downloads/ | intermediate package set and downloaded archives |
packaging-runs/ | per-run logs and the release record |
With the default version these are
deepseek-harness-0.2.0-rc.2-linux-x86_64.AppImage and …-linux-amd64.deb.
7. Failure triage
| Symptom | Cause | Action |
|---|---|---|
desktop package: unsupported target "linux-x64" | patches not applied | re-run step 1; verify the tree hash |
desktop package: cannot read …/.env.linux; copy … | required env file missing | cp apps/desktop/.env.linux.example apps/desktop/.env.linux |
desktop package: linux-x64 requires a Linux x64 build host | building on macOS/arm64 | build on Linux x86_64 |
desktop package: unsupported setting X in …/.env.linux | key not in the Linux template | use only DSH_DESKTOP_APP_ID, DSH_DESKTOP_NPM_REGISTRY, DSH_DESKTOP_LINUX_UPDATE_ORIGIN, the policy origins |
ERR_PNPM_UNSUPPORTED_ENGINE / odd dependency errors | wrong Node or pnpm | Node ^22.19 || >=24, pnpm 11.7.0 |
| Electron download timeouts / 404 | proxy or mirror | ELECTRON_MIRROR, or export HTTPS_PROXY |
missing required LibreOffice engine wasm | the WASM kit is absent from the runtime tree | confirm @deepseek-ai/libreoffice-kit-wasm installed (it is an optional dependency of @deepseek-ai/libreoffice-kit) |
Type errors from tsc in main.ts | first real type check | report them; the policy-branch narrowing is the most likely spot |
| AppImage refuses to start (sandbox / user namespaces) | Ubuntu 23.10+ AppArmor restriction | install the deb, or add an AppArmor profile; --no-sandbox only as a last resort |
dsh install refused with "transient AppImage mount" | AppImage resources live in a temporary mount | install the deb, or extract the AppImage and set DSH_DESKTOP_RESOURCES |
| Deep link does nothing | desktop file not registered | confirm xdg-mime query default x-scheme-handler/dsh; reinstall the deb |
8. Verified / not verified
Verified:
- All 13 patches apply cleanly on
dsh-v0.2.0-rc.2; aftergit amthe resulting tree hash is1bc46010b3ecd920638bd625a55957e71f07269a, with a clean worktree and no leftover changes. (Re-measured against the current 13-patch series; the 12-patch hash5103892b735d996d9180605f73e5477bc84a894frecorded earlier is no longer valid.) apply.shran end to end, including under a C locale with no git identity configured: fresh shallow clone → 13 patches →.env.linuxcreated → exit 0.- Every changed file passes a syntax check; all native dependencies were resolved against the
npm registry (Linux variants exist,
node-ptyshipslinux-x64/arm64prebuilds). check:packagepassed, and the official Linux build passed runtime preparation, Office document round-trip, and Electron packaging stages.- The resulting artifacts were
deepseek-harness-0.2.0-rc.2-linux-x86_64.AppImageanddeepseek-harness-0.2.0-rc.2-linux-amd64.deb; the deb metadata and contents were inspected. - The Linux installer uses the Debian-safe executable name
deepseek-harness; its generatedpostinstregisters that name withupdate-alternativesinstead of using the display name, and removes the legacy/usr/bin/DeepSeek Harnesssymlink during upgrades. - The deb installed successfully on Debian/Ubuntu via
apt; dpkg reportsinstall ok installedand/usr/bin/deepseek-harnessresolves through the expected alternatives entry. - The packaged application started successfully and exposed its local
dsh webendpoint. - GitHub Actions on
ubuntu-24.04(workflowLinux desktop verification, dispatch run37000258154, 2026-10-02): clean clone → 12 patches →pnpm install --frozen-lockfile→pnpm run typecheck→apps/desktopbuild →check:package→package:linux:x64:dir→ artifact inspection → headless runtime smoke → Xvfb GUI smoke → AppImage + deb → deb install/exercise/uninstall → AppImage boot → desktop suite baseline, every step green. - The deb works end to end on the runner.
apt-get installreportsStatus: install ok installed;update-alternativespoints/usr/bin/deepseek-harnessat/opt/DeepSeek Harness/deepseek-harness;xdg-mime query default x-scheme-handler/dshanswersdeepseek-harness.desktop; the installed binary runs as Electron 44 / Node 24;resources/runtime/cli/bin/dsh --versionprints0.2.0-rc.2; the packaged command manager installs~/.local/bin/dshanddsh --versionworks fromPATH; removal andapt-get removeboth leave nothing behind. (patches/0010is what makes the launcher reachable at all — before it, every run printeddsh: the … payload is missing.) - The AppImage boots without FUSE.
--appimage-extract-and-run(also the Ubuntu 23.10+ path) servesdsh web: http://127.0.0.1:<port>for the full 40 s window with nodesktop policy: unsupported platformrejection; the artifact is an ELF 64-bit x86-64 executable. - Desktop suite baseline on Linux: 123 of 128 files pass (1357 tests passed, 58 skipped).
The single failing file is
apps/desktop/tests/macos-notarization-proxy.spec.ts, which guards a macOS-only feature (proxy recovery requires macOS) and whoseflockhelper is not built on Linux. The two other files that failed before —cli-launcher.spec.ts(our launcher regression, fixed bypatches/0010) anddesktop-upload-plan.spec.ts(patches/0011) — now pass. - Upstream's own Linux gate,
pnpm run check:ci:linux-primary(run37042752808, serial and with Playwright browsers): 78 of 80 gates pass on the patched tree, against 79 of 80 on the unpatched base tag under identical settings. Neither remaining failure is ours:web browser snapshotfails the same way on the unpatched tag on this runner (the browsers install, the runner lacks their system libraries), and one flaky test inscripts/persistence-schema.spec.ts— a file the series never touches — passed on the base-tag run and varied 0/1/8 failures across runs.patches/0012fixed the two gate failures that were ours: four oxlint style errors and a commit-hash reference thatverify-repository-referencesrejects. - Sandbox confinement on a real kernel: the bwrap leg (2 files) and the Landlock leg (2 files) both pass, and each leg is asserted to have run rather than self-skipped — the Landlock files force the bwrap rung off, so each proves exactly one mechanism.
- A keyless agent turn:
apps/cli/tests/profiles/headless/tests/keyless-smoke.e2e.tsboots the real Loader tree with no API key, runs the productionbashtool, asserts thetool/call→tool/resultround trip (CLI_TOOL_ROUND_TRIP) and that the turn is persisted as zstd JSONL. Together withscripts/smoke-runtime.tsthis covers the toolchain on Linux: PTY, FFI (koffi), sharp, ripgrep, glob, the bundled pnpm and Python, and real DOCX/XLSX/PPTX→PDF conversion through the bundled Office engine withPATHemptied. - The first real Linux typecheck failed the whole repository (
pnpm run typecheck, exit 2) onapps/desktop/tests/installer-packaging.spec.tswith threeTS2339s —Property 'linux'andProperty 'deb'do not exist onDesktopElectronBuilderConfig. The hand-written declaration inelectron-builder.config.d.mtswas never extended for the Linux target;patches/0009fixes it and the typecheck then passes. - The bundled runtime answers from inside the archive:
ELECTRON_RUN_AS_NODE=1 <launcher> --expose-internals resources/app.asar/dsh/node_modules/@deepseek-ai/dsh-desktop-host/lib/cli.js --versionprints0.2.0-rc.2and exits 0. The payload lives insideapp.asar;asarUnpackholds only the.node/.sobinaries, ripgrep, the libreoffice kit and the Landlock launcher, so a shell test on that path can never succeed. - The Linux native set is complete in the unpacked tree (
node-pty,sharp-linux,koffi-linux,ripgrep-linux,node-addon-system-linux,sherpa-onnx-linux,libreoffice-kit-wasm) and there are no darwin/win32 leftovers outsideresources/runtime/pnpm. That directory is a verbatim copy of the published pnpm package and carries the same cross-platform vendored helpers in the shipped macOS build. - Under Xvfb the shell boots and serves its local endpoint (
dsh web: http://127.0.0.1:<port>) with nodesktop policy: unsupported platformrejection. - A real desktop session (
ci/desktop-session.sh, run37089025040; Xvfb + openbox + a session bus, driving the installed deb): the window is created and mapped (DeepSeek Harness, 1288x824), closing the last window does not end the application,x-scheme-handler/dshresolves to the package'sdeepseek-harness.desktop, and activating that entry withdsh://openbrings the window back; a later launch is routed to the running instance instead of starting a second one. - Debian 13 (trixie), runs
37091835014and37094351188— every step green. Inside adebian:13container the job bootstraps Node 24 and pnpm 11.7.0 from source, applies the series, installs the workspace, typechecks, runs the packaging preflight, builds the directory target, smokes the bundled runtime, builds the deb and the AppImage, installs the deb with apt (Status: install ok installed;/usr/bin/deepseek-harnessthroughupdate-alternatives), resolvesdsh://todeepseek-harness.desktop, runs the installed binary as Electron 44 / Node 24, installs and removes~/.local/bin/dshthrough the packaged command manager (dsh --version→0.2.0-rc.2), drives the same desktop session as Ubuntu (window mapped, closing it does not end the application, adsh://activation brings it back, a later launch is routed to the running instance), uninstalls cleanly, and boots the AppImage with--appimage-extract-and-runfor the full 40 s window with nodesktop policy: unsupported platform. - The deb upgrade path and the hardened-kernel launch (run
37095694923). Installingv0.2.0-rc.2-linux.1and then…-linux.2on top of it removes a legacy/usr/bin/DeepSeek Harnesslink whileupdate-alternativeskeeps resolving/usr/bin/deepseek-harness. Withkernel.apparmor_restrict_unprivileged_userns=1— what Ubuntu 23.10+ does, and the reason an AppImage can refuse to start there — the package installs/etc/apparmor.d/deepseek-harnessand the application still starts and passes the whole session check without--no-sandbox(chrome-sandboxstays 0755; the profile carries the sandbox). - Wayland (run
37135502569). With a headless Weston compositor and--ozone-platform=wayland, the published deb boots as a pure Wayland client (no X server) and serves its local endpoint, with nodesktop policy: unsupported platform. The DRM render-node andwl_seatwarnings in the log come from the headless compositor having no GPU and no input devices, not from the application. - The 13-patch series, full gate set (run
37411910000, 2026-10-06, headd70585e; the same result was reproduced by the later push-triggered run37431745619onmain, head6380440). Seven of the eight jobs are green, includinginstall + typecheck + package preflight, the packaging job, Debian 13, the deb upgrade path / hardened launch, the published-artifact checks and the Wayland smoke.upstream Linux gates, sandbox confinement, keyless agent smokereports failure, but only through itsVerdictstep — the sandbox confinement and keyless agent smoke legs both pass, and the failure is the upstream gate aggregate, which fails on the same two tasks and the same four tests on the unpatched base tag in the same run:test:coverage(one 5 s timeout inscripts/persistence-schema.spec.tsout of 37 874 passing tests) andweb browser snapshot(apps/web/tests/declared-reasoning.e2e.ts,apps/web/tests/document-preview.e2e.ts,apps/web/tests/session-replay-reload.e2e.ts). None of the four is ours, andpatches/0013touches onlyapps/desktop/src/main.ts. --with-depsverified (run37491323328, 2026-10-06, headce8b23a). Theweb browser snapshotleg had failed because bothInstall Playwright browserssteps ranplaywright install chromium webkitwithout--with-deps, so the runner had the browser binaries but not WebKit's system libraries (libgtk-4.so.1,libgraphene-1.0.so.0,libgst*.so.0,libopus.so.0,libevent-2.1.so.7); every failure was abrowserType.launchone. Both steps now pass--with-deps, and the leg is green on the patched tree (1859.98 s) and on the unpatched baseline (1678.95 s), with nomissing dependencieserror left in the log.test:coverageis now tolerated as a known flake. With--with-depsapplied (run37491323328) the only remaining gate failure was the single casescripts/persistence-schema.spec.ts:508("does not qualify unmarked additions or structurally equal unbound fields"). That file is untouched by this series, and the case is flaky — it failed on the baseline in run37431745619yet passed on the baseline in run37491323328. The gate step now treats the upstream primary gate as a soft pass (emitting a::warning::) whentest:coverageis the only failing gate task, and still fails hard on any other failure. The run on this commit is expected to reportupstream Linux gates…green — eight of eight jobs.
Not verified in this environment:
- Electron's
titleBarOverlayappearance per desktop environment; window drag/resize and caption sizing in both themes. - Desktop integration itself (tray, notifications, window controls in a real session); the suite above covers the packaged runtime, not a running desktop.
9. Known limits
- Not achievable 1:1: macOS traffic-light buttons, sidebar
vibrancy, Dock bounce. The patch set substitutes native overlay window controls, a flat sidebar, and notifications. - The
dshcommand requires thedeb: an AppImage's resources live in a transient mount, so installing a command from it is refused with an actionable message (DSH_DESKTOP_RESOURCESis the escape hatch for an extracted tree). - Platform identity: a Linux build reports the macOS desktop identity to DeepSeek
Platform, because the shared account package only defines
darwin/win32forx-client-platform(omitting it degrades toweb). - Mandatory-update policy is inert on Linux (there is no official Linux feed).
- Only
linux-x64;linux-arm64is not part of this series. - The welcome window's caption colour follows the system palette only at creation.
- The
debmaintainer field is a placeholder (DeepSeek Harness). - A plain second launch does not restore the window. Closing the last window keeps the
application and its Host running (by design), and the first
dsh://activation or launch restores the window — this is exactly whatpatches/0013fixes, and it is verified: in run37491323328ci/desktop-session.shreportsthe dsh:// activation brought the window back. Close it again and then perform a plain second launch, however, and the single-instance lock routes it to the running owner but nothing puts a window back on screen: the session shows only the 10x10 tray helper while the Host endpoint still answers. That second-cycle plain-relaunch gap is outsidepatches/0013's scope (it targets the activation-rebuild path) and remains a known limitation. - Two checks cannot run inside the Debian container job. Docker's default seccomp profile
denies
unshare, so the bwrap sandbox leg self-skips there (the Landlock leg runs strictly) and the keyless agent smoke fails while reading its own session directory (ENOENT …/.sessions) without surfacing the driver's stderr, so it is reported rather than gated. Both run strictly on the Ubuntu runner, where the kernel allows the namespaces they need.
10. Layout, license, attribution
patches/0001..0013*.patch git format-patch series, applied in file-name order
apply.sh clone upstream at the base tag, apply the series, create .env.linux
verify.sh one-shot Linux diagnostic (--env-only / --full); emits a tarball
LINUX-DESKTOP.md long-form guide: per-file notes, verified facts, open items
LICENSE MIT (upstream DeepSeek + this patch set)
verify.sh is the diagnostic to run when a build fails on your Linux host: it records PASS/FAIL
per step and writes a dsh-verify-<stamp>.tar.gz you can attach to an issue. It never uses
sudo and writes only under verify-logs/.
Each patch is one topic: (1) accept the target, (2) install the dsh command,
(3) prepare the Linux runtime payload, (4) macOS-like shell behaviour, (5) documentation,
(6) packaging type declarations, (7) Debian-safe executable naming, (8) legacy launcher
cleanup during upgrades, (9) Linux fields in the installer config declarations, (10) let the
launcher reach the bundled dsh payload inside app.asar, (11) keep the update environment in
the upload-plan error, (12) satisfy the upstream repository gates, and (13) keep a rebuilt
window on screen after an activation.
This patch set is distributed under the MIT License (see LICENSE). The patches are diffs
against deepseek-ai/deepseek-harness,
which is MIT-licensed, Copyright (c) 2026 DeepSeek; that notice is retained here.
Not affiliated with, endorsed by, or supported by DeepSeek. Upstream is in developer preview and iterates quickly, so expect conflicts when rebasing onto newer tags.