marsh

Configuration

marsh keeps configuration and runtime state per MARSH_HOME. Use this page to change job limits, choose a shell, or find the files used by your installation.

For a separate guest home and set of VMs, launch with MARSH_HOME=~/.marsh-work marsh. To raise the per-job memory limit to 16 GiB, finish active work, exit open shells, run marsh stop, then launch with MARSH_JOB_MEMORY_BYTES=17179869184 marsh.

marsh status shows the limits in effect and whether each came from a built-in default or the daemon's launch environment.

Scopes

A scope is one canonical MARSH_HOME path. It has its own daemon, VMs, guest home, and job records. The default scope is ~/.marsh. Persistent-home shells in that scope share the shell VM; an ephemeral-home shell gets a separate VM and home.

Use separate scopes when work must not share a VM or guest home, for example a client project and your personal agent logins. Scopes do not separate your project files: a job in any scope can write the project it runs in.

For skills, dotfiles, MCP connections, and extra directories, see Set up your marsh home.

Environment

VariableMeaning
MARSH_HOMEAbsolute scope root. Default ~/.marsh. The guest home is $MARSH_HOME/home.
MARSH_SHELLShell to run: marsh (Brush, the default), bash, or zsh. See Choosing your shell.
MARSH_SBXPath to sbx. Default: sbx on PATH.
MARSH_CONTROL_HOMEHost-only state root. See Control home.
MARSH_SPAWNNames that jobs started from this shell may start. A comma-separated list, or none. See spawn restrictions and refusal statuses.
MARSH_PLACEWhere registered commands run. Only local is accepted; any other value is an error (MARSH_PLACE must be local).
MARSH_KIT_IMAGE_CACHECache of Kit images built from source. Default ~/Library/Caches/marsh/kit-images.

Job limits

The daemon reads these once, when it starts for a scope. They apply to every job in the scope. Values are positive integers.

VariableDefault
MARSH_JOB_CPU_MILLIS4000 (4 CPUs)
MARSH_JOB_MEMORY_BYTES8589934592 (8 GiB)
MARSH_JOB_PIDS4096
MARSH_JOB_WRITABLE_BYTES10737418240 (10 GiB). Counts the container's own files, not mounted directories.
MARSH_JOB_OUTPUT_BYTES268435456 (256 MiB). stdout and stderr together.
MARSH_JOB_WALL_SECONDS86400 (24 hours)
MARSH_TREE_KIT_VMS4. Distinct Kit VMs used by live jobs in one tree, 1 to 64. Aliases of the same Kit share a VM.

To see the values in effect, run marsh status (or marsh status --json and read job_defaults).

To change them:

  1. Let running work finish and exit open shells.
  2. Run marsh stop.
  3. Start marsh with the new values, as in the example at the top.

A shell started with a value that conflicts with the running daemon is refused. marsh status shows the daemon's values.

Writable limit

marsh periodically measures the container's writable layer and kills a job that exceeds the limit (limit:writable). A fast writer can overshoot between checks. Files in mounted directories do not count toward this limit.

Fixed limits

These cannot be changed. A call that exceeds one is refused with exit 125 (messages).

  • 8 jobs at once per daemon
  • depth 4
  • 4 live children per job
  • the same Kit at most twice in a row
  • 64 launches per tree, including refused child calls

Children also inherit their parent's wall-time deadline. With less than one second remaining, a new child is refused. Parallel composition has separate fanout and split capture limits.

Control home

MARSH_CONTROL_HOME must be an existing directory with mode 0700. Under it:

  • scope control directories (HASH/);
  • MCP and ACP publications: published-mcp/, published-acp/, and publication-locks/.

Generated MCP server scopes go beside it, in $MARSH_CONTROL_HOME-mcp-scopes/.

When unset, control directories are in ~/Library/Application Support/marsh/control. Publications are in ~/Library/Application Support/marsh.

Files

