Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions docs/api/_media/configuration.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -152,6 +152,9 @@ Notes:
| `tui.showVersion` | `true` | Show the Forge version in the sidebar title. |
| `tui.keybinds.executePlan` | `"<leader>f"` | Open the execution dialog. Avoid `<leader>e`, which conflicts with opencode's built-in `editor_open`. |
| `tui.keybinds.dashboard` | `""` | Optional keybind for opening the dashboard. Empty registers the command without a default binding. |
| `tui.keybinds.toggleHostSandbox` | `""` | Optional keybind for `Toggle host sandbox`, which enables or disables the project host-session sandbox for the current session. Empty registers the command without a default binding. Requires `sandbox.enabled`. |

The host-session sandbox applies only to sessions outside active loops. Its desired and applied state is stored per project, and one selected session (including its descendants) can use it at a time. `bash`, `glob`, and `grep` route through the sandbox; file tools remain host-side. A failed enable request blocks those routed tools rather than falling back to the host until the request is disabled or succeeds on retry.

## Dashboard

Expand Down
14 changes: 7 additions & 7 deletions docs/api/_media/sandbox.md
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
# Sandbox

Forge can run loop iterations inside an isolated `sbx` sandbox while keeping the loop worktree mounted at its identical host path for fast host/sandbox file sharing.
Forge can run loop iterations or one selected host session inside an isolated `sbx` sandbox while keeping the active project directory mounted at its identical host path for fast host/sandbox file sharing.

See also: [Configuration](configuration.md), [Tools](tools.md), [Loop System](loop-system.md).

Expand All@@ -23,9 +23,9 @@ The image includes Node.js 24, pnpm, Bun, Python 3 + uv, ripgrep, git, jq, and a

## How It Works

1. Forge creates an isolated git worktree for the loop.
2. If sandboxing is enabled and the `sbx` daemon is available, Forge creates one sandbox for that loop.
3. The worktree and the read-only source project (when `sandbox.mountProjectReadonly` is enabled) are each mounted at their identical host path, so absolute paths resolve the same on both sides. There is no `/workspace` or `/project` container path.
1. A sandbox loop uses its isolated git worktree. A host-session sandbox instead uses the project root selected from the TUI.
2. Forge creates one sandbox per loop, or one project-scoped host-session sandbox shared by plugin instances in the process.
3. The active directory and the read-only source project (when `sandbox.mountProjectReadonly` is enabled) are mounted at their identical host paths, so absolute paths resolve the same on both sides. There is no `/workspace` or `/project` container path.
4. Shell commands and search tools execute inside the sandbox; file tools stay on the host, so LSP and editor integration continue to work.

The read-only project mount is dropped whenever the worktree's git directories live inside the source project (the default forge layout), so `sandbox.mountProjectReadonly` is effectively inert there.
Expand All@@ -37,14 +37,14 @@ Sandbox loops use opencode's native `bash` tool — streaming output, truncation
> Requires opencode >= 1.15.5 (the session-aware `shell.env` plugin hook). Enforced via the `engines.opencode` field in Forge's package.json: older opencode versions refuse to load the plugin instead of silently running sandbox loop commands on the host.

1. Forge points opencode's `shell` config at a generated shim (`<dataDir>/forge-shell`).
2. On every bash tool call, Forge's `shell.env` hook resolves the session to its loop. Sessions belonging to an active sandbox loop (including Task-tool subagents) get `FORGE_SANDBOX_CONTAINER` injected; the shim then runs the command via `sbx exec -w "$PWD" <sandbox> bash`.
3. All other sessions get no container env, and the shim execs the host shell unchanged (respecting a user-configured `shell` via `FORGE_HOST_SHELL`).
2. On every bash tool call, Forge's `shell.env` hook resolves the session. Sessions belonging to an active sandbox loop, or to the acknowledged host-session selection, get `FORGE_SANDBOX_CONTAINER` injected; descendants such as Task-tool subagents inherit the same routing. The shim then runs the command via `sbx exec -w "$PWD" <sandbox> bash`.
3. Sessions with no expected sandbox get no container env, and the shim execs the host shell unchanged (respecting a user-configured `shell` via `FORGE_HOST_SHELL`). Active loop routing always takes precedence over host-session preference.

The shim fails closed: if the sandbox is expected but `sbx exec` fails (or the loop sandbox cannot be restored), the command errors — it never silently runs on the host.

## Tool Behavior

| Tool category | Behavior in sandbox loop |
| Tool category | Behavior in a sandboxed session |
|---|---|
| Shell | Native `bash` tool, executed inside the loop sandbox via the shell shim. |
| Search tools | `glob` and `grep` route through the `sbx exec` execution hooks. |
Expand Down
2 changes: 1 addition & 1 deletion docs/api/functions/createForgePlugin.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@

> **createForgePlugin**(`config`): `Plugin`

Defined in: [index.ts:205](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L205)
Defined in: [index.ts:276](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L276)

Creates an OpenCode plugin instance with loop management and sandboxing.

