Running Commands

Your workspace has a shell, and you can drive it from your own terminal. monofile bash runs one command in the cloud and prints the output locally, and monofile sh gives you a session. Monofile writes the files the command touches back into your workspace, versions them, and groups them so you can undo the whole thing.

One command at a time

Terminal
monofile bash "ls -la /Projects"

The command runs against your workspace, not against your laptop, so every path is a workspace path starting at /. Output comes back on stdout and the exit code is your command's own exit code, exactly like ssh host cmd:

Terminal
monofile bash "grep -q TODO /Projects/notes.md" && echo "there is still a TODO"

Two flags shape the run:

FlagDefaultNotes
--timeout <seconds>60Hard maximum 240. Monofile kills the command at the limit
--cwd <path>/Working directory inside the workspace
Terminal
monofile bash --cwd /Projects "grep -rl TODO ."
monofile bash --timeout 180 "python3 /scripts/report.py > /out.md"

A session instead of a call

Terminal
monofile sh
plaintext
monofile sh — one line = one command (no PTY). `exit` to leave.
monofile:/$ cd /Projects
monofile:/Projects$ ls
notes.md
report.md
monofile:/Projects$ wc -l /Projects/notes.md
42 /Projects/notes.md
monofile:/Projects$ exit

Each line you type is one command in the workspace. There is no pseudo-terminal, so interactive programs such as vim or top have nothing to attach to. The CLI tracks cd locally and applies it as the working directory of the next line. exit, quit or end-of-file ends the session.

sh also reads piped input, so it can run a script:

Terminal
monofile sh < ./setup.sh
printf 'ls /\nwc -l /notes.md\n' | monofile sh

Piped input exits with the last command's exit code. Each line is a separate command, so shell variables do not carry from one line to the next. When you need real script semantics, write the script into your workspace and run it in one call:

Terminal
echo "$SCRIPT" | monofile write /scripts/fix.sh
monofile bash "sh /scripts/fix.sh"

What the result tells you

Monofile writes anything the command created, edited, renamed or deleted back into your workspace and reports it. In the human rendering you get a one-line summary on stderr:

Terminal
monofile bash "sed -i 's/2025/2026/g' /notes/*.md"
plaintext
[workspace: updated /notes/a.md, /notes/b.md]

With --json you get the full payload, which is the form to use from a script:

Terminal
monofile --json bash "mkdir -p /reports && echo draft > /reports/q3.md"
FieldWhat it means
output, stderrWhat the command printed
exitCodeThe command's own exit code
changescreated, updated, deleted and renamed lists of workspace paths
conflictsFiles that changed elsewhere while your command ran. Your version won, and theirs is in the file's history
warningsNon-fatal notices
timedOuttrue when the command hit the timeout

changes reports what the command wrote, taken from the write-back itself; the CLI does not parse your command text to guess. A command that timed out still writes back whatever it finished.

Output is capped at 400 lines or 30 KB, whichever comes first, with a truncation marker at the end. When a stray find / would dump your whole workspace, narrow the command with head, tail or grep.

Undo a command

Every command is its own changeset, including every line of an sh session.

Terminal
monofile changesets list --limit 1
monofile changesets revert <id>

That restores the files the command edited and deletes the files it created. Changesets covers the model, and Reverting Safely covers what happens when something changed in the meantime.

The two shells

Monofile has a built-in shell and a full one, and the same bash command reaches both. Which one runs your command depends only on what you asked for.

The built-in shell answers instantly, straight from your files, and is available on every plan. It covers pwd, ls, tree, cat, head, tail, stat, wc, find and grep, plus basic file management with mkdir, rm, mv, cp, touch, echo and printf. You can chain those with ;, && and ||, and redirect with > or >> from echo and printf.

The full shell is a real sh with real coreutils, running on a persistent sandbox whose disk mirrors your workspace. That is what you need for pipes, redirects into arbitrary commands, command substitution, multi-line scripts, and anything not in the list above: sed, awk, sort, jq, git, python3, node.

Terminal
monofile bash "ls -la /Projects"                  # built-in: instant, every plan
monofile bash "grep -rl TODO /src | xargs wc -l"  # full shell: pipes
monofile bash "python3 /scripts/report.py"        # full shell: interpreters

Only one command runs in a workspace at a time. A second one arriving while the first is still going gets a conflict error, so retry after it finishes.

Scopes and permissions

Monofile enforces scopes at write-back, after the command has run. Creating or editing needs files:write, and deleting needs files:delete. A missing scope rejects the entire diff: nothing is written, and the error lists the paths that caused it. A key restricted to one folder cannot write outside it, by the same mechanism. See Scopes for the full map.

The underlying tool

bash and sh are thin wrappers over one public tool, which the API and MCP expose under the same name with the same contract. File and Shell Tools documents it directly, including the full error code list. If you are scripting against Monofile, read that page too.

Next steps

863 words