Skip to content
ƒtsforgev0.52.0
19

Subsystems

8 min read

Derived from packages/core/src: 30 subsystems, 686 files, 134k lines, 143 cross-subsystem edges.

This page is the exhaustive record: every subsystem, every cross-subsystem edge, and a file:line witness for each claim. For the shape of the system rather than its inventory, see the hand-drawn map on Internals.

SubsystemPurposeTierFilesLinesFan-inFan-out
loopThe drive-to-green engine: turns, tools, gate settling, steering, adapterscore17045k822
rule-packsThe ESLint rule packs the gate enforces, grouped by stackcore19123k33
renderTerminal UI — status bar, menus, wizards, markdown, diffs, spinnerscore4511k77
cliArgument parsing, the interactive REPL, and per-mode wiringcore259k218
agentTool schemas, the model-as-agent wrapper, and the malformed-tool-call repair laddercore114k89
inferenceOpenAI-compatible provider: streaming, tool calls, reasoning, token usagecore123k104
meta-rulesGate rules that need no AST — config shape, CI wiring, supply chaincore423k12
self-harnessLets the harness propose, trial, and keep edits to its own prompts and rulesoptional153k29
configtsforge.config.json, profiles, recipes, agent specs, and external pluginscore133k98
scaffoldStands up a new project from an archetype and configures its gateoptional203k33
(root)CLI entry, model registry, session persistence — the loose files in src/core63k615
editorThe terminal input-line editor behind the REPL promptcore102k22
gateComposes and runs the deterministic gate: linter, stages, tool pathscore152k58
reviewersIndependent review panel that grades a change before it is trustedoptional92k13
evalRun scoring, failure classification, and the quality judgeoptional102k44
libShared primitives — fs, json, guards, scope globs, SSRF checks, clipboardcore182k240
filesReading, creating, and hash-anchored editing of workspace filescore92k51
policyDecides which actions are allowed in the current mode before they runcore52k53
architecture ⚠️Derives this map from source so the docs cannot drift from the codeoptional81k00
mcpModel Context Protocol client that exposes external servers as toolsoptional8<1k21
lspTypeScript language service powering navigation and write-time diagnosticsoptional3<1k50
browserHeadless Chromium oracle that render-checks a page as a gate stageoptional3<1k11
infer-rulesScans a repo for its conventions and turns them into rule overridescore7<1k52
validateRuns the gate command and parses tool output into structured errorscore7<1k72
specTask and spec shapes, spec parsing, and test generation from intentcore6<1k66
stack-detectionDetects the project’s stack and picks which rule packs applycore4<1k81
setupOnboarding wizard that writes a project’s initial tsforge configoptional4<1k25
codebaseStructural workspace map and hub ranking used to seed prompt contextcore6<1k24
proptest ⚠️Derives property-based test inputs from TypeScript typesoptional3<1k00
constitution ⚠️Baseline system-role text and the reference ESLint constitutionoptional1<1k00

⚠️ marks a subsystem with no imports in either direction inside src/. That does not make it dead — it may be reached only from tests/ or scripts/ — but it does mean the running harness never pulls it in.

Pairs that import each other, with the line proving each direction. Only mutual pairs are listed: longer cycles exist in a graph this dense, and enumerating them buries the ones someone can actually go and break.

PairOne wayThe other
(root)clicli.ts:30./cli/argscli/config-menu.ts:10../models-config
(root)gatecli.ts:32./gate/gate-runnergate/core-gate.ts:3../update-check
(root)inferenceclassify.ts:1./inferenceinference/image-gen.ts:4../models-config
(root)loopcli.ts:13./looploop/expert-handoff.ts:21../models-config
agentinferenceagent/agent-runner.ts:18../inferenceinference/wire.ts:9../agent
agentloopagent/agent-runner.ts:21../loop/loop.typesloop/context-hygiene.ts:12../agent/agent.constants
agentpolicyagent/agent-runner.ts:20../policypolicy/classify.ts:1../agent
agentspecagent/agent.types.ts:1../specspec/generate-tests.ts:5../agent
clirendercli/banner.ts:9../renderrender/command-menu.ts:2../cli/commands
configrule-packsconfig/external-plugins.ts:5../rule-packsrule-packs/index.ts:135../config/plugin-fingerprint
editorrendereditor/completion.ts:8../render/file-menurender/frame/input-seq.ts:1../../editor/segments
evalloopeval/failure-class.ts:1../loop/loop.typesloop/loop.types.ts:7../eval/failure-class
inferenceloopinference/wire.ts:10../loop/context-hygieneloop/assistant-message.ts:1../inference
looprenderloop/gate/panel.ts:3../../render/frame/ansi-plainrender/agent-tree.ts:8../loop/loop.types
loopself-harnessloop/feedback/rule-docs.ts:3../../self-harness/overlayself-harness/build-evidence.ts:3../loop
loopspecloop/feedback/feedback.ts:2../../specspec/generate-tests.ts:4../loop
specvalidatespec/generate-tests.ts:8../validatevalidate/accept.ts:1../spec

The interfaces an adapter fills in. The core loop may not import an adapter — @typescript-eslint/no-restricted-imports in eslint.config.js enforces it — so everything stack-specific arrives through one of these.

SeamDeclaredFiles referencing it
IStackAdapterloop/planning/stack-adapter.ts:146
IConventionProviderloop/conventions-provider.ts:1017
IPlanSchemaloop/planning/plan-types.ts:458
IGategate/gate-runner.ts:2522
IProductPlanloop/planning/plan-types.ts:3210

Async functions returning an exit code, declared under the CLI — the commands.

FunctionDeclared
agentsModecli.ts:364
greenfieldModecli.ts:665
harnessDiagnoseModecli/harness-diagnose-mode.ts:211
harnessReviewModecli/harness-review-mode.ts:700
maincli.ts:781
mapModecli.ts:500
recipesModecli.ts:519
replcli/repl.ts:1096
reviewModecli.ts:201
runOncecli.ts:103
runTraceCommandcli/repl-commands.ts:160
scaffoldModecli.ts:747
setupModecli.ts:508
traceModecli.ts:570

src/ reaching into scripts/ inverts the house rule that scripts orchestrate and src/ decides — logic imported this way sits where tests are not looking.

FromImportTarget
scaffoldscaffold/io.ts:11scripts/boot-check.ts

Stated so a gap is not mistaken for a clean result:

  • Dynamic import() and createRequire are not followed — only static imports.
  • tests/ and scripts/ are not scanned; only imports into them are noted above.
  • Coupling through shared global state or the filesystem is invisible here.
  • Only mutual dependency pairs are reported, not longer cycles.