Expand Down
2 changes: 1 addition & 1 deletion docs/api/functions/createParentSessionLookup.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@

> **createParentSessionLookup**(`__namedParameters`): (`sessionId`) => `Promise`\<`string` \| `null`\>

Defined in: [index.ts:59](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L59)
Defined in: [index.ts:93](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L93)

## Parameters

Expand Down
2 changes: 1 addition & 1 deletion docs/api/functions/createSessionDirectoryLookup.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@

> **createSessionDirectoryLookup**(`__namedParameters`): (`sessionId`) => `Promise`\<`string` \| `null`\>

Defined in: [index.ts:140](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L140)
Defined in: [index.ts:154](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L154)

## Parameters

Expand Down
6 changes: 3 additions & 3 deletions docs/api/interfaces/CompactionConfig.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

# Interface: CompactionConfig

Defined in: [types.ts:164](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/types.ts#L164)
Defined in: [types.ts:165](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/types.ts#L165)

Configuration for session compaction behavior.

Expand All@@ -16,7 +16,7 @@ Configuration for session compaction behavior.

> `optional` **customPrompt?**: `boolean`

Defined in: [types.ts:166](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/types.ts#L166)
Defined in: [types.ts:167](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/types.ts#L167)

Use a custom compaction prompt.

Expand All@@ -26,6 +26,6 @@ Use a custom compaction prompt.

> `optional` **maxContextTokens?**: `number`

Defined in: [types.ts:168](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/types.ts#L168)
Defined in: [types.ts:169](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/types.ts#L169)

Maximum context tokens for compaction.
12 changes: 6 additions & 6 deletions docs/api/interfaces/CreateParentSessionLookupOptions.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,31 +6,31 @@

# Interface: CreateParentSessionLookupOptions

Defined in: [index.ts:49](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L49)
Defined in: [index.ts:52](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L52)

## Properties

### client

> **client**: `ForgeClient`

Defined in: [index.ts:50](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L50)
Defined in: [index.ts:53](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L53)

***

### directory

> **directory**: `string`

Defined in: [index.ts:51](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L51)
Defined in: [index.ts:54](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L54)

***

### logger

> **logger**: `object`

Defined in: [index.ts:53](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L53)
Defined in: [index.ts:56](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L56)

#### debug

Expand DownExpand Up@@ -92,12 +92,12 @@ Defined in: [index.ts:53](https://github.com/chriswritescode-dev/opencode-forge/

> **loop**: `Loop`

Defined in: [index.ts:52](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L52)
Defined in: [index.ts:55](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L55)

***

### negativeTtlMs?

> `optional` **negativeTtlMs?**: `number`

Defined in: [index.ts:54](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L54)
Defined in: [index.ts:57](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L57)
16 changes: 12 additions & 4 deletions docs/api/interfaces/CreateSessionDirectoryLookupOptions.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,28 +6,36 @@

# Interface: CreateSessionDirectoryLookupOptions

Defined in: [index.ts:134](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L134)
Defined in: [index.ts:147](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L147)

## Properties

### client

> **client**: `ForgeClient`

Defined in: [index.ts:135](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L135)
Defined in: [index.ts:148](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L148)

***

### directory

> **directory**: `string`

Defined in: [index.ts:136](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L136)
Defined in: [index.ts:149](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L149)

***

### loop

> **loop**: `Loop`

Defined in: [index.ts:137](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/index.ts#L137)
Defined in: [index.ts:150](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L150)

***

### negativeTtlMs?

> `optional` **negativeTtlMs?**: `number`

Defined in: [index.ts:151](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/index.ts#L151)
6 changes: 3 additions & 3 deletions docs/api/interfaces/DashboardConfig.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

# Interface: DashboardConfig

Defined in: [types.ts:200](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/types.ts#L200)
Defined in: [types.ts:201](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/types.ts#L201)

Configuration for the read-only observability dashboard HTTP server.
The dashboard is unauthenticated: binding to a non-loopback address exposes
Expand All@@ -20,7 +20,7 @@ for the canonical warning text rendered by launch surfaces.

> `optional` **host?**: `string`

Defined in: [types.ts:202](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/types.ts#L202)
Defined in: [types.ts:203](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/types.ts#L203)

Bind hostname or IP. Defaults to "localhost". Use "0.0.0.0" to listen on all interfaces.

Expand All@@ -30,6 +30,6 @@ Bind hostname or IP. Defaults to "localhost". Use "0.0.0.0" to listen on all int

> `optional` **port?**: `number`

Defined in: [types.ts:204](https://github.com/chriswritescode-dev/opencode-forge/blob/4781cfd6d6b1994ce6d5de8e795c35f0499fd5fe/src/types.ts#L204)
Defined in: [types.ts:205](https://github.com/chriswritescode-dev/opencode-forge/blob/bae347e91d162356f5d88217fa4b5258e5c999ac/src/types.ts#L205)

Base bind port. Defaults to 4747. Consecutive ports are tried when busy.
Loading