All skills
Skillintermediate

@flowiseai/agentflow - Architecture

This document describes the internal architecture of the `@flowiseai/agentflow` package.

Claude Code Knowledge Pack7/10/2026

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/ or infrastructure/ (except types from core/types for prop definitions, design tokens from core/theme, and primitives from core/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.ts gatekeeper
  • Features never import from other features directly - If canvas needs logic from generator, move that logic to core/
  • 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 from atoms/.
  • utils/ — Domain-aware utilities that understand node structures, flow data, or validation logic (e.g., initNode, buildDynamicOutputAnchors). Only importable by features/ and infrastructure/.

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:

  • featuresatoms, infrastructure, core
  • infrastructurecore
  • atomscore/types, core/theme, and core/primitives only ✅
  • core → nothing (leaf node) ✅
  • Atoms and Core are "leaf" nodes - they cannot import from features/ or infrastructure/

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

  1. 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
    
  2. Export only what's needed:

    // index.ts
    
    
  3. 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 app
  • Agentflow.tsx: The primary component users will drop into their apps
  • useAgentflow.ts: Primary public hook for accessing flow state and actions
  • index.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

TypeConventionExample
ComponentPascalCase.tsxAgentFlowNode.tsx
HookcamelCase.ts (use prefix)useFlowHandlers.ts
Logic/TypescamelCase.tsflowValidation.ts, nodeFilters.ts
Styleskebab-case (co-located)canvas.css