Desk scans PATH in command-resolution order and refuses to install behind an
unidentified executable. Inspect every candidate:
type -a deskcommand -v desk
An npm link or checkout-provided command may already be the full CLI. Remove or
move only files whose ownership you have verified, then refresh shell lookup:
hash -r
If you set DESK_BIN_DIR, it must be an absolute canonical directory already on
PATH, with no earlier conflicting command.
Desk refuses a store written by Desk v0.3.1 or older
The manifest, the Channels paused store, the delivery-events ring and member
manifests changed shape at v0.3.2, and v0.3.2 is the last release that migrates
the older shape in place. The current release does not migrate: a reader that
meets the older shape refuses it and names the remedy, for example
session codex carries the retired tmuxSession key: this manifest was written by Desk v0.3.1 or older; this version does not migrate stores written by Desk v0.3.1 or older; boot Desk v0.3.2 once against this store (the last release that migrates it in place), then upgrade. Install v0.3.2 with the pinned
installer (DESK_VERSION=v0.3.2), start it once, then rerun the installer for
the latest release. A session you wrote into desk.yml by hand needs a
sessionId matching ^[a-z][a-z0-9-]{2,63}$, unique across the manifest;
sessions added through Desk receive one.
Terminals report missing because Desk cannot find moor
Desk preflights the Moor executable before starting the terminal daemon. It
logs the failure and keeps non-terminal workspace features available. Resolution
is explicit DESK_MOOR_BIN, then an attested same-release libexec/moor, then
an attested absolute moor found on PATH. Managed releases and the Docker
image include the pinned same-release binary.
Reinstall or rebuild a missing or corrupt bundle; use an absolute override only
when intentionally testing another build:
DESK_MOOR_BIN=/opt/moor/bin/moor desk serve
Terminal transport fails closed rather than reporting a healthy runtime that
cannot provision sessions.
This is an operating-system watcher limit, not a reason to change server modes.
Close unnecessary watcher-heavy processes and inspect the current limits. On
Linux, increase the user or inotify limits through your system configuration,
then restart the shell and desk serve --dev. The default Bun mode does not run
Vite’s source watcher.
If capture has output but the browser is blank, inspect terminal transport
health in Operations. If capture is empty, attach to the Moor
session directly through Desk:
OpenCode is a full-screen TUI. Its conversation scroll lives inside the app,
not in the daemon’s frozen scrollback like append-style Codex or Claude output.
Desk routes scroll based on terminal state so full-screen TUIs receive
page-scroll keys instead of the frozen scrollback overlay.
Then restart managed agent sessions so their launch environment and hook
configuration are active. Custom commands may require manual event integration.desk hooks install also covers every Codex profile in the manifest; a profile
whose directory is missing is reported as SKIPPED. A profiled Codex session
needs its hooks trusted inside that profile, separately from ~/.codex.
Desk binds a provider session only after the provider’s own transcript names
it with the session’s working directory. Check that the session’s hooks are
installed and trusted (above). Working directories are compared in one
normalized spelling, so /root/projects/ and /root/projects identify the same
working directory. Desk does not resolve symlinks: if the provider records a different
path for the directory, write that path in the manifest.
If startup reports a live legacy Channels owner, stop that process before
starting another Desk for the same home. An abandoned engine.pid whose PID
no longer exists is ignored. If the record is unreadable or invalid, inspect
~/.config/desk/channels/_engine/engine.pid and verify the old process is gone
before removing the artifact. The current runtime lease still excludes a
second server.
Open the channel delivery diagnostics console. Check whether the item is queued,
delivering, acknowledged, failed, or held by diagnostic state.Useful CLI checks:
Agent publication is refused or has unexpected authorship
The managed credential and session-to-member binding establish the author.
--as checks that expected name; it cannot select another agent or human.
Ask the operator to correct the roster/managed launch binding if it disagrees.
publication-binding-absent (HTTP 409) means this session has no local member in
the destination channel; mirrored members do not establish that binding. The
prepare/post hint gives the local operator the supported /api/channels/member-add
payload for the existing session and channel. The agent cannot call that route.
publication-binding-ambiguous means multiple local bindings, while
publication-binding-invalid means a binding to the reserved human identity.
The operator corrects the roster through participant management and reads back
exactly one local binding before the author retries with the retained draft and
requestKey. These refusals do not create a preparation or change channel history.
For a work reply, first retrieve and read context for the actual destination:
desk channels prepare channel-name --as member-name --thread msg-PARENT# Read the context; copy the exact Publication preparation ID and then draft.desk channels post channel-name --as member-name --thread msg-PARENT --preparation publication-ID "message"
needs-context requires that preparation ID on the write. needs-refresh
requires reviewing fresh applicable context while preserving the draft/requestKey.
publication-binding-unavailable requires the operator to initialize project
custody and bind the channel and session launch worktree to its genesis; a missing
managed cwd also needs manifest/launch repair. Work remains refused until the
binding and complete assignment are available. Use --reason first-contact only
for an introduction, --reason status for a progress report, or
--reason escalation to report the blocker. Read and pass the returned ID in each
case; changing the reason does not authorize work.
Channels preparation or publication reports a transport failure
transport-failed during prepare means no message was submitted. The diagnostic
includes a bounded cause such as timeout or ECONNREFUSED; it does not establish
that the owner stopped. Retry preparation and read the returned context before
drafting. Preparation has no message draft or publication request key to recover.outcome-unknown during post or edit means message acceptance is uncertain,
including when the response disconnects after its headers arrive. Keep the saved
draft and its requestKey, inspect channel history or message.byRequestKey, and
preserve the same body/key when retrying. An HTTP rejection keeps its own server
code, such as needs-refresh.
Custody shows recorded history but current context is unavailable
For custody- and publication- anchors, desk custody --anchor reads current
observations from the authenticated backend. Check DESK_API, backend availability
and the normal managed launch or operator authentication. A refused or unavailable
read preserves the exact local recorded context, names the current-context error
and exits nonzero. Retain the anchor and read it again after the backend or session
is restored. Reading history does not renew a preparation or authorize a write.
native-runtime-http-error with native-runtime-http-500 means the daemon
answered but its observation request failed. Report the status to the runtime
owner; it does not establish that the daemon or provider conversation is absent.
native-runtime-unavailable means a usable runtime observation is unavailable,
and native-runtime-response-mismatch means the response could not be validated
for the requested execution. These states keep custody checks closed.native-identity-unobserved means the accepted snapshot contains no provider
identity. A terminal execution can return this snapshot without a native producer
cursor. Reading the snapshot does not start an agent or bind a provider identity.
Desk discovers owning repositories from the selected root. Switch the editor
root or selected project to the directory you expect, then refresh the Git
panel.
Check that LSP is enabled in settings and that the project has a supported
language server path. Desk includes TypeScript, Python, and Rust integration
logic, but language servers still depend on the host environment and project
layout.
Desk never reads, transmits, or proxies them — but with agent profiles it
does own the directory they sit in, so the honest answer depends on how the
session runs.
Without a profile, the agent CLI authenticates into its own normal
location (~/.claude, ~/.codex) and Desk touches nothing.
With a profile, Desk points the CLI at ~/.config/desk/profiles/<id>
by setting CLAUDE_CONFIG_DIR or CODEX_HOME. The CLI writes its own
credential files (.credentials.json, auth.json) there. Desk creates the
directory 0700 and does not parse what the CLI puts in it.
The practical consequences: those files are as sensitive as the ones in your
home directory, and they are not covered by a backup of ~/.claude — see
the backup answer below.
Yes, but remember each browser is a view onto the same local Moor sessions and
manifest state. Coordinate operator actions when multiple people access the
same server.
Back up the whole of ~/.config/desk — that is the simplest correct answer,
because everything Desk owns lives under it:
Path
Holds
desk.yml
the manifest: projects, groups, sessions, profiles
channels/
every conversation, thread, upload, and delivery queue
notes/
markdown notes
profiles/
agent credentials for profiled sessions
claude/settings.json
the hook settings Desk hands Claude at launch
profiles/ is the one that hurts to lose. A profiled session authenticates
into its profile directory, so a backup that copies only desk.yml,
channels, and notes restores a workspace whose agents are all logged out.