@flowiseai/agentflow - Architecture
This document describes the internal architecture of the `@flowiseai/agentflow` package.
Overview
@flowiseai/agentflow - Architecture
This document describes the internal architecture of the @flowiseai/agentflow package.
Overview
The package follows a Domain-Driven Modular Architecture with clear separation of concerns. The goal is to separate low-level UI primitives from high-level business logic to ensure high reusability and easy testing.
src/
├── index.ts # Public Package API ("Public Face")
├── Agentflow.tsx # Main component
├── AgentflowProvider.tsx # Root provider (composition)
├── useAgentflow.ts # Primary public hook
│
├── atoms/ # ⚛️ UI Primitives ("What it looks like" (Dumb))
├── features/ # 🧩 Domain Features ("What it does" (Smart))
├── core/ # 🧠 Business Logic ("Business Rules" (Types/Logic))
└── infrastructure/ # 🌐 External Services ("Outside World" (API/Storage))
Directory Structure
atoms/ - UI Primitives
"What it looks like." Tiny, irreducible UI components with no business logic. These are the building blocks used by features.
atoms/
├── MainCard.tsx # Styled card wrapper
├── NodeInputHandler.tsx # Form input for node properties
├── ... # Other UI primitives
└── index.ts # Central export
Rules:
- Must be "dumb" and stateless
- No business logic
- No API calls
- Stateless or minimal local state
- Imported by features, never the reverse
- Forbidden: Importing from
features/orinfrastructure/(except types fromcore/typesfor prop definitions, design tokens fromcore/theme, and primitives fromcore/primitives)
Goal: 100% visual consistency.
features/ - Domain Features
"What it does." Complex, self-contained domain modules (silos) that house the application's core functionality. Each feature owns its components, hooks, and utilities.
features/
├── canvas/ # Core ReactFlow canvas
│ ├── containers/ # Smart components with state/logic
│ │ ├── AgentFlowNode.tsx
│ │ ├── AgentFlowEdge.tsx
│ │ ├── ... # Other node containers
│ │ └── index.ts
│ ├── components/ # Presentational components
│ │ ├── ConnectionLine.tsx
│ │ ├── NodeOutputHandles.tsx
│ │ ├── ... # Other presentational components
│ │ └── index.ts
│ ├── hooks/ # Canvas-related hooks
│ │ ├── useFlowHandlers.ts
│ │ ├── useDragAndDrop.ts
│ │ ├── ... # Other canvas hooks
│ │ └── index.ts
│ ├── styled.ts # Styled components
│ └── index.ts # Public API
│
├── node-palette/ # Add nodes drawer
│ ├── AddNodesDrawer.tsx
│ ├── search.ts # Feature-specific utility (private)
│ ├── ...
│ └── index.ts
│
├── generator/ # AI flow generation
│ ├── GenerateFlowDialog.tsx
│ ├── ...
│ └── index.ts
│
└── node-editor/ # Node property editing
├── EditNodeDialog.tsx
└── index.ts
Rules:
- Each feature has an
index.tsgatekeeper - Features never import from other features directly - If
canvasneeds logic fromgenerator, move that logic tocore/ - Feature-specific utils stay in the feature folder
- Styles are co-located with their feature
- Use
containers/for smart components (with state, hooks, side effects) - Use
components/for presentational components (props in, JSX out)
Goal: High cohesion. Should be able to delete a feature folder without breaking others.
core/ - Business Logic
"The Brain." Framework-agnostic logic, types, and utilities. No React, no UI - pure TypeScript. Contains validation schemas, node registries, domain constants, and shared types.
core/
├── types/ # Global interfaces (Node, Edge, Flow)
│ └── index.ts
├── primitives/ # Domain-free utilities (safe for atoms)
│ ├── inputDefaults.ts # getDefaultValueForType
│ └── index.ts
├── node-config/ # Node configuration (icons, colors, default types)
│ ├── nodeIcons.ts # AGENTFLOW_ICONS, DEFAULT_AGENTFLOW_NODES
│ └── ...
├── node-catalog/ # Node catalog and filtering logic
│ ├── nodeFilters.ts # filterNodesByComponents, isAgentflowNode
│ └── ...
├── theme/ # Design tokens and MUI theming
│ ├── tokens.ts # Color palettes, spacing, shadows
│ ├── createAgentflowTheme.ts
│ └── ...
├── validation/ # Flow validation logic
│ ├── flowValidation.ts # validateFlow, validateNode
│ ├── connectionValidation.ts # isValidConnectionAgentflowV2
│ └── ...
├── utils/ # Domain-aware utilities (NOT importable by atoms)
│ ├── nodeFactory.ts # initNode, getUniqueNodeId
│ └── ...
└── index.ts # Barrel export (use sparingly)
Rules:
- No React components allowed - Pure TypeScript only
- No browser-specific APIs if possible
- No side effects
- Pure functions where possible
- Can be tested in isolation
core/primitives/ vs core/utils/
core/ contains two utility directories with different import permissions:
primitives/— Domain-free, general-purpose functions with no knowledge of nodes, flows, or any business concept. These are pure data transformations (e.g., computing a default value from a type string). Safe to import fromatoms/.utils/— Domain-aware utilities that understand node structures, flow data, or validation logic (e.g.,initNode,buildDynamicOutputAnchors). Only importable byfeatures/andinfrastructure/.
When adding a new utility, ask: "Does this function need to know what a Node or Flow is?" If no → primitives/. If yes → utils/.
Goal: To be the framework-agnostic source of truth.
infrastructure/ - External Services
"The Outside World." Handles communication with external systems: data persistence, network requests, and global state management.
infrastructure/
├── api/ # API client layer (network requests)
│ ├── client.ts # Axios factory
│ ├── ... # Endpoint modules (nodes, chatflows, etc.)
│ └── index.ts
│
└── store/ # State management
├── AgentflowContext.tsx # Flow state context
├── agentflowReducer.ts # Reducer for flow state actions
├── ... # Other contexts (ApiContext, ConfigContext)
└── index.ts
Rules:
- All external communication goes here
- Contexts are internal (composed in AgentflowProvider)
- API hooks live with their API modules
Goal: To wrap external dependencies so they can be easily swapped or mocked in tests.
Dependency Flow
Dependencies must only flow downwards.
┌─────────────────────────────────────────────────────────┐
│ Root Files (Public API) │
│ (index.ts, Agentflow.tsx, AgentflowProvider.tsx) │
│ "The Public Face" │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ features/ │
│ (canvas, node-palette, generator, node-editor) │
│ "What it does" │
└─────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────────┐
│ atoms/ │ │ infrastructure/ │
│ (UI primitives) │ │ (api, store) │
│ "What it looks │ │ "The Outside World" │
│ like" │ │ │
└──────────────────┘ └────────────────────────┘
│ │
└──────────────┬─────────────────────┘
▼
┌─────────────────────┐
│ core/ │
│ (types, constants, │
│ validation, etc.) │
│ "The Brain" │
└─────────────────────┘
Import Rules:
features→atoms,infrastructure,core✅infrastructure→core✅atoms→core/types,core/theme, andcore/primitivesonly ✅core→ nothing (leaf node) ✅- Atoms and Core are "leaf" nodes - they cannot import from
features/orinfrastructure/
Gatekeeper Pattern
Each module exposes only what's needed via its index.ts:
// features/canvas/index.ts
// ✅ Public API
// Container components are re-exported for advanced usage
// ❌ Internal sub-components stay private within containers/components
This enables:
- Encapsulation: Internal refactoring doesn't break consumers
- Tree-shaking: Bundlers can eliminate unused code
- Clarity: Clear contract of what each module provides
Adding a New Feature
-
Create folder under
features/:features/my-feature/ ├── containers/ # Smart components (optional) │ └── MyContainer.tsx ├── components/ # Presentational components (optional) │ └── MyComponent.tsx ├── hooks/ # Feature-specific hooks (optional) │ └── useMyHook.ts ├── helper.ts # Feature-specific util └── index.ts # Public exports only -
Export only what's needed:
// index.ts -
Import from infrastructure/core, never from other features:
// ✅ Good // ❌ Bad - cross-feature import
Root Files (src/*.ts)
"The Public Face." The entry point of the package.
AgentflowProvider.tsx: Injects infrastructure (stores/api) into the appAgentflow.tsx: The primary component users will drop into their appsuseAgentflow.ts: Primary public hook for accessing flow state and actionsindex.ts: The "Barrel" that exports the public API for npm
Public API
The package exposes a minimal public API via src/index.ts:
// Components
// Hooks
// Types
// Utilities (for advanced usage)
Everything else is internal implementation detail.
Development Principles
Barrel Exports
Every directory must have an index.ts that acts as a gatekeeper.
✅ Good:
❌ Bad:
// Never deep-link into files
Prop Drilling vs. Context
- Atoms: Use props for all configuration
- Features: Use context/state for shared data
Naming Convention
| Type | Convention | Example |
|---|---|---|
| Component | PascalCase.tsx | AgentFlowNode.tsx |
| Hook | camelCase.ts (use prefix) | useFlowHandlers.ts |
| Logic/Types | camelCase.ts | flowValidation.ts, nodeFilters.ts |
| Styles | kebab-case (co-located) | canvas.css |