Documentation
Architecture
The layers of the harness and what each one owns.
Forge is a harness around a model, and the harness is the part that matters. The model proposes; the layers below decide what actually happens, and stay in charge when the model is wrong.
┌─────────────────┐ │ Developer │ └────────┬────────┘ │ one task, one sentence ▼ ┌─────────────────┐ │ Forge CLI │ flags · config · REPL └────────┬────────┘ ▼ ┌─────────────────┐ │ Agent runtime │ the loop, until done └────────┬────────┘ │ ┌────────────────────┼────────────────────┐ ▼ ▼ ▼ ┌─────────┐ ┌──────────┐ ┌──────────┐ │ Context │ │ Tools │ │ Provider │ └────┬────┘ └────┬─────┘ └────┬─────┘ │ │ risk-gated │ ▼ ▼ ▼ conversation ┌──────────┐ model call + compaction │ Policy │ └────┬─────┘ ▼ filesystem · shell · git │ ▼ RepositoryWhat each layer owns
CLI
Parsing flags, resolving configuration from five sources, and choosing between a session and a one-shot run. Owns the exit code.
Knows nothing about tools or prompts.
Agent runtime
The loop. Sends the conversation to the provider, receives tool calls, dispatches them, appends results, and decides whether the task is done.
Never touches the filesystem itself.
Context
The conversation, the environment summary gathered at startup, and compaction when the window fills.
Holds no state between runs.
Tool registry
Names, typed schemas, risk levels, and handlers. One interface, whatever the tool does.
Does not decide whether a call is allowed.
Permission policy
Deny matching, escalation, allow-lists, and the mode lookup. Every call passes through it.
Cannot be bypassed by a tool or a prompt.
Provider
Turning a conversation into a model call and a reply into tool calls. Anthropic today, plus a fake for tests.
The only layer that makes a network request.
The loop
One iteration is: send the conversation, receive tool calls, run them through the policy, append the results, repeat. It ends when the model stops asking for tools, or when the iteration ceiling is reached.
The last stage feeds back into the middle. That single edge is the difference between an agent and a model call - a failing test is not the end of the run, it is the input to the next iteration.
Design decisions worth knowing
Tool results are data, never exceptions
A missing file, a non-zero exit, a patch that will not apply - each comes back as a result the model must read. Nothing about a failed tool call ends the run, which is precisely what allows the loop to correct itself.
The policy sits below the registry
Permission checks happen at dispatch, not inside individual handlers. A new tool cannot forget to ask, and a prompt cannot talk its way around the check because the check is not in the conversation. See Permissions.
Paths resolve against one root
Every filesystem tool resolves relative to the workspace root and refuses a path that escapes it. There is one place that logic lives, so there is one place to audit.
Compaction instead of failure
When the context approaches the window limit, earlier history is summarised rather than truncated blindly. A long run degrades in fidelity instead of dying at a hard boundary.
The provider is an interface
The loop depends on an interface, not a vendor. That is what makes the fake provider possible - the whole harness is testable with no network and no spend - and it is where additional providers attach.
Observability
- Each tool call is logged as it happens, with its arguments, at the level you set.
FORGE_LOG_JSONswitches the step log to structured JSON for ingestion.- Every run prints a summary: duration, model calls, tool calls, and token usage.
--jsonputs a machine-readable result on stdout while the log stays on stderr, so both are usable at once.
Reading the log is the fastest way to understand the agent's behaviour. When a run goes wrong, it usually went wrong several steps before the visible failure - and the log shows where.