You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 680bf5a
Browse filesBrowse the repository at this point in the historyBrowse files
The TUI talks to the server through the V2 plugin RPC port (`FORGE_RPC`): `executePlan` for plan launches, `loopDefaults` for the execution dialog's default iterations and sandbox resources, and `autoApproveState`/`autoApproveSet` for per-session auto-approve (served by the core in `src/host/forge-core.ts`), and, served by `src/services/tui-rpc-service.ts`, `loops`/`loopSidebar` for the loop list and sidebar, `sessionPlan` for the stored plan, `loopRestart` for loop restarts, `hostSandboxState`/`hostSandboxSet` for the host-session sandbox, and `worktrees` for the server's Forge worktree directories; `version` reports the server plugin version. The server pushes `toast`, `sessionDelete`, `loopsChanged`, `autoApproveChanged`, and `hostSandboxChanged` events; the TUI never polls — it fetches at startup, when one of these events arrives for its project, when the open session changes, and on `server.connected` after a reconnect. The TUI holds no Forge database of its own — its only `forge.db` reference is the path handed to the local dashboard launcher — so it works attached to a remote OpenCode server running Forge.
71
+
The TUI talks to the server through the V2 plugin RPC port (`FORGE_RPC`): `executePlan` for plan launches, `loopDefaults` for the execution dialog's default iterations and sandbox resources, and `autoApproveState`/`autoApproveSet` for per-session auto-approve (served by the core in `src/host/forge-core.ts`), and, served by `src/services/tui-rpc-service.ts`, `loops`/`loopSidebar` for the loop list and sidebar, `sessionPlan` for the stored plan, `loopRestart` for loop restarts, `hostSandboxState`/`hostSandboxSet` for the host-session sandbox, and `worktrees` for the server's Forge worktree directories; `version` reports the server plugin version. The server pushes `toast`, `sessionDelete`, `loopsChanged`, `autoApproveChanged`, and `hostSandboxChanged` events; the TUI never polls — it fetches at startup, when one of these events arrives for its project, when the open session changes, and on `server.connected` after a reconnect. The OpenCode client ends an RPC event subscription for good when its shared event connection closes or the subscriber overflows, so `followRpcEvent` (`src/tui/v2-client.ts`) resubscribes each event stream and re-reads the state that stream drives. The TUI holds no Forge database of its own — its only `forge.db` reference is the path handed to the local dashboard launcher — so it works attached to a remote OpenCode server running Forge.
72
72
73
73
## Module Layout
74
74
@@ -119,7 +119,7 @@ Sandbox is optional and controlled by `sandbox.enabled` (default `true`) with dr
-**SandboxTools** (`hooks/sandbox-tools.ts`) - Hooks for sandbox integration
122
-
-**SandboxMessage** (`hooks/sandbox-message.ts`) - Tells the agent its tool calls run in a container
122
+
-**SandboxMessage** (`hooks/sandbox-message.ts`) - Adds the sandbox context note to every sandboxed request, and after the sandbox is turned off repeats the host note on every request until it is turned back on
123
123
-**SessionSandboxController** (`sandbox/session-controller.ts`) - Host-session sandbox selection and reconciliation
124
124
-**Shell shim** (`sandbox/shell-shim.ts`) - Generated shim routing the native `shell` tool through `msb exec`
Copy file name to clipboardExpand all lines: docs/api/_media/configuration.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -96,7 +96,7 @@ The block applies to loop, audit, and post-action sessions.
96
96
97
97
### Post-Action
98
98
99
-
`loop.postAction` configures an optional post-completion action phase. It runs inside the worktree after a clean final audit and before teardown.
99
+
`loop.postAction` configures an optional post-completion action phase. It runs inside the worktree after a clean audit (a clean final audit for sectioned loops, `audit-clear` for non-sectioned plan loops) and before teardown. Goal loops never run it. See [Post-Completion Action Phase](loop-system.md#post-completion-action-phase) for completion confirmation.
100
100
101
101
The phase is enabled only when `enabled === true` and at least one of `skill` or `prompt` is configured.
Copy file name to clipboardExpand all lines: docs/api/_media/loop-system.md
+6-3Lines changed: 6 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -236,7 +236,7 @@ A loop completes when the active phase emits a clean audit result (optionally fo
236
236
- Sectioned loops advance through clean section audits, then complete on `final-audit-clean`.
237
237
- Dirty section audits rotate back to coding for the same section so findings can be addressed.
238
238
- Dirty final audits rotate to a coding session in the `final_audit_fix` phase (no section rewind); when the fix coding pass goes idle, the loop returns straight to `final_auditing`.
239
-
- After a clean audit — a clean final audit for sectioned loops, `audit-clear` for non-sectioned plan loops — if `loop.postAction.enabled` is `true` and specifies a `skill` or `prompt`, the loop enters a `post_action` phase that runs inside the worktree before teardown. Completion occurs when the post-action session goes idle (`post-action-complete` event). Goal loops never enter this phase.
239
+
- After a clean audit — a clean final audit for sectioned loops, `audit-clear` for non-sectioned plan loops — if `loop.postAction.enabled` is `true` and specifies a `skill` or `prompt`, the loop enters a `post_action` phase that runs inside the worktree before teardown. Normal confirmed completion (`post-action-complete` event) occurs once the post-action session is idle, every loop session has settled, and the final reply confirms completion; see [Behavior](#behavior) for the best-effort completion that follows exhausted or failed continuation attempts and the abort-with-reply exceptions. Goal loops never enter this phase.
240
240
241
241
## Termination
242
242
@@ -269,15 +269,18 @@ After a clean audit (a clean final audit for sectioned loops, `audit-clear` for
269
269
|`loop.postAction.enabled`|`boolean`|`false`| Enable the post-completion action phase. |
270
270
|`loop.postAction.skill`|`string`| — | Name of a skill to load via the Skill tool at action time (e.g. `"pr-review"`). Must be installed host-side. |
271
271
|`loop.postAction.prompt`|`string`| — | Optional extra instruction text appended to the action prompt. Used standalone when no skill is set. |
272
+
|`loop.postAction.model`|`string`| — | Optional `provider/model` for the post-action session. Falls back to the loop's auditor model when unset or when the configured model fails. |
272
273
273
274
### Behavior
274
275
275
276
- Runs only after a clean audit completes (a clean final audit for sectioned loops, `audit-clear` for non-sectioned plan loops); goal loops never run it.
276
277
- Runs **inside the worktree** as the `code` agent, with access to the full worktree state (including uncommitted changes).
277
278
-**Best-effort:** The post-action result is not re-audited; it applies only safe, scoped fixes. The question tool is blocked — any finding requiring clarification is auto-deferred.
278
-
- On idle (`post-action-complete`), the loop terminates normally.
279
+
-**Completion confirmation:** The prompt requires the agent to finish every step (subagents, merges, saved records) before ending its turn, and to end its final reply with the line `<!-- forge:post-action-complete -->` (`POST_ACTION_COMPLETE_MARKER` in `src/loop/prompts.ts`). When the session goes idle, Forge first waits until every loop session, subagents included, is idle and no prompt is queued in the session inbox; the wait is bounded by `busyStallTimeoutMs`, after which the loop terminates with an error because the worktree cannot be torn down safely. It then checks the final reply for the marker. Without it, Forge sends a continue prompt asking the agent to finish, up to 3 times; after the third, or if the continue prompt fails to send, the loop completes best-effort.
280
+
- On a confirmed (or best-effort) `post-action-complete`, the loop terminates normally.
281
+
- If the post-action session is aborted after it has replied, the reply is processed as-is: the settle wait and marker check are skipped.
279
282
- If the post-action session fails to create, the loop terminates as completed without retrying.
280
-
-**Outcome capture:** On `post-action-complete`, the post-action session's full assistant transcript is stored in the loop's `postActionReport`, and its raw final assistant messageis stored verbatim in `completion_summary`. `loop-status` and the dashboard prefer the full **Post-Action Report** and fall back to **Completion Summary** when no report was captured. The loop status is **always**`completed` regardless of what the post-action reported — the plan itself was already cleared by the audit; the report only provides context (alternate-review verdict, CI result, etc.). Completion summary and report are captured only on the clean `post-action-complete` path; idle-exhausted, error, and abort-without-assistant terminations leave them empty.
283
+
-**Outcome capture:** On `post-action-complete`, the post-action session's full assistant transcript (including any continue-prompt turns) is stored in the loop's `postActionReport`, and its final assistant message, with the completion marker removed, is stored in `completion_summary`. `loop-status` and the dashboard prefer the full **Post-Action Report** and fall back to **Completion Summary** when no report was captured. The loop status is **always**`completed` regardless of what the post-action reported — the plan itself was already cleared by the audit; the report only provides context (alternate-review verdict, CI result, etc.). Completion summary and report are captured only on the clean `post-action-complete` path; idle-exhausted, error, and abort-without-assistant terminations leave them empty.
| `sandbox-message.ts` | Tells the agent its tool calls run in a container |
158
+
| `sandbox-message.ts` | Adds the container note to every sandboxed request and, once the sandbox is turned off, the host note to every request until it is turned back on |
159
159
| `group-orchestrator.ts` | Advances queued features when a group loop terminates |
Defined in: [host/forge-core.ts:162](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L162)
11
+
Defined in: [host/forge-core.ts:162](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L162)
Defined in: [host/forge-core.ts:264](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L264)
11
+
Defined in: [host/forge-core.ts:264](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L264)
Copy file name to clipboardExpand all lines: docs/api/interfaces/CreateParentSessionLookupOptions.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,31 +6,31 @@
6
6
7
7
# Interface: CreateParentSessionLookupOptions
8
8
9
-
Defined in: [host/forge-core.ts:124](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L124)
9
+
Defined in: [host/forge-core.ts:124](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L124)
10
10
11
11
## Properties
12
12
13
13
### client
14
14
15
15
> **client**: `ForgeClient`
16
16
17
-
Defined in: [host/forge-core.ts:125](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L125)
17
+
Defined in: [host/forge-core.ts:125](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L125)
18
18
19
19
***
20
20
21
21
### directory
22
22
23
23
> **directory**: `string`
24
24
25
-
Defined in: [host/forge-core.ts:126](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L126)
25
+
Defined in: [host/forge-core.ts:126](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L126)
26
26
27
27
***
28
28
29
29
### logger
30
30
31
31
> **logger**: `object`
32
32
33
-
Defined in: [host/forge-core.ts:128](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L128)
33
+
Defined in: [host/forge-core.ts:128](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L128)
34
34
35
35
#### debug
36
36
@@ -92,4 +92,4 @@ Defined in: [host/forge-core.ts:128](https://github.com/chriswritescode-dev/open
92
92
93
93
> **loop**: `Loop`
94
94
95
-
Defined in: [host/forge-core.ts:127](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L127)
95
+
Defined in: [host/forge-core.ts:127](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L127)
Copy file name to clipboardExpand all lines: docs/api/interfaces/CreateSessionDirectoryLookupOptions.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,36 +6,36 @@
6
6
7
7
# Interface: CreateSessionDirectoryLookupOptions
8
8
9
-
Defined in: [host/forge-core.ts:210](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L210)
9
+
Defined in: [host/forge-core.ts:210](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L210)
10
10
11
11
## Properties
12
12
13
13
### client
14
14
15
15
> **client**: `ForgeClient`
16
16
17
-
Defined in: [host/forge-core.ts:211](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L211)
17
+
Defined in: [host/forge-core.ts:211](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L211)
18
18
19
19
***
20
20
21
21
### directory
22
22
23
23
> **directory**: `string`
24
24
25
-
Defined in: [host/forge-core.ts:212](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L212)
25
+
Defined in: [host/forge-core.ts:212](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L212)
26
26
27
27
***
28
28
29
29
### loop
30
30
31
31
> **loop**: `Loop`
32
32
33
-
Defined in: [host/forge-core.ts:213](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L213)
33
+
Defined in: [host/forge-core.ts:213](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L213)
34
34
35
35
***
36
36
37
37
### negativeTtlMs?
38
38
39
39
> `optional`**negativeTtlMs?**: `number`
40
40
41
-
Defined in: [host/forge-core.ts:214](https://github.com/chriswritescode-dev/opencode-forge/blob/60a77095f4a0787f7b93be817c313586da5e2cc2/src/host/forge-core.ts#L214)
41
+
Defined in: [host/forge-core.ts:214](https://github.com/chriswritescode-dev/opencode-forge/blob/9f9f4b4938fa505ff72d179150b77baca67ba3e6/src/host/forge-core.ts#L214)
0 commit comments