PathContents
$MARSH_HOME/config.jsonThe default shell, set by marsh config shell NAME. Default path ~/.marsh/config.json.
$MARSH_HOME/home/The guest home. Agent logins and settings (.claude, .codex) live here. Every job in the scope can read it. Default path ~/.marsh/home/.
$MARSH_HOME/sbxenv.yamlShared MCP servers and extra directories for every Kit and the shell.
$MARSH_HOME/sbxenvs/NAME.yamlAdditional servers and directories for registered command NAME; shell.yaml also configures the shell VM.
CONTROL/HASH/Host-only control directory for a scope. marsh status prints it. Never mounted into a VM.
CONTROL/HASH/commands.jsonYour command registry. Overrides packaged entries by name. See Commands and Kits.
CONTROL/HASH/agents.jsonYour ACP agent list. Replaces the packaged list; [] disables ACP. See ACP.
CONTROL/HASH/state/results.journalStructural job receipts, for marsh results.
PREFIX/libexec/marsh/Packaged commands.json, agents.json, shell-image, and the Linux binaries.
~/Library/Application Support/marsh/published-mcp/, published-acp/Host-only MCP and ACP publication declarations. Under MARSH_CONTROL_HOME when it is set.
~/Library/Application Support/marsh-mcp-scopes/Generated scope roots for marsh mcp install sbx and marsh-mcp broker modes.
PROJECT/.marsh/split/ID/A split's forks and results. Ignored by Git.

CONTROL is $MARSH_CONTROL_HOME, or ~/Library/Application Support/marsh/control when unset. HASH is the SHA-256 of the canonical MARSH_HOME path.

A malformed commands.json or agents.json stops the daemon from starting. The error names the file. Fix that file; deleting other state does not help.

Servers and extra directories

The optional sbxenv.yaml and sbxenvs/NAME.yaml files use these fields:

FieldMeaning
schemaVersionRequired; the string "1"
mcp.serversList of servers, each with a name and either url or command
mcp.servers[].argsLiteral argument list for a local command server
additionalWorkspacesList of existing Mac directories, each with path and optional readOnly
additionalWorkspaces[].readOnlyDefaults to false; use true for reference material

Other fields are rejected. For examples, see the home guide.

Files and merging

  • Each YAML file must be a regular file owned by your Mac account, not a symlink, and not writable by group or others. The sbxenvs directory must also be a real directory, not a symlink.
  • Shared lists are followed by the command's lists. Entries cannot remove or override shared entries. Duplicate server names or overlapping directories in the combined lists are errors.
  • The same MCP name must have the same definition across Kits. Aliases of one Kit must have identical combined configuration because they share a VM.
  • Each file is limited to 64 KiB. A combined environment permits at most 32 MCP servers and 16 extra directories.

Paths and access

Extra directories appear at their canonical Mac paths in Linux. Relative paths are resolved from the YAML file's directory; ~ and variables are not expanded. Directories cannot overlap the project, the guest home's backing directory, another extra directory, or marsh's install and host-control files. They cannot replace the guest home itself.

Root jobs receive the shared directories plus their command's directories. Child jobs inherit the parent's mounts, without adding directories from the child Kit's file. Split Kit jobs omit extra directories. marsh jobs show JOB --json includes the mount targets and access modes.

A local MCP command is an absolute path or an executable name on the Mac's PATH; its arguments are literal strings. Its resolved executable and the environment files cannot be guest-mounted. The YAML ownership and symlink rules above apply to the configuration files, not the executable.

MCP servers are loaded per VM. The shell VM can load servers too, but you need an MCP client to call them. See MCP access.

Applying changes

Files are read when the daemon starts. After editing them or adding a file for a newly registered command, finish jobs, exit shells, run marsh stop on the Mac, and launch marsh again. A worker reset reloads the daemon's existing configuration; it does not reread the YAML. Ephemeral-home sessions skip these files' servers and directories.

A declared server must register and load successfully before its VM can be used. Setup errors explain authentication and name conflicts.

Shell prompt and startup files

The shell reads the usual startup files from the guest home. Set PS1 there to change the prompt. See The shell.

Results

marsh results lists job receipts with the registered command name, where it ran, exit status, cleanup verification, and timing. The journal retains up to 1,000 terminal receipts, including at most 16 arguments of 200 characters each. Prompts passed as arguments can be stored; stdin, stdout, and stderr are not recorded. marsh does not resume work after a daemon restart.

Next: Commands and Kits, Troubleshooting.

Edit this page on GitHub