@orbisapp/remote-dsh is the DeepSeek Harness Web bundle for the Orbis remote
DSH host. It lives entirely in this repository, does not modify the DeepSeek
Harness source tree, and contains the DSH adapter, remote host composition,
plugin lifecycle, and Web settings client as internal modules of one package.
The bundle adds Settings → Plugins → Orbis to DSH Web. It owns pairing, trusted
devices, DSH-registered workspace access, and the dedicated Orbis listener.
It attaches each accepted transport connection to OrbisRemoteDshHost; v2
methods become reachable only after the peer completes the orbis.hello
handshake. The host advertises the canonical v2 protocol rather than legacy
dsh.* methods or raw DSH events:
orbis.models.list, orbis.sessions.list, orbis.sessions.create,
orbis.sessions.sync, orbis.sessions.entries,
orbis.sessions.prompt, orbis.sessions.update, and orbis.sessions.cancel;
replayable terminal entry.appended events with host-assigned cursors,
transient deltas, and ordered session-state updates;
DSH sessionPersistence and the native harness runtime as catalog/transcript
authority, with the node state storing only host identity, cursor indexes,
and idempotency claims. There is no host transcript copy, ACK journal, or
retention overlay.
The initial release supports two automatically discovered connection paths:
LAN: private IPv4 addresses are discovered automatically on the standalone
WebSocket listener (default port 47000).
Tailnet: Tailscale-style CGNAT IPv4 addresses are discovered automatically
on that same listener.
Both paths carry the same authenticated encrypted protocol. Pairing uses one
available address. After authenticating the host, the encrypted welcome
publishes the current LAN and Tailnet addresses.
Direct ws:// invitations are restricted to private/LAN, loopback, .local,
or Tailscale-style CGNAT addresses. A public direct endpoint must use WSS; the
bundle does not expose DSH Web as a remote endpoint and does not perform NAT
traversal.
Local installation
@orbisapp/remote-dsh · DSH Hub
cd public
pnpm install
ORBIS_DSH_HARNESS_DIR=/path/to/deepseek-harness pnpm --filter @orbisapp/remote-dsh run build
dsh plugin --profile web add link:$PWD/packages/orbis-remote-dsh
DSH_TELEMETRY_DISABLED=1 dsh web
The public workspace uses pnpm for every package. The @deepseek-ai/dsh-*
modules are peer dependencies supplied by the selected DSH profile; the DSH
source tree is deliberately not vendored into this repository. The shared
Orbis protocol packages are workspace dependencies and are bundled into the
plugin at build time. setup:dsh creates ignored symlinks into the checkout
supplied by ORBIS_DSH_HARNESS_DIR; it never copies Harness source into this
repository.
Adapter and host tests do not require the DSH SDK:
pnpm --filter @orbisapp/remote-dsh run check:core
For a local smoke check before installing the profile link:
pnpm install
ORBIS_DSH_HARNESS_DIR=/path/to/deepseek-harness pnpm --filter @orbisapp/remote-dsh run check
dsh plugin --profile web add link:$PWD/packages/orbis-remote-dsh
dsh plugin --profile web why @orbisapp/remote-dsh
The package also provides a one-command local Web launcher. It installs and builds
the bundle, installs it into the persistent DSH web profile, prints the active
profile dependency, and starts DSH Web on 127.0.0.1:3080:
pnpm run serve:dsh
The launcher reuses ~/.dsh/profiles/web and creates only the workspace root in a
disposable temporary directory. Supply the Harness checkout explicitly (the
launcher has no repository-specific default), and override the DSH home or keep
the generated workspace for inspection when needed:
ORBIS_DSH_HARNESS_DIR=/path/to/deepseek-harness pnpm run serve:dsh
pnpm run serve:dsh --port 3090 --keep
pnpm run serve:dsh --home "$DSH_HOME"
pnpm run serve:dsh --workspace-root /path/to/workspace
Before refreshing the local plugin link, the launcher runs the active pnpm in
the existing Web profile. This safely realigns a profile created by an older
pnpm store version. It also removes the former development package names
@orbis/dsh-orbis-remote and @orbis/remote-dsh, so obsolete and current Orbis
bundles cannot load together. The launcher probes available Node executables and selects one that
can safely refresh DSH's generated profile links; override it explicitly with
--node-bin or ORBIS_DSH_NODE_BIN when needed.
Open http://127.0.0.1:3080, then choose Settings → Plugins → Orbis. Stop the
launcher with Ctrl-C. DSH Web must remain on 127.0.0.1; the Orbis data-plane
listener binds all network interfaces separately.
dsh plugin --profile web why @orbisapp/remote-dsh prints the active local
package. Re-running add refreshes the profile link to the current build while
keeping the Harness-owned peer packages visible; a package version bump is not
required during local development.
Open the address printed by dsh web, choose Settings → Plugins → Orbis, and
save the computer name. The connection port is available under Advanced
Settings, while LAN and Tailnet addresses are discovered automatically. Turn on
remote access, create a pairing code, then scan it from Orbis on the phone. The
bundle restores remote access whenever dsh web starts.
Keep DSH Web on its default loopback host (127.0.0.1). Its privileged Orbis
management API refuses non-loopback origins and Host headers. The direct
transport listener is a separate, encrypted data-plane server and has no
management routes.
Mobile DSH E2E
Plain ws:// is permitted only for private LAN/Tailnet/local destinations.
Every candidate must complete the pinned host handshake before it can connect.
Start DSH Web locally: DSH_TELEMETRY_DISABLED=1 dsh web. Keep its Web
listener on 127.0.0.1.
In Settings → Plugins → Orbis, save the host name and port 47000. LAN and Tailnet
addresses are discovered automatically; do not advertise 127.0.0.1 or
localhost to a physical phone. Turn on remote access and allow inbound TCP
47000 through the desktop firewall when using direct routes.
Build a fresh Orbis custom development client, not only a Metro refresh.
iOS source configuration declares NSAllowsLocalNetworking and the local
network usage description; grant the resulting iOS prompt on first use.
Keep the phone on the same local network or connect both devices through
Tailscale, scan the pairing QR (or enter it manually), verify the safety
number, and pair.
In Orbis, open Remote, tap the enabled DSH server, choose an existing
DSH session, and submit a text prompt. DSH workspace creation remains in
DSH Web for mobile because orbis.sessions.create requires an opaque
registered workspaceRef.
On open, Orbis renders its encrypted per-host cache first and makes exactly one
once snapshot/replay refresh. It retains live delivery only for the session
where this phone submitted an unfinished run; navigating to another session or
away from the chat removes only the UI observer, never cancels that DSH run.
The present mobile configuration intentionally does not enable broad Android
cleartext traffic. Therefore validate this plain-LAN ws:// path on iOS; an
Android deployment needs a reviewed secure endpoint policy (for example WSS)
before it can claim the same physical-device flow.
State and credentials
The host private identity uses DSH credentials under
ORBIS_DSH_HOST_IDENTITY_V1.
Only non-secret host configuration and paired public keys are stored in
$DSH_HOME/orbis/dsh-remote-host.v2.json with owner-only permissions.
The host-owned v2 cursor replica is separate:
$DSH_HOME/orbis/dsh-remote-agent.v2.json. It contains session entry-id
indexes and idempotency claims only; it is not the DSH transcript authority,
does not store event payloads or ACKs, and owner-only permissions are not
payload-level at-rest encryption.
A pairing secret lives in memory only for its active invitation and is never
written to disk.
Server diagnostics are written as owner-only JSONL to
$DSH_HOME/orbis/dsh-remote-debug.jsonl (override with plugin logPath); the
file rolls to .1 at 8 MiB. Entries include lifecycle, peer, request method,
request id, session identity, duration, and redacted error metadata, but never
prompt content, transcript payloads, pairing secrets, access tokens, or
response bodies.
Workspace and session semantics
DSH's registered workspace service is the authority for new remote sessions.
A paired client can browse configured server roots with orbis.workspaces.browse
and convert a selected opaque folder ref into a registered workspace with
orbis.workspaces.register. Responses never contain absolute server paths.
The plugin's optional workspaceRoots array controls the exposed roots and
defaults to the browse directory picker's Home location. Every request resolves symlinks
and rechecks containment before listing or registration.
A new orbis.sessions.create request must pass its opaque workspace id as
workspaceRef; it never accepts a filesystem path:
The host resolves that ID through ctx.workspace, uses the registry's
canonical directory, and attaches the created session to the workspace. A
paired client cannot supply a filesystem path. Existing sessions are discovered
and projected through ctx.sessionPersistence, so they keep their persisted
DSH cwd and do not depend on current Orbis host configuration.
orbis.sessions.list remains a lightweight catalog read: it returns durable header
timestamps plus the title in DSH Web's persisted projection cache when one is
available. A missing or stale cache row only omits that display label; the
catalog never opens a historical transcript just to list it.
Closing a mobile page or an encrypted socket only detaches the remote observer;
it never cancels/disposes a DSH run. Only plugin/host shutdown closes the
owned DSH controllers.
Real DSH profile E2E (explicit opt-in)
The package includes a repeatable LAN-only runner at
scripts/real-profile-e2e.ts. It creates a disposable DSH home, profile
plugin link, workspace, loopback web port, direct transport port, and state
files; provisions an opaque workspace through DSH Web's real
/api/workspace.create RPC; then performs direct AuthPSK pairing followed by
authenticated reconnects through OrbisRemoteAgentV2Connection.
The runner covers driver/session discovery, opaque workspaceRef create/list,
snapshot sync, model catalog discovery and selection through DSH's shared
session gateway, short prompts, cursor-index reconnect replay, idempotent
writes, state permissions/no-secret assertions, and a full DSH Web restart. It
does not assert provider-generated text and it never uses a fake backend or transport.
Replay is bounded by the native DSH transcript and the persisted entry-id
index; the host does not maintain a second event log.
# from this package; without a provider key this still runs the real
# profile/pairing/model-selection smoke and skips only prompt/replay phases
ORBIS_DSH_REAL_E2E=1 pnpm run e2e:real
# provider credentials extend the same fixture through real prompt/replay phases
ORBIS_DSH_REAL_E2E=1 DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" pnpm run e2e:real
# fail instead of skip when dsh/provider prerequisites are absent
ORBIS_DSH_REAL_E2E=1 ORBIS_DSH_REAL_E2E_STRICT=1 pnpm run e2e:real
Useful controls are ORBIS_DSH_BIN, ORBIS_DSH_E2E_ROOT (a parent for the
new disposable fixture), and ORBIS_DSH_E2E_KEEP=1 (preserve the fixture for
local forensics). The runner
always sets an isolated DSH_HOME, binds DSH Web to 127.0.0.1, and removes
the ambient Orbis identity environment variable. The disposable runner
discovers the local LAN endpoint. The runner never touches
the mobile app or its integration tests.
The compatibility gate checks dsh --version (expected 0.0.1-rc.2), the
launcher --patch flag, and Web's --host/--port flags before creating a fixture. Set
ORBIS_DSH_EXPECTED_VERSION only for another explicitly reviewed DSH
profile; an unreviewed or missing CLI is a clear skip by default and a
failure in strict mode.
Host identity rotation is exercised only inside the disposable fixture: the
runner stops DSH Web, removes the isolated $DSH_HOME/.env identity, verifies
that an old pinned client is rejected, and verifies that a newly paired client
cannot open the old host-key-bound delivery state. It restores that fixture
file before cleanup. Production rotation still requires an explicit migration
API; the runner never deletes or mutates a user's profile.