A Muse bwrap line follows the binary path, and unrestricted is rejected

John Burns

The permissions page tells you to pass --sandbox-network unrestricted when a Muse Code session should have full network access. It calls enabled the earlier name, and it says that earlier name still works. On Muse Code 1.4.14 the value unrestricted never starts a session. muse exec exits 2 and prints the three names it will accept: restricted, enabled, and proxy-only.

A later line, printed only after a session has started, tells you to install the distribution bwrap package. On this host that line tracked where the binary file resolved. It did not track whether bwrap was on PATH. The same file, with the same missing package, printed the line from /tmp and omitted it from a directory outside /tmp and outside TMPDIR. Both runs printed echo: ping and exited 0. Neither run executed a shell command.

Those are two different gates. The flag refusal is the parser, and it fails closed. The helper line is a sandbox startup notice, and on the echo provider it does not become the process result. A job that treats either sentence as the Linux sandbox decision is reading the wrong line.

The flag vocabulary

The permissions page, read on 6 November 2026, lists three network modes. proxy-only is the default: the first connection to a new host, port, or protocol stops for review. restricted is no network access. unrestricted is full network access, and the page says the earlier name enabled still works but is deprecated. The same page says the sandbox refuses to run a shell command when it cannot confirm that the sandbox is active, and that a Linux host without a working bubblewrap fails every shell command as an environment error.

The binary was Muse Code 1.4.14, release 1.4.14-R7309.1, the public muse-stable x86_64 Linux artifact. Its sha256 was 0809aac7cb58d18f5022b6d05e02aa1974683c0ec430e5f04d25b60ed17de2da, matching the release manifest, and its size was 414927192 bytes. The host was Linux x86_64. command -v bwrap found nothing. No muse login was run. No META_API_KEY was set. The provider was echo, which prints the prompt and does not call Muse Spark. Each exec used --no-session-log and --max-model-steps 1. The prompt was ping. The working directory for the flag runs was /tmp.

The refusal is on stderr, then the usage line, then exit 2. It names the flag, prints unsupported sandbox network mode unrestricted, and lists restricted|enabled|proxy-only. The CLI also wraps the flag name in its own slot marker. That marker is not a value you pass, and it is not part of the mode list.

muse exec --sandbox-network unrestricted --help did not print that error. It printed the help and exited 0. muse --sandbox-network unrestricted --version printed Muse Code 1.4.14 (1.4.14-R7309.1) and exited 0. Help and version parse far enough to accept the flag name, and they stop before the value check. A wrapper that adds --help or --version to see whether a mode is legal will not see this refusal.

The three names in the error are the names a real exec accepts. With the binary resolved outside /tmp and outside TMPDIR, each of these exited 0 and printed echo: ping on stdout:

muse exec --provider echo --no-session-log --max-model-steps 1 --sandbox-network enabled ping
muse exec --provider echo --no-session-log --max-model-steps 1 --sandbox-network proxy-only ping
muse exec --provider echo --no-session-log --max-model-steps 1 --sandbox-network restricted ping

Acceptance is not a network grant. The echo provider did not open a socket. This run does not say enabled is full egress, and it does not say restricted dropped a packet. It says the name the page calls current is the name the parser rejects, and the name the page calls deprecated is one of the three values the parser lists. muse exec --help describes the flag as restricted|enabled|proxy-only and names proxy-only as the default. That help text matches the error. It does not match the permissions page.

A bogus value fails the same way. --sandbox-network bogus exited 2 with the same expected list. The parser is not special-casing the documented word. It has one list, and unrestricted is absent from it.

The sandbox subcommand

muse sandbox is not the Linux helper check. With no arguments it prints usage and exits 0:

usage: muse sandbox windows check
       muse sandbox windows setup

There is no linux subcommand in that usage. The permissions page does not send you to muse sandbox for the bubblewrap check. It describes a check that runs when a shell command is about to run. If a job treats a zero exit from muse sandbox with no arguments as a Linux sandbox pass, it has read the usage text.

muse sandbox windows check on this Linux host exited 1. Stdout and stderr together were:

backend=windows_elevated
status=setup_required
reason=Windows elevated sandbox setup has not run
diagnostic=windows_host_required:windows_elevated readiness can only pass on Windows
Windows elevated sandbox setup has not run

That diagnostic is honest about the host. It is not the helper line. It does not mention bubblewrap, /tmp, or TMPDIR. A Linux job that requires muse sandbox windows check to pass will fail here even when the helper line is absent. A Linux job that requires it to fail has checked the Windows subcommand, not the binary path.

