FivFold - Logo

How it works

High-level architecture of the FivFold CLI engine: packages, detection, manifests, pipeline, VFS, AST, and plugins.

Package structure

FivFold is built as a monorepo with three main packages. The core engine is shared; the UI and API CLIs orchestrate it for their respective domains.

@fivfold/core

Shared engine: VFS, StrategyPipeline, TemplateEngine, Manifests, TsMorphEngine, Detection, Workspace. Used by both CLIs. No framework or database specifics—fully agnostic.

@fivfold/ui

init, add, list, agents, setup. Uses VFS + loadUiManifest for copy-based scaffolding. No StrategyPipeline—templates are copied directly into your project.

@fivfold/api

init, add, list. Uses full pipeline (VFS + StrategyPipeline + TemplateEngine + manifests + AST) for manifest-based Kits. Legacy registry mode for older modules.

Architecture

The FivFold CLI is an extensible scaffolding engine. It does not hardcode every stack permutation. Instead, it uses manifests to describe Kits, a Strategy Pattern to compose generators, and a Virtual File System to stage changes before committing.

FivFold CLI Architecture

Shared config

Both CLIs read from fivfold.json. Run @fivfold/ui init first if you use both; the API init merges its config into the existing file in a monorepo setup.

Pipeline

When you run npx @fivfold/api add <module>:

1

Detect

Parse package.json to detect framework and ORM. Skip prompts when detected.
2

Load manifest

Load the Kit manifest (or legacy registry). Manifest lists files, dependencies, AST mutations.
3

Run strategies

Run strategies in order: domain → framework → orm → auth (when applicable). Each strategy generates files into the VFS.
4

VFS stage

All creates, modifies, and deletes are staged. No disk writes until commit.
5

Commit

If not --dry-run, flush to disk atomically. Then run npm install for new dependencies.

UI vs API

API uses StrategyPipeline for manifest-based Kits. UI uses VFS + manifests for copy-based scaffolding—no pipeline, just direct template copy.

Manifests

Kits are defined by declarative JSON/YAML schemas (manifests). The manifest specifies dependencies to install, template files to copy, and AST mutation targets. The CLI acts as an agnostic orchestrator—it does not hardcode every Kit.

Manifest-driven

Modern Kits use .kit.json manifests in ui/manifests/ and api/manifests/. Declarative, extensible, and easy to add new Kits.

Legacy registry

Older modules may use registry JSON. Still supported for backward compatibility. New Kits use manifest-driven approach.

Manifest structure

A .kit.json typically includes: files (templates to copy), shadcnDependencies (primitives to add), astMutations (targets for code injection), and optional auth provider configuration when applicable.

Strategy Pattern

FivFold avoids hardcoding directories for every stack permutation. Instead, it uses interchangeable strategy classes. Each strategy implements IGeneratorStrategy and generates files for its layer. The pipeline composes them based on the user's selection.

domain

Framework-agnostic entities, DTOs, ports (interfaces).

framework

Modules, controllers, routes, middleware—adapts to your chosen framework.

orm

Entities, repositories, schema—adapts to your chosen data layer.

auth / delivery

Auth adapters when applicable; HTTP transport wiring.

StrategyPipeline runs strategies in order. Each receives a GeneratorContext with the VFS, template engine, manifest, and stack config. Strategies write to the VFS—they never touch the disk directly.

Strategy pipeline
// Simplified flow const pipeline = new StrategyPipeline([ getStrategy('domain'), getStrategy('framework'), getStrategy('orm'), getStrategy('auth'), // Optional, when applicable ]); await pipeline.run(ctx);

Virtual File System

The VFS ensures no partial writes. All file creations, modifications, and deletions are staged in memory first. Only after all generators complete successfully does the VFS flush to disk in a single transaction. If any step fails, nothing is written.

1

Stage

All operations go to stageCreate, stageModify, or stageDelete. Nothing hits disk.
2

Preview or commit

With --dry-run, call preview(root) to see the diff. Otherwise, call commit(root) to write atomically.

From @fivfold/core:

  • stageCreate(path, content) — Stage a new file
  • stageModify(path, content) — Stage an overwrite
  • stageDelete(path) — Stage a deletion
  • preview(rootDir) — Human-readable diff for dry run
  • commit(rootDir) — Write all staged ops to disk
Preview without writing
npx @fivfold/api add <module> --dry-run

AST Engine

For existing files, FivFold never uses regex or .replace(). That would be fragile and could destroy user modifications. Instead, it uses Abstract Syntax Tree (AST) manipulation via ts-morph: parse the file, inject the node, serialize back.

Existing vs new files

AST mutations apply only to existing files (e.g. app entry, module registration). New files use Handlebars templating.

Built-in mutations include:

  • Register module in app — Add a module to app imports
  • Register middleware — Add middleware to the app
  • Add import if not present — Inject an import statement when missing

Plugin Architecture

FivFold has two packages today: @fivfold/ui and @fivfold/api. The architecture is being prepared for a unified, language-agnostic future.

Orchestrator

Terminal input, VFS, manifest resolution, pipeline orchestration. Framework and database agnostic.

Plugins

Language-specific logic (e.g. ts-morph for Node/TypeScript) will live in isolated plugins. The orchestrator stays agnostic; plugins do the heavy lifting.

Search docs

Search documentation by title or keywords