A source-backed reference for every module in the src/ directory. Each section lists its purpose, key files, public exports, and relationships.
See also: Architecture, Loop System, API Reference.
src/
├── index.ts # Server plugin entry point (V2 setup)
├── tui.tsx # TUI plugin entry point (V2 setup)
├── config.ts # Agent/command configuration handler
├── setup.ts # Config loading, skill installation
├── types.ts # Core type definitions (PluginConfig, etc.)
├── version.ts # VERSION constant generated from package.json
│
├── agents/ # AI agent definitions
├── client/ # ForgeClient port + V2 host adapter
├── host/ # Host-neutral core + V2 composition adapter
├── hooks/ # Plugin event/lifecycle hooks
├── loop/ # Core loop state machine & runtime
├── services/ # Business logic services
├── sandbox/ # msb sandbox management
├── storage/ # SQLite persistence layer
├── tools/ # Plugin tools callable by AI agents
├── tui/ # TUI-specific components
├── utils/ # Shared utility modules (~40 files)
└── workspace/ # Git worktree / workspace management
The server plugin entry. The default export is the OpenCode 2.x module (id + setup) built with define.
Public API (src/index.ts):
| Export | Type | Description |
|---|---|---|
setupForgeV2(ctx) |
Function | OpenCode 2.x setup entry, exported for the module and tests |
createParentSessionLookup(options) |
Function | Resolves parent sessions across worktrees |
createSessionDirectoryLookup(options) |
Function | Resolves session directory across worktrees |
PluginConfig |
Interface | Complete plugin configuration |
CompactionConfig |
Interface | Session compaction settings |
VERSION |
Constant | Plugin version string |
Source: src/index.ts
The TUI plugin entry, providing the sidebar widget and dialog system. It talks to the server plugin through the V2 plugin RPC port.
- Exports
{ id: 'oc-forge', setup: setupForgeTuiV2 } - Registers commands:
Execute plan,Open web dashboard,Build sandbox template, andToggle sandbox - Provides the loop sidebar, session-rotation following, and the missing-build-context toast
Source: src/tui.tsx, src/tui/v2.tsx
Host-neutral core plus the thin adapter that maps the OpenCode V2 plugin context onto it.
| File | Purpose |
|---|---|
forge-core.ts |
createForgeCore() — shared services, handlers, tools, cleanup, sandbox resolution, lookups |
v2.ts |
setupForgeV2(ctx) — V2 setup: client, registrations, event pump, cleanup |
v2-events.ts |
Normalizes V2 events into Forge's event shape; busy, idle, and retry derive only from session.execution.* and session.retry.scheduled |
forge-rpc.ts |
FORGE_RPC contract: the TUI methods (executePlan, loopDefaults, autoApproveState/autoApproveSet, loops, loopSidebar, sessionPlan, loopRestart, hostSandboxState/hostSandboxSet, worktrees, version) and the toast/sessionDelete/loopsChanged/autoApproveChanged/hostSandboxChanged events the V2 server emits and the V2 TUI consumes |
v2-hooks.ts |
Registers the core handlers through V2's hook API |
v2-tools.ts |
Registers the shared Forge tools on V2 |
v2-config.ts |
Resolves and registers agents and commands on V2 |
createForgeCore(config: PluginConfig, host: ForgeHostInput): Promise<ForgeCore>
buildArchitectReminder(): string
createParentSessionLookup(options): ...
createSessionDirectoryLookup(options): ...
setupForgeV2(ctx: Plugin.Context): Promise<() => Promise<void>>Source: src/host/forge-core.ts, src/host/v2.ts
The port every Forge service depends on, plus the V2 adapter.
| File | Purpose |
|---|---|
port.ts |
ForgeClient interface |
v2-adapter.ts |
Adapter over the V2 plugin context |
v2-workspaces.ts |
V2 worktree/location workspace implementation |
errors.ts |
Shared error classification and unavailableError() |
Source: src/client/port.ts
Defines roles and system prompts for each AI agent used in the forge pipeline.
| File | Purpose |
|---|---|
index.ts |
buildAgents() factory, barrel exports |
types.ts |
AgentRole, AgentDefinition, AgentConfig types |
code.ts |
Code execution agent |
architect.ts |
Read-only planning/design agent |
auditor.ts |
Code review agent + auditor-loop variant |
architect-auto.ts |
Autonomous architect agent |
feature-splitter.ts |
Splits a PRD into features for a group |
buildAgents(): Record<AgentRole, AgentDefinition>
type AgentRole = 'code' | 'architect' | 'auditor' | 'auditor-loop' | 'architect-auto' | 'feature-splitter'Source: src/agents/index.ts
Translates OpenCode events into loop actions and manages lifecycle side-effects.
| File | Purpose |
|---|---|
index.ts |
Barrel exports |
session.ts |
Session lifecycle (message, compacting) |
loop.ts |
LoopEventHandler adapter (events → Loop runtime) |
host-side-effects.ts |
Termination side-effects (teardown, toast, log) |
watchdog.ts |
Stall detection and recovery |
plan-approval.ts |
Plan approval dedup/event gating + tool execute before/after hooks |
plan-capture.ts |
Marked-plan capture from streaming assistant message parts |
forge-session-attach.ts |
Auto-attach loops on session.created and chat.message events |
loop-permission.ts |
Patches subagent permission rulesets on session.created for active-loop sessions |
sandbox-tools.ts |
Sandbox tool before/after redirection hooks |
sandbox-message.ts |
Tells the agent its tool calls run in a container |
group-orchestrator.ts |
Advances queued features when a group loop terminates |
tool-hook-types.ts |
Shared tool before/after hook types |
createSessionHooks(): SessionHooks // Session lifecycle hooks (session.ts)
createLoopEventHandler(): LoopEventHandler // Loop event handling adapter (loop.ts)
createToolExecuteBeforeHook() // Pre-tool execution hook (plan-approval.ts)
createToolExecuteAfterHook() // Post-tool execution hook (plan-approval.ts)
createPlanApprovalEventHook() // Plan approval event hook (plan-approval.ts)Additional hooks available via direct imports (not re-exported by the barrel):
createSandboxToolBeforeHook()/createSandboxToolAfterHook()— sandbox tool redirection (sandbox-tools.ts)createSandboxMessageHook()— container note injection (sandbox-message.ts)createForgeSessionAttachHook()/createForgeSessionMessageAttachHook()— auto-attach loops on session events (forge-session-attach.ts)createLoopPermissionPatcher()— patch subagent permissions onsession.created(loop-permission.ts)createPlanCaptureEventHook()— plan marker extraction from streaming parts (plan-capture.ts)createGroupOrchestratorEventHook()— group scheduling on loop termination (group-orchestrator.ts)
Source: src/hooks/index.ts
The heart of Forge. Implements autonomous iterative development with phases: coding → auditing → final_auditing → post_action.
| File | Purpose |
|---|---|
index.ts |
Public API barrel (all re-exports) |
runtime.ts |
createLoop() factory, Loop interface |
service.ts |
DB-backed LoopService (createLoopService) |
state.ts |
Discriminated union LoopState (4 phases: coding, auditing, final_auditing, post_action), row↔state converters |
transitions.ts |
Pure nextTransition() table — no side effects; includes 'post-action-complete' event and handlePostActionEvent |
termination.ts |
TerminationReason union, terminationStatusFor() |
prompts.ts |
Prompt builders for each loop phase, including buildPostActionPrompt() |
post-action-config.ts |
ResolvedPostActionConfig interface and resolvePostActionConfig() resolver |
section-summary.ts |
Parse audit output markers |
idle-gate.ts |
Session busy detection and timeout tracking |
in-flight-guard.ts |
Single-flight guard for concurrent loop start attempts |
restartability.ts |
getRestartability() — decides whether a non-completed loop can restart, blocked, or requires force |
token-usage.ts |
Extract and normalize per-message usage from session output |
name-uniqueness.ts |
Reserve a unique loop identity before any side effects |
session-output.ts |
Fetch session output for loop display |
type Phase = 'coding' | 'auditing' | 'final_auditing' | 'post_action'
type LoopState =
| CodingState
| AuditingState
| FinalAuditingState
| PostActionState
type TerminationReason =
| { kind: 'completed' }
| { kind: 'cancelled' }
| { kind: 'user_aborted' }
| { kind: 'shutdown' }
| { kind: 'max_iterations' }
| { kind: 'stall_timeout' }
| { kind: 'missing_worktree_dir' }
| { kind: 'session_creation_failed' }
| { kind: 'audit_retry_exhausted' }
| { kind: 'final_audit_retry_exhausted' }
| { kind: 'coding_no_assistant' }
| { kind: 'worktree_failed'; message: string }
| { kind: 'error_max_retries'; message: string }// Runtime
createLoop(deps: LoopRuntimeDeps): Loop
isWorkspaceNotFoundError(error): boolean
// State
loopRowToState(row, largeFields?): LoopState
loopStateToRow(state, projectId): LoopRow
MAX_RETRIES: number
// Transitions
nextTransition(state, event): Transition
// Prompts
buildContinuationPrompt(state, auditFindings?): string
buildAuditPrompt(state): string
buildSectionInitialPrompt(state, sectionIndex?): string
buildSectionAuditPrompt(state, sectionIndex?): string
buildSectionContinuationPrompt(state, sectionIndex?): string
buildFinalAuditPrompt(state): string
buildPostActionPrompt(state, opts): string
// Termination
terminationStatusFor(reason: TerminationReason): TerminationStatus
terminationReasonToString(reason): string
parseTerminationReasonString(str): TerminationReason
// Section summary
parseSectionSummary(text): { startLine, endLine, summary }
SECTION_SUMMARY_START_MARKER: string
SECTION_SUMMARY_END_MARKER: string
// Idle gate
sessionsAwaitingBusy: Map<string, ...>
AWAITING_BUSY_TIMEOUT_MS: number
markPromptSent(sessionId, loopName): void
clearPromptPending(sessionId): void
isAwaitingBusy(sessionId): boolean
isAwaitingBusyExpired(sessionId): boolean
// Name uniqueness
generateUniqueName(baseName: string, existingNames: readonly string[]): string
// Session output
fetchSessionOutput(client, sessionId, directory, logger?, options?): LoopSessionOutput | nullAll external consumers import through the barrel: src/loop/index.ts
Source: src/loop/index.ts
Higher-level orchestration services coordinating between hooks, loop runtime, and storage.
| File | Purpose |
|---|---|
execution.ts |
Unified command bus for plan execution (createForgeExecutionService()) |
session-loop-resolver.ts |
Resolve which loop owns a given session |
unified-sandbox-resolver.ts |
Loop-first sandbox resolution shared by the shell wrapper and tool hooks |
deterministic-decomposer.ts |
Slice a plan into milestones (section_plans rows) deterministically — called once at loop start by execution.ts, not a runtime loop phase |
section-bootstrap.ts |
Build the initial milestone rows for a loop |
plan-capture.ts |
The single write path into a session-scoped plans row (writeSessionPlanContent), marked-plan capture from messages, and resolveSessionPlanOfRecord — the one implementation of "stored plan wins, chat capture is the fallback" |
group-orchestrator.ts |
Feature-group scheduling and per-feature loop launch |
group-scheduler.ts |
Ordering and concurrency cap for a group's features |
tui-rpc-service.ts |
Server-side TUI RPC service: loop list/sidebar, session plan, loop restart (rejected when the loop was restarted after the dialog read it, checked under the shared loop lock), host-sandbox desired/applied state, and the worktree list |
worktree-log.ts |
Log worktree completions |
type ForgeExecutionSurface = 'tool' | 'approval-hook' | 'api' | 'tui'
interface ForgeExecutionRequestContext {
surface: ForgeExecutionSurface
projectId: string
directory: string
sourceSessionId?: string
requestId?: string
}
type PlanSource =
| { kind: 'inline'; planText: string }
| { kind: 'stored'; sessionId: string }
| { kind: 'loop-state'; loopName: string }Source: src/services/execution.ts
Drives the msb CLI to provision isolated sandboxes for loop execution.
| File | Purpose |
|---|---|
msb.ts |
SandboxRuntime facade over the msb CLI (create/exec/remove/list, availability probe) |
process.ts |
Child-process runner (runCommand) shared by the sandbox helpers |
template.ts |
Image build/save/load helper (docker build/docker save/msb load) |
config-warnings.ts |
Warnings for legacy Docker-era sandbox config keys |
manager.ts |
SandboxManager lifecycle management (start/stop/ensureRunning/isLive, orphan cleanup) |
reconcile.ts |
Sandbox reconciliation with loop states |
context.ts |
SandboxContext, isSandboxEnabled() |
path.ts |
Sandbox path utilities |
exec-fs.ts |
Filesystem operations through msb exec |
shell-shim.ts |
Generated shim routing the native shell tool through msb exec |
session-controller.ts |
Per-project host sandbox selection and ownership |
loop-settings.ts |
Per-loop sandbox overrides: validation, workspace extra carrier, and the effective-resource resolver shared by creation and the TUI |
env-probe.ts |
Bounded environment probe for the container note |
interface SandboxRuntime {
checkAvailable(): Promise<MsbAvailability>
templateExists(ref: string): Promise<boolean>
loadTemplate(tarPath: string, ref: string): Promise<void>
createSandbox(name: string, workspaces: SandboxWorkspace[], opts: CreateSandboxOpts): Promise<void>
removeSandbox(name: string): Promise<void>
exec(name: string, command: string, opts?: SandboxExecOpts): Promise<CommandResult>
getSandboxState(name: string): Promise<SandboxState>
sandboxContainerName(worktreeName: string): string
listSandboxesByPrefix(prefix: string): Promise<string[]>
refreshSandboxSecrets(name: string, secrets: SandboxSecretConfig[]): Promise<boolean>
readSandboxSettings(name: string): Promise<SandboxRuntimeSettings | null>
resizeSandbox(name: string, resources: Pick<SandboxResources, 'cpus' | 'memory'>): Promise<void>
}interface SandboxManager {
runtime: SandboxRuntime
start(worktreeName: string, projectDir: string, startedAt?: string, overrides?: SandboxOverrides): Promise<{ containerName: string }>
stop(worktreeName: string): Promise<void>
getActive(worktreeName: string): ActiveSandbox | null
isActive(worktreeName: string): boolean
isLive(worktreeName: string): Promise<boolean>
cleanupOrphans(preserveWorktrees?: string[]): Promise<number>
restore(worktreeName: string, projectDir: string, startedAt: string): Promise<void>
ensureRunning(worktreeName: string, projectDir: string, startedAt?: string): Promise<string>
applyOverrides(worktreeName: string, projectDir: string): Promise<ApplyOverridesOutcome>
}applyOverrides converges an existing sandbox to its effective settings (persisted overrides over config) and returns whether it was unchanged, resized (a CPU or memory change restarts the sandbox in place, keeping its disks), or recreated (a LAN-access change recreates it, because msb fixes network policy at create time). It rejects when the current settings cannot be read, so a LAN restriction is never assumed to hold.
SandboxManagerConfig no longer carries a dataDir field — its only reader was the deleted per-sandbox env-file writer. The overlapping-workspace drop rule is a single shared implementation used by both the mount plan and the workspace builder, so a mount conflict resolves identically on either path. removeSandbox also removes both of the sandbox's named volumes in one bulk msb volume rm — <container>-docker-data, which backs /var/lib/docker for the in-VM Docker Engine, and <container>-cache-data, which backs /opt/forge/cache. Because named volumes survive msb rm, stop routes through the same removal path even when the sandbox is already gone, so a container destroyed out of band still has its disks reclaimed.
Source: src/sandbox/msb.ts, src/sandbox/manager.ts
All data persistence via bun:sqlite. Organized as:
| Export | Description |
|---|---|
initializeDatabase(dataDir, options) |
Creates SQLite DB with migrations |
closeDatabase(db: Database) |
Closes database connections |
resolveDataDir() |
Platform-appropriate data directory |
resolveLogPath() |
Default log file path |
Each created via createXxxRepo(db) factory with project-scoped queries:
| Repository | Table(s) | Key Types |
|---|---|---|
LoopsRepo |
loops, loop_large_fields |
LoopRow, LoopLargeFields |
PlansRepo |
plans |
PlanRow |
ReviewFindingsRepo |
review_findings |
ReviewFindingRow |
SectionPlansRepo |
section_plans |
SectionPlanRow — one row per milestone (decomposed plan section). See Loop System. |
LoopTransitionsRepo |
loop_transitions |
LoopTransitionRow — append-only phase-transition log per loop |
PlanAmendmentsRepo |
plan_amendments |
PlanAmendmentRow — append-only plan-amendment audit trail |
LoopSessionUsageRepo |
loop_session_usage |
LoopSessionUsageRow, LoopUsageAggregate |
FeatureGroupsRepo |
feature_groups |
FeatureGroupsRepo — grouped-execution state |
LoopAttemptsRepo |
loop_attempts |
LoopAttemptsRepo — durable audit-attempt history |
SessionSandboxPreferencesRepo |
tui_preferences (JSON keys session-sandbox.desired / .applied / .controller) |
SessionSandboxPreferencesRepo — host-session sandbox desired/applied state |
SessionAutoApproveRepo |
tui_preferences (TTL-scoped JSON keys session-auto-approve.<sessionId>) |
SessionAutoApproveRepo — per-session auto-approve state |
Migrations are registered explicitly, in execution order, in the migrations array (ids 100–149; inline migrations are valid, so not every id ships a .sql file) and tracked in a migrations table.
See storage/migrations/README.md for migration details.
Source: src/storage/index.ts
Implements tools callable by AI agents during conversations.
| Tool | File | Description |
|---|---|---|
review-write |
review.ts |
Store a code review finding (file, line, severity, description) |
review-read |
review.ts |
Retrieve review findings, filter by file or regex pattern |
review-delete |
review.ts |
Delete a review finding by file and line |
plan-write |
plan-authoring.ts |
Architect agents create or overwrite the stored session plan; returns a structure report. Denied while the session owns a running loop. |
plan-edit |
plan-authoring.ts |
Architect agents edit the stored session plan by exact string replacement (oldString/newString/replaceAll); returns a structure report. |
plan-read |
plan-kv.ts |
Retrieve plans with pagination and pattern search |
section-read |
section-read.ts |
Retrieve the current, specified, or (with pending_suffix) ordered pending sections of an active loop's plan; titles are display labels, section content is the executable requirement |
plan-adjust |
plan-adjust.ts |
Auditor-only, section-audit-only: revise the section under audit (currentSection) and/or destructively replace the pending suffix (sections) of the active loop plan's executable section instructions; the stored master plan row is unchanged. Logged as a plan amendment |
execute-plan |
loop.ts |
Execute a plan using an iterative development loop, or mode: new-session for a fresh standalone session. Args: title required; plan, loopName, hostSessionId, mode optional. |
execute-goal |
loop.ts |
Execute a non-empty goal in a dedicated session inside a managed worktree. Args: goal required; title, loopName, maxIterations, hostSessionId optional. |
loop-status |
loop.ts |
List active/recent loops, show cumulative usage for detailed status, or restart loops with restart/force arguments |
loop-cancel |
loop.ts |
Cancel an active loop by worktree name |
tool.ts is the local tool() helper every definition uses; its schema is zod 4, and the V2 tool registrar converts each definition's args to JSON Schema.
All tool implementations receive a shared context:
interface ToolContext {
projectId: string
directory: string
config: PluginConfig
logger: Logger
db: Database
dataDir: string
loopHandler: LoopEventHandler
loop: Loop
client: ForgeClient
cleanup: () => Promise<void>
sandboxManager: SandboxManager | null
plansRepo: PlansRepo
reviewFindingsRepo: ReviewFindingsRepo
loopsRepo: LoopsRepo
sectionPlansRepo: SectionPlansRepo
loopSessionUsageRepo?: LoopSessionUsageRepo
featureGroupsRepo: FeatureGroupsRepo
groupOrchestrator: GroupOrchestrator
pendingTeardowns: PendingTeardownRegistry
resolveActiveLoopForSession: (sessionID) => Promise<ResolvedLoop | null>
}Source: src/tools/index.ts, src/tools/types.ts
Creates and manages git worktrees for isolated loop execution, registered through the V2 worktree inventory.
| File | Purpose |
|---|---|
forge-adapter.ts |
createForgeWorkspaceAdapter() — the host-neutral worktree adapter |
forge-worktree.ts |
bindSessionToWorkspace(), createBuiltinWorktreeWorkspace(), workspace permission rules |
forge-naming.ts |
Worktree/branch naming and forge-worktree directory detection |
forge-workspace-metadata.ts |
<worktree>/.forge/workspace.json read/write/list |
pending-teardown.ts |
Registry of pending teardown contexts for commit message building |
worktree-commit.ts |
Teardown commit building |
worktree-opencode-config.ts |
Writes opencode.jsonc into a fresh worktree |
classify-stale.ts |
Decision function for stale forge workspace handling |
remove-with-context.ts |
Workspace removal with teardown context |
sweep-stale.ts |
Opportunistic same-project sweep of stale forge workspaces during loop teardown |
Source: src/workspace/forge-adapter.ts
Cross-cutting helpers (~40 files) organized by concern:
| Group | Files | Purpose |
|---|---|---|
| Logging | logger.ts |
File logger with rotation (10MB max) |
| Caching | lru-cache.ts |
Generic LRU cache |
| Paths | opencode-paths.ts, shipped-paths.ts, resolve-project-root.ts |
Data/tool-output/tmp paths, bundled-asset root, project root |
| Plan | plan-execution.ts, plan-structure.ts, marked-plan-parser.ts, markdown-fences.ts |
Plan parsing, structure reports, marker extraction |
| Sections | section-capture.ts, section-summary.ts |
Section extraction/summary parsing |
| Loop | loop-helpers.ts, loop-format.ts, loop-session.ts, loop-registry.ts, loop-permission-options.ts, loop-permission-warnings.ts |
Loop model/format/session/permission helpers |
| Sessions | audit-session.ts, audit-snapshot.ts, coder-decisions.ts, session-ancestry.ts, session-titles.ts |
Session naming, ancestry, audit history |
| TUI | tui-execution-preferences.ts, tui-execution-context-cache.ts, tui-models.ts |
TUI preferences and models |
| Workspace | worktree-cleanup.ts, git-service.ts |
Worktree cleanup and git operations |
| Sandbox | sandbox-ready.ts |
Sandbox readiness probe |
| Misc | partial-match.ts, model-fallback.ts, busy-guard.ts, format.ts, duration.ts, is-record.ts, toast.ts, architect-auto-output.ts, feature-list-parser.ts, review-format.ts, cli-flags.ts, bundled-sync.ts |
Various helpers |
Security rules for loop and audit sessions.
buildLoopPermissionRuleset(options?): PermissionRule[] // Allow-all, then configured rules, then review/plan/loop structural denies
buildAuditSessionPermissionRuleset(options?): PermissionRule[] // Allow-all, configured rules, then structural denies for the direct mutation tools edit/write plus the shared plan/loop denies
resolveLoopPermissionOptions(config?): LoopPermissionRulesetOptions // Local resolver: configured loop.permissions deny rulesOnly deny entries are honoured; Forge-managed permissions and blanket denies of Forge-required
permissions (FORGE_REQUIRED_PERMISSIONS) are rejected with a warning.
Source: src/constants/loop.ts
Workspace-aware resolution (merges portable extra.permissionRules persisted in a workspace's metadata)
lives in resolveLoopPermissionOptionsForWorkspace.
Source: src/utils/loop-permission-options.ts
Every major component uses a factory function pattern with dependency injection:
setupForgeV2(ctx) // Server plugin entry
createForgeCore(config, host) // Host-neutral core
createLoop(deps) // Loop runtime
createLoopService(...) // State management
createSandboxManager(runtime, config, logger, git?) // Sandbox
createTools(ctx) // Tool registry
createForgeWorkspaceAdapter(deps) // Workspace
createMsbRuntime(logger) // Sandbox
createLogger(config) // LoggingDependencies are injected via parameter objects, not global singletons. The one deliberate exception is process-shared state (processShared in src/utils/process-shared.ts): OpenCode loads a separate module graph per location in one process, so state that must be one per process (host sandbox controllers, idle-gate markers, the loop registry) lives on globalThis under registered symbols, and every module copy resolves the same value.
Five modules use barrel index.ts files:
src/hooks/index.tssrc/storage/index.tssrc/loop/index.tssrc/agents/index.tssrc/tools/index.ts
Other modules do NOT have barrel files (utils, sandbox, services, workspace).
All data access goes through typed repo interfaces:
LoopsRepo,PlansRepo,ReviewFindingsRepo,SectionPlansRepo,LoopSessionUsageRepo,FeatureGroupsRepo- Each created via
createXxxRepo(db)with project-scoped queries. - Rows are mapped to domain objects via
loopRowToState()etc.
The loop follows a strict phase-based state machine:
- States:
coding,auditing,final_auditing,post_action - Transitions managed by
nextTransition()intransitions.ts - Each phase has dedicated prompt builders and session rotation logic
- State changes are persisted to SQLite after every mutation
A LoopChangeNotifier callback is threaded through all state mutation calls. It fires on insert, delete, terminate, rotate, phase, iteration, status, session, sandbox, workspace, audit-result, error, reconcile events.
setup(ctx) registers the core handlers through V2's hook API:
tool.transform— register the Forge tools and wrap the built-inshelltool for sandbox routingtool.hook('execute.before')/tool.hook('execute.after')— pre/post tool executionshell.hook('create.before')— sandbox shell routingsession.hook('prompt')— session message handlingsession.hook('context')— system context injection and the architect remindersession.hook('compaction')— context compactionagent.transform/command.transform— agent/command configuration injectionevent.subscribe— event dispatching