The helper line and the resolved path

The helper line appears on stderr when muse exec --provider echo starts and the resolved binary sits in a directory Muse treats as a writable sandbox root. From /tmp/muse-path-probe/muse-bin, with TMPDIR set to a different directory, the line was:

muse: Linux sandbox helper `/tmp/muse-path-probe/muse-bin` is under writable sandbox root `/tmp`; to fix: move the install outside `/tmp`; Bubblewrap is unavailable for linux: no capability-valid system bwrap was found on PATH and no usable embedded fallback is available; install your distribution's bwrap package

Stdout was echo: ping. The exit code was 0. The line names the binary, names /tmp as the root, tells you to move the install, and then tells you to install bwrap. Both pieces of advice were in one sentence. Only the first piece changed when the file moved.

A second copy of the same binary, checksum-matched, lived outside /tmp and outside TMPDIR. The same echo command printed no helper line. It still printed echo: ping and exited 0. bwrap was still absent from PATH. The package advice is not an independent probe that fires whenever the package is missing. On this binary it fired with the location sentence, and it did not fire when the location sentence did not fire.

/tmp is a root even when it is not TMPDIR. Pointing TMPDIR elsewhere did not clear the line for a binary under /tmp. It changed the wording. When the binary itself was under the directory assigned to TMPDIR, the line called that directory an unprotected writable ProxyOnly sandbox root and told you to move the install outside that directory. The rest of the sentence, including the bwrap package advice, was the same, and the exit code was still 0. Unsetting TMPDIR cleared the line for a binary that had been under the previous TMPDIR, as long as that binary was not also under /tmp. Unsetting TMPDIR did not clear the line for the /tmp binary. With TMPDIR unset, that /tmp line used the ProxyOnly wording and named /tmp.

The check uses the resolved file, not the path you typed. A name outside /tmp that was a symlink to /tmp/muse-path-probe/muse-bin still printed the helper line, and the line named the /tmp target. A name under /tmp that was a symlink to the copy outside /tmp did not print the line. Moving a symlink is not enough if the inode Muse opens is still under the root. Copying the file out, or pointing the link at a file that is already out, is what changed the result here.

--disable-sandbox on the /tmp binary omitted the helper line. The same echo command still printed echo: ping and exited 0. The line is the sandbox helper check. Turning the sandbox off skips it. It is not a package probe that runs on every invocation, and it is not printed by muse --version.

A missing Meta credential does not reach the check. muse exec --provider meta with no key and no login exited 1 and reported missing credentials. It did not print the helper line, even though that binary was the /tmp file. A key error is an earlier gate. It is not evidence that the helper path was accepted, and it is not evidence that the helper path was rejected.

--json does not move the line into the event stream. On the /tmp binary the helper line stayed on stderr. Stdout was JSONL. One later record had payload type run.terminal.completed, terminal completed, and text echo: ping. The process still exited 0. A scraper that reads only stdout will miss the helper line. A scraper that fails the run because stderr contains install your distribution's bwrap package is failing the location check, not a non-zero sandbox result.

Two other stderr lines showed up on these echo runs and are not the helper check. --no-session-log printed local session messaging disabled: session logging is required. The untrusted /tmp workspace printed Agent delegation: auto unavailable: workspace is untrusted. The extending page says a headless run with no session log cannot resume. It does not mention the messaging line. The permissions page says project rules load only after you trust the workspace. This run did not trust the workspace, did not load project rules, and does not say what a trusted workspace would have loaded.

What exit 0 does not settle

The extending page says muse exec exit 0 means the turn completed, not that the work is correct. That sentence covers the echo result. Exit 0 here means the echo turn finished and printed the prompt back. It does not mean a shell command was sandboxed, blocked, or allowed.

The permissions page’s shell-failure sentence was not exercised. Echo does not run shell. No tool call was requested, and no command such as echo data > $HOME/notes.txt was handed to the sandbox. The page’s example of a read-only filesystem error is still a documentation example, not a result from this host. If you need to know whether a shell command is refused when bubblewrap cannot be confirmed, this note does not answer that. It answers a prior question: which command rejects the documented network mode, which command prints a Linux helper line, and which command exits 0 while printing advice to install bwrap.

