Skip to content

System Architecture Overview

This is the shortest authoritative technical description of Forge. Deeper documents explain each boundary.

1. System shape

text
┌───────────────────────────────────────────────────────────────┐
│ Electron                                                      │
│ window lifecycle · OS integration · Go core lifecycle         │
└──────────────────────────────┬────────────────────────────────┘


┌───────────────────────────────────────────────────────────────┐
│ React + TypeScript                                            │
│ views, interaction, cached server data, bounded live streams  │
└──────────────────────────────┬────────────────────────────────┘
                               │ generated RPC

┌───────────────────────────────────────────────────────────────┐
│ Go core                                                       │
│                                                               │
│ Domain → Application Commands → Durable Operations            │
│                                  │                            │
│                    ┌─────────────┼──────────────┐             │
│                    ▼             ▼              ▼             │
│                  Git     Execution Env     Agent Adapters     │
│                                                               │
│ SQLite · RawLog · Activity · Realtime Sync · Verification     │
└───────────────────────────────────────────────────────────────┘


                    local Git repositories

2. Responsibility rule

React knows presentation. Electron knows desktop integration. Go knows engineering work and execution. Agent Adapters know how to speak to agents. Execution Environments know where work runs. Git knows the repository.

This sentence should help resolve many future “where should this code go?” questions.

3. Core layers

Domain

Pure business concepts and transitions: Tasks, Plans, Reviews, Decisions, Agent Runs, revisions, and invariants. Domain code must not call SQLite, Git, processes, HTTP/RPC, or provider protocols.

Application

Use cases expressed as domain commands: StartTask, ResolveDecision, ApproveTask, SubmitPlanRevision, RunVerification, etc. Application code coordinates domain rules and persistence. It records side-effect intent but does not hide uncontrolled external work inside database transactions.

Durable Operations

External actions that cannot be made part of a SQLite transaction are represented as durable Operations. A worker performs them idempotently and records outcomes. This allows crash recovery and makes “command accepted” distinct from “side effect finished.”

Examples: create worktree, start agent, run verification, merge branch, remove worktree.

Infrastructure boundaries

  • GitService: invokes the installed Git executable.
  • ExecutionEnvironment: prepares and describes where work executes. First implementation: local worktree.
  • AgentAdapter: protocol/lifecycle integration for one adapter strategy.
  • ProcessRunner: one controlled argv-based process-launch boundary.
  • RawLog: append-only raw protocol retention written before parsing.
  • Storage: SQLite persistence and migrations.
  • RPC: generated boundary for desktop/client commands and queries.

4. The important separations

Task ≠ Agent Run ≠ Agent Turn ≠ process

A Task may have many Runs; a Run may have many Turns; a provider may implement a Run using one process, many processes, or a shared service.

Agent Adapter ≠ Execution Environment

Claude-via-streaming is about how to communicate with the worker. Local worktree versus Docker is about where the worker operates. Keeping these separate prevents a combinatorial integration mess.

State transition ≠ side effect

READY → WORKING is a domain decision. Starting a provider process is an external side effect. The first can commit transactionally; the second requires a recoverable Operation.

Live stream ≠ durable history

Token/tool deltas help the live UI. Historical state needs compact messages/activity, pagination, and bounded replay. Do not persist or replay a firehose as if it were the optimal read model.

Fact ≠ claim

Observed change and agent narration have different truth status in the data model.

5. Storage model

SQLite stores queryable application state. Raw provider streams live as append-only files on disk. Git remains source truth for code.

The database is not intended to become a giant raw transcript store or an event-sourcing framework that requires replaying everything to reconstruct a Task.

Important persisted JSON structures carry schema/version information.

6. API model

Mutations are domain commands rather than generic CRUD patches.

Prefer:

text
StartTask(task_id)
RequestChanges(review_id, comments)
ResolveDecision(decision_id, option_id)
ApproveTask(task_id)

Avoid giving the renderer an unrestricted UpdateTask({status: DONE}) path that bypasses rules.

Queries can be resource/view oriented.

7. Realtime model

Clients hydrate from a snapshot/query, then subscribe to bounded updates. Connection health and sync health are tracked separately. If a client cursor is too far behind, the core returns a fresh snapshot instead of replaying an unbounded backlog.

8. Concurrency model

Go goroutines and context.Context are sufficient. Concurrency is deliberately bounded: limited active agent runs, limited verification runs, bounded queues, and cancellation propagated from the owning Task/Run/Operation.

No external job queue is required.

9. Extension model

The first extension boundaries are compile-time/internal interfaces:

  • Agent Adapter Strategy
  • Execution Environment
  • Verification runner/definition

A general third-party plugin system is postponed until real use proves what the stable extension surface should be.

Forge is local-first. The docs are part of the product engineering system.