Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ arboard = { version = "3.6", default-features = false, features = ["image-data",
axum = "=0.8.4"
base64 = "0.22"
clap = { version = "4.5", features = ["derive"] }
clap_complete = "4.5"
command-fds = "0.3.3"
crossterm = { version = "0.29", features = ["event-stream"] }
futures-core = "0.3"
Expand Down
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,19 @@ target/release/merry run --resume migration-1 "now update the tests"

# Generate a command plan without executing it
target/release/merry cmd "find the largest Rust files"

# Shell completions (bash, zsh, fish, elvish, powershell), generated from the
# same clap definition that parses the flags above
target/release/merry completions zsh > "${fpath[1]}/_merry"
target/release/merry completions bash > ~/.local/share/bash-completion/completions/merry
target/release/merry completions fish > ~/.config/fish/completions/merry.fish
```

`merry completions <SHELL>` prints the script to stdout and exits without
reading `config.toml` or starting a sandbox, so it works before Merry is
configured. Regenerate it after upgrading; the flags, subcommands, and value
lists such as `--approval-policy` are read from the binary itself.

Every `merry run` saves its session state under
`$XDG_STATE_HOME/merry/sessions/<session-id>` when the run settles, so a later
`--resume <session-id>` continues that session's ledger, transcript, artifacts,
Expand Down Expand Up @@ -229,6 +240,39 @@ by action sandboxes. With `--no-sandbox`, action `/tmp` maps to the current
process's validated `TMPDIR` directly. Debug commands remain unsandboxed unless
`--with-sandbox` is supplied.

The `[cli]` table in `config.toml` sets defaults for every `merry` invocation,
so a preferred sandbox mode or approval policy does not need to be passed as a
flag on each command:

```toml
[cli]
sandbox = "no-sandbox"
approval_policy = "none"
```

`sandbox` takes `with-sandbox` (outer+inner, the built-in default for TUI and
`run`), `no-sandbox`, or `inner-sandbox`, matching the root flags; a sandbox
mode given on the command line replaces the configured one. `approval_policy`
is the config equivalent of `--approval-policy` and names who reviews
permission requests before a command runs:

| Value | Reviewer |
|---|---|
| `none` | nobody: configured actions run without an approval round |
| `deny` | nobody: every permission request is rejected without asking |
| `model_only` | the `[models.approval_review]` model decides; no human fallback |
| `model_then_human` (default) | the model decides first; when it denies or cannot decide, you are asked in the TUI dialog or on the `merry run` prompt |
| `human_only` | you decide, in the TUI dialog or on the `merry run` prompt |

Unreviewed execution runs without any sandbox, so `approval_policy = "none"`
requires `sandbox = "no-sandbox"` next to it; any other `sandbox` value, or
leaving `sandbox` unset, is rejected when the config loads. The configured
`none` policy applies to every session that runs without a sandbox; passing
`--with-sandbox` or `--inner-sandbox` on the command line runs that session
sandboxed with the default `model_then_human` reviewer. Every other configured
policy applies under any sandbox mode, and `--approval-policy` on the command
line always wins.

Outer filesystem mounts are applied parent-first after resolving access-rule
precedence. Explicit file and directory imports preserve symbolic links instead
of replacing them with their target's contents. Trusted and integration directory
Expand Down Expand Up @@ -263,11 +307,19 @@ HOME. This applies to both inner-only and outer+inner execution.
defaults to `true`. It does not preauthorize network access: ordinary actions
remain network-isolated, and each action must request and obtain its own network
approval. With `network = false`, network requests are rejected before review
or execution, including in fully trusted review mode; approval cannot override
or execution, including under the `none` approval policy; approval cannot override
the ceiling. The setting is inherited by new process sessions and does not
restrict model-provider or configured MCP connections. Explicit `--no-sandbox`
host execution remains outside this network-isolation boundary.

`--approval-policy none` skips model and host permission review for configured
actions in the TUI and `merry run`; `[cli] approval_policy = "none"` applies it
to every session that runs without a sandbox. `--approval-policy deny` is the
opposite end: actions that need no approval still run, but every permission
request and high-risk action review is denied without consulting a reviewer.
Neither policy changes any access ceiling: `deny_paths`, `review_paths`
masking, and `network = false` still apply.

Trusted `readonly_paths` and `readwrite_paths` are preauthorized in the inner
sandbox at their declared access level. `review_paths` marks existing subtrees
within these grants for **per-action** review, without adding a new grant or
Expand Down
1 change: 1 addition & 0 deletions crates/merry-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ rust-version.workspace = true

[dependencies]
clap.workspace = true
clap_complete.workspace = true
crossterm = { workspace = true, features = ["osc52"] }
futures-util.workspace = true
merry-core = { path = "../merry-core", version = "0.1.0" }
Expand Down
Loading
Loading