From 65a5cdabd5195f3541a94c4eeefcf70befa0bcbb Mon Sep 17 00:00:00 2001 From: wqymi Date: Fri, 3 Jul 2026 13:55:24 +0800 Subject: [PATCH 1/3] feat(tui): add --dangerously-skip-permissions flag Mirror `mimo run --dangerously-skip-permissions` in TUI mode. The flag sets MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS, which injects an allow-all base ruleset UNDER the user's permission config so every tool auto-approves unless the user explicitly denied it. Denies still win, matching the run flag's semantics. --- packages/opencode/src/cli/cmd/tui/thread.ts | 12 ++++++++++ packages/opencode/src/config/config.ts | 7 ++++++ packages/opencode/src/flag/flag.ts | 4 ++++ packages/opencode/test/cli/tui/thread.test.ts | 2 ++ packages/web/src/content/docs/cli.mdx | 23 +++++++++++-------- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index f8fe065a4..abe93c4f7 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -170,6 +170,11 @@ export const TuiThreadCommand = cmd({ type: "boolean", describe: "skip workspace trust prompt and trust the directory", default: false, + }) + .option("dangerously-skip-permissions", { + type: "boolean", + describe: "auto-approve permissions that are not explicitly denied (dangerous!)", + default: false, }), handler: async (args) => { // Keep ENABLE_PROCESSED_INPUT cleared even if other code flips it. @@ -180,6 +185,13 @@ export const TuiThreadCommand = cmd({ // spawn or async work so the OS cannot kill the process group. win32DisableProcessedInput() + // Propagate to the worker (which loads config) via the env it inherits + // from sanitizedProcessEnv. Config injects an allow-all base under the + // user's permission rules so denies still win. + if (args["dangerously-skip-permissions"]) { + process.env.MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS = "1" + } + if (args.fork && !args.continue && !args.session) { UI.error("--fork requires --continue or --session") process.exitCode = 1 diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 5f5d2ae74..7a391d724 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -927,6 +927,13 @@ export const layer = Layer.effect( }) } + if (Flag.MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS) { + // Allow-all base, merged UNDER user config so an explicit deny still + // wins. Matches `mimo run --dangerously-skip-permissions`: auto-approve + // everything not explicitly denied. + result.permission = mergeDeep({ "*": "allow" } as ConfigPermission.Info, result.permission ?? {}) + } + if (Flag.MIMOCODE_PERMISSION) { result.permission = mergeDeep(result.permission ?? {}, JSON.parse(Flag.MIMOCODE_PERMISSION)) } diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index 8e7570793..6175ec57e 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -66,6 +66,10 @@ export const Flag = { MIMOCODE_DISABLE_TERMINAL_TITLE: truthy("MIMOCODE_DISABLE_TERMINAL_TITLE"), MIMOCODE_SHOW_TTFD: truthy("MIMOCODE_SHOW_TTFD"), MIMOCODE_PERMISSION: process.env["MIMOCODE_PERMISSION"], + // Set by the TUI's --dangerously-skip-permissions flag. When truthy, an + // allow-all base ruleset is injected UNDER the user's config permission so + // every tool auto-approves unless the user explicitly denied it. + MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS: truthy("MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS"), MIMOCODE_DISABLE_DEFAULT_PLUGINS: truthy("MIMOCODE_DISABLE_DEFAULT_PLUGINS"), MIMOCODE_DISABLE_LSP_DOWNLOAD: truthy("MIMOCODE_DISABLE_LSP_DOWNLOAD"), MIMOCODE_ENABLE_EXPERIMENTAL_MODELS: truthy("MIMOCODE_ENABLE_EXPERIMENTAL_MODELS"), diff --git a/packages/opencode/test/cli/tui/thread.test.ts b/packages/opencode/test/cli/tui/thread.test.ts index 89ef9d133..971417035 100644 --- a/packages/opencode/test/cli/tui/thread.test.ts +++ b/packages/opencode/test/cli/tui/thread.test.ts @@ -63,6 +63,8 @@ describe("tui thread", () => { "never-ask": false, neverAsk: false, trust: true, + "dangerously-skip-permissions": false, + dangerouslySkipPermissions: false, port: 0, hostname: "127.0.0.1", mdns: false, diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index 2bc40a4f7..f4de18672 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -29,16 +29,19 @@ opencode [project] #### Flags -| Flag | Short | Description | -| ------------ | ----- | ----------------------------------------------------------------------- | -| `--continue` | `-c` | Continue the last session | -| `--session` | `-s` | Session ID to continue | -| `--fork` | | Fork the session when continuing (use with `--continue` or `--session`) | -| `--prompt` | | Prompt to use | -| `--model` | `-m` | Model to use in the form of provider/model | -| `--agent` | | Agent to use | -| `--port` | | Port to listen on | -| `--hostname` | | Hostname to listen on | +| Flag | Short | Description | +| -------------------------------- | ----- | ----------------------------------------------------------------------- | +| `--continue` | `-c` | Continue the last session | +| `--session` | `-s` | Session ID to continue | +| `--fork` | | Fork the session when continuing (use with `--continue` or `--session`) | +| `--prompt` | | Prompt to use | +| `--model` | `-m` | Model to use in the form of provider/model | +| `--agent` | | Agent to use | +| `--port` | | Port to listen on | +| `--hostname` | | Hostname to listen on | +| `--never-ask` | | Start in never-ask mode — auto-decide without asking (permissions excluded) | +| `--trust` | | Skip workspace trust prompt and trust the directory | +| `--dangerously-skip-permissions` | | Auto-approve permissions that are not explicitly denied (dangerous!) | --- From 7c69c17cc87f0cdf78fea8aa9aa88f6cb9c60c90 Mon Sep 17 00:00:00 2001 From: wqymi Date: Fri, 3 Jul 2026 18:12:17 +0800 Subject: [PATCH 2/3] feat(tui): warn and require confirmation for --dangerously-skip-permissions Add a startup gate mirroring Claude Code's bypass-permissions warning: when the TUI is launched with --dangerously-skip-permissions, show a red warning and require an explicit accept before auto-approving all permission checks. The gate is skipped when there is no TTY so automation still works, and adds an extra root warning when running as uid 0. Adds en/zh i18n strings. --- packages/opencode/src/cli/cmd/tui/i18n/en.ts | 9 ++++ packages/opencode/src/cli/cmd/tui/i18n/zh.ts | 9 ++++ packages/opencode/src/cli/cmd/tui/thread.ts | 53 +++++++++++++++++--- 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/i18n/en.ts b/packages/opencode/src/cli/cmd/tui/i18n/en.ts index 3cc80c68a..707bc5ce8 100644 --- a/packages/opencode/src/cli/cmd/tui/i18n/en.ts +++ b/packages/opencode/src/cli/cmd/tui/i18n/en.ts @@ -466,4 +466,13 @@ export const dict: Record = { "trust.dangerous.advice_root": "Unless you have a very specific reason, DO NOT trust the filesystem root.", "trust.dangerous.option.yes": "I understand the risks, trust for this session", "trust.dangerous.option.no": "Exit (recommended)", + "skip_permissions.title": "WARNING: Bypass Permissions mode", + "skip_permissions.body": + "You started with --dangerously-skip-permissions. MiMo Code will read, edit, and execute files and run shell commands WITHOUT asking for approval. Only rules you have explicitly denied in config are still enforced. You are solely responsible for anything it does.", + "skip_permissions.plugin_warn": + "In this mode a malicious prompt, file, or plugin can run arbitrary commands, and modify or exfiltrate your data without any confirmation.", + "skip_permissions.root_warn": + "You are running as root. Bypassing permissions as root gives the model unrestricted control over this machine.", + "skip_permissions.option.no": "No, exit (recommended)", + "skip_permissions.option.yes": "Yes, I accept the risks and want to skip permissions", } diff --git a/packages/opencode/src/cli/cmd/tui/i18n/zh.ts b/packages/opencode/src/cli/cmd/tui/i18n/zh.ts index 0d5ea65a9..87ae5d001 100644 --- a/packages/opencode/src/cli/cmd/tui/i18n/zh.ts +++ b/packages/opencode/src/cli/cmd/tui/i18n/zh.ts @@ -455,4 +455,13 @@ export const dict = { "trust.dangerous.advice_root": "除非有明确的理由,否则不要信任文件系统根目录。", "trust.dangerous.option.yes": "我了解风险,仅本次信任", "trust.dangerous.option.no": "退出(推荐)", + "skip_permissions.title": "警告:跳过权限确认模式", + "skip_permissions.body": + "你使用 --dangerously-skip-permissions 启动。MiMo Code 将在不征求同意的情况下读取、修改、执行文件并运行 Shell 命令。只有你在配置中明确拒绝(deny)的规则仍然生效。由此产生的一切后果由你自行承担。", + "skip_permissions.plugin_warn": + "在此模式下,恶意的提示词、文件或插件可以在无任何确认的情况下执行任意命令,并修改或窃取你的数据。", + "skip_permissions.root_warn": + "你正在以 root 身份运行。以 root 跳过权限确认会让模型对本机拥有不受限制的控制权。", + "skip_permissions.option.no": "否,退出(推荐)", + "skip_permissions.option.yes": "是,我已知晓风险并希望跳过权限确认", } satisfies Partial> diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index abe93c4f7..36c5a5b78 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -124,6 +124,36 @@ async function promptWorkspaceTrust(directory: string, level: "untrusted" | "dan return result } +// Startup gate for --dangerously-skip-permissions. Mirrors Claude Code's +// bypass-permissions warning: an explicit, red-highlighted accept is required +// before every permission check is auto-approved. Returns false to abort. +async function promptDangerousPermissions(): Promise { + const prompts = await import("@clack/prompts") + const { EOL } = await import("os") + + const asRoot = typeof process.getuid === "function" && process.getuid() === 0 + + prompts.log.warning( + [ + UI.Style.TEXT_DANGER + t("skip_permissions.title") + UI.Style.TEXT_NORMAL, + "", + t("skip_permissions.body"), + "", + UI.Style.TEXT_DANGER + t("skip_permissions.plugin_warn") + UI.Style.TEXT_NORMAL, + ...(asRoot ? ["", UI.Style.TEXT_DANGER + t("skip_permissions.root_warn") + UI.Style.TEXT_NORMAL] : []), + ].join(EOL), + ) + const result = await prompts.select({ + message: "", + options: [ + { label: t("skip_permissions.option.no"), value: false }, + { label: t("skip_permissions.option.yes"), value: true }, + ], + }) + if (prompts.isCancel(result)) return false + return result +} + export const TuiThreadCommand = cmd({ command: "$0 [project]", describe: "start mimocode tui", @@ -185,13 +215,6 @@ export const TuiThreadCommand = cmd({ // spawn or async work so the OS cannot kill the process group. win32DisableProcessedInput() - // Propagate to the worker (which loads config) via the env it inherits - // from sanitizedProcessEnv. Config injects an allow-all base under the - // user's permission rules so denies still win. - if (args["dangerously-skip-permissions"]) { - process.env.MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS = "1" - } - if (args.fork && !args.continue && !args.session) { UI.error("--fork requires --continue or --session") process.exitCode = 1 @@ -225,6 +248,22 @@ export const TuiThreadCommand = cmd({ } } + if (args["dangerously-skip-permissions"]) { + // Require an explicit accept when interactive; skip the gate with no TTY + // (CI / piped stdin) so automation still works. + if (process.stdin.isTTY) { + const accepted = await promptDangerousPermissions() + if (!accepted) { + process.exit(0) + return + } + } + // Propagate to the worker (which loads config) via the env it inherits + // from sanitizedProcessEnv. Config injects an allow-all base under the + // user's permission rules so denies still win. + process.env.MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS = "1" + } + const env = sanitizedProcessEnv({ [MIMOCODE_PROCESS_ROLE]: "worker", [MIMOCODE_RUN_ID]: ensureRunID(), From 30aac616e80faddce73a8a6e055bd0b2b02ae8cf Mon Sep 17 00:00:00 2001 From: wqymi Date: Fri, 3 Jul 2026 20:16:24 +0800 Subject: [PATCH 3/3] docs(tui): document --dangerously-skip-permissions and complete i18n Add ja/fr/ru translations for the bypass-permissions warning (en/zh already present), document the flag in the builtin mimocode skill (permissions.md and commands.md), and add a README section (en + zh) explaining the flag, its allow-all-under-deny semantics, the startup confirmation, and its risks. --- README.md | 28 +++++++++++++++++++ README.zh.md | 25 +++++++++++++++++ packages/opencode/src/cli/cmd/tui/i18n/fr.ts | 9 ++++++ packages/opencode/src/cli/cmd/tui/i18n/ja.ts | 9 ++++++ packages/opencode/src/cli/cmd/tui/i18n/ru.ts | 9 ++++++ .../.bundle/mimocode/reference/commands.md | 2 ++ .../.bundle/mimocode/reference/permissions.md | 14 ++++++++++ 7 files changed, 96 insertions(+) diff --git a/README.md b/README.md index e43cfebac..610ed6362 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,34 @@ controlled environments or inside a container. Keep the allowlist as narrow as p +
+Skipping permission prompts (--dangerously-skip-permissions) + +For trusted, disposable environments (containers, sandboxes, CI) you can auto-approve +everything the agent does instead of confirming each action: + +```bash +# TUI — prompts once for an explicit confirmation on startup +mimo --dangerously-skip-permissions + +# Headless +mimo run --dangerously-skip-permissions "your prompt" + +# Or via environment variable (any surface) +MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS=1 mimo +``` + +This injects an **allow-all base underneath your config**, so every tool auto-approves +*unless you explicitly `deny` it* — your `deny` rules still win. In the TUI it shows a +red warning and requires you to accept the risk before it takes effect (the prompt is +skipped when there is no TTY, so automation keeps working). + +**This is dangerous.** With permissions bypassed, a malicious prompt, file, or plugin can +run arbitrary shell commands and read, modify, or exfiltrate your data without any +confirmation. Only use it where you fully trust the workspace. + +
+ --- ## Development diff --git a/README.zh.md b/README.zh.md index 0fab3ed29..e0d825b01 100644 --- a/README.zh.md +++ b/README.zh.md @@ -303,6 +303,31 @@ Max Mode(并行 best-of-N 推理 + 裁判选优)可通过配置中的 `exper +
+跳过权限确认(--dangerously-skip-permissions + +在可信、可丢弃的环境(容器、沙箱、CI)中,你可以让智能体自动放行所有操作,而不必逐个确认: + +```bash +# TUI —— 启动时会弹出一次红色警告,需你明确接受风险 +mimo --dangerously-skip-permissions + +# 无头模式 +mimo run --dangerously-skip-permissions "你的提示词" + +# 或通过环境变量(任意入口) +MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS=1 mimo +``` + +它会在你的配置**下方**注入一条“全部放行”的基础规则,因此除非你在配置中**明确 `deny`**, +否则所有工具都会自动放行——你的 `deny` 规则仍然生效。在 TUI 中会显示红色警告并要求你确认后才生效 +(无 TTY 时会跳过该提示,以保证自动化可用)。 + +**这非常危险。** 一旦跳过权限确认,恶意的提示词、文件或插件就能在无任何确认的情况下执行任意 Shell +命令,并读取、修改或窃取你的数据。请仅在你完全信任的工作区中使用。 + +
+ --- ## 开发 diff --git a/packages/opencode/src/cli/cmd/tui/i18n/fr.ts b/packages/opencode/src/cli/cmd/tui/i18n/fr.ts index ae51f84f4..f3458264f 100644 --- a/packages/opencode/src/cli/cmd/tui/i18n/fr.ts +++ b/packages/opencode/src/cli/cmd/tui/i18n/fr.ts @@ -516,4 +516,13 @@ export const dict = { "trust.dangerous.advice_root": "Sauf raison très spécifique, NE faites PAS confiance à la racine du système de fichiers.", "trust.dangerous.option.yes": "Je comprends les risques, faire confiance pour cette session", "trust.dangerous.option.no": "Quitter (recommandé)", + "skip_permissions.title": "AVERTISSEMENT : mode contournement des permissions", + "skip_permissions.body": + "Vous avez démarré avec --dangerously-skip-permissions. MiMo Code va lire, modifier et exécuter des fichiers et lancer des commandes shell SANS demander d'approbation. Seules les règles que vous avez explicitement refusées (deny) dans la configuration restent appliquées. Vous êtes seul responsable de tout ce qu'il fait.", + "skip_permissions.plugin_warn": + "Dans ce mode, une invite, un fichier ou un plugin malveillant peut exécuter des commandes arbitraires et modifier ou exfiltrer vos données sans aucune confirmation.", + "skip_permissions.root_warn": + "Vous êtes en root. Contourner les permissions en root donne au modèle un contrôle illimité sur cette machine.", + "skip_permissions.option.no": "Non, quitter (recommandé)", + "skip_permissions.option.yes": "Oui, j'accepte les risques et veux ignorer les permissions", } satisfies Partial> diff --git a/packages/opencode/src/cli/cmd/tui/i18n/ja.ts b/packages/opencode/src/cli/cmd/tui/i18n/ja.ts index 38c0f1221..a9e2e803b 100644 --- a/packages/opencode/src/cli/cmd/tui/i18n/ja.ts +++ b/packages/opencode/src/cli/cmd/tui/i18n/ja.ts @@ -464,4 +464,13 @@ export const dict = { "trust.dangerous.advice_root": "明確な理由がない限り、ファイルシステムのルートを信頼しないでください。", "trust.dangerous.option.yes": "リスクを理解した上で、今回のみ信頼する", "trust.dangerous.option.no": "終了(推奨)", + "skip_permissions.title": "警告: パーミッションスキップモード", + "skip_permissions.body": + "--dangerously-skip-permissions を指定して起動しました。MiMo Code は承認を求めずにファイルの読み取り・編集・実行やシェルコマンドの実行を行います。設定で明示的に拒否(deny)したルールのみが引き続き適用されます。発生したいかなる結果についてもあなた自身が全責任を負います。", + "skip_permissions.plugin_warn": + "このモードでは、悪意のあるプロンプト・ファイル・プラグインが一切の確認なしに任意のコマンドを実行し、データを改ざんまたは持ち出す可能性があります。", + "skip_permissions.root_warn": + "root で実行しています。root でパーミッションをスキップすると、モデルがこのマシンを無制限に制御できるようになります。", + "skip_permissions.option.no": "いいえ、終了する(推奨)", + "skip_permissions.option.yes": "はい、リスクを理解した上でパーミッションをスキップする", } satisfies Partial> diff --git a/packages/opencode/src/cli/cmd/tui/i18n/ru.ts b/packages/opencode/src/cli/cmd/tui/i18n/ru.ts index 903b5efe3..50bedad4d 100644 --- a/packages/opencode/src/cli/cmd/tui/i18n/ru.ts +++ b/packages/opencode/src/cli/cmd/tui/i18n/ru.ts @@ -528,4 +528,13 @@ export const dict = { "trust.dangerous.advice_root": "Если нет весомой причины, НЕ доверяйте корню файловой системы.", "trust.dangerous.option.yes": "Я понимаю риски, доверять только в этой сессии", "trust.dangerous.option.no": "Выйти (рекомендуется)", + "skip_permissions.title": "ПРЕДУПРЕЖДЕНИЕ: режим обхода разрешений", + "skip_permissions.body": + "Вы запустили с --dangerously-skip-permissions. MiMo Code будет читать, редактировать и выполнять файлы, а также запускать команды оболочки БЕЗ запроса подтверждения. Действуют только правила, которые вы явно запретили (deny) в конфигурации. Вы несёте полную ответственность за все его действия.", + "skip_permissions.plugin_warn": + "В этом режиме вредоносный запрос, файл или плагин может выполнить произвольные команды и изменить или похитить ваши данные без какого-либо подтверждения.", + "skip_permissions.root_warn": + "Вы работаете от имени root. Обход разрешений от имени root даёт модели неограниченный контроль над этой машиной.", + "skip_permissions.option.no": "Нет, выйти (рекомендуется)", + "skip_permissions.option.yes": "Да, я принимаю риски и хочу пропустить проверку разрешений", } satisfies Partial> diff --git a/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/commands.md b/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/commands.md index a829ac168..5b71372b7 100644 --- a/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/commands.md +++ b/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/commands.md @@ -29,6 +29,8 @@ Invoked from the shell. `mimo` with no command opens the TUI. Run `mimo --help` for flags on any command. +Notable TUI flags: `--continue`/`-c` (resume last session), `--session`/`-s`, `--model`/`-m`, `--agent`, `--never-ask`, `--trust`, and `--dangerously-skip-permissions` (auto-approve everything not explicitly denied; prompts once for confirmation — see permissions.md). + ## Slash commands (inside the TUI) | Command | Purpose | diff --git a/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/permissions.md b/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/permissions.md index 9647c431d..f22d70a66 100644 --- a/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/permissions.md +++ b/packages/opencode/src/skill/builtin/.bundle/mimocode/reference/permissions.md @@ -59,6 +59,20 @@ Ask before every file edit: { "permission": { "edit": "ask" } } ``` +## Skipping permission prompts + +For trusted, disposable environments (containers, sandboxes, CI) you can auto-approve everything the agent does. + +| Surface | How | +|---------|-----| +| TUI (`mimo`) | `mimo --dangerously-skip-permissions` | +| Headless (`mimo run`) | `mimo run --dangerously-skip-permissions ""` | +| Any surface (env) | `MIMOCODE_PERMISSION='"allow"'` or `MIMOCODE_DANGEROUSLY_SKIP_PERMISSIONS=1` | + +Semantics: an **allow-all base is injected UNDER your config**, so every tool auto-approves *unless you explicitly `deny` it*. Your `deny` rules still win — this only removes the `ask` prompts. + +In the TUI the flag is gated by a one-time red confirmation on startup (you must explicitly accept the risk); the prompt is skipped when there is no TTY so automation still works. This is dangerous — a malicious prompt, file, or plugin can then run arbitrary commands without confirmation. Only use it where you fully trust the workspace. + ## Notes - Rules are evaluated in your original insertion order and **the last matching rule wins**. Put the `*` catch-all **first** and more specific patterns after it — a `*` placed last would shadow everything above it (e.g. a trailing `"*": "ask"` makes preceding `allow`/`deny` rules dead code).