The helper line also does not prove the embedded fallback is broken on every path. Outside /tmp and outside TMPDIR, the missing bwrap package produced no line at all. The package clause traveled with the location clause. Installing bwrap was not required to make the line disappear. Moving the resolved binary was.

--disable-sandbox made the line disappear without moving the file, and the echo turn still completed. That is a second way to silence the check. It is not a fix for a shell sandbox. The permissions page says --disable-sandbox keeps approval and skips the sandbox, and that it also removes workspace confinement from the file tools. This run did not write a file, so it does not confirm that confinement change. It confirms only that the helper line is skipped when the sandbox is disabled.

No model reply was accepted. --provider echo is not muse-spark-1.2, which the configuration page names as the default model. A session that reaches a real model still has the flag parser in front of it. unrestricted will not get there. A session that starts from a binary under /tmp can still print the helper line and then continue, at least on this echo path. Do not infer the model path from the echo path beyond the checks that actually ran.

Verification

Confirm the version before you compare a result with this note. muse --version on the tested binary printed Muse Code 1.4.14 (1.4.14-R7309.1). A different release can change the accepted mode list or the helper wording. Record the version you have. Do not treat a help page from another date as a substitute for that print.

For the network mode, require the refusal on a real exec, not on --help or --version:

muse exec --provider echo --no-session-log --max-model-steps 1 --sandbox-network unrestricted ping

Expect exit 2, no echo: ping, and the expected list restricted|enabled|proxy-only. Then run the same command with enabled. Expect exit 0 and echo: ping on stdout. That second exit means the parser accepted the name. It does not mean a connection was opened. If you need the network behavior, test a shell or a fetch in a later run and keep that result separate from this parser check.

Do not use muse sandbox with no arguments as a Linux pass. Exit 0 there is the usage text, and the usage text names only Windows subcommands. If you run muse sandbox windows check on Linux, expect exit 1 and windows_host_required. That failure does not replace the helper line, and a missing helper line does not replace that failure.

For the helper line, resolve the binary two ways and run the same echo command. Under /tmp, expect the line that names /tmp and tells you to install bwrap, then echo: ping, then exit 0. Outside /tmp and outside TMPDIR, expect no helper line, the same stdout, and exit 0, even when bwrap is absent. If the outside copy still prints the line, you are not looking at the split measured here. Repeat the /tmp case with --disable-sandbox and expect the line to be absent. If it remains, the line is no longer only the sandbox helper check.

Use a symlink only as a check of the resolved file. A link whose target is under /tmp should still print the line and should name the target. A link that lives under /tmp but points outside it should not. If your installer publishes a /tmp path that points at another file, read the line’s path, not the path in the unit file.

Do not treat a missing META_API_KEY as either result. That failure exits 1 before the helper line. Do not treat local session messaging disabled or workspace is untrusted as the helper line. They come from --no-session-log and from an untrusted workspace. They were present on runs that printed the helper line and on runs that did not.

Stop there. Move the resolved binary if the helper line is what you need to clear. Install bwrap only after the line still appears from a binary that is not under /tmp or TMPDIR. That second case was not observed on this host. This note does not say a shell command was contained, and it does not say enabled opened the network.

Sources

  • Muse Code 1.4.14 (muse --version printed Muse Code 1.4.14 (1.4.14-R7309.1)) on Linux x86_64, 6 November 2026. The x86_linux artifact sha256 was 0809aac7cb58d18f5022b6d05e02aa1974683c0ec430e5f04d25b60ed17de2da and the size was 414927192 bytes, matching the public release manifest. Channel muse-stable, manifest state public. No login, no META_API_KEY, provider echo. bwrap was not on PATH. Commands were muse exec with --sandbox-network, muse sandbox, and muse sandbox windows check.
  • Muse Code permissions page, read 6 November 2026: Permissions and safety. It names unrestricted as the full-network mode, calls enabled deprecated, and says a Linux host without working bubblewrap fails shell commands. It does not say unrestricted is rejected, and it does not say the helper line follows /tmp or TMPDIR on an echo run that still exits 0.
  • Muse Code configuration page, read 6 November 2026: Configuration and context. It lists --sandbox-network among the flags common to the interactive and headless surfaces. It does not list the accepted mode names.
  • Muse Code extending page, read 6 November 2026: Extending and automating. It says muse exec exit 0 means the turn completed, not that the work is correct, and it documents --disable-sandbox as a headless approval posture that keeps the sandbox. The permissions page is the one that says --disable-sandbox skips the sandbox.