foldkit
foldkit is a frontend framework for TypeScript built on Effect-TS, implementing The Elm Architecture. It is a good stress test for the analyzer because it mixes small example apps, framework internals, long runtime orchestration files, subscriptions, managed resources, routing, and devtools.
This case study is based on the current analyzer output against the real foldkit repository.
Project-level architecture is the strongest view now
Section titled “Project-level architecture is the strongest view now”Run the analyzer at the repository root with the architecture format:
npx effect-analyze ./ \ --format architecture \ --no-colocateCurrent output:
Found 9 service(s), 33 unresolved.
Project architecture (30 runtimes, 6 layer assemblies)...program (examples/todo/src/main.ts) Constructor: Runtime.makeProgram Loop: Flags -> init -> Model + Commands Loop: Message -> update -> Model + Commands Loop: Model -> view -> Html Commands in file: GenerateTodo, SaveTodos Capabilities: flags...overlayRuntime (packages/foldkit/src/devtools/overlay.ts) Constructor: makeProgram Loop: Flags -> init -> Model + Commands Loop: Message -> update -> Model + Commands Loop: Model -> view -> Html Subscriptions: makeOverlaySubscriptions(store) -> Message stream Devtools: false Commands in file: JumpTo, InspectState, InspectLatest, Resume, Clear, LockScroll, UnlockScroll, ScrollToTop Capabilities: flags, subscriptions, devtools...program (packages/website/src/main.ts) Constructor: Runtime.makeProgram Loop: Flags -> init -> Model + Commands Loop: Message -> update -> Model + Commands Loop: Model -> view -> Html Subscriptions: subscriptions -> Message stream Resources: Layer.mergeAll(...) Routing: { onUrlRequest: ..., onUrlChange: ... } (onUrlRequest, onUrlChange) Title: ({ route }) => routeTitle(route) Devtools: { show: 'Always', mode: 'Inspect', ... } Commands in file: InjectAnalytics, InjectSpeedInsights, CopySnippet, ... Capabilities: flags, routing, subscriptions, resources, title, devtoolsThis is where the analyzer is most useful on foldkit today. It does not just find Effect programs. It reconstructs the application shape:
Flags -> init -> Model + CommandsMessage -> update -> Model + CommandsModel -> view -> Html- optional capabilities like
routing,subscriptions,resources,managedResources,crash,slowView,title, anddevtools - command definitions per file
For foldkit, that architecture summary is more valuable than a raw per-call diagram of every file.
Example app output is clean
Section titled “Example app output is clean”Running architecture mode on a single example app gives a compact Elm-style summary:
npx effect-analyze ./examples/todo/src \ --format architecture \ --no-colocateProject architecture (1 runtime, 0 layer assemblies)
program (main.ts) Constructor: Runtime.makeProgram Loop: Flags -> init -> Model + Commands Loop: Message -> update -> Model + Commands Loop: Model -> view -> Html Commands in file: GenerateTodo, SaveTodos Capabilities: flags
Command definitions: main.ts: GenerateTodo, SaveTodosThat is the level of summary most users want first when they open a foldkit app.
The same example also produces small Mermaid diagrams well:
npx effect-analyze ./examples/todo/src/main.ts --format mermaidflowchart TB %% Program: saveTodos start((Start)) end_node((End)) n2["store <- KeyValueStore.KeyValueStore (service-call)"] n3["store.set (side-effect)"] %% Edges n2 --> n3 start --> n2 n3 --> end_node %% Styles classDef startStyle fill:#c8e6c9,stroke:#2e7d32 classDef endStyle fill:#ffcdd2,stroke:#c62828 classDef effectStyle fill:#90EE90,stroke:#333,stroke-width:2px class start startStyle class end_node endStyle class n2 effectStyle class n3 effectStyle
That is still an important part of the tool. The analyzer works best on foldkit when you use architecture mode first, then drop to Mermaid for small, self-contained programs.
The large runtime file is still analyzable
Section titled “The large runtime file is still analyzable”The main runtime file is still large and noisy, but the analyzer now gets enough structure out of it to be useful:
npx effect-analyze ./packages/foldkit/src/runtime/runtime.ts \ --format explainExcerpt from the current output:
program-2 (generator): 1. maybeResourceLayer = If resources: Provides layer: Calls resources 2. managedResourceRefs = Iterates (forEach) over managedResourceEntries: (opaque: callback-body) 3. Yields flags <- resolveFlags 4. messageQueue = queue.create 5. modelSubscriptionRef = subscriptionRef.create 6. Iterates (forEach) over initCommands: (opaque: callback-body) 7. Yields modelRef <- make ... 14. If Option.isSome(resolvedDevtools): Yields devtoolsStore <- createDevtoolsStore Calls set Calls devtoolsStore.recordInit Calls createOverlay 15. Calls render 16. If subscriptions: Pipes subscriptions through: Calls subscriptions Calls Record.toEntries Iterates (forEach) ... 17. Iterates (forEach) over managedResourceRefs: Calls forkManagedResourceLifecycle 18. Pipes forever through: Calls forever Handles errors (catchAllCause)The important part is not perfect prettiness. It is that the analyzer now recovers the runtime shape:
- resource layer setup
- managed resource reference creation
- flag resolution
- message queue and subscription reference setup
- init command forking
- devtools bootstrapping
- render loop
- subscription wiring
- managed resource lifecycle forking
- forever-processing loop
That is enough to orient a reader in a file that is otherwise hard to scan.
Devtools store is now concise
Section titled “Devtools store is now concise”The current analyzer output for the devtools store is concise:
npx effect-analyze ./packages/foldkit/src/devtools/store.ts \ --format explaincreateDevtoolsStore (generator): 1. stateRef = subscriptionRef.create 2. Calls gen 3. subscriptionRef.update
jumpTo (generator): 1. state = subscriptionRef.get 2. Calls bridge.render 3. subscriptionRef.set
resume (generator): 1. currentModel = Bridge.getCurrentModel — service-call 2. Calls bridge.render 3. subscriptionRef.update
Services required: BridgeAnd for this file, Mermaid is still useful for the smaller programs:
npx effect-analyze ./packages/foldkit/src/devtools/store.ts --format mermaidflowchart TB %% Program: resume start((Start)) end_node((End)) n2["currentModel <- bridge.getCurrentModel (service-call)"] n3["bridge.render <unknown, never, never> (side-effect)"] n4["subscriptionRef.update (concurrency)"] %% Edges n2 --> n3 n3 --> n4 start --> n2 n4 --> end_node %% Styles classDef startStyle fill:#c8e6c9,stroke:#2e7d32 classDef endStyle fill:#ffcdd2,stroke:#c62828 classDef effectStyle fill:#90EE90,stroke:#333,stroke-width:2px classDef concurrencyPrimitiveStyle fill:#B0E0E6,stroke:#333,stroke-width:2px class start startStyle class end_node endStyle class n2 effectStyle class n3 effectStyle class n4 concurrencyPrimitiveStyle
This is a better fit for real review. The analyzer now avoids inventing fake service dependencies for stateful primitives like SubscriptionRef, and it can recognize service-backed calls like Bridge.getCurrentModel.
What the analyzer is good at on foldkit
Section titled “What the analyzer is good at on foldkit”- detecting
Runtime.makeProgramstyle app loops across many apps - extracting command definitions at project scale
- surfacing capabilities like routing, subscriptions, resources, managed resources, crash handlers, slow view hooks, title hooks, and devtools
- recognizing service-backed calls in smaller generators
- keeping large runtime files readable enough to navigate
What still compresses poorly
Section titled “What still compresses poorly”Some framework internals are still only partially summarized:
- callback-heavy
forEachbodies in the runtime still show as(opaque: callback-body)in a few places - some helper-heavy pipes still collapse to generic calls like
Calls gen - architecture extraction is stronger than low-level flow rendering on the largest internal files
That is an acceptable tradeoff for now. On foldkit, the analyzer is already more useful as an architecture and orientation tool than as a perfect instruction-by-instruction renderer.
Coverage snapshot
Section titled “Coverage snapshot”Project mode currently reports:
npx effect-analyze ./ \ --project \ --no-colocateFound 9 service(s), 33 unresolved.Analyzed 284 file(s), 1399 program(s).The analyzer is recovering the structure of the framework and its example applications at repository scale.