* feat(bwrap): support {src, dst} mount form for distinct host/sandbox paths
Extends coworkBwrapMounts (#339) so additionalROBinds and additionalBinds
accept entries of the form { src, dst } in addition to the existing string
form. This unlocks the persistent /tmp use case: the default --tmpfs /tmp
gets wiped between Bash tool calls because of --die-with-parent, and the
old string-only API (--bind p p) had no way to map a host directory under
$HOME onto /tmp inside the sandbox without exposing the host /tmp itself.
Validation:
- src: same checks as the string form (absolute, not in
FORBIDDEN_MOUNT_PATHS, $HOME constraint when RW)
- dst: absolute and non-forbidden only — the $HOME constraint is
intentionally skipped since the whole point of the form is to map
outside $HOME (e.g. /tmp)
- malformed objects are filtered out with a warning, matching the
existing string-validation behavior
Doctor (--doctor) renders the object form as "src -> dst" in both the
Python and Node parser branches.
100% backwards compatible: the string form is preserved unchanged. The 36
existing tests pass; 13 new tests cover accept/reject paths, mixed
string+object configs, the persistent-/tmp recipe end-to-end, and the
doctor rendering (58/58 total).
Closes #530
---
Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <claude@anthropic.com>
* docs(configuration): document {src, dst} mount form
Refs #530
---
Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <claude@anthropic.com>
* chore(bwrap): address PR #531 review feedback
- doctor: warn when an additional mount's dst lands on a default RO
mount (/usr, /etc, /bin, /sbin, /lib, /lib64, or subpaths). bwrap
honors the later mount, so the user's bind silently replaces the
default — a config footgun, not an escape, but worth surfacing
(RayCharlizard issue 1)
- docs(configuration): note the shadowing implication under
"Distinct host/sandbox paths" (RayCharlizard issue 2)
- test(bwrap-config): pin the reject contract for dst under a
forbidden path (e.g. /proc/self), beyond the existing exact-match
case (RayCharlizard issue 3)
- bwrap-config: harmonize the rejected-mount warning text — the
string-form path now reads "rejected mount" like the object-form
variants (RayCharlizard issue 4)
Tests: 61/61 passing (3 new: 1 reject-subpath + 2 doctor shadow
positive/negative).
Refs #530
---
Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <claude@anthropic.com>
---------
Co-authored-by: Claude <claude@anthropic.com>
5.2 KiB
Configuration
MCP Configuration
Model Context Protocol settings are stored in:
~/.config/Claude/claude_desktop_config.json
Environment Variables
| Variable | Default | Description |
|---|---|---|
CLAUDE_USE_WAYLAND |
unset | Set to 1 to use native Wayland instead of XWayland. Note: Global hotkeys won't work in native Wayland mode. |
CLAUDE_MENU_BAR |
unset (auto) |
Controls menu bar behavior: auto (hidden, Alt toggles), visible / 1 (always shown), hidden / 0 (always hidden, Alt disabled). See Menu Bar below. |
Wayland Support
By default, Claude Desktop uses X11 mode (via XWayland) on Wayland sessions to ensure global hotkeys work. If you prefer native Wayland and don't need global hotkeys:
# One-time launch
CLAUDE_USE_WAYLAND=1 claude-desktop
# Or add to your environment permanently
export CLAUDE_USE_WAYLAND=1
Important: Native Wayland mode doesn't support global hotkeys due to Electron/Chromium limitations with XDG GlobalShortcuts Portal. If global hotkeys (Ctrl+Alt+Space) are important to your workflow, keep the default X11 mode.
Menu Bar
By default, the menu bar is hidden but can be toggled with the Alt key (auto mode). On KDE Plasma and other DEs where Alt is heavily used, this can cause layout shifts. Use CLAUDE_MENU_BAR to control the behavior:
| Value | Menu visible | Alt toggles | Use case |
|---|---|---|---|
unset / auto |
No | Yes | Default — hidden, Alt toggles |
visible / 1 / true / yes / on |
Yes | No | Stable layout, no shift on Alt |
hidden / 0 / false / no / off |
No | No | Menu fully disabled, Alt free |
# Always show the menu bar (no layout shift on Alt)
CLAUDE_MENU_BAR=visible claude-desktop
# Or add to your environment permanently
export CLAUDE_MENU_BAR=visible
Cowork Sandbox Mounts
When using Cowork mode with the BubbleWrap (bwrap) backend, you can customize
the sandbox mount points via ~/.config/Claude/claude_desktop_linux_config.json
(a dedicated config for the Linux port, separate from the official
claude_desktop_config.json):
{
"preferences": {
"coworkBwrapMounts": {
"additionalROBinds": ["/opt/my-tools", "/nix/store"],
"additionalBinds": ["/home/user/shared-data"],
"disabledDefaultBinds": ["/etc"]
}
}
}
| Key | Type | Description |
|---|---|---|
additionalROBinds |
(string | {src, dst})[] |
Extra paths mounted read-only inside the sandbox. Accepts any absolute path except /, /proc, /dev, /sys. |
additionalBinds |
(string | {src, dst})[] |
Extra paths mounted read-write inside the sandbox. src is restricted to paths under $HOME for security; dst is unconstrained. |
disabledDefaultBinds |
string[] |
Default mounts to skip. Cannot disable critical mounts (/, /dev, /proc). Use with caution: disabling /usr or /etc may break tools inside the sandbox. |
Distinct host/sandbox paths ({src, dst} form)
By default a string entry like "/opt/tools" mounts the host path at the
same path inside the sandbox. To map a host directory to a different path
inside the sandbox, use the object form { "src": "...", "dst": "..." }.
The most common use case is making /tmp persistent across Bash tool calls.
Each Bash invocation spawns a fresh bwrap with --tmpfs /tmp and
--die-with-parent, so the default /tmp is wiped between calls. Mapping a
host cache directory onto /tmp keeps state across calls without exposing the
host's real /tmp:
{
"preferences": {
"coworkBwrapMounts": {
"additionalBinds": [
{ "src": "/home/user/.cache/claude-tmp", "dst": "/tmp" }
],
"disabledDefaultBinds": ["/tmp"]
}
}
}
disabledDefaultBinds: ["/tmp"] is required to remove the default
--tmpfs /tmp so the bind takes effect.
The string and object forms can be mixed freely in the same array.
Caution: Mapping
dstonto a default RO mount (/usr,/etc,/bin,/sbin,/lib,/lib64) silently replaces it inside the sandbox; you almost never want this, and--doctorwill warn if you do.
Security notes
- Paths
/,/proc,/dev,/sys(and their subpaths) are always rejected for bothsrcanddst - For read-write mounts (
additionalBinds),srcmust be under your home directory.dsthas no$HOMEconstraint — that is the entire purpose of the object form (e.g. mapping onto/tmp) - The core sandbox structure (
--tmpfs /,--unshare-pid,--die-with-parent,--new-session) cannot be modified - Mount order is enforced: user mounts cannot override security-critical read-only mounts
Applying changes
The daemon reads the configuration at startup. After editing the config file, restart the daemon:
pkill -f cowork-vm-service
The daemon will be automatically relaunched on the next Cowork session.
Diagnostics
Run claude-desktop --doctor to see your custom mount configuration and any
warnings about potentially dangerous settings.
Application Logs
Runtime logs are available at:
~/.cache/claude-desktop-debian/launcher.log