diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx
index db057a4c41f..40ffafaf389 100644
--- a/packages/app/src/components/settings-general.tsx
+++ b/packages/app/src/components/settings-general.tsx
@@ -1,4 +1,4 @@
-import { Component, Show, createEffect, createMemo, createResource, type JSX } from "solid-js"
+import { Component, Show, createEffect, createMemo, createResource, createSignal, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { Button } from "@opencode-ai/ui/button"
import { Icon } from "@opencode-ai/ui/icon"
@@ -10,6 +10,7 @@ import { showToast } from "@opencode-ai/ui/toast"
import { useLanguage } from "@/context/language"
import { usePlatform } from "@/context/platform"
import { useSettings, monoFontFamily } from "@/context/settings"
+import { useGlobalSDK } from "@/context/global-sdk"
import { playSound, SOUND_OPTIONS } from "@/utils/sound"
import { Link } from "./link"
@@ -37,6 +38,53 @@ export const SettingsGeneral: Component = () => {
const language = useLanguage()
const platform = usePlatform()
const settings = useSettings()
+ const globalSDK = useGlobalSDK()
+
+ // YOLO state - wird später vom Server geladen
+ const [yoloEnabled, setYoloEnabled] = createSignal(false)
+ const [yoloPersisted, setYoloPersisted] = createSignal(false)
+
+ // Lade YOLO status beim Öffnen - mit kleinem Delay für Stabilität
+ const loadYoloStatus = () => {
+ const doFetch = platform.fetch ?? fetch
+ doFetch(`${globalSDK.url}/config/yolo`)
+ .then((response) => {
+ if (response.ok) return response.json()
+ return null
+ })
+ .then((data) => {
+ if (data) {
+ setYoloEnabled(data.enabled === true)
+ setYoloPersisted(data.persisted === true)
+ }
+ })
+ .catch(() => {
+ // Silently ignore errors
+ })
+ }
+
+ // Initialer Load mit kleinem Delay
+ setTimeout(loadYoloStatus, 100)
+
+ const setYolo = (enabled: boolean, persist: boolean) => {
+ const doFetch = platform.fetch ?? fetch
+ doFetch(`${globalSDK.url}/config/yolo`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ enabled, persist }),
+ })
+ .then((response) => {
+ if (response.ok) return response.json()
+ return null
+ })
+ .then((data) => {
+ if (data) {
+ setYoloEnabled(data.enabled === true)
+ setYoloPersisted(data.persisted === true)
+ }
+ })
+ .catch((e) => console.error("Failed to set YOLO:", e))
+ }
const [store, setStore] = createStore({
checking: false,
@@ -450,6 +498,128 @@ export const SettingsGeneral: Component = () => {
)
}}
+
+ {/* YOLO Mode Section */}
+
+
+
YOLO Mode
+
+
+ ACTIVE
+
+
+
+
+
+ Skip ALL permission prompts. OpenCode will execute without asking for confirmation.
+
+
+ {/* Warning */}
+
+
+ Warning: This is dangerous. Only enable if you fully trust OpenCode's
+ actions. Explicit deny rules in your config will still be respected.
+
+
+
+ {/* This Session Only Card */}
+
+
+
+
+ This Session Only
+
+ ACTIVE
+
+
+
Resets when you restart OpenCode
+
+
setYolo(true, false)}
+ class="px-3 py-1.5 rounded text-12-medium bg-fill-danger-base text-white hover:bg-fill-danger-strong transition-colors"
+ >
+ Enable
+
+ }
+ >
+
+
+
+
+
+ {/* Always Enabled Card */}
+
+
+
+
+ Always Enabled
+
+ ACTIVE
+ Saved
+
+
+
Persists across restarts (saved in config.json)
+
+
setYolo(true, true)}
+ class="px-3 py-1.5 rounded text-12-medium bg-fill-danger-base text-white hover:bg-fill-danger-strong transition-colors"
+ >
+ Save to Config
+
+ }
+ >
+
+
+
+
+
+ {/* CLI Usage */}
+
+
CLI Usage
+
+
+ opencode --yolo
+ one session
+
+
+ OPENCODE_YOLO=true
+ env var
+
+
+
+
)
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index a231a530072..291223290c1 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -1163,6 +1163,10 @@ export namespace Config {
prune: z.boolean().optional().describe("Enable pruning of old tool outputs (default: true)"),
})
.optional(),
+ yolo: z
+ .boolean()
+ .optional()
+ .describe("Enable YOLO mode - auto-approve all permission prompts (except explicit deny rules)"),
experimental: z
.object({
disable_paste_summary: z.boolean().optional(),
diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts
index b11058b3405..cd6028a34ea 100644
--- a/packages/opencode/src/flag/flag.ts
+++ b/packages/opencode/src/flag/flag.ts
@@ -4,6 +4,7 @@ function truthy(key: string) {
}
export namespace Flag {
+ export const OPENCODE_YOLO = truthy("OPENCODE_YOLO")
export const OPENCODE_AUTO_SHARE = truthy("OPENCODE_AUTO_SHARE")
export const OPENCODE_GIT_BASH_PATH = process.env["OPENCODE_GIT_BASH_PATH"]
export const OPENCODE_CONFIG = process.env["OPENCODE_CONFIG"]
diff --git a/packages/opencode/src/permission/next.ts b/packages/opencode/src/permission/next.ts
index 2481f104ed1..bbcbad73e79 100644
--- a/packages/opencode/src/permission/next.ts
+++ b/packages/opencode/src/permission/next.ts
@@ -7,6 +7,7 @@ import { Storage } from "@/storage/storage"
import { fn } from "@/util/fn"
import { Log } from "@/util/log"
import { Wildcard } from "@/util/wildcard"
+import { Yolo } from "@/yolo"
import os from "os"
import z from "zod"
@@ -137,6 +138,11 @@ export namespace PermissionNext {
if (rule.action === "deny")
throw new DeniedError(ruleset.filter((r) => Wildcard.match(request.permission, r.permission)))
if (rule.action === "ask") {
+ // YOLO mode auto-approves all "ask" permissions (but respects explicit "deny")
+ if (Yolo.isEnabled()) {
+ log.warn("YOLO mode auto-approved", { permission: request.permission, pattern })
+ continue
+ }
const id = input.id ?? Identifier.ascending("permission")
return new Promise((resolve, reject) => {
const info: Request = {
diff --git a/packages/opencode/src/project/bootstrap.ts b/packages/opencode/src/project/bootstrap.ts
index efdcaba9909..ea1861f82f8 100644
--- a/packages/opencode/src/project/bootstrap.ts
+++ b/packages/opencode/src/project/bootstrap.ts
@@ -13,9 +13,11 @@ import { Log } from "@/util/log"
import { ShareNext } from "@/share/share-next"
import { Snapshot } from "../snapshot"
import { Truncate } from "../tool/truncation"
+import { Yolo } from "../yolo"
export async function InstanceBootstrap() {
Log.Default.info("bootstrapping", { directory: Instance.directory })
+ await Yolo.init()
await Plugin.init()
Share.init()
ShareNext.init()
diff --git a/packages/opencode/src/server/routes/config.ts b/packages/opencode/src/server/routes/config.ts
index 85d28f6aa6b..a0e55a09e5e 100644
--- a/packages/opencode/src/server/routes/config.ts
+++ b/packages/opencode/src/server/routes/config.ts
@@ -1,8 +1,11 @@
import { Hono } from "hono"
import { describeRoute, validator, resolver } from "hono-openapi"
import z from "zod"
+import path from "path"
import { Config } from "../../config/config"
import { Provider } from "../../provider/provider"
+import { Yolo } from "../../yolo"
+import { Global } from "../../global"
import { mapValues } from "remeda"
import { errors } from "../error"
import { Log } from "../../util/log"
@@ -10,6 +13,22 @@ import { lazy } from "../../util/lazy"
const log = Log.create({ service: "server" })
+// Helper to read/write global config for YOLO persistence (uses config.json, not opencode.jsonc)
+async function readGlobalConfig(): Promise> {
+ const filepath = path.join(Global.Path.config, "config.json")
+ try {
+ const text = await Bun.file(filepath).text()
+ return JSON.parse(text)
+ } catch {
+ return {}
+ }
+}
+
+async function writeGlobalConfig(config: Record): Promise {
+ const filepath = path.join(Global.Path.config, "config.json")
+ await Bun.write(filepath, JSON.stringify(config, null, 2))
+}
+
export const ConfigRoutes = lazy(() =>
new Hono()
.get(
@@ -88,5 +107,82 @@ export const ConfigRoutes = lazy(() =>
default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
})
},
+ )
+ .get(
+ "/yolo",
+ describeRoute({
+ summary: "Get YOLO mode status",
+ description:
+ "Check if YOLO mode is enabled. When enabled, all permission prompts are auto-approved (except explicit deny rules).",
+ operationId: "config.yolo.get",
+ responses: {
+ 200: {
+ description: "YOLO mode status",
+ content: {
+ "application/json": {
+ schema: resolver(z.object({ enabled: z.boolean(), persisted: z.boolean() })),
+ },
+ },
+ },
+ },
+ }),
+ async (c) => {
+ const globalConfig = await readGlobalConfig()
+ return c.json({
+ enabled: Yolo.isEnabled(),
+ persisted: globalConfig.yolo === true,
+ })
+ },
+ )
+ .post(
+ "/yolo",
+ describeRoute({
+ summary: "Set YOLO mode",
+ description:
+ "Enable or disable YOLO mode. When enabled, all permission prompts are auto-approved (except explicit deny rules). Use with caution. Set persist=true to save to config file.",
+ operationId: "config.yolo.set",
+ responses: {
+ 200: {
+ description: "YOLO mode updated",
+ content: {
+ "application/json": {
+ schema: resolver(z.object({ enabled: z.boolean(), persisted: z.boolean() })),
+ },
+ },
+ },
+ },
+ }),
+ validator("json", z.object({ enabled: z.boolean(), persist: z.boolean().optional() })),
+ async (c) => {
+ const { enabled, persist } = c.req.valid("json")
+ Yolo.set(enabled)
+
+ try {
+ const globalConfig = await readGlobalConfig()
+ const wasPersisted = globalConfig.yolo === true
+
+ if (persist) {
+ // Explicitly save to or remove from config
+ if (enabled) {
+ globalConfig.yolo = true
+ } else {
+ delete globalConfig.yolo
+ }
+ await writeGlobalConfig(globalConfig)
+ log.info("YOLO mode config updated", { enabled, path: Global.Path.config })
+ } else if (wasPersisted && enabled) {
+ // Downgrade from persistent to session-only: remove from config but keep enabled
+ delete globalConfig.yolo
+ await writeGlobalConfig(globalConfig)
+ log.info("YOLO mode downgraded to session-only", { path: Global.Path.config })
+ }
+ } catch (e) {
+ log.error("Failed to update YOLO config", { error: e })
+ }
+
+ // Return the actual persisted state from config
+ const finalConfig = await readGlobalConfig()
+ return c.json({ enabled: Yolo.isEnabled(), persisted: finalConfig.yolo === true })
+ },
),
)
diff --git a/packages/opencode/src/yolo/index.ts b/packages/opencode/src/yolo/index.ts
new file mode 100644
index 00000000000..b36e809265d
--- /dev/null
+++ b/packages/opencode/src/yolo/index.ts
@@ -0,0 +1,54 @@
+import { Bus } from "@/bus"
+import { BusEvent } from "@/bus/bus-event"
+import { Config } from "@/config/config"
+import { Flag } from "@/flag/flag"
+import { Log } from "@/util/log"
+import z from "zod"
+
+export namespace Yolo {
+ const log = Log.create({ service: "yolo" })
+
+ let enabled = Flag.OPENCODE_YOLO
+
+ export const Event = {
+ Changed: BusEvent.define(
+ "yolo.changed",
+ z.object({
+ enabled: z.boolean(),
+ }),
+ ),
+ }
+
+ export async function init() {
+ const config = await Config.global()
+ if (config.yolo === true) {
+ enabled = true
+ log.warn("YOLO mode enabled via config")
+ }
+ if (Flag.OPENCODE_YOLO) {
+ enabled = true
+ log.warn("YOLO mode enabled via OPENCODE_YOLO env var")
+ }
+ if (enabled) {
+ log.warn("YOLO mode is ACTIVE - all permission prompts will be auto-approved")
+ }
+ }
+
+ export function isEnabled(): boolean {
+ return enabled
+ }
+
+ export function set(value: boolean) {
+ const previous = enabled
+ enabled = value
+ if (previous !== value) {
+ log.warn(`YOLO mode ${value ? "ENABLED" : "DISABLED"}`)
+ Bus.publish(Event.Changed, { enabled: value })
+ }
+ }
+
+ export function toggle(): boolean {
+ set(!enabled)
+ return enabled
+ }
+}
diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts
index b757b753507..9f989b73ab8 100644
--- a/packages/sdk/js/src/v2/gen/sdk.gen.ts
+++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts
@@ -19,6 +19,8 @@ import type {
ConfigProvidersResponses,
ConfigUpdateErrors,
ConfigUpdateResponses,
+ ConfigYoloGetResponses,
+ ConfigYoloSetResponses,
EventSubscribeResponses,
EventTuiCommandExecute,
EventTuiPromptAppend,
@@ -643,6 +645,64 @@ export class Pty extends HeyApiClient {
}
}
+export class Yolo extends HeyApiClient {
+ /**
+ * Get YOLO mode status
+ *
+ * Check if YOLO mode is enabled. When enabled, all permission prompts are auto-approved (except explicit deny rules).
+ */
+ public get(
+ parameters?: {
+ directory?: string
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }])
+ return (options?.client ?? this.client).get({
+ url: "/config/yolo",
+ ...options,
+ ...params,
+ })
+ }
+
+ /**
+ * Set YOLO mode
+ *
+ * Enable or disable YOLO mode. When enabled, all permission prompts are auto-approved (except explicit deny rules). Use with caution. Set persist=true to save to config file.
+ */
+ public set(
+ parameters?: {
+ directory?: string
+ enabled?: boolean
+ persist?: boolean
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "body", key: "enabled" },
+ { in: "body", key: "persist" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).post({
+ url: "/config/yolo",
+ ...options,
+ ...params,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ ...params.headers,
+ },
+ })
+ }
+}
+
export class Config2 extends HeyApiClient {
/**
* Get configuration
@@ -716,6 +776,11 @@ export class Config2 extends HeyApiClient {
...params,
})
}
+
+ private _yolo?: Yolo
+ get yolo(): Yolo {
+ return (this._yolo ??= new Yolo({ client: this.client }))
+ }
}
export class Tool extends HeyApiClient {
diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts
index 9543e5b5796..af5b1e01fa3 100644
--- a/packages/sdk/js/src/v2/gen/types.gen.ts
+++ b/packages/sdk/js/src/v2/gen/types.gen.ts
@@ -509,6 +509,13 @@ export type EventMessagePartRemoved = {
}
}
+export type EventYoloChanged = {
+ type: "yolo.changed"
+ properties: {
+ enabled: boolean
+ }
+}
+
export type PermissionRequest = {
id: string
sessionID: string
@@ -919,6 +926,7 @@ export type Event =
| EventMessageRemoved
| EventMessagePartUpdated
| EventMessagePartRemoved
+ | EventYoloChanged
| EventPermissionAsked
| EventPermissionReplied
| EventSessionStatus
@@ -1823,6 +1831,10 @@ export type Config = {
*/
prune?: boolean
}
+ /**
+ * Enable YOLO mode - auto-approve all permission prompts (except explicit deny rules)
+ */
+ yolo?: boolean
experimental?: {
disable_paste_summary?: boolean
/**
@@ -2673,6 +2685,51 @@ export type ConfigProvidersResponses = {
export type ConfigProvidersResponse = ConfigProvidersResponses[keyof ConfigProvidersResponses]
+export type ConfigYoloGetData = {
+ body?: never
+ path?: never
+ query?: {
+ directory?: string
+ }
+ url: "/config/yolo"
+}
+
+export type ConfigYoloGetResponses = {
+ /**
+ * YOLO mode status
+ */
+ 200: {
+ enabled: boolean
+ persisted: boolean
+ }
+}
+
+export type ConfigYoloGetResponse = ConfigYoloGetResponses[keyof ConfigYoloGetResponses]
+
+export type ConfigYoloSetData = {
+ body?: {
+ enabled: boolean
+ persist?: boolean
+ }
+ path?: never
+ query?: {
+ directory?: string
+ }
+ url: "/config/yolo"
+}
+
+export type ConfigYoloSetResponses = {
+ /**
+ * YOLO mode updated
+ */
+ 200: {
+ enabled: boolean
+ persisted: boolean
+ }
+}
+
+export type ConfigYoloSetResponse = ConfigYoloSetResponses[keyof ConfigYoloSetResponses]
+
export type ToolIdsData = {
body?: never
path?: never